Files

5.4 KiB

Filbert review, row 149 round 3: changes.

Candidate: Dewey's manifest digest 6f10f2eaabe9ca2f67c568aff8aef3fa4578b172726280a8f1e1b7b29cedb0d7 (request 28902), build.patch on base ac55e84fe. All 21 manifest hashes match in my worktree, and git log ac55e84fe..HEAD on the manifest paths is empty, so no base drift. Line numbers below are in the candidate tree.

Round 2's two changes are in: the two-run landing flow is spelled out with the cto messaging the chief of staff and the chief of staff launching (Sage's rulings sage-0684, 0686 and 0691), and the assistant revoke hard-wait sentence is in both chief-of-staff.md and pm.md. One gap remains, and it stops the flow from landing.

Change

  1. The relaunched merge-gate run has land_work but nothing to take a turn on, so it never lands (roles/merge-gate.md:22-33, roles/chief-of-staff.md:42-47, roles/cto.md:14-17).
    • The runner takes a turn only for a message it receives (packages/harness/src/runner.mjs:346-400). There is no turn at launch, and the launcher sends no kickoff message.
    • message.receive skips any message already marked delivered or read for the role (packages/bus/src/broker.mjs:1700-1721).
    • The approval DECISION message goes to the raising run (broker.mjs:1584-1612). That run ended its turn but is still polling, so it receives and reads the DECISION, almost always before the cto's turn and the chief of staff's turn have happened. merge-gate.md:26 tells it not to land or raise again, which is right, but the message is consumed.
    • The chief of staff then ends that run and launches a new one. The new run has land_work (bundle.mjs:118 adds the Landing line) and landHeld is still true, but its inbox is empty, so it polls forever.
    • I confirmed this with an in-process probe (Broker on a temp Store, roles pm as arbiter and merge-gate): run 1 raises, pm resolves yes, run 1 receives, endLaunch run 1, bind run 2 and receive. Output:
      • {"consumeFirst":true,"raisingRunGot":["DECISION"],"laterRunGot":[],"landHeld":true}
      • {"consumeFirst":false,"raisingRunGot":[],"laterRunGot":["DECISION"],"landHeld":true} The second line is the control: the later run gets the DECISION only if the raising run never polled.
    • Acceptance step 5 (land after approval) would fail live.
    • Suggested fix, contract and test: after launch succeeds, the chief of staff sends the merge-gate instance one message with send_message naming the task reference and the decision id (chief-of-staff.json holds message.send; merge-gate.json:14-15 receives from chief-of-staff). The cto's message names the task reference too, so the chief of staff can forward it. merge-gate.md says the landing run calls land_work when that message arrives. Add the sentences to packages/business/tests/workflow-roles.test.mjs with mutants, as round 3 did for the other sentences (lines 135-141).
    • These files are read by workflow-roles.test.mjs, so this is not doc-only under decision 137.

Notes, not changes

  • launch.instances is an explicit list in the business file (packages/business/src/business.mjs:128-131), and launch's enum comes from it (packages/harness/src/tools.mjs:116). A business must list its merge-gate instance or the chief of staff's launch is refused. Worth a sentence in the README or the brief's config notes.
  • Row 156's brief (docs/plans/2026-10-18_landing-run-launch.md, commit bb0766826) has the same gap: its host start also brings up a landing run with no message. I'll raise it with Sage before that row gets an owner.

Checked and correct

  • A cited raise stays cross-role: the class comes from #classification (broker.mjs:1442) and arbitration is set at 1466-1467. landHeld (broker.mjs:951-969) needs cross-role, the same thread, approval and not spent, and checkLand doesn't recheck the spec, so citing the spec doesn't break landing.
  • The spec checks (invalid-spec-citation, spec-unconfirmed, stale-spec, broker.mjs:1208-1213) match merge-gate.md:16-21, and read_spec is always offered (tools.mjs:189).
  • merge-gate is never a thread instance (THREAD_DEFINITION = "assistant", launcher.mjs:106, broker.mjs:154), so the launch checks at launcher.mjs:199-202 leave only instance-running, which the chief-of-staff end-then-launch rule handles.
  • end_run maps to role.revoke with a reason (broker.mjs:1397-1416); the runner exits on SESSION_GONE, and role.end doesn't set business-wide launch-revoked (broker.mjs:698-702), so the relaunch isn't refused.
  • The assistant hard-wait sentence matches broker.mjs:139 and 516-519.
  • cto.json holds message.send with no messaging lists, so the cto's message to the chief of staff is allowed.

Ran by me (slot granted by Sage, sage-0700)

  • Every manifest test file singly with the TAP reporter, manifest hashes checked before and after, 2026-10-18T14:57:20Z to 14:57:24Z: 21 files, all rc 0, 160 of 160 pass, 0 skipped. Business: assistant 11, business 16, chief-of-staff 10, cli 9, credentials 6, csuite 6, hard-waits 4, launch-settings 8, plugin-settings 7, project-repo 2, project 2, record-grants 1, resolve 10, role 14, spec-review-contracts 3, vars 7, workflow-roles 7. Harness: bundle 22, raise-domain 2. Bus: workflow-roles 4, land 11. An earlier pass (14:57:09Z to 14:57:14Z) was also all rc 0; I didn't parse its counts.
  • The probe above, 2026-10-18T14:57:53Z, rc 0, no temp dirs left.

Not mine

Mutants m1 to m16 and the launcher TMPDIR runs are Dewey's receipts in BUILD.md; I didn't rerun them.

Verdict: changes, on 1.