reckon crew dispatch ran six nodes across two external harnesses and the
calling harness, with no change to the calling instruction and no harness named anywhere an
agent reads. All eleven declared measures banked: one node definition reached the same
36-key routing result on two backends; three commits landed scoped clean; a worker's
unprompted four-field NEEDS-HELP: report was answered and resumed in
the same session, which restated its prior measurements without re-running anything; budget
read utilisation 1.02% on one backend and an explicit unknown on the other.
1,598 tests pass, 103 of them new. Two live defects were found and fixed; one constructed
measurement did not fire and is recorded as a negative result.
Full record: landed
evidence (commits a927c9c, 8a44624, 0ae4167,
d3a7617, 2224770).
§1 — Why this exists
Reckon can coordinate a sprint but cannot dispatch a worker that is not an in-process
subagent of the orchestrator's own harness. This plan adds that path, and does so through
a single dispatch instruction that names no harness, model, effort level or
sandbox flag. The agent states what it wants; reckon resolves how. Per-backend
flag translation is compiled code the agent never reads, which is what makes drift between
execution paths structurally impossible to express.
The seam design, the single permitted branch and the verified per-backend matrix are
recorded in
Agent Fleet Orchestration §2–§3.
Read that before implementing.
✓ landed §2 — The task-definition contract
Landed as crew.validate_node plus a pre-dispatch
checklist in the skill. A live rejection named five failing properties at exit 2; 18 tests cover
the seven, including the three the measure names. Independently verifiable gained a real
test on implementation — the manifest path must be absolute, because a relative one resolves
against the worker's own worktree and makes a delivered node look silent. Contract text now lives
in references/worker-protocol.md; the table below is the design record.
§ contract
This is the highest-value deliverable in the sprint, because a worker that thrashes is
almost always executing a malformed task. The contract makes well-formedness checkable
before dispatch, so the escape hatch handles only the genuine residual.
A node is dispatchable only when all seven hold:
Property
Test
Single goal
The goal states one deliverable. If it joins two with "and", it is two nodes.
Fully specified
Every input is already in the live plan or in the node's fences. Nothing requires
the worker to infer intent.
Demonstrable
Done-when is a measure that emits evidence — a named test, a recorded
command output, a numeric result against a stated bound. A subjective adjective
("clean", "robust", "better") fails this test.
Closed
No decision from outside the node is needed. A required-but-unlocked decision
means the node is not ready; a decision node precedes it.
Scoped
Exclusive write paths are enumerated, and nothing outside them is needed. No
concurrent node shares a path.
Bounded
The work fits the resolved time budget. If it cannot, split it — a budget is not
a target to overrun.
Independently verifiable
The orchestrator can audit completion from the manifest, git show
--stat and the gate evidence, without reading the implementation.
Implement this as an explicit pre-dispatch checklist in the skill and as a validation
in reckon crew dispatch that refuses a node missing a goal, a measurable
done-when, or a write scope. A node that fails is reshaped or split — never dispatched
with the hope that the worker will work it out.
✓ landed §3 — Deliverables
All eight landed: reckon/_backends.py (translation, keyed
to a backend's command, verified against four event streams recorded from live runs),
reckon crew dispatch/attach — plus observe,
resume, list and stop, without which the measures are
unreachable — references/worker-protocol.md, the structured escape hatch, the
four-axis reflex with a validator that refuses a non-quantitative completion, continuation at
three altitudes, budget capture with an explicit unknown state, and the skill upgrade with the
gate-fence rule authored solely here.
§ dispatch,
§ divergences
The launch matrix as code.reckon/_backends.py translates
a resolved flight config plus a node into a concrete invocation for each backend: argument
construction, session-id capture from the backend's machine-readable stream, resume form,
terminal-event recognition, and final-message retrieval. Unit-tested per backend against
recorded event fixtures, with no live process required.
The uniform CLI primitive.reckon crew dispatch --project P
--plan L --section S --role R --node N and reckon crew attach --run R --task
T. Dispatch validates the node against §2, resolves flight config, creates the
detached worktree through the existing fleet script, composes the fenced prompt, and then
branches once on launch: kind — spawning the process and returning a run id
for a cli backend, or returning a dispatch directive for an
in-harness backend which the agent binds back with attach.
Atomic: it performs the whole operation or none of it. JSON on stdout.
The harness-agnostic worker contract.skills/reckon-ship/references/worker-protocol.md owns the task-definition
contract, the four fences, the compact manifest shape, and the escape hatch — everything
true of a worker regardless of backend. Having one home for these is what stops them
drifting between backends. The fence set is scope, time, evidence and delivery; delivery
is a fence rather than a convention because a background worker can complete its work and
end its turn without delivering a report, at which point the node looks failed when it is
not.
The escape hatch. A worker stops and emits a report opening with
NEEDS-HELP: and four required fields: tried: the attempt and its
observable result, options: two or three concrete paths, leaning:
which and why, cost-if-wrong: what must be redone. Named triggers: the same
command failed twice with different fixes attempted; a decision the plan does not settle is
required; the necessary change exceeds the write scope; the gate's evidence cannot be
produced with the available tools or data; or the budget is spent with the gate still
closed. The orchestrator answers by default, escalates only scope trade-offs and
irreversible choices, and resumes the same session — which is why session reuse is
load-bearing rather than an optimisation.
The summary reflex. Four axes — what, why, how, when — emitted at
dispatch, at completion, and when micro-planning the next step, one line each, at most two
lines per axis, restating nothing the plan already says. The binding discipline is that
at completion, why carries the gate evidence, which forces every wave report to be
quantitative and makes a wave that cannot state its evidence visibly incomplete rather
than plausibly done. Specified with worked examples in
Agent Fleet Orchestration §8.
Continuation wiring at every level. Work must never end without naming
what comes next, and the chain has to close at three altitudes rather than one. A
worker returns candidate follow-ons in its manifest — work it discovered but
was fenced out of — which the orchestrator either folds into the current wave or writes as a
plan followup; today a worker's out-of-scope discovery has nowhere to go but prose. A
plan landing resolves its driving followup and appends the next one-line
invocation, or records that the chain closes; this rule exists but is enforced only by
discipline, so make it a validated condition of the writeback. A sprint close
reports the sprints it feeds, derived from the dependency graph — the downstream sprints whose
items this sprint's plans unblock — which does not exist at all today. Enforce all three: a
session ending with neither a next invocation nor an explicit no-followup outcome is a
failure, at every altitude.
Record whatever budget signal the backend emits. The two CLI backends are
asymmetric here and the design must not pretend otherwise. One emits a structured rate-limit
event carrying utilisation, reset time and a threshold status — enough to reason about
headroom. The other emits per-turn token usage but no headroom at all, and offers no query
command for it. So capture what is emitted into the run record, expose it as a budget block
that may legitimately read unknown, and never infer exhaustion from absence. Acting
on that signal is the subject of budget-aware-dispatch; this plan only ensures
the data is captured from the first dispatch onward, so the later work has history to reason
over.
The skill upgrade — and this plan owns SKILL.md outright.reckon-ship/SKILL.md gains the pre-dispatch checklist, the one dispatch
instruction, the summary reflex and the gate-fence rule that a wave does not open through a
closed gate. It gains no backend-specific text.
references/worker-backends.md is added as maintainer documentation of what
_backends.py does internally — it is not agent-facing, and the ownership test
is that a sentence in it which does not turn on process, session or observation mechanics
is misfiled.
The gate-fence rule is authored here and nowhere else. Gates are not yet structured
state, so enforcement at this stage means the orchestrator reads the plan's declared
evidence-gate table and refuses to open the next wave until its measure has produced evidence.
derived-gate-state later swaps that enforcement from reading prose to reading
computed state; it must not re-author the rule, and no concurrent node may write this file
until this plan's changes are integrated. Saying so explicitly is the point — two plans
claiming one rule is how a worker rewrites a peer's text believing it owns it.
✓ landed §4 — Evidence gates
Eleven of eleven banked, with one exemption stated rather than glossed:
the routing-leakage grep returns three hits, all in a documented legacy-tier reader that never
selects a worker, and the property is now guarded by a test so it cannot decay. Two limits found
while running it are recorded for the work downstream: one backend's restrained tier blocks all
writes including the manifest, and configured concurrency is not yet enforced by dispatch.
§ gates
Measures to demonstrate, not thresholds to tune around. The sprint closes on the first
row; the rest must all bank before the sprint is done.
End-to-end dispatch
One real node dispatched through reckon crew dispatch lands a commit in a detached worktree with its manifest on disk, verified by git show --stat showing only assigned paths. Record the run id, commit SHA and manifest path.
The same node definition dispatches successfully against at least two backends with no change to the calling instruction — only flight config differs. Both invocations recorded.
A worker deliberately driven to a NEEDS-HELP: report, all four fields present, answered by the orchestrator and resumed in the same session, with the resumed turn demonstrably retaining prior context.
A recorded case where the manifest file exists on disk; the recovery ladder is followed in order and redispatch is not the first response to an idle signal.
Tests proving each: a worker manifest carrying a candidate follow-on reaches a plan followup; a plan writeback without a next invocation or an explicit no-followup outcome is refused; a sprint close reports its downstream sprints derived from the graph. A recorded end-to-end trace shows the chain intact from worker to sprint.
A run record from each CLI backend, one carrying parsed utilisation and reset time, the other legitimately reading unknown. A test proves absence is never read as exhaustion.
§6 — A worker must be able to read the plan it is sent to read
Dispatch resolves the base to a commit, compares the working plan's bytes against that
commit's blob and verifies the named section by authored id or heading — all before a worktree
exists. It refuses at exit 4 with error=plan-unavailable, beside
2 for a malformed node and 3 for a budget hold, so a caller branches without parsing prose.
Demonstrated on the live failure rather than a fixture: with the plan genuinely dirty, a
dispatch naming it returned "differs from base 'HEAD'; commit the plan before
dispatching" and created 0 worktrees. It then blocked this session twice more, correctly
both times. 5 new tests, suite green at 1,680 (commit c558f47).
A dispatch cuts a detached worktree from a base ref and then tells the worker its first act
is to read the live plan at the named section. Those two facts do not compose: the worktree
holds the committed plan, so any edit still sitting in the orchestrator's working tree
is invisible to the worker. The node names a section that, from where the worker stands, does
not exist.
The failure is quiet in the worst way. The node is well-formed — it passes all seven
properties, because well-formedness is judged against the node, never against what its
worktree can show. Nothing warns. The worker either burns its budget hunting a missing section
or, worse, finds an older revision of it and implements the previous intent faithfully.
Observed 2026-08-12 while dispatching against a section written minutes earlier: caught
thirty-seven seconds in, by chance, only because the worktree was opened to check. The cost was
one stopped run and one removed worktree; unnoticed it would have been a wasted budget and a
plausible-looking wrong result.
Dispatch refuses before it creates anything. The plan the node names must be
readable at the base ref, must contain the named section there, and must not differ from the
orchestrator's working copy. Any of those failing is a refusal that names the file and says to
commit — checked before the worktree exists, so a refused dispatch leaves nothing to unwind.
No override accompanies this. The remedy is one commit, the rule is cheap to satisfy, and an
escape hatch here would be taken exactly in the hurry that produces the bug.
Measure
Required evidence
An uncommitted plan is refused
A dispatch whose plan differs between the working tree and the base ref is refused
with no worktree created and no run record written, and the message names the file and
the remedy.
A missing section is refused
A dispatch naming a section absent from the plan at the base ref is refused the same
way, rather than being discovered by the worker.
A clean plan is unaffected
A dispatch whose plan and section are present and committed proceeds exactly as
before; the existing dispatch tests pass unchanged.
The refusal is branchable
The caller can distinguish this refusal from a malformed node and from a budget hold
without parsing prose, and the command surface documents which code it is.
Suite green
Full reckon suite passes; new-test count recorded.
✓ landed 2026-08-12
§7 — The contract must not refuse a well-formed node
A conjunction bounds two deliverables only when a task action follows it, and a listed term
preceded by a hyphen no longer fails demonstrability; then and ;
stay explicit separators. All 3 conjoined-noun goals refused in one wave now pass while the
genuine two-deliverable goal from that same wave is still refused. Re-checked against this
session's own three refusals: 2 were false positives and now pass, 1 was a true positive and
still refuses — a bare vague adjective, which is the case the check exists for.
2 new tests, suite green at 1,701 (commit a2aef3e).
Two properties reject nodes that satisfy them, and both failures share a shape: a pattern
matching a surface feature of the wording rather than the thing the property is about.
Single-goal matches any " and ". A goal naming one deliverable
through a conjoined noun phrase — "round-trip a section from parse and serialisation", "derived
age and a staleness verdict", "sprint order and incompleteness" — is refused as two nodes. Three
of three nodes in one wave were refused this way, each reworded to remove a conjunction that was
never a second deliverable. The distinction that matters is between a conjunction joining two
verb phrases and one joining a noun phrase.
Demonstrable matches a subjective term inside a compound. The check tests a
word boundary, and a hyphen is one, so machine-readable, human-readable
and any compound ending in a listed adjective are rejected as opinions. Observed twice today,
once while dispatching the guard in §6 itself: a done-when naming a machine-readable exit code
was refused for resting on the term "readable".
The direction of the error is what makes these worth fixing. Both checks
exist to stop a worker being sent an unmeasurable goal; here they block the most precise
available wording and push the coordinator toward vaguer text. And both were survivable only
because a human noticed — a refused dispatch is silent about whether the refusal was correct.
The checks are worth keeping: the same pass correctly caught a genuine two-deliverable goal
and a time budget overrunning its fence. The defect is precision, not existence, so the measure
is a test carrying both the correctly-refused and the wrongly-refused wording from the waves that
produced them.
Measure
Required evidence
A conjoined noun phrase passes
The three real goals refused in one wave pass, while a genuine two-deliverable goal
from the same wave is still refused, in one test.
A hyphenated compound passes
machine-readable in a done-when passes while a bare subjective adjective
is still refused, in one test.
Suite green
Full reckon suite passes; new-test count recorded.
✓ landed 2026-08-12
§8 — A property that checks exclusivity must not sound like it checks sufficiency
A dry run now returns the write paths it resolved, so a coordinator sees what it actually
fenced before committing a wave to it, and the worker protocol states plainly that scoped
checks exclusivity and does not prove the named paths can carry the goal. 2 new tests
(commit 7952c4c). The worker reported blocked rather than
claiming complete, because the full suite was red on arrival from a concurrent commit deriving
plan dispatchability — its own two measures passed throughout, and the suite came back green at
1,711 once that peer landed its fix. The run is recorded with gate not-run: the
measure was unevaluable against this node, which is not the same as failed.
A node can satisfy all seven properties and still be unbuildable. Scoped verifies that write
paths are enumerated and shared with no concurrent node; nothing verifies that those paths can
carry the goal. Observed today: a node fenced to two files passed validation and blocked on
arrival, because the behaviour it had to change lived in two further files — exactly one of the
two required surfaces was reachable, so the assertion the node existed to make could not
truthfully be made.
The escape hatch handled it as designed: the worker audited the call graph, changed nothing,
and named both missing files. The cost was still a full dispatch cycle, and the fault was the
coordinator's — the fence came from a symbol search rather than from the callers of the thing
being changed.
A property that sounds like it guarantees buildability while checking only
exclusivity is worse than one that states its own limit. So the cheap half is to report
the resolved write scope back from a dry run, letting a coordinator see what it actually fenced
before committing a wave to it; and the honest half is to say plainly, in the contract, what
scoped does and does not check.
Measure
Required evidence
A dry run reports the scope it resolved
The dry-run payload carries the resolved write paths, shown by a test reading them
back.
The property states its own limit
The contract says scoped checks exclusivity and not sufficiency, in the skill and in
the worker protocol, asserted by a contract test.
Suite green
Full reckon suite passes; new-test count recorded.
✓ landed 2026-08-12
§9 — A followup id must identify exactly one followup
Append refuses a duplicate id across followups, questions, research and comments, naming the
existing entry and leaving the version unmoved; a resolve whose id has no open entry returns
an error instead of reporting success; and resolve skips a closed duplicate to reach the open
match. Validated non-mutatingly against this plan's own live HTML — 2 matching entries, 1 open
before and 0 open after — then the stuck record was closed for real. 4 new tests, suite green
at 1,703 (commit 6b043e3).
Two sessions independently minted f-uwd-003 against this plan, and the store
accepted both. The consequence is not cosmetic: resolve targets by id, so it matched
the same article twice and reported success both times while leaving the second
followup open. A write that cannot address a record it claims to have written is worse than one
that fails, because nothing surfaces the miss — it was caught only by reading the state back and
counting.
The neighbouring ledger already refuses this exact shape: append_run rejects a
second record for a run id, on the grounds that a double promotion double-counts the very
measurements a later reader depends on. A collection whose entries are addressed by id owes the
same guarantee, and followups are addressed by id on every resolve.
Two halves, and the second is what makes the first safe to rely on. Append refuses a
duplicate id, naming the existing entry, so the collision is a visible error at the
moment it is created rather than a silent one later. And a resolve that matches no open
entry says so instead of reporting success, which is the failure that hid this one.
The stuck record on this plan is the test case: its content is already folded into §7, and it
cannot be closed through any sanctioned write path today — the prose tool correctly refuses to
edit structured state, and the state tool cannot reach past the first match.
Measure
Required evidence
A duplicate id is refused on append
Appending a followup whose id already exists raises, naming the existing entry, in a
test; the same holds for the other id-addressed collections.
A resolve that matches nothing says so
Resolving an id with no open entry reports a failure rather than success, in a test
that would have caught the duplicate-id miss.
The stuck record closes
The second f-uwd-003 on this plan is resolvable and resolved, shown by an
open-followup count of zero.
Suite green
Full reckon suite passes; new-test count recorded.
✓ landed 2026-08-12
§10 — The continuation check must fire on a landing, not on a resolve
An active plan below full implementation now carries its own continuation, so an ordinary
mid-run resolve passes; at 1.0 a final resolve with no chain answer still refuses, new terminal
landings without one still refuse, and plans already recorded as shipped stay writable. The
gate that mattered is met directly: the same resolve driven through the ops path and the HTTP
patch path returns [true, true], and both persist zero open followups — the two
doors that disagreed now answer alike. 5 new tests over 6 cases, suite green at 1,717
(commit ac93488). Reported blocked on a stale base: the 3 roadmap failures it saw
had already been fixed on main by a concurrent session before it finished.
The rule that work must not end without naming what comes next is enforced on two write
paths, and they disagree. The ops path treats a batch that resolves a followup or sets a
terminal status as a landing; the HTTP patch path keys on terminal status alone. The same resolve
is therefore refused through one door and accepted through the other — which is exactly the drift
the shared definition was introduced to prevent, and the module says so in its own words: one
definition exists "so the ops writer and the HTTP patch writer cannot disagree". They share the
definition of a continuation. They do not share the trigger.
Resolving a followup is not a landing. A plan left active, below full
implementation, with a section dispatched and in flight, has manifestly not ended — yet the
refusal reads "plan landing leaves no continuation". An error that misdescribes what happened is
worse than no error, because the reader satisfies the string instead of the intent.
And the cheapest way past a false fire corrodes the signal it protects. The
outcome text only has to contain "no followup" to pass, so a check firing on ordinary mid-run
resolves trains its users to write that phrase into outcomes that are not final. Every false fire
devalues the marker for the one case it exists to catch. This was met live: the phrase had to be
worded carefully into a genuinely non-final outcome to get a true statement past the check.
Once same-plan follow-on work is folded into sections rather than deferred as followups,
zero open followups becomes the normal state of a healthy active plan. A check
keyed to that condition fires on the common case and stays quiet on the rare one.
Fix the definition, not the trigger. Narrowing the ops trigger to terminal
status would lose a real protection: a session that resolves its driving followup, leaves the
plan active and ends naming nothing is the failure this was built for. Instead let a plan that is
manifestly still in progress — non-terminal status below full implementation — count as carrying
its own continuation. A final resolve on a plan with nothing left still refuses; both fields are
already structured state, so nothing has to parse the HTML for a rendering convention that would
rot; and the reconciliation lands in the shared definition, which is where the module already
says the single truth belongs.
Measure
Required evidence
Both write paths agree
One test drives the same resolve through the ops path and the HTTP patch path and
asserts the same verdict from each.
A mid-run resolve passes
Resolving a followup on an active plan below full implementation succeeds and leaves
no open followup, reproducing the case met on this plan today.
The real failure still refuses
A batch setting a terminal status with no open followup and no chain-closed outcome is
still refused, and so is a final resolve that leaves nothing naming what comes next.
History stays editable
The existing rule that only a new landing owes an answer is preserved, so plans already
recorded as shipped without a followup remain writable.
Suite green
Full reckon suite passes; new-test count recorded.
§5 — Constraints
Worker prompts carry fences and a pointer to the live plan. They never copy plan
context, decisions, research or done-when prose — a copied brief becomes a second source of
truth that drifts between workers and sessions.
The worktree dispatch contract already in
references/sprint-orchestration.md §6 remains binding and is not restated:
no branch creation or switching, no stash, rebase, clean or hard reset, explicit path
staging only, no shared plan-state edits, conventional commit subject and body, no
AI attribution, no plan or sprint identifiers in commit messages.
Workers default to the full-access tier bounded by their detached worktree. A node whose
only write is its own manifest may be dropped to a read-only tier as a runtime choice; that
is routing, not a policy change.
§ Decisions
One execution skill, or a sibling skill for external-harness teams?
A sibling skill was designed first and rejected during review as a drift risk.
Classifying the intended additions showed only two of six were harness-specific — launch mechanics and session reuse. The other four would have been duplicated subsystems. The durable rule: split a skill when the process differs, never when only the substrate differs. Adding a thin entry point later costs a small file; un-forking two drifted skills is a real merge.
What tier do workers run at inside their worktree?
A workspace-write sandbox is inherited by child processes and breaks test runners, builds and anything spawning subprocesses — workers must be able to run the verification their gates demand. The detached worktree bounds blast radius instead. The reviewed tier remains available per-node for work that does not build.
Should dispatch be an MCP tool or a CLI command?
Dispatch must spawn a background process the agent then yields on, which an MCP tool cannot usefully do. Keeping reads on MCP also holds that surface at five tools, consistent with reckon's ongoing tool-count collapse.
§ Followups
Build the uniform dispatch path and the worker contract
Land the backend translation module, the atomic dispatch and attach primitives, the task-definition contract with pre-dispatch validation, the structured escape hatch, the four-axis summary reflex, and the skill upgrade. Close on a real node dispatched end to end through the uniform call.
/reckon-ship uniform-worker-dispatch
Landed — commits a927c9c, 8a44624, 0ae4167, d3a7617, 2224770. Six nodes dispatched through one call across two external harnesses and the calling harness; all 11 gates banked. One node definition reached the same 36-key routing result on two backends; an unprompted four-field NEEDS-HELP report was answered and resumed in the same session, which restated its measurements without re-running; budget read utilisation 1.02% on one backend and explicit unknown on the other. 1,598 tests pass (103 new). Two live defects found and fixed: the resume invocation was rejected on argument order, and a dead process with an empty log misread as starting.
Promote live run pointers into the committed run ledger
Dispatch now writes a transient live pointer per run and observation folds the stream, manifest presence and budget signal back into it, but nothing promotes a finished run into durable committed history. Two limits surfaced while running the wave and belong to this work or its neighbours: one backend's restrained tier blocks all writes including the manifest, so a read-only node has no delivery channel; and configured per-backend concurrency is resolved but not enforced by dispatch, so the cap is currently advice to the caller.
/reckon-ship crew-run-ledger
Foreign-owner: the promotion work it names landed in crew-run-ledger, which is shipped at 1.0 — live pointers now promote into the repository's committed ledger with recovery for an interrupted orchestrator. Closed here rather than left open against a plan that no longer owns it.
Stop the single-goal check rejecting a conjoined noun phrase
The single-goal property matches any " and " in the goal, so it refuses goals that name one deliverable: round-trip a section from parse and serialisation, derived age and a staleness verdict, sprint order and incompleteness. Three of three nodes in one wave were refused on this, each reworded to remove a conjunction that was never a second deliverable.
The check is worth keeping - the same pass correctly caught a genuine two-deliverable goal and a time budget overrunning its fence in the same wave. The defect is precision, not existence. Distinguish a conjunction joining two verb phrases (two deliverables) from one joining a noun phrase (one deliverable), and measure it with a test carrying both the refused-correctly and refused-wrongly goals from that wave.
/reckon-ship uniform-worker-dispatch
Folded into §7 as its second measure, and closed only once §9 made it reachable: resolve now skips a closed duplicate to reach the open match, so the record that reported success twice while leaving this one open is addressable. Measured on the merged code — two of the three wordings this session was refused on now pass, and the third was a true positive that still refuses, because "correctly" standing alone really is the vague adjective the check exists to catch.
The subjective-term check fires inside hyphenated compounds
The demonstrable property rejects a done-when containing a subjective adjective, matched on a word boundary. A hyphen is a word boundary, so machine-readable, human-readable and any compound ending in a listed term are rejected as opinions. Observed 2026-08-12 dispatching the section-6 guard itself: a done-when naming a machine-readable exit code was refused for resting on the subjective term 'readable', and the node had to be reworded rather than fixed.
The cost is small but the direction is wrong: the check exists to stop a worker being sent an unmeasurable goal, and here it blocks the most precise available wording. Narrow the match so a compound whose head is not the listed adjective passes, and keep a test for both the true positive and this false one.
/reckon-ship uniform-worker-dispatch
Folded into §7 as its second measure and closable only once §9 shipped, since resolve now skips a closed duplicate to reach the open match. Closed through the merged code in-process: the long-running MCP server still held the pre-merge store, so its resolve reported success while changing nothing — the silent-success failure §9 exists to remove, met once more on the way out. done — no followup: every remaining item on this plan is a section (§8 is dispatched and in flight), which is the folding rule working as intended rather than a chain that stops.
Scoped checks that paths are exclusive, never that they are sufficient
A node can satisfy all seven properties and still be unbuildable. The scoped property verifies that write paths are enumerated and shared with no concurrent node; nothing checks whether those paths can actually carry the goal. Observed today: a node routing gate state into the blocking derivation was fenced to reckon/lifecycle.py and reckon/roadmap.py, passed validation, and blocked on arrival - read_plan builds its blocking rows in mcp_views._blocking for typed reads and serve._derive_lifecycle for discovery reads, so exactly one of the two required surfaces was reachable and the two-direction assertion could not truthfully be made.
The escape hatch caught it cleanly, which is the intended division of labour: the worker audited the call graph, changed nothing, and named both missing files and functions. But the cost is a full dispatch cycle, and the fault was the coordinator's - the fence was inferred from a symbol search rather than from the callers of the thing being changed.
Two directions, and the first is cheap. Have --dry-run report the write scope back as a resolved list so a coordinator sees what it actually fenced before committing a wave to it. Then consider whether a sufficiency hint is possible at all: the paths naming a symbol the goal mentions, or the callers of a function in scope, would have surfaced both missing files here. If it cannot be checked, say so in the contract - a property that sounds like it guarantees buildability while checking only exclusivity is worse than one that states its own limit.
/reckon-ship uniform-worker-dispatch
Folded into §8. The finding is sharper than a missing check: a property that sounds like it guarantees buildability while verifying only exclusivity is worse than one that states its limit, so the section requires both the cheap fix (a dry run reporting the scope it resolved) and the honest one (the contract saying what scoped does not check).
Plan closed — done, no followup. Five sections landed in one run (§6 worktree-visibility guard, §7 contract precision, §8 scope sufficiency, §9 followup id integrity, §10 continuation trigger), every one of them work that surfaced during the run rather than being deferred out of it. Four followups were drained to zero: one closed against the plan that had since shipped its work, three folded into sections. Suite 1,717 green. Two workers reported blocked rather than claiming complete, both times against a suite made red by a concurrent session; the escape hatch and the ownership rule between them cost nothing and hid nothing.