6.6 KiB
Queue as data: the process stops being prose (#1508)
Owner of the plan: Jason. Coordinator: the Claude session. Builder: darkwing.
Tracking: #1508. Rows 9 to 13 in docs/plans/QUEUE.md, state required.
Jason, 2026-09-13: "It all starts out great, then goes off the rails. I want this iron-clad." This page is the plan, the decomposition, and the briefs. It is not a design discussion. Each piece below has one owner, one gate, and one commit-sized scope. Nothing on this page is optional and nothing moves to DEFERRED.md; a piece that cannot ship gets a Blocked line in QUEUE.md with the reason.
Problem, in one paragraph
The entry point for "what is next" was prose in four files (AGENTS.md,
CURRENT.md, ROADMAP.md, CONDUCTOR.md), edited by hand by any seat in one
shared checkout. State lived in sentences, so it drifted: three "Next
action" paragraphs, edits swept into other seats' commits, 160 review files
invented as a side channel, and Jason unable to find the next step. The fix
is the same fix already applied to decisions (brain.py is the only writer)
and to seat identity (registration.json is the only record): the queue
becomes a record with one writer and checks that fail loudly.
Ordering and preconditions
Starts after piece 5 (darkwing on point, QUEUE row 6) reaches Gate F or is blocked, whichever comes first. Runs before the fleet migration (row 8). Pieces A to E below ship in order; each is one issue comment on #1508 and one QUEUE row move. Nothing on this page waits for the WebUI, the comms MVP, or the orchestrator to be finished.
Piece A: queue record and mosaic queue (QUEUE row 9)
Owner: darkwing. Reviewer: filbert. Package: packages/queue,
same shape as packages/seat. Files owned: packages/queue/**,
scripts/mosaic (subcommand dispatch only), docs/plans/QUEUE.md.
What ships
- One file,
<repo>/docs/plans/queue.json, committed. It is the queue. Array of rows:id(integer, never reused),piece(one line),owner(seat name,jason,coordinator, orunassigned),issue(integer or null),state(queued|briefed|in-progress|in-review|waiting-on-jason|done|blocked|parked|required),gate(one sentence),brief(repo path plus optional section),updatedAt,updatedBy(fromMOSAIC_AGENT_NAME, or--by, else refused),note(one line, optional),blockedReason(required when state is blocked). scripts/mosaic queue list [--owner SEAT] [--json],queue next [SEAT](prints the one row that seat should work on, or "nothing" with exit 0),queue add --piece --owner --gate --brief [--issue],queue move ID STATE [--reason],queue assign ID SEAT,queue note ID TEXT. All writes through the CLI; the CLI validates the transitions below and refuses anything else with one line on stderr and exit 2.- Transitions: queued→briefed→in-progress→in-review→waiting-on-jason→done;
any→blocked (reason required) and blocked→previous; required→in-progress
only; parked only from queued or briefed and only with
--by jason; done and parked rows never change. A seat may move only rows it owns;coordinatorandjasonmay move any row. docs/plans/QUEUE.mdbecomes a rendered view:mosaic queue renderwrites the table between two marker comments and the CLI runs it after every write. The header text above the markers stays hand-written.- Tests: fixtures for every transition and every refusal; render is
byte-stable;
queue nextpicks the first row by id, not by file order.
Out of scope: Gitea sync, board display, the ledger, hooks, any change
under packages/seat, packages/control-board, packages/ledger.
Gate G (Jason): a seat launched fresh, with no prior session, is told
only "run mosaic queue next and do it". It finds its piece, opens the
brief the row names, and starts, with zero further human messages. Jason
watches from the board. Pass or fail, one sentence on #1508.
Piece B: seats read the queue, not CURRENT.md (QUEUE row 10)
Owner: coordinator. Done 2026-09-13 for the cadence and pointer
lines in AGENTS.md (cbf24b01). Remaining under this piece, after Piece A:
the cadence line says mosaic queue next instead of naming the file, and
agents/*/AGENTS.md or context files that still point at CURRENT.md for
"what now" are changed to the command. One commit. No gate; verified by
Gate G.
Piece C: brief template (QUEUE row 11)
Owner: darkwing, as part of Piece A's review round. File:
docs/plans/BRIEF-TEMPLATE.md, one page, these headings only: Problem,
Owner and reviewer, Files owned, What ships, Out of scope, Gate (who says
yes, on what evidence). mosaic queue add refuses a --brief path that
does not exist. The pieces on this page are written in that shape and are
the first three uses. Passing: Piece A's brief and one later brief are
accepted by Jason without a follow-up question about scope.
Piece D: reviews through a channel, not files (QUEUE row 12)
Owner: darkwing. After Piece A. Review requests and receipts go as
issue comments on the piece's issue (scripts/gitea-api.sh exists) or as
board messages once the comms MVP has a record; no new files under
docs/plans/reviews/. The existing 160 files stay as history. mosaic queue move ID in-review posts the request comment itself from the row's
data, so the seat does not write one. Passing: one full review round on a
later piece with zero new files under docs/plans/reviews/.
Piece E: ledger checks the queue (QUEUE row 13)
Owner: darkwing. Reviewer: filbert. After Piece A. packages/ ledger gains a "queue" section: every open Gitea issue with a #N in a
queue row has that row not done; every in-progress or in-review row has
an owner seat with a live registration; every done row's issue is closed;
every required row older than 14 days is listed by name. Violations print
above the weekly table and in --json. First run Monday 2026-09-21 with the
weekly number. Passing: zero violations, or every violation has a row moved
within the day.
What "iron-clad" means here, so it can be checked
- The queue has one writer (
mosaic queue) and refuses bad transitions. - Seats are told a command, not a file, so nothing to reinterpret.
- Every row names an owner, a gate, and a brief that exists.
- The ledger reports drift weekly, next to the number Jason already reads.
requiredrows cannot be parked; only Jason moves them.
If any of the five stops being true, that is a finding on #1508, reopened.
Log
- 2026-09-13 — page written by the coordinator after Jason's "iron-clad" ruling; #1508 opened; QUEUE rows 9 to 13 point here.