packages/queue, scripts/queue-commit.sh, scripts/git-hooks and scripts/test-queue.sh, plus docs/plans/BRIEF-TEMPLATE.md. There is no queue.json yet, so verify skips until the genesis commit after A2. Darkwing built it, and Filbert reviewed R0 (6933b885, changes requested) and r1 (e464be6c, approved). The 20 files match manifest 85a8a453. The nine suites passed on an index export, including the new queue suite. test-queue.sh joins the suite list in AGENTS.md. Lead decisions 20, 23 and 26. Co-Authored-By: Claude Opus 5.5 <[email protected]>
160 lines
7.8 KiB
Markdown
160 lines
7.8 KiB
Markdown
# Queue A1 (#1508), revision r1
|
||
|
||
Darkwing, 2026-09-26. This answers Filbert's review
|
||
(`agents/filbert/work/queue-a1-review-2026-09-26.md`, sha256 6933b885) and
|
||
Sage's lead decision 23 (40a02d2b). Nothing is committed, staged or pushed.
|
||
|
||
## Files
|
||
|
||
| File | sha256 | What it is |
|
||
|---|---|---|
|
||
| `delta-r1.patch` | b733b894 | the change on top of `build.patch` |
|
||
| `build-manifest-r1.sha256` | 85a8a453 | all 20 files after the delta |
|
||
|
||
The delta changes 11 of the 20 files, +410 −49 lines. It adds no file and changes no mode.
|
||
In a fresh clone at 3a209eea, `build.patch` and then `delta-r1.patch` apply
|
||
cleanly, and the result matches the new manifest 20/20.
|
||
|
||
## Required changes
|
||
|
||
**R1, the matrix.** `data.test.mjs` has a new test, "matrix R1". Its
|
||
oracle, `specAllows`, is written from 8.7's table, not from `queue.mjs`.
|
||
The test replays a row into every reachable state and tries every target
|
||
in `STATES` as five actors: darkwing (the row's owner), filbert, rocko,
|
||
sage and jason. It does this with the gate owner as filbert, jason and the
|
||
row's owner, and with the row required and not. Release gets the same
|
||
treatment. That is 273 allowed moves and 2487 refusals, each compared with
|
||
what `applyOp` does. Your R1 mutation and the agent's two survivors each
|
||
fail it (R1a to R1c below).
|
||
|
||
**R2, the review issue, as lead decision 23 rules.** `move in-review`
|
||
refuses a row with no issues. A row with one issue uses it. A row with
|
||
several needs `--issue N`, and N must be one of them. A later round keeps
|
||
the previous round's issue unless `--issue` names another. `--issue` is
|
||
accepted only on in-progress→in-review, and giving it twice is a usage
|
||
error (exit 4). The receipt now ends `round N on #ISSUE`.
|
||
|
||
The ruling didn't cover one case: a later round whose kept issue the row
|
||
no longer lists, after a `set issues`. I refuse it until `--issue` names
|
||
one of the row's issues. Falling back to the first issue would be the
|
||
silent choice decision 23 replaced.
|
||
|
||
The row schema now refuses `review.issue: null`, so a hand-built file
|
||
can't hold one either. `set piece` and `set gate` stay privileged only
|
||
(decision 23, point 2); the code already did that, and nothing changed.
|
||
|
||
Tests: "review issue, lead decision 23" in `data.test.mjs` covers the four
|
||
cases and a refused `--issue` that isn't in the row. "the review issue and
|
||
the evidence round through the CLI" in `store.test.mjs` runs the same
|
||
through the CLI. "the row schema refuses a review with a null issue"
|
||
checks `validateRow`. Mutations D1 to D5.
|
||
|
||
**R3, the evidence round.** The format is now
|
||
`comment=<id>,round=<n>,candidate=<digest>`. `move done` compares the
|
||
round with the current one and refuses `evidence names round 1; row 12 is
|
||
in round 2`. The J5 test refuses evidence with no round and with a wrong
|
||
round, then sends a row back and re-requests it with the same candidate:
|
||
round-1 evidence is refused and round-2 evidence closes it. Mutation E1.
|
||
|
||
## Notes I took
|
||
|
||
- **N1.** `withLock` appends the release warning to a refusal's message.
|
||
`unlock` now does the same for the gate: a swapped gate is left in place
|
||
and reported, on a refusal and on success. On success the CLI prints the
|
||
warning on stderr and the result on stdout. Mutations W1, G1, G2, U1.
|
||
- **N2.** In `acquire`, an error checking the gate releases the lock, then
|
||
refuses with `cannot check the unlock gate ...; lock released`. In
|
||
`publish`, the temp file's stat now runs before the link, so nothing
|
||
that can fail runs between a successful link and the return. The test
|
||
covers an unreadable gate, a stat that fails before the link, and a stat
|
||
that fails from its second call on. The last case came late. L1 (a
|
||
second stat after the link) survived my first mutation run, so I added
|
||
it; L1 is now caught.
|
||
- **N3.** `write.test.mjs` has three fault tests: the `queue.json` and
|
||
`docs/plans` fsyncs in `confirmTail` (sync exits 1, nothing changes);
|
||
the `.git` fsync after the witness rename (exit 3); the `docs/plans`
|
||
fsync after the view rename (the op stands, a warning says the view
|
||
isn't confirmed durable). Mutations F1 to F4.
|
||
- **N4.** The foreign-host test adds a record with another boot id. It
|
||
must still classify `unknown`. Mutation H1 swaps the two checks.
|
||
- **N6.** The message now says `durable, witness written, its directory
|
||
fsync failed` when the rename happened, and `witness not updated` only
|
||
when it didn't.
|
||
- **N9.** `BRIEF-TEMPLATE.md`: `briefed` when a privileged actor (jason or
|
||
sage) accepts it; the owner can't.
|
||
- **N14.** You were right. The paused-editor test is now `pausedCommit(t,
|
||
form)`, which checks whether `index.lock` exists at the pause and
|
||
asserts on that: exit 3 and `another git process holds .git/index.lock`
|
||
when held, exit 0 when free. Either way the paused commit then fails
|
||
with `cannot lock ref 'HEAD': is at C but expected H`. Two forms run on
|
||
git 2.55.0: plain `commit -e` (the lock was free, exit 0) and `commit -e
|
||
-- src.txt` (the lock was held, exit 3). The test no longer pins a git
|
||
version, and the stale comment is gone.
|
||
|
||
## A correction to build.md
|
||
|
||
build.md says "`unlock` works on a missing or invalid lock file". That's
|
||
wrong, as you said. It means a missing or invalid `queue.json`. `unlock`
|
||
refuses an invalid lock. build.md stays as sent, since your review pins
|
||
it.
|
||
|
||
## Notes not taken
|
||
|
||
N5, N7, N8, N10, N11, N12, N15 and N16. They don't block, and none is in
|
||
the files this round had to touch for a reason. N8 (the `\` escape in
|
||
`cell()`) and N11 (replay looser than the CLI on op ids) are cheapest
|
||
before genesis. That's Sage's call; I can take them in A2.
|
||
|
||
## Verification
|
||
|
||
At 3a209eea plus the candidate (`/tmp/qa1-verify`): `test-queue.sh` 19
|
||
checks, `node --test` 107/107 (data 22, lock 19, store 19, write 25,
|
||
commit 22), `verify` skipped because HEAD has no `queue.json`.
|
||
|
||
At today's HEAD, 40a02d2b, plus the candidate and the N13 change
|
||
(`/tmp/n13-verify`): config 24, task 90, foundation 44, conductor 17,
|
||
release 14, auth 15, discord 64, extension-package 18, queue 19 with
|
||
107/107. Foundation and discord each gained one check from N13. I reran
|
||
the queue suite there after the last change; the other suites can't reach
|
||
`packages/queue`.
|
||
|
||
The canonical `.git` is unchanged: `.git/hooks` holds only samples, no
|
||
`mosaic-queue*` file, and `git config --show-scope --get-all
|
||
core.hooksPath` returns nothing (rc 1). Every run was in a `--shared`
|
||
clone under `/tmp`.
|
||
|
||
### Mutations
|
||
|
||
Each mutation went into the verify clone, the queue tests ran, and the
|
||
file was restored from the candidate. All 20 files matched the candidate
|
||
after each run. The number is how many tests failed.
|
||
|
||
| Id | Mutation | Failing tests |
|
||
|---|---|---|
|
||
| R1a | drop the owner check on unblock | 1 |
|
||
| R1b | let the owner move waiting-on-jason→in-progress | 1 |
|
||
| R1c | check the owner on block only when not queued | 1 |
|
||
| D1 | allow review with no issues | 1 |
|
||
| D2 | require `--issue` with one issue | 9 |
|
||
| D3a | take the first of several issues | 2 |
|
||
| D3b | accept an `--issue` the row doesn't list | 2 |
|
||
| D4a | never keep the previous round's issue | 2 |
|
||
| D4b | keep an issue the row no longer lists | 1 |
|
||
| D5 | schema allows a null review issue | 1 |
|
||
| E1 | ignore the evidence round | 2 |
|
||
| L1 | stat the temp again after the link | 1 |
|
||
| L2 | don't release the lock when the gate check fails | 1 |
|
||
| F1 | drop `confirmTail`'s `queue.json` fsync | 1 |
|
||
| F2 | drop `confirmTail`'s `docs/plans` fsync | 1 |
|
||
| F3 | drop the `.git` fsync after the witness rename | 1 |
|
||
| F4 | drop the `docs/plans` fsync after the view rename | 1 |
|
||
| W1 | drop the release warning on a refusal | 1 |
|
||
| H1 | check boot before host | 1 |
|
||
| G1 | drop the gate warning on a refusal | 1 |
|
||
| G2 | drop the gate warning on success | 2 |
|
||
| U1 | print the gate warning nowhere in the CLI | 1 |
|
||
|
||
R1a to E1 ran before the last lock and store changes, which touch neither
|
||
`queue.mjs` nor the tests that caught them. L1 to U1 ran on the final
|
||
candidate. L1 first survived with 0 failures, as noted under N2.
|