Candidate patch (state verb, runner state block, header time, pm.md rule, fake-adapter fixture), six new harness tests, six mutants, full suite outputs, candidate manifest. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
75 lines
7.9 KiB
Markdown
75 lines
7.9 KiB
Markdown
# Row 109 (#1603) build notes
|
|
|
|
Researcher, 2026-10-13. Brief: `docs/plans/2026-10-13_pm-tester-and-fresh-state.md`, "A new PM run reads current launch state and task status before it plans". BASE: `02fe2d9d5` (origin/refactor after row 106 landed as `8b58cb7e4`). Reviewer: Filbert. Gate owner: Sage.
|
|
|
|
Candidate change: `row109.patch` (8 files: 7 modified, 1 new). Built and run in `/mnt/storage/scratch/researcher/q109`, detached at `02fe2d9d5`, `node_modules` linked to the canonical one. The patch applies to BASE; the packet is not in it.
|
|
|
|
## What ships
|
|
|
|
- `packages/bus/src/broker.mjs`: read verb `state`, no arguments, open to role, human and reader sessions (reader allowlist gains `state`). It returns `{launch:{state,at,event}, tasks:{open:[{task_ref,title}], total, cap}}` for the capability's business.
|
|
- `launch` is the latest `launch.revoked` / `launch.restored` event of the business: `state` `revoked`, else `allowed`; `at` and `event` are that event's time and id, null when no event exists (`allowed`).
|
|
- `tasks.open` is `#tasks(business,{done:false})`, so it is the tracker snapshot's open tasks, tombstones left out, in `task_ref` order, refs and titles only. The cap is the `tasks` page size (`TASK_PAGE`, 50), stated as `cap`; `total` counts every open task.
|
|
- Nothing is stored. No schema change.
|
|
- `packages/harness/src/runner.mjs`: before each turn the runner calls `state` and prefixes the turn request with `stateBlock(state, readAt)`: `Current state, read at <iso>:`, `Launches: ...`, `Open tasks: N[, the first K of cap C].`, one line per task. The read time is the runner's clock at the call. A failed read (anything but a dead session) fails that turn without running the adapter: the sender gets the usual RESULT `The turn failed: could not read the current state: <code>`, the failure is logged, and `message.read` still runs. A dead session (`SESSION_GONE`) exits as it does on `message.receive`.
|
|
- `turnRequest()`: the header gains `sent <at>` from the message row's `at`, after the sender and before the class.
|
|
- `roles/pm.md`: one rule in Protocol: the block is the truth for launch state and task status; a message or a note that disagrees is out of date; before planning to resume or launch work on a task, check it with `get_task`.
|
|
- READMEs: one table row in `packages/bus/README.md`, one paragraph in `packages/harness/README.md`.
|
|
- `packages/harness/src/tools.mjs` is untouched: `state` is not exposed as a tool; only the runner calls it.
|
|
|
|
## Fixture edit (accepted by Sage, rows 109 scope)
|
|
|
|
`packages/harness/tests/fixtures/fake-adapter.mjs` took the message body as everything after the first blank line of the request. The state block adds a blank line above the `Message ...:` header, which broke every TOOL/SLEEP/FAIL/NOMARKER test. It now takes the body after the `Message ...:` header line (regex), with the old split as fallback. This is the only reason for the edit; no other harness test needed a change. Every other test using the fixture passes in the full harness suite (79/79).
|
|
|
|
## Tests
|
|
|
|
- `packages/bus/tests/state.test.mjs` (new, 6): never switched reads `allowed` with null time and event; revoked then restored reads `allowed` with the restore event's time and id (and `revoked` with the revoke id in between); a task closed on the tracker leaves the open list and `total` drops; a tombstone is not open; the list stops at the cap and says so while `total` counts all; role and reader sessions read the same state, an argument refuses `invalid-request`, an unbound cap refuses `unauthenticated`.
|
|
- `packages/harness/tests/runner.test.mjs` (6 new tests, 20 in the file; harness suite 73 -> 79). By name:
|
|
1. `turnRequest shows the message's own sent time, a day old as well as new`
|
|
2. `stateBlock names the launch state with its time and event, and the open tasks with the cap`
|
|
3. `launches revoked and then restored: the turn's block reads allowed and gives the restore time`
|
|
4. `a task closed on the tracker is missing from the next turn's open list`
|
|
5. `a message read a day after it was sent shows the time it was sent` (the broker's clock jumps a day after the send)
|
|
6. `a failed state read fails the turn: no adapter runs, the sender hears why, the message is read` (no adapter turn file, RESULT with the reason, message read, log line)
|
|
|
|
My message to Sage before the gate run said five new runner tests. That was a miscount: it left out test 2, the `stateBlock` unit test, which I wrote as a unit test beside test 1. The suite count (+6) is the evidence. The existing first end-to-end test, `a message becomes a turn, the answer goes back as a RESULT, ...`, is changed, not new: it now checks the exact block and the header with `sent <at>`.
|
|
- The state block and the time are checked by the runner tests through the fake adapter, which echoes the request.
|
|
|
|
## Mutants (the kills)
|
|
|
|
`mutants.sh <worktree> <outdir>` runs one test file for the control and one per mutant, each mutant one exact-once text edit, and restores every source on exit. Outputs in `mutants/`; run summary in `mutants-run.txt`. `mutants/<name>.patch` is `git diff` of that file against BASE, so it also shows the candidate's own edits; the mutation is the one changed expression. The candidate was byte-identical to `row109.patch` after the run.
|
|
|
|
| mutant | edit | result | failing tests |
|
|
|---|---|---|---|
|
|
| control | none | runner 20/20, bus 6/6 | none |
|
|
| m1 | request is `turnRequest(m)`, no block | runner 17/20 | the first end-to-end test; "launches revoked and then restored"; "a task closed on the tracker is missing" |
|
|
| m2 | header drops `sent <at>` | runner 17/20 | the first end-to-end test; "a message read a day after it was sent"; "turnRequest shows the message's own sent time" |
|
|
| m3 | a failed read sets `block = ""` instead of failing the turn | runner 19/20 | "a failed state read fails the turn" |
|
|
| m4 | launch event read oldest-first | bus 5/6 | "launches revoked and then restored read allowed, with the restore time and event id" |
|
|
| m5 | open list built without the `done:false` filter | bus 5/6 | "a task closed on the tracker leaves the open list" |
|
|
| m6 | `cap` dropped from the output | bus 4/6 | the closed-task test and the cap test |
|
|
|
|
The `roles/pm.md` rule has no test; it is prose. Out of scope as the brief says: expiring old messages, tracker poller or `list_tasks` defaults, and who may switch launches.
|
|
|
|
## Suites (all in q109, output teed to `suites/`)
|
|
|
|
BASE `02fe2d9d5`; slot held 23:04:51Z to 23:08:36Z, "clear" sent; no process of mine left in q109.
|
|
|
|
| suite | result | Sage's gate count |
|
|
|---|---|---|
|
|
| `node --test packages/bus/tests/*.test.mjs` | 134 pass, 0 fail | 128 (+6 new) |
|
|
| `node --test packages/harness/tests/*.test.mjs` | 79 pass, 0 fail | 73 (+6 new) |
|
|
| `node --test packages/queue/tests/*.test.mjs` | 156 pass, 0 fail | 156 |
|
|
| `scripts/test-release.sh` | 14 passed, 0 failed | 14 |
|
|
| `test-auth` 15, `test-conductor` 17, `test-config` 24, `test-discord` 66, `test-extension-package` 18, `test-foundation` 44, `test-task` 98 | 0 failed each | n/a |
|
|
| `scripts/test-queue.sh` | 28 passed, 0 failed | n/a |
|
|
|
|
The `queue verify and render --check` case of `test-queue.sh` is skipped in a worktree (q109 is not the queue's canonical root `/mnt/storage/src/mosaic-stack`; Filbert's N3 from row 101). Sage's canonical-root gate rerun is the evidence of record. I did not apply the patch to or run suites in the canonical checkout.
|
|
|
|
## PM workspace (read-only)
|
|
|
|
`pm-workspace-names.txt`: the PM's persistent workspace holds one planning-notes file, `findings-2026-10-12.md` (7737 bytes, 2026-10-12T14:53Z), and `stack/`, a git checkout of the repository. Names only; no contents read. The note is a likely second source of the stale picture alongside old inbox messages; the pm.md rule covers it. The file is left alone.
|
|
|
|
## Scope and live
|
|
|
|
Owned files only, plus the accepted fixture. Live use needs a new copy and re-pin under Mos's go, with decision 109 notices before and after (runner.mjs reaches new role sessions at their next start; the broker verb needs a bus restart).
|