12 KiB
Status: written by Sage, lead. It follows docs/plans/BRIEF-TEMPLATE.md.
It covers the faults from Jason's first PM test that rows 89 to 92
don't: the PM's findings file
(<dataRoot>/workspaces/mosaic-stack/pm/findings-2026-10-12.md)
faults 3, 5 and 8, Jason's "blind after each send" report (Mos
sage-0103) and his Console report (Mos sage-0105). Fault 9 went into
row 89. Jason's ruling through Mos (sage-0104, Q125 yes): these are
fixed through Sage's rows, not by the running PM, then the stack is
redeployed and his test re-run. Gitea issues #1587, #1588 and
#1589.
The fixes from Jason's PM test (2026-10-12)
A review loop through the bus
Problem
The coder role holds git.push.working and review.request, and the
reviewer holds review.verdict (roles/coder.json:9,
roles/reviewer.json:9). The broker lists all three actions
(packages/bus/src/broker.mjs:13-17) and records review.* events
against a task (:254), but no verb handles them and no typed tool
exists (packages/harness/src/tools.mjs). In the test the coder
couldn't hand its change to the reviewer except by pasting it into a
message, the reviewer sent its verdict as a message, and the PM cited
that message in task_close. P19 #229's review asked for changes
only because nothing could be pushed.
Owner and reviewers
Owner: Filbert, after row 91 (a project checkout in each role workspace) and their row 95. Reviewers: Darkwing and Dewey, both required, since the host runs git for a session.
Files owned
packages/bus/src/broker.mjs, the new review verbs onlypackages/cli/src/launcher.mjsandpackages/seat/src/checkout.mjs, only the host-side push and fetchpackages/harness/src/tools.mjs,runner.mjs, the new tools onlyroles/coder.md,roles/reviewer.md,roles/pm.md, the review paragraphs onlypackages/bus/README.md,packages/harness/README.md,packages/seat/README.md- tests under
packages/bus/tests/,packages/harness/tests/,packages/seat/tests/andpackages/cli/tests/ agents/filbert/work/queue-<row>/
What ships
- A working repository per business and project, a bare git repository under the data root that only the host writes. It is not the project's root and not a forge. No credential goes near it.
push_working(actiongit.push.working): the host, outside the session's sandbox, pushes one branch of the caller's clone to the working repository aswork/<task ref>. It takes a task ref and a branch, refuses anything but a fast-forward of that one ref, and records the commit.request_review(actionreview.request): records areview.requestevent on the task, naming the commit already in the working repository, and messages the reviewer role. A commit not in the working repository refuses.fetch_reviewfor holders ofreview.verdict: the host fetches the requested commit into the caller's clone as a remote-tracking ref, so the reviewer reads and tests it in its own workspace.review_verdict(actionreview.verdict): recordsapproveorchangeswith a body on the task, citing the request event. The PM'stask_closecites the verdict event's id. Whether the broker checks that citation is a choice the packet makes and argues.- The session text from the bundle names the review steps; the role files say the same.
- Tests: the whole loop between a fake coder and a fake reviewer session over real clones, each refusal (another task's branch, a non-fast-forward, an unknown commit, a role without the action), and the project root unchanged after every case.
Suites: the bus, harness, seat and cli node suites, and every
scripts/test-*.sh.
Out of scope
Landing an approved commit in the project, which stays Sage's gate
under R28. git.push.protected. A forge or Gitea remote. Credentials
in any session.
Gate
Darkwing and Dewey approve on the row's issue, naming the candidate manifest. The suites above pass on Sage's gate rerun. Live at the next bus restart, which Mos approves first (sage-0104).
Every message to the human, live
Problem
mosaic talk sends, then prints whatever reaches the human until the
direct reply comes, and stops there (packages/cli/src/cli.mjs:204-214).
A message the PM sends later, from a turn another seat or the PM itself
started, has no in_reply_to and waits unread until the next talk
prints it. Jason reads that as each answer arriving one message late.
mosaic inbox lists decisions only (broker.mjs:846-851). The Console
shows replies to its own send (row 81, the replies verb,
broker.mjs:915-925) and nothing else, so it never shows those
messages either.
Owner and reviewer
Owner: Rocko, after row 77, and before their rows 84 and 85. Reviewer: Dewey, who built row 81.
Files owned
packages/bus/src/broker.mjs, amessagesread verb onlypackages/cli/src/cli.mjs,talkandinboxonlypackages/webui/src/serve.mjs(BUS_VERBS),packages/webui/src/public/bus.js,bus.cssif neededpackages/bus/README.md,packages/cli/README.md,packages/webui/README.md- tests under
packages/bus/tests/,packages/cli/tests/andpackages/webui/tests/ agents/rocko/work/queue-<row>/
What ships
- A broker
messagesread verb for the human and the Console's reader: messages to the human, newest first, withlimit(default 50, at most 200),afterfor paging, and whether each is read. Reading it marks nothing. mosaic talk --follow: after the send, it keeps printing each message to the human as it arrives, marking it read astalkdoes today, until Ctrl-C.mosaic followdoes the same without sending. Without the flag,talkis unchanged.mosaic inboxlists unread messages to the human under the decisions, without marking them read.- A Messages page in the Console, refreshing like the other bus pages,
shows every message to the human with its sender, class, time, read
state and a trail link. It marks nothing, so
talkstill prints each one. The nav shows the unread count. - Tests: a message with no
in_reply_toarriving after atalkreturns is printed bytalk --followand byfollow, listed byinboxand shown in the Console; nothing the Console reads is marked read; the verb's paging and refusals.
Suites: the bus, cli and webui node suites, and every
scripts/test-*.sh.
Out of scope
Pushing messages to the browser (polling stays). Marking messages read from the Console. Messages between roles.
Gate
Dewey approves on the row's issue, naming the candidate manifest. The suites above pass on Sage's gate rerun. Sage notifies Mos before the landing; it is live after the bus and Console restart Mos approves.
The Console's Board shows the stack's seats and a sign-out
Problem
The Console's Board is the machine scan the old board server serves at
127.0.0.1:7331 (packages/webui/src/serve.mjs:8, proxied as
/api/board). It lists tmux and T3 sessions. The stack's own seats
(the PM, coder and reviewer) appear only on the Agents page
(packages/webui/src/public/bus.js:410-415), and a message to them
only from the Inbox page's "Message a role" form (bus.js:270). In
the test Jason saw the fleet's seats and not the stack's (findings
fault 8, P19 #231), and he approved hiding the machine sessions.
Jason also reports he signs in to mosaic.woltje.com and then can't see updated info or interact (Mos sage-0105). Checked 2026-10-12:
- The edge admits the Console. ops-01 read the outpost log: forward-auth
302s only from 19:28:16Z to 19:29:26Z, after a pod replacement at
19:28:07Z, then 225 browser 200s and no 302 to 19:48:25Z (Mos
sage-0106). The Console has no websocket; every page polls with
fetch. - The Board's data is current: the scan at 7331 answered in 1.3 s with
generatedAt2026-10-12T19:49:24Z, 44 sessions, projectsmosaic-stackandfleet, all machine sessions. - The running Console started at 19:05:38Z, before row 81 (
c9a5650e) landed, so it shows no reply to a web send. Its log has no send line since then.
So the Console works as built, and what Jason needs from it isn't there: the stack's seats aren't on the Board, the send is on another page, the replies aren't deployed, and messages the PM starts never show (the row above).
During the 19:28 sign-in loss every Console API fetch got a 302 to the
sign-in origin (the same answer an unauthenticated
GET https://mosaic.woltje.com/api/board gets). A fetch that follows a
redirect across origins fails with Firefox's "NetworkError when
attempting to fetch resource", which the Board showed earlier today.
The Console keeps the last data and retries every 10 s, failing the same
way until the page is reloaded (app.js:290-291, bus.js:31,42). A
pod replacement will do this again.
Owner and reviewer
Owner: Filbert. Reviewer: Darkwing.
Files owned
packages/webui/src/public/app.js,bus.js,index.html,app.csspackages/webui/src/serve.mjs, only if the Board needs a new routepackages/webui/README.md- tests under
packages/webui/tests/ agents/filbert/work/queue-<row>/
What ships
- The Board's first section lists the stack's held roles from the bus
agentsread, including claims with no address, each with its state and a Message action that opens the send form addressed to that role. - The machine scan's sessions sit behind a "Show machine sessions" toggle, off by default, kept in the page's settings like the other Board filters.
- Every Console fetch uses
redirect: 'manual'. A redirect answer (opaqueredirect) stops the refresh and shows one line: signed out, reload the page to sign in. It doesn't show a NetworkError or stale data as current. - Tests: the Board with held roles and no machine sessions, a claim with no address, the toggle, the Message action's role, and a redirect answer on a Board read, a bus read and a send.
Suites: the webui and control-board node suites, and every
scripts/test-*.sh.
Out of scope
The edge's sign-in lifetime, which is ops-01's through Mos. Removing the machine scan. A Board for other businesses.
Gate
Darkwing approves on the row's issue, naming the candidate manifest. The suites above pass on Sage's gate rerun. Live after the Console restart Mos approves.
Row 95 follow-up: Board tests fail fast, README lists every redirect
Problem
Darkwing's review of row 95 (comment 27953, approve) left three notes,
and row 95 landed in 17ad6f35 without a second round.
- N1:
packages/webui/tests/browser-edge.test.mjsawaitsboardRequested(line 29), which only the server's/api/boardhandler resolves. If the "Show machine sessions" toggle stops reading the board, the await never settles. The test is cancelled at 120 s, itsfinallynever closes the browser and server, and the file never exits.node --testhas no file timeout, so the webui suite stalls instead of failing. - N2: test 2 in
board-held.test.mjsclaims no further request on the poll, but it waits 600 ms and both polls are 10 s. Mutants 13 and 27 survive for that reason. - N3: the webui README's test paragraph says test 2 redirects three
reads. It redirects six: the board,
agents,/api/conversations,/api/seen,/api/queueand the send.
Owner and reviewer
Owner: assigned on the row. Reviewer: Darkwing.
Files owned
packages/webui/tests/browser-edge.test.mjs,packages/webui/tests/board-held.test.mjs, and any test helper they sharepackages/webui/README.md, the test paragraph onlyagents/<owner>/work/queue-<row>/
What ships
- N1: the toggle step in
browser-edge.test.mjsfails within a few seconds when no/api/boardrequest comes, and the browser and server close either way. Prove it with the toggle-on mutant: the file exits nonzero inside 30 s, with no browser or node process left. - N2: either test 2 reaches a poll tick, by a shorter poll in the test or a clock the test controls, and mutants 13 and 27 die; or the test's comment and the README stop claiming the poll. The packet says which, and why.
- N3: the README's test paragraph names all six redirected requests.
Suites: the webui and control-board node suites, and every
scripts/test-*.sh.
Out of scope
Any change under packages/webui/src/. Row 95's behavior stays as
landed.
Gate
Darkwing approves on the row's issue, naming the candidate manifest. The suites above pass on Sage's gate rerun. Tests and README only, so nothing goes live and no restart is involved.