queue: pin the add retry order and drop row history from the gate-owner refusal (row 107, #1601)

A retried privileged add recorded with no gate owner answers with its
receipt before the --gate-owner check runs; a test pins that order and
a hoisting mutant fails it. The refusal no longer cites row 100.
SEMANTICS stays 2. Packet: agents/researcher/work/queue-107/ (manifest
b70dfe4a). Filbert approved round 1 in comment 28286. Sage's
canonical-root gate: queue 156/0, test-queue 30/0 with queue verify.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-13 17:16:51 -05:00
co-authored by Claude Opus 5.5
parent ae4ae7102a
commit fe27adea1c
2 changed files with 44 additions and 5 deletions
+4 -3
View File
@@ -528,11 +528,12 @@ function mutateAs(ctx, { verb, op, args, by, yes = false, derived = false }) {
if (view.state === "unknown") throw refuse(unknownMessage(view));
if (view.state === "stale" && verb !== "accept-history") throw refuse(staleMessage(view, cur.doc.log));
// A privileged add names its gate owner. There is no default for it: the
// Jason default put a gate nobody meant on row 100. This check lives in the
// Jason default put a gate nobody meant on a row. This check lives in the
// write path, not in applyEntry, so replay of old entries is unchanged and an
// older reader still loads the log.
// older reader still loads the log. It stays below step 3: a retry of an add
// recorded before this check answers with its receipt.
if (verb === "add" && PRIVILEGED.has(actor) && cargs.gateOwner === null) {
throw refuse(`${actor} must pass --gate-owner SEAT on add: a privileged add has no default gate owner, so a row never gets a gate nobody meant (row 100 got jason by default)`);
throw refuse(`${actor} must pass --gate-owner SEAT on add: a privileged add has no default gate owner, so a row never gets a gate nobody meant`);
}
// Step 5.
const resolved = resolveFor(ctx, loc, cur, verb, cargs, cmp);