feat(dispatch): background form (claude --bg) with the T4 guards - GREEN

The dispatch skill gains a third form beside paste and plan-file: the
PM starts the child itself (operator decision 2026-09-22). Template:
cd <dir> && claude --model <m> --effort <e> --disallowedTools
AskUserQuestion,SendMessage,ListAgents --bg --name <name> "<starter>",
with --model first because pre-dispatch-budget.sh counts only that
position, and model/effort spliced from route.sh's command= so the order
holds by construction. The ASCII starter claims and closes by full path,
says claim KUN denne, pins the branch with git checkout -B, and forbids
push/tag/release. The skill says what follows: watch the order file,
re-measure on the commit, merge in the operator's push round. The
description triggers on the form (EN + NO).

valgt: no bg= line in board.sh, fordi the background form uses none of
the plan-block format (no tab=, no pane, no morning consumer) and its one
generated part already has a single generator in route.sh. §19b pins
that --target-pane still refuses 'bg'. Stated overlap: starter steps
(1)(2)(4) repeat board.sh's thin-starter protocol.

board-selftest 478 -> 493 (§19b: 12 red -> green). Suites under bash
3.2: coord 257, board 493, route 73, orders 116, guard 54 = 993.
npm test 12/12. No version bump: release is the operator's push round.

Order 20260923T070445Z-9974217048-from-.claude.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-23 09:27:23 +02:00
commit 24adf594bf
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
4 changed files with 135 additions and 8 deletions

View file

@ -14,7 +14,7 @@ Session A in repo X leaves a message for repo Y; the next session in repo Y gets
![Hooks](https://img.shields.io/badge/hooks-1-green)
![Skills](https://img.shields.io/badge/skills-4-orange)
![CLI scripts](https://img.shields.io/badge/CLI_scripts-8-blue)
![Selftest checks](https://img.shields.io/badge/selftest_checks-978-blue)
![Selftest checks](https://img.shields.io/badge/selftest_checks-993-blue)
---
@ -98,6 +98,8 @@ Scoring is judgement and belongs to the skill; turning scores into a row is a lo
**Handing a task to another session (the `dispatch` skill).** "Start a session in repo X on this order." `board.sh --dispatch` turns that into one line the operator can paste: the order written to a prompt file, the model and effort looked up from the same row table `route.sh` uses, and the prompt passed **in argv**`claude --model … --effort … "$(cat <file>)"` — so the session is handed its task instead of having to guess it out of STATE.md. It emits one of two forms, and which one is a measurement rather than a preference: a repo with no terminal pane gets a plan block (`morning --plan-file <f> --no-go`), while a repo that already has one gets a bare paste line for that tab, because a plan block for an already-open repo is silently dropped by the driver and reads as a broken plan file. `--target-pane yes|no` is therefore required with no default, exactly as `route.sh` refuses to default `--last-effort`: it is a fact about the world, and this plugin never looks for a terminal itself. Read-only holds — the prompt file and the plan file are written by the caller, never by `board.sh`.
**A third form: the background session.** When the dispatching session starts the child itself, the skill describes `claude --model <m> --effort <e> --disallowedTools AskUserQuestion,SendMessage,ListAgents --bg --name <name> "<starter>"`. `--model` comes directly after `claude`, and the model and effort are taken from `route.sh`. The three disallowed tools are there because a background child cannot be answered: a question stops the child, and a message reaching back to its parent is a direction nobody asked for. The starter tells the child to pin its branch with `git checkout -B`, to commit there, and to push, tag or release nothing. Merging and publishing belong to the operator. This form lives in the skill alone. It has no pane, no plan block and no `morning` consumer, so `board.sh --dispatch` still emits exactly the two forms above.
**Making the order outlive the tab (the order queue).** A prompt file passed through argv dies with the pane it was typed into, and nothing in the receiving repo records that an order ever arrived. Measured 2026-08-17: one order was dispatched three times over 90 minutes before it was worked, because the first two tabs ran something else. So dispatch now delivers the order into the recipient's own queue — `~/.claude/coord/<repo>/orders/` — and the pasted line becomes a thin **starter** carrying only the order id. The order text has one home. If the tab is never run, nothing is lost: the order stays pending, is re-injected at every session start in that repo, and shows up in `board`'s ORDRE column, which sits beside INN and is never summed with it — INN is "others are waiting on you", ORDRE is "work is waiting on this repo".
Ownership is explicit rather than implied. An order is pending until a session **claims** it, and the claim is a rename with no check-then-act step, so of any number of racing sessions exactly one wins and the rest get a clean refusal. The claiming session owns it until it either closes it with a commit pointer or **returns** it with a reason recorded in the order itself. At claim time the session is told to compare the order against its own `STATE.md` next step and to state any divergence in its first reply — a dispatch that displaces a live next step is a decision, and this makes it an uttered one. A session that claims an order and dies is the one remaining way an order could vanish, so claimed orders stay visible in the injection with their in-flight age; that is a visible-again rule, not a lease timer, because nothing here can know that a session is dead.
@ -201,7 +203,7 @@ Note that raising the inbox's priority (Rule 7) deliberately does **not** widen
## Development
bash scripts/coord-selftest.sh # 257 checks against a throwaway mailbox
bash scripts/board-selftest.sh # 478 checks against a throwaway repo tree
bash scripts/board-selftest.sh # 493 checks against a throwaway repo tree
bash scripts/route-selftest.sh # 73 checks, incl. the route->board round trip
bash scripts/orders-selftest.sh # 116 checks, incl. the 20-way barriered claim race
bash scripts/state-line-guard-selftest.sh # 54 checks, incl. the Edit replace_all projection and the ratchet