Skip to content

feat: P1 gate storm harness — load + N leader switchovers + divergence report#44

Merged
emrebulutlar merged 2 commits into
mainfrom
feat/storm-divergence-harness
Jul 3, 2026
Merged

feat: P1 gate storm harness — load + N leader switchovers + divergence report#44
emrebulutlar merged 2 commits into
mainfrom
feat/storm-divergence-harness

Conversation

@emrebulutlar

Copy link
Copy Markdown
Member

Part of #32 (P1.5) — the acceptance instrument for P1.1-P1.4: make p1-gate (or p1-gate-smoke for a ~5-minute 3-switchover variant) produces runs/<ts>/p1-gate-report.json with the gate numbers first-class: terminal-vs-OPEN divergence counts/pcts, overflow-rejects, engine counters, invariants.

Wall-clock: ~15-30s per switchover cycle, so the full 50-switchover gate is a 25-45 minute run. P1.2's acceptance (0% terminal, <0.5% self-healing OPEN) reads straight off the report's divergence block.

🤖 Generated with Claude Code

emrebulutlar and others added 2 commits July 3, 2026 21:52
…e report

The P1.5 acceptance instrument (match#32): one command produces the
divergence/overflow numbers used to accept P1.1-P1.4.

- tools/durability/storm.py: orchestrates the existing pieces (repro-bug9
  observer, oms_load, reconcile) through sustained OMS-REST load + >=50
  forced leader switchovers -> runs/<ts>/p1-gate-report.json. Detaches the
  market gateway during the run (match#37 OOM until P3.3) and restores it;
  REQUIRES the truthful status API (admin-gateway#13) and cross-checks its
  leader claim against the observer's newLeader events. Exit 0 = harness
  completed; workstream gates live in the report (--enforce-gates once
  P1.1/P1.2 land).
- tools/durability/diag_counters.py: harvests submitted/terminal/overflowRej/
  droppedMkt/droppedOms from EGRESS-DIAG lines in the node logs, stitching
  PM log rotation and summing per-incarnation values (counters reset on
  every node restart; a decrease marks a new incarnation).
- tools/repro-bug9/reconcile.py: adds the terminal-vs-OPEN classification
  (omsOpenClusterTerminal = the stuck-holds direction / omsTerminalClusterOpen)
  from observer statusRaw + trade-tape fully-filled evidence, and switches
  per-order REST gets to bulk per-user fetches (a storm run submits far too
  many orders for one GET each).
- Makefile: p1-gate / p1-gate-smoke targets; run-load-test.sh: LOADGEN_CORES
  taskset pinning (unpinned load-gen reports an artifactual ~9k/s ceiling).

Part of match#32 (P1.5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@emrebulutlar
emrebulutlar merged commit ebc4a59 into main Jul 3, 2026
1 check passed
emrebulutlar added a commit that referenced this pull request Jul 3, 2026
A 5-minute auto-snapshot firing while the storm has a node down or rejoining
is exactly the snapshot/housekeeping-with-a-member-down hazard (match#35) and
would strand a member mid-measurement. Suspend it at run start and restore
the prior schedule in the finally, alongside the market-gateway restore.

Follow-up to #44 (match#32 P1.5).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
emrebulutlar added a commit that referenced this pull request Jul 3, 2026
The first full 50-switchover run (20260703-224136) exposed a race: a status
read immediately after restart-node returns the CACHED pre-kill world (2s
poller), so wait_healthy_core passed in 0.0s, the pre-kill leader was
recorded (all 50 'disagreements'), and kills outpaced the OMS's reconnect —
it rejected 309k of 312k orders and the divergence numbers were measured
over near-zero in-flight traffic. The observer cross-check flagged it
(statusObserverAgreement=false), which is how this was caught.

wait_switchover_settled(killed) now requires, in order: the restart is
OBSERVED (killed node leaves HEALTHY or the leader moves off it), TWO
consecutive healthy-core polls, and an accepted canary order (dedicated
user 819999, far-from-market LIMIT, submit+cancel) proving OMS -> cluster
ingress is live end-to-end before the next kill.

Also: load-collapse guard in the report (no silent caps) — acceptance rate
below 50% marks loadCollapsed and fails harnessOk instead of presenting a
near-empty measurement as a valid baseline.

Follow-up to #44 (match#32 P1.5).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
emrebulutlar added a commit that referenced this pull request Jul 3, 2026
…51)

Run 20260703-233910 aborted at switchover 1 because the canary (BUY at
price=1) was PRICE_COLLAR-rejected for the whole 90s settle window. The
canary now SELLs 0.05 at mid*1.05: inside the 10% collar, resting (never
crosses), and clear of the FixedPoint negative-notional band (~$922-$1844,
match#30) that spuriously rejects ~3% of typical orders today.

README: run-sizing guidance for the OMS open-order slot leak found tonight
(500/user in-memory counter never decremented for bug9-lost terminals;
consecutive runs walled at 15001 -> 2356 -> 617 accepted). Restart OMS
before full runs; size users x 500 > orders x ~0.2 until P1.2 lands.

Follow-up to #44/#50 (match#32 P1.5).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant