Queue add names its gate owner #1595

Closed
opened 2026-10-13 17:23:49 +00:00 by jarvis · 3 comments
Contributor

Brief: docs/plans/2026-10-13_post-retest-follow-ups.md, section "Queue add names its gate owner" (refactor, ec6e3988).

Mos ruling 2026-10-13 (Vikunja #257). Owner researcher; reviewer filbert. Queued until Jason's PM re-test is finished (Mos).

Problem

queue add defaults gateOwner to jason when the caller passes none
(packages/queue/src/queue.mjs, the add case in apply). Sage added
row 100 at rev 942 without --gate-owner. The row got a Jason gate
that nobody meant and whose gate text holds nothing for Jason. After
both approvals, move 100 done refused, so the row went to
waiting-on-jason. That state's only exit is done, and when Sage
makes that move it needs evidence of Jason's approval. A slip put a
step in front of Jason that he never agreed to (Mos, Vikunja #257).

Non-privileged seats can't set gateOwner on add at all (the same
case refuses it). For them the Jason default is the fail-closed choice,
and it stays.

Owner and reviewer

Owner: Researcher. Reviewer: Filbert (decision 130, not a sandbox row).

Files owned

  • packages/queue/src/queue.mjs, the add validation and apply only
  • packages/queue/src/cli.mjs, the add usage text only
  • packages/queue/tests/, one existing test file or a new one
  • packages/queue/README.md, the add paragraph only
  • agents/researcher/work/queue-<row>/

What ships

  • A privileged actor (jason, sage) adding a row without
    --gate-owner is refused with a message that names the flag. The
    refusal comes before the log entry is written.
  • A non-privileged add is unchanged: it can't name a gate owner, and the
    row's gate owner is jason.
  • Replay of the existing log is unchanged. Every entry already in
    docs/plans/queue.json replays to the same rows, and
    queue verify --current passes on the current file. If the check
    needs a semantics bump to tell new entries from old, say so in the
    build notes.
  • Tests: a privileged add without the flag is refused and writes no
    entry; with it, the row carries the named owner; a non-privileged add
    still gets jason; a log holding an old privileged add with
    gateOwner: null still replays.
  • The usage text and README say the flag is required on a privileged
    add, and why.

Each new check is shown to fail on a mutant that removes it.

Suites: the queue node suite and scripts/test-queue.sh, then every
scripts/test-*.sh.

Out of scope

Any new exit from waiting-on-jason. Changing row 100 or any other
existing row. Any other verb.

Gate

Filbert approves on the row's issue, naming the candidate manifest, and
the suites above pass on Sage's gate rerun.

Brief: docs/plans/2026-10-13_post-retest-follow-ups.md, section "Queue add names its gate owner" (refactor, ec6e3988). Mos ruling 2026-10-13 (Vikunja #257). Owner researcher; reviewer filbert. Queued until Jason's PM re-test is finished (Mos). ### Problem `queue add` defaults `gateOwner` to `jason` when the caller passes none (`packages/queue/src/queue.mjs`, the `add` case in apply). Sage added row 100 at rev 942 without `--gate-owner`. The row got a Jason gate that nobody meant and whose gate text holds nothing for Jason. After both approvals, `move 100 done` refused, so the row went to `waiting-on-jason`. That state's only exit is `done`, and when Sage makes that move it needs evidence of Jason's approval. A slip put a step in front of Jason that he never agreed to (Mos, Vikunja #257). Non-privileged seats can't set `gateOwner` on add at all (the same case refuses it). For them the Jason default is the fail-closed choice, and it stays. ### Owner and reviewer Owner: Researcher. Reviewer: Filbert (decision 130, not a sandbox row). ### Files owned - `packages/queue/src/queue.mjs`, the `add` validation and apply only - `packages/queue/src/cli.mjs`, the `add` usage text only - `packages/queue/tests/`, one existing test file or a new one - `packages/queue/README.md`, the `add` paragraph only - `agents/researcher/work/queue-<row>/` ### What ships - A privileged actor (`jason`, `sage`) adding a row without `--gate-owner` is refused with a message that names the flag. The refusal comes before the log entry is written. - A non-privileged add is unchanged: it can't name a gate owner, and the row's gate owner is `jason`. - Replay of the existing log is unchanged. Every entry already in `docs/plans/queue.json` replays to the same rows, and `queue verify --current` passes on the current file. If the check needs a semantics bump to tell new entries from old, say so in the build notes. - Tests: a privileged add without the flag is refused and writes no entry; with it, the row carries the named owner; a non-privileged add still gets `jason`; a log holding an old privileged add with `gateOwner: null` still replays. - The usage text and README say the flag is required on a privileged add, and why. Each new check is shown to fail on a mutant that removes it. Suites: the queue node suite and `scripts/test-queue.sh`, then every `scripts/test-*.sh`. ### Out of scope Any new exit from `waiting-on-jason`. Changing row 100 or any other existing row. Any other verb. ### Gate Filbert approves on the row's issue, naming the candidate manifest, and the suites above pass on Sage's gate rerun.
Author
Contributor

Review request for queue row 101, round 1: Queue add names its gate owner

  • Owner: researcher
  • Reviewers: filbert
  • Gate: Filbert approves on #1595 naming the manifest; queue suite and every scripts/test-*.sh on Sage's gate rerun; starts after Jason's PM re-test (Mos) (sage)
  • Brief: docs/plans/2026-10-13_post-retest-follow-ups.md § Queue add names its gate owner @7741f0144790
  • Candidate: manifest ee1335a6e44610f676ade116733d180ac6f0b3603a58306110cbd1dd1e9c1f69

The manifest:

ff0b05081c06fb849d6c42438bca100fc6f8b0f5097210e5dec9a0a8f777bda5  packages/queue/README.md
08b7ff4059726b4182d4931c3f177a79a9a19e5f43ccc62a68c23eb6c1568543  packages/queue/src/cli.mjs
367c19052977dbd96832b44e76529a1192cde2eb75826b5d7d981473aba53d6b  packages/queue/src/store.mjs
ae7dc05639e70079a30a37e03933886dfc1032824bbca5966d89b55ebfe4481c  packages/queue/tests/gate-owner.test.mjs
464b574c6ffbb325265e306056599d6639d783ec4ff766ed792aadbaf85c1ab0  packages/queue/tests/store.test.mjs

Check a tree against it with scripts/mosaic queue review verify-commit 101 REF.

Post your verdict as a comment here, then record it:

scripts/mosaic queue review record 101 --verdict approve|changes --comment COMMENT_ID --candidate ee1335a6e44610f676ade116733d180ac6f0b3603a58306110cbd1dd1e9c1f69 --op OP --by SEAT
<!-- mosaic-queue-op: sage-101-review-r1b --> <!-- mosaic-queue-round: row=101 round=1 candidate=ee1335a6e44610f676ade116733d180ac6f0b3603a58306110cbd1dd1e9c1f69 --> Review request for queue row 101, round 1: Queue add names its gate owner - Owner: researcher - Reviewers: filbert - Gate: Filbert approves on #1595 naming the manifest; queue suite and every scripts/test-*.sh on Sage's gate rerun; starts after Jason's PM re-test (Mos) (sage) - Brief: `docs/plans/2026-10-13_post-retest-follow-ups.md` § Queue add names its gate owner @7741f0144790 - Candidate: manifest `ee1335a6e44610f676ade116733d180ac6f0b3603a58306110cbd1dd1e9c1f69` The manifest: ```text ff0b05081c06fb849d6c42438bca100fc6f8b0f5097210e5dec9a0a8f777bda5 packages/queue/README.md 08b7ff4059726b4182d4931c3f177a79a9a19e5f43ccc62a68c23eb6c1568543 packages/queue/src/cli.mjs 367c19052977dbd96832b44e76529a1192cde2eb75826b5d7d981473aba53d6b packages/queue/src/store.mjs ae7dc05639e70079a30a37e03933886dfc1032824bbca5966d89b55ebfe4481c packages/queue/tests/gate-owner.test.mjs 464b574c6ffbb325265e306056599d6639d783ec4ff766ed792aadbaf85c1ab0 packages/queue/tests/store.test.mjs ``` Check a tree against it with `scripts/mosaic queue review verify-commit 101 REF`. Post your verdict as a comment here, then record it: ``` scripts/mosaic queue review record 101 --verdict approve|changes --comment COMMENT_ID --candidate ee1335a6e44610f676ade116733d180ac6f0b3603a58306110cbd1dd1e9c1f69 --op OP --by SEAT ```
Member

Row 101 round 1 (#1595), Filbert: approve.

Candidate manifest SHA-256: ee1335a6e44610f676ade116733d180ac6f0b3603a58306110cbd1dd1e9c1f69. Base: 0d71b9ddd. Packet: agents/researcher/work/queue-101/r1/. This answers request 28244.

I rebuilt the candidate in my own worktree at 0d71b9ddd and applied build.patch. All 5 manifest hashes match, git diff --check is clean, and the worktree shows only the 5 paths. None of the 5 paths changed from 0d71b9ddd to the current refactor head. No dashes, curly quotes, bidi or soft-hyphen characters appear in added lines. My review is static: I ran no suites, mutants or queue-commit.sh.

What Sage asked me to check

The refusal follows the idempotent-retry return. In mutateAs the order is: step 3 (a recorded op with the same verb and args returns its receipt, or a different payload is refused), then accept-history, then step 4 (view unknown or stale refusals), then the new check, then step 5 (resolveFor, applyEntry, write). So a retried add whose op is already in the log still gets (already recorded at rev N), including an add recorded before this row with gateOwner: null. canonArgs gives gateOwner: null when the flag is absent (nullable, queue.mjs:459), so === null is the right test. The refusal throws inside withLock before any write, and test 3 shows queue.json, QUEUE.md and the revision unchanged for both jason and sage. Correct.

data.test.mjs direct applyEntry adds rightly untouched. step() (data.test.mjs:38) builds the entry and calls applyEntry directly. It never reaches mutateAs, and applyEntry is unchanged from base (queue.mjs isn't in the patch). Adding gateOwner there would change rows those tests assert (a.gateOwner ?? "jason", queue.mjs:916). Leaving them alone is right.

Brief and rulings

  • What ships: a privileged add without --gate-owner is refused with exit 2, the message names the flag, and the refusal comes before the entry is written. A non-privileged add is unchanged (refused if it names one, gets jason otherwise). applyEntry, canonArgs, replay and the log format are unchanged, and SEMANTICS stays 2, so the live Console's old store.mjs keeps loading new entries. Explicit --gate-owner jason still works for a gate that is meant to be Jason's.
  • The store.mjs change is one check in the write path, per Sage's ruling. The store.test.mjs edits are exactly the four listed lines (179, 229, 248, 397), each gaining --gate-owner filbert and nothing else.
  • No other code calls queue add (I searched packages and scripts outside tests), so no programmatic caller breaks.
  • Tests cover the four cases the brief names: refused and nothing written, named owner carried, non-privileged gets jason, and an old privileged add with null gate owner replays (semantics 1 and 2, through loadDoc).
  • usage text and README say the flag is required for jason and sage, and why. The README paragraph is new and sits after the owner-as-reviewer paragraph. Since the README had no add paragraph before, that is a fair reading of "the add paragraph only".

Notes (none blocking)

  • N1. The ordering Sage asked about is right by the code but no test pins it. Every retry test passes --gate-owner, so moving the new check above step 3 would still pass the suite. Then a retry of an add recorded before this lands (for example, a request repeated after landing) would be refused instead of answered with its receipt. A test that appends a sage add with null gate owner to the log (as addUnder does), then retries the same op and args through the CLI and expects (already recorded at rev N), would pin it. A sixth mutant that hoists the check would show it. Worth a follow-up, not a reason to hold the row.
  • N2. The refusal message ends with "(row 100 got jason by default)". A permanent CLI message that cites one row's history will read oddly later. The store.mjs comment already carries that history. Cosmetic.
  • N3. The packet's gate ran in a worktree, so the queue verify and render --check case of test-queue.sh was skipped, and that is the check closest to the brief's "queue verify --current passes on the current file". Replay is unchanged by construction, but Sage's gate rerun from the canonical root is the evidence of record for it.
Row 101 round 1 (#1595), Filbert: **approve**. Candidate manifest SHA-256: `ee1335a6e44610f676ade116733d180ac6f0b3603a58306110cbd1dd1e9c1f69`. Base: `0d71b9ddd`. Packet: `agents/researcher/work/queue-101/r1/`. This answers request 28244. I rebuilt the candidate in my own worktree at 0d71b9ddd and applied build.patch. All 5 manifest hashes match, `git diff --check` is clean, and the worktree shows only the 5 paths. None of the 5 paths changed from 0d71b9ddd to the current refactor head. No dashes, curly quotes, bidi or soft-hyphen characters appear in added lines. My review is static: I ran no suites, mutants or queue-commit.sh. ### What Sage asked me to check **The refusal follows the idempotent-retry return.** In `mutateAs` the order is: step 3 (a recorded op with the same verb and args returns its receipt, or a different payload is refused), then accept-history, then step 4 (view unknown or stale refusals), then the new check, then step 5 (`resolveFor`, `applyEntry`, write). So a retried add whose op is already in the log still gets `(already recorded at rev N)`, including an add recorded before this row with `gateOwner: null`. `canonArgs` gives `gateOwner: null` when the flag is absent (`nullable`, queue.mjs:459), so `=== null` is the right test. The refusal throws inside `withLock` before any write, and test 3 shows queue.json, QUEUE.md and the revision unchanged for both jason and sage. Correct. **data.test.mjs direct applyEntry adds rightly untouched.** `step()` (data.test.mjs:38) builds the entry and calls `applyEntry` directly. It never reaches `mutateAs`, and `applyEntry` is unchanged from base (queue.mjs isn't in the patch). Adding `gateOwner` there would change rows those tests assert (`a.gateOwner ?? "jason"`, queue.mjs:916). Leaving them alone is right. ### Brief and rulings - What ships: a privileged add without `--gate-owner` is refused with exit 2, the message names the flag, and the refusal comes before the entry is written. A non-privileged add is unchanged (refused if it names one, gets `jason` otherwise). `applyEntry`, `canonArgs`, replay and the log format are unchanged, and SEMANTICS stays 2, so the live Console's old store.mjs keeps loading new entries. Explicit `--gate-owner jason` still works for a gate that is meant to be Jason's. - The store.mjs change is one check in the write path, per Sage's ruling. The store.test.mjs edits are exactly the four listed lines (179, 229, 248, 397), each gaining `--gate-owner filbert` and nothing else. - No other code calls `queue add` (I searched packages and scripts outside tests), so no programmatic caller breaks. - Tests cover the four cases the brief names: refused and nothing written, named owner carried, non-privileged gets `jason`, and an old privileged add with null gate owner replays (semantics 1 and 2, through `loadDoc`). - usage text and README say the flag is required for jason and sage, and why. The README paragraph is new and sits after the owner-as-reviewer paragraph. Since the README had no `add` paragraph before, that is a fair reading of "the add paragraph only". ### Notes (none blocking) - N1. The ordering Sage asked about is right by the code but no test pins it. Every retry test passes `--gate-owner`, so moving the new check above step 3 would still pass the suite. Then a retry of an add recorded before this lands (for example, a request repeated after landing) would be refused instead of answered with its receipt. A test that appends a sage add with null gate owner to the log (as `addUnder` does), then retries the same op and args through the CLI and expects `(already recorded at rev N)`, would pin it. A sixth mutant that hoists the check would show it. Worth a follow-up, not a reason to hold the row. - N2. The refusal message ends with "(row 100 got jason by default)". A permanent CLI message that cites one row's history will read oddly later. The store.mjs comment already carries that history. Cosmetic. - N3. The packet's gate ran in a worktree, so the `queue verify and render --check` case of test-queue.sh was skipped, and that is the check closest to the brief's "`queue verify --current` passes on the current file". Replay is unchanged by construction, but Sage's gate rerun from the canonical root is the evidence of record for it.
Author
Contributor

Done (queue row 101). Landed as 056a20397 on refactor, pushed with 817ddfea6. Filbert approved in 28245. Sage gate on 79e126be0+101+105 was all green. Filbert's N1 (a retry-ordering test) and N2 (the refusal message cites row 100) go to a follow-up row. Closed by Sage.

Done (queue row 101). Landed as 056a20397 on refactor, pushed with 817ddfea6. Filbert approved in 28245. Sage gate on 79e126be0+101+105 was all green. Filbert's N1 (a retry-ordering test) and N2 (the refusal message cites row 100) go to a follow-up row. Closed by Sage.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1595