Files
stack/agents/filbert/work/queue-e-review-r2-2026-09-27.md
T
jason.woltjeandClaude Opus 5.5 fd72d26899 feat(ledger): Piece E, queue section in the weekly ledger (row 13, #1508)
The ledger prints a queue section above the weekly table. It checks four
things:
- open issues named by done rows;
- owner registrations for active rows;
- closed issues for done rows;
- the age of required rows.
The result is fail, incomplete or reduced pass. It uses its own Gitea
budget of the open list plus at most 10 lookups. A full open page counts
only while an issue in some row's closes has no known state (lead
decision 40). T3 seats are exempt per run with --unsupported-runtime.
The weekly routine is in packages/ledger/README.md.

Built by Darkwing (build.patch ab1f12ca, manifest 0b20bbca). Filbert
reviewed it: round 1 81f26f2e asked for changes (C1, ISO requiredSince
never aged); round 2 ce8ce150 approved. Also carries Filbert's plan
amendment for decision 40 (68a25ffe).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 11:33:44 -05:00

4.9 KiB

Queue Piece E review, round 2 (#1508, row 13)

Filbert, 2026-09-27. Round 1: queue-e-review-r1-2026-09-27.md (sha256 81f26f2e…). This round checks C1, n1, n2 and n3.

Verdict

Approved. The review covers build.patch sha256 ab1f12cad711284f8a722ea51fa73cd8e344c703701f8b76957ae33de091ae84 at 2333d837, with build-manifest.sha256 0b20bbca… and build.md 75571f0b…. C1 is fixed, and so are n1, n2 and n3. Two of my mutants survive. Neither hides a defect; see the notes below. Nothing needs a round 3.

What I checked

All of this ran in a scratch clone, /tmp/fqe3, at 2333d837 with push disabled, on frozen 0444 copies of the three inputs. Darkwing's r1/ copies still match the hashes I reviewed in round 1.

  • Manifest and suites. The manifest checks 5/5. node --test packages/ledger/tests/ passes 78/78, and packages/queue/tests with packages/seat/tests passes 161/161.

  • What changed. I compared all five files with the round-1 candidate. cli.mjs and ledger.test.mjs are unchanged. queue-checks.mjs, the README and queue-checks.test.mjs change only for C1, n1, n2 and n3.

  • C1.

    • requiredDay floors Date.parse to 00:00Z of its UTC day. A bare date parses as 00:00Z, so the separate date branch I suggested would add nothing. Dropping it is right.
    • Counting an ISO time from its UTC day rather than its hour is a change from my fix, and I agree with it. Both forms age in whole UTC days. A row can be flagged up to a day early, never late.
    • A value that doesn't parse is an age-invalid violation, so the run fails. Any finding in violations counts toward the result, and no other code matches on the check name, so the new name needs no other wiring.
    • The tests cover an ISO time at 15 days (fails), at 14 days (passes), and at 23:59Z fifteen days back (fails, which needs the floor), and month 13 (age-invalid, result fail).
  • n1. Each call runs as timeout -s KILL 60 gitea-api.sh GET …. Without --foreground, GNU timeout signals the whole process group, which kills curl too. The new test starts a helper with a hanging child and a 1 s deadline, then checks that both pids are gone. Adding --foreground leaves the child alive, and the test catches it (R7).

  • n2. Metric-page evidence needs state === 'closed' and a closed_at. The metric call returns the raw Gitea records, filtered but not mapped (ledger.mjs readIssues), so state is there in real runs. The fixture covers a reopened entry (closed_at only) and one with state only. Both are looked up.

  • n3. The message reads is unknown (over the lookup budget).

  • Mutations. I wrote 13 mutants of my own for this round. The suite kills 11:

    • R1: no floor on requiredDay;
    • R2: the NaN guard removed;
    • R3: age-invalid counted as undecided;
    • R4: metric evidence on closed_at alone;
    • R5: metric evidence on state alone;
    • R6: the default TERM signal in place of KILL (caught by the message);
    • R7: --foreground (caught by the orphan check);
    • R8: a kill recognised only by exit 137;
    • R10: exit 127 no longer read as "unavailable";
    • R11: ceil in place of floor;
    • R12: a signal-killed call treated as success.

    Two survive:

    • R9, a kill recognised only by r.signal === 'SIGKILL'. Without --foreground, GNU timeout sends KILL to its own group and dies with it, so spawnSync sees the signal, not exit 137. The status === 137 branch is defensive and can't be reached in this setup. The mutant is equivalent.
    • R13, if (r.error) throw r.error; removed. With timeout missing from PATH, the call still fails, but the message says "credential or Gitea request failure" rather than "the timeout command is unavailable". That's still a refusal (exit 2); only the wording is wrong. See n1.

Non-blocking

  • n1. The missing-timeout message has no test (R13). A test could point PATH at an empty directory for one call and give the helper by absolute path. That's optional. The failure is closed either way.
  • n2. A day past the end of the month doesn't parse as invalid. V8 turns 2026-02-30 and 2026-02-30T00:00:00.000Z into 2026-03-02. It returns NaN only for values like month 13. So age-invalid catches some impossible dates but not all. A row whose date overflows ages from the wrong day and gets no warning. This belongs with Darkwing's follow-up (a): the queue validator checks shape, not calendar. A calendar check there, such as a round trip through toISOString, closes both. The CLI never writes such a value, and readQueue refuses hand edits, so it can't happen today.
  • Darkwing's follow-ups. I agree with both:
    • (a), above;
    • (b), the metric call's orphan curl in ledger.mjs, the same fix as n1 in round 1. Neither is E's scope.

For Darkwing and Sage

E is approved as it stands. My plan amendment (68a25ffe…) and both review files go into E's commit.