6.4 KiB
Row 227, Case 2 C2-14: end-to-end acceptance on a scratch root (#1728)
Owner Gizmoduck (sage-3581, 10-23), reviewer Dewey, who also runs the script.
Brief: docs/plans/2026-10-20_case2-rows.md, section "C2-14 end-to-end acceptance on a scratch
root", read at 45dca69f6. Branch gizmoduck/row227 on 45dca69f6.
Files
scripts/test-case2.sh(new). The entry point: syntax check, one driver run, one counted line per step, an order check on the step ids, and a check that the made-up token is in no driver output.scripts/case2/e2e.mjs(new), its fixture. Every step runs in one node process, because her remote is row 199's fake Gitea over TLS with a scratch CA, and it lives only as long as the process that started it.checkMappingtakeshttps://remotes only (packages/library/src/mapping.mjs:46-48), so a plain file remote isn't an option.
The driver reuses the test fixtures already on refactor and adds none of its own:
packages/seat/tests/fake-gitea.mjs (scratchCa, fakeGitea) and packages/library/tests/helpers.mjs
(BASE, her layout's tree, MARKER, git, mappingEntry).
Two stand-ins
- The human.
human-cli.mjsproves a human shell and refuses any caller with an agent among its ancestors (packages/bus/src/human.mjs;packages/cli/tests/access.test.mjs:3-4,285-286pins the refusal). Dewey and I both run under an agent, so a shell driver of human-cli would refuse every human verb. The driver binds the human in-process withbroker.bindHuman, as the bus tests do (packages/bus/tests/library-sync.test.mjs:27). The bus checks after the bind are the real ones. - The fake harness. No launcher and no model. The driver binds the creative instance's run on her
thread (
bindLaunchwiththread), claims it, receives her message and answers in reply to it. That covers the thread routing and the companion's messaging lists (roles/companion.json), and leaves the launcher out. If Dewey wants the launcher in the path,fakeHarnesses(packages/cli/tests/helpers.mjs:133) is the way in. That is a bigger fixture, and I'd rather take it with C2-06's own fake harness (brief C2-06) than build a second one here.
Steps
The ids are the driver's. "Waits on" names every row whose code the step needs and that isn't on
refactor at 45dca69f6. A waiting step prints skip <id> waits on row <ids>: <text>, counted apart from
pass and fail. When its rows land, the step gets written and its skip line goes.
| Step | Brief text | State |
|---|---|---|
| S1a | bare repo in her layout | runs: classify on the fixture mapping (canon, manuscript, playground, unmapped, second universe) |
| S1b | with a supporting folder | waits on 283 (C2-01d, supporting folders and the editor field) |
| S2a | it syncs | runs: library.sync over https from the fake Gitea, served is her head |
| S2b | runs: library.file reads canon and playground at served, refuses an unmapped note project-read-path |
|
| S2c | runs: her fast-forward push is served by the next sync | |
| S2d | runs: the token is under no file of the data root, the mirror included | |
| S3a | asks a creative agent in its thread | runs: project, thread on instance bean (companion), thread.send |
| S3b | through a fake harness | runs: the fake harness receives it and its reply is stored in her thread, in_reply_to her message |
| S3c | stores a reply whose cites verify | waits on 216 (C2-05a lookups) and 217 (C2-06 guard and page store) |
| S4 | refuses a playground cite with "as": "canon" |
waits on 217 (playground-cited-as-canon) |
| S5a | holds a force-push as library-diverged |
runs: refused, served unchanged, diverged.commit is the forced tip, the refusal recorded |
| S5b | runs: accept of a stale commit refuses library-accept-stale, accept of the tip serves it |
|
| S6 | fixture-grant write, one commit with the trailer, notice in her thread | waits on 283, 285, 286, 288 |
| S7 | story-path write refuses library-write-story-path, ref unchanged |
waits on 283, 288 |
| S8 | her revert lands as one commit | waits on 288 |
| S9 | her library.file.save lands as one commit, her editor as author |
waits on 283, 288 |
| S10 | the Console renders the reply and the notice | waits on 220, 225 |
Row notes:
- Sage's in-flight list was 216, 217, 220, 225, 226, 283, 285 and 286. Rows 284, 287, 288 and 289 also
touch these steps, and the brief's "After" names the Q226 rows (told Sage in gizmoduck-0419). I mark
a step with the rows its code needs, not every row that touches it:
- 288 (C2-02) is the write verb, the notice, the revert and
library.file.save, so S6-S9 all name it. - 287 (C2-21, the grant executor) isn't named on S6, because the brief asks for a fixture grant.
- 284 (C2-05c) adds supporting docs to the lookups. S3c cites canon, so it waits on 216 and 217 only.
- 289 (C2-11b) is the Console library page. S9 is the verb, which 288 owns. If Dewey reads S9 as the page, 289 joins its list.
- 226 (C2-13, install script and precheck) gates no step. A scratch root isn't an install.
- 288 (C2-02) is the write verb, the notice, the revert and
- PRD 1.17 (row 308) made story files DOCX. The brief predates it and the fixture tree is Markdown. S1-S5 read that tree, which is what the landed reader takes. S6-S9 take the file shape 288 lands with.
Choices
- One driver process, not one per step: the fake Gitea's port and CA would change with each process, and the library entry's remote is fixed at bus start.
- The bus timer stays on with a one-hour period, since
startBrokerneedslibrarySyncto carry the CA'scommand. Its pass at start can hold the mirror, so a step's sync retrieslibrary-sync-busyfor up to about 10 s. - The refusal check opens the bus store read-only (
node:sqlite,readOnly: true). The runtime hands back no store, and no bus verb lists the events. - Git in the driver runs with
GIT_CONFIG_GLOBAL=/dev/nullandGIT_CONFIG_NOSYSTEM=1, so a caller's hooks, signing or credential helper can't reach it.helpers.mjsgitalready passes the identity andcore.hooksPath=/dev/null.
Carry for Dewey
- The launcher in the path waits for C2-06's fake harness (row 217). Sage accepted both stand-ins, labelled, in sage-3608. When 217 lands, S3b moves to its fake harness behind the launcher.
Not yet run
Darkwing's re-pin window holds the slot (sage-3581), so as of this draft no node ran on it: no
node --check, no driver run, no suite. bash -n scripts/test-case2.sh passes. The first run waits for
Sage's CLEAR, and the runs go below.