# Settlement race runtime evidence

No test runner was used as evidence.

## Environment

Both commits ran from separate detached worktrees using `vp i` and
`T3CODE_DEV_SEED=0 vp run dev`, on Linux, with each worktree's freshly created
isolated database. The same synthetic project, replay fixture and driver were used.
The recordings show the driver's real observations from each running server,
in Ghostty under `headless-desktop`, at 1920 x 1080, with identical dark colors
and 14-point text. This is server evidence, not a recording of the web UI.

## Controlled scheduling

The race cannot be reliably won manually. `hook.mjs` loads `control.mjs` into
the actual server process using Node's load hook. It adds a loopback-only driver
endpoint and pauses the terminal-run completion reaction **before** its normal
queue-promotion work. It does not modify settlement decisions, provider execution,
events, projections, clocks or the settlement worker. The replay turn completes
through the actual provider adapter and runtime. The normal settlement worker
then competes against the delayed completion reaction. Release permits the
original completion reaction to proceed.

The driver sends the internal watch-sync command that the watch reactor sends,
including its monitor notification. It writes the synthetic linked pull request's
open and merged snapshots through the server's commands. It does not create or
merge a real external pull request and does not exercise forge polling.

## Same interaction, both commits

1. Enable Settle on merge and disable inactivity settlement.
2. Create a synthetic thread, link an open pull request and enable its watch.
3. Start a real replay-provider turn; deliver the watch update behind that active
   run and verify that the resulting wake is queued.
4. Synchronize the merged snapshot before the active run completes.
5. Let the replay turn complete naturally; pause only its completion reaction.
6. Allow four wall-clock seconds for the normal automatic-settlement worker.
7. Read persisted server projections, release the reaction, and observe eight
   more seconds of run and session state.

Before: the worker settles, cancels the wake and detaches the session. Releasing
promotion does not start the cancelled wake.
After: the worker refuses early settlement, retains the queued wake and session;
release starts the wake, which completes before the thread settles normally.

## Running the uploaded driver

Place hook.mjs, control.mjs, driver.py and record.sh together in a scratch folder.
Create an empty Git repository in that folder's `sample` subdirectory. In each
checkout run (substitute its control port and paths):

```sh
T3CODE_DEV_SEED=0 EVIDENCE_CONTROL_PORT=<port> \
  NODE_OPTIONS='--import=<scratch>/hook.mjs' vp run dev
node apps/server/src/bin.ts project add --base-dir .t3 \
  --title 'Watch notification evidence' <scratch>/sample
headless-desktop <scratch>/record.sh <before-or-after> <port> <project-id> <commit>
```

`driver.py` writes each run into a new timestamped folder. The `.cast` files
are timed terminal transcripts in asciicast v2 format. The `.txt` files are the
same observations without terminal timing metadata. `record.sh` captures real
X11 terminal output to MP4 using ffmpeg; it stops its captured ffmpeg PID.

A supplemental head run uses `EVIDENCE_HOLD_SECONDS=185` with the same driver
to keep promotion paused past the two-minute grace period. The normal periodic
settlement sweep is permitted to expire the queued wake.

## Limits

This proves the settlement-before-promotion ordering using an explicit scheduling
gate. It does not measure how often that ordering occurs without instrumentation.
External forge polling and a physical merge were replaced with synthetic watch
and linked-pull-request commands. Desktop and mobile clients were not exercised.

AI-assisted; verified with the tests and tools listed above.
