From the four-agent pre-release review (all read-only), the three items that warranted
fixing before ship:
1. NONCE PREFIX WIDENED (the one security-relevant finding). The interim counter-nonce
used a 32-bit random prefix + 64-bit counter; since a fresh instance restarts the
counter at 0, two instances that drew the same prefix would reuse nonces under the
same long-lived key (catastrophic for AES-GCM), and 32 bits collides at only ~2^16
instances. Now 48-bit random prefix + 48-bit counter: birthday bound ~2^24 instances
while 2^48 packets/session stays far beyond any real session - strictly safer than
both the interim scheme AND the original per-packet 96-bit-random nonce. Wire
unchanged (receiver reads the nonce off the packet). Comment corrected.
2. STATUS-TEXT DE-DUPLICATED. The CheckedListBox spoken-status builder existed in two
copies (CheckedListAccessibility + MainForm) with a comment falsely claiming they were
"exact" - and they had already drifted (the remembered-apps empty-state line was in the
MainForm copy only). Folded to ONE builder (CheckedListAccessibility.ApplyStatus +
EmptyTextFor); MainForm delegates. NVDA wording is now identical in the main window and
every dialog by construction. No user-visible change today; removes the silent-desync trap.
3. STALE COMMENTS. RemPacket still documented the pre-5.6 plaintext control wire format
(2 bytes / 14 on the wire); it is now sealed (50 on the wire, the 2 bytes are inner
plaintext). Fixed that and the MainForm.Peers.cs comment that misplaced CaptureSpecBuilder
in Core (it is App by necessity). Docs only.
Plus review-flagged test top-ups: NonceSequence layout + two-instance-distinct-prefix
assert; ControlReceiveGuard future-dated rejection + 300-command burst (no false replay
across the prune threshold); log-rotation INTEGRITY (every line survives exactly once)
+ a 4-thread concurrency test that actually fails if writeGate is removed; ReleaseSigning
now honestly SKIPs (not caveat-PASSes) when the publisher key is absent.
Gate 69/69.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The god-object shrink, completed as pure code motion: the peer state (known/manual/
remembered/selected/named peers, endpoint anti-thrash) and the whole Peers section
(discovery reconciliation, endpoint follow, arming refresh, manual add, named-peers
dialog, remembered delete) move VERBATIM into MainForm.Peers.cs as a partial-class
split - the same pattern Andre's SensorReadout form uses. Same class, same members,
compiler-proven identical; MainForm.cs drops ~430 lines and the peer logic finally
has its own front door. The shared LOGIC under it (PeerArming, CaptureSpecBuilder,
PeerAddress) landed in stages 1-2.
Plus the last flagged test gap: the heartbeat Healthy->Stale->Unreachable windows are
now pinned against a CONTROLLED clock via a seam over the real derivation
(SnapshotHealthLocked, made static - it was already pure): 1s = Healthy, 3s = Stale,
6s = Unreachable, never-answered = pending first, Unreachable only after sustained
pinging. These are the numbers every peer's armed/pruned state hangs off in both the
app and the service.
Gate 61/61. This completes the review plan's Phase 4.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>