sage: briefs for P19 380 (tester refusal, #1667, row 170) and P19 379 (project names vs repos, option B, #1668, row 171), for Mos's approval
This commit is contained in:
1 parent
42817065e1
commit
97cc7f0a32
2 files changed
+171
No files matched your search
@@ -0,0 +1,92 @@
|
||||
# Brief: a thread project named like a business-file repo
|
||||
|
||||
P19 379, Gitea #1668, queue row 171. This brief comes from Mos's finding F2 in the 8e7ea89a1 window (mos-0844) and
|
||||
Mos's ruling mos-0845 D1. Owner Rocko, reviewer Dewey, gate owner Sage. Line numbers are at origin/refactor 42817065e.
|
||||
|
||||
## Decision needed first: this brief departs from D1
|
||||
|
||||
mos-0845 D1 gave a go to the "one-registry design" in Sage's F2 recommendation: the bus lists the business file's
|
||||
projects in `project.list`, and `thread.create` accepts their ids. When Sage wrote that recommendation, Sage hadn't
|
||||
checked three things, and each of them is a reason against it:
|
||||
|
||||
1. PRD 1.2 (`docs/prd/mosaic-stack.md:726-730`) says the business file's `projects` key names git repositories to
|
||||
clone, while a REQ-ORG-2 project is the user's container for threads. Row 121 kept the two apart and linked them by
|
||||
`repo` (`packages/bus/src/broker.mjs:2244-2245`: "`repo` names a project from the business file; the rename to repos
|
||||
is a P19 follow-up").
|
||||
2. REQ-THREAD-2 (prd:673-678) has the user create projects from the CLI or the WebUI. Only Jason edits the business
|
||||
file, so if the business file were the registry, users couldn't create projects at all.
|
||||
3. `threads.project` is `REFERENCES projects(id)` (`packages/bus/src/migrations/3d-3e.sql:17`). Accepting
|
||||
business-file ids in `thread.create` would need a schema migration, a re-pin with `--migrate` and downtime.
|
||||
|
||||
Sage recommends option B below in place of D1's one-registry design. Mos rules on it. If Mos keeps D1, this brief gets
|
||||
rewritten as a schema and PRD change for Jason, and none of the B text below applies.
|
||||
|
||||
## Option B: keep the two apart and close the name trap
|
||||
|
||||
### The problem B fixes
|
||||
|
||||
The live store's `projects` table is empty, and the business file names `stack`. So:
|
||||
- `mosaic threads --project stack` and `mosaic thread create stack <name>` refuse "no project is named or numbered"
|
||||
(`packages/cli/src/thread.mjs:41-45`), which doesn't say why.
|
||||
- `mosaic project create stack` succeeds with no repo and makes a thread project called `stack` that has nothing to do
|
||||
with the `stack` repo (`broker.mjs:2246-2262`).
|
||||
|
||||
### The change
|
||||
|
||||
Bus, `project.create` (`broker.mjs:2246`):
|
||||
- If `a.name` is a key of the business file's `projects` (`b.projects`), the create needs `a.repo` equal to that same
|
||||
key. Otherwise refuse `project-name-is-repo`. `mosaic project create stack --repo stack` makes the thread project for
|
||||
the `stack` repo, and `mosaic project create stack` refuses.
|
||||
- The check comes after `unknown-repo` and before `project-exists`, and nothing gets written when it refuses.
|
||||
- Rows already in a store aren't checked again. The live table is empty.
|
||||
|
||||
CLI:
|
||||
- `resolveProject` (`thread.mjs:41-45`): when no store project matches and `ref` is a key of the business file's
|
||||
`projects`, the refusal says
|
||||
`"<ref>" is a repository in the business file, not a thread project yet; mosaic project create <ref> --repo <ref> makes one`.
|
||||
The CLI reads the business file with the `loadBusiness` that `packages/cli/src/project.mjs:1` already imports. If the
|
||||
file doesn't load, the old message stands, and the CLI does no other read.
|
||||
- `project create` prints the bus refusal as `"<name>" is a repository in the business file; add --repo <name> to make
|
||||
its thread project, or pick another name`, exit 2.
|
||||
|
||||
WebUI:
|
||||
- `packages/webui/src/bus.mjs` `STATUS` (:85-104) maps `project-name-is-repo` to 409. That file is pinned in
|
||||
`packages/bus/tests/channel-proof.test.mjs:18`, so the same diff updates the pin and adds a comment line, as rows 155
|
||||
and 165 did. The chat create form (`packages/webui/src/chat.mjs:19`) shows the bus code as it shows the others.
|
||||
|
||||
Docs:
|
||||
- `packages/cli/README.md` and the `project create` usage line (`project.mjs:12-13`) say that a thread project named for
|
||||
a repo carries that repo.
|
||||
- The PRD isn't edited. Its 1.2 bullet already allows keeping the two apart, and any PRD wording is Jason's.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Renaming the business file's `projects` key to `repos`. That's a business-file schema change, it needs Jason, and it
|
||||
gets its own P19 task if Mos wants one.
|
||||
- Any store migration, any edit to the live business file, and any run against the live stack.
|
||||
- `mosaic project init|check`, which works on repos on disk.
|
||||
|
||||
### Tests
|
||||
|
||||
Every item gets its own test, plus a mutant that removes the new check and fails it.
|
||||
|
||||
1. Bus: `project.create` with a name that's a business-file project key and no `repo` refuses `project-name-is-repo`
|
||||
and writes no row. With a different `repo` key it refuses the same way. With `repo` equal to the name it succeeds.
|
||||
2. Bus: a name that isn't a business-file key keeps today's behavior, both with and without `repo`.
|
||||
3. CLI: `threads --project stack` with an empty store and a business file naming `stack` prints the repository line,
|
||||
exit 2. With a business file that doesn't load, it prints the old line.
|
||||
4. CLI: `project create stack` prints the refusal line and exits 2.
|
||||
5. WebUI: `busStatus("project-name-is-repo")` is 409, and channel-proof passes with the new pin.
|
||||
|
||||
Run every changed test file singly before in-review, and grep the tests for the path and any 64-hex pin of each changed
|
||||
file.
|
||||
|
||||
### Acceptance
|
||||
|
||||
- Every test and mutant above.
|
||||
- The `packages/bus`, `packages/cli`, `packages/webui` and `packages/plugins` suites and every `scripts/test-*.sh`
|
||||
green on Sage's gate. The reviewer approves the candidate manifest.
|
||||
- The diff touches only `broker.mjs`, `packages/cli/src/thread.mjs`, `packages/cli/src/project.mjs`,
|
||||
`packages/webui/src/bus.mjs`, their tests, `channel-proof.test.mjs` and `packages/cli/README.md`.
|
||||
- The window plans keep reading `threads --business mosaic-stack --json` and expecting `[]` until this row lands and
|
||||
reaches the live stack by a re-pin.
|
||||
@@ -0,0 +1,79 @@
|
||||
# Brief: a tester message to a role nobody runs is refused, not queued
|
||||
|
||||
P19 380, Gitea #1667, queue row 170. This brief follows Mos's ruling mos-0845 D2, made on Mos's finding F3 from the
|
||||
8e7ea89a1 window (mos-0844). Owner Dewey, reviewer Filbert, gate owner Sage. Line numbers are at
|
||||
origin/refactor 42817065e.
|
||||
|
||||
## The problem
|
||||
|
||||
When nobody holds a role, a tester's `message.send` to that role is stored anyway, and the message waits for a claim
|
||||
(`#route`, `packages/bus/src/broker.mjs:2482-2485`). `#waiting` (:2495-2504) tells launch.by nothing about a
|
||||
tester's message, since a PM test authorizes nothing. So the message sits until the role is next launched, and then that
|
||||
run reads a stale test as its first input. The 8e7ea89a1 window did exactly this. Message 02f0e5d6
|
||||
(`[mos test] re-pin 8e7ea89a1`) is still queued for pm.
|
||||
|
||||
mos-0845 D2: a tester message to a role with nobody running is refused, not queued, and the refusal comes before the
|
||||
message is stored.
|
||||
|
||||
## The change
|
||||
|
||||
### Bus, `message.send` (`broker.mjs:1790-1872`)
|
||||
|
||||
- When the caller is the tester (`s.tester`), and after `#threadFor` (:1850) has picked the thread, refuse
|
||||
`tester-target-not-running` if `this.#recipient(s.business, to, thread)` is null. The refusal must come before the
|
||||
`INSERT INTO messages` (:1852). No messages row, no delivery row and no notice get written.
|
||||
- The lookup is the same `#recipient` that `#route` and `#waiting` use, so a run that is launched but hasn't claimed yet
|
||||
counts as no holder, as it does in `#waiting`.
|
||||
- A holder that releases between this check and the insert leaves the message waiting like any other message. The
|
||||
brief accepts that race and doesn't add a lock.
|
||||
- Human and agent sends don't change. A human's message to a stopped role still stores, waits and tells launch.by
|
||||
(row 146).
|
||||
- Update the `#waiting` comment (:2486-2494). Its "a tester's" case can no longer reach `#waiting` with no holder.
|
||||
|
||||
### CLI
|
||||
|
||||
- Leave `packages/cli/src/transport.mjs` alone. Row 164 freezes its bytes
|
||||
(`packages/bus/tests/channel-proof.test.mjs:13`), and its `EXIT` map sends an unlisted code to 2.
|
||||
- In `talk` (`packages/cli/src/cli.mjs:353`), the `catch` around the send (:377-384) turns a `--tester` send that the
|
||||
bus refuses with `tester-target-not-running` into
|
||||
`CliError("<role> isn't running, so the tester's message was refused and nothing was stored", 3)`. Exit 3 matches
|
||||
the other tester refusals (`tester-off`, `tester-refused`).
|
||||
- Remove the `!w.told` line in `waitingLines` (:342-343). The bus no longer returns a tester's message as waiting, and
|
||||
since row 85 the CLI and the bus run from the same tree (the human and tester proofs are path-bound), so no older bus
|
||||
can answer this CLI.
|
||||
- `packages/cli/README.md:130-131` and the `--tester` paragraph (:162-171) say the new behavior.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Message 02f0e5d6 and every other stored message. Any store edit waits for Jason (mos-0845 D2).
|
||||
- Expiry of messages that are already waiting.
|
||||
- Any change to the human's or an agent's send, to `thread.send` (the tester has none), or to the launcher.
|
||||
- Any run against the live stack.
|
||||
|
||||
## Tests
|
||||
|
||||
Every item gets its own test, plus a mutant that removes the new check and fails it.
|
||||
|
||||
1. Bus (`packages/bus/tests/tester.test.mjs`): a tester `message.send` to a role with no claim refuses
|
||||
`tester-target-not-running`. The `messages` and `deliveries` row counts don't change. No `_bus` notice is written.
|
||||
2. Bus: the same send succeeds and routes once a run holds the role with a claim. A launched but unclaimed run still
|
||||
refuses.
|
||||
3. Bus: a human `message.send` to the same stopped role still stores the message, returns `waiting` with `told: true`,
|
||||
and writes launch.by's notice. This is the row 146 behavior, unchanged.
|
||||
4. CLI (`packages/cli/tests/tester.test.mjs:130-136`, replaced): `talk --tester` to a stopped role exits 3, prints the
|
||||
refusal line, prints no `sent` line, and stores no message.
|
||||
5. CLI: a `--tester` send refused with any other code keeps its old message and exit, and a human send refused with
|
||||
`tester-target-not-running` (a stand-in transport) is not rewritten by the new branch.
|
||||
|
||||
One mutant deletes the bus check and must fail items 1, 2 and 4. A second deletes the CLI branch and must fail item 4.
|
||||
Run every changed test file singly before in-review. Grep the tests for the path and a 64-hex pin of each changed file.
|
||||
At 42817065e no test pins `broker.mjs` or `packages/cli/src/cli.mjs`, and `transport.mjs` stays untouched.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Every test and mutant above.
|
||||
- `packages/bus` and `packages/cli` suites and every `scripts/test-*.sh` green on Sage's gate. Filbert approves the
|
||||
candidate manifest.
|
||||
- The diff touches only `packages/bus/src/broker.mjs`, `packages/cli/src/cli.mjs`, their tests and
|
||||
`packages/cli/README.md`. `docs/TOOLS.md` has no tester talk line at 42817065e (its :431 covers only the switch).
|
||||
- The change reaches the live stack only through a later re-pin. This row doesn't schedule one.
|
||||
Reference in new issue
Block a user