docs(queue): queue-as-data plan round 6, Rocko approved (#1508)

Plan 282fabbb (Filbert) and the six adversarial rounds (Rocko, r6 80cde839).
Lead item 15: Gate F first, then A1 and A2 as separate reviewed commits.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-26 16:05:16 -05:00
co-authored by Claude Opus 5.5
parent ffc22c04c6
commit 1c5f6bc3a0
8 changed files with 3944 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,403 @@
# Queue as data: adversarial plan review
VERDICT: revise
Rocko, 2026-09-26, for Sage / #1508. Read-only investigation; this report
is the only file written for this assignment. No commits, issue writes,
credentials read, live launches, or source changes. This is a design review,
not a claim that unimplemented queue code has failed tests.
Reviewed Filbert's plan after the Q5–Q9 decisions and the final section-5
proposal/decision distinction were folded in:
- `agents/filbert/work/queue-as-data-plan-2026-09-26.md`, SHA-256
`59d5a22f1f67426237761341b686c3a9dcf0dffb2d353bab8dd2f9741bcc1fdb`.
- Brief `docs/plans/2026-09-13_queue-as-data.md`, SHA-256
`12d8d39f95f40e7d1e93f3a4420390152bbf52d04a6596b48d443512ce559061`.
- HEAD `21e3e908b6f64d3eba202480fede05e174799e1d` plus current shared
working files: AGENTS, QUEUE, scripts/mosaic, seat, control-board, ledger,
launcher and Gitea helper sources. No `packages/queue` exists yet.
High means a credible loss of state, authority bypass, or false acceptance;
medium means a material workflow or evidence defect. Findings against decided
items request reconsideration or clarification by Sage; they do not silently
reverse those decisions. Q1–Q4 remain with Jason.
## Findings
### R1 — High: the two-file write has no crash/recovery contract
**Where:** plan 2.A and 3.A, atomic write under a lock; test kills only before
rename.
**Scenario:** A reads revision 10, installs revision 11 of queue.json, then
dies before QUEUE.md is rendered. JSON readers and humans now select different
work. Separately, a standalone renderer can read revision 10 before B's write
and replace the Markdown with revision 10 after B has installed revision 11.
A timeout-based stale-lock remover can also admit B while a slow A is alive.
Atomic rename prevents a torn individual file, not these outcomes.
**Fix:** specify one canonical lock identity across the checkout and its
compatibility symlink; acquire it before reading, not merely before writing.
All mutations and standalone render use it. Generate both outputs from one
validated revision; record a durable transaction/revision and define recovery
for every interruption point. Readers must detect an incomplete pair rather
than treating it as current. Prefer kernel-released locking or provable stale
owner detection; do not steal a lock because a deadline elapsed. Bound waits.
Document fsync behavior if surviving a host crash is promised.
**Acceptance:** race add/add, move/note and render/write through both checkout
paths; kill after each file replacement and before/after commit; inject disk
errors and a dead lock holder. Recover one acknowledged operation exactly
once, or refuse with a concrete recovery instruction. Never erase a completed
neighbor's update.
### R2 — High: Q3's path-limited commit still captures another author's work
**Where:** Q3; AGENTS invariant 8.
**Scenario:** someone has an uncommitted change to QUEUE.md's hand-written
header or historical footer. `git commit -- queue.json QUEUE.md` includes
that entire file, not just the generated table. A concurrent ordinary commit
can also capture the queue between its write and auto-commit: it does not
honor the queue lock. An index-lock or hook failure leaves already-mutated
queue state without the promised commit, and an unsafe rollback could erase
a later writer. Git's index lock is not a lock over the whole operation.
**Fix:** default auto-commit off until Q3 is settled. If authorized, require
clean queue paths relative to the intended baseline, no conflicting staged
versions, no merge/rebase, and the authorized branch; serialize *all* relevant
commit writers through an agreed repository protocol. Freeze and validate
the exact prospective file contents, check HEAD/revision before committing,
and define retry/recovery without reset/checkout of others' changes. A queue
lock alone cannot enforce cooperation by arbitrary host git commands.
The statement that a validator means invariant 8 holds is false: schema
validation is not the applicable suites. Identify the required checks and
bind their receipt to the actual prospective content/code version. Absence
of a shell suite wrapper does not exempt existing Node package tests.
**Acceptance:** pre-dirty header, partially staged queue file, unrelated
staged files, competing ordinary commit, hook failure, and changed HEAD.
Verify both the committed tree and preservation of the other author's index
and working changes. No push authority follows from any local commit.
### R3 — High: single-writer checks validate appearance, not provenance
**Where:** 5.9, 3.A, migration and `render --check`.
**Scenario:** hand-edit a row from queued to done, run render, and both schema
validation and `render --check` pass. A Markdown hand edit is silently erased
by the *next successful CLI mutation*, before the suite ever checks it.
A merge can produce valid JSON with illegal transitions or removed rows;
two clones can independently allocate the same new id. A fresh clone has no
local lock installation or uncommitted audit trail and cannot reconstruct
the claimed writer from a matching table.
**Fix:** check for unexpected drift *before* mutating or rendering, refuse
ambiguous markers and refuse to overwrite unexplained manual changes. Define
a reviewed genesis/migration and validate each subsequent operation against
its parent revision, including immutable IDs, deletions and authority rules.
Use a committed operation history or another explicitly authorized receipt
scheme, with merge reconciliation and fresh-clone validation. Keep a high
water mark/tombstones for retired IDs, including removed row 7. If multiple
clone writers are out of scope, refuse their integration until reconciled;
a per-checkout lock does not solve that problem.
Be honest about the boundary: code running as the same host user cannot
prevent that user from rewriting both data and receipts. Without an enforced
integration boundary, this is a cooperative writer with drift detection,
not tamper-proof authority. Hooks alone would not fix fresh clones and are
outside Piece A's brief anyway.
**Acceptance:** valid-but-illegal hand-edited JSON with regenerated Markdown,
deleted highest id, duplicate-id branch additions, conflicting merge,
fresh clone, missing/duplicate render markers, and preexisting Markdown drift.
### R4 — High: identity attribution is still being used as authorization
**Where:** Q5, 3.A authority tests, 5.3 and 5.8; brief iron-clad point 5.
**Scenario:** a seat runs `--by jason` or sets `MOSAIC_AGENT_NAME=sage` and
moves a protected row. If assign lacks the move permission check, it can
instead assign another seat's row to itself and then move it. Even without
spoofing, the proposed rule only restricts *clearing* required, while the
brief says only Jason *moves* required rows. These are different rules.
**Fix:** separate claimed attribution from verified authority. Q5 can map
the new lead's queue role, but does not turn an environment variable into
proof or grant managed-worker policy authority. Specify the permitted actor
for every mutating verb/field, including assign, dependencies, required,
gate ownership, notes and terminal rows. Either retain an explicit reviewed
human gate for protected mutations or have Jason accept the limited
cooperative trust model; weekly reporting is detection after the fact, not
enforcement. Reconcile the exact required-row exception before building.
**Acceptance:** forged identity, reassignment bypass, dependency/gate edits
by an ordinary seat, edits to done/parked rows, and every operation on a
required row. No roles/*.json expansion is implied by this review.
### R5 — High: Gate G can appear to pass with extra human help or no work
**Where:** Gate G setup and pass evidence; ledger.mjs `messageKind` (line 78)
and `readSessions` (line 92); agent-host-dev.sh context and fresh handling.
**Scenario:** Jason supplies a correction through the board or a lead relays
it. The ledger counts it as board/agent, leaving exactly one human message.
`--fresh` creates a new conversation but preserves old session files and
loads shared SOUL/USER/CONTEXT/skills; a task-specific hint there can make
the demo pass without discovering the assignment. Another seat can move
the row using the test seat's claimed identity. Reading the brief and
moving the row alone is also not evidence of actually starting its work.
**Observed read-only probe:** `messageKind` returns human for the initial
instruction, board for `[dragon-lin:control-board -> dragon-lin:rocko]`
followed by a human correction, and agent for a similarly prefixed Sage
relay. The new `[from: sage (...) -> to: rocko (...) class=actionable]`
header is classified human. Table 2 aggregates a seat's sessions over the
date range, not an identified Gate G session. It is unsuitable as the
sole acceptance counter in either direction.
**Fix:** pin the exact fresh session id, initial context/brief/queue
revisions, test interval and command output. Audit *all* input channels in
that interval; distinguish the initial instruction from further human
input regardless of routing. Preserve generic governance context but
exclude task-specific pre-coaching. Require a concrete first authorized
work action tied to the returned row and that session. Jason's observed
pass/fail remains authoritative; do not infer it from the row or git author.
Allow normal prerequisite reads instead of requiring the literal first
filesystem read to be the brief. A commit is not necessary proof of G and
must not bypass Q3 or suite requirements.
**Acceptance:** negative controls with a board correction, relayed hint,
resumed session and row moved by a helper must fail. Use unit tests with
competing eligible rows to test selection: the single-row demo cannot.
### R6 — High: dependencies and `next` do not prevent unauthorized starts
**Where:** Q8, section 1, 3.A and 5.11.
**Scenario:** `next` skips a dependent row, but the seat directly runs
`move ID in-progress` and bypasses the filter. Two sessions of the same
seat both read `next`, then both start the same work; a state of in-progress
does not distinguish resume by the owner session from a second claimant.
An in-review row returned to its author may cause premature continuation;
a reviewer can repeatedly receive a row it already reviewed if its receipt
is not represented.
**Fix:** enforce prerequisite and authority predicates at transition time
under the lock, not only in selection. Define atomic claiming or an explicit
single-active-session assumption with detectable conflict. Return the action
role (implement, resume, review, wait) and track review round/receipt so
review dispatch has a stopping condition.
There are unresolved semantics: Q8's done-only dependencies cannot express
the brief's row-6-*blocked* start exception. State-priority ordering differs
from the existing first-eligible-row cadence. `after` alone cannot express
every arbitrary owner priority, especially between active rows. Decide these
once and update the brief/cadence together. Test that required work cannot
be subordinated to ordinary queued work through dependencies.
### R7 — High: posting then recording cannot promise exactly one review request
**Where:** 2.D, 3.D, 5.14; scripts/gitea-api.sh.
**Scenario:** Gitea accepts a comment but the response is lost, or the CLI
dies before storing its id. The row remains unchanged and retry posts a
second request. Conversely, a posted request survives a failed local commit.
A repository lock cannot roll back the remote side effect. The existing
helper supplies an ordinary POST, not an exactly-once transaction.
**Fix:** define a durable operation id containing row, revision, review
round and candidate digest; persist intent before sending. Include the id
in the request, reconcile uncertain outcomes by lookup/readback, and refuse
blind retries if delivery cannot be determined. Specify outbox/recovery
state and bounded lock behavior. An authorized token path also needs an
expected account check; checking that the path differs from the default is
not proof of the intended poster. Do not read or provision tokens before Q4.
**Acceptance:** accepted POST with dropped response, crash before receipt,
duplicate retry, concurrent moves, stale candidate and local commit failure.
Fake success/failure alone does not test these boundaries.
### R8 — High: missing from the open list does not establish closed
**Where:** Q7 and 2.E.
**Scenario:** a row references a typo/nonexistent issue, a deleted issue, a
PR number or an inaccessible item. It is absent from a complete open-issues
response and the proposed algorithm declares it closed. Even a short page
only shows that that response is short; it does not prove each referenced
number is a known issue. A done row can therefore pass with no closure
evidence.
**Fix:** retain the additional open-list call and full-page refusal, which
are useful, but represent absent as unknown unless there is positive issue
existence/type/state evidence. Fetch/cache positively identified referenced
issues under a revised call budget, or report incomplete evidence instead
of success. Bound cache age and detect changed scope. Specify `--no-issues`
as unknown queue issue checks, not zero violations.
**Acceptance:** nonexistent/deleted/PR references, denied access, malformed
responses, a full page and no-issues mode. This is a requested correction
to decided Q7, not an instruction to silently implement another fetch policy.
### R9 — High: the liveness exemption can turn missing evidence into green
**Where:** Q6, 2.E and 3.E; scan.mjs lines 272–307.
**Scenario:** remove a native seat's registration and it gets the same
non-violation label as a T3 seat. `loadRegistrations` returns records plus
errors; it does not check liveness and loads multiple layouts. Matching a
seat name alone can select a fleet/other-workspace record. A dead or reused
PID is not evidence of the intended active session. Corrupt records must
not become the missing-registration exemption.
**Fix:** preserve Q6's prohibition on T3 probing, but distinguish explicitly
unsupported runtime, missing expected registration, invalid record, stale
record and live matched record. Match repository/layout/session identity.
Propagate scanner errors. Show coverage/unknowns alongside violations and
do not call E fully passed on zero violations when liveness was untested.
Record the owner's explicit acceptance of a temporary reduced gate.
**Acceptance:** missing native registration, corrupt record, duplicate seat
across layouts, wrong workspace, dead PID, unknown PID and an exempt T3 seat.
### R10 — Medium: history needed for E is absent from the schema
**Where:** 5.3, 5.8 and 5.12; brief E's age and same-day remediation rules.
**Scenario:** `queue note` refreshes updatedAt every week, making a
long-neglected required row appear young. A row is changed twice between
ledger runs and updatedBy remembers only the last writer, so E cannot list
every protected change as 5.8 promises. Removing a row and having no delete
verb does not prove an id was never reused. A single latest timestamp also
cannot prove each observed violation was remedied within the day.
**Fix:** define stable createdAt/requiredSince, operation history and audit
retention, with explicit time zone and first-observed violation evidence.
Do not depend on optional Q3 commits for mandatory checks. If a journal is
chosen, make corrections new entries and place it in a dedicated directory;
do not rewrite BUILD-LOG, SESSIONS or existing append-only runtime logs.
Terminal required rows should not age forever as outstanding work.
### R11 — High: some section-5 fixes change owner requirements, not details
**Where:** 5.6, 5.7, 5.10, 5.13 and 5.14; brief A/C/D and iron-clad point 3.
**Scenario:** the builder follows “settle in A's round” and makes brief
optional, reopens parked rows, allows completion without Jason, or changes
the issue/gate semantics. Those are externally visible requirements changes.
The brief explicitly demands an existing brief for every row and says
parked/done rows never change. A queued row can have an existing planning
brief not yet accepted; a missing brief is not technically necessary to
make queued reachable.
**Fix:** put each unresolved behavioral change in a disposition table:
original rule, proposed rule, approving authority, acceptance change. Keep
already-decided changes separate. Do not conflate source review approval
with owner approval of altered gates. Decide the blanket `any→blocked`
versus terminal immutability conflict and block→block semantics too.
The multi-row issue problem is real, but “open iff at least one row not
done” is only sound if rows exhaust the issue's scope. Row 1/22 explicitly
separates broader MVP acceptance from one targeted correction; row 6 has
two issue phases. Model which row gates issue closure, or report mismatch
for disposition without forcing automatic closure. A single reviewer field
also loses row 6's independent Darkwing/Dewey reviews; use a review policy
that can preserve both if that row is migrated intact.
### R12 — Medium: immutable review candidate and receipt lifecycle are missing
**Where:** 5.14 and Piece D pass tests.
**Scenario:** a request posts `/tmp/candidate.sha256`; the file is replaced
or disappears, so a later reviewer cannot identify what was approved. This
takeover already found the historical #1511/#1512 `/tmp` snapshots absent.
With `issues: [int]`, “the piece's issue” also no longer selects an unambiguous
posting target. Posting a request alone does not establish a full review
round or preserve its verdict when the row loops through review again.
**Fix:** resolve and store the candidate content digest and durable commit
or artifact reference, not just a path verbatim. Name the request issue,
review round, required reviewers and receipt links; preserve prior rounds.
Test request→changes requested→new candidate→approval against exact pins.
Keep the brief's ban on new review files, but evaluate the stronger proposed
ban separately: no-files-anywhere is not a substitute for durable receipts.
### R13 — Medium: brief validation and migration are too shallow
**Where:** 3.A migration/C and 5.12; current QUEUE rows and parked table.
**Scenario:** a directory or symlink outside the repository “exists” as a
brief, or an untracked local brief makes the author's tests pass but is absent
in a fresh clone. A nonexistent section passes even though the fresh seat is
instructed to open only the named brief section. Migration shortens a state
cell and drops an acceptance/publication boundary that is not actually
duplicated in CURRENT or an issue. A valid golden Markdown file proves none
of those semantics.
**Fix:** require a readable repository-contained regular brief, a defined
symlink policy, and tracked prospective content for publishable rows. Either
validate section anchors or disallow them for actionable rows until resolved.
Produce a reviewed row-by-row migration map preserving owners, review lanes,
gates, required status, dependencies, historical IDs and each unresolved
boundary. Map parked entries with no briefs explicitly rather than inventing
authority from their free text. Preserve history through exact durable links
or a reviewed archive; do not assume it was copied elsewhere.
### R14 — Medium: package reuse and acceptance wiring need concrete decisions
**Where:** 2.E, 3.B, section 1; package.json and existing module layout.
**Scenario:** ledger imports `@mosaic/queue` but adding a sibling package.json
does not install a workspace package. Root package.json declares no workspaces;
a read-only `import.meta.resolve('@mosaic/seat')` probe returns
`ERR_MODULE_NOT_FOUND` today. Moving the registration loader into seat also
touches a package outside E's listed files and requires its regression tests.
**Fix:** use the existing relative-module convention or explicitly plan
package linking and its installation/lockfile consequences; do not leave
it implicit. Reuse the loader without silently expanding ownership, and
specify liveness/error handling separately (R9). Name actual package test
commands and affected suites. C also needs the promised two owner-accepted
briefs, not just missing-path tests. D needs a full review round and E the
dated ledger receipt/remediation evidence. B's `--check` verifies inputs
exist, not that a running or fresh session received the new cadence; inspect
the launch context and then perform G. Clarify the brief's “A to E in order”
against the proposed C-with-A and D/E parallel delivery before dispatch.
## What is fine
- Repository-local `scripts/mosaic` dispatch, keeping seat argv/env behavior,
and tests for that behavior are appropriate. Q1 correctly remains an owner
wording choice; no global CLI or fleet edits are needed.
- Queue data under docs/plans and code under packages/queue respect
bootstrap-only root. An edit to the existing root AGENTS.md is permitted;
a new root lock/journal/config file would not be. The plan proposes no
contract, secret, run-record or managed-role changes.
- Required as a flag, an explicit review-to-work edge, strict unknown-field
validation, dependency cycle checks, deterministic rendering and a
non-mutating render check are good building blocks. They need the
transaction/history/authority rules above to deliver the claimed result.
- Missing identity refusal, Q4 held for explicit credentials, no automatic
push, no T3-backed product feature, and preservation of the old table log
are sound boundaries. Historical log corrections must remain additions.
- Combining migration with the introduction of the authoritative data file
avoids a deliberate two-master interval. A reviewed migration map still
matters. Reusing one validator is correct once module resolution is explicit.
## Recommended disposition
Revise the write/recovery/commit protocol (R1–R3), settle protected authority
and requirement changes (R4/R11), strengthen Gate G evidence (R5), and specify
transition claims and review delivery recovery (R6/R7) before implementation.
Correct E's positive-evidence rules and audit model (R8–R10); complete the
candidate, migration and packaging details (R12–R14). These are bounded plan
changes, not authorization to build a new policy service or alter live state.
Validation for this review was source inspection and read-only in-process
probes of the existing message classifier and module resolution. No queue
implementation or fault-injection suite was run because none exists yet.
This report records the session outcome in place of editing SESSIONS.md,
as this assignment explicitly permits writes only to the report.
@@ -0,0 +1,352 @@
# Queue as data — adversarial review, round 2
VERDICT: revise
Rocko for Sage, 2026-09-26. Verified the requested plan SHA-256 **before
reading**: `94922cc5319f03d9f4d11c3a3a8935022440ff2386c9dd160c4bce1daaa27cc5`.
Review target is section 7 plus the revised body of
`agents/filbert/work/queue-as-data-plan-2026-09-26.md`. Prior findings are
the unchanged R1 report, SHA-256
`df433f932f6e8687fdb2ad6d707d133b633a245ac39293362ce6bde6942cbf5c`.
The dispositions make substantive improvements. They do not yet supply a
consistent implementable protocol: the lock/recovery design has unresolved
failure schedules, claims rely on a variable the launchers explicitly
unset, and the review-post retry still overpromises. These are design fixes
for the lead/planner, not nine more questions for Jason.
“Closed” below means closed at the planning level, subject to implementation
and its tests. No implementation, fault injection, live state change, or
credential access was performed. This report is the only write for round 2.
## Disposition of all original findings
| Original | Round-2 status | Does the proposed change close the scenario? |
|---|---|---|
| R1 transaction/recovery | Open | Journal-first ordering helps, but partial append, stale-lock reclamation, drift/recovery discrimination and retry identity remain unspecified or contradictory. See S1–S4. |
| R2 auto-commit ownership | Partly closed | Removing the commit feature closes the automatic sweep. Manual path commits still need exact-content freezing, header ownership and coordinated integration; “after tests” alone has a race. See S5. |
| R3 provenance | Partly closed | Replay, tombstones and an honest cooperative boundary close several scenarios. Worktrees/forks/genesis and automatic repair still undermine the proposed guarantees. See S2, S3, S6. |
| R4 authority | Conditional, not yet closed | The claimed-actor matrix and J1/J2 are concrete, bounded improvements. Protected field creation, parked immutability and exception precedence need correction; owner acceptance of cooperative trust remains pending. See S7. |
| R5 Gate G | Partly closed | Auditing every user-role entry and requiring a work action close the classifier/no-work holes. Incarnation evidence is unavailable, USER is not a committed input, and helper/file-based coaching remains outside the stated check. See S8. |
| R6 dependencies/claims | Open | Transition predicates and review actions help. The required dependency prohibition rejects row 9's own prerequisite; absent identities and “resume another incarnation” leave duplicate work possible. See S7/S8. |
| R7 remote request | Open | Durable intent and a marker improve recovery but lookup-then-retry cannot establish at-most-once delivery. Outcome state and replay also need definition. See S9. |
| R8 issue evidence | Closed at design level, budget pending | Unknown-by-default, positive typed issue lookup, bounded fetches and not-run reporting close the original false-closure scenarios. Keep those rules even if J8 is declined. |
| R9 liveness | Partly closed | Coverage and explicit exemptions close the false-green policy. The plan cannot compare process start identity against a field never recorded; unknown PID/start evidence needs a defined result. See S8. |
| R10 age/history | Partly closed | Stable requiredSince and journal history address note-reset and overwritten attribution. Genesis dates and proof of remediation still need rules. See S6/S10. |
| R11 owner changes | Mostly closed as triage | Changes are now explicitly held rather than silently implemented. J3/J7/J9 need not all go to Jason; closure mapping still needs per-issue semantics for multi-issue rows. See S7 and the J table. |
| R12 candidates/receipts | Partly closed | Digests, review rounds, multiple reviewers and reviewIssue help. A local manifest path or unreferenced commit is not durable candidate content. See S10. |
| R13 brief/migration | Partly closed | Exact legacy rows, anchor checks and a migration map are real fixes. Index membership does not prove committed content, and replay cannot revalidate historical briefs against current files. See S6/S10. |
| R14 wiring/acceptance | Closed at design level | Relative imports, no loader move, named suites, C/D/E receipts and B context inspection resolve the original wiring gaps. Consolidate stale body instructions before implementation (S11). |
## Remaining mechanism findings
### S1 — High: mkdir plus PID/start time is not a complete lock protocol
**Failure schedules:**
- A successfully creates the lock directory and dies before creating its
owner file. A paused live A looks identical to a dead A at this point.
There is no PID/start time to prove stale. A partial owner file has the
same problem.
- B and C both inspect dead A's lock. B removes it and acquires a new lock.
C removes the path using its earlier observation of A. B and C can now
both enter. A check immediately before removal still has a race unless
the removal/reclamation protocol itself is serialized.
- PID and start ticks identify a process within a boot/PID namespace, not
across reboot or another host mounting the checkout. Permission errors
reading `/proc` are not proof of death.
**Required fix:** either use a kernel lock for *all* entry points, including
direct CLI invocations, or fully specify atomic owner publication,
exclusive reclamation, owner-checked release and incomplete-owner handling.
Kernel locking need not be limited to the shell wrapper: the CLI can invoke
a locked child path; implementation choice belongs to the lead. If retaining
mkdir, refusing incomplete owner records for explicit recovery is honest;
pretending PID checks automatically recover them is not. Include boot/host
scope or explicitly refuse unsupported environments. Do not delete a lock
based on age or an old inspection.
**Tests:** kill between mkdir and owner publication; pause there; partial
owner record; two simultaneous reclaimers; reboot identity mismatch;
unreadable `/proc`; delayed old owner's cleanup after replacement.
### S2 — High: partial journal appends have no append-only recovery rule
**Scenario:** append writes only the first half of a JSON object before an
I/O error or kill. Replay now cannot parse the tail. Appending the next JSON
object does not repair the malformed line. Truncating the tail would alter
the new append-only journal, contrary to the proposed invariant. “Anything
else: refuse with recovery instruction” is safe refusal, but the recovery
instruction itself has not been designed.
**Required fix:** define complete-entry framing, entry checksum/hash chain,
format version, short-write handling and the durable commit point. Choose
one bounded torn-tail procedure that preserves prior bytes/evidence: for
example a precisely recognized incomplete frame plus an explicit recovery
record, or a new journal segment linked to preserved damaged evidence.
Alternatively retain refusal and require a separately specified recovery
operation; do not promise automatic recovery in its absence. Arbitrary
interior corruption must never be skipped as an incomplete tail.
The durability prose is also wrong: an entry fsynced before stdout **can
survive without acknowledgement** and will be replayed. Say acknowledged
operations are durable; unacknowledged operations may have committed and
must be queried/retried by identity. The Markdown write lacks explicit file
and directory fsync. It may be a rebuildable cache, but then do not promise
that the entire acknowledged three-file set survives a host crash. Fsync
new journal/genesis directory entries as well as file data.
**Tests:** short write and ENOSPC during append, crash before/after fsync,
missing newline, invalid interior entry, crash on initial journal creation,
and recovery without rewriting already-persisted evidence.
### S3 — High: “stale view: re-render” also erases hand edits
**Scenario:** a user changes the Markdown table or stamps it with an older
revision. Under R1 it is stale and automatically regenerated; under R3 it
is unexplained drift and must refuse. A JSON hand edit that happens to
equal an old parent similarly resembles incomplete materialization.
Current instructions do not distinguish these cases or decide whether
verification precedes recovery or recovery precedes byte equality.
**Required fix:** define recovery only for exact known materializations of
the prior/current revision, with expected content hashes and transaction
state. Preserve and reject anything else. Revision markers alone are not
content proof. Define separately non-mutating `verify`/`render --check`,
normal reads, and an explicit repair path. Running a check must not silently
fix the drift that the check was intended to expose. If `list`/`next` may
repair caches, label that effect and never repair unexplained content.
**Tests:** stale genuine view versus edited view with the same old marker;
current marker with changed body; missing/duplicate marker; edited header
during rendering; verify/check on an interrupted materialization. Body and
hand-maintained header/footer must retain their respective ownership.
### S4 — High: equality of rows/states is not idempotency
**Scenario:** A starts review, its result is lost, B requests changes and
moves back to in-progress, then A retries. Comparing only current state
permits a second review round. An add retry after reassignment/completion
no longer matches the same non-terminal tuple and can allocate a new id.
An unrelated writer can produce the same state and A is incorrectly told
its own earlier operation succeeded. Notes and other mutations are omitted.
R1 says moving to the current state succeeds; R6 says
in-progress→in-progress is refused. Both cannot be the retry contract.
**Required fix:** stable caller operation id plus expected parent/row
revision and canonical payload, persisted for every mutation. Retrying
the same id returns its recorded result even after later state changes;
reusing it with a different payload refuses. A *new* operation attempting
in-progress→in-progress may refuse. Specify how the caller retains the id
before sending so a killed CLI does not generate a new id on every retry.
Otherwise withdraw the at-most-once retry claim and expose uncertainty.
### S5 — Medium: manual commits still need an integration boundary
**Scenario:** test-queue.sh passes revision 12, another CLI writes revision
13, and the lead commits by path. Or QUEUE.md's header contains another
author's unreviewed change. Removing auto-commit does not make either file
content safe to include automatically.
**Required fix:** Sage can decide a cooperative integration procedure:
freeze/pin all three queue files and hand-maintained changes, prevent queue
mutations between exact-content verification and staging/commit, and check
the prospective tree and HEAD. Coordinate other commit writers. Do not
hold a non-reentrant lock and run a test suite whose verify subcommand waits
on the same lock; define the maintenance/integration path explicitly.
No automatic git operation needs to be added to A. The tests/code receipt
must match what is actually committed. Lead status alone still grants no
commit or push authority beyond the established plan.
### S6 — High: common-dir serialization does not establish one queue history
**Scenario:** two linked worktrees share the real common-dir lock, but each
has its own queue files. They write sequentially under the lock from the
same parent and create divergent histories anyway. A later merge resolving
the journal by selecting only one side leaves no visible fork for replay
to detect. An appended “reconciliation” entry also cannot make an earlier
fork satisfy a strictly single-parent replay rule without special semantics.
**Required fix:** for this canonical-checkout assignment, simplest is to
refuse mutations in other worktrees/clones and pin the canonical root,
branch and queue identity. The symlink to that root is fine. Resolve a
relative git-common-dir result against the command's actual cwd before
canonicalization. Define integration checks against the last accepted tail
and relevant parents; acknowledge that discarded branches are not detectable
from the remaining journal alone. Prefer refusing forks for a reviewed
reconciliation procedure over inventing an unspecified append that bypasses
validation. No distributed writer support is needed here.
**Genesis:** it must be a single, reviewed, versioned migration seed, not a
normal sequence of transitions (legacy rows start done/parked and lack old
claims/receipts). Permit this exception exactly once. Keep original rows,
the reviewed normalized mapping, retired IDs/high-water mark, and provenance
of legacy dates/acceptance gaps. Do not invent historical approvals. Set
requiredSince from evidence or explicitly unknown; migration time must not
reset old required rows' age. A second genesis/reset must refuse.
Historical replay must use versioned operation semantics and recorded brief
identities, not today's mutable brief files, owner roster or transition
implementation. Check *current* actionable briefs separately. Otherwise
editing or removing a once-valid brief makes all future replay impossible.
Specify deterministic JSON serialization for the byte-equality requirement.
### S7 — High: the revised matrix rejects its own prerequisite and has gaps
**Scenario:** R4 forbids a required row depending on a non-required row.
Row 9 is required and depends on row 6, which is not marked required in
the current queue. Genesis/current validation cannot enforce that blanket
rule while preserving the approved start condition. Real prerequisites are
not the same thing as gratuitously lowering required work's priority.
**Required fix:** preserve explicit owner-approved prerequisites, including
row 6, and restrict who may change them; do not ban their data shape. Define
what happens after `settled` allowed a child to start and the parent later
leaves blocked: do not inadvertently strand review/completion by rechecking
start prerequisites on every transition.
Permission checks need field-level precedence on `add` as well as subsequent
edits (an ordinary owner must not choose a privileged gate/required field to
bypass the matrix). Parked-row note/assign edits must not escape terminal
immutability unless J4 explicitly permits them. Specify the closure mapping
per issue: one `closesIssue` boolean on a row with `issues: [1511,1512]`
does not explain which issue it governs. Multiple rows for #1508 also need
an explicit closure rule. Review receipt writes need a permitted actor and
exact-candidate check, not just storage fields.
### S8 — High: claim and process identity are not provided by current code
**Observed:** `scripts/agent-host-dev.sh:131` and
`agents/rocko/launch.sh:84` explicitly `unset MOSAIC_LAUNCH_INCARNATION`.
No producer for that variable was found in the scoped launcher/seat code.
The registration whitelist in `packages/seat/src/seat.mjs:130` contains
PID and an ISO `startedAt`, but no captured `/proc` start ticks or boot id.
The latter timestamp is recorded at registration creation; it is not a
saved process-start identity suitable for the comparison R9 proposes.
**Consequences:** Gate G's required claim cannot be satisfied as written.
R6's “when present” falls back to indistinguishable claims for multiple
same-seat sessions. A different incarnation offered `resume` can still
resume the work; a claimed-by warning is not refusal. Liveness cannot prove
that a present PID was reused by comparing against evidence never recorded.
**Required fix:** choose an existing verifiable session/launch receipt
identity, or explicitly plan the narrowly scoped identity producer and
its ownership/review dependencies. Do not silently change launchers or
registration schema as A/E implementation detail. Refuse missing claim
identity where exclusivity is required; report another claimant as wait/
conflict, with explicit handover/reclaim semantics. Treat unavailable
process-start proof as unknown/incomplete, not live or stale by invention.
Gate G must use actual launch inputs: USER defaults to
`<dataRoot>/user/USER.md` in agent-host-dev.sh:66, not a committed repo file.
Hash/audit it privately without copying private content into git. Bound
the no-coaching audit to all actual context sources, including loaded
skills and post-launch task-specific file changes; transcript messages
alone do not cover them. An incarnation string remains a cooperative
claim; bind acceptance to the observed test-session command/action trace
and Jason's observation, rather than claiming it proves no helper spoofed it.
### S9 — High: marker lookup does not guarantee at-most-one POST
**Scenario:** Gitea receives a POST, the client times out, and the first
request is still being processed. A subsequent successful GET shows no
marker yet; retry creates a second comment, and the first request then
completes. Incomplete pagination or a removed comment also looks absent.
Changing queue revision while an intent is unresolved can generate a new
operation id for the same logical review if identity is recomputed.
**Required fix:** on uncertainty, reconcile a found marker; otherwise
remain unresolved and do not re-POST merely because a GET found nothing.
Retry only when non-acceptance is positively known, or use server-side
idempotency if separately established. This bounds availability honestly.
Define complete comment lookup, pagination bounds and ambiguous duplicates.
Persist the operation id and candidate before send and reuse them unchanged.
Specify journal events for intent, confirmed request, definite failure and
unresolved outcome, including their materialized snapshot/review states.
If the lock is released during I/O, finalization must compare the expected
row/round and cannot overwrite a newer candidate. If held, set network
deadlines and state the effect on all reads sharing the 10-second lock wait.
A replay/check must never send the POST. Removing “exactly once” but keeping
an unsupported “at most one” claim does not close R7.
### S10 — Medium: hashes and tracking are necessary, not sufficient, evidence
**Candidates:** a repository-contained manifest may still be untracked or
overwritten; its digest cannot recover absent source bytes. A present commit
may be unreachable and later garbage-collected. Require a retained commit
reference or durable, committed manifest *and retrievable pinned source*,
with readback verification. Keep all prior review rounds.
**Briefs:** `git ls-files --error-unmatch` proves index membership. A staged
new brief has no committed copy; a tracked modified brief can have an anchor
only in the dirty version. Resolve brief content/anchor against the actual
prospective committed tree and bind that blob identity to the queue evidence.
**Remediation:** a same-day journal timestamp proves a row changed, not that
the recorded violation was addressed. Link the specific violation/issue and
follow-up result or explicit accepted disposition. A note-only edit must not
erase an invalid-registration finding. RequiredSince for legacy rows must
retain uncertainty rather than invent a recent date (S6).
### S11 — Medium: contradictory executable instructions remain in the body
Section 7 contains the better decisions, but 2.E still says absent issues
count as closed; 3.E still exempts every missing registration; 3.A says
anchors are not verified; 5.6 still recommends optional briefs. 2.A still
says missing shell wrappers mean invariant 8 does not cover package tests.
Some sections explicitly mark supersession; these do not consistently do so.
**Fix:** consolidate the active specification and tests, retaining the old
reasoning only as clearly marked history. Publish one state/permission
matrix, one schema (including the new snapshot envelope replacing the old
array), one journal/recovery table and one acceptance checklist. Otherwise
builders can implement opposite rules while following the same plan.
## Are the four modifications honest and bounded?
| Modification | Assessment |
|---|---|
| R1: mkdir/PID-start lock instead of flock | Legitimate implementation choice, but “provable stale-owner detection” is not yet earned. Accept only after S1–S4 specify the failure boundaries. Node lacking built-in flock is not proof a kernel lock cannot cover direct CLI calls. |
| R3: cooperative writer, fork refusal | Honest and appropriate with J2 accepted. Bound to one canonical writable checkout and say forks are detected only when their evidence is retained. Do not promise an undefined reconciliation entry repairs arbitrary merged history. |
| R6: conditional dependencies and optional incarnation | `settled`, action roles and the no-active-priority limitation are reasonable. Optional nonexistent incarnation and resume of another claim are not a bounded substitute for exclusivity. Correct S7/S8; the row-6 condition need not be asked of Jason again if Sage is applying the already explicit brief. |
| R7: at-most-one request with reconciliation | Honest intention, currently false guarantee. At most one attempted POST after ambiguity, with unresolved state and no automatic resend, is bounded and implementable. Successful empty lookup alone is not safe retry authority. |
## J1–J9: who should decide?
| Item | Disposition | Recommendation |
|---|---|---|
| J1 required-row authority | Real owner boundary | Resolve the ambiguous “only Jason moves” against delegated routine progression. Recommend owners may progress approved required work; only Jason changes its mandated priority/removes required status. Do not misstate required→in-progress as inherently contradicting Jason-only authority: it is a legal edge, not an actor rule. |
| J2 cooperative trust model | Real owner boundary | Jason must accept the limitation relative to “iron-clad,” or fund a different boundary. Journal replay is not authenticated human authorization. |
| J3 queued wording | Lead should resolve | Existing mandatory brief rule is clear. Define queued as an existing planning brief not yet accepted, keep `add --brief`, correct the descriptive queue header and record the interpretation. No need for a separate owner question unless Jason previously mandated brief-less records. |
| J4 unpark | Real conflict if implementing | The brief says never change, the queue says Jason reopens. Keep terminal refusal until settled; if reopening is wanted, ask once, preserving Jason-only reopening. |
| J5 review→done | Real owner gate change | Jason decides any relaxation of mandatory waiting-on-jason. A non-Jason gateOwner must come from approved gate policy, not a row author's convenience. |
| J6 issue closure model | Real acceptance-rule change | Jason approves replacing literal E equivalence; Sage supplies a concrete per-issue closure mapping and test cases first. Do not ask Jason to design the schema. |
| J7 broader review-file ban | Lead should drop the optional expansion | The assigned brief already chooses issue receipts and bans docs/plans/reviews. Implement that. There is no present need to ask Jason whether to prohibit every private working report as well. If Sage later wants that broader governance change, it is a separate proposal. |
| J8 fetch budget | Conditional owner boundary | Keep #1506's existing weekly metric query unchanged. Sage can choose E's bounded technical fetch design; if the one-call restriction governs the entire combined command, Jason must approve exceeding it. Resolve scope from the original contract before asking, and present one concrete amended budget (base/open-list/per-issue/identity calls distinguished), not “allow 20 or permanently incomplete.” |
| J9 row-8 brief | Lead should supply the conservative stub | A factual parked brief can preserve “no fleet migration without Jason,” ownership unassigned, and current boundaries without authorizing work. Keep historical id 8; do not remove the row merely to avoid documenting it. Jason is needed to activate/change its scope, not to record the existing prohibition. |
The explicitly held reduced-liveness acceptance and an E-before-D delivery
exception remain real owner decisions if the team wants them. They need not
block source planning that preserves the original gates. No new Jason
decisions are required to fix torn writes, locking, replay determinism or
test coverage.
## Recommended next round
Sage should choose the canonical-checkout-only cooperative design and a
concrete lock/recovery protocol, then have Filbert consolidate the plan with
S1–S11 resolved. Prefer refusal with a documented recovery path over claims
of automatic repair/idempotency that have not been specified. Carry only
the actual owner boundaries above to Jason. Keep implementation held until
the protocol and the missing identity evidence are reconciled.
Source verification for the key runtime findings used the current shared
files (no edits): agent-host-dev.sh SHA-256
`706f8e02fe0d8c18887d2e030f64f447a7db05badb3df3a20800c68ed5313687`,
Rocko launch.sh `b23341bc66dbf4594e4aabe641c53e71efbc4ad33a3c91004eb66a1a76447670`,
seat.mjs `eec970961a667c9e614d1474d33c31a019b2cf1b0bf931a51458d874bca13a15`.
Failure schedules above are adversarial design analyses, not claims of
executed fault-injection tests against queue code that does not exist yet.
@@ -0,0 +1,410 @@
# Queue as data — adversarial review, round 3
VERDICT: revise
Rocko for Sage, 2026-09-26. The requested plan hash was verified **before
reading section 8**:
`cfdaa3fe4fa3fa6ef339f834a9814eb4a472ceac7c832c19bf955b61351ff21f`.
This review applies to that section plus Sage's explicit assignment rulings:
one JSON file with embedded log, complete-record link lock, canonical root in
genesis, 12-call E budget, 8.15 defaults and explicit per-seat credentials.
The superseded separate-journal alternative and unresolved-Q4 prose are not
treated as active choices.
During review the shared plan changed to
`1666f74b615c72a3b1f9f7bc306d3e1baed920d7eb3a19968bfa7727137aca46`.
Sage was notified. That intermediate revision is not separately reviewed;
the requested section was already read in full before the change. At Sage's
subsequent direction, the final revision is reviewed in the delta below.
The architecture is substantially simpler and the complete-record lock is
sound under its cooperative, single-host assumptions. Remaining blockers are
specific: durability versus visibility, out-of-protocol git rollback, the
requesting/uncertain lifecycle, the shared git index, and acceptance evidence.
No separate journal, repair engine, distributed locking or new identity
service is recommended.
## Direct answers to Sage's four questions
1. **Rename removes partial in-place JSON updates, not every torn system
state.** After rename but before directory fsync, the new name is visible
but not yet durably committed. JSON and Markdown are still two separate
replacements. Ordinary git ignores the lock and can overwrite the entire
internally valid log. See T1/T2.
2. **The link lock plus exclusive unlock gate is a reasonable design.**
Complete owner publication and manual-only reclaim address the earlier
races. Same-host boot/start mismatch may authorize unlinking the stale
record; foreign host or unreadable identity must remain unknown. Apply
the same rules to cleanup of a stale unlock gate. See T3.
3. **No resend on uncertain outcome is the right rule, but requesting must
be unresolved too.** A kill or failed outcome write leaves no uncertain
record. The human not-posted resolution also cannot be based solely on
not seeing a comment. See T4.
4. **The Gate G link is checkable as cooperative evidence.** Pi records
tool-call IDs, command arguments and corresponding tool results. An op-id
substring anywhere in a call is insufficient; inspect the actual command,
result, session branch and matching log transition. See T6.
## Findings
### T1 — High: visibility is being called durable commitment too early
**Where:** 8.0, 8.5 steps 4–6, unlocked reads in 8.4.
**Scenario:** the temp file is fsynced and renamed; the process is killed
before directory fsync, or that fsync returns an I/O error. A reader can
already observe the new revision. A host crash can then lose the rename's
durability: the design must not promise which pre-fsync namespace state
survives. On first creation it cannot even assume a prior queue exists.
This differs from a mere process kill while the host continues running.
The single-file design does avoid a half-appended log **when the complete
validated temp file is fsynced and only then renamed on the same filesystem**.
It does not establish the stronger statement “an operation after step 4
stands” when step 4 was interrupted before its durability barrier. Nor does
the word rename imply that every invalid file could only have been written
by an outsider; failed I/O or an implementation fault also need diagnosis.
**Required revision:** distinguish the visibility/linearization point
(rename), durable completion (successful directory fsync), and acknowledgement
(receipt). On failed fsync, report an uncertain local outcome with op id,
do not print success and do not undo by overwriting another version. Reads
may expose visible state, but must not authorize an external POST from an
intent whose durable write failed. The originating request path proceeds
to network I/O only after its own successful persistence barrier.
Define startup/retry behavior after this uncertainty without automatic
repair: inspect/verify and, if needed, explicitly establish durability of
the observed operation before claiming it durable. A plain read or replay
does not itself perform a durability barrier. State filesystem/platform
assumptions and handle short writes before rename.
**Acceptance:** distinguish process kill from host-crash reasoning; inject
file-fsync, rename and directory-fsync failures separately. Check that no
receipt or POST follows failed persistence, and no unsafe rollback occurs.
Do not claim power-loss behavior was tested merely by SIGKILLing a child.
### T2 — High: a valid git rollback erases both data and deduplication evidence
**Where:** 8.2 replay, 8.5 manual recovery, 8.12 integration.
**Schedule A:** writer A holds the queue lock and has read revision 12.
Seat B runs checkout/restore/stash on queue.json, installing revision 9.
A then renames revision 13 computed from 12, silently overwriting B's
operation. If B runs last, revision 9 silently wins instead. Git does not
consult `.git/mosaic-queue.lock`.
**Schedule B:** after an acknowledged review POST, ordinary checkout or
stash restores an older JSON and matching Markdown pair. It is perfectly
canonical and replay-consistent, but the log no longer contains the POST's
op id. Reissuing the same op can now send again. Internal replay cannot
detect replacement of its entire trusted history by an earlier valid one.
**Required revision:** make preservation of queue history part of the
cooperative git protocol: no checkout/stash/restore/reset/branch switch
touching queue paths while they carry unintegrated operations or active
review requests; lead coordinates and verifies any exceptional restoration.
Check baseline file identity/hash immediately before replacement to catch
ordinary accidental interference, while stating that this cannot atomically
exclude uncooperative git. Pin the branch as well as canonical path.
Withdraw the generic instruction “restore with git” for invalid JSON. First
preserve the failed bytes and reconcile all acknowledged and outstanding
ops against receipts; restoring HEAD may delete work performed since the
last commit. A deliberate history reset requires explicit disposition of
external side effects and cannot retain the normal deduplication guarantee.
No same-user file format can make arbitrary rollback impossible. This is
a necessary trust-model limit, not a demand for a second authoritative log.
**Acceptance:** checkout/stash interleavings and a restored older valid pair
must be either refused by the cooperating workflow or explicitly diagnosed
as outside the guarantee. Do not label a passing replay as proof that no
history was lost. Preserve append-only *logical* history across normal writes.
### T3 — Medium: stale-gate cleanup needs the same identity rules as unlock
**What is fine:** the lock record is complete before `link()` publishes it.
EEXIST preserves exclusivity. The exclusive unlock gate prevents two
unlockers acting on old observations. A writer publishing after the gate
appears either sees it and releases or is classified live and retained.
I find no two-cooperating-writers schedule violating that argument, given
the specified post-publication gate check and identity validation.
**Remaining scenario:** the lock/gate was created on host A; it is later
seen on host B where the numeric PID is absent. The Discord helper's
`ownerState` checks PID death before other identity fields and knows no
host. Blindly adopting that order would classify the foreign record dead.
The queue specification correctly says foreign host is unknown: that test
must take precedence over local PID liveness. A stale gate's current hint,
“remove it by hand once that pid is gone,” omits host, boot and reuse.
**Required revision:** define queue classification explicitly: validate the
record, establish supported host/namespace scope, then evaluate boot/start
and PID evidence. Same-host known previous boot is a mismatch; foreign-host
record or missing evidence refuses, even if no such local PID exists.
Apply this to the unlock gate's manual cleanup too. A reused local PID may
be alive but cannot be the old owner if known start/boot differs; never
signal that unrelated process. Unknown remains unknown.
The release check should compare the full acquisition identity (and ideally
the acquired inode), not merely op+PID. This is a small defensive improvement,
not a replacement for the gate. `unlock` must use the gate protocol directly,
not first try to acquire the very lock it is supposed to remove. Validate
temp writes and use exclusive temp creation; other link errors must refuse.
**Acceptance:** PID reuse within a boot; same PID/start on a different boot;
foreign host with locally absent PID; unknown /proc; stale gate with reused
PID; both writer/unlocker orderings. No age-based reclaim. A renamed host
may require manual diagnosis: safe unavailability is acceptable here.
### T4 — High: requesting is an unresolved outcome, not permission to request again
**Where:** 8.9; op uniqueness in 8.2 and retry order in 8.5/8.6.
**Scenario:** durable intent is recorded, the lock is released, POST is
accepted, and the CLI dies before reacquiring the lock. The row remains
`requesting`, not `uncertain`. The current prohibition on further requests
only explicitly covers uncertain. A new op could open another request.
Failure to reacquire after the 30-second network call has the same result.
A timeout of the shell helper may also leave its curl child running; the
server outcome remains unknown regardless of client cleanup.
**Required revision:** requesting-without-terminal-outcome and uncertain
must both block a new request for that logical review. An explicit manual
resolve handles both. Keep the original op and candidate frozen through
all phases. No retransmission on replay, read, retry or a new op while the
prior attempt is unresolved. Define outcome finalization as a separate
logged event referencing the original op: log op IDs are unique, so intent
and outcome cannot both append entries with the same ID. State who may
resolve and how conflicting/late resolutions are rejected.
**Manual not-posted:** a human merely checking that a comment is absent
does not prove a timed-out request will never complete. Require positive
non-delivery evidence or leave it unresolved. If the lead explicitly
overrides uncertainty to permit a fresh attempt, record the accepted
duplicate risk; do not still claim at-most-one delivery for that case.
`posted:<id>` must refer to the expected issue, marker, round and candidate.
This is operational reconciliation, not a blind state setter.
The 4xx rule should be limited to actual trusted endpoint responses known
to mean non-acceptance; an arbitrary transport/proxy failure is uncertain.
The existing helper provides HTTP status in stderr and response JSON in
stdout: the wrapper must preserve that distinction without exposing tokens.
There is no timeout inside the helper; D must bound the process tree and
treat interrupted transport conservatively.
**Related gap:** 8.7 allows `move in-review` separately from `review request`,
but Piece D's brief requires the move itself to post the request. Define
that move as the request workflow (or explicitly change the brief); otherwise
a seat can enter review without a request/round. Also, 8.5 runs stale-view
checks before retry lookup: a recorded op followed by a view-write crash
does not get 8.6's promised recorded receipt until someone renders. Define
read-only lookup/receipt behavior before view freshness blocks new mutations.
**Acceptance:** kill before POST, after server acceptance, before outcome
write and during lock reacquisition; new-op request while requesting;
same-op retry after stale view; delayed first POST after attempted resolution;
late outcome after manual resolution; no second POST in any uncertain path.
### T5 — High: the shared-index commit procedure can sweep unreviewed files
**Where:** 8.12.
**Scenario:** another seat already staged source. Step 1 adds the queue pair,
step 2 checks it, and step 3's plain `git commit` commits the other seat's
source too. Or another seat changes the index after staged verification;
the commit is no longer the tested staged snapshot. Even reading
`git show :queue.json` and then `git show :QUEUE.md` can observe different
index generations. Neither is solved by keeping the queue write lock out
of the test path.
**Required revision:** Sage should choose an isolated index for the intended
commit, or an explicit cooperative exclusive staging/commit interval with
a clean/approved index. Freeze a prospective tree id once, verify the queue
pair from that tree, verify the complete intended path set and compare HEAD
before committing exactly that tree. Preserve others' index and working
changes. Do not use path commit as a substitute: it can select current
working bytes instead of the tested staged pair.
The sequence says `verify-commit ID COMMIT` runs before the source is
committed. Define a prospective-tree verification target or verify the
resulting local commit before treating it as approved integration. Also
ensure package tests exercise the proposed queue code, not unrelated dirty
working versions while claiming the staged code passed.
**Acceptance:** unrelated staged file; two-stage reads across an index
mutation; index mutation after verification; working queue changes during
integration; changed HEAD; manifest compared with the actual prospective
source tree. Commit authorization remains separate from this procedure.
### T6 — Medium: Gate G's evidence exists, but the checklist must follow execution
**Observed in the installed pinned Pi code:** session entries have `id` and
`parentId`; the header may carry `parentSession`. Assistant `toolCall`
blocks have `id`, `name` and `arguments`; a `toolResult` has `toolCallId`,
`toolName`, content and `isError`. Thus a direct bash command and its result
can be linked without inventing an incarnation variable.
**False pass:** a failed command, a dry-run/echo containing the op ID, or a
command on an abandoned session branch satisfies “op id appears in a tool
call.” Meanwhile a helper has moved the row. The checklist already concedes
helper spoofing is outside the cooperative proof, which is honest; it
should still reject these observable non-execution cases.
**Required revision:** pin session id/file hash at the evidence cutoff,
freshness/no-parent evidence, active entry ancestry and the test interval.
Inspect the actual `scripts/mosaic queue` invocation in canonical cwd,
its op/row/actor/arguments, the corresponding tool-result ID and receipt,
and the matching log entry/revision. A successful recorded retry is evidence
of lookup, not proof this session originated the move: check the original
timing and pre-test revision. If output was lost or truncated, preserve the
actual recoverable evidence or declare the link inconclusive.
Require the trace `next output → named brief read → successful start
transition → concrete work`, with normal prerequisite reads allowed. The
work action needs its own successful result/effect, not merely a proposed
tool call. Define when input counting stops so later verdict/housekeeping
messages cannot retroactively fail the completed interval.
The literal “any row-specific text” context rule needs an exception for
the authorized brief/task data discovered during the test; otherwise the
task itself fails the audit. `git status` at two endpoints does not detect
an edit made and reverted between them. Record content hashes and bound
the no-coaching claim to the observed interval under the cooperative
no-external-edits rule. Jason's observation remains the final gate.
**Negative controls:** echo-only op id; nonzero command result; helper's
earlier op reused by the seat; resumed/forked session; wrong branch of the
session tree; brief never read; work command failed. Manual review suffices;
no checker package is required.
### T7 — Medium: unverified PIDs still qualify as a full liveness pass
**Where:** 8.10.
The display correctly says pid-present is unverified, but the full-pass
predicate allows every owner to be pid-present without any verified process
identity. A reused PID can therefore produce “full pass” although the
brief required a live owner registration. This recreates the acceptance
gap in more honest display wording.
**Required revision:** either call this a reduced registration/PID-presence
check and obtain the designated reduced-gate acceptance, or retain
incomplete liveness and do not issue a full pass. No start-time producer
or schema expansion is needed. Null/unknown PID needs a category and cannot
be converted to verified liveness. Keep the approved 12-call Gitea budget;
it is unrelated to this finding.
The age-unknown legacy case similarly needs incomplete coverage reporting
if it prevents deciding whether a required row is overdue. A report can
truthfully have zero known violations without meeting every full-pass gate.
### T8 — Medium: a few executable rules are still internally inconsistent
These are lead-level specification fixes, not new owner questions:
- **Ordinary add:** every add requires brief, but brief is privileged-only
“on add as well as afterwards.” Define the allowed initial fields/defaults
for an ordinary owner's add, or state that only privileged actors add.
- **Claim lifecycle:** specify claim creation/clearing for
in-review→in-progress, blocked→previousState and reassignment. Otherwise
“claimant” permissions can refer to the wrong owner or stale op.
- **Current briefs:** add validates a HEAD blob, but the fresh seat opens
a working path. `next`/start should refuse or visibly flag a working brief
that differs from the pinned blob; an optional verify --current against
HEAD alone does not establish what the seat reads.
- **Genesis bootstrap:** canonicalRoot exists only inside the file genesis
creates. Define the reviewed root input and special absence check for
first creation, without guessing a root or allowing a second genesis.
Resolve git-dir paths relative to the cwd actually used for the git call;
simplest is to run those queries explicitly from the discovered toplevel.
- **B scope:** 8.1 now lists only AGENTS.md, whereas Piece B also requires
seat context files that direct work to CURRENT.md to change. Keep those
named context edits and their snapshot verification in the active scope.
## What is now closed or honestly limited
| Earlier concern | Round-3 disposition |
|---|---|
| S1 owner-publication/reclaim race | Complete-record hard link and manual gated unlock address the core race. T3 specifies remaining classification/cleanup details. |
| S2 partial journal append | Removed by one validated fsynced temp JSON file. T1 is the narrower durability distinction; no journal repair verb requested. |
| S3 unexplained table drift | Genuine old-render hash versus unknown body and manual-only render is a sound boundary. JSON/Markdown mismatch remains detectable and intentional. |
| S4 tuple retry matching | Explicit persistent op IDs close the core ABA/tuple problem. T4 addresses receipt lookup ordering and multi-phase request events. |
| S5 shared git integration | Still open; T5 gives an exact prospective-tree procedure. |
| S6 multiple histories/replay | Canonical-root genesis, linked-worktree refusal and versioned replay are suitable for this scope. External git rollback remains a cooperative boundary (T2). |
| S7 impossible required dependency | Fixed by owner-approved prerequisites of either required status. Remaining field/claim details are T8. |
| S8 unsupported identity | Same-seat sessions deliberately share a claimant: an honest bounded limitation under Sage's ruling. T6 makes Gate G checkable; T7 prevents unsupported liveness acceptance. |
| S9 uncertain POST | No automatic retry is correct. Requesting, outcome events and manual negative resolution remain open (T4). |
| S10 candidate/brief evidence | Embedded manifest plus exact integration digest check is useful. It explicitly does not preserve uncommitted source bytes: review can become unrecoverable if those bytes vanish; that must block integration, not silently downgrade to a fresh candidate. T5/T8 bind verification to the actual source/brief. |
| S11 conflicting active sections | Section 8's precedence banner resolves the old-section conflict. This review does not relitigate superseded alternatives or accepted defaults. |
## Recommendation and evidence limits
Keep the ruled architecture. Before coding, close T1/T2/T4/T5 and make the
bounded checklist/matrix corrections in T3/T6/T7/T8. These are operational
and specification changes; they do not require Jason to choose a locking
algorithm or a new service. At the third review round, Sage should record
this remaining disposition explicitly rather than infer approval from the
absence of rejected earlier findings.
Investigation was read-only except this report. Failure schedules are
design analyses, not executed power-loss, git-interference or transport
tests against queue code (which does not exist yet). I inspected existing
process-identity helpers, API transport and local Pi transcript types; no
live session transcripts or credentials were read for this round.
Source pins: `packages/discord/src/journal.mjs`
`db33880f88dc2c7708015efecd0c6db604bc40387ea0dd6259d91f621a5b022c`;
`scripts/gitea-api.sh`
`033e6d5fdd4626fb0ca1c981b6d85eba961a4618a303faf2bb7b30ae024ed9a6`;
`scripts/agent-host-dev.sh`
`706f8e02fe0d8c18887d2e030f64f447a7db05badb3df3a20800c68ed5313687`.
Pi evidence: local `pi-coding-agent/dist/core/session-manager.d.ts` and
`pi-ai/dist/types.d.ts` under `node_modules/@earendil-works/`; bash tool
implementation under `pi-coding-agent/dist/core/tools/bash.js`.
## Delta: final specification 124b6f9e
Verified **before reading** the final section 8:
`124b6f9e250985d48654c6068ddfb0d82be6984f16da8700969281c4e06b0d26`.
Main review target remains
`cfdaa3fe4fa3fa6ef339f834a9814eb4a472ceac7c832c19bf955b61351ff21f`.
**Delta verdict: revise, for the same remaining technical findings.** The
recorded rulings are taken as authoritative for this review; no Q/J approval
is requested again. The only outstanding external input identified by the
final plan is seat tokens for D's live posting test.
- **J4:** Jason-only unpark to queued is explicit and appropriate: it
requires renewed briefing before work can start. Refusing required=true
on parked rows closes that conflicting state combination. Test unpark
actor refusal, queued re-entry and claim/review state cleanup. No new
authority finding against this ruling.
- **J5:** the new edge correctly refuses gateOwner=jason and requires
logged approval evidence for the allowed gate-owner/privileged path.
Define permission precedence against 8.8's blanket refusal for another
seat moving a claimed row; otherwise a legitimate non-owner gateOwner
could be rejected. Evidence must identify this candidate/round's approval,
and completion must settle the claim. These are the existing T8 lifecycle
details, not objections to delegated completion.
- **D:** fake-transport construction/testing reads no token; the live round
waits for explicit per-seat credentials. This is a clean build/live split.
It does not close T4: requesting can still outlive the CLI, and manual
not-posted resolution still needs a defined uncertainty disposition.
- **No repair/journal:** the final removal matches Sage's accepted design.
“Reviewed hand restore” improves recovery governance, but T1/T2 still
require reconciliation of uncommitted/externally effective operations
before a git restore discards their log. No repair verb is proposed here.
- **Other rulings:** accept the 12-call budget, root in genesis, link lock,
cooperative claims, narrowed closes with a logged reason, and E-before-D.
The reduced liveness gate is now explicitly accepted. T7 consequently
needs **no further approval**: label unverified PID-only coverage reduced
too, rather than full merely because no exempt seat exists. The accepted
reduced gate resolves permission to report limited coverage, not evidence
of verified liveness.
The final delta does not change the write/fsync sequence, shared-index
procedure or Gate G op-id test; T1/T2/T5/T6 remain applicable. T3's lock
classification and T8's ordinary-add, current-brief, genesis and B-context
details likewise remain. The core architecture is accepted as the target;
the revise verdict concerns these bounded implementation contracts.
@@ -0,0 +1,170 @@
# Queue as data — adversarial review, round 4
VERDICT: revise
Rocko for Sage, 2026-09-26. Plan SHA-256 verified before reading:
`14dccfd07325347b1905320ecc739f50d9729a509fbf2355ab52822567cee63f`.
Target: active section 8, based on `124b6f9e…0d26`, against round-three
T1–T8. Sage's confirmed choices in 8.15 are accepted. No policy decision
is reopened. This report is the only write for this review; no code,
runtime, token or git state was changed.
Most previous findings now have concrete dispositions. Four remaining
findings are below; F1/F2 are the main blockers. A small fifth consistency
fix is included for the builder. Failure schedules are design analysis,
not executed fault-injection tests against queue code that does not exist.
## 1. High — the HEAD/shared-index gap can make another normal commit roll back the queue
**Where:** 8.12 steps 6–7; remaining part of T5.
The private index prevents sweeping unrelated staged files into *this*
commit, and expected-old-value update-ref correctly detects an earlier
HEAD change. It does not protect the interval after the branch update.
**Concrete schedule:**
1. Shared index and HEAD contain queue revision 10. Another seat has staged
an unrelated source change, obeying “seats never stage queue files.”
2. Lead creates and publishes commit C with queue revision 12 using the
temporary index and update-ref. The shared index still holds revision 10.
3. Before step 7, the other seat commits its shared index. Its parent is C,
but its tree includes queue revision 10, unintentionally reverting the
queue. It never explicitly staged a queue change.
4. Lead's step 7 updates the shared index to revision 12, now against the
other seat's later HEAD. Or step 7 fails on index.lock and leaves the
rollback staged against C until manual intervention.
**Fix:** retain the approved private-index/exact-tree approach, but add an
explicit cooperative exclusive *git integration* interval covering HEAD
publication and shared-index reconciliation. All ordinary commit writers
must participate, not just queue writers. If reconciliation fails, leave a
clear maintenance hold against further commits until the shared index is
correctly rebased/reconciled against the actual HEAD. Recheck HEAD and the
queue entries before touching them; do not overwrite later staging using
only the initial guard. No queue lock need be held across tests/git.
**Acceptance:** pause immediately after update-ref, attempt an ordinary
commit of unrelated staged source, and prove the protocol prevents the
rollback. Also cover step-7 index-lock failure, changed HEAD, and later
staging of a queue path. Preserving unrelated index entries alone is not
enough; their relationship to HEAD matters.
## 2. Medium — unlocked reads can falsely diagnose lost history during a normal write
**Where:** 8.4 unlocked reads, 8.5 witness comparison; T1/T2 follow-through.
**Concrete schedule:** a reader loads queue revision 10. The writer
durably replaces queue.json and the witness with revision 11. The reader
then loads witness 11 and compares it to its earlier queue bytes. The
comparison says “history lost,” although no history was lost. Reversing
read order gives the opposite transient mixture: witness 10, queue 11.
Atomic replacement of each file does not make the pair an atomic read.
**Fix:** give reads a coherent snapshot protocol. Simplest is the existing
queue lock; alternatively perform bounded re-reads and validate that the
witness did not change across reading the queue, with a retry/busy result
for concurrent change. A read-only transient mismatch must not recommend
accept-history before rechecking a stable pair. Preserve the distinction
between an actual unconfirmed tail and a writer still publishing.
Also distinguish `verify --snapshot` from canonical witness-aware verify:
the former checks the supplied immutable pair; it cannot certify live
witness continuity and should not claim it does.
**Acceptance:** reader paused between queue/witness reads in both orders;
writer paused before and after witness rename; true rollback; deleted
witness. Normal writers must not provoke a history-reset diagnostic.
## 3. Medium — first commit and snapshot verification have no complete bootstrap path
**Where:** 8.2 genesis and 8.12 steps 3–5; residual T5/T8.
**Scenario:** genesis succeeds, but HEAD has no queue.json yet. The commit
script requires HEAD's committed queue log and requires the snapshot to
extend it. There is no declared empty-base/genesis exception. If queue
code itself has not been committed first, HEAD's archived queue tests and
validator also do not exist. The script cannot perform the first queue
commit as specified.
There is also an execution-context omission: `git archive H` extracted
into a temp directory has no git object database. Its snapshot verifier
cannot read `HEAD`/H's queue blob from that directory unless the caller
passes the base bytes or an explicit source repository. The snapshot
exception permits execution there, but does not supply those bytes.
**Fix:** specify the bootstrap sequence: approved queue implementation
committed first under normal source integration; then verified genesis
committed with a narrowly defined absent-base exception, requiring exactly
the reviewed genesis (and any explicitly allowed migration operations).
Supply the base queue blob and commit/tree identity to the isolated
validator, or explicitly read them from the canonical object database.
Do not resolve them from an ambient unrelated cwd.
The temporary index must be a valid index or a nonexistent file path;
`mktemp` creates an empty file, so specify initialization accordingly rather
than assuming every git operation accepts that as an index. These are
bounded implementation details, not a request for another commit feature.
**Acceptance:** fresh implementation-only HEAD, first genesis commit,
later extending commit, missing base in a non-bootstrap case, and archived
validator execution outside any repository.
## 4. Medium — no parentSession does not prove a fresh session
**Where:** 8.11 pins and negative controls; residual T6.
**Scenario:** a normal previously used Pi session is resumed. Its original
header still has no parentSession; that field describes a fork, not every
resume. The audit interval begins at Jason's new instruction, so prior
coaching/user turns can be outside the counted chain. The listed negative
control “resumed or forked session (parentSession present)” fails to cover
ordinary resume.
**Fix:** keep the new execution-trace checks, which are good. Separately
prove freshness from the actual launch: new session id/file created for
that launch, header timing consistent with it, and no earlier user/model
history, inherited compaction or branch-summary context. Pin these before
the instruction and after the observed work. Test an ordinary resumed
session whose header has no parentSession, not only a fork.
An input on an abandoned branch can still have coached the same agent
before it retraces a branch. For the deliberately short Gate G interval,
the conservative manual rule is to reject additional user input anywhere
in that session during the interval, while following the active ancestry
for the execution trace. Alternatively exclude branching in the demo.
Neither choice requires a checker package or new runtime identity.
## 5. Low — generated outcome IDs can violate the declared op length
**Where:** 8.6 and 8.9.
An external request op may be 80 characters, but appending `.outcome` makes
the system-generated op 88 characters. If log entries share the declared
op schema, a valid request can never record its outcome. Define separate
external/internal length limits or reserve the suffix budget in accepted
request IDs, and test both boundaries. The reserved suffix otherwise
provides a reasonable one-attempt/one-outcome identity scheme.
## T1–T8 disposition
| Prior finding | Round-four assessment |
|---|---|
| T1 durability | Substantively addressed: platform assumptions, distinct barriers, no success/POST after failed persistence, sync, and explicit power-loss evidence limits. Witness reads still need F2. |
| T2 git rollback | Addressed within the accepted cooperative model: branch pin, baseline check, witness, preservation/reconciliation and explicit accept-history with lost-range guarantee withdrawal. F2 prevents false diagnoses; F1 prevents ordinary integration from creating rollback. |
| T3 lock cleanup | Addressed: complete checked temp record, host-first classification, full record/inode release and same rules for gate cleanup. Retain manual quiescence when removing a classified stale gate. |
| T4 review uncertainty | Addressed at design level: requesting blocks across the row, no negative resolution, explicit duplicate-risk abandonment, immutable attempts, conflict handling, reserved outcome identity and move-to-review linkage. F5 is a schema consistency correction. Bound pre-send identity GET and resolution GET too, not just POST, when implementing. |
| T5 integration | Partly addressed: exact prospective bytes, isolated index, source-tree tests and expected-HEAD publication. F1 and F3 remain. |
| T6 Gate G | Execution trace, results, timing, successful work and cooperative context audit are substantially improved. Freshness/branch-input proof remains F4. |
| T7 coverage | Addressed: fail/incomplete/reduced-pass; no full liveness claim; unknown PID and legacy age are explicit. Approved reduced scope is respected. |
| T8 consistency | Ordinary-add fields, claim lifecycle/J5 precedence, pinned working briefs and B context-file scope are addressed. Genesis-to-first-commit is F3. |
The witness is treated as an approved check value, not challenged as a new
architecture. Same-seat concurrency and same-user history rewriting remain
the accepted limits; this review does not request authenticated authority.
The remaining fixes are bounded lead/builder decisions. No new Jason
ruling is needed to close them.
This review was completed while waiting for Darkwing's pinned #1509 6b
handoff. That review retains priority as soon as it arrives. No conclusion
about 6b or restart approval follows from this queue review.
@@ -0,0 +1,133 @@
# Queue as data — adversarial review, round 5
Verdict: **revise**. Rocko for Sage, 2026-09-26.
Plan hash verified before reading:
`889f25665b42f620a82051e916b017e26e2aeb5c5ef4a4549e327f796b1ae3d3`.
This supersedes 7d61f18d. Review target is active section 8, against round-4
report `fcb8933d515bcf98c509d17cb7c5bb384f2bce844b2b87eab6f83e67658efcff`.
Sage's choices and credential rulings are accepted. Two bounded fixes
remain; neither needs a new owner decision or architecture.
## Round-four disposition
| Finding | Assessment |
|---|---|
| F1 HEAD/shared-index gap | The installed, active pre-commit guard closes the ordinary-commit rollback schedule. Cooperative exclusions are explicit in 8.5. Its active status needs the additional validation in finding 2 below. |
| F2 incoherent reads | Resolved. Witness-first reading plus a locked recheck before adverse diagnosis avoids falsely declaring lost history during a normal publication. An ahead revision is only visible/unconfirmed. Snapshot verify explicitly does not certify live witness continuity. |
| F3 genesis/bootstrap | Resolved at plan level. Implementation-first commit, genesis-only first queue commit, base-absent exception, explicit base bytes from H and a nonexistent temporary-index path are concrete. |
| F4 freshness/branch coaching | The intended proof closes ordinary resume and abandoned-branch coaching, but the newly prescribed pre-instruction file pin cannot be obtained from pinned Pi. See finding 1. |
| F5 op-id length | Resolved. External maximum 72 plus reserved eight-character suffix fits internal maximum 80; boundaries have tests. |
## 1. Medium — Gate G requires evidence Pi has not written yet, and its first-parent rule rejects a fresh session
**Where:** 8.11 freshness and linear-file bullets.
The plan requires the new session file/header to be pinned before Jason's
instruction, containing only header and launch settings. Pinned Pi's
SessionManager creates these entries in memory but defers file creation
until an assistant message exists. Even appending the initial user message
does not create the file. The launcher does not pre-create it.
Separately, the session header has a session id, but is not the parent of
the first tree entry. That entry has parentId null. “Every entry's parentId
must be the previous entry's id” fails on a valid session immediately after
the header. Subsequent tree entries should form the requested linear chain.
**Executed evidence:** imported the repository's installed
`@earendil-works/pi-coding-agent/dist/core/session-manager.js`, created a
session in a temporary directory, appended model/thinking settings and a
user instruction, then a synthetic assistant message. Results:
- before instruction: session file absent;
- after instruction: session file absent;
- after assistant: file present;
- first nonheader entry parentId is null, not header.id.
Source: `_persist` at line 739 and `newSession` around line 650. This used
no model, live session or credentials; the temporary fixture was removed.
**Fix:** pin the pre-launch directory listing, launch snapshot, launch
arguments and start time before the instruction. Pin the completed session
file at cutoff (or once Pi first creates it, with a final cutoff pin).
Audit the resulting header timestamp, absence of parentSession and the
prefix before the instruction retrospectively against those pre-launch
receipts. Do not introduce a warm-up message or manually seed Pi's session
file. State that the first nonheader entry has parentId null and every
later tree entry points to its preceding tree entry. The header's id is
session identity, not an entry-chain node.
**Acceptance:** run the checklist on a real fresh session generated by the
pinned Pi; it must pass without a pre-instruction model turn. Retain the
ordinary-resume, prior-compaction and branching negative controls.
## 2. Medium — matching hook bytes does not prove the commit guard will run
**Where:** 8.12 installation and step-1 guard.
Installation writes mode 0755 and refuses core.hooksPath. Each subsequent
queue commit checks only that `.git/hooks/pre-commit` bytes match HEAD.
If the executable bit is lost during a hook copy/restore, the bytes still
match, but Git ignores the hook. Likewise a later core.hooksPath setting
can select a different location while the checked file remains unchanged.
No malicious edit or --no-verify flag is needed on the ordinary commit.
**Executed schedule in an isolated temporary repository:** HEAD/index
queue=10, unrelated source staged, private-index commit publishes queue=12
without reconciling the shared index. With the executable guard, plain
`git commit` refuses. Remove only the hook executable bit, preserving its
bytes; the same plain commit succeeds and HEAD queue becomes 10.
**Fix:** before publication, verify both expected bytes and that the hook
is executable and selected by the effective Git configuration/environment
used by ordinary committers. Recheck core.hooksPath at invocation, not only
installation. Refuse before publishing if the guard is inactive. Explicitly
include disabling/replacing hooks or overriding their selection among the
cooperative bypasses seats must not perform during integration. No software
check can prevent a deliberate later same-user bypass; that accepted trust
limit remains. Do not represent bytes alone as an active maintenance hold.
**Acceptance:** same-byte nonexecutable hook and a newly set alternate
hooksPath both make queue-commit refuse before update-ref. Keep the existing
ordinary-commit race tests with an active hook.
## What is fine, and the remaining bounds
The cooperative model is now stated honestly in 8.5: ordinary commits use
the guard; --no-verify is forbidden; merge, rebase, cherry-pick, revert and
am are lead operations because the guard does not protect them. These are
routine Git operations that bypass this protection, so the lead must apply
the recovery/integration discipline too. “Lead-only” is not an enforcement
mechanism. The witness detects lost history afterward; it cannot prevent
an uncooperative Git write. No stronger same-user security boundary is
requested here.
The private index, exact snapshot blobs and expected-old-HEAD publication
are sound for the intended ordinary source-commit workflow. commit-tree
intentionally skips hooks; its own prospective-tree checks and compare-and-
swap remain necessary. I independently reproduced the active guard refusing
an ordinary commit after publication. I did not rerun Filbert's claimed
full three-order race experiment; the remaining schedules were reviewed
from the specification.
Jarvis is an explicit authorized lead identity, not a fallback token. The
read-in-place rule does not authorize copies, token inspection by this
review, or credential changes. GET user must map the lead to expected login
jarvis, while preserving the queue actor as the lead; “seat's expected
login” in step 2 must be read with that exception. Include a fake-transport
lead success case and wrong-login refusal to prevent accidentally comparing
jarvis to sage. Stat ownership/mode and path checks are metadata checks;
the helper alone reads the token. A 403 is a recorded failed attempt under
the accepted endpoint assumption, never an automatic retry or scope upgrade.
The permission-scope question remains with Sage, as ruled.
No new defect was found in the uncertain-outcome protocol: durable intent
precedes network work, all three request types have bounded process groups,
and unresolved attempts are not resent. Abandonment explicitly withdraws
the at-most-one claim. Fake transport is appropriate for this build; it is
not evidence that a live token has comment permission.
Only this report was written in the repository. Scratch Git and Pi fixtures
were isolated and removed. No source/index edits, commit, live process
change, secret read or external request. The source fixes above are plan
clarifications for the builder; implementation acceptance remains necessary.
@@ -0,0 +1,63 @@
# Queue as data — adversarial review, round 6
Verdict: **approve** the plan. Rocko, 2026-09-26.
Verified target SHA-256 before reading:
`282fabbb8969510ae9e139a12082421ca3ffc395a90a800d936cc47abf6ab67a`.
This supersedes round-five target 889f2566 and answers report
`3b031a707555960dc69cc274fef6c39c0d8c0ebad539a5e8ae0c0c2545f4177e`.
Review covers the active specification, especially 8.11, 8.12, 8.5 and
8.9. No blocking findings remain from round five.
1. **G1 resolved — the freshness proof is now obtainable.** Pre-launch
listings, command line and UTC start time exist before Pi starts. The
later session/header audit no longer requires a file Pi has not created,
nor a warm-up message or manual session seeding. The header is correctly
outside the entry chain; null first parent and sequential later parents
match the pinned SessionManager behavior reproduced in round five.
Prefix restrictions and whole-file input audit still exclude ordinary
resume, inherited summaries and branch coaching. Positive controls now
complement the negative controls. The pre-instruction context hashes
remain required; moving the session-file pin to cutoff does not waive
those hashes. This is cooperative evidence with the previously accepted
helper/context-edit limits, not independent proof against an actor
rewriting all receipts.
2. **G2 resolved — activation is checked, not inferred from bytes.** The
plan checks file type, ownership, executability, bytes and hooksPath at
invocation and again before publication. The canary invokes Git's hook
mechanism using an isolated index, checks both acceptance and the
guard's specific refusal, and makes disabled/redirected hooks fail
before publishing. 8.5 explicitly forbids later mode/config/environment
overrides and honestly states the same-user limitation. Nothing here
claims to prevent a seat deliberately bypassing the protocol after a
check. Keeping that limit is appropriate for the accepted scope.
Independent scratch-repository check of the stated canary returned:
clean index 0; changed queue index 1 with the refusal line;
nonexecutable hook 1 on the clean index; redirected hooksPath 1 on the
clean index. The temporary repository was removed. This is validation
of the mechanism, not of queue-commit.sh, which has not been built.
3. **Lead identity note resolved.** 8.9 explicitly expects jarvis from
GET user when the lead posts, while retaining the lead as queue actor.
Fake-transport positive and wrong-login cases include the sage mismatch.
This closes the ambiguity without changing the authorized credential
rule. No token was opened or live API request made in this review.
Builder detail, nonblocking: step 1 currently lists the canary before the
bullet that captures H, although the canary reads its temporary index from
H. Capture H before constructing that canary, use that same H for the
snapshot/base work, and retain expected-old-value publication. A concurrent
HEAD change may cause a conservative refusal; it must never cause the
script to silently adopt a new untested base. For the genesis canary,
QUEUE.md is already a tracked queue entry even though queue.json is absent.
The previous round's F2 coherent reads, F3 genesis/base procedure and F5
op-length bounds remain resolved. No new contradiction in the reviewed
changes requires an owner ruling. Approval is for the design and its stated
acceptance tests; implementation still needs the fault-injection, Git-race,
transport and Gate G evidence specified in section 8.
Only this report was written in the repository. No source/index edit,
commit, push, live process change or credential access.
+9
View File
@@ -172,3 +172,12 @@ which stay with him. Each item names who decided it and what happened.
Either way it exits 1. The three nits ride in the build. The JSON records Either way it exits 1. The three nits ride in the build. The JSON records
which database file it read, so a fixture can't pass for Gate F evidence. which database file it read, so a fixture can't pass for Gate F evidence.
Darkwing builds. Filbert reviews the code, and Sage commits. Darkwing builds. Filbert reviews the code, and Sage commits.
15. **Queue as data (#1508) plan approved.** Rocko approved round 6
(282fabbb…, report 80cde839…). One ordering note goes to the builder:
capture H before the step-1 canary that reads from it. Build order is
the plan's section 1. Darkwing builds Gate F first, because row 6 closes
on it, then Piece A. Sage splits A into A1 (journal, lock, CLI, verify)
and A2 (migration, render, dispatch), each with its own Filbert review, so
each round stays small. C ships inside A1. Gate F's code goes ahead on
Filbert's verdict, without a separate look from Jason. The design calls
are the lead's (item 12).