From 9cdc47d0488b014f1302060796bea48fefa27db5 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Thu, 22 Oct 2026 00:30:06 -0500 Subject: [PATCH] honker: row 194 b15 (b') (sage-2507): T15 drops the exited reviewer stand-in's registry entry by hand, the N6 convention, so the post-resume coder launch isn't refused on an entry with no provider/model; BUILD.md notes for (a) and (b') --- agents/honker/work/queue-194/BUILD.md | 31 +++++++++++++++++++++++++++ packages/cli/tests/lifecycle.test.mjs | 2 ++ 2 files changed, 33 insertions(+) diff --git a/agents/honker/work/queue-194/BUILD.md b/agents/honker/work/queue-194/BUILD.md index b1ad8af45..ab3d70e7e 100644 --- a/agents/honker/work/queue-194/BUILD.md +++ b/agents/honker/work/queue-194/BUILD.md @@ -1052,3 +1052,34 @@ Doc-only. `git diff 899e30a80 -- packages` is empty, so the runs c - **Correction to N4 above.** "Until a human verb or a new end clears it" is wrong. `#aliveAfterFire` checks only `session.ended`, and today nothing else clears the flag. It stays until the follow-up row adds a clear. + +### b15 (a), product change: the constructor's argument checks move ahead of the store reads (sage-2501) + +- **Why.** The b14 runb8 (`run-20261022T052118Z`) went red on chief-of-staff T8b (`:864/868`). It + builds `new Broker({ store: null, roleFile: 'roles' })` and expects `roleFile must be a function`. + Row 191 (4bdc7e0e8) reads `dirname(store.directory)` in the constructor before the roleFile check, + so a null store throws its own TypeError first. The order was already like this at b8, but the last + 194 run before 191 landed was b7, and runb8 had never run on 191's base until today. +- **Change.** The harnessOn (row 65), testerOn and roleFile type checks move up, unchanged, to just after + the invalid-business check and before `this.#businesses`, `this.#store` and every store read. Each + descriptive comment stays with its assignment, and one new comment line goes above the moved checks. + Nothing else moves. 191's lines are byte-identical. invalid-business stays first because it was + already ahead of every store read. Diff: broker.mjs +4/-3. +- **Pins.** chief-of-staff.test `:868` (roleFile, null store) now gets its message. + routes-verb.test `:89` (harnessOn 'yes', a real store) keeps its message. + +### b15 (b'), test fixture: T15 drops the reviewer stand-in's registry entry (sage-2503, sage-2507) + +- **Why.** The other b14 red was cli lifecycle T15 (`:744`). The debug run printed the launch log tail: + after the resume the coder launch closes `launch-failed` with why `running session has no exact + provider/model; reconcile before launching` (business/src/launch.mjs usageCounts, row 122). The + reviewer stand-in has exited, but its registry entry is still there, and that entry carries no + provider/model. The launcher's exit handler only removes the runs it started itself. +- **Not (b).** I didn't give standIn's entry provider/model (honker-0118). prepare()'s limits are + `{ sonnet: 1 }`, and the reviewer and coder both run claude-sonnet-5-5, so the stale entry would count + 1 against a limit of 1 and the same launch would refuse on the limit instead. Sage ruled (b') + in place of (b) (sage-2507). standIn is unchanged. +- **Change.** T15, after `assert.equal(await x.exited, 143)`, adds + `s.launcher.registry.remove("acme", "reviewer-run")` with N6's comment. That's the convention at + N6 `:763-764`, and it's test-only. standIn's `t.after` removal still runs, and a second remove of + a missing run is the same no-op it already is in N6. diff --git a/packages/cli/tests/lifecycle.test.mjs b/packages/cli/tests/lifecycle.test.mjs index b187b5abc..9a8bb04b8 100644 --- a/packages/cli/tests/lifecycle.test.mjs +++ b/packages/cli/tests/lifecycle.test.mjs @@ -736,6 +736,8 @@ test("row 194 T15: while halted the pass closes a launch and a regenerate proces for (const request of [launch, regen]) assert.deepEqual([s.state(request).state, s.state(request).done.refusal], ["closed", "processing-halted"], request); assert.equal(s.state(end.request).state, "closed"); assert.equal(await x.exited, 143); + // The launcher's exit handler drops its own runs. A stand-in's entry goes by hand. + s.launcher.registry.remove("acme", "reviewer-run"); assert.deepEqual(launchLog(p.f).filter((e) => e.event === "lifecycle-end").map((e) => e.run), ["reviewer-run"]); assert.equal(asked, 0, "a halted tick runs no thread pass"); assert.equal(s.running("coder").length, 0);