Repository navigation
fix(regions): exclude planned paths from observed history - #507
Conversation
Independent reviewReviewed commit No actionable findings remain. The review covered:
The pre-PR UI review identified a P3 wording problem: incomplete observation attribution was described as a reached safety limit. The final commit corrects that reason and adds a browser regression test. I reviewed that follow-up; no open issue remains from it. The parent agent reports passing full Go server/ingestor tests, focused race tests, JS tests and real-database/browser validation. I reviewed the regression coverage but did not independently rerun the full test suite. CI for this exact head is still running at the time of this review; this comment does not claim a green final CI result or authorize merge/deployment. |
Review — CS-Coordinator PR#507 — head 4c20a19Verdict: REQUEST CHANGES. One blocking finding, from staging with real data. Reviewed against master
The direction is right: membership now comes from each observation's own provenance, and planned DIRECT paths no longer gain scope membership. Findings
|
…rates (#507) Review F1/F3 for PR #507, red on 4c20a19: - TestRegionsEvidenceIncompletenessIsPerBucketAndScope mixes valid, excluded (known TRANSPORT_DIRECT, unscoped FLOOD, mismatched transport code), unprovable (missing header/codes) and capped (oversized path) observations across hours and scopes. coverage.evidence must report excluded/unprovable/capped per hour bucket and stored scope for history, routes and each Latest window; stepEvidence must split the same counts. - TestRegionsEvidenceExcludedOnlyIsComplete: known direct and mismatched observations alone are not incomplete evidence. Red: the snapshot-wide evidenceIncomplete flag is true. - TestRegionsEvidenceStepCapCountedSeparately: the directed-step cap is counted as capped step appearances and never reaches coverage evidence. - test-regions-map.js: rates, chart values and comparisons stay available for unaffected buckets/scopes, are withheld only where an included bucket/scope is unprovable or capped, and unknown placement fails closed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…et and scope (#507) Review F1 (blocking) and F3 for PR #507. On staging the snapshot-wide coverage.evidenceIncomplete flag was always true, so Health and Timeline rates and comparisons were permanently unavailable. - One provenance gate classifies each observation of a scoped transmission: eligible; excluded (known DIRECT/unscoped header, or own transport codes that differ from the stored frame - forwarders never rewrite them, firmware Mesh::sendFlood/sendZeroHop); unprovable (unknown/malformed own header, own codes or canonical scope code). Exclusions never make counts incomplete. - Counts are attributed to the transmission's stored scope and FirstSeen hour, together with capped observations and capped memberships. They are published as coverage.evidence (named Go structs, no new map[string]interface{}): totals, per-scope totals and, in history and routes, per-bucket cells; Latest sums the requested window. A bounded 128-scope x 505-hour budget sets evidence.truncated, which fails closed. - The client withholds rates, chart values and comparisons only for intervals that include an unprovable/capped bucket of the selected scope (any scope for "all scopes"); other buckets and scopes stay available. Publication caps remain snapshot-wide. - Unresolved hop tokens qualify directed steps (adjacency), not the memberships of uniquely resolved relays. - F3: stepEvidence splits excluded/unprovable/capped observations, and the directed-step, pair and cell caps are counted once, in one helper, as cappedStepAppearances; they never reach coverage evidence. Mutants killed: global flag on any unprovable/capped (Go and JS), mismatch classified unprovable, rate ignoring evidence, step cap counted as coverage capped, step cap not counted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#507) Review F2 for PR #507: Health 24h relay appearances on staging rose from ~28k (#503) to 104k with this PR. Since #507 memberships come from every attributable scoped-flood observation's own path; #503/#505 history used the canonical display path and its candidate index, so relays seen only on other observers' paths were not counted. - TestRegionsEvidenceAppearancesUnionAcrossObservers pins the meaning: one transmission observed via [A,B], [C,D], a repeat of [A,B] and a loop [B,A,B] gives A, B, C and D one appearance each (total 4). Run against c6574b4 (pre-#507 master) the same test yields only A and B (total 2). Mutants killed: only the first observation path counted; per-transmission membership dedup removed (total 7). - Health note, Timeline details and docs state the union semantics, that repeated observers/paths/loops count once, and that more observers can reveal more relays for the same traffic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds a mixed-evidence variant of the 30k transmission / 2k relay fixture (8 scopes, one known-direct and one mismatched-code observation per transmission, an unknown header on every 10th) for the background snapshot and the warm paired response, plus the worst-case evidence payload at the full 128-scope x 505-hour budget. Local, Linux x86-64 (4 vCPU), Go toolchain of this repo, 5x5 iterations, median, decedf1 (before) -> this branch: - background snapshot: 132.1 -> 139.2 ms; mixed 137.3 -> 144.2 ms; allocations unchanged (130.2 / 137.5 MB) - capture under the packet read lock: 11.7 -> 12.0 ms, 13.1 MB both - warm paired response, mixed: 32.0 -> 32.5 ms; payload +10,026 bytes - worst-case evidence payload: 3,673,684 bytes for 64,640 cells Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review — CS-Coordinator PR#507 — head 18c6e3fVerdict: APPROVE. F1–F3 are resolved. Two release-relevant issues remain outside this PR and are filed separately. Staging ( Still observed on staging, not caused by this PR:
The fix here is correct, honest and well tested (red-first tests, union-of-observers definition documented, step cap kept separate). Merging. |
Summary
Fix the Regions history limitation disclosed in #505: a planned DIRECT path must never acquire observed scope membership merely because another observation of the same content transmission was FLOOD.
This is a separate correctness follow-up to #505. #501–#505 are merged and this PR now targets
master(merged in atc6574b46). No merge or deployment is included.Changes
FirstSeenhour and published ascoverage.evidence(named Go structs): totals, per-scope totals and, for history/routes, per-bucket cells. Latest sums the requested rolling window.coverage.evidence.truncated, which fails closed for every rate and comparison. Publication caps stay snapshot-wide.stepEvidencesplits excluded/unprovable/capped observations; directed-step, per-transmission pair and cell caps are counted separately ascappedStepAppearancesand never reach coverage evidence. Unresolved hop tokens qualify directed steps (adjacency), not the memberships of uniquely resolved relays.What "relay appearances" now means
A relay appearance is one transmission counted once for each distinct relay identified on any observer's own attributable scoped-flood path, the union across observers, not only the displayed path. Repeated observers, identical paths and loops count once. #503/#505 history was attributed through the canonical display path and its candidate index, so relays seen only on other observers' paths were not counted. Totals therefore rise where several observers hear the same transmission along different paths, and more observers can reveal more relays for the same traffic. This is the mechanism behind staging's 24 h Health total rising from ~28k to 104k while observed relay nodes went from 378 to 383. A regression test pins it: one transmission observed via
[A,B],[C,D], a repeat of[A,B]and a loop[B,A,B]gives 4 appearances on this branch and 2 (A and B only) onc6574b46. The UI Health note, Timeline details and docs now state this definition.The generic node liveness, public relay statistics and traffic-share algorithms are intentionally unchanged. Region names still reuse stored canonical scope attribution; matching frame evidence is not independent authentication of a region name or proof of a cross-scope forwarding event.
Bounded work and performance
Capture still occurs once per transmission under the existing snapshot lock. Resolution and membership aggregation run outside it; warm handlers do not scan packets or acquire the packet-store lock. The existing shared capture limits remain 250k path variants, 128 per transmission, 8,192 bytes per path and 64 tokens. Capture now includes the current hour for Latest. Membership has independent 1M-entry / 10k-identity budgets and retains 32 newest scopes per identity; directed-step/edge-cell caps cannot suppress valid singleton membership. Limits are disclosed, not used as a ranking of all evidence. No per-node API calls, schema/config changes or new dependencies.
Matched local synthetic benchmark, Apple M5 / Go 1.26.3, 30k transmissions / 2k relays, ten iterations per version:
Round 2 (per-bucket evidence), local Linux x86-64 (4 vCPU), 5×5 iterations, median,
decedf15(before) →18c6e3fd:Evidence classification adds O(1) map updates per non-eligible observation inside the existing capture loop; per-bucket aggregation, sorting and publication run outside the lock. The worst-case evidence payload at the full budget is 3,673,684 bytes (64,640 cells); with 48–168 h retention only populated hours of active scopes are emitted.
These are noisy single-host measurements, not a speedup claim or production guarantee. Strict membership aggregation costs additional transient allocations (about 30.5 MB in the matched run); three-iteration repeats measured 109–167 ms / 140–161 MB allocated for the whole background snapshot. Published membership state retains bounded latest scope summaries, not the temporary per-transmission entries. This work runs on the existing background refresh, not per request. Future configurable display/budget limits remain tracked in the Regions documentation; protocol validity checks are not tunable thresholds.
Validation (round 2, head
18c6e3fd)3e475793added the red tests (per-bucket/scope evidence with a realistic mix of valid, excluded, unprovable and capped observations; excluded-only data is complete; step cap counted separately; unaffected buckets keep rates and comparisons in the client). They failed on4c20a190, where excluded-only data was reported asevidenceIncomplete: true.cmd/serversuite,-raceonRegion|Route|Relay|Evidence|412|470, fullcmd/ingestorsuite,sh test-all.sh(258/258),node test-frontend-helpers.js(719), Regions browser suite (34/34) and core browser regression (154 passed, 3 fixture-dependent skips) against a local Go server with the CI-preparede2e-fixture.db. XSS diff preflight and Go shard assignment passed.18c6e3fd: every job passed on attempt 2. Attempt 1 failed once in the unrelatedtest-issue-76-heard-by-e2e.jsHome card test, which passed 8/8 three times locally; see the round-2 report comment.Validation (round 1, head
4c20a190)Round 1 commit:
4c20a1900d26f0e3c16b31cc8aff645d69757cc4. The post-push unmocked API/browser regression passed on this source, and the worktree is clean. Full-stack CI run 39007001083 passed on this exact head: every Go/race, ingestor, library/CLI, script/container, JavaScript/lint, Docker, E2E shard, coverage aggregation and final required gate succeeded. The stacked branch needs an explicit manual CI run because automatic PR CI targetsmaster. The actual workflow conditions were checked: publishing requires an upstream push, and deployment additionally requires upstreammaster; this dispatch on our fork's feature branch did not publish or deploy.🤖 Generated with Claude Code