feat(queue): queue as data A2, migration, render and dispatch (#1508)

Filbert approved round 1 (f167b85e). Manifest 782bcb62, 21 files, plus
the QUEUE.md markers and the TOOLS.md section. Lead decision 35.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-26 20:14:09 -05:00
co-authored by Claude Opus 5.5
parent c9539baa0f
commit 6ca116b7ba
32 changed files with 4886 additions and 103 deletions
+44 -11
View File
@@ -7,14 +7,15 @@ specification is section 8 of
`agents/filbert/work/queue-as-data-plan-2026-09-26.md`. This README states
what the code does and the limits it accepts.
Until A2 adds `scripts/mosaic queue`, run the CLI directly from the canonical
checkout. Messages already name `scripts/mosaic queue`.
Run it from the canonical checkout as `scripts/mosaic queue <verb>`, which
execs `node packages/queue/src/cli.mjs` with the same arguments and exit
code.
```sh
node packages/queue/src/cli.mjs list
node packages/queue/src/cli.mjs next darkwing
node packages/queue/src/cli.mjs move 9 in-progress --op darkwing-9-start-1 --by darkwing
node packages/queue/src/cli.mjs verify --current
scripts/mosaic queue list
scripts/mosaic queue next darkwing
scripts/mosaic queue move 9 in-progress --op darkwing-9-start-1 --by darkwing
scripts/mosaic queue verify --current
node --test packages/queue/tests/
scripts/test-queue.sh
```
@@ -35,8 +36,20 @@ scripts/test-queue.sh
Every change takes `--op ID` (8 to 72 characters of `[a-z0-9._-]`,
starting with a letter or digit, not ending in `.outcome`) and an actor from `--by NAME` or
`$MOSAIC_AGENT_NAME`. Reads need no actor. `next` with neither a SEAT nor
`$MOSAIC_AGENT_NAME` refuses. The privileged actors are `jason` and `sage`.
`$MOSAIC_AGENT_NAME`. `--by` wins when both are set; if they differ, the
command prints a warning on stderr and goes on. Reads need no actor. `next`
with neither a SEAT nor `$MOSAIC_AGENT_NAME` refuses. The privileged actors
are `jason` and `sage`.
Text the table shows (piece, gate, note, the move reason, the brief anchor,
a blocked reason) refuses `\` and `<`. The table escapes `|` itself; a
backslash could undo that escape and `<` starts raw HTML, so the CLI refuses
both rather than escape them.
`set ID issues` also moves `closes`. If `closes` equals the old issues, it
becomes the new list. If it was narrowed (`set ID closes` with `--reason`,
or genesis from the map), it keeps the part still among the new issues, and
the receipt ends in `(kept narrowed)`.
Exit codes: 0 ok; 1 the operation failed; 2 invalid data or refused;
3 uncertain (visible or durable, not acknowledged); 4 usage.
@@ -50,7 +63,8 @@ The review's issue follows lead decision 23. A row with no issues can't
request review. A row with one issue uses it. A row with several needs
`--issue N`, one of its issues. Later rounds keep the previous round's issue
unless `--issue` names another; if the row no longer lists the kept issue,
the request refuses until `--issue` names one.
the request refuses until `--issue` names one. Each round records the issue
it used (`review.rounds[].issue`).
`move ID done` from in-review needs `--evidence
comment=<id>,round=<n>,candidate=<digest>`. The round must be the current
@@ -146,12 +160,23 @@ the guard, runs `queue genesis` from the reviewed migration map, then
`genesis not committed` until that commit exists. After that,
`scripts/test-queue.sh` also runs `verify` on the live queue.
The map is `agents/darkwing/work/queue-migration-map.md`. It names the
QUEUE.md blob it was built from. Before genesis, `node
agents/darkwing/work/queue-a2/map-check.mjs` lists every table line changed
since that blob and every row whose piece, owner or issues no longer match
the map; exit 0 means no drift. QUEUE.md needs its two markers around the
table and the parked list before genesis, since genesis keeps the text
between them as `legacyView`.
Committing still needs its own authorization. The script never pushes.
## Durability
Supported: Linux with `docs/plans/` and `.git/` on local ext4, xfs or btrfs
(tmpfs for tests). The CLI checks the filesystem type and refuses others.
Supported: Linux with `docs/plans/` and `.git/` on local ext4, xfs or btrfs.
The CLI checks the filesystem type and refuses others. ext2 and ext3 report
ext4's magic number, so the check can't tell them apart. tmpfs passes only
for a test that hands in an io layer with `allowTmpfs: true`; the CLI's own
layer never has it.
The host-crash claims assume that rename replaces its target atomically and
that fsync of a directory persists the renamed entry. The tests kill
processes with SIGKILL at each step. **Power loss is not tested.**
@@ -198,6 +223,9 @@ reporting, so a write in progress is never reported as lost history.
- `queue unlock --check-gate` classifies a stale unlock gate. Remove the
gate by hand only after it says `dead` or `mismatch` and no queue command
is running.
- A process killed while taking the lock can leave
`.git/mosaic-queue.lock.<pid>.<hex>.tmp`. Nothing reads it or removes it.
Delete it by hand once that pid is gone.
## Manual recovery
@@ -240,5 +268,10 @@ Faults reach the code only through options the tests pass in (`io`, `proc`,
views, snapshot.
- `write.test.mjs`: every write fault, SIGKILL at each step, git
interference, unlocked-read races.
- `dispatch.test.mjs`: `scripts/mosaic queue` passes arguments and exit
codes through, and the seat commands still reach the seat CLI.
- `migration.test.mjs`: the real map renders the golden genesis table, the
marked QUEUE.md fixture holds every row between its markers, and
`map-check.mjs` reports each kind of drift.
- `commit.test.mjs`: `queue-commit.sh` and the guard, through PATH shims
that run an action at an exact point in the procedure.