Files

8.4 KiB

Row 135 round 2 review (Filbert): changes

Candidate: manifest sha256 50b28ebfa1d6b4917071bf38b77fdbd1025bef14e891a08f5fe830f4617a4352, which lists docs/prd/mosaic-stack.md 1cedf318... and docs/acceptance/314.md 85a015f8.... Patch agents/sage/work/queue-135/build.patch, commit 9f5273116 on base 7a2987cf5. This verdict covers round 2 only (sage-0503, request comment 28764). I had finished my round 1 analysis but did not post it; every round 1 finding below still applies, because round 2 changes only REQ-ROLE-5 and REQ-LAND-1.

One finding fails a test, so this is changes. The request said no test reads docs/prd. Two do.

Rebuild

  • A fresh worktree at 7a2987cf5 with git am of build.patch. Both manifest hashes matched and git diff --check was clean (2 files, +372 -4).
  • The added lines have no dash, curly-quote or control characters.
  • No commit from 7a2987cf5 to refactor HEAD touches either path.
  • Against my round 1 rebuild, the PRD diff is the REQ-ROLE-5 technical-domain clause and the new REQ-LAND-1 paragraph. The acceptance file is unchanged.

Blocking

B1. packages/tasks/tests/requirements.test.mjs fails on the candidate.

grep -rlF mosaic-stack.md packages/*/tests names packages/bus/tests/requirements.test.mjs and packages/tasks/tests/requirements.test.mjs. On the candidate:

  • tasks: pass 2, fail 1. "the list holds the PRD's requirement ids, in its order, at its version" fails 58 !== 43 at line 21. The same test also asserts [list.prd, list.version] is ['docs/prd/mosaic-stack.md', '1.4'].
  • bus: pass 3, fail 0.
  • Base control (round 1 worktree, base PRD restored): tasks 3/3. I put the candidate PRD back afterwards and its hash checked.

The 15 new ids are REQ-ROLE-5, REQ-ROLE-6, REQ-COS-2, REQ-ASSIST-3, REQ-DEC-5, REQ-DEC-6, REQ-WAIT-1 to REQ-WAIT-3, REQ-MSG-2, REQ-PROJ-1 to REQ-PROJ-4 and REQ-LAND-1. Every earlier PRD bump updated the list and the test in the same commit: 19fabe47c (1.4), 240d25518 (1.3), 7eb5ad0cb (1.2) and f7c8537b3 (1.1).

Fix: add the 15 ids in PRD order to packages/tasks/requirements.json with version 1.5, and change the test's 43 to 58 and '1.4' to '1.5'. Both files are outside the brief's owned files, so the brief needs them added.

The PRD findings below block too, because under decision 137 a finding on a file a test reads blocks. Each can be fixed in the same round.

F2. The source block misattributes two things.

  • It says the waits list came "from Jason's AGENTS.md". No source file says that. docs/plans/2026-10-15_q167-north-star-rows.md says the list is "as Mos gave it".
  • It gives "Any change to the list itself, and any grant of a listed action to a role, also goes to Jason" as Mos's reading of Q5. In north-star-rows that is Sage's preamble ("Also gated to Jason: ..."). Mos's Q5 there is "Q167 covers shrinking GATED_ONLY and the role grants through rows 135 and 139".

The other quotes match their sources exactly: Jason's added text (rows-r2 lines 16 to 30), the two Q167 ruling sentences, "Your decisions look good. Proceed." with task 314 comment 225, and the seven waits.

F3. REQ-PROJ-4: "Each human commit to the spec sends one notice". Row 143's pinned brief covers only commits made through row 148's save. A commit Jason makes with git, which his text asks for ("without an agent"), sends no notice. Either narrow the PRD to Console saves or re-pin 143 to cover any human commit.

F4. "git.push.protected covering force pushes on any branch is new in 1.5. Row 139 builds it." Row 139's pinned brief doesn't list it. The host already refuses non-fast-forward pushes (packages/seat/src/working.mjs, "non-fast-forward"). Either name it in 139's brief or say the host refusal covers it today.

F5. REQ-ROLE-5 versus row 149, and REQ-DEC-5's binding.

  • REQ-ROLE-5 says merge-gate "holds the merge and the land operation and no other grant". Row 137 records a landing as the action.allowed for git.merge.protected, so landing is the merge grant, not a second one. Raising needs no grant (no decision.raise in roles/*.json). The wording reads as two grants. Row 149's pinned brief says "holds only row 137's land op" and doesn't mention raising, so it needs a re-pin for the raise and for the round 2 technical domain.
  • I agree with the call that merge-gate must raise what it lands. #checkAuthority requires raised_by_role === s.role and the same thread, so a pm-raised decision could never be landed by merge-gate.
  • REQ-DEC-5 says the approval "binds to the decision and to the role instance". The code also binds the thread (this.#raisedThread(d) !== s.thread). The PRD should say so.

F6. REQ-PROJ-3 versus row 148. The PRD says "the files under docs/", where brief 148 says docs/*.md. It requires "a permissive license", which the brief doesn't. It says "The editor library is vendored", where the brief allows a textarea fallback with no library.

F7 (new in round 2). REQ-LAND-1's new check has no pinned row. "The land operation refuses a gated decision; the check ships with whichever of rows 137 and 139 lands second." Neither section in docs/plans/2026-10-15_q167-rows-r3.md (d5a9bf4c3) lists that refusal or a test for it. Row 137 is in progress and row 139 is queued. Row 139's tests name "a spec-covered merge going to the arbiter", which under the new text is exactly the decision that must never land if a role without the grant raises it. Re-pin whichever row will carry the check, with a test that an approved merge decision raised without the grant is refused at land. The PRD can't close this alone.

The rule itself holds against the code. #classification makes an ungranted action "gated", so "raised by a role without that grant" and "gated" pick out the same decisions. Since #checkAuthority binds the lander to the raiser, refusing a gated merge decision at land leaves landing only to a granted role. A suggestion, not a finding: refusing such a raise up front would spare the arbiter or Jason a decision that can't land.

Doc-only, follow-up (docs/acceptance/314.md)

grep -rlF 314.md packages/*/tests scripts/test-*.sh finds nothing, so these don't block.

  • A1. Step 2, "Open the file again at the old commit": the editor opens the current commit. The second tab has to be opened before the save.
  • A2. "Before the run" leaves out prerequisites:
    • security-reviewer and merge-gate instances added through chief's organization change, a live step needing Mos's go;
    • those instances listed in launch.instances, since row 152 refuses others;
    • arbiters.technical set to cto, which step 5 assumes.
  • A3. Step 8: Jason can't raise a decision himself, so "a raise citing the step 2 commit is refused stale-spec" isn't a step he can run. Reword it as something he observes, or drop it.
  • A4. Step 10 doesn't name row 141's command, which isn't built yet.

The other commands exist: mosaic project init|check <business> <project>, bus start <business> --pm and talk.

Nit, also non-blocking: the REQ-ROLE-5 edit leaves one line at 116 characters (line 209); the rest of the file wraps near 72.

What I checked and found correct

  • Check 2. REQ-DEC-2 is replaced in place. The version 1.5 tech notes keep the 1.0 text word for word, flattened from a list into a sentence.
  • Check 3.
    • REQ-WAIT-1 covers all seven waits.
    • git.push.protected covers force push and history rewrite on any branch.
    • New internet exposure is network.expose, and deploy stays a hard wait.
    • REQ-WAIT-2 makes a list change, or a grant of a hard wait, a hard wait.
  • Code claims that hold:
    • broker.mjs 975 and 976 refuse spec-unconfirmed and stale-spec.
    • project/src/read.mjs 69 confirms on the human author.
    • broker.mjs 1184 to 1186 route a cross-role decision to b.arbiters[domain], with the raiser choosing the domain. That lets merge-gate raise in technical as the round 2 REQ-ROLE-5 says.
    • #consumeAuthority refuses a second consume (decision-consumed).
    • Supersede uses the same instance and thread.
    • The staff request carries a count.
    • packages/project ships the five templates.
    • The CLI verbs named in the PRD exist.

What I ran and what I took from receipts

I ran, as single files on the round 2 candidate with Docker disabled and TMPDIR set to scratch:

Test file Result
tasks requirements 2 pass, 1 fail (58 !== 43)
bus requirements 3/3
tasks requirements, base PRD control (round 1 worktree) 3/3

I ran no mutants, no suite and no gate, and I took no slot. I took nothing from other seats' receipts.