P3.3.3 — Gossip Adaptive Fanout — Verification Evidence
Step 5 of the 5-step chain (CLAUDE.md §6). Records the gate runs that authorize PR creation.
§1. Gate run log
| Gate | Command | Result | Notes |
|---|---|---|---|
| Build | npm run build |
PASS | tsc clean; postbuild copied 8 migrations |
| Lint | npm run lint |
PASS (1 fixed) | One round-trip: removed unused type ExchangeRecord import from test file (consumer asserts behavior via the class API, not the type) |
| Test | npm test -- adaptive-fanout |
PASS — 3005/3005 | Full suite under --testPathPattern=adaptive-fanout (Jest’s pattern is permissive and ran the whole suite; result was a clean 3005 pass across 65 suites) |
Earlier run hit a single pre-existing flake in domains/reputation/tools.test.ts (Migration 998_broken.sql failed), which passes cleanly in isolation (28/28). Same scope re-run after that immediately returned 3005/3005. Not a regression from this slice; flagged as known full-suite-load behavior consistent with the pre-existing-flake notes already captured in MEMORY.md.
§2. Test count delta
| Source | Count |
|---|---|
Baseline (origin/main 9c7165d5) |
2970 |
| After P3.3.3 | 3005 |
| Delta | +35 |
Within the task-prompt expected range of +12–20 (S task), slightly higher because the contract enumerates 19 invariants and describe.each worked-table row expansion accounts for 6 of the surplus (the 6 worked-table fixture rows are independent test cases by Jest’s test.each).
§3. Invariant coverage map (I1 – I19)
| ID | Test group | Status |
|---|---|---|
| I1 | A1 + A2 (range assertion in A2) | covered |
| I2 | A1 worked table | covered |
| I3 | A2 (negative score) | covered |
| I4 | A2 (>12 score) | covered |
| I5 | A3 (in-range, boundaries) | covered |
| I6 | A3 (below + above range) | covered |
| I7 | B1 (any string peer_id, no throw) | covered |
| I8 | B2 (multiple exchanges in same epoch accumulate) | covered |
| I9 | C1 (delta < period → null) | covered |
| I10 | C2 (delta >= period → score) | covered |
| I11 | C3 + C3a + C3b (default + overrides) | covered |
| I12 | D1 (only failed → not live) | covered |
| I13 | D2 (≥1 success → live) | covered |
| I14 | D3 + D6 (out-of-window → pruned) | covered |
| I15 | D4 (13 peers → score=12n → fanout=3n) | covered |
| I16 | E1 (memory bound + peer removal) | covered |
| I17 | F1 (initial currentScore=0n) | covered |
| I18 | F2 (currentFanout = computeFanout(currentScore)) | covered |
| I19 | G1 (static forbidden-token scanner) | covered |
Additional coverage beyond the contract minimum:
- D5: mixed success/failure across peers within window — exercises the
any_successbranch inrecomputeIfDue. - D7: epoch === cutoff is included (inclusive lower bound) — guards against an off-by-one in the prune predicate.
- C3c:
current < lastclock anomaly — confirms no throw, returns null.
§4. Worked-table evidence (s08 §Adaptive fanout)
Group A1 test.each produces the 6 rows verbatim from docs/spec/s08-gossip.md §Adaptive fanout table:
score=0 → fanout=10
score=3 → fanout=10
score=5 → fanout=10
score=7 → fanout=8
score=10 → fanout=5
score=12 → fanout=3
All 6 rows assert toBe(expected) with bigint equality. The spec table is bit-for-bit reproduced.
§5. Static scanner result (Group G)
adaptive-fanout.ts post-JSDoc-strip is free of every pattern in:
Math\.[A-Za-z_]Date\.[A-Za-z_]new\s+DatesetTimeout,setInterval,setImmediatefetch\s*\(XMLHttpRequestcrypto\.[A-Za-z_]process\.hrtime,process\.nextTickasync\s+function,await- float literals
\d+\.\d+ [native code]Math.random
hits array is []. Determinism contract holds.
§6. Commit sequence
| Commit | SHA | Scope |
|---|---|---|
| 1 | ac2300c8 |
audit(p3-3-3-adaptive-fanout): inventory surface |
| 2 | 229289a7 |
contract(p3-3-3-adaptive-fanout): behavioral contract |
| 3 | 89d7b1d1 |
packet(p3-3-3-adaptive-fanout): execution plan |
| 4 | d5bc9c8c |
feat(p3-3-3-adaptive-fanout): connectivity-scaled gossip fanout [3,10] |
| 5 | this commit | verify(p3-3-3-adaptive-fanout): test evidence |
§7. Blockers
None. The slice is pure data, depends on no external service, introduces no npm deps, and matches the s08 §Adaptive fanout worked table exactly. PR ready.