429 lines
17 KiB
Markdown
429 lines
17 KiB
Markdown
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 only
|
|
- `packages/cli/src/launcher.mjs` and `packages/seat/src/checkout.mjs`,
|
|
only the host-side push and fetch
|
|
- `packages/harness/src/tools.mjs`, `runner.mjs`, the new tools only
|
|
- `roles/coder.md`, `roles/reviewer.md`, `roles/pm.md`, the review
|
|
paragraphs only
|
|
- `packages/bus/README.md`, `packages/harness/README.md`,
|
|
`packages/seat/README.md`
|
|
- tests under `packages/bus/tests/`, `packages/harness/tests/`,
|
|
`packages/seat/tests/` and `packages/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` (action `git.push.working`): the host, outside the
|
|
session's sandbox, pushes one branch of the caller's clone to the
|
|
working repository as `work/<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` (action `review.request`): records a `review.request`
|
|
event 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_review` for holders of `review.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` (action `review.verdict`): records `approve` or
|
|
`changes` with a body on the task, citing the request event. The PM's
|
|
`task_close` cites 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`, a `messages` read verb only
|
|
- `packages/cli/src/cli.mjs`, `talk` and `inbox` only
|
|
- `packages/webui/src/serve.mjs` (`BUS_VERBS`),
|
|
`packages/webui/src/public/bus.js`, `bus.css` if needed
|
|
- `packages/bus/README.md`, `packages/cli/README.md`,
|
|
`packages/webui/README.md`
|
|
- tests under `packages/bus/tests/`, `packages/cli/tests/` and
|
|
`packages/webui/tests/`
|
|
- `agents/rocko/work/queue-<row>/`
|
|
|
|
### What ships
|
|
|
|
- A broker `messages` read verb for the human and the Console's reader:
|
|
messages to the human, newest first, with `limit` (default 50, at
|
|
most 200), `after` for 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 as `talk` does today,
|
|
until Ctrl-C. `mosaic follow` does the same without sending. Without
|
|
the flag, `talk` is unchanged.
|
|
- `mosaic inbox` lists 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 `talk` still prints each
|
|
one. The nav shows the unread count.
|
|
- Tests: a message with no `in_reply_to` arriving after a `talk`
|
|
returns is printed by `talk --follow` and by `follow`, listed by
|
|
`inbox` and 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
|
|
`generatedAt` 2026-10-12T19:49:24Z, 44 sessions, projects
|
|
`mosaic-stack` and `fleet`, 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.css`
|
|
- `packages/webui/src/serve.mjs`, only if the Board needs a new route
|
|
- `packages/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
|
|
`agents` read, 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.mjs` awaits
|
|
`boardRequested` (line 29), which only the server's `/api/board`
|
|
handler resolves. If the "Show machine sessions" toggle stops reading
|
|
the board, the await never settles. The test is cancelled at 120 s,
|
|
its `finally` never closes the browser and server, and the file never
|
|
exits. `node --test` has no file timeout, so the webui suite stalls
|
|
instead of failing.
|
|
- N2: test 2 in `board-held.test.mjs` claims 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/queue` and 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
|
|
share
|
|
- `packages/webui/README.md`, the test paragraph only
|
|
- `agents/<owner>/work/queue-<row>/`
|
|
|
|
### What ships
|
|
|
|
- N1: the toggle step in `browser-edge.test.mjs` fails within a few
|
|
seconds when no `/api/board` request 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.
|
|
|
|
## Row 94 follow-up: text-mode inbox works against a pre-94 bus
|
|
|
|
### Problem
|
|
|
|
Row 94 (2b2a9e14) made text-mode `mosaic inbox` call the bus `messages`
|
|
verb after `inbox`. The running bus predates row 94 and has no
|
|
`messages` verb, so it answers `unknown-verb`. Text-mode inbox then
|
|
fails and prints nothing, not even the decisions. `--json` still works
|
|
because it returns before the messages call. Mos found it; Sage
|
|
reproduced it in-process with a stub transport. The bus restart stays
|
|
where decision 118 puts it, so the CLI has to cope (decision 132).
|
|
|
|
### Owner and reviewer
|
|
|
|
A Haiku subagent builds it under decision 129, owner `researcher`.
|
|
Filbert reviews.
|
|
|
|
### Files owned
|
|
|
|
- `packages/cli/src/cli.mjs`, the text-mode branch of the `inbox` verb
|
|
only.
|
|
- `packages/cli/tests/` (the existing cli test file that covers
|
|
`inbox`, or a new one).
|
|
|
|
### What ships
|
|
|
|
- When the `messages` call fails with error code `unknown-verb`,
|
|
text-mode inbox prints the decisions as it did before row 94, then
|
|
one line, `messages: not available until the bus restarts`, and
|
|
exits 0.
|
|
- Any other error from the `messages` call still fails as it does now.
|
|
- `--json` is unchanged.
|
|
- Tests, with a stub transport as the existing cli tests use: the
|
|
unknown-verb case prints the decisions and the line and exits 0;
|
|
another error code still fails; the normal path still lists unread
|
|
messages. Each test is shown to fail on a mutant that removes or
|
|
widens the fallback.
|
|
|
|
Suites: the cli node suite and every `scripts/test-*.sh`.
|
|
|
|
### Out of scope
|
|
|
|
The bus, the Console, `talk`, `messages` and `follow`. No restart.
|
|
|
|
### Gate
|
|
|
|
Filbert approves on the row's issue, naming the candidate manifest.
|
|
The suites above pass on Sage's gate rerun. `cli.mjs` applies to new
|
|
CLI runs as soon as it lands, so it gets decision-109 notices to Mos
|
|
before and after landing.
|
|
|
|
## Row 93 follow-up: git socket hardening and refusal tests
|
|
|
|
### Problem
|
|
|
|
Row 93 (4da68152, #1587) landed with approvals from Dewey (28196) and
|
|
Sage (28197), and neither blocked. Their non-blocking notes, with
|
|
Darkwing's `agents/darkwing/work/queue-93/r1-notes.md` (eabd5982),
|
|
leave these gaps:
|
|
|
|
- Five host refusals have no test: `not-a-role`, `host-closing`,
|
|
`git-busy`, `root-unreadable`, `unknown-project`.
|
|
- `working.mjs` kills a timed-out git with SIGKILL, so git never
|
|
removes its lockfiles. A stale `refs/heads/<branch>.lock` then blocks
|
|
every later push to that branch until an operator removes it.
|
|
- When `record` throws, the work ref's rollback `update-ref` result
|
|
isn't checked. A failed rollback leaves an unrecorded commit on the
|
|
work ref, and nothing reports it.
|
|
- `readBody` in `git-socket.mjs` has only a per-chunk idle timeout. A
|
|
session that sends a byte every 29 seconds holds a slot, and eight
|
|
such sessions make the socket refuse `git-busy` for everyone.
|
|
- A reviewer that disconnects mid-fetch is filed as `git-failed`.
|
|
- The runner fills `have` (HAVE_MAX 32) from all origin and working
|
|
refs in sort order, so with many refs it can drop the ones that
|
|
matter.
|
|
- The repository lock is in-process: it assumes one launcher per
|
|
dataRoot, and no README says so.
|
|
|
|
### Owner and reviewer
|
|
|
|
Darkwing builds it. Dewey and Sage review.
|
|
|
|
### Files owned
|
|
|
|
- `packages/seat/src/working.mjs`, `packages/seat/tests/working.test.mjs`,
|
|
`packages/seat/README.md`
|
|
- `packages/cli/src/git-socket.mjs`, `packages/cli/tests/git-socket.test.mjs`,
|
|
`packages/cli/README.md`
|
|
- `packages/harness/src/git-tools.mjs` and its tests, for `have` only
|
|
|
|
### What ships
|
|
|
|
- One test per untested refusal named above.
|
|
- On timeout, host git gets SIGTERM, a short grace period, then SIGKILL.
|
|
A test shows a timed-out push leaves no ref lock behind, and that the
|
|
next push to the branch lands.
|
|
- A failed rollback refuses `rollback-failed` and is logged by the host,
|
|
in place of the record's code. The broker's own refusal is already on
|
|
the trail. Test it with a rollback forced to fail.
|
|
- `readBody` has a total deadline as well as the idle timeout. The
|
|
deadline is a stated constant, or a stated function of the request's
|
|
size. A trickling client test refuses within it and frees its slot.
|
|
- A client gone mid-fetch is filed as `fetch-aborted`, not
|
|
`git-failed`.
|
|
- The runner's `have` lists the working refs before origin's and never
|
|
more than HAVE_MAX. A test uses more than 32 refs.
|
|
- The seat README says the lock assumes one launcher per dataRoot. The
|
|
reviewer docs say what `nothing-to-fetch` means.
|
|
|
|
Each new check is shown to fail on a mutant that removes it.
|
|
|
|
Suites: every node suite and every `scripts/test-*.sh`.
|
|
|
|
### Out of scope
|
|
|
|
- Tying a push's project to the task's own project, and checking that
|
|
the pusher is the task's assignee. Both need a design ruling first.
|
|
- gc of objects from refused pushes.
|
|
- Any broker or schema change.
|
|
|
|
### Gate
|
|
|
|
Dewey and Sage approve on the row's issue, naming the candidate
|
|
manifest, and the suites above pass on Sage's gate rerun. The cli and
|
|
seat changes reach the host only at a bus restart. That restart needs
|
|
Mos's go, and it batches with row 80's. Decision 109 notices go to Mos
|
|
before and after landing.
|