Skip to content

fix: clock skew tolerance 30s -> 5min (stacks on #67 -> #66)#68

Open
grumbach wants to merge 3 commits intoWithAutonomi:mainfrom
grumbach:feat/clock-skew-fix
Open

fix: clock skew tolerance 30s -> 5min (stacks on #67 -> #66)#68
grumbach wants to merge 3 commits intoWithAutonomi:mainfrom
grumbach:feat/clock-skew-fix

Conversation

@grumbach
Copy link
Copy Markdown
Collaborator

@grumbach grumbach commented Apr 9, 2026

Stacked on #67 (Mick's NAT fixes) -> #66 (workspace consolidation).

One constant change: MAX_FUTURE_SECS: 30 -> 300.

Without this: 0/3 uploads from Mac (31s clock skew caused all messages to be rejected as future-dated). With this: 3/3 uploads succeeded.

A decentralized network cannot partition when a consumer device's clock drifts by 31 seconds. The past window was already 5 minutes; the future window was asymmetrically tight at 30 seconds.

492 ant-node tests pass.

Copilot AI review requested due to automatic review settings April 9, 2026 05:29
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR is intended to increase future clock-skew tolerance (30s → 5m) to prevent rejecting slightly future-dated messages/uploads from devices with drift.

Changes:

  • Adds extensive architecture and planning/review documentation under crates/saorsa-core/ and .planning/.
  • Introduces/updates local tooling and lint configuration files for saorsa-core (e.g., .clippy.toml, .actrc, .gitignore).
  • Updates the root Cargo.toml to define a workspace and switch saorsa-core from a crates.io dependency to a local path dependency.

Reviewed changes

Copilot reviewed 75 out of 632 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
crates/saorsa-core/ARCHITECTURE.md Adds architecture overview documentation for saorsa-core.
crates/saorsa-core/.planning/reviews/workflow-configuration.md Adds workflow review notes/documentation.
crates/saorsa-core/.planning/reviews/type-safety.md Adds type-safety review report.
crates/saorsa-core/.planning/reviews/type-safety-review-validation.md Adds validation report (includes build/checklist details).
crates/saorsa-core/.planning/reviews/test-coverage.md Adds test coverage review document.
crates/saorsa-core/.planning/reviews/task-spec.md Adds task-spec review document.
crates/saorsa-core/.planning/reviews/review-iteration-1-complete.md Adds review iteration completion report.
crates/saorsa-core/.planning/reviews/phase-1-review-summary.md Adds phase-1 review summary document.
crates/saorsa-core/.planning/reviews/minimax.md Adds external review notes (MiniMax).
crates/saorsa-core/.planning/reviews/kimi.md Adds external review notes (Kimi).
crates/saorsa-core/.planning/reviews/iteration-2-summary.md Adds iteration-2 summary document.
crates/saorsa-core/.planning/reviews/iteration-2-fixes-applied.md Adds iteration-2 fixes-applied report.
crates/saorsa-core/.planning/reviews/glm.md Adds external review placeholder/notes (GLM).
crates/saorsa-core/.planning/reviews/fixes-applied-phase2-task2.md Adds fixes-applied writeup for phase2 task2.
crates/saorsa-core/.planning/reviews/fixes-applied-phase2-task1.md Adds fixes-applied writeup for phase2 task1.
crates/saorsa-core/.planning/reviews/fixes-applied-encoding.md Adds encoding module fixes summary.
crates/saorsa-core/.planning/reviews/error-handling.md Adds error-handling audit report.
crates/saorsa-core/.planning/reviews/documentation.md Adds documentation coverage audit report.
crates/saorsa-core/.planning/reviews/consensus-type-safety-20260129.md Adds consensus report for type-safety review.
crates/saorsa-core/.planning/reviews/consensus-encoding-review-20260129.md Adds consensus report for encoding review.
crates/saorsa-core/.planning/reviews/consensus-20260204-183500.md Adds consensus report for refocus/cleanup effort.
crates/saorsa-core/.planning/reviews/consensus-20260202-143500.md Adds consensus report for v0.10.2 work.
crates/saorsa-core/.planning/reviews/consensus-20260129-210600.md Adds consensus report for uncommitted-changes review.
crates/saorsa-core/.planning/reviews/consensus-20260129-200500.md Adds consensus report for Phase 5 Task 3.
crates/saorsa-core/.planning/reviews/consensus-20260129-155118.md Adds post-commit consensus note for Task 3.
crates/saorsa-core/.planning/reviews/consensus-20260129-154812.md Adds consensus note for Task 2.
crates/saorsa-core/.planning/reviews/consensus-20260129-153828.md Adds consensus note for Task 1.
crates/saorsa-core/.planning/reviews/build.md Adds build validation report (includes noted fixes).
crates/saorsa-core/.planning/reviews/build-iteration-2.md Adds build verification report for iteration 2.
crates/saorsa-core/.planning/reviews/EXTERNAL_REVIEWS_COMPLETE.md Adds summary that external reviews are complete.
crates/saorsa-core/.planning/reviews/CODEX_REVIEW_SUMMARY.md Adds Codex external review summary for Phase 1.
crates/saorsa-core/.planning/progress.md Adds progress log for message encoding optimization.
crates/saorsa-core/.planning/architecture-analysis/06-forward-secrecy.md Adds forward secrecy architecture analysis doc.
crates/saorsa-core/.planning/architecture-analysis/05-message-persistence.md Adds message persistence architecture analysis doc.
crates/saorsa-core/.planning/architecture-analysis/04-routing-strategy.md Adds routing strategy architecture analysis doc.
crates/saorsa-core/.planning/architecture-analysis/03-offline-delivery.md Adds offline delivery architecture analysis doc.
crates/saorsa-core/.planning/STATE.json Adds planning state tracking JSON for the project.
crates/saorsa-core/.planning/REVIEW_ITERATION_1_COMPLETE.md Adds review-iteration completion report.
crates/saorsa-core/.planning/REVIEW_CYCLE_COMPLETE.md Adds external review cycle completion report.
crates/saorsa-core/.planning/REVIEW_CYCLE_1_COMPLETE.md Adds review cycle completion report for encryption review.
crates/saorsa-core/.planning/PROJECT.md Adds project-level planning doc for encoding optimization.
crates/saorsa-core/.planning/PLAN-phase-5.md Adds plan doc for binary encoding migration.
crates/saorsa-core/.planning/PLAN-phase-3.md Adds plan doc for solution design phase.
crates/saorsa-core/.planning/PLAN-phase-1.md Adds plan doc for baseline measurement phase.
crates/saorsa-core/.planning/PHASE_2_TASK_1_REVIEW_ITERATION_1.md Adds review iteration doc for Phase 2 Task 1.
crates/saorsa-core/.planning/PHASE_2_TASK_1_ITERATION_1_STATUS.md Adds status report for Phase 2 Task 1 iteration 1.
crates/saorsa-core/.planning/PHASE_2_TASK_1_FIXES_APPLIED.md Adds fixes-applied doc for Phase 2 Task 1.
crates/saorsa-core/.planning/MILESTONES.md Adds milestone definitions for the project.
crates/saorsa-core/.planning/CODE_QUALITY_REVIEW_EXECUTIVE_SUMMARY.md Adds executive summary for code quality review.
crates/saorsa-core/.gitignore Adds crate-level ignore rules (target, IDE, tool state, etc.).
crates/saorsa-core/.cursorules Adds Cursor rules pointer to CLAUDE.md.
crates/saorsa-core/.cursorrules Adds Cursor rules pointer to CLAUDE.md (alternate filename).
crates/saorsa-core/.clippy.toml Adds clippy configuration (test unwrap/expect/panic allowances + thresholds).
crates/saorsa-core/.actrc Adds act runner image mappings (including macos-latest mapping).
Cargo.toml Adds workspace members and switches saorsa-core dependency to local path.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +8
[workspace]
members = [
".",
"crates/saorsa-core",
"crates/saorsa-transport",
"crates/saorsa-transport/saorsa-transport-workspace-hack",
]
resolver = "2"
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title/description claims a single constant change (MAX_FUTURE_SECS 30→300), but this diff introduces a workspace and additional members. Either update the PR title/description to reflect these broader changes, or split the workspace/config/docs changes into separate PR(s) so the clock-skew tolerance change can be reviewed in isolation.

Copilot uses AI. Check for mistakes.
## Review Summary

### File Analyzed
- **Path**: `/Users/davidirvine/Desktop/Devel/projects/saorsa-core/src/messaging/encoding.rs`
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This document embeds an absolute local filesystem path (/Users/...), which can leak developer-machine details and is brittle for other contributors. Prefer repo-relative paths (e.g., src/messaging/encoding.rs) or omit the local path entirely.

Suggested change
- **Path**: `/Users/davidirvine/Desktop/Devel/projects/saorsa-core/src/messaging/encoding.rs`
- **Path**: `src/messaging/encoding.rs`

Copilot uses AI. Check for mistakes.
"repository": "saorsa-labs/saorsa-core",
"branch": "feature/encoding-optimization",
"created_by": "Claude Sonnet 4.5",
"last_updated": "2026-01-29T11:30:00Z",
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state file records last_updated twice with conflicting formats/values (ISO-8601 string vs epoch float) that don't appear to represent the same timestamp. If tooling depends on this field, this inconsistency can lead to incorrect ordering or stale-state behavior; consider keeping a single canonical last_updated field (or ensure both are derived from the same source of truth and match).

Copilot uses AI. Check for mistakes.
},
"session_note": "Paused - work continuing in new session. Task 3 complete and merged to main (commit 3abbc59)"
},
"last_updated": 1738702200.000000,
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The state file records last_updated twice with conflicting formats/values (ISO-8601 string vs epoch float) that don't appear to represent the same timestamp. If tooling depends on this field, this inconsistency can lead to incorrect ordering or stale-state behavior; consider keeping a single canonical last_updated field (or ensure both are derived from the same source of truth and match).

Suggested change
"last_updated": 1738702200.000000,
"last_updated": 1769686200.000000,

Copilot uses AI. Check for mistakes.
@grumbach grumbach force-pushed the feat/clock-skew-fix branch 2 times, most recently from 412a26d to 8f68954 Compare April 9, 2026 06:13
Copilot AI review requested due to automatic review settings April 9, 2026 06:13
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 55 out of 486 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +43 to +45
let elapsed = now.duration_since(self.last_update).as_secs_f64();
let refill_rate = cfg.max_requests as f64 / cfg.window.as_secs_f64();
self.tokens += elapsed * refill_rate;
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cfg.window.as_secs_f64() will be 0.0 for a zero-duration window, which would cause a division-by-zero and produce inf/NaN token behavior. Since EngineConfig is a public struct, consider validating window > Duration::ZERO at construction time (e.g., in Engine::new) or handling the zero case explicitly in try_consume.

Copilot uses AI. Check for mistakes.
Comment on lines +154 to +164
impl Default for JoinRateLimiterConfig {
fn default() -> Self {
Self {
max_joins_per_64_per_hour: 10_000,
max_joins_per_48_per_hour: 10_000,
max_joins_per_24_per_hour: 10_000,
max_global_joins_per_minute: 10_000,
global_burst_size: 10_000,
}
}
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JoinRateLimiterConfig field docs state strict defaults (e.g., “/64 per hour (default: 1)”, global 100/min), but Default currently sets everything to 10_000, effectively disabling Sybil protections in default configurations. Either (a) change Default to match the documented secure defaults, or (b) update the doc comments to reflect that defaults are permissive (ideally also providing a JoinRateLimiterConfig::production_defaults() / ::development_defaults() to avoid insecure-by-default behavior).

Copilot uses AI. Check for mistakes.
async fn process_message(&self, message: DhtMessage) -> LinkResult<DhtResponse> {
match message {
DhtMessage::FindNode { target, count } => {
let engine = self.dht_engine.read().await;
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A tokio::sync::RwLock read guard is held across an .await (find_nodes(...).await). Holding async locks across await points can lead to writer starvation and, in some designs, deadlocks (especially if find_nodes internally needs write access or awaits on work that depends on writers). Consider restructuring to avoid awaiting while the lock is held (e.g., clone/copy required state out of the guard, or move concurrency control inside DhtCoreEngine).

Suggested change
let engine = self.dht_engine.read().await;
let engine = {
let engine = self.dht_engine.read().await;
engine.clone()
};

Copilot uses AI. Check for mistakes.
//! Enables nodes to detect when their identity doesn't "fit" a DHT close group
//! and automatically regenerate with a new identity.

pub mod node_identity;
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/identity/node_identity_extensions.rs is added in this PR but is not declared here (or elsewhere) as a module, so it will not be compiled or available to consumers. If these extension methods are intended to exist, add pub mod node_identity_extensions; and re-export what should be public; otherwise, remove the file to avoid dead code drift.

Suggested change
pub mod node_identity;
pub mod node_identity;
pub mod node_identity_extensions;

Copilot uses AI. Check for mistakes.
// Re-export saorsa-transport PQC functions for convenience
pub use self::saorsa_transport_integration::{generate_ml_dsa_keypair, ml_dsa_sign, ml_dsa_verify};

// Primary post-quantum cryptography types from saorsa-pqc 0.3.0
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says saorsa-pqc 0.3.0, but crates/saorsa-core/Cargo.toml depends on saorsa-pqc = \"0.5\". Please update the comment to match the actual dependency version to avoid misleading readers.

Suggested change
// Primary post-quantum cryptography types from saorsa-pqc 0.3.0
// Primary post-quantum cryptography types from saorsa-pqc 0.5

Copilot uses AI. Check for mistakes.

## Quick Start

Add this to your `Cargo.toml`:
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README quick-start pins saorsa-core = \"0.16.0\", but crates/saorsa-core/Cargo.toml declares version = \"0.22.0\". Update the README to reference the current crate version (or use a broader version requirement policy) so consumers copy/paste a valid, up-to-date dependency.

Copilot uses AI. Check for mistakes.
@grumbach grumbach force-pushed the feat/clock-skew-fix branch from 8f68954 to 2fb339c Compare April 9, 2026 06:15
Copilot AI review requested due to automatic review settings April 9, 2026 06:24
@grumbach grumbach force-pushed the feat/clock-skew-fix branch from 2fb339c to 9240dc1 Compare April 9, 2026 06:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 57 out of 488 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +22 to +24
impl NodeIdentity {
/// Save identity to file
pub async fn save_to_file(&self, path: &Path) -> Result<()> {
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NodeIdentity::save_to_file and NodeIdentity::load_from_file are also defined in crates/saorsa-core/src/identity/node_identity.rs (same inherent impl target). Rust does not allow duplicate inherent methods on the same type, so this will fail to compile. Remove one set of methods, or consolidate into a single module (or rename the extension methods to avoid collisions).

Copilot uses AI. Check for mistakes.
Comment on lines +50 to +51
/// Load identity from file
pub async fn load_from_file(path: &Path) -> Result<Self> {
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NodeIdentity::save_to_file and NodeIdentity::load_from_file are also defined in crates/saorsa-core/src/identity/node_identity.rs (same inherent impl target). Rust does not allow duplicate inherent methods on the same type, so this will fail to compile. Remove one set of methods, or consolidate into a single module (or rename the extension methods to avoid collisions).

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +19
use super::node_identity::{PeerId, NodeIdentity};
use crate::{P2PError, Result};
use std::path::{Path, PathBuf};
use std::time::Duration;
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These imports are unused in this file (PeerId and Duration are never referenced), which will trigger unused-import warnings and fail CI when warnings are denied. Remove the unused imports (or use them if intended).

Suggested change
use super::node_identity::{PeerId, NodeIdentity};
use crate::{P2PError, Result};
use std::path::{Path, PathBuf};
use std::time::Duration;
use super::node_identity::NodeIdentity;
use crate::{P2PError, Result};
use std::path::{Path, PathBuf};

Copilot uses AI. Check for mistakes.
Comment on lines +157 to +161
max_joins_per_64_per_hour: 10_000,
max_joins_per_48_per_hour: 10_000,
max_joins_per_24_per_hour: 10_000,
max_global_joins_per_minute: 10_000,
global_burst_size: 10_000,
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JoinRateLimiterConfig field docs describe much lower 'default' limits (e.g., /64 per hour default 1, global joins per minute default 100), but Default sets everything to 10,000. This effectively disables Sybil-protection rate limiting by default and conflicts with the documentation. Align the Default values with the documented/desired policy (or update the docs to match the intended permissive defaults).

Suggested change
max_joins_per_64_per_hour: 10_000,
max_joins_per_48_per_hour: 10_000,
max_joins_per_24_per_hour: 10_000,
max_global_joins_per_minute: 10_000,
global_burst_size: 10_000,
max_joins_per_64_per_hour: 1,
max_joins_per_48_per_hour: 5,
max_joins_per_24_per_hour: 3,
max_global_joins_per_minute: 100,
global_burst_size: 10,

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +100
pub fn try_consume_key(&self, key: &K) -> bool {
let mut map = self.keyed.write();
// Get or insert with LRU cache (automatically evicts oldest if at capacity)
if let Some(bucket) = map.get_mut(key) {
bucket.try_consume(&self.cfg)
} else {
let mut bucket = Bucket::new(self.cfg.burst_size as f64);
let result = bucket.try_consume(&self.cfg);
map.put(key.clone(), bucket);
result
}
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every keyed rate-limit check takes an exclusive RwLock write guard, even when just consuming from an existing bucket. Under high concurrency, this can become a contention bottleneck. Consider using a concurrent map (e.g., sharded map) or a design that narrows lock duration (e.g., store per-key buckets behind their own locks), while keeping LRU eviction semantics.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +11
| Node | Provider | IP Address | Region | Purpose | Status |
|------|----------|------------|--------|---------|--------|
| saorsa-1 | Hetzner | 77.42.75.115 | Helsinki | Dashboard & Website | Active |
| saorsa-2 | DigitalOcean | 142.93.199.50 | NYC1 | Bootstrap Node | Active |
| saorsa-3 | DigitalOcean | 147.182.234.192 | SFO3 | Bootstrap Node | Active |
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc embeds live infrastructure details (public IPs, provider inventory, and later includes SSH key IDs and operational commands). If this repository is public or shared broadly, this materially increases attack surface (reconnaissance). Consider moving this document to a private ops repo, redacting sensitive fields (IPs/key IDs), or replacing them with placeholders/examples.

Copilot uses AI. Check for mistakes.
grumbach added 3 commits April 9, 2026 16:10
Move saorsa-core and saorsa-transport into crates/ as workspace members.
All dependencies now use path references instead of fragile git URLs,
branch names, or commit hashes.

Cleaned up ~100 non-source files: AI planning artifacts, saved test
outputs, Go legacy files, orphaned scripts.

492 ant-node tests pass.
@grumbach grumbach force-pushed the feat/clock-skew-fix branch from 9240dc1 to 3d2d5a8 Compare April 9, 2026 07:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants