# Margin Rescue evidence

Every file here is labelled by where it came from. Integers in JSON are decimal strings
of raw units (USDso and prices have 18 decimals; base sizes use each market's decimals).
`SHA256SUMS` lists a content hash for every file in this directory.

| Label | Meaning |
|---|---|
| `fixture` | Synthetic data or mocks; no network. Validates arithmetic and logic only |
| `fork` | A local fork (Foundry `forge` or `anvil`) of Hideki at a pinned block, running the REAL deployed venue contracts; accounts may be fresh test accounts or real accounts impersonated on the fork. Transaction hashes here exist only on that local fork |
| `live-read-only` | Calls (`eth_call`, `eth_getLogs`, `eth_estimateGas`) against the live Hideki RPC; nothing signed or sent |
| `live-write` | Transactions signed and sent on the live network, published only as checked bundles (`PUBLICATION.json`, `SANITIZATION.md`) with an independent read-back (`verification.json`). One so far: `live-write/run-1/`, live run 1 on 2026-10-28 (`VERIFIED_COMPLETE`) |

## Layout

| Path | Label | What it shows |
|---|---|---|
| `versions.json` | — | Node, npm, TypeScript, tsx, viem, SDK, Foundry, solc, forge-std commit, guard source hashes and bytecode size |
| `fixture/typecheck.txt` | fixture | `tsc --noEmit` |
| `fixture/npm-test.txt` | fixture | All TypeScript unit tests (Proving Ground and Margin Rescue): fixtures A and B, receipt binding and its 19 tamperings, recomputation with partial fills, funding drift and external changes, the pre-send refresh, the transaction ledger and journal on a stub chain (lookup timeouts on a mined transaction, unlocatable or self-located nonce consumers, located replacements, node rejections, foreign nonces), the cleanup bound and gas reserve, stop paging; in the fourth round also the command's exit codes under injected faults, the publication boundary and the static build's evidence gate, the independent verifier on a real-venue fork run replayed from its recorded chain answers (`test/fixtures/verify-fork-run.json.gz`), and the run states every view shows; in the fifth round also a failed transaction lookup that must not verify, the `live-write/` README scanned by the build, a recomputation without actual figures rendered as unavailable, and cleanup verified only with nothing remaining |
| `fixture/forge-unit-mock.txt` | fixture | Solidity unit tests with mocks: reentrancy, constructor validation, venue failure report, postcondition matrix and fuzz, action-id vector |
| `fork/forge-fork-tests.txt` | fork | Every Solidity fork suite at block 33472615: guard execution and preconditions, postcondition rollback, account ledger, raw venue semantics |
| `fork/trace-postcondition-rollback.txt` | fork | `-vvvv` call trace: the venue's fills and margin updates inside `placeOrderFor`, then `PositionFlippedOrIncreased`, then the revert of everything |
| `fork/trace-per-fill-bound.txt` | fork | `-vvvv` traces of the per-fill limit tests on both sides |
| `fork/e2e-33472615/` | fork | End-to-end on anvil: analysis of a real 6-market account, guard deployment, grant, refresh, journalled send, bound receipt, recomputation, a replayed confirmation and an expired quote |
| `fork/rehearsal-33472615/` | fork | The live executor with a throwaway key: `happy` (liveRun.ts as the live command), `tamper` (its own evidence altered), and injected faults: `book-change`, `partial-fill`, `owner-change`, `timeout` (then `--resume`), `rpc-outage` (the reduction is mined while receipt and transaction lookups time out; then `--resume`), `preflight-refusal` (existing collateral and allowance: refused, nothing signed), `cleanup-retries` (both legs need all three guarded attempts; 12 cleanup transactions against 12 reserved) `cleanup-fail` (every guarded BTC close is rejected in simulation, `WOULD_REVERT`, `tx: null`, so nothing is broadcast) and `result-unwritable` (the live command cannot write its result: exit 50, every transaction settled, nothing more sent). `happy` and `result-unwritable` run the live command in a private folder, copied here; `happy` is then read back by the independent verifier (`verification.json`, `verification.txt`). Each scenario directory holds the run ledger, the action journal, every snapshot, the recomputation, the cleanup report, `result.json` and `outcome.json` (expected vs observed checks) |
| `fork/rehearsal-33609475/funding-drift/` | fork | The same executor forked one second before a real hourly BTC funding settlement, with the clock moved across it between the analysis and the refresh |
| `fork/live-rehearsal-33472615/` | fork | **Superseded** history: the previous executor's rehearsal, whose cleanup used plain IOCs |
| `live-read-only/reconcile-<account>/` | live-read-only | Hash-pinned snapshots and field-by-field reconciliation of real accounts with 3, 6, 9 and 21 markets |
| `live-read-only/analysis-0x2E3631D9/` | live-read-only | Scenario (BTC −8%, ETH −12%, others at reference) and the candidate comparison for a real 6-market account |
| `live-read-only/stop-pagination.json` | live-read-only | Three accounts with more than 200 indexed stop records: the old single 200-row request against the paged listing, each stop checked on chain at the pinned block |
| `live-read-only/funding-settlement.txt` | live-read-only | The projected funding index around a real hourly settlement (flat, then one step at `lastUpdate + 3600 s`) |
| `live-read-only/rounding-study.json` | live-read-only | Every holder of every pool at one block, rebuilt with floor and with truncation |
| `live-read-only/live-plan.json` | live-read-only | The authorized live plan (`mr-live-plan/4`, read at block 34,756,532, SHA-256 `7f090328…ea3d1175`) for the dedicated test EOA: balances, markets, the guard build it is bound to, gas estimates, every call, bound and exit code. Executed once, as live run 1 (`live-write/run-1/`, where it is copied as `live-plan.json`) |
| `live-read-only/plan-recheck.txt` | live-read-only | The re-check before the run, after the fifth round's fixes: the test account untouched at block 35,044,107 (nonce 0 latest and pending, 50 STT, no position, order, stop or collateral, no code at the guard's address, no run of it in the private registry), the local guard build equal to the plan's hashes, and the plan regenerated with the current code at block 35,044,503 differing only in market data (BTC +0.33%, ETH +0.52%), the read block and the opening lots that follow from the price |
| `live-read-only/authorized/<sha256>.json` | live-read-only | Content-addressed copies of the plans authorized before a run; the site shows a live run as verified only if its read-back was made against one of them |
| `regression/` | live-read-only | The earlier Proving Ground commands still work (`test:live`, `snapshot`, `precheck`) |
| `live-write/README.md` | — | Live run 1 in one page: execution, rescue goal and cleanup reported apart, the fixed scenario and the candidates, every transaction and fill, the recomputation, gas and collateral, and how the run was verified and published |
| `live-write/run-1/` | live-write | Live run 1 on the test account (2026-10-28, blocks 35,213,160–35,217,219), as `mr:publish-run` copied it from the private run folder: the preflight, the analysis and its snapshot, the candidates, the scenario, the refresh, the action journal, the receipt and the recomputation, the cleanup report, the run ledger (all 13 transactions), the run log, the executor's result, the plan it ran under, the independent read-back (`verification.json`, `verification.txt`: 93 / 93 checks), `PUBLICATION.json` and `SANITIZATION.md` |

## How this round's fork evidence was produced

- `fork/rehearsal-33472615/`, `fork/rehearsal-33609475/` and `fork/e2e-33472615/` were run in parallel against one caching RPC shim (`SHIM_CACHE=1 node tools/rpc-shim.mjs 8556`, which only remembers state reads at an explicit past block). Each rehearsal scenario directory has `outcome.json` (every expected-versus-observed check), `result.json` and `results.jsonl` (the executor's result; `timeout/` holds both the stopped run and the resumed one), `run-ledger.json` (every transaction, persisted before broadcast), `journal/` (every confirmation, including invalidated and cleanup ones), the snapshots, `recompute.json`/`.txt`, `cleanup.json` and `run-log.jsonl`. Transaction hashes exist only on those local forks.
- `fork/forge-fork-tests.txt` (38/38) is from the second round and was not rerun in the third: the contracts are unchanged, and the third round changed only TypeScript (transaction resolution, refusal, cleanup reserve). It was produced on its own through the plain shim; a first attempt that ran it concurrently with the anvil forks failed in `setUp` on upstream `fetch failed` errors (no test logic ran), that output was discarded, and the shim now retries transport failures.
- Third round: `fixture/`, `fork/e2e-33472615/`, `fork/rehearsal-33472615/` (10 scenarios, including the new `rpc-outage`, `preflight-refusal` and `cleanup-retries`), `fork/rehearsal-33609475/` and `live-read-only/live-plan.json` (`mr-live-plan/3`) were regenerated from the final code.
- Fourth round (2026-10-27): `fixture/`, `fork/rehearsal-33472615/` (11 scenarios: the ten above plus `result-unwritable`; `happy` read back by the independent verifier) and `fork/rehearsal-33609475/` were regenerated from the final code, after the three review passes over this round's fixes (the last of which derives the rescue's and the cleanup closes' request nonces in separate domains), and `live-read-only/live-plan.json` (`mr-live-plan/4`); `live-read-only/plan-recheck.txt` verifies that plan against the final code and the chain. The verifier's replayed fork run (`test/fixtures/verify-fork-run.json.gz`, block 34,671,145) was recorded again from the final code as well; it keeps each transaction without its signature (`r`, `s`, `v`, `yParity`), so it holds no signed transaction, not even one of a throwaway fork key. Two passes of that regeneration were discarded. In the first, `funding-drift` was refused at its preflight because a dreamDEX indexer request failed (`fetch failed`; the executor exited 1 with nothing signed, as designed), and `result-unwritable` printed the disk's error with the repository's absolute path and left a temporary copy of `result.json`, which the build's scan would have refused. In the second, the indexer failed again during `timeout`'s analysis: the analysis was `BLOCKED`, nothing was reduced, both legs were closed through the guard, and the run ended `CLEANUP_INCOMPLETE` (exit 30) because the end state's stops could not be listed; the rehearsal then stopped on the missing reduction. Each cause was fixed with a regression test (`paths.ts` `localText`, `json.ts` `writeFileAtomic`, `common.ts` `readAgain`; the rehearsal now records a scenario that cannot reach its checks as failed instead of stopping), and the fixture logs, both rehearsals and the verifier's replayed run were produced again from that code. `fork/e2e-33472615/` and `fork/forge-fork-tests.txt` were not rerun: the contracts and the end-to-end path (the `mr` CLI's plan, refresh and recompute) are unchanged; this round changed the live command, the transaction sender's persistence, the publication, the verifier and the site.
- Fifth round (2026-10-28 UTC): `fixture/` and both rehearsals were produced again from commit `9fd1c0e` (`versions.json`), after its four fixes: `fork/rehearsal-33472615/` 11/11 (`happy` read back by the independent verifier: 93/93 checks, `GOAL_MET`) and `fork/rehearsal-33609475/` (funding drift) 1/1, run in parallel against one caching RPC shim. The previous round's rehearsal folders were moved out first, so nothing of the earlier runs remains in them. The verifier's replayed fork run (`test/fixtures/verify-fork-run.json.gz`) was not recorded again: the verifier makes the same chain reads as before (only what a failed lookup means changed), and the unit test that requires every read to be in the recording passes. The capturing shell printed one startup warning (`compdef:153: …`) before each command; that line was removed from `fixture/*.txt` and the two rehearsal consoles, and everything the commands printed is kept. `fork/e2e-33472615/` and `fork/forge-fork-tests.txt` were not rerun: the contracts and the end-to-end path are unchanged; this round changed the verifier, the build's evidence gate, the run-state model, the site's feeds and the app's run screen. `live-read-only/plan-recheck.txt` was made again from the same commit.
- Live run 1 (2026-10-28 UTC): the owner ran `npm run mr:live` on the authorized plan (`7f090328…ea3d1175`) in their own terminal, which held the test account's key, from the working tree at `83dc3f9` (its contracts, `src/` and `tools/` are those of `9fd1c0e`). The run's own preflight at block 35,212,668 (`run-1/preflight.json`, and the `preflight` line of `run-1/run-log.jsonl`) found the account as the plan expects: 50 STT, 100 USDso, no allowance, an empty bank account, no position, order or stop; the run ledger starts at nonce 0. The run wrote to the private folder `.margin-rescue/live/run-1` and ended `COMPLETE` (exit 0) after 13 transactions. `mr:verify-run` then read it back from the chain into that folder (93 / 93 checks), and `mr:publish-run` copied it to `live-write/run-1/` (the run folder's 24 files and the plan, all unchanged: they held no local path and no URL other than the public RPC, and no key, signed transaction or mnemonic; with `PUBLICATION.json` and `SANITIZATION.md`). The published copy alone was read back once more (93 / 93 at block 35,220,185). `live-write/README.md` summarises it.
- The throwaway keys of the rehearsals were generated in memory and never written; the "third party" that takes liquidity in the fault scenarios is a second fork-only account funded from the MarginBank's own USDso by impersonation.

## Reading the traces

Foundry names only events whose ABI it compiled; the venue's own events appear in the
traces as raw `topic 0` values. The ones that matter:

| topic 0 | Event | Emitted by |
|---|---|---|
| `0xd90f62f6…639d` | `OrderPlaced(uint128,(…))` | PerpPool |
| `0xc87f4223…a399` | `OrderFilled(uint128 taker, uint128 maker, uint256 qty, uint256 takerRemaining, uint256 makerRemaining, uint256 price)` | PerpPool |
| `0xf7816a37…82de` | `PositionUpdated(address account, address pool, int128 newSize, uint128 entry, int256 realizedPnl, int256 entryFundingIndex)` | MarginBank |
| `0xa1506168…ca85` | `FundingSettled(address account, address pool, int256 payment)` | MarginBank |
| `0x9d952b90…3335` | `CollateralLocked(address,address,uint256)` | MarginBank |
| `0x5c87c81b…2e1a` | `CollateralUnlocked(address,address,uint256)` | MarginBank |
| `0x11fa725a…0a0e` | `DepositedFor(address,address,uint256)` (a wallet pull; never seen on the guard's route) | MarginBank |

`c663a157(…)` in the traces is the bank's per-fill settlement call from the pool.

## Third-party accounts

The live read-only runs and the fork end-to-end use public testnet accounts that hold
several markets (for example `0x2E3631D9c6497103BE981Fe3a48B11ba06fDB745`). They are read
from public chain state only; on the fork the account is impersonated locally and
nothing is sent to the network on its behalf.
