Files
stack/docs/plans/2026-09-26_lead-decisions.md
T
jason.woltjeandClaude Opus 5.5 af4d3c0f6a docs(plans): lead decision 67, S3 starts before the Vikunja runbook half (sage)
The estate Vikunja (T236) won't serve by Jason's 10-09 run. S3 builds
against the recorded fake and a scratch container; its gate still needs
the live run. R20's PM and Lead match the slice 1 brief's staffing.
Merge plan step 2 no longer holds for T235 (brief c733ac92b).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 16:56:56 -05:00

76 KiB
Raw Blame History

Lead decisions, 2026-09-26

Written by Sage (lead). At 20:02Z Jason asked for my decision on the open items ("You are lead... Proactive movement and intelligent decisions"). I read that as his say-so for the push and the local operational calls below. It does not cover credentials, the ~/.mosaic restriction or the live Discord service, which stay with him. Each item names who decided it and what happened.

Decided and done

  1. Push refactor. Done at 20:03Z with the jarvis identity: origin/refactor 43d7574d → 42c08d52 (21e3e908, af4203ca, 0f5b7cb9, 42c08d52). Fast-forward only. All eight suites were green at 42c08d52.
  2. No merge into next. next is the old monolith: apps/, Woodpecker CI and the npm packages behind the estate mosaic CLI that the live fleet still runs. refactor is 172 commits ahead of it, and next has one commit refactor lacks (2101c9b4, a v1 git-tools fix, #1502). A merge replaces the default branch's content, may trigger CI and publishing, and could break the fleet before it is retired. Merge conditions: row 8 (fleet retirement) done, a CI definition for the new root, and 2101c9b4 either carried into v1/ or ruled moot. Until then refactor is the working branch and pushes stay fast-forward only.
  3. Control board restarted at 20:03:52Z so #1512's relaunch notice runs live. Old PID 3414098 (from 09-14) stopped on SIGTERM; new PID 3977979, log /tmp/control-board-20260926T200352Z.log, same flags (none), same port 7331. Before and after: 44 sessions, identical counts, seen state kept; relaunchedAt now appears in /api/board. The WebUI (PID 1266267) reads files from disk and needed no restart.

Decided, work under way

  1. Queue as data (#1508). Section 8 of Filbert's plan is the specification (sha256 124b6f9e…). Rocko reviews round 3.
    • Q1: Gate G reads "run scripts/mosaic queue next and do it".
    • Q2: Gate G runs on a Pi launcher (--fresh); next refuses without an identity.
    • Q3: the CLI never commits; the lead commits the queue files by explicit path after scripts/test-queue.sh.
    • Q4: D posts only with an explicit per-seat credential file and refuses the default. It is built and tested against a fake transport.
    • J1, J2, J4, J5: as proposed in section 7.2. J6: closes = issues, not narrowed without a logged reason. J8: E's budget is 12 Gitea calls at most, 0 with --no-issues. Reduced liveness gate: yes. E before D: yes.
    • J3 (every row has a brief), J7 (dropped), J9 (row 8 stub): decided earlier today.
    • No separate journal file. The log lives inside queue.json, written by temp file, fsync, rename and a directory fsync. The lock is link() of a complete record, with no automatic reclaim.
  2. Gate F waits for a T3 source. The ledger's Table 2 reads only Pi session logs. Filbert confirmed no Pi log carries T3 traffic, so the Human column cannot see T3 seats. Darkwing briefs a read-only T3 thread source after the #1509 engine fixes. When it exists, Sage picks Filbert's Gate F item and Jason sends nothing.
  3. Gate E "all seats" means every seat that registers on the board. T3 threads are listed as not covered until they carry identity.
  4. Sage launch files. Dewey reviewed them (revise, small). Sage made the revisions: sage is added to the launcher test, the README is rewritten for the lead role, and the seat reads but never writes the old DYOR records under ~/.mosaic. It creates no new DYOR records until Jason names a location. Dewey re-reviews, then updates the other seats' persona files that still name Darkwing as lead.

Jason's rulings (walkthrough, 20:19Z to 20:31Z)

  • Seat tokens for piece D's live round. Jason ruled at 20:19Z: yes, in place. Piece D reads each seat's own Gitea token by path, ~/.mosaic/fleet/agents/<seat>/secrets/gitea-mosaicstack-<seat>.token (0600), read-only. It makes no copies and changes nothing under ~/.mosaic. Sage's Gitea calls use jarvis. Darkwing and Dewey have write:repository, and Filbert and Rocko have write:issue only.
  • Discord connector restart. Jason ruled at 20:20Z: one restart, after Rocko approves 6b and it is committed, and row 25 goes live in the same restart. Steps: back up the binding to the Sage evidence directory, add the setspark key (keyFile ~/.config/setspark/keys/sage.json, never read), run discord.sh check, restart, then Jason's live check (one work item, one proposal approved by button).
  • Fleet retirement scope (row 8). Jason ruled at 20:21Z: dev seats only. orch-01, plan-01, rev-code-01, rev-code-02, code-be-01 and code-dogfood-01 get no new work and retire because the T3 seats cover them (Sage leads, Filbert plans, Rocko reviews, Darkwing and Dewey build). Jason stops each process himself or tells Sage to, one seat at a time. The other eight live fleet seats (jarvis, joe, huey, ricer, topher, velma, zane, resume) are outside row 8. Credentials stay in place (see piece D above). The ~/.mosaic restriction still stands.
  • DYOR records. Jason ruled at 20:23Z: DYOR work belongs in /mnt/storage/src/dyor-stack-v4/, a separate project from SetSpark. Sage has moved from DYOR to SetSpark tasks. Sage's SOUL, CONTEXT, README and DISCORD-USER files change to match, and that commit lands before the next Discord restart so the Discord Sage picks it up.
  • One live reply test in the WebUI. Passed. Jason sent "ping" to researcher at 20:10:57Z and "pong" came back at 20:11:06Z. /api/board showed it at 20:15:18Z. Dewey went through 30 board sends to repo Pi seats. 29 got a final answer in the same session file, and the one miss was a seat relaunched mid-turn. No second return defect was found. Jason confirmed at 20:31Z that "pong" appeared in the inspector without Refresh. The 09-13 report was about the missing thread view, which CHAT-02 builds.
  • skills/aws-*. Jason ruled at 20:25Z: add them to .git/info/exclude, a local ignore that is never committed. Done at 20:26Z. That covers the 20 aws-* directories and two more from the same 09-21 install, launch-with-aws and signing-in-to-aws. They stay where they are and no longer show in git status.
  • Row 5 CHAT-02 to 08. Jason ruled at 20:31Z: go on CHAT-02 only, at Dewey's brief 636b0fac (Filbert approved R4). CHAT-03 to 08 stay held, and Sage takes CHAT-03 back to Jason before anyone starts it. Order: the board Host and Origin guard (Rocko reviews), then the packages/conversation backend, then the Console. Filbert reviews the code, and Darkwing reviews the two board routes. CHAT-03 owns the Claude catalogue after B1.

Added later the same day

  1. CHAT-02 brief (Dewey, sha256 314da8b0…). Sage ruled D1 to D4 at about 20:18Z:

    • D1: the writer-claim record and R3-1 move to CHAT-03.
    • D2: Pi only in CHAT-02. The Claude catalogue refuses unsupported-harness until B1 has evidence. This narrows the plan's "both harnesses".
    • D3: packages/conversation is a library with no server. The board adds two read-only routes, and Darkwing reviews that change.
    • D4: Dewey writes the backend, then the Console. Filbert reviews.
    • D5 (the go on CHAT-02 to 08) is still Jason's.
  2. Discord connector restart held. Jason said to restart before 20:17Z. The unit runs from this checkout, and the tree holds Darkwing's uncommitted, unreviewed #1509 engine change (engine-pi.mjs, the new engineBusy). A restart now would load it. The only committed Discord change since the 18 September restart is 43d7574d (row 25), which does nothing until the binding gets a setspark key. So a restart today would change nothing except to pick up unreviewed code. Sage restarts once, after Rocko approves 6b and it is committed. If Jason wants row 25 live, the binding change goes in the same restart. discord.sh check passed at 20:17Z. The service was idle, with the last turn on 09-18. Rocko's 6b R1 verdict (about 20:34Z) was request changes. The high finding is that removing the grace lets delayed events from an old run resolve the next prompt (report agents/rocko/work/discord-engine-busy-r1-review-2026-09-26.md, 047dbd8f). Darkwing is on R2, and the restart stays held.

  3. Board guard live. Rocko approved Dewey's Host and Origin guard (de9ff942), and Sage committed it as d1629d61 after the eight suites, control-board (121/121) and webui (9/9) passed on an index export. It was pushed. The board restarted at 20:40:43Z: old PID 3977979 stopped on SIGTERM, new PID 288909, log /tmp/control-board-20260926T204043Z.log, the same flags and port 7331, 44 sessions before and after. Live checks: a foreign Host on /api/board returns 403, a foreign Origin on POST /api/reply returns 403, and the WebUI proxy's /api/board returns 200.

  4. Row 25 was never live. Before 20:56Z discord.sh check passed with the new setspark key, but it listed no SetSpark verbs. resolveToolRoots dropped tools.setspark, so pi never got the record verbs and the connector never built its SetSpark client. Passing the validated object through as-is would also fail, because the extension refuses its maxResponseBytes as an unknown key. Sage wrote the fix with a test that fails first (binding to extension round trip). The connector's client now uses the validated object, which keeps the response cap. The README now marks principal as required. The eight suites passed on an index export, and the check lists the eight verbs. Rocko reviews the staged diff (agents/sage/work/row25-setspark-fix.diff, 4dec1898…). The restart waits on that verdict and the commit.

  5. Gate F brief (Darkwing, 08959a05…). Sage ruled on the three questions Darkwing had marked for Jason:

    • Gate F is on by default. A missing DB exits 1 and names --no-t3.
    • The t3:unmapped row stays.
    • The 14 old Discord Bot headers stay as recorded and appear only in the JSON diagnostic.

    The 6a uppercase-class fix rides in Gate F. Filbert reviews the brief, and no code starts before the verdict.

  6. Discord restarted with row 25 live. Rocko approved the fix, which is committed and pushed as 6c06a6f3. The restart ran at 20:58:03Z: PID 890894 was replaced by 499064, the gateway was READY at 20:58:04Z, and pi has the SetSpark verbs. Jason's live check comes next.

  7. Gate F brief approved. Filbert approved R2 (e8300cb6…); his review is at bb02d8d3…. He corrected one of his own facts: a cleanly stopped T3 database in a read-only directory fails with 1544, as Darkwing measured. 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. Darkwing builds. Filbert reviews the code, and Sage commits.

  8. 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).

  9. Row 25 approvals, second fix and restart. Jason's live check found no Approve button. DEC-009's approvers had been stored as names, and the connector refused them. Sage fixed it so the model writes user names, the connector maps them to Discord ids, and no id reaches tool text. Rocko approved R3, and the fix is 20ea5a0b, pushed. Sage restarted the connector at 21:30:21Z, the second restart today. It is a local dev service, and Jason was waiting on the check. Two design calls:

    • A user id or name change with setspark on needs a restart, not a reload.
    • Tool text drops every Discord user id, including ids the binding doesn't know. The SetSpark service accepting free-text approvers is reported to Jason as a shared-signals gap. Mosaic doesn't change it.
  10. CHAT-02 backend committed and live. Filbert approved the code at R2 (3b14d66c…), and Darkwing approved the route changes at R2 (b9d92003…). Sage committed the nine pinned files with the packet, the evidence and the three reviews as a5beb6d9. The eight suites, conversation and control-board 153/153, and webui 9/9 passed on an index export. It was pushed. The board restarted at 21:36:29Z: PID 288909 stopped on SIGTERM, and the new PID is 1042473. The log is /tmp/control-board-20260926T213629Z.log, with the same flags and port 7331, and 44 sessions before and after. Live checks:

    • /api/conversations returns 200 with 19 entries (18 Pi available, 1 Claude unsupported, as D2 rules).
    • One conversation returns 200 with a 10-entry page.
    • An extra parameter returns 400, a foreign Host or Origin returns 403, and POST returns 405. The two nonblocking notes from Darkwing (the scan test checks keys, not status values, and it reads a fixed list of three files) go to Dewey as optional. The Console and its WebUI proxy allowlist are next.
  11. Gate F committed. Filbert approved Darkwing's build (manifest ba73a163, review e47ec6da), with the U+2028 reader fix as its own item. Sage committed the eleven paths as 136958c9 after the eight suites and ledger 47/47 passed on an index export. It was pushed. The live ledger had been refusing on HEAD because of that line split, and it reads again. Darkwing does Filbert's notes 1 to 3 as a small reviewed follow-up, then queue-as-data A1. Note 4 is in DEFERRED.

  12. Row 25 live check passed. Jason reported the button approval worked: DEC-010, request 2, approved at 21:38:58Z, confirmed in the approvals log. Jason named the SetSpark lead (T3 thread ac03938d), and Sage sent the approver validation request there. Mosaic needs no further change.

  13. Queue as data splits into A1 and A2. Filbert's plan (282fabbb) §1 left the split to Sage. A1 is the journal, lock, CLI and verify. A2 is migration, render and dispatch. A1 lands first under five conditions:

    • nothing runs against the canonical .git;
    • QUEUE.md, AGENTS.md and TOOLS.md stay unedited;
    • scripts/test-queue.sh is green at a HEAD with no queue.json;
    • H is recorded before the canary;
    • the fault layer is reachable only from tests. Darkwing's A1 packet (build.md a1125ebd, manifest 4319695a) reports all five met, and Filbert is reviewing it. When A1 lands, queue joins the suite list. Genesis and the hook install stay Sage's bootstrap steps 2 to 4, after A2.
  14. The SetSpark approver fix is Mosaic's, through a Sage subagent. Jason delegated the owner choice. The SetSpark lead can't touch shared-signals. A Sage subagent writes the change in shared-signals stack/api, Rocko reviews it, and Sage commits it to shared-signals main following that repo's AGENTS.md. The subagent stopped at the compatibility check. The strict discord: rule would refuse all 16 approvers on vault DEC-001 to DEC-008, which are sanctioned pending:<text> markers (RECORDS.md, the decision template, validate_vault.py), and that would block the cutover migration. Ruling: keep the records convention. An approver is either a Discord ID under the service's existing digit rule, shared with validate_vault.py so the two can't disagree, or a pending: marker. The status condition comes from validate_vault.py. Any other value gets a 422 with the value not echoed. Opening an approval request is refused while any approver is still pending. No data migration: the README gets a read-only query for bad stored rows. DEC-009 stays as stored. If it was more than a test record, a record_update through the Discord Sage writes its approvers as discord: IDs, which bumps proposal_version, and request 1 closes as stale on its next use. Deploying to VM 1022 is a host action and is not part of this; it goes to Jason when the commit is pushed.

  15. CHAT-03 chartered. Jason approved it on 2026-09-26. Dewey writes the brief, Filbert reviews it after A1, and Rocko does an adversarial pass on control races and recovery. The brief must settle D1 and R3-1 (item 8), the Claude catalogue after B1, and the board send that can become a Pi slash command. It names the CHAT-01/01C contracts by hash and keeps path authority clear of queue A1/A2 and the ledger. Following the plan page, Darkwing names the source author once the brief is approved. No real seat migration.

  16. Queue A1 review rulings. Filbert asked for changes (review 6933b885): all five conditions met, three small fixes R1 to R3. He left two questions for Sage.

    • The review issue: sorted issues make "the first issue" the lowest number, so a row for #1508 that also lists #1495 would post reviews on #1495. That is not the intent. move in-review refuses a row with no issues. A row with one issue uses it. A row with several needs --issue <n>, which must be one of the row's issues. Later rounds keep the previous round's issue unless --issue names another. That also fixes R2.
    • set piece and set gate are privileged only. 8.7's field table didn't list them, and the reason for the default is that piece and gate change what a row is, not how far along it is. Filbert's N13 (the nested node --test in test-foundation.sh and test-discord.sh) is added to the DEFERRED entry. It goes to Darkwing as a small reviewed item after the A1 delta, before A2.
  17. SetSpark approver fix landed in shared-signals. Rocko approved R2 (41e735f4, review c190814b) after R1 found that rows stored before the fix could still open requests, collect approvals, seal and be superseded. Sage reran the suites on the checkout (188 with a test database, 131 without, vault 45 PASS) and committed it to shared-signals main as cc74d92 under the Sage identity, following that repo's AGENTS.md. It was pushed. Correction to item 21's reasoning about legacy Accepted rows with more than 16 approvers: I called them unlikely because sealing one needed more than 16 live approvals. Rocko points out that the old coordinator import could seal from supplied evidence, so imported sealed rows need the same survey. The ruling stands: they stay refused, and a one-off correction goes to Jason if the README query finds any. Deploying to VM 1022 and running that query on production are host actions for Jason.

  18. CHAT-03 deviation V-1 accepted, with limits. Dewey's brief r2 (5c5b45a2) has no durable receipts. So an exact retry across a controller restart refuses stale-incarnation instead of returning the original receipt, which CHAT-01 line 145 and CHAT-01C line 212 promise. Sage accepts it for CHAT-03, because it replays nothing and fails closed. Three limits apply:

    • the client shows stale-incarnation as "outcome unknown, check the transcript" and never resends on its own;
    • a fixture proves that no retry after a restart reaches the engine;
    • CHAT-04's durable receipts must restore the contract behavior, and V-1 closes only then. CHAT-04's brief lists it as required. Rocko's R2 on the same brief (07b938fb) requests one change: an idle slot with empty clears does not prove an interrupted turn. Dewey separates receipt settlement from the stop proof in r3.
  19. Queue A1 committed. A2 starts. Filbert approved r1 (e464be6c). He agrees with Darkwing's refusal of a later round whose kept issue has left the row until --issue names one; that detail belongs with item 23. Filbert's r1 notes all go into A2 before genesis, as Darkwing proposed (carry-forward b2a738f0): P1, the unguarded release on the gate paths, with a test; P2, each round records its own issue, which changes the round schema; P3, unlock returns the result and the warning separately. N13-a, having the check apply the patch instead of copying the suites, won't be done: the approval pins the patch and the suite hashes, and Filbert applied the patch himself. Darkwing starts A2 now.

  20. Goals review, and the SetSpark deploy decided. Jason asked Sage to decide instead of asking him. The SetSpark approver fix (cc74d92) deploys. Sage handed the deploy and the read-only production survey to the shared-signals stack operator seat (T3 thread 12fe8cda), which follows that repo's rules and host holds. Sage does not touch VM 1022. Jason also asked whether the north star and goals need a review. They do. The ledger shows human messages per closed issue at 47.7, then 33.0, against a goal of under 10, and one issue closed last week. See docs/plans/2026-09-27_goals-review.md. In effect now:

    • CHAT-03 source work waits for a rescope against Gate E;
    • briefs get two review rounds, then scope is cut;
    • work for other repositories goes to their own seats;
    • the ledger runs every Monday. Jason ratifies the north star sentence and the goal order.
  21. SetSpark deploy result and DEC-009. The operations seat deployed cc74d92 to VM 1022 at 00:23Z on 2026-09-27 and verified it (hash, health, tunnel). The survey found one bad row, DEC-009 (Proposed), and no Accepted decision over 16 approvers, so Jason has no correction to make. DEC-009 stays as stored. It was the live-check record from item 16. The fixed service refuses to approve it, and correcting it would change production data for no gain. If someone wants it approved, a record_update through the Discord Sage writes discord: approvers and request 1 closes as stale. The deploy also recreated caddy through depends_on, about 20 s of edge downtime. I suggested --no-deps setspark-api to the operations seat. The procedure is theirs to change.

  22. Open items closed (goal 1). Jason said on 2026-09-27 that Sage had been distracted from mosaic-stack. Sage closed what the evidence supports:

    • #1511 closed. af4203ca is pushed, Filbert approved R2, and Jason confirmed the live display on 2026-09-15.
    • #1503 closed. D-001's MVP was one page of running Pi sessions with a waiting-on-Jason flag. Gate A passed, and the attention status fix is operator-accepted (row 22). Cross-harness board work is Gate E's.
    • Row 25 is done (item 19). Row 23 is done on its live write with web calls recorded. Its outside-root refusal rests on the offline suite.
    • Row 24 is done without a live use. The Discord Sage has never called commit or push. Records now go through row 25, and SetSpark cutover freezes vault/, so another Discord check from Jason isn't worth asking for. First real use is the check, and a failure opens a new issue.
    • #1509 closed. Gate H passed on 2026-09-13, and rows 14 to 25 are done. Its gaps stay in DEFERRED.
    • Row 6 closed, and Gate F is recorded as not passed. The ledger counts 2 human messages in Filbert's T3 thread during #1512's life. One is Jason's 09-26 takeover message. The item's first 11 days also predate the T3 source, so a zero was never provable. Gate G (row 9) tests the same thing on the queue, so it carries the test and Gate F isn't rerun. Rows 9 to 13 no longer wait on row 6. Still open: #1507 (Gate E, row 5) and #1508 (Gate G, A2 in progress).
  23. CHAT-03 rescoped against Gate E. Dewey's r3 (BRIEF.md 2c5be6b4, 1,527 lines; packet e197b882, "Gate E map") marks each section for Gate E. Rulings:

    • Goal: option (a). A seat bound to the Console runs without the goal extension, and Jason drives its turns. Goal continuation is a CHAT-06 item. Options (b) and (c) are refused: (b) is new machinery, and (c) makes interrupt useless. A launch without the Console keeps goal as it does today. The change is one launch flag and is reversible.
    • Cut from CHAT-03: §7 Pi native dialogs, §5 H5–H8 on Pi dialogs, C-1, C-2 and C-4. No repository Pi seat raises dialogs, and the interim rule already counts unknown events.
    • §2's idle drift check moves to CHAT-07. The live-session guard stays and keeps CHAT-03 off real sessions until CHAT-07 lifts it.
    • C-5 moves to CHAT-04 with its own contract review. CHAT-04 comes before Gate E anyway. Without C-5, an interrupt that races a completion ends in a force stop, which costs time but is safe.
    • C-3 only if B1 finds a gap. I3 (a recording that calls a model or reads Claude auth) still needs Jason's go. Sage asks when B1 is next, not before.
    • Filbert and Rocko review r3 only on the sections Gate E needs. A finding in a cut section is not blocking. After r3, Dewey removes the cut sections instead of rewording them.
  24. CHAT-03 seal: no explicit extensions. Rocko's r3 pass (report 19e3fcff) closed his R2 blocker and found one new one in the retained seal. An explicit extension can import a helper outside its hashed tree, and the helper can change after review with every hash still passing. Ruling: take his first cut. A Console-bound seat loads no explicit extensions. It launches with --no-extensions and no --extension, and binding refuses otherwise. Goal was the only explicit extension any repository seat loads (scripts/agent-host-dev.sh line 137), and decision 30 already turns it off for bound seats, so nothing is lost. The seal covers only built-in code tied to the pinned Pi artifact. Reviewed extensions come back with goal in CHAT-06, which must pin their executable dependencies. No dependency crawler. Rocko's nonblocking note goes to the build: no-turn fence cleanup must not undo a concurrent force-stop, overlap or revocation fence. No round 4.

  25. CHAT-03 r3 closes. Filbert approved r3 on the sections Gate E keeps (review 48447592), with no blocking finding. Rocko's one blocker is closed by item 31. Two notes are rulings for the edit:

    • n1: pi runs dist/bundle, not the dist/core and dist/extensions files the brief pins. The seal pins the package-lock.json integrity of @earendil-works/pi-coding-agent 0.85.1 (sha512), which covers the whole tarball. There's no hand-made bundle manifest.
    • n2: Pi's own clear emits a queue_update before the clear response. O5 counts it, and a fixture proves that an ordinary Interrupt doesn't end uncertain because of it. Dewey makes one edit: remove the sections cut by item 30, apply items 31 and 32, and add Rocko's fence note to the build. Filbert checks that the diff only does that. That's a scope check, not a review round. Then Sage pins the hash, and CHAT-03 is ready for a source author.
  26. CHAT-03 brief pinned. Filbert's scope check passed. The final agents/dewey/work/chat-03/BRIEF.md (sha256 1ef15ac0…, 1,451 lines, down from 1,527) differs from r3 (2c5be6b4) only by items 30 to 32 and what follows from them. Dewey's diff c6bd1f1e matched Filbert's own regeneration. His two observations are accepted as written. The P3 rule disables every Pi dialog, which is wider than CHAT-01, but no dialog can reach the controller without explicit extensions. Sage committed the brief, the earlier rounds and the six review reports. Sage names the source author after queue A2 lands, so Darkwing isn't split between them. The code may not start before then.

  27. CHAT-03 build note, Filbert n3. Under items 30 and 31, only the controller's abort can produce aborted. If the code ever sees aborted with no stop in progress, it treats it as an overlap signal. It does not invent a stop link. This goes into the build and its tests, and the pinned brief stays as it is.

  28. Queue A2 lands, then genesis. Filbert approved A2 round 1 with no blocking finding (f167b85e). Sage commits it with both patches, then runs the dry run's order on the canonical checkout: map check, install the hook, genesis, queue-commit.sh --genesis, then these logged ops:

    • assign 10 sage (map choice 2).
    • Row 13's gate becomes "rows 9 to 12 done, then a Monday ledger run with zero queue violations, or every one moved the same day". This is Filbert's n1. after gates only the start of a row, so it can't stop row 13 going done before Gate G. The gate text does, and Sage owns that gate. It also drops the stale 2026-09-21 date. Map choices 1 to 8 are accepted as written. Row 16 stays waiting-on-jason at genesis. #1510 is checked after genesis, through the queue. Filbert's n2 (point the header at the goals review, reword AGENTS.md's priority line) is row 10's work, now Sage's. n3 (a README line saying queue-commit.sh calls cli.mjs directly) rides with row 10.
  29. Genesis done, row 10 landed, #1510 stays with Jason, CHAT-03 author. Genesis is 3377b877 (rev 0, 30 rows). Item 35's two ops are in 42f3f2d9. Row 10's source is 5efe28ab: the AGENTS.md cadence, pointer and recovery rule name scripts/mosaic queue next <seat> and the goals review, the six seat CONTEXT files run the queue instead of reading CURRENT.md, and the queue README carries Filbert's n3. The QUEUE.md header now points at the goals review (n2, eae341d3). Row 10 waits on Gate G, which is Jason's gate.

    • #1510 (row 16). Its five acceptance items are met, and the source is in af4203ca and d41f81aa, pushed. The queue lets Sage close a waiting-on-jason row only by citing Jason's approval. His 2026-09-26 ruling uses the team #1510 built, but it doesn't accept the issue, so citing it would stretch his words. Row 16 stays with him and needs one word.
    • CHAT-03 source author: Dewey. Dewey owns row 5 and wrote the pinned brief (1ef15ac0). Filbert reviews first, and Rocko reviews the controller binding and the extension-load refusal (item 31). Two rounds, as item 27 sets. Darkwing stays on queue rows 12 and 13, so goal 2 isn't split.
    • Export recipe after genesis. An index export isn't the canonical root, so test-queue.sh's two live checks refuse there (24 pass, 2 fail). The canonical checkout passes 26/26. This goes to DEFERRED for Darkwing. Until it is fixed, read the queue suite's result in the canonical checkout.
  30. Gitea helper reads the per-seat raw token files (row 12). Darkwing found that scripts/gitea-api.sh accepts only the JSON credential file, while the per-seat files Jason ruled on hold a raw token (checked with stat only: 41 bytes for four seats, 40 for jarvis, all 0600). Without a change every live Piece D attempt fails at the pre-send GET user. Sage says yes to a separate helper patch with the D candidate, on these terms:

    • The JSON path is unchanged. The raw path applies only when the file isn't JSON.
    • The raw path accepts exactly one line of token characters, with an optional trailing newline, and refuses anything else before any request.
    • On the raw path the base URL is fixed at https://git.mosaicstack.dev, with no override.
    • The file checks stay (regular file, no symlink, no group or other bits). The token goes only through the curl config stream. Tests use stubs and read no real token.
    • A seat uses only its own file.
    • Rocko reviews the patch as well as Filbert. This doesn't widen access: each seat already has the token by Jason's ruling, and the change only lets the helper read the file's actual format. JSON wrapper files would need writes under ~/.mosaic, which are forbidden.
  31. Gitea helper round 2: one blocker left, fixed under a lead check. Rocko closed the round 1 blocker (config is built and checked before curl starts) on helper.patch dd9e38bf. The round 2 report (2096b0a3) has one new blocker: CFG keeps an export attribute inherited from the caller, so an exported CFG in the environment carries the secret config into curl and the body-file utilities. The fix is Rocko's: export -n CFG right after the checked assignment, before any child starts, plus inherited-CFG regressions for GET and POST with raw and JSON dummy credentials, and a mutation that removes the line and must fail them. Item 27 says scope is cut rather than opening round 3, and Sage told Darkwing the raw path would be cut. Sage departs from that here. The fix is one line and the reviewer has specified it and its test, while cutting the raw path would stall Piece D's live round and Gate G. Darkwing applies it. Sage checks it with Rocko's reproducer and the ledger tests. That is a lead check, not a review round. If the check fails, the raw path is cut.

  32. Lead check passed on helper.patch 48edd46b (decision 38), and C1 goes into D.

    • export -n CFG follows the checked assignment directly. Darkwing also found SHELLOPTS=allexport as a second route to the same leak, and the same line closes it.
    • Sage checked it with dummy credentials and stub curl and git: raw and JSON files, GET and POST, with an exported CFG, with SHELLOPTS=allexport, and with both. On the patch all 12 cases keep the token out of curl's environment, argv, stdout and stderr, and the token appears only in the config stream. With the export -n line removed, all 12 leak it into curl's environment.
    • Ledger tests pass 58/58 on the patch alone at 8efc0ff3. The helper ships with the D commit, together with Rocko's two reports (e896192f, 2096b0a3).
    • Filbert's D round 1 (a2dc2302) raised C1: on a comment round, in-review→waiting-on-jason needed no reviewer approvals, so an owner could move a Jason-gated row past its reviewers. It is fixed in D, not deferred: that move gets the approval and unresolved checks of in-review→done, plus a regression. No semantics-2 entry is logged yet, so the fix is cheap now.
    • Filbert's plan correction (293747cd) goes into the D commit. Round 2 of D is Filbert's.
  33. Piece E (row 13): Darkwing's four questions (build.md "For Sage", 2026-09-27).

    • Full open-issue page. mosaicstack/stack has 50 or more open issues, so under 8.10's rule every run is incomplete. Relaxed. A full page makes the queue issue checks incomplete only when some wanted issue is left without a known state. Truncation can't hide a violation. Since 8.10, an issue absent from the open list is looked up, and closed needs positive evidence. A truncated issue is either looked up or left unknown (budget), and unknown (budget) already makes the run incomplete. Darkwing adds the change and a test to E before the commit, and Filbert's round covers it. Filbert amends 8.10's budget table, as with C1.
    • Row 7's brief. Sage re-pins row 7 with set 7 brief in the queue commit after E lands. That keeps verify --current clean.
    • Row 7 stays for now. This amends Q9. Q9 had row 7 leaving the queue. Row 7's gate belongs to Jason, and closing a Jason-gated row needs his cited approval, so the lead can't retire it alone. E puts the weekly routine in the ledger README anyway. Row 7 retires when Jason closes it.
    • Age from 2026-09-28. The rule stays. Rows 9, 10 and 11 wait on Jason, and row 13 can't finish before them. Monday's run will list all four as age violations. That's true, and it points at Gate G. Sage asks Jason for Gate G rather than weakening the check.
    • T3 seats. The weekly run passes --unsupported-runtime for each T3 seat that owns an active row, and the output prints it. That matches 8.10's exempt class.
  34. Gate G is set up, not run (2026-09-28). The gate needs a fresh seat launch at a terminal. agents/<seat>/launch.sh --fresh opens a TUI, and Sage can't drive one from T3. Jason watches the run under the brief. So Sage prepared the rest.

    • Row 31 is a real piece for Rocko, whose queue was empty: refuse a row's owner as its reviewer (Filbert's n2). Its brief was committed at 92aeeeef, and the row is briefed (rev 26, c989dfe9). queue next rocko now answers "start row 31".
    • Rocko's launcher exports MOSAIC_AGENT_NAME=rocko, so a bare mosaic queue next names the seat.
    • Jason's part is agents/rocko/launch.sh --fresh, then the one sentence, then a pass or fail line on #1508.
    • Row 31 is also a brief Jason can accept toward row 11's gate.
    • Correction: Sage ran agents/rocko/launch.sh --help to read its usage. The launcher ignores --help and registered rocko before printing usage. That rewrote ~/.mosaic-dev/seats/repo/rocko/registration.json with a pid that has since exited. Rocko owns no active row, so the ledger doesn't read it, and the next launch rewrites it.
    • The Monday ledger (2026-09-28, #1508 comment 26592) failed on age for rows 9, 10, 11 and 13, as decision 40 expected.
  35. Jason's rulings on seven unlock questions (2026-10-04). Sage asked in thread 1ef1e4f8. Answers and what followed:

    1. Gate G: "pass". Rows 9 and 10 are done (revs 32, 33). Verdict posted on #1508 as comment 26621.
    2. Row 31's brief: "accepted". That's brief 1 of the 2 row 11 needs (note, rev 35).
    3. Credentials: "use a different seat. Rocko doesn't have the creds or launch." Sage posted row 31's request as jarvis (rev 30), and it went up as comment 26620 (rev 31). A rocko token file does exist under ~/.mosaic/fleet/agents/rocko/secrets/ (checked with stat only, per the 2026-09-26 ruling), but Sage doesn't use it. Rocko's current seat is treated as having no credentials and no launch. Row 31's closes narrowed to none (rev 36), so finishing that row won't close #1508.
    4. Sage may launch seats: "yes". The limits Sage proposed and Jason accepted: the mosaic-stack project only; only seats already in agents/README.md, with the harness and model listed there; at most two sessions Sage launched running at once; each launch logged in SESSIONS; Jason can revoke it with one word. This grants no new seats, roles, credentials, push, merge or deployment.
    5. #1510: "yes". Row 16 is done (rev 34). Sage closed #1510 as jarvis with comment 26622.
    6. Paperclip: "Not loving the operations." Not adopted. The instance on 127.0.0.1:3170 that Jason tested stays up as a reference until he says otherwise. Nothing is built on it.
    7. Row 7's metric: "We are chasing a metric that may be useless. A good starting point perhaps." Row 7 keeps running as a baseline, and its gate stays Jason's. Sage owes a proposal for better guideposts, made in a brief and not in the ledger first. Queue ops ran on the working tree's queue.mjs, which carries Rocko's unreviewed row 31 change. That change only adds refusals, and none of these ops hit them.
  36. Jason's first rulings on the foundation direction (2026-10-04). Sage proposed docs/plans/2026-10-04_foundation-direction.md after Jason rejected the KPI line of work. Jason's answers in thread 1ef1e4f8:

    1. Ratifying the direction: "Where are these located? I will review. Or you grill me with intelligent suggestions." Not ratified yet. Sage put the choices inside it to him as lettered questions.
    2. Vikunja: "integrate". Mosaic Stack reaches Vikunja through its API behind a task interface. No Vikunja code enters the repository.
    3. Row 32 (ledger guideposts): "advise or grill me". Sage advised parking it. Only Jason parks, so the row stays queued until he says so.
    4. First roles: "agreed". PM, CTO, coder and reviewer for Mosaic Stack. The role schema can declare CEO, CFO and the others, but none is instantiated until a business needs it. Jason also named Pocket ID as a candidate for integrated SSO ("working very well for SSO for my SetSpark project"). Facts Sage checked: Pocket ID is an OpenID Connect provider with passkey-only sign-in, under the BSD 2-Clause license. That makes it a fit for people signing in. Agents can't use passkeys, so roles still need their own service tokens. Recorded as a candidate, not adopted. On measuring, Jason: "Good metrics. We can measure against that. The failures cause introspection and repair." That refers to slice 1's logged events taking the place of hand tagging.
  37. Jason ratifies the foundation direction (2026-10-04). Answers to Sage's seven lettered questions, thread 1ef1e4f8:

    • "park 32". Row 32 parked, rev 55, op jason-32-park-20261004, run by Sage on Jason's word. The queue closes notes on a parked row, so this entry is the citation.
    1. "A". The working north star sentence is the one in the goals page's 2026-10-04 section. The PRDY interview turns it into the PRD.
    2. "you choose". Sage chose A: slice 1 becomes goal 1, and goals 2 to 4 fold into it. Goals 2 and 3 are close to done, and their remaining rows (5, 11, 13) are slice work anyway. Holding the slice for them would repeat the problem Jason named.
    3. "A". Mosaic Stack builds itself on slice 1.
    4. "A". A CLI first, with the WebUI reading the same data. CHAT-03 continues.
    5. "A. Always allow the user to use an existing instance, or use the embedded version on installation though." The default for Mosaic Stack's own work is a dedicated local Vikunja. The installer must offer two choices: point at an existing Vikunja, or deploy the bundled one. "Embedded" means a bundled Vikunja deployment that the stack installs and talks to over its API. It doesn't mean Vikunja source in the repository (decision 43, item 2).
    6. "A". Design for Pocket ID now and wire it in after slice 1. People sign in through Pocket ID. Agents use service tokens per role.
    7. "B". Decisions and messages go in SQLite. Run records stay write-once files (canon invariant 5). The decision and message tables are append-only: a correction is a new row, never an update. That keeps invariant 9's rule for logs.
  38. PRDY round 1 answers and more seat sessions (2026-10-04). Jason, thread 1ef1e4f8. The answers fill docs/prd/mosaic-stack.md (draft 0.1):

    1. Users: "D". Jason alone for now, built so outside users can install it later.
    2. Problems, in order: "A, C, B". Admin falls on Jason; he can't see what agents are doing or what's waiting on him; agents drift.
    3. Hard limits: "all five". No spend without Jason. No speaking externally as Jason without approval. No founder credentials in agents. Not a multi-tenant SaaS in v1. It wraps the harnesses and doesn't replace them.
    4. Hosting: "A first". Self-hosted, with cloud not ruled out later.
    5. v1 done: "A". Mosaic Stack builds pieces of itself from one-sentence CLI requests, five in a row, with only gated decisions reaching Jason and a full trail. Session limit: "You are now permitted to run more than 2 agent sessions. ... Opus 5.5 and Sonnet 5.5 should be able to run as many as 4 sessions each." This replaces decision 42's limit of two. Sage may run up to 4 Opus 5.5 and up to 4 Sonnet 5.5 roster-seat sessions at once, in T3, in the mosaic-stack project. Sage's own thread isn't counted. Every other limit from decision 42 stands: roster seats only, each launch logged in SESSIONS, revocable with one word, and no new roles, credentials, push or merge. The roster lists Pi for Darkwing, Dewey, Filbert and Researcher, but their T3 sessions run on Claude Code. Sage reads Jason's ruling as covering those T3 Claude sessions. The first launch under it is a Researcher thread on Sonnet 5.5 (9bac0794), researching Vikunja and Pocket ID.
  39. Sage's rulings on the slice 1 data model's open questions (2026-10-04). Source: Darkwing's note agents/darkwing/work/slice1-data-model-2026-10-04.md (sha256 948b94ce…), section 6.

    • 6.1, business files: accepted. A business file at ~/.config/mosaic-dev/businesses/<id>.json is a separate layer, not a second system config. The user writes it, the stack never writes it, and a missing or invalid file fails closed. config.json doesn't change. Invariant 2 holds as written.
    • 6.2, claims and events in bus.sqlite: accepted. They fall under decision 44, item 7, with the same append-only rule.
    • 6.3, human resolution: accepted. Stack-launched agents reach the bus only through a broker that stamps role and run from the launch record. A human resolution comes only from a mosaic CLI session started outside any agent run. The brief will say plainly that today's T3 seats, running as the same user, are advisory, not a boundary.
    • 6.4, tamper evidence: accepted. Triggers plus a schema check at open. Hash chaining waits until a measure needs it.
    • 6.5, coder vs. the worker invariant: accepted. Role agents are a new kind of seat, launched with a role binding. Workers keep "no git, no credentials".
    • 6.6, the PM launching sessions: goes to Jason in PRDY round 3. It changes who starts work (relaunch constraint 4). Decisions 42 and 45 cover Sage launching T3 roster seats, not a product role.
    • 6.7, revoking a role: accepted. A revoke is gated in slice 1 and cites a resolved decision.
    • 6.8, Vikunja concurrency: accepted, provisionally. Compare, then write. Only the assigned role writes a task's mutable fields, and people's edits arrive as task.changed.external events. Revisit if Researcher finds Vikunja supports conditional updates. Also adopted from the note: credential scope is the hard boundary for gated actions, and harness hooks are logging plus early stops. The brief won't call hooks enforcement. A plain append-only rule isn't enough: INSERT OR REPLACE overwrote a row in the prototype despite UPDATE and DELETE triggers. Each table also needs a BEFORE INSERT guard, which the prototype verified.
  40. Sage's rulings on the meta-harness survey (2026-10-04). Source: Filbert's agents/filbert/work/meta-harness-survey-2026-10-04.md (sha256 05f83807…), section 8. The survey's finding: no harness's hook is a hard block on its own. Pi's tool_call hook fails closed. Claude Code's command hooks and Codex's hooks fail open. Nothing was run against a live harness. The survey's section 9 has a probe matrix that must pass before any build brief relies on a block.

    1. Pi gate extension: accepted. It enters through the CHAT-06 path (decision 31) as one digest-checked file. Until then Pi role seats get no hook.
    2. Brief wording: accepted. The hard layers are credential scope, the verbs refusing without a resolved decision, the tool ceiling and a container. Hooks are early refusal plus logging.
    3. No machine-wide /etc locks in slice 1. They would govern Jason's own sessions, which makes them a gated policy change.
    4. Host-seat --approve: the generator emits --no-approve and --system-prompt. A bounded follow-up for scripts/agent-host-dev.sh goes in DEFERRED.
    5. Claude credentials for isolated seats: a per-role setup token or an API key. Both are gated, so this goes to Jason at slice 1 step 7.
    6. Role credentials stay in the broker and never enter an agent's environment or files. The existing exposure of worker provider keys goes in DEFERRED.
    7. Build order: Pi, then Claude Code, then Codex.
  41. PRDY round 2 answers (2026-10-04). Jason, thread 1ef1e4f8. The answers fill PRD draft 0.2 (docs/prd/mosaic-stack.md), with requirement ids:

    1. Out of scope for v1: "all". That covers other businesses, credential minting, Codex, Pocket ID and SSO, and access from beyond localhost.
    2. "A". A gated decision reaches the CLI inbox, plus a Discord DM when it blocks work.
    3. "A". Blocking decisions arrive right away. Everything else goes into one daily digest.
    4. "A". Sage is PM and Darkwing is CTO for Mosaic Stack.
    5. "A". mosaic talks to an agent session the stack launches and owns, running Pi or Claude Code headless. T3 stays a development tool.
    6. "A". The PM launches role sessions within limits set in the business file: role instances only, 4 Opus and 4 Sonnet, each launch logged, revocable with one word. That settles open question 6.6 from decision 46. Researcher's report (agents/researcher/work/2026-10-04_vikunja-pocketid.md, sha256 fcfc970f…) was committed as a record with this entry. The PRD's technical considerations draw on it.
  42. Sage's rulings on slice 1 addendum A (2026-10-04). Source: Darkwing (CTO), agents/darkwing/work/slice1-data-model-addendum-2026-10-04.md (sha256 0b36acb0…). Where the addendum and the original note disagree, the addendum wins.

    • Vikunja token scopes cover whole route groups. So "one writing role per field" is enforced by broker verbs, not by tokens. That works only because agents never hold the tokens.
    • A1, coder push: accepted. The broker fetches the branch into a bare repository it owns and pushes from there with hooks off. Gitea branch protection stays the server-side line.
    • A2: no webhooks in slice 1. Poll every 30 seconds with a keyset cursor and reconcile hourly. That removes the allownonroutableips prerequisite.
    • 6.8 stands, with an ETag check on GET and a PATCH of only the owned fields. The brief will say the race window is still there.
    • A3: accepted. A task_snapshots table, decisions.blocking and the new event kinds. Darkwing extends the prototype before the brief.
    • A4: accepted. Researcher runs probes P1 to P7 against a scratch vikunja/vikunja:2.7.0 container with SQLite, bound to 127.0.0.1, removed afterwards, test tokens only. P8 goes to whoever builds the broker.
    • A5: the one word stops new launches, and mosaic stop ends a running session. Sage reads Jason's "revocable with one word" that way. If he meant otherwise, he says so.
    • The PM's role.launch needs a launch block in the business file. Without that block the action is gated.
    • The PM moving from T3 to a session the stack launches is a named step in the slice 1 brief (REQ-CLI-2).
    • PRD wording for REQ-VAR-2 and REQ-TASK-1 adopted in draft 0.3, with REQ-TASK-2 updated for A2.
  43. Sage's rulings on the slice 1 prototype v2 (2026-10-04). Source: Darkwing (CTO), agents/darkwing/work/slice1-proto/proto-v2-notes.md (sha256 90ce5645…), schema-v2.sql (ffb7cf90…) and proto-v2.mjs (d428da74…). Sage reran proto-v2.mjs on Node 26.8.1 and got the same output as Darkwing's Node 26 run, apart from version lines. schema-v2.sql replaces schema.sql as the design the broker starts from.

    • A blocking decision must cite a task (trigger): accepted. Slice 1 has no blocking work outside a task. If one turns up, the broker files a task first.
    • launch.revoked and launch.restored carry no role and no run: accepted. An empty role is not proof of a human. The broker must write these only from the CLI path that runs outside any agent run (REQ-DEC-3). The slice 1 brief states that.
    • credential.* events name a service and a role instance: accepted.
    • The open-time digest covers every schema object: accepted. This check notices tampering, it doesn't prevent it, the same limit as the triggers.
    • The three views: accepted as demonstrations. Counting a person's edit in the same second as a broker write as external is the cautious side, and stays.
  44. Sage's rulings on the Vikunja probes (2026-10-04). Source: Researcher, agents/researcher/work/2026-10-04_vikunja-probes.md (sha256 ef0beec6…), probes P1 to P7 against a scratch vikunja/vikunja:2.7.0 (digest e2204a1c…), since removed. Where the probes and addendum A disagree, the probes win.

    • Token scopes: addendum A's example group names don't exist, and Vikunja refuses unknown groups with 400. Darkwing rewrites the scope map from the real route groups in addendum B.
    • Polling on updated misses bucket moves between columns that aren't done, bulk label sets and deletions. The hourly reconcile alone would leave a person's column move unseen for up to an hour. Darkwing proposes in addendum B how the 30-second poll catches moves and deletions too, for example by also listing the task ids in each bucket of the project's kanban view. At slice 1 scale that costs a few requests per poll.
    • Vikunja doesn't enforce If-Match. The broker compares before it writes and the race window stays, as 6.8 already says. The broker writes with PATCH of owned fields only, never PUT, which clears omitted fields. Labels change only through the single add and remove routes, never as a labels key in a PATCH body.
    • A 401 means either an expired token or one out of scope. The broker checks expires_at itself, both after minting (Vikunja accepts a past date) and before each use, then treats any 401 as a refusal and logs both possible causes.
  45. Sage's rulings on slice 1 addendum B (2026-10-04). Source: Darkwing (CTO), agents/darkwing/work/slice1-data-model-addendum-b-2026-10-04.md (sha256 14e747f5…). Darkwing checked each claim on a scratch Vikunja with the same image digest as the probes, since removed. Where B and addendum A disagree, B wins.

    • B1: yes. A read-only bot-<business>-sync, shared at permission 0, does every poll, reconcile and compare-read. Role tokens keep their write verbs plus tasks read_one. A bug in the poll path then can't write, and both the scope and the share would stop it. The install runbook gains one bot and one token.
    • The poll is two requests per project per tick: the open-task kanban listing and the updated cursor. The hourly reconcile still covers done-task deletions and label sets, comment edits and relation changes.
    • B2: reopening a task isn't an agent action in slice 1. A person reopens it, and the stack records that as an external change.
    • B3: section 5 becomes schema v3 in slice1-proto/ when the brief is written.
    • Section 7's unverified points join the brief's probe matrix as preconditions. The first is which labels GET /labels returns to a bot. Until that's settled, the business file lists label ids.
  46. PRDY round 3 answers (2026-10-04). Jason, thread 1ef1e4f8, "1A 2A 3A 4A 5A 7B".

    • 1A: Jason creates the slice 1 tokens by hand from a runbook Sage writes. Nothing in v1 mints them.
    • 2A: Gitea gets new bot users per role: pm-bot, cto-bot, coder-bot and reviewer-bot.
    • 3A: slice 1 agents run as Jason's OS user. The PRD names the broker as a rule they follow, not a wall. Containers come next.
    • 4A: the existing Discord connector (#1509) sends the DM for a blocking decision.
    • 5A: the daily digest arrives at 08:00 Central.
    • 7B: row 5's Gate E demonstration happens during the slice 1 WebUI step. Row 5 stays waiting-on-jason until then.
    • Question 6, approving the PRD as 1.0, got no answer. The PRD stays a draft (0.4) until Jason approves it. Sage writes the slice 1 brief against 0.4's requirement ids, and any id that changes before approval gets fixed in the brief.
  47. The slice 1 brief and its rows (2026-10-04). Source: docs/plans/2026-10-04_slice-1.md (commit 43c48d7a). Epic #1515, row issues #1516 to #1524, queue rows 34 to 42.

    • The owners follow who designed each part: Filbert gets the probes (S0) and the meta-harness (S6), Darkwing roles (S1) and tasks (S3), Rocko the bus (S2) and the CLI (S4), Dewey the WebUI (S5). Sage writes the identity runbook (SR) and conducts acceptance (S7). Rocko needs no credentials for S2 or S4, because the broker is tested with fixture tokens until S3.
    • Sage accepts rows 34 to 37 as briefed, so S0, SR and S1 can start now and S2 can start once schema v3 lands. Rows 38 to 42 stay queued until the rows they follow are done. If Jason raises a scope question, only the rows in flight need rework.
    • Assumption, flagged to Jason: REQ-CRED-1 and REQ-CRED-2 cover the service tokens (Gitea, Vikunja). Model-provider login stays as it is today, since slice 1 has no container to isolate it in.
    • No new root directory. The runbook goes in docs/guides/, and the bundled Vikunja option goes in packages/tasks/deploy/vikunja/.
  48. Schema v3 accepted (2026-10-04). Source: Darkwing, commit 7ed83178, agents/darkwing/work/slice1-proto/schema-v3.sql (sha256 084d0a07…). Sage's rerun on Node 26.8.1 matched the recorded output. Row 37 (S2) builds from it.

    • The extra trigger events_task_missing_body stays. It enforces the task.missing body that addendum B section 5 already defined: the task in subject, a reason of moved, not-found or no-access, and the new project id when the reason is moved. The v2 schema checks credential.* bodies the same way, and an event the reader can't act on is worse than a refused write.
  49. Dewey's S5 questions (2026-10-04). Source: Dewey, design note agents/dewey/work/wui/SLICE1-VIEWS.md (uncommitted, Dewey's working file). All five recommendations are accepted.

    • Q1: the inbox, tasks, agents and trail reads live in one module in packages/bus, over the broker client. Both the CLI (S4) and the WebUI server (S5) import it, so REQ-WEB-1's "same data" holds by construction. The WebUI never opens bus.sqlite. Rocko owns it, because S2 and S4 are both his rows.
    • Q2: the broker gains a status read giving the last successful board and cursor read per project, plus the last poll error. Row S3 builds it, since the poller is S3's.
    • Q3: any event about one task carries the task ref in subject. The task.create body also names the human.input event that asked for it, so a trail can begin at Jason's request. These are body rules, so the kind list doesn't change. Darkwing decides whether a trigger or the broker enforces each one.
    • Q4: the WebUI writes nothing in slice 1, not even seen. The inbox detail shows the mosaic decide command to copy.
    • Q5: S5 also fixes escalating staying set after a throw, and a takeover followed by Enter in one chunk, because both sit in files S5 owns. The freeze-ordering test stays in DEFERRED.
  50. Schema v3a accepted (2026-10-04). Source: Darkwing, commit 29daa482, agents/darkwing/work/slice1-proto/schema-v3a.sql (sha256 d55e41fd…). Sage's rerun on Node 26.8.1 matched. Row 37 (S2) builds from v3a instead of v3.

    • Both Q3 rules from decision 56 are triggers, and the broker also sets the fields. Every task.* event names its task in subject. The task.created body's request names a human.input event already in the bus, from the same business.
    • The requirement check in the same trigger stays, beyond what Q3 asked. REQ-TASK-1 already refuses a task without a requirement id, and addendum A put that id on task.created. The trigger checks the shape, and the broker checks that the id exists in the PRD.
    • The tighter task ref pattern (vikunja:<int>/<int>, positive, no leading zero) stays, and it now covers decisions.task_ref too.
    • The broker, not a trigger, links action.* and review.* events to a task, because the kind alone doesn't say when one is about a task.
  51. Row SR round 1 rulings (2026-10-04). Source: Darkwing's review, #1517 comment 26709, record agents/darkwing/work/slice1-sr-review-r1-2026-10-04.md. Every change requested is taken into the guide.

    • Bot names carry the business id on both services, because usernames are global to each instance: Gitea <business>-<role>-bot, Vikunja bot-<business>-<role>. PRD draft 0.4's REQ-CRED-1 wording changes to match. That is a naming correction inside a draft, not a new requirement.
    • Reviewer-bot's Gitea approvals are advisory. It joins no approvals allowlist, merges stay Jason's, and the verdict that gates a row lives in the queue and the bus.
    • The guide says plainly that reviewer-bot's token can open a pull request through an AGit push. That's acceptable only because the broker holds the token and gives the reviewer no push action.
    • Slice 1 needs no Vikunja labels. The business file example comes from row S1, and the template file waits for it.
  52. A stale poll read stays stored but isn't shown as current (2026-10-04). Source: Dewey, agents/dewey/work/wui/SLICE1-VIEWS.md section 8 (revision 2, sha256 1b31e1d2…, Dewey's uncommitted working file). The case: a board read that began before the broker's own move is written, because its digest differs, and it then becomes the latest snapshot. So tasks_open shows the old bucket until the next tick. Dewey's check confirmed it against schema v3a.

    • The poller keeps writing the row. A snapshot records what Vikunja returned, and dropping one to make a view right would thin the evidence.
    • The schema decides what "current" means, once, for every reader. A v3b amendment adds a view of each task's current snapshot. It skips a poll row whose read_at is at or before the task's latest self snapshot, and tasks_open is built on that view. The Q1 module, the CLI and the WebUI read the view and don't reimplement the rule. Darkwing writes v3b, with a mutant that drops the rule.
    • Dewey's Q3 correction also stands: the trail joins a task to its request through task.created's request, not through subject on the human.input event.
  53. Schema v3b accepted, and the S3 poller compares against the current snapshot (2026-10-04). Source: Darkwing, agents/darkwing/work/slice1-proto/ at 48d76de7, schema-v3b.sql sha256 179ffe35…, stored schema digest 52514a11…, notes in proto-v3b-notes.md. Tables 8, triggers 36, views 5.

    • The v3b change is one view, task_current, and tasks_open is rebuilt on it. diff schema-v3a.sql schema-v3b.sql shows nothing else. I reran proto-v3b.mjs on Node 26.8.1 on the host and on Node 24 in the node:24 image with no network. Both outputs match Darkwing's recorded files byte for byte.
    • S2 pins v3b instead of v3a. Rocko already has the change from Darkwing.
    • Darkwing's poller rule is accepted and amends addendum B section 5. The poller decides whether to write a read by comparing its digest against task_current, not against the task's raw latest row. Compared against the raw row, a stale write followed by a person's real move back hides that move from both views. The prototype shows it on vikunja:3/46. S3 carries the rule and a test for it.
    • One condition for the writers. Both views compare read_at and at as text, and the schema doesn't check their format, which was already true of v3a's external-change view. Every writer, S2's bus and S3's poller, stamps both columns in one fixed-width UTC form with the same precision. S2 and S3 each test that a mixed-format write is refused or can't happen.
    • Dewey moves checks/slice1-verify.mjs from v3a to v3b in Dewey's own working files. Darkwing's fixture replay already shows v3b agreeing with the mockup on all 72 rows.
  54. Jason's answers when I questioned him: the PRD is 1.0, and slice 1's framing stands (2026-10-05). Source: Jason's answers to four questions in Sage's thread 1ef1e4f8, around 2026-10-05T03:37Z.

    • The PRD is approved. Draft 0.4 becomes version 1.0 unchanged, which settles question 6 of round 3 (lead decision 53). From now on a change to docs/prd/mosaic-stack.md is a new version, not an edit.
    • The same-user boundary is accepted for slice 1. Agents run as Jason's OS user, and the broker is a rule, not a wall, which confirms round 3's 3A. A broker running as its own OS user comes later and doesn't gate S3 or S7.
    • REQ-CRED covers service tokens only, Gitea and Vikunja. Provider logins for Claude and Codex stay the way they work today. That turns the brief's stated assumption (lead decision 54) into a ruling.
    • Row 35 uses Path B. Slice 1 bots run against a bundled local Vikunja at the pinned digest, never SetSpark's tasks.setspark.io. Jason still runs the runbook. Row 35 stays waiting-on-jason until it's done.
    • Jason hasn't said whether he accepts the slice 1 brief as a whole, so row 11's second accepted brief is still open.
  55. Jason's answers, rounds 2 and 3: the brief is accepted, merges are gated, S7 is strict, and the human proof is cooperative (2026-10-05). Source: Jason's answers in Sage's thread 1ef1e4f8.

    • Jason accepts the slice 1 brief as written, with no scope question. That's row 11's second accepted brief, so row 11 closes.
    • Every merge of a coder-bot pull request is a gated decision. Each of S7's five pieces reaches Jason at least once for its merge, and S7 counts that as expected, not as a failure.
    • S7 is strict. If Jason steps in on a piece with a correction that isn't a gated decision, the piece fails, the correction is logged as a finding, and the count of five starts again.
    • Vikunja tokens keep the runbook's 90-day lifetime.
    • The human proof (REQ-DEC-3) is cooperative in slice 1. On one OS user, an agent that deliberately escapes S2's /proc check gets a human capability, as Darkwing showed with setsid -f env -i (agents/darkwing/work/slice1-s2-review/review-r2.md). The proof stops an agent that runs mosaic decide directly, and that is all slice 1 claims for it. S6 closes the gap for managed agents: they run in their own PID namespace or user, with no human socket mounted. A T3 seat that runs the human CLI or works around the proof breaks the rules, and the trail shows it.
    • Darkwing's npm install on 2026-10-04 rewrote ~/package.json and ~/package-lock.json. Jason says the old contents didn't matter. Nothing gets restored.
  56. S1's extras, and two S2 rulings (2026-10-05). Sources: Filbert's S1 verdicts (#1518 comments 26724 and 26730), Darkwing's S2 reviews (agents/darkwing/work/slice1-s2-review/, #1519).

    • S1's extras are accepted. The action vocabulary lives in packages/business/src/vocabulary.mjs, not contracts/, because only host code reads it, and Filbert checked that the image copies nothing that uses it. The example business file lives at packages/business/examples/mosaic-stack.example.json and refuses as shipped. scripts/mosaic gains a business branch, the same way it carries queue. The runbook's section 4 should point to that example when it is next revised.
    • A cross-role decision raised by its own arbiter goes to the human, and its class stays cross-role. Routing it to the other arbiter would be a guess about who's qualified, and sending it to the human fails closed. Rocko built this in S2 round 2.
    • A gated approval is single-use. Today one resolved approval authorizes the same action, target and run any number of times (Darkwing's P3 deploys three times). authorize must record that it consumed an approval, and a second use refuses. This doesn't reopen S2's approved round 2. It comes in a new row owned by Rocko and reviewed by Darkwing, and it has to land before S3 or S6 calls authorize for a gated action. If it needs a schema change, Darkwing writes a v3c.
    • Dewey's list of what the views need beyond the Q1 verbs (agents/dewey/work/wui/SLICE1-VIEWS.md section 9) goes to Rocko for S4. Session events belong to S6, and credential events belong to S3. Anything S4 doesn't add is labeled "not in the Q1 module" in S5.
  57. Every decision-backed approval is single-use, and a class mismatch refuses (2026-10-05). Source: Darkwing's S2b round 1 review, #1525 comment 26765, agents/darkwing/work/slice1-s2b-review/ (4f28c090).

    • Single-use covers every authorize that names a decision, not only gated ones. One CTO yes to a coder's task.scope.change on a task today authorizes every later scope change on that task in the run, because the decision doesn't bind the change's content. Within-role actions pass no decision and aren't affected. The S2b brief left this open for review, and this settles it.
    • The verbs that use a decision outside authorize consume it too. Today message.send and role.revoke don't, so one gated message.send approval sends without limit (Darkwing's R1).
    • If a decision's recorded class differs from the action's current class, #checkAuthority refuses with decision-mismatch. Today, once policy makes an action gated, an arbiter's earlier approval authorizes it as gated with no yes from Jason. That gap came from S2, and the fix changes S2's behavior beyond the S2b brief. I'm taking it in S2b round 2 anyway, because it's the same lines, and in both directions it refuses rather than widens.
    • Indexing the events scan stays a follow-up. Neither the consumption check nor the existing raise lookup has an index, and at slice 1 volumes that doesn't matter.
  58. A within-role message cites a decision; it doesn't spend one (2026-10-05). Source: Dewey, agents/dewey/work/wui/SLICE1-VIEWS.md section 10, probe ~/dewey-scratch/s2b-probe.w9pJ/probe.mjs, run against 38828a2c and 4afab552.

    • Decision 64 said within-role actions pass no decision. That is true for authorize, but not for message.send, which stores its decision argument in messages.decision. The trail and the inbox read that column as "this message is about this decision". Since S2b, a within-role send that names a decision runs the full check, so the PM's DECISION message to the human about a pending role.launch refuses with decision-mismatch. Fixture messages 101 and 102 are that case.
    • Ruling: when message.send is within-role for the sender and target, decision is a citation. The broker checks that the decision exists in the business and stores it. The broker doesn't class-match it, doesn't consume it, and doesn't put it in the action.allowed event, so the citation can't consume the decision or count as using it up. When message.send isn't within-role, decision is the authority, as decision 64 says, and the stored column names that approval.
    • Not chosen: a separate citation argument, which needs schema v3c for a slice 1 gap that the class split already closes. Dewey's option 2 also wasn't taken in place of this. S4 still sends the Discord DM for a blocking gated decision and records the delivery (REQ-DEC-4), but agents keep citing decisions in messages.
    • Row 44 (S2c, Rocko, reviewed by Darkwing) carries the change and Darkwing's README wording note from S2b round 2.
    • Correction, from Darkwing's S2c round 1 review (#1526 comment 26778). "Within-role for the sender and target" overstates what the policy can express. Role authority has no per-target entries, so the broker classifies message.send by the sender's role alone. S2c does that, and that's the rule.
  59. Jason's 2026-10-08 rulings for the stack: next stays the trunk, Mosaic Stack uses the estate Vikunja, and non-gated defaults apply at their deadline (2026-10-08). Source: Mos, thread 1eba59e5, relaying Jason's rulings R1, R5, R8, R10 and R17. Mos's lane state file holds the full list.

    • R10: the trunk stays next, and refactor merges into it. The plan is docs/plans/2026-10-08_refactor-to-next-merge-plan.md. Nothing is merged. next's .mosaic/repo.json already names next as the integration trunk, so no record contradicts the ruling. refactor has no root .mosaic/; the plan adds one.
    • R8: one new estate Vikunja 2.7.x instance serves Mosaic Stack, Launchpad, personal and system projects. SetSpark stays on tasks.setspark.io. Path A on that instance meets slice 1, so row 35 uses Path A there, and this replaces decision 61's Path B bullet. Decision 61 chose Path B to keep slice 1 off SetSpark's instance, and R8 keeps that separation.
      • Isolation comes from shares. A bot sees only projects shared with it, and the runbook shares only mosaic-stack. The bot names, bot-mosaic-stack-<role>, already avoid collisions with a second business on the same instance.
      • S3's probes still run on a scratch container, never the estate instance. Its first probe, which labels GET /labels shows a bot, has to show nothing from an unshared project before the PM bot runs on the estate instance.
      • S3's one live run writes into the mosaic-stack project only.
      • The bundled path stays in S3 as the REQ-TASK-3 option for other installs.
    • R1 and R5: when a non-gated item's deadline passes, its recommended default applies and is logged. Gated items wait for Jason: money, credentials and legal; prod infra and prod data; anything sent to people outside the fleet. Product and UX direction isn't gated.
    • R17: Jason runs docs/guides/slice-1-identities.md on 2026-10-09 at about 10:30 Central. If the estate instance isn't serving by then, he runs section 1 (Gitea) and leaves sections 2 to 4 for when it is. Don't start Path B as a stopgap, because that makes two Vikunjas and mints bot tokens twice.
  60. S3 starts before the runbook's Vikunja half, and the stack's PM and Lead are Sage and Darkwing (2026-10-08). Source: Mos, thread 1eba59e5, after decision 66.

    • The estate Vikunja won't serve by Jason's 2026-10-09 run. Mos dispatched it to orch-01 as T236 with no date yet. Jason runs the runbook's section 1 (Gitea) on 10-09, and sections 2 to 4 wait for T236's base URL. The existing tasks.mosaicstack.dev runs 2.1.0, which is too old, and stays untouched.
    • Row 38 (S3) no longer waits for row 35. Everything S3 builds runs against the recorded fake of the v2 routes and a scratch container, as its brief already says. Only the one live run needs the estate instance, and S3's gate still requires that run's log, so the row can't close without it. Without this change every slice 1 row sits behind T236. Row 38 keeps rows 36 and 37 as prerequisites.
    • Jason's R20 gives every project a separate PM and Lead. Mos proposed Sage as PM and Darkwing as Lead (the PRD's CTO role). That is the slice 1 brief's staffing already: PM held by Sage, CTO by Darkwing. No row changes.