📝 Headless forks Phase 2: smoke results and phase close

This commit is contained in:
2026-10-16 17:44:38 +02:00
parent fae6e1bd13
commit 3b1de6cc54
@@ -396,3 +396,48 @@ Gate after 2.3 (Athanor, 17:36): G-unit exit 0, `Ran 130 tests in 130.584s`, OK;
- Left for later: none for 2.3.
- Expected broken: none.
- Commits: `4b92b51` (code and tests), then this note's commit.
### Block 2.4 — Phase tests and live smoke
- Model: `claude-opus-5-5[1m]` (the Athanor, own Bash; no fallout agent needed)
- Start / end: 2026-10-16 17:36:23 +0200 / 17:44:04 +0200 (`date`)
- Phase-end tests: the full G-unit ran once after the last code change of Phase 2 (17:36, after 2.3): exit 0, `Ran 130 tests in 130.584s`, OK; G-where exit 0. No code changed after it, so per the new cadence it was not re-run.
- Live smoke per plan §7 "Phase 2 tests and smoke", scratch clone (HEAD `a54bb59`, clean), run log `…\headless-forks-p0\smoke2\2026-10-16-17-smoke2-run.md`, model `claude-opus-5-5`, every `wait` from Bash with `timeout: 600000`, briefs in `…\smoke2\brief-*.md`:
- `init` (defaults) → `train B1 --phase 1` → `wait` exit 0: `ok`, base context 23,676, $0.2099.
- `fork P1 --phase 1` (commit) → `wait` exit 0: `hit` (first read 23,674), clone commit `9002b6a`, $0.0997.
- `fork P2a --phase 2` from B1 → launch return `rebase_due: true`, `reasons: ["phase_boundary"]` (it ran anyway, as the flags are advisory: `hit`, $0.0163).
- `rebase --base B1 --as B2 --phase 2` → `wait` exit 0: `ok`, kind `rebase`, first read 23,674 (B1's prefix), $0.0336. `list`: B1 `superseded` (`superseded_by: B2`), B2 `active`, `parent: B1`, `lineage_rebases: 1`, `base_commit` `9002b6a`, context 25,279.
- `fork P2b --phase 2` from B2 (commit) → `wait` exit 0: `hit`, first read **25,277 of B2's 25,279**, `rebase_due: false`, clone commit `a0837be`, $0.0951.
- Ping: `init --warm-margin-s 3500` (config change after bases exist: `changed_fields: ["warm_margin_s"]`) so B2 turns `expiring` 100 s after its last hit. A `wait` at 17:41:57 ticked and launched ping `j0006` (`base_state: expiring` at launch); the next `wait` returned it in `pings` (not `done`): `ok`, `hit`, first read 25,277, $0.0087. B2's `last_hit` moved 17:40 → 17:42:00, state back to `warm`. A second ping `j0007` at 17:43:5x: `ok`, `hit`, $0.0052.
- `usage --phase 1 --format md`, `--phase 2`, `--block P1`, `--block P2b`, and json for the whole run all exit 0; outputs saved in `…\smoke2\usage-*.md|json`. Phase 1 md:
| Kind | Calls | in | out | cache write | cache read | cost |
|---|---|---|---|---|---|---|
| train | 1 | 4 | 855 | 23,674 | 16,913 | $0.2099 |
| fork | 1 | 12 | 1,888 | 3,892 | 153,622 | $0.0997 |
| total | 2 | 16 | 2,743 | 27,566 | 170,535 | $0.3096 |
Cold starts 0, cache-hit ratio 1/1, priced total $0.3096. Block P1 row: `| P1 | claude-opus-5-5 | eb446d8f | 9002b6a | 12 | 1,888 | 3,892 | 153,622 | $0.0997 |` (the Commit cell is the fork's real commit). Phase 2: rebase 1 ($0.0336), fork 2 ($0.1114), total $0.1450, hit ratio 3/3. Whole run (json, before the second ping): 6 calls, $0.4633, `reconciled: []`.
- All seven calls ran 2.1.299. **No visible window**: checked during ping `j0007` (supervisor, `claude.exe`, a `git.exe` child, three `conhost.exe`): no visible window of the tree and none on the desktop.
- Processes after the smoke (17:44, by command line `_supervise`, `forks-test-`, `smoke2`, `poscontrol`): none.
- Deviations from plan: the "let one base sit into expiring" step used the new `init --warm-margin-s` tunable (3500 s) instead of a 54-minute wait; the cache itself stayed on its real 1 h TTL, so the pings were real hits.
- Flagged for review:
- Pings have `phase: null`, so `usage --phase N` leaves them out; they appear only in the whole-run `usage`. The phase-close table therefore under-reports keep-warm cost unless the whole-run figure is pasted too.
- The superseded B1 still shows `base_state: expiring` in `list` (computed for every base); no ping went to it (`status` gate), as expected.
- Ping `j0006` read 25,277 of B2's 25,279 (`hit`); the P0.6 partial-ping case was not reproduced live (a 1-hour wait); the unit tests cover it.
- Commits: run log only (this note and the Phase 2 close).
### Phase 2 close
- Gate: G-where exit 0 after every block; between-block gates were full G-unit runs until the 17:36 cadence instruction (logged above).
- Tests: G-unit once at phase end (17:36) — exit 0, 130 tests, 130.6 s. Live smoke — every plan §7 Phase 2 criterion met (above). No fallout block.
- Flags for the reviewer (each with its block; details in the notes):
- Digest: `docs/workpad/plans/2026-10-16-16-headless-forks-phase2-contract.md` is Athanor-written and pins the ping rule details, the rebase/retrain reason vocabulary, `init` accepting changes after bases exist (replacing Phase 1's refusal), `--warm-margin-s`, and the block assignment of the folded items. Check it against the build plan.
- 2.1: read-only calls keep the previous TTL even when it was 300 (deviates from the digest's literal rule); `messages` also renames `wait`/`list` running fields; pings use the base's record if present; `wait` ticks at its start; naming a ping job in `wait` exits 2; activity definition (`run.last_wait_at`, fork/continue in the last 600 s); ping counting by job number, every status counts; `break_even` uses the 1 h ratio above 300 s; ping wall limit 300 s; a missing binary skips the base; the supervisor's tick pauses its loop 1–3 s; a ping's `last_hit` set at ping end; the M8 positive control opens minimised; a pre-existing `ResourceWarning` (stdout pipe left open in `Supervisor.run`); untested: a ping launched by a supervisor's own tick, a real `--max-turns 1` call through the helper (the smoke now covers this: `j0006`, `j0007`), POSIX.
- 2.2: `rebase` returns train's shape plus `parent`; the new base always records the binary the rebase ran under; `phase_boundary` follows the digest's "or" literally; a rebased base's phase is `--phase`; `delta_tokens` counts existing `*.md` paths in the brief; `lines` includes uncommitted changes; "last call" for `runtime_drift`; `defining:` field set (effort and allow/deny lists are not defining); the transcript read from the tail; `list` computes flags for active bases only (the smoke shows `rebase_due: false` on the superseded B1, consistent); `train` re-validates the whole record; a rebase's first event refreshes the old base's `last_hit` even if the rebase then fails; M11 has 2 s slack; untested: `rebase_conflict`, `defining:` for fields other than model, `train --cwd/--agent/--binary` overrides, bases created before 2.2, a real transcript, POSIX.
- 2.3: call counts include killed/lost calls; the md phase table omits zero-call kinds; R1 also reconciles a result whose registry entry still reads `running`; `usage` stamps the orchestrator call (not from a fork); `head_at_end` can include another fork's commit, so Commit is only shown for sequential forks; untested: a ledger with `rebase` calls (the smoke now covers this: phase 2 md has a `rebase` row), a real run (covered by the smoke), POSIX.
- 2.4: the three flags in its note.
- Not run / untested: the partial-ping refresh live; supervisor survival past the Athanor's hand-back; POSIX; a large base through the helper.
- Spend (Phase 2): live smoke $0.4685 client estimate (7 calls: train, 3 forks, rebase, 2 pings). Unit tests spend nothing. Subagent tokens: 2.1 320,462; 2.2 350,639; 2.3 187,248 (harness totals); the Athanor's own unknown.
- Processes at hand-back: none.
- Status: provisional until review, fix pass and re-check close.