8.0 KiB
Row 220: C2-10a, no raw session view (M7) and no raw Discord engine (M8)
Phase A. No test, suite or mutant has been run. Sage opens the slot.
- Owner: researcher seat (Haiku 5.5 subagent), dispatched by Sage under lead decision 129.
- Reviewer: Filbert.
- Branch:
researcher/row220, fromorigin/refactoratd37210288. - Brief:
docs/plans/2026-10-20_case2-rows.md, C2-10a (line 495) and "Rules every row keeps". - Design:
agents/gosalyn/work/case2/DESIGN.mdonorigin/gosalyn/case2-design, sections 5.1 (M7, M8), 7.6, 8 (row list).
Status
| Item | State |
|---|---|
M7 reader side (conversation-not-listed) |
Built. Tests written, not run. |
M7 production wiring (the caller that passes isCreative) |
Not built. Outside the file list, and it needs a ruling (question 1). |
M8 discord check and discord run refusals |
Not built. packages/discord/src/cli.mjs is untouched. Blocked on question 1 and question 2. |
Phase A is therefore partial. The row cannot pass its acceptance until Sage rules on the questions below.
Files
packages/conversation/src/reader.mjs: exportsNOT_LISTED;createReadertakesisCreative(default() => false);catalogue(),open()andnext()hide a root for which it returns truthy.packages/conversation/tests/reader.test.mjs: three new tests, inserted before the "unknown conversations" test.agents/researcher/work/queue-220/BUILD.md: this file.
Nothing else is changed. node_modules in the worktree is a symlink to the canonical checkout and is ignored by git.
Brief and design items mapped to tests
| Item | Test |
|---|---|
| M7: a creative session file under the root isn't listed | "M7: a creative seat's session is not listed and won't open by id; an assistant seat still lists" |
M7: and won't open by id (conversation-not-listed) |
same test; second check of the open refusal in "M7: a creative session already open refuses its next page once the root is hidden" |
| M7: an assistant session still lists | same test (the sage seat is listed and opens with its text) |
| M7: an already-issued cursor stops once the root is hidden (my addition; the design's "won't open" implies it) | "M7: a creative session already open refuses its next page once the root is hidden" |
| M7: refused rows and the unsupported placeholder of a creative root are hidden too (my addition; the design hides "creative sessions", and a refused row or placeholder names one) | "M7: a creative root's refused files and its unsupported placeholder are hidden as well" |
Default behavior without isCreative is unchanged |
the existing reader suite; the default predicate returns false |
M8: discord check / discord run refuse discord-engine-not-allowed on a library business, and a mosaic-bus binding with tools |
none (not built, question 1) |
| M8: a pi binding on a business without a library still checks clean | none (not built, question 1) |
Every test's fixture text is CREATIVE-MARKER or a made-up assistant line. The M7 tests assert the marker is absent from the catalogue and refusal output.
Choices made in phase A
isCreative(root)is the reader's only input. The reader reads no business file. A truthy answer hides, so a doubtful answer fails closed. The predicate must depend onroot.seatandroot.projectonly, because a cursor is checked against the root object from an earlier listing.- Hidden check placed after the cursor's actor/purpose/conversation/branch checks in
next(), and before the source is read. open()checks hidden after the id resolves, so a creative id getsconversation-not-listed, and an unknown id still getsunknown-conversation.conversation-not-listedisreconcile: false. The design names no reconcile flag.unknown-conversationuses true. Question 3.- The default predicate is
() => false. Until a caller passes one, M7 does nothing. This is the open risk, and question 1 covers it.
Grep over packages/*/tests and scripts/test-*.sh (static, phase A)
Changed path packages/conversation/src/reader.mjs:
packages/conversation/tests/reader.test.mjs:14importsrootsFromSpecs, createReader, conversationId, cwdInProject, UNSUPPORTED_HARNESS. It is the file under change.packages/control-board/tests/serve.test.mjs:26importsUNSUPPORTED_HARNESS. That export is unchanged.packages/library/tests/sync.test.mjs:15importspackages/library/src/reader.mjs, a different file. Not a hit.scripts/test-*.sh: no reference to the conversation reader.- 64-hex pins naming this path: none.
packages/bus/tests/grant-migration.test.mjs:24has a 64-hex value, but it is a DDL digest, not a pin on this path. That file matched only the word "reader" in a test title.
Changed path packages/conversation/tests/reader.test.mjs:
- No other test or script names this file. It runs through
packages/conversation'snode --test tests/. - No 64-hex value in the file.
Changed path agents/researcher/work/queue-220/BUILD.md: no pin.
node --check passed on both changed .mjs files.
Phase B plan (not run)
The reader test uses os.tmpdir(). Set TMPDIR to a scratch dir first, per the rule against /tmp.
export TMPDIR="$(mktemp -d /mnt/storage/scratch/tmp/r220XXXXXX)"
cd packages/conversation && node --test tests/reader.test.mjs
cd packages/conversation && node --test tests/
cd packages/discord && node --test tests/
cd packages/control-board && node --test tests/serve.test.mjs
The first command is the touched file whole. The second and third are the conversation and discord suites whole, as the brief asks. The control-board serve test is not in the brief. It consumes reader.mjs, so I recommend it. Sage can drop it.
Questions for Sage
-
Business link (blocks M8 and the M7 wiring). Neither rule can be built from this row's file list, because the inputs don't exist in the code:
- A reader root carries
seat(the spec'sagent) andproject(the repo directory name). It has no business id. Roots come from control-board scan specs (packages/control-board/src/scan.mjs,discoverRepoAgents) and seat registrations. Neither carries a definition. - A Discord binding has
seatand no business key (packages/discord/src/binding.mjs,TOP_KEYS). - Creative status lives only in the business file:
roles.<instance>.definitioninCREATIVE_DEFINITIONS(packages/business/src/vocabulary.mjs:176). A library project isprojects.<id>.kind === "library"(packages/business/src/business.mjs:243). - Creative thread sessions are stored at
<dataRoot>/threads/<business>/<thread>/session(packages/seat/src/session.mjs:59-64), outside the.pi/stateroots the board scans. M7 may therefore reach only creative seats that have a.pi/statesession root. Please confirm. - The design does not define the mapping from a seat to a business.
Recommendation: add a required
businesskey to the binding, validated againstbusinesses/<id>.json. The board buildsisCreativefromloadBusiness(id): a root is creative when its seat is aroleskey whose definition is inCREATIVE_DEFINITIONS, and the business has a library project. This needs file scope forpackages/discord/src/binding.mjsandcli.mjs(M8), andpackages/control-board/src/serve.mjs(M7 wiring). None of those is on this row's list. I need that scope amendment and the mapping ruling before I build M8 or the wiring. - A reader root carries
-
M8 refusal code for a
mosaic-busbinding withtools. The design namesdiscord-engine-not-allowedfor the engine case and no code for the tools case. A new code goes to you first. My proposal is to reusediscord-engine-not-allowedwith a message that names the tools key. -
reconcileonconversation-not-listed. I chosefalse. Confirm or change. -
HTTP status for
conversation-not-listed.REFUSAL_STATUSinpackages/control-board/src/serve.mjshas no entry, so the route returns 422. My proposal is 404, next tounknown-conversation. This needs that file on the scope list too.
Phase A stops here. On your "slot clear" I will run the phase B commands above. I will not build M8 or the wiring until question 1 is answered.