178 lines
12 KiB
Markdown
178 lines
12 KiB
Markdown
# Row 239 (#1745) build notes (append only)
|
|
|
|
## 2026-10-22 b1 (Honker)
|
|
|
|
Design d1 5da5f28f6 was approved by Duckworth with C1 and C2 and no blockers (duckworth-0165, note
|
|
agents/duckworth/work/row239/REVIEW-design-d1.md). The code is on honker/row239 from aca16404c. No test
|
|
has run yet: every run waits for Sage's CLEAR.
|
|
|
|
### Duckworth's conditions and answers
|
|
|
|
- C1 (option a): `outcome-unknown-revoked` is in the Console's `OPEN` list (webui bus.mjs), so
|
|
`sendOutcome` answers it as `outcome-unknown` with `sent: 'unknown'` and never "Nothing changed". T6
|
|
covers it and M3f is its mutant.
|
|
- C2: `write()` sets `revoked = true` after `beforeWrite()` returns, and a catch around the whole
|
|
`withLock(...)` call marks the error. So a throw from the lock's release in its finally is marked as
|
|
well. This is structural and has no test, as Duckworth said.
|
|
- Q1: `beforeWrite` runs after both validations. Q2: two codes. Q3: M2 removes the `:188` check (now
|
|
organization.mjs:195).
|
|
|
|
### Notes N1-N5
|
|
|
|
- N1: `beforeWrite` must not write the same business, because it would find its own lock and refuse
|
|
`organization-busy`. This is said in the comments on `write()` and `commit()`. Today's revokes (the
|
|
bus's credential revoke) write no business file.
|
|
- N2: the lock is held across the revoke. A fire or a delete now keeps other writers of that business
|
|
out for as long as the revoke takes. They refuse `organization-busy`, as they do for any held lock.
|
|
- N3: a revoke that fails partway (some tokens revoked, then `credential-revoke-failed`) behaves as
|
|
today. The error carries no `revoked` mark, because `beforeWrite` didn't return, and nothing is
|
|
written. This row doesn't change that.
|
|
- N4: a delete closed with `outcome-unknown-revoked` exits 3 in the CLI, as every closed refusal does.
|
|
Exit 1 (transport EXIT) applies only to a direct verb answer.
|
|
- N5: I grepped for "before the write" and similar comments. The ones left (lifecycle-revoke.test:2,
|
|
instance-settings:56, cli instances.mjs:53, serve.mjs:365) are still true and are unchanged. T21 in
|
|
bus lifecycle-revoke.test:173 is unchanged.
|
|
|
|
### Differences from the design
|
|
|
|
- The business tests are in lifecycle-settings.test.mjs, not instance-settings.test.mjs. The fire tests
|
|
and their fixture already live there. The fixture now returns `dir` and `rolesDir` too.
|
|
- T3 covers T3b (the delete) in the same test, looping over fire and delete. It also checks that a
|
|
revoke throwing `credential-revoke-failed` carries no mark and writes nothing.
|
|
- T4b is the plain-code check. The design's "T4b, outcome-unknown-revoked for an fs-style error" is in
|
|
T4, which checks EIO with and without the mark for both a fire and a delete.
|
|
- The bus test's fake org gets `deleteError`, thrown from its `instances.set` branch, so T4 can drive a
|
|
delete.
|
|
- transport.test gets one assertion, `busExit("outcome-unknown-revoked") === 1`, for M3g.
|
|
- A latent Console text: a direct (not closed-request) `revision-conflict-revoked` answer in the
|
|
Console would still get " Nothing changed." appended, because only `OPEN` codes skip it. That sentence
|
|
is true there: the file is unchanged. No direct human path gives this code today, since a delete
|
|
reaches the Console as a closed request's refusal.
|
|
- The Console's STATUS entry for `outcome-unknown-revoked` (503) can't be reached while the code is in
|
|
`OPEN`. It stays for symmetry with the CLI and is harmless.
|
|
|
|
### What changed
|
|
|
|
- packages/business/src/organization.mjs: `write()` takes `beforeWrite`, runs it under the lock after
|
|
the revision check and both validations, and marks any later error `revoked`. The body is reindented
|
|
inside the try.
|
|
- packages/business/src/instance-settings.mjs: `instanceSettings` takes an optional `writer`. `commit()`
|
|
passes `beforeWrite` to `writer.write` instead of calling it. The early check stays, and its comment
|
|
is rewritten.
|
|
- packages/bus/src/broker.mjs: `#organizationFail` maps a marked error to `revision-conflict-revoked` or
|
|
`outcome-unknown-revoked` before the existing mappings. `#fireJob`'s notice adds "Its credential
|
|
tokens may already be revoked." for a `-revoked` code.
|
|
- packages/bus/src/runtime.mjs: comment only.
|
|
- packages/cli/src/instances.mjs: two REASONS entries. packages/cli/src/transport.mjs: EXIT
|
|
`outcome-unknown-revoked` 1.
|
|
- packages/webui/src/serve.mjs: two AGENT_REASONS entries. packages/webui/src/bus.mjs: `OPEN` entry and
|
|
two STATUS entries.
|
|
- Tests:
|
|
- business lifecycle-settings.test: "row 239 T1", "row 239 T2", "row 239 T3".
|
|
- bus fire-revokes-grants.test: "row 239 T4", "row 239 T4b".
|
|
- cli instances.test: "row 239 T5 CLI". cli transport.test: one assertion in "busExit and
|
|
refuseInsideAgent".
|
|
- webui agents.test: "row 239 T6".
|
|
- bus channel-proof.test re-pins packages/cli/src/transport.mjs (662642a8...) and
|
|
packages/webui/src/bus.mjs (1eba9774...), with a comment on each. Neither changes a proof or the
|
|
transport. The design's file list missed this. The pin grep found it before the first run.
|
|
### Mutants for the gate (exact-once replacements)
|
|
|
|
- M1 (instance-settings.mjs, beforeWrite before the lock): replace
|
|
` const receipt = writer.write(business, next, { revision, actor, context, beforeWrite });` with
|
|
` if (beforeWrite) beforeWrite();\n const receipt = writer.write(business, next, { revision, actor, context });`.
|
|
The kill is lifecycle-settings "row 239 T1" (the revoke spy has a call).
|
|
- M2 (organization.mjs, the fire refusal dropped): delete the line
|
|
` if (revision !== before) fail("revision-conflict", "organization revision changed; read again");`.
|
|
The kill is "row 239 T1" (the write lands over the hand edit).
|
|
- M3a (organization.mjs, the mark dropped): ` if (revoked && e instanceof Error) e.revoked = true;`
|
|
becomes ` void revoked;`. The kills are "row 239 T2" and "row 239 T3" (business). T4 drives the mark
|
|
through a fake org, so it doesn't see M3a.
|
|
- M3b (broker.mjs): delete the line
|
|
` if (e.revoked) fail(e.code === "revision-conflict" ? "revision-conflict-revoked" : "outcome-unknown-revoked");`.
|
|
The kill is fire-revokes-grants "row 239 T4".
|
|
- M3c (cli instances.mjs): delete the five lines from ` "revision-conflict-revoked": "the business file`
|
|
through ` "business file again with \`mosaic business instances\` before trying again",`. The kill is
|
|
instances.test "row 239 T5 CLI".
|
|
- M3d (webui serve.mjs): delete the two lines starting ` 'revision-conflict-revoked': 'the business file`
|
|
and ` 'outcome-unknown-revoked': 'the agent\'s tokens`. The kill is agents.test "row 239 T6".
|
|
- M3e (broker.mjs): ` const tokens = code.endsWith('-revoked') ? ' Its credential tokens may already be revoked.' : '';`
|
|
becomes ` const tokens = '';`. The kill is "row 239 T4".
|
|
- M3f (webui bus.mjs, C1): the `OPEN` line loses `, 'outcome-unknown-revoked'`. The kill is "row 239 T6"
|
|
(the launch POST answers 503 outcome-unknown, sent unknown).
|
|
- M3g (cli transport.mjs): delete the line ` "outcome-unknown-revoked": 1,`. The kill is transport.test
|
|
"busExit and refuseInsideAgent".
|
|
|
|
A kill counts only as a failed assertion in the named test, not a load error or a different test.
|
|
|
|
### Gate plan (mos-1275 timeouts)
|
|
|
|
- My row 256 gate (2026-10-22 10:34Z, same machine) took 590s for the cli package, 57s for webui and
|
|
38s for test-foundation, the longest shell script.
|
|
- Packages: `timeout -k 10 1800` per package (3x the cli run).
|
|
- Each scripts/test-*.sh: `timeout -k 10 300` (more than 3x the 38s longest).
|
|
- Single files and mutants: `timeout -k 10 600` per file run (cli instances.test whole is the longest
|
|
single file).
|
|
- Order on Sage's CLEAR: the touched test files whole (business lifecycle-settings, bus
|
|
fire-revokes-grants and channel-proof, cli instances and transport, webui agents), then M1-M3g, then
|
|
the full gate.
|
|
- Before the in-review move: grep packages/*/tests for the changed comment and error text and for
|
|
64-hex pins on the changed files, and drift-check BASE..refactor against them.
|
|
|
|
## 2026-10-22 r2 rebase (Honker)
|
|
|
|
- Duckworth approved b1 b0c28366f statically, with no blockers (duckworth-0168). On N1 (`endsWith('-revoked')`
|
|
would also match `access-revoked`, which can't reach a fire job today), the check stays as it is, so the
|
|
approved candidate doesn't change before the gate (honker-0163).
|
|
- Rows 253 (48e450ce8) and 275 landed. b1 is rebased onto refactor 94c33a43c as honker/row239-r2. The
|
|
push branch honker/row239 isn't rewritten.
|
|
- Drift between aca16404c and 94c33a43c on the 15 paths: only packages/bus/src/broker.mjs, where row 275
|
|
changes the viewer verbs. Neither of row 239's two hunks (`#fireJob` and `#organizationFail`) moves in
|
|
meaning. The rebase applied with no conflict. The two pinned files (cli transport.mjs, webui bus.mjs)
|
|
and channel-proof.test have no upstream change, so the b1 pins stand.
|
|
- Each M1-M3g replacement string still matches exactly once.
|
|
- The touched test files run whole again on the new base, in the slot (the rebase rule).
|
|
|
|
## 2026-10-23 r3 rebase (Honker, sage-3730)
|
|
|
|
- r2 (70c6e3772) is rebased onto refactor 93694c518 as honker/row239-r3. honker/row239-r2 isn't rewritten.
|
|
- Between 94c33a43c and 93694c518, five of the 16 paths changed upstream: bus broker.mjs and runtime.mjs,
|
|
channel-proof.test, and webui bus.mjs and serve.mjs. Every file merged on its own except channel-proof.test,
|
|
where row 301 (59f0e44f4, mos-1449) re-pinned webui bus.mjs for the user transport fold. The merged
|
|
pin keeps row 301's comment and row 239's, and takes sha256 e3f52172…1c2a89 of the merged bus.mjs.
|
|
The transport.mjs pin (662642a8…6e55b) still matches the file.
|
|
- Row 239's hunks in broker.mjs (`#fireJob`, `#organizationFail`), runtime.mjs (the revoke comment),
|
|
bus.mjs (OPEN, STATUS) and serve.mjs are unchanged apart from their position. The range-diff shows
|
|
only the channel-proof pin and the hunk context moved.
|
|
- Each M1-M3g replacement string still matches exactly once. M3f's target is the whole `OPEN` line,
|
|
since `, 'outcome-unknown-revoked'` also appears in the STATUS line.
|
|
- No 64-hex pin in packages/*/tests or scripts names a changed file except channel-proof.test.
|
|
- On the CLEAR (sage-3730): the touched files whole, then M1-M3g, then the counts here. Sage runs the
|
|
full gate on the replay at landing.
|
|
|
|
## 2026-10-23 r4 replay and the slot run (Honker, sage-3773 CLEAR)
|
|
|
|
- On the CLEAR, refactor was 546366f4a (row 320 landed at 094124b4e). None of the 16 manifest paths changed
|
|
between 93694c518 and 546366f4a. Upstream did change library src/index.mjs, which bus runtime.mjs imports,
|
|
and business src/index.mjs, which the cli imports, so the run was on a replay onto 546366f4a rather than
|
|
on r3's base. That replay is honker/row239-r4 0cae2dad5. The range-diff of r3 against r4 is four `=`
|
|
lines with equal patch-ids, so duckworth-0292's read of r3 applies to r4. r3 isn't rewritten.
|
|
- The run was on 0cae2dad5 with a clean tree, TMPDIR under /mnt/storage/scratch/tmp, 22:01:27Z-22:01:52Z.
|
|
- The touched files, run whole: business lifecycle-settings 12/12, bus fire-revokes-grants 24/24, bus
|
|
channel-proof 2/2, cli instances 15/15, cli transport 3/3, webui agents 9/9. That's 65/65 with 0 skipped,
|
|
and no first-run red.
|
|
- Mutants: 9 of 9 killed. Each was applied exactly once, and each made its named test fail as an assertion:
|
|
- M1 lifecycle: 3 fail (T1, T2, T3).
|
|
- M2: T1.
|
|
- M3a: T2 and T3.
|
|
- M3b fire-revokes-grants: T4.
|
|
- M3c instances: T5 CLI.
|
|
- M3d agents: T6.
|
|
- M3e: T4.
|
|
- M3f agents: T6.
|
|
- M3g transport: "busExit and refuseInsideAgent".
|
|
|
|
T4b passed under M3b and M3e. Every restore matched the HEAD blob by sha256, and the tree was clean
|
|
after the run.
|
|
- No full gate (sage-3730): Sage runs it on the replay at landing.
|