Files

4.9 KiB

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.