Skip to content

feat(queue): record a wait on a condition outside the queue - #68

Merged
LeTuR merged 3 commits into
mainfrom
feat/record-a-wait-on-a-condition
Sep 11, 2026
Merged

feat(queue): record a wait on a condition outside the queue#68
LeTuR merged 3 commits into
mainfrom
feat/record-a-wait-on-a-condition

Conversation

@LeTuR

@LeTuR LeTuR commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Intent

Give a task held by something OUTSIDE the fleet queue a state it can actually be recorded in, so the reconciler stops reporting it as work somebody could dispatch.

The incident: on 2026-09-11 vending-machine-egress-resume/01-vm-identity-reconciliation was ready by every record fleet keeps and unrunnable in fact — its brief's first instruction reads Azure and az was not authenticated. queue.sh block required --on <ref> ("the task this one waits for"), so nothing could be written down. plan listed the task as ready and scripts/lib/notify_lead.py correctly typed the reconciler's one line into the lead's terminal telling it to dispatch. The only honest response was to refuse in conversation and leave the record saying nothing.

What was built, and the decisions behind it:

  • A second form of blocker. A blocked_by entry now names EITHER task: or condition:, never both; --on and --condition are a required mutually-exclusive argparse group. The existing task-to-task form is unchanged, deliberately, including clearing on landed rather than done and printing UNCLEARABLE when the upstream is stuck/failed/abandoned.
  • CONDITION_KINDS is a SECOND closed set rather than a reuse of BLOCKER_KINDS. Those four all describe a relationship between tasks, so every condition would have landed on other and the set would have stopped saying anything. --why stays required: a wait nobody explained is what this repo already refuses. --kind's argparse choices is the union because argparse has not read --on/--condition yet; cmd_block refuses a kind from the wrong set, where it can say which set applies.
  • A condition NEVER clears itself. blocker_cleared answers False for it forever; only block <ref> --clear --condition '<text>' removes one. No timer, no collect, no reap, no inference from a later dispatch succeeding — a condition that expired on its own would put back exactly the silence the defect is about. reconcile.sh remains unable to clear one, which follows from the existing rule that the loop calls only watch/collect/shepherd/refuel/plan; reconcile-selftest.sh was left alone so it keeps asserting that.
  • Every surface carries it, derived from queue.py's blocker_view/blocker_line so the four readers cannot disagree: plan's waiting block, list, show, fleet-status.sh (text and --json), and the TUI pane. notify_lead.py needed NO code change — it reads plan --json's ready set and derives nothing, which is the point — so only its header says so; a rule about conditions written there too would be the second opinion the single reading exists to prevent. The outcome is asserted directly in queue-selftest.sh section 20a instead, written as the case it came from: one task ready, one held by a condition, and the loop says one.
  • The pane draws a condition as ⊘ rather than ↳, because "↳ 02-foo" is a wait with an end and a condition has no such event — the operator reading the row is the only actor. Conditions ride in the pane's existing ref|kind field with a ! leader (no task ref can start with one); the shell probe flattens , and | out of the free-prose condition text, and the Lua side runs it through scalar() because PyYAML quotes free prose containing ": " on disk and those quotes are the writer's, not the operator's.
  • A blank --condition is refused rather than falling through to the --on path: the flag being given satisfies argparse, but an empty wait is one nobody named and --clear could never name back.
  • "They edit the same file" is still not a blocker of any kind and the new form must not become a way to spell it. add --touches remains the answer and the existing refusal still refuses; the selftest asserts --kind file-overlap is refused on the condition form too.

Scope constraints the user set: do not change dispatch's behaviour on a spawn failure and do not touch title validation — a parallel task is changing both. Keep changes contiguous in scripts/lib/queue.py and add the new selftest section at the END of scripts/queue-selftest.sh rather than interleaving, so the two diffs rebase cleanly.

Verification: ./scripts/check.sh is green, including its queue, reconcile and pane sections. queue-selftest.sh gained sections 20/20a/20b (about 50 assertions) and pane-selftest.sh gained five. AGENTS.md, scripts/queue.sh's usage header and .agents/skills/fleet-queue/SKILL.md section 3 all describe the new form.

Note on this run: an earlier pipeline run on this branch reached document and its agent exited on an account usage limit. Its review fix commit (193021c, "refuse a blank --condition and unquote it in the pane") was recovered with axi sync --recover and is part of the history being validated here.

What Changed

  • queue.sh block gains a second, mutually-exclusive form: --condition '<what>' beside --on <ref>, validated against its own closed CONDITION_KINDS set (missing-credential, awaiting-approval, closed-window, broken-dependency, undecided, other) with --why still required. A blank --condition is refused rather than falling through to the --on path, and --kind file-overlap stays refused on both forms.
  • A condition never clears itself: blocker_cleared answers False for it forever, find_cycle skips it since it is not an edge, and only block <ref> --clear --condition '<text>' removes one — which refuses when the task records no such condition. check validates each blocked_by entry against the set matching its form and rejects one naming both a task and a condition.
  • Every reader carries the new form off blocker_view/blocker_line: plan, list, show, the run-log facts block, and the TUI pane, which draws a condition as instead of , carries it in the existing ref|kind field behind a ! leader, and unquotes it through scalar(). notify_lead.py gained header prose only — it still derives nothing from plan --json. Docs updated in AGENTS.md, queue.sh's usage header, the queue README.md and the fleet-queue skill; queue-selftest.sh gained sections 20/20a/20b and pane-selftest.sh five assertions.

Risk Assessment

✅ Low: Purely additive second blocker form with no behaviour change to the existing task-to-task path, every reader of blocked_by updated to the safe accessor, both prior review decisions verified present and correct, and roughly fifty new executable assertions across queue-selftest and pane-selftest covering the refusals, all five surfaces, and the incident case itself.

Testing

Baseline ./scripts/check.sh was already green; I re-ran only the two targeted sections this change touches (check.sh queue pane, exit 0) and then drove the feature myself against the real CLI in a throwaway queue rather than relying on the selftests. The incident replays correctly: with the condition recorded, plan moves the task into the waiting block with the condition, the reason and "only block --clear releases it", plan --json drops it from ready, and the reconciler's line into the lead names one task instead of two. Nothing in the loop releases it — collect, reap, watch, shepherd and refuel all ran with conditions standing and the waits survived, while the ordinary task-form blocker still cleared on the land and not on the conclusion. Both recorded review fixes reproduce as failures on the pre-fix commits: block --condition '' raised TypeError: argument of type 'NoneType' is not iterable on c694a36 and is now a plain refusal (exit 2), and the pane drew ⊘ 'security review #42: …' with the writer's YAML quotes on c694a36 and draws it unquoted now. Visual evidence is a rendered-text artifact (pane-render.html) rather than a screenshot of a live thurbox: the pane is a TUI plugin, and putting it on a real screen would mean installing into the operator's thurbox config outside this worktree, so I fed the pane's own shell probe over live records into its offline renderer instead — the same rows, minus real colours.

  • Live validation: ✅ go - 13 of 13 scenarios driven live against the product
Scenario Result Live Evidence
An operator records a task as held by an unauthenticated az, and plan stops calling it ready ✅ pass live queue.sh block … --condition &#39;az is authenticated for the mazet tenant&#39; --kind missing-credential --why … then queue.sh plan in an isolated FLEET_QUEUE_DIR — evidence/01-record-condition-and-plan.…
The 2026-09-11 incident: the reconciler's line to the lead names only work somebody can dispatch ✅ pass live queue.sh plan --json over the live queue lists only 02-document-the-tables as ready (evidence/02-reconciler-wake-line.txt); piping that into scripts/lib/notify_lead.py types "1 task(s) ready … — v…
Nothing in the reconciler's loop releases a condition — collect, reap, watch, shepherd and refuel all run with one standing ✅ pass live evidence/03-collect-reap-condition-stands.txt and evidence/17-loop-commands-release-nothing.txt: the upstream PR merges, the task-form blocker clears on landed, ready grows by one and not by two, an…
Only a hand releases it: block --clear --condition naming the exact text, and nothing else ✅ pass live evidence/11-clearing-is-a-hand.txt: clearing 'az is logged in' is refused and says what the task does hold; clearing the exact text reports "1 blocker(s) cleared" and the task returns to the ready set…
A blank or whitespace-only --condition is refused instead of crashing (review round 1 regression) ✅ pass live evidence/09b + 09: the c694a36 queue.py raises TypeError: argument of type &#39;NoneType&#39; is not iterable; the target commit refuses with the named-wait paragraph and exit 2, on both the record and the…
"They edit the same file" cannot be spelled as a condition ✅ pass live evidence/10-adversarial-refusals.txt: --kind file-overlap on the condition form is refused and the refusal still points at add --touches; the task record is unchanged afterwards
The two kind sets stay two, and a blocker names a task or a condition and never both ✅ pass live evidence/10: a task kind on --condition is refused listing the condition set, a condition kind on --on is refused listing the task set plus a pointer to --condition, both flags together give arg…
Every reader reports the same wait: plan, list, show, fleet-status (text and --json), the record on disk and the run log ✅ pass live evidence/04 and evidence/05: one blocker_line everywhere; fleet-status.sh --json gives &#34;status&#34;: &#34;outside&#34; with &#34;cleared&#34;: false; the run log writes "waits on a condition outside the queue — ……
The TUI pane draws a condition as ⊘ with the writer's YAML quoting stripped (review round 2 regression) ✅ pass live The pane's own PROBE, extracted verbatim from interface/fleet_queue.lua and run over the live queue, emits !&#39;security review #42: somebody has to answer it&#39;|awaiting-approval (evidence/06); renderin…
A task carrying both blocker forms, with , and | inside the condition text, stays readable everywhere ✅ pass live evidence/14: show and plan keep the text verbatim, the probe flattens the two field separators to spaces, and the pane draws one ⊘ row rather than splitting it into a bogus second edge
dispatch refuses a condition-held task named explicitly and leaves it out of the bare ready set ✅ pass live evidence/12: dispatch --dry-run &lt;ref&gt; exits 2 quoting the condition line; bare dispatch --dry-run plans only the two unheld tasks
check validates the new record shape and catches a hand-edited one ✅ pass live evidence/12 (queue check: ok — 1 topic(s), 4 task(s)) and evidence/13: a blocker naming both forms, a kind from the wrong set, and a missing reason are each reported, exit 1
A condition recorded against a task that already concluded reads as moot and holds nothing ✅ pass live evidence/16: show reads "was held by awaiting-approval outside the queue (…); this task concluded, so it holds nothing" and the ready set is unaffected
Evidence: TUI queue pane rendered from a live queue — after vs. before the unquoting fix, at three widths
<!doctype html>
<meta charset="utf-8">
<title>fleet queue pane — a wait on a condition</title>
<style>
 body { background:#14161a; color:#d7dae0; font:14px/1.5 -apple-system,Segoe UI,sans-serif; margin:2rem auto; max-width:64rem; }
 h1 { font-size:1.25rem; } h2 { font-size:1rem; color:#9aa2ad; margin-top:2rem; }
 pre { background:#0e1013; border:1px solid #272b33; border-radius:6px; padding:1rem;
        font:13px/1.35 "JetBrains Mono",Menlo,Consolas,monospace; overflow-x:auto; }
 .note { color:#9aa2ad; } mark { background:#3a2f12; color:#ffd479; }
</style>
<h1>The TUI queue pane, rendered from a live queue</h1>
<p class="note">Records written by <code>./scripts/queue.sh block … --condition …</code> in an isolated
queue, read by the pane's own shell probe, drawn by <code>interface/fleet_queue.lua</code>.
<code>⊘</code> marks a wait with no actor but the operator; <code>↳</code> stays the wait on a task.</p>
<h2>width 60 — after (target commit 193021c)</h2>
<pre> ⛽ fuel reserve 15%                                      2m
 claude ██████┃██████████████████████░░░░░░░░░░░░░░░░░░  62%
────────────────────────────────────────────────────────────
 1 ready  2 waiting  1 done
────────────────────────────────────────────────────────────
 ▶ READY  1 topic
 ── vending-machine-egress-resume ──────────────────────────
 ◆ 01 Reconcile the VM identities                         0s
   ⊘ az is authenticated for the mazet tenant  credential
 ▶ 03 Terraform the VMs                                   0s
 ◆ 04 Open the egress subnet                              0s
   ⊘ security review #42: somebody has to answer …  approval
   1 landed</pre>
<h2>width 60 — before the review fix (c694a36): the writer's YAML quotes leak into the row</h2>
<pre> ⛽ fuel reserve 15%                                      2m
 claude ██████┃██████████████████████░░░░░░░░░░░░░░░░░░  62%
────────────────────────────────────────────────────────────
 1 ready  2 waiting  1 done
────────────────────────────────────────────────────────────
 ▶ READY  1 topic
 ── vending-machine-egress-resume ──────────────────────────
 ◆ 01 Reconcile the VM identities                         0s
   ⊘ az is authenticated for the mazet tenant  credential
 ▶ 03 Terraform the VMs                                   0s
 ◆ 04 Open the egress subnet                              0s
   ⊘ &#x27;security review #42: somebody has to answer…  approval
   1 landed</pre>
<h2>width 30 — the narrow pane keeps the mark</h2>
<pre> ⛽ fuel reserve 15%        2m
 claude ██┃████████░░░░░░  62%
──────────────────────────────
 1 ready  2 waiting  1 done
──────────────────────────────
 ▶ READY  1 topic
 ── vending-machine-egress-… ─
 ◆ 01 Reconcile the VM id…  0s
   ⊘ az is authen…  credential
 ▶ 03 Terraform the VMs     0s
 ◆ 04 Open the egress sub…  0s
   ⊘ security revie…  approval
   1 landed</pre>
Evidence: Recording the condition, and the plan that follows

$ queue.sh block 01-vm-identity --condition "az is authenticated for the mazet tenant" --kind missing-credential --why "..." vending-machine-egress-resume/01-vm-identity waits on a condition outside the queue (missing-credential): az is authenticated for the mazet tenant Nothing clears this but you: ./scripts/queue.sh block vending-machine-egress-resume/01-vm-identity --clear --condition 'az is authenticated for the mazet tenant' $ queue.sh plan ready: 1 task(s) ... vending-machine-egress-resume/02-document-the-tables waiting: 2 task(s) — each held by a durable, recorded blocker vending-machine-egress-resume/01-vm-identity held by missing-credential outside the queue (az is authenticated for the mazet tenant) — only block --clear releases it: the brief's first instruction reads Azure and az account show fails

$ queue.sh block 01-vm-identity --condition "az is authenticated for the mazet tenant" --kind missing-credential --why "..."
vending-machine-egress-resume/01-vm-identity waits on a condition outside the queue (missing-credential): az is authenticated for the mazet tenant
    Nothing clears this but you: ./scripts/queue.sh block vending-machine-egress-resume/01-vm-identity --clear --condition 'az is authenticated for the mazet tenant'

$ queue.sh block 03-terraform-the-vms --on 02-document-the-tables --kind semantic-dependency --why ...
vending-machine-egress-resume/03-terraform-the-vms waits on vending-machine-egress-resume/02-document-the-tables (semantic-dependency)

$ queue.sh plan
ready: 1 task(s) — every one of them goes out now, there is no concurrency cap
    vending-machine-egress-resume/02-document-the-tables /tmp/fleet-live-mreC/repo  feat/document-the-tables

waiting: 2 task(s) — each held by a durable, recorded blocker
    vending-machine-egress-resume/01-vm-identity
        held by missing-credential outside the queue (az is authenticated for the mazet tenant) — only `block --clear` releases it: the brief's first instruction reads Azure and az account show fails
    vending-machine-egress-resume/03-terraform-the-vms
        held by semantic-dependency on vending-machine-egress-resume/02-document-the-tables (queued): terraforms the identities 02 writes down
Evidence: The reconciler's wake line: one task ready, not two

woke Gate Control: 1 task(s) ready — vending-machine-egress-resume/02-document-the-tables --- what was typed into the lead terminal --- fleet reconciler: 1 task(s) ready and nothing will dispatch them — vending-machine-egress-resume/02-document-the-tables. Run ./scripts/queue.sh dispatch

$ queue.sh plan --json   (the one reading notify_lead consumes)
{
    "ready": [
        "vending-machine-egress-resume/02-document-the-tables"
    ],
    "waiting": [
        {
            "task": "vending-machine-egress-resume/01-vm-identity",
            "blocked_by": [
                {
                    "condition": "az is authenticated for the mazet tenant",
                    "kind": "missing-credential",
                    "why": "the brief's first instruction reads Azure and az account show fails",
                    "recorded": "2026-09-11T11:30:59+00:00"
                }
            ]
        },
        {
            "task": "vending-machine-egress-resume/03-terraform-the-vms",
            "blocked_by": [
                {
                    "task": "vending-machine-egress-resume/02-document-the-tables",
                    "kind": "semantic-dependency",
                    "why": "terraforms the identities 02 writes down",
                    "recorded": "2026-09-11T11:30:59+00:00"
                }
            ]
        }
    ],
    "overlaps": []
}

$ queue.sh plan --json | notify_lead.py     (reconciler pass)
woke Gate Control: 1 task(s) ready — vending-machine-egress-resume/02-document-the-tables

--- what was typed into the lead terminal ---
fleet reconciler: 1 task(s) ready and nothing will dispatch them — vending-machine-egress-resume/02-document-the-tables. Run ./scripts/queue.sh dispatch
Evidence: collect + reap land the upstream task; the condition is untouched
$ queue.sh collect
    vending-machine-egress-resume/02-document-the-tables  shipped  https://github.com/Thurbeen/fleet/pull/777  [publish verified: no-mistakes]
        Wrote the identity tables down.
collect: 1 result(s) read
         1 of them left an open pull request. Run
         `queue.sh shepherd --dry-run` — a PR can go bad long
         after the worker that wrote it stopped.
    vending-machine-egress-resume/02-document-the-tables kept       https://github.com/Thurbeen/fleet/pull/777 is still open — work awaiting review
reap: released 0 session(s), kept 1
    run log updated: /tmp/fleet-live-mreC/runs/2026-09-11-vending-machine-egress-resume.md

--- the PR merges upstream ---
$ queue.sh reap
    vending-machine-egress-resume/02-document-the-tables landed     https://github.com/Thurbeen/fleet/pull/777 is merged
      Run `queue.sh plan` — a blocker clears when the task it names LANDS.
    vending-machine-egress-resume/02-document-the-tables reaped     44444444-4444-4444-4444-444444444444  (idle)
reap: released 1 session(s), kept 0

$ queue.sh plan    (after collect + reap: does anything release the condition?)
ready: 1 task(s) — every one of them goes out now, there is no concurrency cap
    vending-machine-egress-resume/03-terraform-the-vms   /tmp/fleet-live-mreC/repo  feat/terraform-the-vms

waiting: 1 task(s) — each held by a durable, recorded blocker
    vending-machine-egress-resume/01-vm-identity
        held by missing-credential outside the queue (az is authenticated for the mazet tenant) — only `block --clear` releases it: the brief's first instruction reads Azure and az account show fails
Evidence: Every reader agrees: list, show, fleet-status text
$ queue.sh list
queue: /tmp/fleet-live-mreC/queue
vending-machine-egress-resume — Resume the vending machine egress work
    01-vm-identity                     waiting     /tmp/fleet-live-mreC/repo  
        held by missing-credential outside the queue (az is authenticated for the mazet tenant) — only `block --clear` releases it: the brief's first instruction reads Azure and az account show fails
    02-document-the-tables             landed      /tmp/fleet-live-mreC/repo  https://github.com/Thurbeen/fleet/pull/777  merged 0m
    03-terraform-the-vms               queued      /tmp/fleet-live-mreC/repo  
        no session dispatched


$ queue.sh show 01-vm-identity
vending-machine-egress-resume/01-vm-identity — Reconcile the VM identities
    state:       queued
    repo:        /tmp/fleet-live-mreC/repo
    host:        None
    branch:      feat/vm-identity
    base:        main
    agent:       claude
    profile:     default
    session:     None
    prompted:    False
    outcome:     None
    artifact:    None
    publish:     no-mistakes — run `/no-mistakes --yes`
    blocked_by:  held by missing-credential outside the queue (az is authenticated for the mazet tenant) — only `block --clear` releases it: the brief's first instruction reads Azure and az account show fails
    brief:       /tmp/fleet-live-mreC/queue/vending-machine-egress-resume/01-vm-identity/BRIEF.md

$ scripts/fleet-status.sh
fleet status  ·  2026-09-11T11:32:24+00:00

FUEL      1 provider(s) — account windows, every session spends them at once
  claude  22% remaining   reserve 20%   binding seven_day
      five_hour         62%  resets 2026-09-11T16:10:00.345332+00:00
      seven_day         22%  resets 2026-09-11T11:59:59.345358+00:00  binds
      model:fable      100%  resets 2026-09-11T12:00:00+00:00

QUEUE     /tmp/fleet-live-mreC/queue
          1 topic(s), 3 task(s) — ready 1, waiting 1, landed 1
  vending-machine-egress-resume — Resume the vending machine egress work
    01-vm-identity                     waiting     feat/vm-identity
        held by missing-credential outside the queue (az is authenticated for the mazet tenant) — only `block --clear` releases it: the brief's first instruction reads Azure and az account show fails
    02-document-the-tables             landed      shipped https://github.com/Thurbeen/fleet/pull/777
    03-terraform-the-vms               ready       feat/terraform-the-vms
        no session dispatched

SESSIONS  none dispatched by this queue

PRS       none open for these tasks

CHECKOUT  ~/.no-mistakes/worktrees/d1be5edfebb8/01M282XZCR3BX0G6X5H1HVNTZ7  HEAD @ 193021c  clean

$ scripts/fleet-status.sh --json | (blocked_by view)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import json,sys; d=json.load(sys.stdin); print(json.dumps([t for t in json.dumps(d) and d["queue"]["tasks"] if t.get("blocked_by")], indent=2))
                                                                                            ~~~~~~~~~~^^^^^^^^^
KeyError: 'tasks'
Evidence: fleet-status --json blocker view, the task.yaml on disk, and the run log line
$ scripts/fleet-status.sh --json    (blockers of every task that has one)
vending-machine-egress-resume/01-vm-identity
[
  {
    "task": null,
    "condition": "az is authenticated for the mazet tenant",
    "kind": "missing-credential",
    "why": "the brief's first instruction reads Azure and az account show fails",
    "upstream_state": null,
    "status": "outside",
    "cleared": false,
    "line": "held by missing-credential outside the queue (az is authenticated for the mazet tenant) \u2014 only `block --clear` releases it: the brief's first instruction reads Azure and az account show fails"
  }
]
vending-machine-egress-resume/03-terraform-the-vms
[
  {
    "task": "vending-machine-egress-resume/02-document-the-tables",
    "condition": null,
    "kind": "semantic-dependency",
    "why": "terraforms the identities 02 writes down",
    "upstream_state": "landed",
    "status": "cleared",
    "cleared": true,
    "line": "cleared: semantic-dependency on vending-machine-egress-resume/02-document-the-tables has landed"
  }
]

--- the task record on disk (task.yaml) ---
blocked_by:
- condition: az is authenticated for the mazet tenant
  kind: missing-credential
  why: the brief's first instruction reads Azure and az account show fails
  recorded: '2026-09-11T11:30:59+00:00'
session: null

--- the run log the queue wrote ---
27:- **`01-vm-identity` waits on a condition outside the queue — az is authenticated for the mazet tenant** — missing-credential: the brief's first instruction reads Azure and az account show fails
29:- **`03-terraform-the-vms` waits on `vending-machine-egress-resume/02-document-the-tables`** — semantic-dependency: terraforms the identities 02 writes down
Evidence: The pane's own shell probe run over the live queue
$ sh <the pane PROBE, verbatim from interface/fleet_queue.lua>   (over the live queue)
R<TAB>/tmp/fleet-live-mreC/queue
T<TAB>vending-machine-egress-resume<TAB>Resume the vending machine egress work
K<TAB>01-vm-identity<TAB>queued<TAB>Reconcile the VM identities<TAB>null<TAB>null<TAB>!az is authenticated for the mazet tenant|missing-credential<TAB>1<TAB>0<TAB>0<TAB>feat/vm-identity<TAB>1789126251<TAB>no-mistakes<TAB><TAB>0
K<TAB>02-document-the-tables<TAB>landed<TAB>Write the identity tables down<TAB>shipped<TAB>https://github.com/Thurbeen/fleet/pull/777<TAB><TAB>1<TAB>2<TAB>1<TAB>feat/document-the-tables<TAB>1789126333<TAB>no-mistakes<TAB>merged<TAB>1789126333
K<TAB>03-terraform-the-vms<TAB>queued<TAB>Terraform the VMs<TAB>null<TAB>null<TAB>vending-machine-egress-resume/02-document-the-tables|semantic-dependency<TAB>1<TAB>0<TAB>0<TAB>feat/terraform-the-vms<TAB>1789126252<TAB>no-mistakes<TAB><TAB>0
K<TAB>04-open-the-egress-subnet<TAB>queued<TAB>Open the egress subnet<TAB>null<TAB>null<TAB>!'security review #42: somebody has to answer it'|awaiting-approval<TAB>1<TAB>0<TAB>0<TAB>feat/open-the-egress-subnet<TAB>1789126413<TAB>no-mistakes<TAB><TAB>0
A<TAB>0
Evidence: Pane rendered from that probe output, widths 60 and 30
=== the TUI queue pane, rendered at width 60 over the live queue ===
 ⛽ fuel reserve 15%                                      2m
 claude ██████┃██████████████████████░░░░░░░░░░░░░░░░░░  62%
────────────────────────────────────────────────────────────
 1 ready  2 waiting  1 done
────────────────────────────────────────────────────────────
 ▶ READY  1 topic
 ── vending-machine-egress-resume ──────────────────────────
 ◆ 01 Reconcile the VM identities                         0s
   ⊘ az is authenticated for the mazet tenant  credential
 ▶ 03 Terraform the VMs                                   0s
 ◆ 04 Open the egress subnet                              0s
   ⊘ security review #42: somebody has to answer …  approval
   1 landed


=== the same pane at width 30 ===
 ⛽ fuel reserve 15%        2m
 claude ██┃████████░░░░░░  62%
──────────────────────────────
 1 ready  2 waiting  1 done
──────────────────────────────
 ▶ READY  1 topic
 ── vending-machine-egress-… ─
 ◆ 01 Reconcile the VM id…  0s
   ⊘ az is authen…  credential
 ▶ 03 Terraform the VMs     0s
 ◆ 04 Open the egress sub…  0s
   ⊘ security revie…  approval
   1 landed
Evidence: Pane quoting regression: before (c694a36) vs after (193021c)

=== BEFORE the review fix (c694a36 interface/fleet_queue.lua), same live probe output === ⊘ 'security review #42: somebody has to answer… approval === AFTER (193021c) === ⊘ security review #42: somebody has to answer … approval

=== BEFORE the review fix (c694a36 interface/fleet_queue.lua), same live probe output ===
9:   ⊘ az is authenticated for the mazet tenant  credential
12:   ⊘ 'security review #42: somebody has to answer…  approval

=== AFTER (193021c) ===
9:   ⊘ az is authenticated for the mazet tenant  credential
12:   ⊘ security review #42: somebody has to answer …  approval
Evidence: Blank --condition: traceback before the fix, refusal after

### BEFORE (c694a36): TypeError: argument of type 'NoneType' is not iterable ### AFTER (193021c): queue: --condition is the wait itself, in words: --condition 'az is authenticated for the mazet tenant'. Nothing removes one but block --clear --condition naming it back, so a blank one is a wait nobody could name and nobody could release. exit: 2

\### BEFORE the review fix (c694a36 queue.py): a blank --condition
$ block 03-terraform-the-vms --condition "" --kind missing-credential --why "az is not logged in"
    spec.loader.exec_module(mod)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^
  File "<frozen importlib._bootstrap_external>", line 1019, in exec_module
  File "<frozen importlib._bootstrap_external>", line 1156, in get_code
  File "<frozen importlib._bootstrap_external>", line 1214, in get_data
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/fleet-live-mreC/prefix/forge.py'
exit: 

\### AFTER (193021c): the same command
queue: --condition is the wait itself, in words: --condition 'az is
authenticated for the mazet tenant'. Nothing removes one but
`block --clear --condition` naming it back, so a blank one is a
wait nobody could name and nobody could release.
exit: 2

\### and a whitespace-only one, on the --clear form
queue: --condition is the wait itself, in words: --condition 'az is
authenticated for the mazet tenant'. Nothing removes one but
`block --clear --condition` naming it back, so a blank one is a
wait nobody could name and nobody could release.
exit: 2
Evidence: Pre-fix reproduction of the blank-condition traceback
\### BEFORE the review fix (c694a36 scripts/lib/queue.py): a blank --condition
$ block 03-terraform-the-vms --condition "" --kind missing-credential --why "az is not logged in"
  File "/tmp/fleet-live-mreC/prefix/lib/queue.py", line 1769, in cmd_block
    target = q.get(args.on)
  File "/tmp/fleet-live-mreC/prefix/lib/queue.py", line 975, in get
    fetched = self._fetch(ref)
  File "/tmp/fleet-live-mreC/prefix/lib/queue.py", line 996, in _fetch
    if "/" in ref:
       ^^^^^^^^^^
TypeError: argument of type 'NoneType' is not iterable
Evidence: Every refusal path of the new form (wrong set, both flags, neither, file-overlap, no --why)
\### "they edit the same file" is still not a blocker of any kind
$ queue.sh block vending-machine-egress-resume/03-terraform-the-vms --condition nobody else is editing main.tf --kind file-overlap --why both edit main.tf
usage: queue.sh block [-h] (--on ON | --condition CONDITION)
                      [--kind {awaiting-approval,broken-dependency,closed-window,incompatible-migration,missing-credential,other,semantic-dependency,shared-external-state,undecided}]
                      [--why WHY] [--clear]
                      ref
queue.sh block: error: argument --kind: 
a blocker needs --kind and --why, because it is the one thing that
makes work wait and it has to survive the next planning pass.
--kind is one of:
    semantic-dependency      this task consumes something the other one introduces
    shared-external-state    both mutate the same external state
    incompatible-migration   the two migrations cannot be in flight together
    other                    another concrete condition that makes independent progress unsafe
Overlapping files are not on that list. Record them with `add --touches`;
they are reported as a risk beside the ready set and hold nothing up.
Waiting on something that is not a task at all? `--condition` instead
of `--on`, with one of:
    missing-credential       a login, secret or session the work needs is not present
    awaiting-approval        a person or a process has to say yes before this can run
    closed-window            it may only run inside a window that is not open
    broken-dependency        something outside the queue is broken and has to be fixed
    undecided                the operator has not made a decision this task turns on
    other                    another durable thing outside the queue — name it in --why
exit: 2

\### a TASK kind on a condition
$ queue.sh block vending-machine-egress-resume/03-terraform-the-vms --condition az is authenticated --kind semantic-dependency --why reads Azure
queue: a blocker needs --kind and --why, because it is the one thing that
makes work wait and it has to survive the next planning pass.
--kind, for a --condition, is one of:
    missing-credential       a login, secret or session the work needs is not present
    awaiting-approval        a person or a process has to say yes before this can run
    closed-window            it may only run inside a window that is not open
    broken-dependency        something outside the queue is broken and has to be fixed
    undecided                the operator has not made a decision this task turns on
    other                    another durable thing outside the queue — name it in --why
A condition is something OUTSIDE the queue — a credential, an approval,
a window, a machine somebody has to fix. Nothing clears one but
`block <ref> --clear --condition ...`.
exit: 2

\### a CONDITION kind on --on
$ queue.sh block vending-machine-egress-resume/03-terraform-the-vms --on vending-machine-egress-resume/01-vm-identity --kind missing-credential --why az is not authenticated
queue: a blocker needs --kind and --why, because it is the one thing that
makes work wait and it has to survive the next planning pass.
--kind is one of:
    semantic-dependency      this task consumes something the other one introduces
    shared-external-state    both mutate the same external state
    incompatible-migration   the two migrations cannot be in flight together
    other                    another concrete condition that makes independent progress unsafe
Overlapping files are not on that list. Record them with `add --touches`;
they are reported as a risk beside the ready set and hold nothing up.
Waiting on something that is not a task at all? `--condition` instead
of `--on`, with one of:
    missing-credential       a login, secret or session the work needs is not present
    awaiting-approval        a person or a process has to say yes before this can run
    closed-window            it may only run inside a window that is not open
    broken-dependency        something outside the queue is broken and has to be fixed
    undecided                the operator has not made a decision this task turns on
    other                    another durable thing outside the queue — name it in --why
exit: 2

\### a blocker that names both
$ queue.sh block vending-machine-egress-resume/03-terraform-the-vms --on vending-machine-egress-resume/01-vm-identity --condition az is authenticated --kind other --why both
usage: queue.sh block [-h] (--on ON | --condition CONDITION)
                      [--kind {awaiting-approval,broken-dependency,closed-window,incompatible-migration,missing-credential,other,semantic-dependency,shared-external-state,undecided}]
                      [--why WHY] [--clear]
                      ref
queue.sh block: error: argument --condition: not allowed with argument --on
exit: 2

\### a blocker that names neither
$ queue.sh block vending-machine-egress-resume/03-terraform-the-vms --kind other --why something
usage: queue.sh block [-h] (--on ON | --condition CONDITION)
                      [--kind {awaiting-approval,broken-dependency,closed-window,incompatible-migration,missing-credential,other,semantic-dependency,shared-external-state,undecided}]
                      [--why WHY] [--clear]
                      ref
queue.sh block: error: one of the arguments --on --condition is required
exit: 2

\### a condition with no --why
$ queue.sh block vending-machine-egress-resume/03-terraform-the-vms --condition az is authenticated --kind missing-credential
queue: a blocker needs --kind and --why, because it is the one thing that
makes work wait and it has to survive the next planning pass.
--kind, for a --condition, is one of:
    missing-credential       a login, secret or session the work needs is not present
    awaiting-approval        a person or a process has to say yes before this can run
    closed-window            it may only run inside a window that is not open
    broken-dependency        something outside the queue is broken and has to be fixed
    undecided                the operator has not made a decision this task turns on
    other                    another durable thing outside the queue — name it in --why
A condition is something OUTSIDE the queue — a credential, an approval,
a window, a machine somebody has to fix. Nothing clears one but
`block <ref> --clear --condition ...`.
exit: 2
Evidence: Clearing is a hand: wrong text refused, exact text releases
--- after every refusal above, 03 records nothing new ---
blocked_by:
- task: vending-machine-egress-resume/02-document-the-tables
  kind: semantic-dependency
  why: terraforms the identities 02 writes down
  recorded: '2026-09-11T11:30:59+00:00'
session: null

$ queue.sh block 01-vm-identity --clear --condition "az is logged in"   (a condition it does not hold)
queue: vending-machine-egress-resume/01-vm-identity records no condition 'az is logged in'. It holds: 'az is authenticated for the mazet tenant'
exit: 2

$ queue.sh plan   (still held)
waiting: 2 task(s) — each held by a durable, recorded blocker
    vending-machine-egress-resume/01-vm-identity
        held by missing-credential outside the queue (az is authenticated for the mazet tenant) — only `block --clear` releases it: the brief's first instruction reads Azure and az account show fails
    vending-machine-egress-resume/04-open-the-egress-subnet
        held by awaiting-approval outside the queue (security review #42: somebody has to answer it) — only `block --clear` releases it: the subnet stays shut until the review answers

--- the operator logs in, then names the condition back ---
$ queue.sh block 01-vm-identity --clear --condition "az is authenticated for the mazet tenant"
vending-machine-egress-resume/01-vm-identity: 1 blocker(s) cleared
exit: 0

$ queue.sh plan
ready: 2 task(s) — every one of them goes out now, there is no concurrency cap
    vending-machine-egress-resume/01-vm-identity         /tmp/fleet-live-mreC/repo  feat/vm-identity
    vending-machine-egress-resume/03-terraform-the-vms   /tmp/fleet-live-mreC/repo  feat/terraform-the-vms

waiting: 1 task(s) — each held by a durable, recorded blocker
    vending-machine-egress-resume/04-open-the-egress-subnet
        held by awaiting-approval outside the queue (security review #42: somebody has to answer it) — only `block --clear` releases it: the subnet stays shut until the review answers
Evidence: dispatch refuses the condition-held task by name; check calls the record valid
$ queue.sh dispatch --dry-run 04-open-the-egress-subnet   (the condition-held task, named explicitly)
queue: these tasks were named and are not ready to go out:
    vending-machine-egress-resume/04-open-the-egress-subnet: held by awaiting-approval outside the queue (security review #42: somebody has to answer it) — only `block --clear` releases it: the subnet stays shut until the review answers
Clear what is holding them, or leave them out of the dispatch.
exit: 2

$ queue.sh dispatch --dry-run    (bare: what the whole ready set would be)
dispatch: 2 task(s), launched together — no concurrency cap,
          because every one of them has no recorded blocker left.
    vending-machine-egress-resume/01-vm-identity
      thurbox-cli session create --name '🚀 Reconcile the VM identities' --repo-path /tmp/fleet-live-mreC/repo --worktree-branch feat/vm-identity --base-branch main --on-existing fail --agent claude --json
      ./scripts/session-trust.sh <uuid>   # answer the trust dialog first
      thurbox-cli session send <uuid> 'Read /tmp/fleet-live-mreC/queue/vending-machine-egress-resume/01-vm-identity/BRIEF.md and do what it says.'
    vending-machine-egress-resume/03-terraform-the-vms
      thurbox-cli session create --name '🚀 Terraform the VMs' --repo-path /tmp/fleet-live-mreC/repo --worktree-branch feat/terraform-the-vms --base-branch main --on-existing fail --agent claude --json
      ./scripts/session-trust.sh <uuid>   # answer the trust dialog first
      thurbox-cli session send <uuid> 'Read /tmp/fleet-live-mreC/queue/vending-machine-egress-resume/03-terraform-the-vms/BRIEF.md and do what it says.'
exit: 0

$ queue.sh check   (a recorded condition is a valid record)
queue check: ok — 1 topic(s), 4 task(s) in /tmp/fleet-live-mreC/queue
exit: 0
Evidence: check catches a hand-edited blocker naming both forms
--- a hand-edited record: one blocker naming BOTH, one with a kind from the wrong set, one with no reason ---
blocked_by:
- task: vending-machine-egress-resume/01-vm-identity
  condition: az is authenticated
  kind: other
  why: hand-edited
- condition: somebody approves
  kind: semantic-dependency
  why: wrong set
- condition: a window opens
  kind: closed-window
  why: ''
session: null
$ queue.sh check
    vending-machine-egress-resume/03-terraform-the-vms: blocker names both a task and a condition; it is one or the other
    vending-machine-egress-resume/03-terraform-the-vms: blocker kind 'semantic-dependency' is not a real one
    vending-machine-egress-resume/03-terraform-the-vms: blocker on a window opens has no reason
queue check: 3 problem(s)
exit: 1
Evidence: Both blocker forms on one task, with `,` and `|` in the condition text
\### a task carrying BOTH forms, and a condition holding the two characters the pane field is built out of
vending-machine-egress-resume/03-terraform-the-vms waits on a condition outside the queue (broken-dependency): the subscription quota, or the |vnet| peering, is raised
    Nothing clears this but you: ./scripts/queue.sh block vending-machine-egress-resume/03-terraform-the-vms --clear --condition 'the subscription quota, or the |vnet| peering, is raised'

$ queue.sh plan
waiting: 2 task(s) — each held by a durable, recorded blocker
    vending-machine-egress-resume/03-terraform-the-vms
        held by broken-dependency outside the queue (the subscription quota, or the |vnet| peering, is raised) — only `block --clear` releases it: terraform apply fails on quota until somebody raises it
    vending-machine-egress-resume/04-open-the-egress-subnet
        held by awaiting-approval outside the queue (security review #42: somebody has to answer it) — only `block --clear` releases it: the subnet stays shut until the review answers

$ queue.sh show 03-terraform-the-vms   (the record keeps the text verbatim)
    blocked_by:  cleared: semantic-dependency on vending-machine-egress-resume/02-document-the-tables has landed
    blocked_by:  held by broken-dependency outside the queue (the subscription quota, or the |vnet| peering, is raised) — only `block --clear` releases it: terraform apply fails on quota until somebody raises it
    brief:       /tmp/fleet-live-mreC/queue/vending-machine-egress-resume/03-terraform-the-vms/BRIEF.md

$ the pane probe, then the pane
03-terraform-the-vms<TAB>queued<TAB>Terraform the VMs<TAB>null<TAB>null<TAB>vending-machine-egress-resume/02-document-the-tables|semantic-dependency,!the subscription quota  or the  vnet  peering  is raised|broken-dependency<TAB>1<TAB>0<TAB>0<TAB>feat/terraform-the-vms<TAB>1789126252<TAB>no-mistakes<TAB><TAB>0
 ⛽ fuel reserve 15%                                                2m
 claude ████████┃██████████████████████████░░░░░░░░░░░░░░░░░░░░░░  62%
──────────────────────────────────────────────────────────────────────
 1 ready  2 waiting  1 done
──────────────────────────────────────────────────────────────────────
 ▶ READY  1 topic
 ── vending-machine-egress-resume ────────────────────────────────────
 ▶ 01 Reconcile the VM identities                                   0s
 ◆ 03 Terraform the VMs                                             0s
   ⊘ the subscription quota  or the  vnet  peering  is raised  broken
 ◆ 04 Open the egress subnet                                        0s
   ⊘ security review #42: somebody has to answer it  approval
   1 landed
  • Evidence: The lead is woken once, after the hand clears the condition (local file: ~/.no-mistakes/evidence/01M282XZCR3BX0G6X5H1HVNTZ7/15-reconciler-after-the-hand-clears.txt)
  • Evidence: A condition on a concluded task reads as moot and holds nothing (local file: ~/.no-mistakes/evidence/01M282XZCR3BX0G6X5H1HVNTZ7/16-condition-on-a-concluded-task.txt)
  • Evidence: watch / shepherd / refuel release nothing (local file: ~/.no-mistakes/evidence/01M282XZCR3BX0G6X5H1HVNTZ7/17-loop-commands-release-nothing.txt)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 2 infos
  • ℹ️ scripts/lib/pane_harness.lua:288 - The new !-leader wire encoding has a producer (the awk rule in interface/fleet_queue.lua:413) and a consumer (edges() at interface/fleet_queue.lua:490), and only the consumer is exercised. pane_harness.lua injects the probe's tab-separated output directly into thurbox.runs[&#34;fleetqueue:s1&#34;].stdout (line 341), so the shell/awk PROBE never runs under check.sh pane; the fixture hard-codes &#34;!&#39;az login: for the tenant&#39;|missing-credential&#34; as what the probe would emit. I checked the offsets by hand and they are right (- condition: is 13 chars, substr($0, 14) is correct), so this is not a live defect — but if the anchor or the gsub(/[,|]/) flattening drifted, every condition row would render wrong and the pane checks would stay green. Pre-existing in kind: the task-blocker encoding, the publish block and the archived count are all fixtured the same way. Noting it rather than proposing a change; closing it would mean building a probe-execution harness, which extends the change well past its intent.
  • ℹ️ scripts/lib/queue.py:1824 - The two --clear forms now answer the same question differently. block &lt;ref&gt; --on &lt;other&gt; --clear when no such blocker exists prints "0 blocker(s) cleared" and exits 0 (scripts/lib/queue.py:1776); block &lt;ref&gt; --clear --condition &#39;&lt;text&gt;&#39; when the text does not match raises "records no condition …" and exits non-zero (scripts/lib/queue.py:1825-1829). Concrete sequence: an operator who mistypes the condition by one character gets a refusal naming what is actually held, while the same mistype on --on is silently accepted as a no-op. The condition form's behaviour is the better one — an exact free-prose match genuinely needs to say when it missed, which is why the selftest asserts it at scripts/queue-selftest.sh:5293 — so the divergence is a deliberate improvement rather than a defect, and the remedy (making the task form refuse too) would change behaviour the intent explicitly marks as unchanged. Flagging the inconsistency only; no action.
✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 13 of 13 scenarios driven live against the product
Scenario Result Live Evidence
An operator records a task as held by an unauthenticated az, and plan stops calling it ready ✅ pass live queue.sh block … --condition &#39;az is authenticated for the mazet tenant&#39; --kind missing-credential --why … then queue.sh plan in an isolated FLEET_QUEUE_DIR — evidence/01-record-condition-and-plan.…
The 2026-09-11 incident: the reconciler's line to the lead names only work somebody can dispatch ✅ pass live queue.sh plan --json over the live queue lists only 02-document-the-tables as ready (evidence/02-reconciler-wake-line.txt); piping that into scripts/lib/notify_lead.py types "1 task(s) ready … — v…
Nothing in the reconciler's loop releases a condition — collect, reap, watch, shepherd and refuel all run with one standing ✅ pass live evidence/03-collect-reap-condition-stands.txt and evidence/17-loop-commands-release-nothing.txt: the upstream PR merges, the task-form blocker clears on landed, ready grows by one and not by two, an…
Only a hand releases it: block --clear --condition naming the exact text, and nothing else ✅ pass live evidence/11-clearing-is-a-hand.txt: clearing 'az is logged in' is refused and says what the task does hold; clearing the exact text reports "1 blocker(s) cleared" and the task returns to the ready set…
A blank or whitespace-only --condition is refused instead of crashing (review round 1 regression) ✅ pass live evidence/09b + 09: the c694a36 queue.py raises TypeError: argument of type &#39;NoneType&#39; is not iterable; the target commit refuses with the named-wait paragraph and exit 2, on both the record and the…
"They edit the same file" cannot be spelled as a condition ✅ pass live evidence/10-adversarial-refusals.txt: --kind file-overlap on the condition form is refused and the refusal still points at add --touches; the task record is unchanged afterwards
The two kind sets stay two, and a blocker names a task or a condition and never both ✅ pass live evidence/10: a task kind on --condition is refused listing the condition set, a condition kind on --on is refused listing the task set plus a pointer to --condition, both flags together give arg…
Every reader reports the same wait: plan, list, show, fleet-status (text and --json), the record on disk and the run log ✅ pass live evidence/04 and evidence/05: one blocker_line everywhere; fleet-status.sh --json gives &#34;status&#34;: &#34;outside&#34; with &#34;cleared&#34;: false; the run log writes "waits on a condition outside the queue — ……
The TUI pane draws a condition as ⊘ with the writer's YAML quoting stripped (review round 2 regression) ✅ pass live The pane's own PROBE, extracted verbatim from interface/fleet_queue.lua and run over the live queue, emits !&#39;security review #42: somebody has to answer it&#39;|awaiting-approval (evidence/06); renderin…
A task carrying both blocker forms, with , and | inside the condition text, stays readable everywhere ✅ pass live evidence/14: show and plan keep the text verbatim, the probe flattens the two field separators to spaces, and the pane draws one ⊘ row rather than splitting it into a bogus second edge
dispatch refuses a condition-held task named explicitly and leaves it out of the bare ready set ✅ pass live evidence/12: dispatch --dry-run &lt;ref&gt; exits 2 quoting the condition line; bare dispatch --dry-run plans only the two unheld tasks
check validates the new record shape and catches a hand-edited one ✅ pass live evidence/12 (queue check: ok — 1 topic(s), 4 task(s)) and evidence/13: a blocker naming both forms, a kind from the wrong set, and a missing reason are each reported, exit 1
A condition recorded against a task that already concluded reads as moot and holds nothing ✅ pass live evidence/16: show reads "was held by awaiting-approval outside the queue (…); this task concluded, so it holds nothing" and the ready set is unaffected
  • ./scripts/check.sh
  • ./scripts/queue.sh topic add + 4 × add --brief-file into an isolated FLEET_QUEUE_DIR, then block &lt;ref&gt; --condition &#39;az is authenticated for the mazet tenant&#39; --kind missing-credential --why …
  • ./scripts/queue.sh plan and plan --json before and after recording the condition
  • ./scripts/queue.sh plan --json | python3 scripts/lib/notify_lead.py --state-dir … (reconciler wake line), twice, with a capture shim standing in for the thurbox terminal
  • ./scripts/queue.sh attach + collect + reap over a merged pull request while the condition stood
  • ./scripts/queue.sh watch --for-secs 1, shepherd --dry-run, refuel --dry-run with two conditions standing
  • ./scripts/queue.sh list, show &lt;ref&gt;, ./scripts/fleet-status.sh, ./scripts/fleet-status.sh --json, and the generated run log under orchestration/runs/
  • the pane's own PROBE shell text, extracted verbatim from interface/fleet_queue.lua and run over the live queue, then rendered through scripts/lib/pane_harness.lua at widths 30/60/70 — against both 193021c and c694a36 copies of the pane
  • block --condition &#39;&#39;, --condition &#39; &#39;, --clear --condition &#39; &#39;, --kind file-overlap, a task kind on --condition, a condition kind on --on, both flags, neither flag, and --condition with no --why
  • block --clear --condition with text the task does not hold, then with the exact text
  • ./scripts/queue.sh dispatch --dry-run &lt;condition-held ref&gt; and bare dispatch --dry-run
  • ./scripts/queue.sh check on a valid record and on a hand-edited one naming both a task and a condition, a kind from the wrong set, and no reason
  • ./scripts/check.sh queue pane (queue-selftest §20/20a/20b and pane-selftest), exit 0
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

`block` took only `--on <ref>`, so a task held by something that is not a
task had no state it could be recorded in. On 2026-09-11
vending-machine-egress-resume/01-vm-identity-reconciliation was ready by
every record fleet keeps and unrunnable in fact — its brief's first
instruction reads Azure and `az` was not authenticated. `plan` listed it as
ready and the reconciler correctly woke the lead to dispatch it; the only
honest answer left was to refuse in conversation and leave the record silent.

A blocker may now name a CONDITION instead of a task, with its own closed set
of kinds and the same required `--why`. It puts the task in `waiting` and out
of `ready`, so `notify_lead.py` stops counting it, and nothing clears it but
`block --clear` naming it back — no timer, no `collect`, no `reap`.
@LeTuR
LeTuR merged commit 1d462de into main Sep 11, 2026
11 checks passed
@LeTuR
LeTuR deleted the feat/record-a-wait-on-a-condition branch September 11, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant