plans: row 156 brief takes Filbert's three edits (task ref in landHolders, land and landing from one read, decision-consumed in flight)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-18 10:04:32 -05:00
co-authored by Claude Opus 5.5
parent 957fbfd410
commit 9cc0ba0e15
+19 -8
View File
@@ -32,8 +32,8 @@ This row makes the host start the landing run itself.
- `packages/bus/src/broker.mjs`: a trusted read, `landHolders(business)`,
the non-thread instances for which `landHeld` with `thread: null` is
true, each with the id and resolution time of the decision that makes
it true
true, each with the id, the resolution time and the task ref (the
raised context's target) of the decision that makes it true
- `packages/bus/src/runtime.mjs`, `packages/bus/src/process.mjs`: the
launch op `landHolders`, beside `threadsState` (`runtime.mjs:163`,
`process.mjs:18`, `:36`)
@@ -88,8 +88,12 @@ This row makes the host start the landing run itself.
host reads that instance's entries from `landHolders` beside the
`landHeld` call (`launcher.mjs:262`) and writes them into the session
file as `landing: [{ decision, task_ref }]`. `task_ref` is the raised
context's target (`broker.mjs:964`). Before its receive loop, the
runner takes one turn per entry. The request is a fixed template that
context's target (`broker.mjs:964`). For a non-thread instance,
`land` comes from the same read and is true when the instance has a
`landHolders` entry. Two separate reads could disagree if a decision
resolves between them, and the run would get a landing turn without
`land_work`. A thread run keeps the `landHeld` call. Before its
receive loop, the runner takes one turn per entry. The request is a fixed template that
names the decision id and the task ref and says to land it with
`land_work`. The run sends no reply message for these turns, and the
runner logs each turn's outcome. Nothing in the template comes from a
@@ -97,10 +101,15 @@ This row makes the host start the landing run itself.
today.
7. Row 149's fallback, where the chief of staff launches merge-gate and
then sends it a message naming the task ref and the decision, still
works. If the landing turn already spent the decision, the second
land is refused with `decision-consumed` (`broker.mjs:853`), and
merge-gate's contract says that refusal means the landing already
happened.
works. If the landing turn already spent the decision, `checkLand`
refuses the second land with `decision-consumed` (`broker.mjs:853`).
If the first landing is still in flight, `checkLand` passes, because
the broker marks a decision spent only at `recordLand`. The second
land is then refused with `decision-consumed` at `recordLand`, under
the repository lock (`git-socket.mjs:346-378`), and the refusal comes
in the later RESULT, not in the `land_work` reply. Merge-gate's
contract says `decision-consumed` in either place means the landing
already happened. Row 149's round 4 carries that sentence.
Tests:
@@ -119,6 +128,8 @@ Tests:
This holds with the raising run's poll active, which is the shape of
Filbert's probe. A run with no held decision has no `landing` and
takes no turn until a message arrives. A thread run has no `landing`.
- A non-empty `landing` always comes with the bundle's Landing line,
because both come from one `landHolders` read.
- A malformed `landing` entry, one whose decision isn't an id or whose
task ref isn't a task ref, makes the runner refuse to start rather than
take the turn.