diff --git a/.claude/skills/mission-control/SKILL.md b/.claude/skills/mission-control/SKILL.md index 3f89f31c5..141d48a6c 100644 --- a/.claude/skills/mission-control/SKILL.md +++ b/.claude/skills/mission-control/SKILL.md @@ -960,6 +960,18 @@ the PREVIOUS iteration's stamp — if the last iteration's own record is missing stale copy, not a charter awaiting your entry. One command, and it is the difference between appending history and erasing it. +**SPELL THE TELL IN THE CHARTER'S OWN CASE, AND PAIR IT WITH A CONTROL** (added 2026-08-03 +iteration 134). Stamps are written `ITERATION 133` — **UPPERCASE** — while the sentence above says +"the previous iteration's stamp", so the natural transcription is `grep -c "Iteration 133"`, and +that returns **0** on a perfectly healthy charter. Iteration 134 ran exactly that and read `0` for +a charter that was byte-identical to origin. This is rule 3a's trap wearing THIS gate's clothes, +and it is the worst place for it: a broken tell and a genuinely stale charter produce the +identical output, so the failure routes a healthy iteration down the stale-copy path — or, in the +other direction, teaches you to distrust a tell you will need for real. Run it as +`grep -c "ITERATION "` **alongside two controls in the same breath**: a known-present one +(`ITERATION `, must be ≥1) and a known-absent one (`ITERATION 999`, must be 0). A `0` on the +known-present control means your instrument is broken, not that the charter is stale. + **THE STATUS ROTATION IS THE MOST DANGEROUS EDIT THIS LOOP MAKES — SCRIPT IT WITH A LINE-COUNT ASSERTION, NEVER A BARE `## `-HEADER SCAN** (added 2026-08-01 iteration 127; third failure of this same step — iter-83 hand-corrected an already-drifted N>4, iter-123 found the block drifted to 4 diff --git a/design_docs/v1-mission-log.md b/design_docs/v1-mission-log.md index 75bef6a4f..9156b7732 100644 --- a/design_docs/v1-mission-log.md +++ b/design_docs/v1-mission-log.md @@ -7320,3 +7320,35 @@ The Fable designer specified the option-(c) bound as two budgets (`recordedDrain **Next** — **execute S1** (`sprint_M-RECORDED-STREAM-API-S1.json`, validator rc=0, 5 milestones / 3.75 d): executor `codex:gpt-5.6-sol` in a worktree that is **not** under `/tmp`, evaluator `sonnet` (distinct provider → generator≠judge holds). Then `m-mcp-exact-tool-surface` Lane B (Mark's pick #2, and a release ask for Ailang World when it lands), then the two quota offloads. **Parked for human — ONE decision, and it is the planner's ruling, not a request to re-litigate Mark's.** Dropping the sentinel means the drain budget bounds post-failure **work** (O(1)/chunk, zero retention) but not post-failure **wall-clock**; the call returns when the provider's stream ends, on a path unreachable for any `StreamChunk` constructible today. Accept? If no, the only remaining mechanism is a cancellable provider context — the already-rejected option (b) — which becomes a blocking dependency and makes this multi-sprint. `#558` (durable driver self-re-exec), `#554`'s root cause, `#561` and `#563` remain open. + +--- + +## 139 — 2026-08-03 — Iteration 134: **dev CI was RED and the cause was a test helper whose own doc comment was false.** `cmd/ailang` re-linked the same 93 MB binary ~16× inside a 300s budget; on the Windows runner that package went **`FAIL 300.527s` → `ok 83.177s`**. PR **#564** → `3c28cc322`. + +**Picked** — **NOT the queue head.** Gate 1's per-workflow CI read found `CI: completed/failure @ 773894d87`, i.e. dev HEAD itself, and a RED dev outranks the queue. The displaced pick (`m-recorded-stream-api` S1, plan-ready from iteration 133) is untouched and stays next. + +**Reality check** — the red was **not** caused by the commit it landed on. `773894d87` is **docs-only** (`git show --stat`: one design doc, one sprint plan, one JSON — zero Go files), and `test-windows` was green on the previous **11 of 12** dev runs (job wall 337–617s). The failure was `panic: test timed out after 5m0s`, package `cmd/ailang`, stack parked in `buildAilang` → `exec.Cmd.CombinedOutput` → `go build`. Both CI jobs run `go test -timeout 300s ./...` (`ci.yml:74` linux, `:318` windows). So: a package that had been sitting just under its ceiling, tipped over by a slower runner. **The instrument nearly lied first** — a `grep -E "^\s*(--- FAIL|FAIL|panic:)"` over the 99 KB job log returned **nothing**; treated as a claim rather than a fact (rule 3a), a known-positive control (`grep -c "ok "` → 105) proved the log was intact and a widened case-insensitive search found the panic immediately. + +**The find** — `cmd/ailang/main_test.go:430` carried the comment *"buildAilang builds the ailang binary once per test run"*. **The comment was false**: no memoization, every call ran a full `go build` into a fresh `t.TempDir()`. Measured warm (compile-cached) link cost on this Mac: **5–6 s** for a **93 MB** binary, 3/3 runs. **14 call sites**, one per top-level test, none in loops. And the same package linked the same binary twice more — `serve_api_mcp_surface_test.go:29` with its own `go build -o … "."`, and `budget_scoping_e2e_test.go`'s `budgetBin`, **which was already correct** (`sync.Once` + a persistent `os.MkdirTemp` dir, with a comment explaining that `t.TempDir` is torn down when the *first* caller returns and would delete the shared binary). So the right pattern already existed in the same file tree, twelve lines of it, unused by its sibling. That made this Principle 3 (systemic fix, audit before patching) rather than three patches: one `sync.Once` builder, all three paths routed through it, `TestMain` cleaning up after `m.Run()`, signature unchanged so **no call site moved**. The 300s timeout was deliberately **not** raised and nothing was skipped — it is a real hang-detector. + +**Shipped** — PR **#564** → squash **`3c28cc322`**, 2 commits (fix + changelog). Evaluator **sonnet PASS 91/100 round 1, zero blocking**, one NB (missing `[Unreleased]` entry) **actioned** rather than waved through. Measurements, all first-party: + +| | before | after | +|---|---|---| +| `cmd/ailang`, this Mac (controller, **outside** the codex sandbox) | `ok 110.833s` | `ok 15.487s` (**7.2×**) | +| `cmd/ailang`, **windows-latest runner** | `FAIL 300.527s` (timeout) | **`ok 83.177s`** | +| `test-windows` job wall | 536s | 337s | + +86% of the package's runtime was redundant re-linking. The Windows row is the one that matters and it is a **measurement, not an extrapolation** — pulled from the PR's own job log, not scaled from the Mac. + +**Ruled out** — three hypotheses, each refuted by measurement rather than argument. (1) *"The merge broke it"* — refuted: docs-only diff, and the two `go test ./...` failures in the worktree were both proven external. (2) *`internal/effects` `TestNetHttpPost` is a regression* — refuted: reproduces **identically on unmodified `origin/dev`** in the main checkout (httpbin.org **503**), i.e. `#561`, filed by iteration 133. (3) *`internal/smt` `TestSolve_HardTimeout_FakeSolverIgnoringT` is a regression* — refuted, and this one needed real work because it **passed** on the base and **failed** in my worktree, which is exactly the shape a genuine regression has. Isolated: **3/3 pass alone** in the *modified* worktree, and the diff touches **zero files outside `cmd/ailang`** (control: the changed-file list printed alongside). The evaluator then found the leg I had missed — the file carries **`//go:build !windows`** (verified first-party, control: its sibling `solver_test.go` has no tag), so it cannot run on the failing job at all. A load flake under `./...` parallelism, pre-existing. + +**Also ruled out — two local "failures" that were the repo's own guards working.** CI's anti-silent-skip gate appeared to fail locally: 2 of its 3 required tests printed no `--- PASS:`. Not a regression — `TestRunSmokeInTempDir_Pass` skips without `bin/ailang` (absent in a fresh worktree; CI builds it first), and `TestPromptCommand_Piping` skips via `internal/testutil.RequireAilangOnPath`, which **skips when the on-PATH binary is older than the newest Go source** — and I had just edited `main_test.go`. Both PASS once the environment matches CI, proven with a PATH-scoped scratch binary rather than by overwriting the shared `~/go/bin/ailang` that the rig's evals use. That guard is Gate 2's verification-protocol step 1 in mechanical form, and it correctly fired on me. + +**Routing evidence** — model=**claude-opus-5** (controller) task-class=**execute** round1-score=**91** rounds=**1** corrections=**1** (changelog NB actioned) provider=**codex** agent=**codex** cost=**quota-bucket:codex-chatgpt**. Executor **FIRED**: `codex:gpt-5.6-sol`, 1-token probe rc=0, bounded 30-min cap, `--sandbox workspace-write`, 60,751 tokens; `codex login status` → *"Logged in using ChatGPT"*, so the subscription bucket, **not** the metered key (`OPENAI_API_KEY` is set but does not win — checked with the safe `[ -n … ]` form, never the value-printing `${VAR:+…}` shape). Evaluator **FIRED**: `sonnet`, pinned — **generator≠judge holds** (codex/OpenAI executor vs Anthropic judge, different providers). Designer/planner **NOT fired** (a CI hotfix needs no doc or plan), so the designer rotation correctly did **not** advance, staying at `claude:claude-fable-5`. `metered=$0.00` of the `$5` ceiling. **Sandbox rule honoured**: codex reported its `go test ./cmd/ailang` as `UNINFORMATIVE UNDER SANDBOX` (an unrelated `httptest` loopback bind denial) and the controller re-ran every gate outside the sandbox — mandatory here, since the diff touches `cmd/*`. + +**Gate hygiene** — Gate 0/1 clean: kill switch armed, billing **CLEAN**, gh account `sunholo-voight-kampff`, **ZERO** open `[nightly-eval]` alarms (control-verified: the same search returns hits under `--state all`, so the instrument sees positives), no new Mark comment (watermark `2026-08-03T07:04:45Z` already on his last), no rotation due (`#559` created 05:08:48Z = 07:08 CEST, *after* today's Monday 07:00 **local** boundary; 4 comments < 80). Inbox: 6 messages, all eval-suite telemetry plus mission-world's iteration-43 report (informational, no ask) and our own iter-133 report — no directive, no regression; acked. **Gate-1 trap did not fire, 3rd consecutive**: `dev` == `origin/dev` == `773894d87` and the running `SKILL.md` byte-identical to origin (`cmp` silent). **The cheap tell caught my own instrument**: `grep -c "Iteration 133"` on the charter returned **0**, which reads exactly like a stale copy — the charter writes stamps in **UPPERCASE**. Re-run case-correctly it is 1, with controls (`ITERATION 132` = 2, `ITERATION 999` = 0). A case-sensitive grep is an instrument, and this one would have sent a healthy iteration down the stale-charter path. + +**Retro lane** — **skill-fix**, see below. Also: Gate-4 writes were made from a **worktree branched from `origin/dev`**, not in place, because merging #564 left local `dev` 1 behind — the routine post-merge state, not a divergence (zero local commits ahead). + +**Next** — `m-recorded-stream-api` **S1** (`ailang#546`), plan-ready since iteration 133, sprint JSON validated rc=0: executor `codex:gpt-5.6-sol` in a worktree **not** under `/tmp`, evaluator `sonnet`. Unchanged by this iteration. diff --git a/design_docs/v1-mission-status-archive.md b/design_docs/v1-mission-status-archive.md index 8517b0368..9cda8c6db 100644 --- a/design_docs/v1-mission-status-archive.md +++ b/design_docs/v1-mission-status-archive.md @@ -1,5 +1,7 @@ # V1 Mission — STATUS stamp archive (rotated out of the charter) +## STATUS 2026-08-03 — ITERATION 131: **`#558` FILED — every launchd job executes its entry-point script from the SHARED MAIN CHECKOUT's working tree, which is 10 commits behind `origin/dev`, so `#556`'s qwen3.5 retirement LANDED on 2026-08-01 and never reached the rig. This morning's nightly ran the retired model 24/24, two days after Mark's directive.** Pick rationale: NOT the queue head. Mark's dated quota-offload directive re-armed at **07:00 today** and `m-planner-codex-lane` is plan-ready — but characterising the inbox's INVALID nightly surfaced a live regression, and Gate 0.4 ranks that above the queue. It also **blocks the directive itself**: that sprint's HIGH-risk milestone edits `tools/launchd/mission-control.sh`, one of the four launchd entry points executed from the stale tree, so it would land green and change nothing about which model the planner runs on. Gate 0/1 clean: kill switch armed, billing **CLEAN**, gh account correct, dev CI **GREEN** per-workflow on `d847082726` (CI + Build-and-Release + Docs-Deploy all success), **ZERO** open `[nightly-eval]` alarms (control-verified: the same search returns **30** under `--state all`, so the instrument sees positives), **no new Mark comment** (watermark `2026-08-01T06:54:07Z`, iter-130's directive already actioned). **ROTATION DUE AND PERFORMED** — first time the local-timezone rule fired affirmatively: 07:01 CEST is past the Monday 07:00 *local* boundary and `#484` was created 2026-07-27, before it (45 comments < 80, so the time condition alone carried it). `#484` closed → **`#559`**; state files updated, `-prev` set for next iteration's predecessor read. **GATE-1 TRAP FIRED AGAIN** (4th consecutive): local `dev` **1 ahead / 10 behind**, its ahead-commit `9e742037a` still the duplicate of upstream `167c55e6a`; the working-tree charter carried **zero** occurrences of ITERATION 130 (control: 3 stamps present), so an in-place Gate-4 edit would have deleted 127/128/129/130. All writes done in a worktree branched from `origin/dev`. The running `SKILL.md` was byte-identical to origin (`cmp` silent) — iter-128's fix still holding. **THE FIND, and the mechanism is narrower and more interesting than "the checkout is stale".** The nightly is *otherwise correctly pinned*: `nightly-eval.sh:62-87` fetches origin and rebuilds a throwaway worktree at `$HOME/.ailang-nightly/worktree` pinned to `BUILD_REF=origin/dev`, and the `ailang` binary, the benchmarks and `tools/nightly_classify.py` all run **from that fresh worktree**. Line 12 of the script says so in its own words: *"isolated git worktree pinned to committed origin/dev — never the live working tree."* **So the pipeline pins everything except the one file it cannot pin — itself.** launchd invokes `/Users/…/ailang/tools/launchd/nightly-eval.sh` directly (plist verified), and that copy still read `MODEL="opencode-qwen3-5-35b-a3b-mxfp8"` at line 120 while origin read `qwen3-6` at line 129; `/tmp/ailang-nightly-eval.log` confirms **24/24 trials on qwen3.5** this morning. A second, independent symptom corroborates the split-version state: `#551` added a 6th tab field to the classifier's `INVALID` record, the **fresh** classifier emits it and the **stale** driver still parses `$2..$5`, so today's alert printed the old `infra-tainted 6/12` banner and silently dropped the category. ⚠ **I GOT THIS WRONG ONCE AND CAUGHT IT — the correction is the load-bearing part.** My first read was that `#551`'s `RUN_UNMEASURED_CATEGORIES` gate was also inert, from a grep of the main checkout's `nightly_classify.py` that came back empty with a firing known-positive control. The grep was honest; the **object** was wrong — that copy is never executed. That is rule 3c (*a probe identifies what you REACHED, not what you NAMED*) applied to a FILE rather than a service, and it is the same error as the bug under investigation, made while investigating it. The gate is live. **CONTAINMENT APPLIED, and deliberately not called a fix**: restored `nightly-eval.sh` + `nightly-lang-eval.sh` from `origin/dev` — both had **zero** local edits (`git status --porcelain` on those paths empty while repo-wide showed 7), so nothing was destroyed, no branch/reset/stash/pull was involved, and Principle 0's four named operations were all avoided; unstaged afterwards so a sibling's `git add` cannot sweep staged content; both verified **byte-identical to origin** and `bash -n` clean. Tonight's nightly is the first genuine qwen3.6 run. This is a per-file patch of a systemic defect — the durable fix (each driver re-execs itself from the pinned worktree, reusing machinery `nightly-eval.sh` already has) is proposed in `#558` and carries a chicken-and-egg caveat: landing it does not help until the main checkout receives it **once**. **Blast radius measured, not assumed**: four launchd entry points run from the main checkout — `nightly-eval.sh` and `nightly-lang-eval.sh` were stale, `mission-control.sh`, `rig-watchdog.sh` and `os-rotation-filler.sh` are not (unchanged in the missing 10), and `dev.ailang.mission-world` points at a different repo entirely. **Routing evidence**: designer/planner/executor/evaluator **all NOT fired** — triage + containment, zero product code changed, no design doc, no quorum; the designer rotation correctly did NOT advance, staying at `codex:gpt-5.6-sol`. Controller on the session model (quota bucket). `metered=$0.00` of the `$5` ceiling. **THIS IS THE THIRD MEASURED HARM FROM ONE DIVERGENCE** — iter-128's stale *skill*, iter-129's stale *charter*, and now the stale *driver*, which is the first to defeat an explicit human instruction. **PARKED FOR HUMAN — the reconcile is now the blocking ask**, not a hygiene note: it gates the quota-offload directive Mark dated to this morning. `#557` (two ollama servers on :11434) and `#546`'s a/b/c remain open. + ## STATUS 2026-08-01 — ITERATION 130: **Mark's directive executed — the qwen3.5 RETIREMENT LANDED (PR #556), but the SECOND HALF ("Restart ollama") is DELIBERATELY NOT DONE, because characterising it uncovered that the rig has been running TWO ollama servers on port 11434 since the 21 Jul reboot — `0.31.2` on IPv4 and `0.32.1` on IPv6 (`#557`).** Pick rationale: a **human directive outranks the queue** (Gate 0.5) — Mark commented on `#484` at `2026-08-01T06:54:07Z`: *"Remove qwen 3.5 only use qwen 3.6. Restart ollama"*, which is his answer to iteration 129's DECISION-1. Note he **overrode** iter-129's refutation of the qwen3.6 switch and asked for it anyway *plus* the restart; the refutation still stands on its measurement (the switch would not have prevented either outage) and was NOT relitigated — a directive sets priority, not truth. Gate 0/1 clean: kill switch armed, billing **CLEAN**, gh account correct, dev CI **GREEN** per-workflow on `9a50c569a`, **ZERO** open `[nightly-eval]` alarms (control-verified: the same search returns 50 in `--state all`, so the instrument sees positives), no rotation due (`#484` created Mon **07:27 CEST**, after the 07:00 *local* boundary; 45 < 80). Watermark advanced to `2026-08-01T06:54:07Z` **before** routing. **GATE-1 TRAP FIRED AGAIN, and iter-129's new rule caught it**: local `dev` was 1 ahead / 9 behind, its ahead-commit `9e742037a` a duplicate of upstream `167c55e6a`; the working-tree charter's newest stamp was **ITERATION 126** while origin carried 127/128/129 — so an in-place Gate-4 edit would have deleted three iterations. All writes done in a worktree branched from `origin/dev`. The running `SKILL.md` was byte-identical to origin (`cmp` silent, 80493 B) — iter-128's fix still holding. **THE SHIPPED WORK**: `os-rotation-filler` had already dropped qwen3.5 on 2026-06-15, so `nightly-eval.sh:120` was the LAST driver still pinning it — the regression guard itself. Swapped six sites to `opencode-qwen3-6-35b-a3b-mxfp8` (`nightly-eval.sh`, `nightly-lang-eval.sh`, `embedder-ab.sh`, `pi-ollama-models.json`, its README, the plist dependency note). **MEASURED BEFORE SWAPPING** — the swap does not blind the guard: `eval_baselines` in `observatory.db` gives qwen3.5 **61 benchmarks / 58 adaptive-eligible** vs qwen3.6 **60 / 44**, because the OS rotation has been banking qwen3.6 since 06-15; so 44 benchmarks keep adaptive mean+2σ thresholds on day one and 16 fall back to the fixed ceiling until they accrue 5 passing samples — self-healing, and it was the only real risk. models.yml qwen3.5 entries **deliberately KEPT** with RETIRED banners: **2,438 banked pass-trials** are attributed to those ids and deleting them orphans the cost attribution (Principle 2 — no silent data loss). **THE FIND, and it is bigger than the errand.** Verifying the restart, `ollama --version` said server `0.31.2` while `curl localhost:11434/api/version` said `0.32.1`. That contradiction is the whole iteration: measured stable **6/6**, `127.0.0.1:11434` → **0.31.2** (launchd `dev.ollama.serve`, pid 1075, ppid 1) and `[::1]:11434` → **0.32.1** (`Ollama.app` Electron, pid 1351, ppid 1340) — two servers, same port, different ADDRESS FAMILIES, both up since **Tue 21 Jul 10:27** (the post-kernel-panic reboot), sharing `~/.ollama` but holding **separate GPU state** (`/api/ps`: embeddinggemma on one, qwen3.6 on the other). The live rotation eval's runner (pid 98152) is a child of **1351**, so evals reach the IPv6 server while the CLI reaches the IPv4 one — which is why `ollama ps` showed an idle GPU with a 37 GB model resident. The harness connects via **`localhost:11434/v1`**, **not pinned to a family**, so which server (and which tool-calling implementation) an eval reaches depends on the client's dual-stack dial order. Filed `#557` and cross-linked from `#554` as a **falsifiable MECHANISM, explicitly NOT an established cause**. **WHY THE RESTART WAS PARKED RATHER THAN DONE** — this is a deliberate refusal, not an omission: Mark authorised restarting *one stale server*; what exists is two servers under two process managers, and `rig-watchdog.sh` probes `localhost` (→ IPv6, server B) while it kickstarts `dev.ollama.serve` (→ server A, the **0.31.2** one), so a naive restart could heal the rig onto the OLDER version or leave it down over a weekend with no human present. A rotation eval was also mid-run holding the rig lock (acquired 09:17:51Z), and restarting would have injected fake `api_error` rows into the very error-category stream `#554` is investigating. The rig is currently WORKING (6/6 and 7/7 nightlies this morning), so the split brain — live for 11 days — can wait for a human. **Routing evidence**: designer/planner/executor/evaluator **all NOT fired** — a directive-driven config change whose decisions (registry-vs-rotation scope, baseline safety) were controller measurements, and whose edits were deterministic substitutions the skill classes as mechanical; the designer rotation correctly did NOT advance, staying at `codex:gpt-5.6-sol`. Controller on the session model (quota bucket). `metered=$0.00` of the `$5` ceiling. **Gate 3b GREEN SHA-addressed** on PR #556. **PARKED FOR HUMAN — the ollama split brain (`#557`) is the new ask**, with a concrete four-step remediation; `#546`'s a/b/c and the main-checkout reconcile remain open. ## STATUS 2026-08-01 — ITERATION 129: **TRIAGE ITERATION — `#554` FILED. The nightly `non_agentic` outage is a RECURRING ollama TOOL-CALL EMISSION COLLAPSE, not the qwen3.5 lane — and Mark's own proposed remedy ("switch the nightly to qwen3.6") is REFUTED BY MEASUREMENT, because qwen3.6 collapsed by the identical mechanism on 07-29.** Pick rationale: NOT a queue item. `#546` stays PARKED on Mark's a/b/c (Standing rule 2); the seed sprint's M2/M3 and both quota offloads remain date-gated to the 08-03 07:00 re-arm; LANE B1's own row requires `#535` (= the date-gated M2) to land first or alongside. That leaves iteration 128's open ask — a live, ongoing outage of the mission's PRIMARY DATA INSTRUMENT — as the highest-value work, which Gate 0.4 ranks above the queue. Gate 0/1 clean: kill switch armed, billing **CLEAN**, gh account correct, dev CI **GREEN** per-workflow on `b3f628ed8` (CI + Build-and-Release success; Docs-Deploy success on `f64659b12`, path-filtered = N/A for later commits), **ZERO** open `[nightly-eval]` alarms (control-verified: the search returns 5 CLOSED, so the instrument sees positives), **no new Mark comment** (control-verified: exactly **1** comment ever by `MarkEdmondson1234` on `#484`, at `2026-07-27T07:53:53Z` = the watermark, already actioned), no rotation due (`#484` created Mon **07:27 CEST**, *after* the 07:00 local boundary; 43 < 80). **GATE-1 TRAP CAUGHT, AND IT WAS LIVE THIS TIME.** Local `dev` was **1 ahead / 8 behind** origin — the ahead-commit `9e742037a` is iteration 126's record already upstream under a different SHA (`167c55e6a`), so nothing was lost and the shared tree was left untouched (Principle 0). Critically, the working-tree charter carried stamps **123/125/126** while origin carried **126/127/128**: a Gate-4 edit made in place would have **silently deleted iterations 127 and 128's STATUS records**. This is the diverged-checkout class one step further along than iter-128 measured it — that iteration proved the *running skill* was stale; this one proves the *charter the loop writes to* is stale too, and the failure mode is a mass deletion that reports success. All Gate-4 writes were therefore done in a worktree branched from `origin/dev`. The **running skill matched origin byte-for-byte** (`cmp` silent, 78454 B both) — iter-128's fix is holding. **THE FIND — four hypotheses refuted, each first-party.** Triaging iteration 128's parked ask, I built a longitudinal instrument out of **opencode's own session DB** (`~/.local/share/opencode/opencode.db`, ~1.0 GB) and measured per-session tool-emission rate: qwen3.5 scored **100 / 100 / 98.8 / 25.9 / 98.8 / 100 / 12.0 %** on 07-26…08-01. So the collapse is **RECURRING and INTERMITTENT, not new** — 07-29 was the SAME mechanism, and that is the night whose four bogus filings (`#520`–`#523`) iterations 118/119 diagnosed as an `api_error` serving failure. One mechanism, two different `error_category` labels, two separate investigations. Failing sessions end `reason: "stop"` — a **clean stop, NOT truncation** — after ~232 output tokens with **zero tool parts**, the model's own text stopping mid-sentence exactly where a tool call belongs ("Let me first read the existing solution file to see what's there:"). **REFUTED (1) lane-specific to qwen3.5** — on 07-29 hour 00 qwen3.**6** ran **18** sessions with **1** emitting tools; all 17 failures `reason=stop`, avg **236** output tokens, the same shape as qwen3.5's 232. *This is the load-bearing refutation: it answers Mark's open question with data — switching the nightly to qwen3.6 would not have prevented either outage.* **REFUTED (2) prompt-size / context overflow**, which was my own leading hypothesis and looked strong (input 41,217 sits suspiciously near a 40960 `num_ctx`): holding first-step input ≥41,000, the *same* ~41,260-token prompt yields **83/84** (07-30) and **108/108** (07-31) but **21/81** (07-29) and **2/24** (08-01) — identical size, opposite outcome — and successful sessions reach **113,373** input tokens. The first cut of this test was WRONG and I caught it: aggregating `max` input per session conflates multi-turn growth with prompt size, so it had to be redone on the FIRST step-finish to be apples-to-apples. **REFUTED (3) model rot / missing model** — the blob is present and unchanged for 8 weeks, and scored 100% the night before. **REFUTED (4) harness/opencode change** — same opencode `1.15.7` either side, with an **identical 12-tool registry** resolved in good and bad sessions. **NOT ESTABLISHED, and deliberately not claimed**: the root cause itself. It is temporal and environment-level, pointing at ollama serving state; same-hour co-residency of the two 37 GB models is **not** cleanly predictive (08-01 hour 01: qwen3.6 **2/2** while qwen3.5 was **3/25**), so contention is a hypothesis I explicitly refused to assert. One unverified lead handed over: the ollama **server** is `0.31.2`, up since **Tue Jul 21** (11 days), against an installed **client** of `0.32.1`. **Byproduct worth more than the incident**: the eval harness's own `error_category` labelled these two identical-mechanism nights *differently* (`api_error` 07-29, `non_agentic` 08-01), while tool-emission rate separates "we failed to measure" from "the model failed" cleanly — and the opencode DB retains history the `/tmp` run dirs reap after ~5 days. **Zero code changed; no sprint routed** — the root cause is ops-side and the remedy is a human action, so inventing an AILANG-lane fix would have been the wrong lane (PROGRAM.md routing). Designer/planner/executor/evaluator **NOT fired** (triage-only iteration, no doc, no quorum), so the rotation correctly did NOT advance. `metered=$0.00` of `$5` — controller quota-bucket only. **PARKED FOR HUMAN — one ask, now ANSWERABLE**: restart the ollama server (ideally onto 0.32.1) and re-measure the rate table in `#554`; it is cheap and directly falsifiable. `#546`'s a/b/c remains the other open ask, and the shared main checkout still needs its interactive reconcile. diff --git a/design_docs/v1-mission.md b/design_docs/v1-mission.md index d20ca2b90..ff1baf963 100644 --- a/design_docs/v1-mission.md +++ b/design_docs/v1-mission.md @@ -58,12 +58,12 @@ newest 3 to the archive top, newest-first — do not assume exactly one over-cou Rationale: every iteration re-reads this charter — 30+ stamps were ~500 lines of history tax per read, on the scarcest model budget. The append-only history lives in the log + archive. +## STATUS 2026-08-03 — ITERATION 134: **dev CI WAS RED AND THE CAUSE WAS A TEST HELPER WHOSE OWN DOC COMMENT WAS FALSE.** `cmd/ailang` re-linked the same 93 MB binary ~16× inside a 300s budget; on the Windows runner that package went **`FAIL 300.527s` (timeout) → `ok 83.177s`**. PR **#564** → squash **`3c28cc322`**, evaluator **sonnet PASS 91/100 r1, zero blocking**. Pick rationale: **NOT the queue head** — Gate 1's per-workflow read returned `CI: completed/failure @ 773894d87`, dev HEAD itself, and a RED dev outranks the queue; the displaced pick (`m-recorded-stream-api` S1, plan-ready from iter-133) is untouched and stays next. **The red was NOT caused by the commit it landed on**: `773894d87` is docs-only (zero Go files) and `test-windows` was green on 11 of the previous 12 dev runs — a package sitting just under its ceiling, tipped over by a slower runner (`go test -timeout 300s ./...`, `ci.yml:74` linux / `:318` windows). **MY FIRST INSTRUMENT NEARLY LIED**: a `grep -E "^\s*(--- FAIL|FAIL|panic:)"` over the 99 KB job log returned NOTHING; treated as a claim not a fact (rule 3a), a known-positive control (`grep -c "ok "` → 105) proved the log intact and a widened case-insensitive search found `panic: test timed out after 5m0s` immediately, stack parked in `buildAilang` → `go build`. **THE FIND — the comment was the bug.** `main_test.go:430` read *"buildAilang builds the ailang binary once per test run"* and had **no memoization**: every call ran a full `go build` into a fresh `t.TempDir()`. Measured warm link cost **5–6 s** for a **93 MB** binary (3/3 runs). **14 call sites**, one per top-level test, none in loops — plus two more full links of the same binary in the same package (`serve_api_mcp_surface_test.go:29`, and `budget_scoping_e2e_test.go`'s `budgetBin`, **which was ALREADY CORRECT**: `sync.Once` + a persistent `os.MkdirTemp` dir, with a comment explaining that `t.TempDir` is torn down when the *first* caller returns and would delete the shared binary). The right pattern already existed twelve lines away, unused by its sibling — which made this Principle 3 (systemic, audit-before-patch) rather than three patches: one `sync.Once` builder, all three paths routed through it, `TestMain` cleaning up after `m.Run()`, **signature unchanged so no call site moved**. The 300s timeout deliberately **NOT** raised and nothing skipped — it is a real hang-detector. **MEASURED, all first-party**: this Mac, outside the codex sandbox, `ok 110.833s` → `ok 15.487s` (**7.2×**, 86% of runtime was redundant re-linking); **windows-latest**, from the PR's own job log, `FAIL 300.527s` → **`ok 83.177s`** (job wall 536s → 337s) — a **measurement, not an extrapolation**. **THREE HYPOTHESES RULED OUT BY MEASUREMENT.** (1) *the merge broke it* — refuted, docs-only. (2) `internal/effects` `TestNetHttpPost` — refuted, reproduces **identically on unmodified `origin/dev`** (httpbin.org **503**) = `#561`. (3) `internal/smt` `TestSolve_HardTimeout_FakeSolverIgnoringT` — this one needed real work, because it **passed on the base and failed in my worktree**, which is exactly the shape a genuine regression has: isolated to **3/3 pass alone** in the *modified* worktree with the changed-file list printed as a control (zero files outside `cmd/ailang`), and the **evaluator then supplied the leg I had missed** — the file carries **`//go:build !windows`** (verified first-party; control: sibling `solver_test.go` has no tag), so it cannot run on the failing job at all. **TWO MORE LOCAL "FAILURES" WERE THE REPO'S OWN GUARDS WORKING ON ME**: CI's anti-silent-skip gate showed 2 of 3 required tests not PASSing — `TestRunSmokeInTempDir_Pass` skips without `bin/ailang` (absent in a fresh worktree), and `TestPromptCommand_Piping` skips via `internal/testutil.RequireAilangOnPath`, which **skips when the on-PATH binary is older than the newest Go source** — and I had just edited `main_test.go`. Both PASS once the environment matches CI, proven with a **PATH-scoped scratch binary** rather than by overwriting the shared `~/go/bin/ailang` the rig's evals depend on. That guard is Gate 2's verification-protocol step 1 in mechanical form, and it correctly fired on me. **EVALUATOR NB ACTIONED, NOT WAVED THROUGH**: sonnet's one non-blocking finding (missing `[Unreleased]` changelog entry, per coding-standards) was verified first-party and fixed in a 2nd commit. **Routing evidence**: model=**claude-opus-5** (controller) task-class=execute round1-score=**91** rounds=1 corrections=1 provider=**codex** agent=codex cost=**quota-bucket:codex-chatgpt**. Executor **FIRED** (`codex:gpt-5.6-sol`, probe rc=0, bounded 30-min cap, `--sandbox workspace-write`, 60,751 tokens; `codex login status` → *"Logged in using ChatGPT"* = subscription bucket, **not** the metered key — `OPENAI_API_KEY` is set but does not win, checked with the safe `[ -n … ]` form, never the value-printing `${VAR:+…}` shape). Evaluator **FIRED** (`sonnet`, pinned) — **generator≠judge holds** (OpenAI executor vs Anthropic judge). Designer/planner **NOT fired** (a CI hotfix needs no doc or plan), so the designer rotation correctly did **not** advance, staying at `claude:claude-fable-5`. `metered=$0.00` of the `$5` ceiling. **Sandbox rule honoured**: codex labelled its own `go test ./cmd/ailang` `UNINFORMATIVE UNDER SANDBOX` (unrelated `httptest` loopback bind denial) and the controller re-ran every gate outside it — mandatory, since the diff touches `cmd/*`. **Gate 3b GREEN, SHA-addressed** on PR #564 (20 checks, 0 failures, `test-windows=completed/success`) and re-polled on the merge commit. **Gate-1 trap did not fire, 3rd consecutive** — `dev` == `origin/dev` == `773894d87`, running `SKILL.md` byte-identical to origin (`cmp` silent). **BUT THE CHEAP TELL CAUGHT MY OWN INSTRUMENT**: `grep -c "Iteration 133"` on the charter returned **0**, which reads exactly like a stale copy — the charter writes stamps in **UPPERCASE**. Re-run case-correctly it is 1, with controls (`ITERATION 132` = 2, `ITERATION 999` = 0). **A case-sensitive grep is an instrument**, and this one would have sent a healthy iteration down the stale-charter path. Gate-4 writes were made from a worktree branched from `origin/dev` because merging #564 left local `dev` 1 behind — the routine post-merge state, **not** a divergence (zero local commits ahead). **RETRO — ONE skill edit**: Gate 2 rule 3a gains the case/whitespace shape of a vacuous search, citing this iteration's two instances (the FAIL-grep over the CI log, and the charter cheap tell) alongside the existing zsh-glob and `PIPESTATUS` shapes. **PARKED FOR HUMAN — ONE decision**: grant a **standing** authorisation for the Gate-1 fast-forward reconcile when local `dev` has **zero** commits ahead and no incoming commit touches a dirty file? Every iteration that merges a PR ends 1 behind, so without it the checkout re-diverges monotonically and each Gate-4 pays a worktree+PR round-trip. `#558`, `#554`, `#561`, `#563` remain open. + ## STATUS 2026-08-03 — ITERATION 133: **THE `#546` PARK IS CLEARED AND THE SPRINT IS PLAN-READY (PR #562).** Mark's option-(c) ruling folded into the design doc, five post-quorum points from the AUTHOR absorbed, and the designer's own drain mechanism — a **sentinel-panic abort** — REFUTED by the controller and RULED OUT by the planner on Go's `syscall/js` contract. Pick rationale: `m-recorded-stream-api` (`ailang#546`), **not** what iter-132 named as next — two charter commits landed at 10:19/10:20 today, *after* iter-132's report, recording Mark's attended rulings (`#546` → option (c), ROUTABLE, **pick #1**; `m-mcp-exact-tool-surface` Lane B → pick #2, ahead of the quota offloads). Gate 1's origin-sync is what surfaced that: reading the working-tree charter alone would have executed a plan the human superseded 55 minutes earlier. Gate 0/1 clean: kill switch armed, billing **CLEAN**, gh account correct, dev CI **GREEN** per-workflow on `a929ec452`, **ZERO** open `[nightly-eval]` alarms (control-verified), no new Mark comment (watermark already on his last), rotation-week predecessor `#484` re-read (both comments already actioned by iters 114/130), no rotation due (`#559` created 07:08 CEST, *after* today's Monday 07:00 local boundary; 3 < 80). Inbox: 5 messages, all eval-suite telemetry + our own iter-132 report — no directive, no regression. **GATE-1 TRAP DID NOT FIRE, 2nd consecutive** — `dev` == `origin/dev`, running `SKILL.md` byte-identical to origin, cheap tell passed (`ITERATION 132` present; control `ITERATION 131` = 2 hits), so Gate-4 writes were made in place. The reconcile is holding. **GHOST DISCIPLINE — not a ghost, re-verified 58 commits later** on a rebuilt `v0.31.0-58-ga929ec452`: `{IO}` callback rc=0 `✓ No errors found!` beside `{FS}` callback rc=1 `incompatible closed rows: r1 has extra labels [IO], r2 has extra labels [FS]`; `StepResult` carries no chunks. My first probe pair was **uninformative** — both files failed identically on an unrelated missing `images` field; a negative and a positive that fail the SAME way are not a control. **THE AUTHOR'S SEALED-INTERFACE CLAIM CAME BACK STRONGER THAN FILED, and my first instrument was broken**: `grep "StreamChunk()"` returned EMPTY because the marker is `streamChunkMarker()` (correct pattern = 4 hits; control pattern = rc=1). Four legs hold: sealed by an unexported marker (`internal/ai/provider.go:159-163`); exactly **3** implementers; `encodeStreamChunk` (`ai_step.go:422`) covers all three with `default: return nil` at `:447`; nothing embeds `ai.StreamChunk` (flagged as an empty search with no constructible positive control); and the one variable-forwarding call site (`cmd/wasm/effects.go:244`) is nil-guarded at `:243` by an **untyped**-nil producer. **So the fail-loud drain trigger is UNREACHABLE for any value constructible today** — which reframes Mark's ruling as insurance, not a bug fix, and is what let the sprint be sized honestly. **THE FIND — the designer's sentinel-panic abort is UNSOUND ON WASM.** `cmd/wasm/effects.go:238-247` hands the callback to JS as a `js.FuncOf` wrapper and awaits the handler's promise via `awaitPromise` (`:43-53`), whose own comment states *"js.FuncOf callbacks run as goroutines"*. `recover` is **per-goroutine**, so once `awaitPromise` parks, a sentinel raised in a JS-invoked callback cannot be caught by a `recover` scoped to the `StepWithStream` call — unrecovered panic on another goroutine, **fatal to the module**. And **no host test can see it**: the file is `//go:build js && wasm`, and its own sibling comment records that the pure-Go helpers were split out *specifically* to be host-testable. The proposed "containment test" would have passed green while the WASM path crashed — the vacuous-pass class again. **The planner confirmed it against a BETTER source than mine** — Go's own `syscall/js` doc (*"Invoking the wrapped Go function from JavaScript will pause the event loop and spawn a new goroutine. Other wrapped functions which are triggered during a call from Go to JavaScript get executed on the same goroutine"* — the exception clause is the whole question and does not cover the parked-promise path; I re-read `$(go env GOROOT)/src/syscall/js/func.go` first-party) — and added three legs I did not have: (a) the doc's `encoding/json` precedent is FALSE in the load-bearing respect (json re-raises panics from a user-supplied `MarshalJSON`; the precedent is "a package panics through its own frames", never "out of a callback handed to foreign code"); (b) **it refuted MY OWN option ranking** — I offered a build-tag gate second, and `ci.yml`/`build.yml` contain **zero** `wasm` references (control: `release.yml` has 28), so the gate is enforced by nothing until *release*; (c) panicking out of a callback handed to 7 `AIHandler` implementers **including out-of-repo ones (@arniwesth's own driver)** is a **covert version of the option (b) Mark rejected**. **RULING: drain mode ships, the sentinel does not** — locality, no interface change, both budgets (256 chunks / 1 MiB), `drain_exhausted` trace and the preserved typed `Internal` all survive; only a post-failure **wall-clock** bound is lost, on a path unreachable today. **DESIGNER FOLDED IN five points @arniwesth raised AFTER both quorum rounds**: "lossless" over-claimed (chunks are already lost one layer BELOW the encoder — anthropic's delta switch has no `default`, `input_json_delta` is never emitted, WASM drops unknown kinds), so the guarantee is now scoped to adapter-**emitted** chunks in LongDesc + Success Criteria + the A2 axiom; the **sibling divergence** made deliberate (the existing op already skips silently — `ai_step.go:377-382`, shipped, verified); the completeness contract ruled to live on `outcome` with `RecordedStream` **NOT** widened (an `IncompleteStream` code filed as a question needing author sign-off, not assumed); a **StreamChunk exhaustiveness guard** taken in scope as M4, justified as the implementation of Conflict Surface item 4 rather than new scope; and the testability corollary that `onChunk(nil)` is the only constructible input for every unencodable-chunk test. All three of the author's adapter claims were controller-verified before routing. **CONTROLLER CORRECTIONS TO SUB-AGENT OUTPUT, both caught by measuring**: Target **v0.31.0 → v0.32.0** (v0.31.0 SHIPPED 2026-07-29 — `gh release list` → `AILANG v0.31.0 Latest`, tag `1f6f7dd28`; every `Since: "v0.31.0"` string was stale; doc moved to `planned/v0_32_0/`), and **the sprint JSON FAILED validation** — the planner reported "no placeholders" but `S1_M1` carried `estimated_loc == 0`, the `create_sprint_json.sh` sentinel, so sprint-executor would have REFUSED TO START; set to 245 (lines *moved*), validator now rc=0. **SPRINT CUT IN TWO** rather than executing a 6-day sprint: **S1 = 3.75 d / 5 milestones** (file split for headroom → verbatim credited patch adoption → shared core → fail-loud + inert bounded drain → test matrix → contract text), **S2 ≈ 1.5–2.0 d** (example, both false "open row" repairs + CI guard, prompt/μRAG/website, exhaustiveness guard). The plan states what S1's PR may NOT claim — notably not that ADR-009 is unblocked, and nothing about the `js && wasm` build. **DE-RISKED AGAINST MY OWN WARNING**: I told the planner to budget rebase work, then measured and **I was wrong** — all 5 patch-touched files are byte-unchanged since the v0.31.0 tag (control: `nightly-eval.sh` = `180 29`), `git apply --check` rc=0, and the four offered tests pass against current dev (**4/4 PASS**; scope-widened, the whole `internal/effects` package minus two live-network tests = **rc=0, 483 PASS, 0 FAIL**). Correction reached the planner *before* it planned. **BONUS FILINGS**: `#561` (`make test` is network-dependent locally — `TestNetHttpPost` tolerates transport errors but not an httpbin **503**, which arrives as a successful round-trip; skipped in CI, so it only ever fails for a human or an agent establishing a baseline) and `#563` (`validate_sprint_json.sh` overloads `estimated_loc == 0` as the unfilled-placeholder sentinel, so a legitimately net-zero milestone — a pure refactor or docs-only work, both classes the repo's own rules *encourage* — cannot be expressed; 2nd instance after iter-121). **Routing evidence**: model=**claude-opus-5** (verified first-party from process ancestry — `tools/launchd/mission-control.sh`, ppid launchd) task-class=design+plan corrections=3 cost=quota-bucket:opus. **Designer FIRED** (`claude:claude-fable-5` via `claude-sub`, 1-token probe rc=0, bounded 30-min cap) so the rotation ADVANCED `codex:gpt-5.6-sol` → `claude:claude-fable-5`, state file written; **planner FIRED** (opus, pinned). Executor/evaluator **NOT fired** — deliberately deferred, so generator≠judge is N/A. **No quorum re-run**: R2's survivor was resolved by a HUMAN RULING, not a revision, so no round is owed. `metered=$0.00` of the `$5` ceiling — every lane rode a quota bucket. Chain posted (`d2bb709d`). **RETRO — ONE skill edit (`3be3984e7`), executing a remedy iter-127 pre-committed to**: *"If a second iteration hits it, the fix is to standardise the worktree location off `/tmp`."* It did. Gate 3 now forbids `/tmp` worktrees, **widened to throwaway PROBE worktrees** — my sprint worktree was placed correctly and I still bought the false red twice, from two `/tmp` scratch trees made to establish a baseline — and adds a second failing test (`TestSolve_HardTimeout_FakeSolverIgnoringT`, `internal/smt`) beside iter-127's `TestIsTempPath`. Control: both rc=0 from a non-`/tmp` checkout, rc=1 from `/tmp`; location is the only variable. Saved in the MAIN checkout (same inode verified through the `~/.claude` symlink) so it reaches the running skill. **Watch-item (instance 1)**: *a control must be proven DIFFERENT from the thing it controls* — rule 3a demands a known-positive, but says nothing about proving your NEGATIVE control is actually negative; my `sed`-built "corrupted patch" matched nothing, was byte-identical to the real one, and its rc=0 read exactly like a passing check until `cmp` caught it. **Next**: EXECUTE S1 (validator rc=0) — executor `codex:gpt-5.6-sol` in a worktree **not** under `/tmp`, evaluator `sonnet`. **PARKED FOR HUMAN — ONE decision, the planner's ruling and not a re-litigation of Mark's**: dropping the sentinel bounds post-failure **work** (O(1)/chunk, zero retention) but not post-failure **wall-clock**, on a path unreachable for any `StreamChunk` constructible today — accept? If no, the only remaining mechanism is a cancellable provider context (the already-rejected option (b)), which becomes a blocking dependency and makes this multi-sprint. `#558`, `#554`, `#561`, `#563` remain open. ## STATUS 2026-08-03 — ITERATION 132: **BOTH OF MARK'S PARKED ASKS EXECUTED IN ONE ITERATION — the shared main checkout is RECONCILED (`dev` == `origin/dev` == `af3bca9a5`, 0 ahead / 0 behind) and the rig now runs EXACTLY ONE ollama server (`dev.ollama.serve`, pid 7381, **0.32.1**, tuned plist env applied). The 13-day split brain (`#557`) is closed and the four-iteration Gate-1 stale-checkout streak is broken at the source.** Pick rationale: a **human directive outranks the queue** (Gate 0.5) — Mark commented on `#559` at `2026-08-03T07:04:45Z`: *"Yes reconcile dev and only one ollama server"*, answering iteration 131's blocking ask AND iteration 130's deliberately-parked half-directive in one line. Gate 0/1 clean: kill switch armed, billing **CLEAN**, gh account correct, dev CI **GREEN** per-workflow on `af3bca9a5` (CI + Build-and-Release success; Docs-Deploy success on `d84708272`, path-filtered = N/A after), **ZERO** open `[nightly-eval]` alarms (control-verified: the same search returns **30** under `--state all`, so the instrument sees positives). Watermark advanced to `2026-08-03T07:04:45Z` **BEFORE** routing. **Rotation-week predecessor read PERFORMED** (`-prev` = `#484`, fresh from iter-131): 2 Mark comments there, both already actioned by iters 114/130 — re-surfaced only because a rotation resets the watermark to epoch, and correctly NOT re-run. No rotation due (`#559` created `05:08:48Z` = 07:08 CEST, *after* today's Monday 07:00 local boundary; 2 comments < 80). **THE RECONCILE — measured before executed, and the refusal is the evidence.** Local `dev` was **1 ahead / 11 behind**. The ahead-commit `9e742037a` was proven a pure DUPLICATE by **patch-id** (`fc808504e7…`, byte-identical to upstream `167c55e6a`) — so discarding it loses nothing, and that measurement is what made the whole operation safe rather than hopeful. Of 9 dirty files, **3 were already byte-identical to origin** (iter-131's containment restores + `SKILL.md`) and **6 carried real local content** (a sibling's `post-release` skill edits, the fmt hook log, rig-generated benchmark JSON). Measured that **NONE of the 11 incoming commits touch any of those 6** — control-verified in the same call, since the intersection with the 3 same-as-origin files correctly came back non-empty, so the empty answer was informative rather than vacuous (rule 3a). Backed all 9 up first. The first `git checkout -B dev origin/dev` **REFUSED**, blocked by exactly the 3 containment files: git compares the working tree against the **stale local HEAD**, not the target, so files whose content already EQUALS the target still read as clobber risks. Staged origin's blob for just those 3 — sha256-verified that **not one byte on disk changed** — and retried: rc=0. **Principle 0 fully respected**: no `reset --hard`, no `clean -fd`, no `stash`, no `pull`, no branch switch; `checkout -B` is protective by construction and *errored rather than destroying*, which is precisely why it was the right instrument. Old HEAD remains in the reflog. **Verified the POINT, not just the pointer**: only the 6 known-local files now differ from origin; all **four** launchd entry points match origin and are `bash -n` clean; qwen3.5 is **0 hits** in both nightly drivers (control: qwen3-6 = 10 hits); and `#551`'s `RUN_UNMEASURED_CATEGORIES` gate — the one iter-131's per-file containment could **not** reach — is now live in the copy the rig actually executes. **THE OLLAMA CONSOLIDATION, and the find is bigger than the errand.** Split brain reconfirmed live (`127.0.0.1`→**0.31.2**, `[::1]`→**0.32.1**) and both managers identified: `dev.ollama.serve` (launchd, pid 1075) held IPv4; `Ollama.app` (Electron 1340→1351) held IPv6. **The two servers were running `llama-server` with materially DIFFERENT inference flags** — launchd's child: `--no-mmap --cache-type-k q8_0 --cache-type-v q8_0 --flash-attn on`; the app's child (pid 5860): `--flash-attn auto`, **default f16 KV cache**, no cache-type flags. So the rig's tuned plist config (`OLLAMA_FLASH_ATTENTION=1`, `KV_CACHE_TYPE=q8_0`, `KEEP_ALIVE=-1`, `MAX_LOADED_MODELS=1`) applied to **only one** of the two — and iter-130 measured that *evals reached the other one*. An unknown share of local-model eval data since 21 Jul was therefore produced under **unintended inference settings**, with which server a run reached decided by dual-stack dial order. Recorded as a **CONFOUND**, explicitly NOT a claimed cause for `#554` — but it is now a falsifiable one, because the confound is gone. **Kept the launchd server** (it carries the tuned env, the watchdog, and survives logout; the GUI app is untuned and inappropriate for a headless rig), `SIGTERM`'d the app parent → its server exited with it, then `kickstart -k` → **0.32.1**. Verified: exactly **ONE** server; GUI not running; `127.0.0.1` **and** `localhost` → 0.32.1 (clients fall back cleanly from the now-refused `::1` — measured, not assumed); `ollama --version` agrees with **no** client/server warning for the first time since 21 Jul; model store intact (8 models incl. qwen3.6). Disabled `com.ollama.ollama` (the Squirrel autostart) so the split brain cannot silently return. **INSTRUMENT SELF-CATCH**: my own "REAL server count" printed **2** while the list it printed alongside showed **1** — the counting `grep` was matching its own command line. The list was right, the counter was the broken instrument; caught only because the two disagreed in the same output. Rule 3a aimed at my own probe. **SHIPPED** (`87f65ff67`): `rig-watchdog.sh` now pins its probe to `127.0.0.1` so the address it PROBES is the server it RESTARTS — it had probed the app's server while kickstarting launchd's for 13 days (`::1` GET /api/tags rows in `~/.ollama/logs` prove it), meaning a dead `dev.ollama.serve` would never have been noticed and a dead app server would have "healed" by restarting an already-live job. Verified with a known-positive control (dead port → "ollama unreachable" fires), so the passing probe is informative. **Gate-1 trap did NOT fire — first time since iter-127**: local == origin, cheap tell confirmed (`ITERATION 131` present, control `ITERATION 130` present), so Gate-4 writes were made **in place** safely for the first time in five iterations — a direct dividend of the reconcile. **Routing evidence**: designer/planner/executor/evaluator **all NOT fired** — a human-directive ops iteration; the designer rotation correctly did NOT advance, staying at `codex:gpt-5.6-sol`. Controller on the session model (quota bucket). `metered=$0.00` of the `$5` ceiling. **NOTHING PARKED ON MARK THIS ITERATION** — both standing asks are now closed. `#546`'s a/b/c, `#558` (durable driver self-re-exec) and `#554`'s root cause remain open. **Next**: `m-planner-codex-lane` is unblocked and is the pick — the reconcile it was gated on is done. -## STATUS 2026-08-03 — ITERATION 131: **`#558` FILED — every launchd job executes its entry-point script from the SHARED MAIN CHECKOUT's working tree, which is 10 commits behind `origin/dev`, so `#556`'s qwen3.5 retirement LANDED on 2026-08-01 and never reached the rig. This morning's nightly ran the retired model 24/24, two days after Mark's directive.** Pick rationale: NOT the queue head. Mark's dated quota-offload directive re-armed at **07:00 today** and `m-planner-codex-lane` is plan-ready — but characterising the inbox's INVALID nightly surfaced a live regression, and Gate 0.4 ranks that above the queue. It also **blocks the directive itself**: that sprint's HIGH-risk milestone edits `tools/launchd/mission-control.sh`, one of the four launchd entry points executed from the stale tree, so it would land green and change nothing about which model the planner runs on. Gate 0/1 clean: kill switch armed, billing **CLEAN**, gh account correct, dev CI **GREEN** per-workflow on `d847082726` (CI + Build-and-Release + Docs-Deploy all success), **ZERO** open `[nightly-eval]` alarms (control-verified: the same search returns **30** under `--state all`, so the instrument sees positives), **no new Mark comment** (watermark `2026-08-01T06:54:07Z`, iter-130's directive already actioned). **ROTATION DUE AND PERFORMED** — first time the local-timezone rule fired affirmatively: 07:01 CEST is past the Monday 07:00 *local* boundary and `#484` was created 2026-07-27, before it (45 comments < 80, so the time condition alone carried it). `#484` closed → **`#559`**; state files updated, `-prev` set for next iteration's predecessor read. **GATE-1 TRAP FIRED AGAIN** (4th consecutive): local `dev` **1 ahead / 10 behind**, its ahead-commit `9e742037a` still the duplicate of upstream `167c55e6a`; the working-tree charter carried **zero** occurrences of ITERATION 130 (control: 3 stamps present), so an in-place Gate-4 edit would have deleted 127/128/129/130. All writes done in a worktree branched from `origin/dev`. The running `SKILL.md` was byte-identical to origin (`cmp` silent) — iter-128's fix still holding. **THE FIND, and the mechanism is narrower and more interesting than "the checkout is stale".** The nightly is *otherwise correctly pinned*: `nightly-eval.sh:62-87` fetches origin and rebuilds a throwaway worktree at `$HOME/.ailang-nightly/worktree` pinned to `BUILD_REF=origin/dev`, and the `ailang` binary, the benchmarks and `tools/nightly_classify.py` all run **from that fresh worktree**. Line 12 of the script says so in its own words: *"isolated git worktree pinned to committed origin/dev — never the live working tree."* **So the pipeline pins everything except the one file it cannot pin — itself.** launchd invokes `/Users/…/ailang/tools/launchd/nightly-eval.sh` directly (plist verified), and that copy still read `MODEL="opencode-qwen3-5-35b-a3b-mxfp8"` at line 120 while origin read `qwen3-6` at line 129; `/tmp/ailang-nightly-eval.log` confirms **24/24 trials on qwen3.5** this morning. A second, independent symptom corroborates the split-version state: `#551` added a 6th tab field to the classifier's `INVALID` record, the **fresh** classifier emits it and the **stale** driver still parses `$2..$5`, so today's alert printed the old `infra-tainted 6/12` banner and silently dropped the category. ⚠ **I GOT THIS WRONG ONCE AND CAUGHT IT — the correction is the load-bearing part.** My first read was that `#551`'s `RUN_UNMEASURED_CATEGORIES` gate was also inert, from a grep of the main checkout's `nightly_classify.py` that came back empty with a firing known-positive control. The grep was honest; the **object** was wrong — that copy is never executed. That is rule 3c (*a probe identifies what you REACHED, not what you NAMED*) applied to a FILE rather than a service, and it is the same error as the bug under investigation, made while investigating it. The gate is live. **CONTAINMENT APPLIED, and deliberately not called a fix**: restored `nightly-eval.sh` + `nightly-lang-eval.sh` from `origin/dev` — both had **zero** local edits (`git status --porcelain` on those paths empty while repo-wide showed 7), so nothing was destroyed, no branch/reset/stash/pull was involved, and Principle 0's four named operations were all avoided; unstaged afterwards so a sibling's `git add` cannot sweep staged content; both verified **byte-identical to origin** and `bash -n` clean. Tonight's nightly is the first genuine qwen3.6 run. This is a per-file patch of a systemic defect — the durable fix (each driver re-execs itself from the pinned worktree, reusing machinery `nightly-eval.sh` already has) is proposed in `#558` and carries a chicken-and-egg caveat: landing it does not help until the main checkout receives it **once**. **Blast radius measured, not assumed**: four launchd entry points run from the main checkout — `nightly-eval.sh` and `nightly-lang-eval.sh` were stale, `mission-control.sh`, `rig-watchdog.sh` and `os-rotation-filler.sh` are not (unchanged in the missing 10), and `dev.ailang.mission-world` points at a different repo entirely. **Routing evidence**: designer/planner/executor/evaluator **all NOT fired** — triage + containment, zero product code changed, no design doc, no quorum; the designer rotation correctly did NOT advance, staying at `codex:gpt-5.6-sol`. Controller on the session model (quota bucket). `metered=$0.00` of the `$5` ceiling. **THIS IS THE THIRD MEASURED HARM FROM ONE DIVERGENCE** — iter-128's stale *skill*, iter-129's stale *charter*, and now the stale *driver*, which is the first to defeat an explicit human instruction. **PARKED FOR HUMAN — the reconcile is now the blocking ask**, not a hygiene note: it gates the quota-offload directive Mark dated to this morning. `#557` (two ollama servers on :11434) and `#546`'s a/b/c remain open. - ## CURRENT GOAL 1. **Iteration 0 (definition)**: write the v1.0 bar (see "The v1.0 bar" below — draft to be