Files
stack/agents/filbert/work/queue-33/build.md
T
jason.woltjeandClaude Opus 5.5 6fb50cc0a8 fix(queue): genesis owner-not-reviewer check, assign wording, queue-commit HEAD-moved message, calendar dates (row 33, #1508)
Built by filbert, approved by darkwing in round 1 (#1508 comment 26651).
Manifest fe7da3ef, 10 paths. Suites green on an index export.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-04 01:25:06 -05:00

133 lines
6.4 KiB
Markdown

# Queue row 33 build notes (#1508)
Filbert, 2026-10-04. Brief: `docs/plans/2026-10-04_queue-follow-ups.md`
(blob 1dc08bf0…). Reviewer: Darkwing. Base: HEAD 3e39a26a, queue rev 45.
Candidate: `candidate-manifest.sha256` in this directory, uncommitted.
Sage commits it after approval.
## What changed
1. **Genesis and the owner-not-reviewer rule.** `parseMigrationMap` refuses
a map row whose owner is among its reviewers: "migration map row N owner
SEAT can't be a listed reviewer", exit 2. Genesis parses the map before
it writes anything, so no file, witness or view changes.
2. **Assign wording.** "can't assign row N to SEAT: SEAT is one of its
reviewers". The two tests that matched the old text now match this one.
3. **HEAD moved.** `queue-commit.sh` gains `head_moved`, called in
`guard_check` before the canary and again when the clean run fails. A
moved HEAD exits 2 with "refused (STEP): HEAD moved since H was
recorded (another commit landed); run queue-commit.sh again". A real
guard failure, with HEAD unmoved, keeps the old message.
4. **Calendar dates.** `checkTime` refuses any ISO time or date that
doesn't format back to itself through `Date.parse` and `toISOString`:
"WHAT is not a calendar time|date: VALUE". A shape error keeps its old
message. Every time the validator reads goes through `checkTime`: row
times, review times and log entry times.
5. **Cold start.** See "Cold runs" below.
README: the commit steps, the owner rule and the time format. DEFERRED:
four items move to Done, and the cold-start item too, if no failure shows
up.
## Choices
- **C1. The genesis check sits in the map parser, not in replay.** The
review-record refusal is kept as defense in depth for a log written
before the rule (`review.test.mjs`). A check in `checkGenesis` would
make such a log unreadable. A new data test pins this: the parser
refuses the map, and a genesis document built past the parser still
loads. Mutant M10 (the rule added to replay) is killed by it.
- **C2. "another commit landed", not "another queue commit landed".** The
brief quotes the second wording. The check before the canary fires for
any commit, including one that touches no queue file, so "queue" would
be wrong there. The rest of the message is the brief's.
- **C3. HEAD is checked twice.** The brief asks for a check before the
canary. A commit can still land between that check and the hook run, and
then the old misdiagnosis comes back. A second check, only when the
clean run fails, closes that gap. It adds one `rev-parse` on a failing
path only.
- **C4. Two existing F1 tests changed.**
- "HEAD moving after commit-tree and before update-ref" moved its
trigger to `before update-ref`. A move after commit-tree is now caught
at the step-7 check (exit 2). The test still proves update-ref's
expected-old-value check, now at the only point where it's the last
line.
- "H is recorded before the canary…": a commit outside the queue files
during the step-1 canary used to reach update-ref (exit 1). It's now
refused at the step-7 check (exit 2), before that check's canary, and
update-ref never runs. The test asserts that.
- **C5. 24:00 is refused.** V8 parses `T24:00:00.000Z` as the next day's
midnight, so it doesn't round-trip. Minute 60 and second 60 already
parse as NaN.
## Tests
- `data.test.mjs`:
- a new genesis test (map refusal; replay tolerance);
- a new calendar test: month 13, month 0, day 32, 2026-02-30,
2027-02-29 and 2026-04-31 as dates in `requiredSince` and `createdAt`;
the same days plus 24:00, minute 60 and second 60 as ISO times in
`updatedAt` and `requiredSince`; 2028-02-29 valid in both forms; the
shape message kept; a log entry `at` refused on replay;
- the assign wording.
- `store.test.mjs`: genesis from a map with row 9's owner among its
reviewers exits 2. For that repository and the two refusals before it,
there's no queue.json, no witness and an unchanged QUEUE.md. Also the
assign wording.
- `commit.test.mjs`, two new tests, both with a nested
`queue-commit.sh` run landing a real queue commit:
- after `symbolic-ref` (H recorded, before step 1's check): refused at
step 1 with the HEAD-moved message, no canary run, and a rerun commits
the next revision;
- before the first `git hook run`: the clean run fails on the moved
HEAD, and the recheck reports HEAD moved, not the guard.
The existing "the canary refuses a hook that git would not run" test
still covers the guard message.
## Mutants
Eleven, run on an export of the candidate. Ten are killed:
| | Mutant | Killed by |
|---|---|---|
| M1 | no HEAD check before the canary | step-1 and step-7 HEAD tests |
| M2 | no recheck after a failed clean run | the between-check-and-canary test |
| M3 | `head_moved` exits 1 | all three HEAD tests |
| M4 | no round trip | calendar test |
| M5 | NaN check only | calendar test |
| M6 | round trip on ISO times only | calendar test |
| M7 | round trip on dates only | calendar test |
| M9 | genesis rule removed | data and store genesis tests |
| M10 | genesis rule also in replay | data genesis test |
| M11 | old assign wording | data and store assign tests |
One survives:
- **M8** compares only the date part of an ISO time. It's equivalent
under V8. The only out-of-range time V8 parses is 24:00, and that moves
the date, so the date part catches it.
## Suites
On the final candidate bytes, HEAD 3e39a26a:
- canonical checkout: `node --test packages/queue/tests/` passes 148/148
and `bash scripts/test-queue.sh` 29/0;
- an export of HEAD with the candidate files: `bash scripts/test-queue.sh`
27/0 (the live checks skip, as designed);
- `queue verify --current`: ok at rev 45. The live log replays under the
calendar check.
## Cold runs
Not reproduced in 20 cold runs. `cold.sh` (here) built each tree fresh
from HEAD 3e39a26a plus the candidate files: odd runs as a
`git clone --shared` with push set to DISABLED, even runs as a
`git archive` export. It ran `node --test packages/queue/tests/` once in
each, one run at a time with nothing else running, then deleted the tree.
Every run passed 148/148, 2960 of 2960 in total, taking 39 to 61 s each.
The counts are in `cold-runs.txt`. The 300 ms deadline test is unchanged.
Run 1 started with a `queue-commit.sh` that differed from the candidate in
one comment line, the step-1 comment, which I reworded during run 1. Runs
2 to 20 used the candidate bytes.