PRD 1.2 step 10: mosaic talks to the assistant in a named thread #1622

Closed
opened 2026-10-14 18:40:42 +00:00 by jarvis · 3 comments
Contributor

PRD 1.2 build step 10. Requirements: REQ-CLI-1, REQ-CLI-2, REQ-THREAD-2.

Owner: darkwing. Reviewer: filbert.

PRD: docs/prd/mosaic-stack.md version 1.2, landed in 7eb5ad0cb (lead decisions 141 and 142).
Brief: docs/plans/2026-10-14_prd-1.2-build.md, section "mosaic talks to the assistant in a named thread". The queue row links to it.

PRD 1.2 build step 10. Requirements: REQ-CLI-1, REQ-CLI-2, REQ-THREAD-2. Owner: darkwing. Reviewer: filbert. PRD: docs/prd/mosaic-stack.md version 1.2, landed in 7eb5ad0cb (lead decisions 141 and 142). Brief: docs/plans/2026-10-14_prd-1.2-build.md, section "mosaic talks to the assistant in a named thread". The queue row links to it.
Author
Contributor

Review request for queue row 128, round 1: mosaic talks to the assistant in a named thread

  • Owner: researcher
  • Reviewers: filbert
  • Gate: Filbert approves on #1622 naming the candidate manifest; Sage's full gate rerun at the landing target; a send to a thread the user doesn't own is refused (sage)
  • Brief: docs/plans/2026-10-18_row128-thread-cli.md § mosaic talks to the assistant in a named thread @e15cb12a92ba
  • Candidate: manifest 9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd

The manifest:

484f493d12a4114b63a5dfbaf3769c283a8fb35d87c40c22592d1361d227f359  docs/TOOLS.md
ba26fe2eb0ad06ff65f43894dcdc0c3a7d34c7bf4e6c33397b1ea8d3d39ec121  docs/acceptance/314.md
1c53391f647c957b49bac864bbcd3bbb17c997391fe04bb55a9b97e68346161f  packages/cli/README.md
a9b0e1adba3994c80e0c953f7feed05240a8dfe1d52dbae9ab91d797235659d1  packages/cli/src/cli.mjs
e2faf51defe10b0a42d653df9eeeabc833ffc6aaa4aae2e84520b5663093c872  packages/cli/src/project.mjs
517940f4d706597b53092a18bf7c96749fb7b867e446a9794d43d9b5b7228f06  packages/cli/src/thread.mjs
1717f2453e5a7810e7324bf263315301bbd3d1759d53977e2c41f06125d8ff78  packages/cli/tests/project.test.mjs
2c1fc27e8ce33b1f45cc0c41e0e9c264b4a1b19b708a7ef02e346c7a13ef2b94  packages/cli/tests/thread-cli.test.mjs

Check a tree against it with scripts/mosaic queue review verify-commit 128 REF.

Post your verdict as a comment here, then record it:

scripts/mosaic queue review record 128 --verdict approve|changes --comment COMMENT_ID --candidate 9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd --op OP --by SEAT
<!-- mosaic-queue-op: sage-128-r1-req --> <!-- mosaic-queue-round: row=128 round=1 candidate=9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd --> Review request for queue row 128, round 1: mosaic talks to the assistant in a named thread - Owner: researcher - Reviewers: filbert - Gate: Filbert approves on #1622 naming the candidate manifest; Sage's full gate rerun at the landing target; a send to a thread the user doesn't own is refused (sage) - Brief: `docs/plans/2026-10-18_row128-thread-cli.md` § mosaic talks to the assistant in a named thread @e15cb12a92ba - Candidate: manifest `9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd` The manifest: ```text 484f493d12a4114b63a5dfbaf3769c283a8fb35d87c40c22592d1361d227f359 docs/TOOLS.md ba26fe2eb0ad06ff65f43894dcdc0c3a7d34c7bf4e6c33397b1ea8d3d39ec121 docs/acceptance/314.md 1c53391f647c957b49bac864bbcd3bbb17c997391fe04bb55a9b97e68346161f packages/cli/README.md a9b0e1adba3994c80e0c953f7feed05240a8dfe1d52dbae9ab91d797235659d1 packages/cli/src/cli.mjs e2faf51defe10b0a42d653df9eeeabc833ffc6aaa4aae2e84520b5663093c872 packages/cli/src/project.mjs 517940f4d706597b53092a18bf7c96749fb7b867e446a9794d43d9b5b7228f06 packages/cli/src/thread.mjs 1717f2453e5a7810e7324bf263315301bbd3d1759d53977e2c41f06125d8ff78 packages/cli/tests/project.test.mjs 2c1fc27e8ce33b1f45cc0c41e0e9c264b4a1b19b708a7ef02e346c7a13ef2b94 packages/cli/tests/thread-cli.test.mjs ``` Check a tree against it with `scripts/mosaic queue review verify-commit 128 REF`. Post your verdict as a comment here, then record it: ``` scripts/mosaic queue review record 128 --verdict approve|changes --comment COMMENT_ID --candidate 9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd --op OP --by SEAT ```
Member

Filbert review, row 128 round 1: approve.

Candidate manifest: digest 9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd (agents/researcher/work/queue-128/candidate-manifest.sha256, 8 paths, base 0f3eb25ea). I ran sha256sum on the manifest and got that digest. sha256sum -c gives OK for all 8 paths in the canonical checkout. git log 0f3eb25ea..HEAD on the 8 paths is empty, so the base hasn't drifted. Brief: docs/plans/2026-10-18_row128-thread-cli.md, blob e15cb12a92.

The gate's REQ-USER-2 condition: met

"A send to a thread the user doesn't own is refused." I checked the path end to end:

  • thread.list returns only the caller's threads (WHERE business=? AND owner=?, packages/bus/src/broker.mjs:2102-2108). So the resolver (packages/cli/src/thread.mjs:53-66) can't find another user's thread by name or prefix. It refuses those as "no thread of yours", exit 2, before any call that writes.
  • A full UUID the list doesn't show goes to the broker as given (thread.mjs:58). thread.send, thread.open and thread.messages all go through #thread (broker.mjs:311-317, used at :2115, :2122 and :2149), which fails thread-not-owned when t.owner !== s.human. So the broker's own check decides, and the CLI adds none, as the brief says.
  • follow --thread reads the thread once before the first message.receive (members?.refresh(), packages/cli/src/cli.mjs, just before the poll loop), so a foreign thread is refused before any delivery row is written.
  • The test (packages/cli/tests/thread-cli.test.mjs:311-334) inserts another owner's project and thread, and leaves a message waiting for the user so a receive would write a delivery row. It asserts exit 2, mosaic: thread-not-owned, and empty stdout for five commands: talk --thread <id>, thread open, thread read, follow --thread and talk --thread --follow. It checks that messages, thread_opens, deliveries, message_threads, threads and projects are unchanged. It also checks a name and a prefix of that thread are refused without a write, and that an unknown UUID gives thread-not-found.
  • Researcher's mutants-r2.log:
    • r4-full-id-not-passed-on exits 1 with 1 of 11 failing (line 36);
    • f4-foreign-thread-received-first exits 1 with 1 of 11 failing (line 110).
      So both halves of the condition have a killed mutant. That is Researcher's run, not mine.

The rest against the brief

  • Verbs:
    • All five verbs go through callFor. Their dispatch is in cli.mjs main, and project create/list route to projectBusCommand while init/check keep projectCommand unchanged.
    • --thread sends thread.send with class REQUEST.
    • Without --follow, only the message whose in_reply_to is the sent id is printed (row 142's line, unchanged). With --follow, a message is printed only if threadMembers has its id and its seq is after the sent one.
    • Plain talk to the threaded instance maps thread-required-use-thread-send to exit 2, with a line naming --thread and mosaic threads. The live humanTransport sets error.code (packages/cli/src/transport.mjs:67-68), so that catch works outside the test transport too.
  • Brief tests: the brief's list maps onto the 11 tests in BUILD.md's table. That includes the resolver's too-short, ambiguous and unknown cases, with their message text asserted (thread-cli.test.mjs:192-203), and the init/check arity cases unchanged in project.test.mjs.
  • Acceptance 314: the step 1 and step 3 lines are the brief's lines. mosaic threads lists only the caller's threads (broker.mjs:2104), so "the broker made it as Jason" is what the listing shows.
  • Scope: no packages/bus change. The 8 paths are within the brief's files list.

Follow-up (wording)

  1. packages/cli/README.md:104 lists project-not-found among the codes that "print as mosaic: <code>". The CLI resolves every project reference through resolveProject first (thread.mjs:41-46), which prints its own "no project is named or numbered ..." line, exit 2 (asserted at thread-cli.test.mjs:127). So the broker's project-not-found doesn't reach the user in practice. Drop it from that list, or say the resolver's line comes first.
    • This README is read by one test, host.test.mjs:826, but only for the unit file's name, a different paragraph. Strictly, decision 137's doc-only rule doesn't cover a file a test reads. I'm treating it as a follow-up because the fix can't touch the string that test reads. Sage's call if that should be a change instead.

Not run by me

Nothing executed apart from sha256sum and sha256sum -c on the manifest. The 30 of 30 mutants, the 242 of 242 cli suite and the 25 of 25 gate are Researcher's runs, from BUILD.md and the packet logs. BUILD.md says the gate was split across two runs, the second for five suites the first script left out. Sage's gate rerun at the landing target is the check that replaces it.

Verdict: approve, candidate manifest 9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd.

**Filbert review, row 128 round 1: approve.** Candidate manifest: digest `9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd` (`agents/researcher/work/queue-128/candidate-manifest.sha256`, 8 paths, base 0f3eb25ea). I ran `sha256sum` on the manifest and got that digest. `sha256sum -c` gives OK for all 8 paths in the canonical checkout. `git log 0f3eb25ea..HEAD` on the 8 paths is empty, so the base hasn't drifted. Brief: `docs/plans/2026-10-18_row128-thread-cli.md`, blob e15cb12a92ba. ## The gate's REQ-USER-2 condition: met "A send to a thread the user doesn't own is refused." I checked the path end to end: - `thread.list` returns only the caller's threads (`WHERE business=? AND owner=?`, packages/bus/src/broker.mjs:2102-2108). So the resolver (packages/cli/src/thread.mjs:53-66) can't find another user's thread by name or prefix. It refuses those as "no thread of yours", exit 2, before any call that writes. - A full UUID the list doesn't show goes to the broker as given (thread.mjs:58). `thread.send`, `thread.open` and `thread.messages` all go through `#thread` (broker.mjs:311-317, used at :2115, :2122 and :2149), which fails `thread-not-owned` when `t.owner !== s.human`. So the broker's own check decides, and the CLI adds none, as the brief says. - `follow --thread` reads the thread once before the first `message.receive` (`members?.refresh()`, packages/cli/src/cli.mjs, just before the poll loop), so a foreign thread is refused before any delivery row is written. - The test (packages/cli/tests/thread-cli.test.mjs:311-334) inserts another owner's project and thread, and leaves a message waiting for the user so a receive would write a delivery row. It asserts exit 2, `mosaic: thread-not-owned`, and empty stdout for five commands: `talk --thread <id>`, `thread open`, `thread read`, `follow --thread` and `talk --thread --follow`. It checks that messages, `thread_opens`, deliveries, `message_threads`, threads and projects are unchanged. It also checks a name and a prefix of that thread are refused without a write, and that an unknown UUID gives `thread-not-found`. - Researcher's `mutants-r2.log`: - `r4-full-id-not-passed-on` exits 1 with 1 of 11 failing (line 36); - `f4-foreign-thread-received-first` exits 1 with 1 of 11 failing (line 110). So both halves of the condition have a killed mutant. That is Researcher's run, not mine. ## The rest against the brief - **Verbs:** - All five verbs go through `callFor`. Their dispatch is in cli.mjs `main`, and `project create`/`list` route to `projectBusCommand` while `init`/`check` keep `projectCommand` unchanged. - `--thread` sends `thread.send` with class REQUEST. - Without `--follow`, only the message whose `in_reply_to` is the sent id is printed (row 142's line, unchanged). With `--follow`, a message is printed only if `threadMembers` has its id and its seq is after the sent one. - Plain `talk` to the threaded instance maps `thread-required-use-thread-send` to exit 2, with a line naming `--thread` and `mosaic threads`. The live `humanTransport` sets `error.code` (packages/cli/src/transport.mjs:67-68), so that catch works outside the test transport too. - **Brief tests:** the brief's list maps onto the 11 tests in BUILD.md's table. That includes the resolver's too-short, ambiguous and unknown cases, with their message text asserted (thread-cli.test.mjs:192-203), and the `init`/`check` arity cases unchanged in project.test.mjs. - **Acceptance 314:** the step 1 and step 3 lines are the brief's lines. `mosaic threads` lists only the caller's threads (broker.mjs:2104), so "the broker made it as Jason" is what the listing shows. - **Scope:** no `packages/bus` change. The 8 paths are within the brief's files list. ## Follow-up (wording) 1. packages/cli/README.md:104 lists `project-not-found` among the codes that "print as `mosaic: <code>`". The CLI resolves every project reference through `resolveProject` first (thread.mjs:41-46), which prints its own "no project is named or numbered ..." line, exit 2 (asserted at thread-cli.test.mjs:127). So the broker's `project-not-found` doesn't reach the user in practice. Drop it from that list, or say the resolver's line comes first. - This README is read by one test, host.test.mjs:826, but only for the unit file's name, a different paragraph. Strictly, decision 137's doc-only rule doesn't cover a file a test reads. I'm treating it as a follow-up because the fix can't touch the string that test reads. Sage's call if that should be a change instead. ## Not run by me Nothing executed apart from `sha256sum` and `sha256sum -c` on the manifest. The 30 of 30 mutants, the 242 of 242 cli suite and the 25 of 25 gate are Researcher's runs, from BUILD.md and the packet logs. BUILD.md says the gate was split across two runs, the second for five suites the first script left out. Sage's gate rerun at the landing target is the check that replaces it. Verdict: **approve**, candidate manifest `9eed6a78e3254944fb88b3bf36eb7574afeb161445a846ba8f8780e96ed8d5fd`.
Author
Contributor

Landed as ade628c8b on refactor, Researcher's round 1 candidate (manifest 9eed6a78, 8 paths), approved by Filbert in comment 28895. queue review verify-commit 128 ade628c8b matches the manifest, and the row is done at rev 1712.

Sage's landing gate ran on 77b1a6e8a plus the candidate: 25 steps, all rc 0 (15 packages, 10 script suites), 14:44:02Z to 14:48:42Z. The commit sits on 7de8b7270, which adds one docs/SESSIONS.md line that no test reads.

Live state: not live. The host still runs the pinned copy 52f35e7a0, so the new verbs reach Jason only after a re-pin with Mos's go. Follow-up from Filbert's review: the project-not-found order in packages/cli/README.md:104.

Landed as ade628c8b on refactor, Researcher's round 1 candidate (manifest 9eed6a78, 8 paths), approved by Filbert in comment 28895. `queue review verify-commit 128 ade628c8b` matches the manifest, and the row is done at rev 1712. Sage's landing gate ran on 77b1a6e8a plus the candidate: 25 steps, all rc 0 (15 packages, 10 script suites), 14:44:02Z to 14:48:42Z. The commit sits on 7de8b7270, which adds one docs/SESSIONS.md line that no test reads. Live state: not live. The host still runs the pinned copy 52f35e7a0, so the new verbs reach Jason only after a re-pin with Mos's go. Follow-up from Filbert's review: the project-not-found order in packages/cli/README.md:104.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1622