launchpad: row 294 round 2 (#1800): browser.test pin gains /federation.js at index 2 (Mos mos-1412 (a)), G5 pins one action.refused {code: access-refused} per refused verb and every other table unchanged (sage-3194); manifest round 2 (18 paths), ASSERTION-PRESERVATION.json, run 1 receipts; unrun

This commit is contained in:
jason.woltje committed 2026-10-23 00:03:51 -05:00
1 parent 685ff053b6
commit 66c1817176
11 files changed
+139 -18

No files matched your search

@@ -0,0 +1,22 @@
{
"row": 294,
"round": 2,
"ruling": "mos-1412 (through sage-3195): option (a) approved, (b) rejected",
"changes": [
{
"file": "packages/webui/tests/browser.test.mjs",
"line": 21,
"kind": "comment",
"old": " // Rows 129, 154, 191 and 194: chat.js, editor.js, processing.js and agents.js are the scripts added, same origin; the list is the pin, so another script is a visible change.",
"new": " // Rows 129, 154, 191, 194 and 294: chat.js, editor.js, processing.js, agents.js and federation.js are the scripts added, same origin; the list is the pin, so another script is a visible change."
},
{
"file": "packages/webui/tests/browser.test.mjs",
"line": 22,
"kind": "assertion",
"old": " assert.deepEqual(await b.evaluate('[...document.querySelectorAll(\"script\")].map(s => s.getAttribute(\"src\"))'), ['/editor.js', '/processing.js', '/brand.js', '/app.js', '/markdown-preview.js', '/chat.js', '/agents.js', '/bus.js']);",
"new": " assert.deepEqual(await b.evaluate('[...document.querySelectorAll(\"script\")].map(s => s.getAttribute(\"src\"))'), ['/editor.js', '/processing.js', '/federation.js', '/brand.js', '/app.js', '/markdown-preview.js', '/chat.js', '/agents.js', '/bus.js']);"
}
],
"unchanged": "every other line of browser.test.mjs is byte-identical to c902a767d"
}
+42 -1
View File
@@ -204,7 +204,12 @@ and an in-process Broker with an access function, like bus/tests/user-principal.
routes, agents, processing, project files, /api/bus/message, /api/board), a user session gets
403 `owner-only` and the transport ran zero times.
- G5 the bus refusal stands alone: the same session's user transport, called directly with each
owner verb, gets `access-refused` from the broker and nothing is written.
owner verb, gets `access-refused` from the broker. The only write is the broker's own refusal
evidence: exactly one `action.refused` event per verb, the count taken from the verb list's length
(22 today), each body exactly `{ code: 'access-refused' }`, and every other table's row count
unchanged (round 2; run 1 placed the round 1 "events unchanged" pin as a test defect, sage-3194).
The broker's `#refused` (bus broker.mjs:4423) writes the code alone and no verb, so the test can't
match each event to its verb; pinning the whole body means a field added there shows up here.
- G9 the C6 seam (sage-3153, sage-3157), with the test's userOptions built by userOptionsFor as
cli.mjs builds them: a user session runs the chat's project list, thread create, list,
open, send and messages. The owner transport (a recording `ownerCall`) saw only
@@ -308,4 +313,40 @@ exception is accepted and does not go to Mos.
- N4: the user-bus.mjs fold-back (C7) is proposed to Sage as a queue row, for the next
channel-proof re-pin.
Round 2 (Mos mos-1412 through Sage sage-3195; for Duckworth): two test changes after run 1, no
product change. The manifest adds packages/webui/tests/browser.test.mjs (18 paths).
- Red 1, old test, Mos approved (a): browser.test.mjs:22 pins index.html's script list. It gains
'/federation.js' at index 2, where 294's index.html:7 puts it, ahead of brand.js. The :21 comment
adds row 294 and federation.js. No other assertion in the file changes. Old and new lines are in
ASSERTION-PRESERVATION.json. (b), loading the federation view another way, was rejected.
- Red 2, new test G5: the pin is the one in the G5 note above. Mos's suggestion is taken: the count
is `refusals.length`, not a literal. The verb check is not possible, because the event names no
verb; the test pins the whole body instead.
## Runs
### Run 1, 2026-10-23 04:57Z (sage-3187 CLEAR), head 685ff053b, manifest 0b3f9c9d…94f3
Before the run, the branch was rebased from 253346e3c onto c902a767d. `git range-diff -s` showed all 6
commits "=", and the stable patch-ids matched. The head was pushed as launchpad/row294-on-c902a767d
024499fc2. TMPDIR was under /mnt/storage/scratch/tmp. npm ci --ignore-scripts ran at the root only.
| Step | Result | Time | Limit |
|---|---|---|---|
| webui suite | 365 tests: 362 pass, 2 fail, 1 skip | 55.8 s | 600 s |
The driver stopped at the first red, so the cli, bus, scripts and mutants did not run. The slot was
returned (launchpad-0060).
- browser.test.mjs:22, an old test, pins index.html's script list. 294 adds `/federation.js` at
index 2. It went to Mos through Sage (sage-3192); I made no change before the ruling.
- G5:262, a new test, failed `22 !== 0`: the broker writes one `action.refused` per refusal. This
was placed as a test defect under mos-1272 and accepted by Sage (sage-3194). It is fixed in round 2.
- The skip was the editor rebuild check (editor-provenance.test.mjs:162), which needs esbuild
0.28.2 from packages/webui's own lockfile. An environment fix: the next run also runs npm ci
--ignore-scripts in packages/webui (sage-3194).
- The last landed whole-webui gate skipped the same test: row 264a's run, webui 345 pass of 346 with
1 skipped, "the esbuild 0.28.1 editor rebuild" (gizmoduck queue-264 BUILD.md:516-518, DEFERRED
264a N2). Row 270's gate ran only webui pinned-copy.test. The fresh 294 gate still runs npm ci in
packages/webui first, so the test should run here. If it skips again, the run names it and says why.
+21 -10
View File
@@ -1,15 +1,26 @@
# Row 294 (FED R6, #1800) candidate manifest, round 1
# Row 294 (FED R6, #1800) candidate manifest, round 2
Branch launchpad/row294, base 253346e3c, pushed tip 9450774cbe7986d80150b27a4da33b43d93bf026.
MANIFEST.sha256 lists the 17 code and test paths changed from the base, hashed from the tip's
blobs (`sha256sum -c` passes on the tip). BUILD.md is the row note and is not in the manifest.
No old test changes. webui/src/bus.mjs is byte-identical to the base (channel-proof hash pin, C7).
packages/cli/tests/access.test.mjs is unchanged; packages/cli/src/access.mjs overlaps row 295,
which rebases after this row (sage-3153).
Branch launchpad/row294, base c902a767d (the round 1 head ee77b3635 rebased with range-diff all "="
and stable patch-ids unchanged; receipts in run1/). The round 2 head is the commit that adds this
file. MANIFEST.sha256 lists the 18 code and test paths changed from the base, hashed from that
commit's blobs (`sha256sum -c` passes on it). BUILD.md, ASSERTION-PRESERVATION.json and run1/ are
the row note and are not in the manifest. webui/src/bus.mjs is byte-identical to the base
(channel-proof hash pin, C7). packages/cli/tests/access.test.mjs is unchanged;
packages/cli/src/access.mjs overlaps row 295, which rebases after this row (sage-3153).
Nothing has run. Runs follow Duckworth's approval and Sage's test CLEAR, in slot order: each
touched file alone, mutants M1-M11, the webui, cli and bus suites and every scripts/test-*.sh,
with the limits in BUILD.md.
Round 1 was 0b3f9c9d…94f3, approved by Duckworth (rev 3435, duckworth-0249b). Round 2 changes two
tests after run 1 went red, and no product file:
- packages/webui/tests/browser.test.mjs (new to the manifest; an old test, Mos's ruling (a) in
mos-1412): the script-list pin at :22 gains '/federation.js' at index 2 and the :21 comment adds
row 294. No other line changes. ASSERTION-PRESERVATION.json has the old and new lines.
- packages/webui/tests/granted-user.test.mjs, G5 (new test, a run 1 placement Sage accepted in
sage-3194): exactly one `action.refused` per refused verb, the count from the verb list's length,
each body exactly `{ code: 'access-refused' }`, and every other table's row count unchanged.
Run 1 (webui only, stopped at the first red) is recorded in BUILD.md. The whole gate runs fresh on
Sage's next CLEAR: npm ci --ignore-scripts at the root and in packages/webui, the webui, cli and
bus suites, every scripts/test-*.sh, then mutants M1-M11, with the limits in BUILD.md.
## Exception for Duckworth to rule on: the owner transport in a user's chat (C6; mos-1394, sage-3157)
@@ -14,4 +14,5 @@ e7673188c1d76ecc63cdc24e7d1470922b1d69bedeb994a862e94924edfc27d2 packages/webui
9343ea9edb862c1545df2886754244ffd76b714cc90d7791fc32aee4ecfec594 packages/webui/src/serve.mjs
70b243ed9a83ff822a4c7a148528ff5153574cc87d5c776fd2e12f340762ed76 packages/webui/src/sso.mjs
8cc1185beda9085ced62470f1b9e39d95dcca2dcc8bf9325c18c2f0b2da618dc packages/webui/src/user-bus.mjs
8f89a1cc853ad275e62a518eb4f5567b5aaa629d32060c11daaaa671aded29db packages/webui/tests/granted-user.test.mjs
58f022643839b78c0bd149927157d1f7b36977212975a4fe549c9661c31c4e40 packages/webui/tests/browser.test.mjs
8bf20e514817d21356e59ca21a8a99ee25609f084f4a26c5a409d71a90b6f6a4 packages/webui/tests/granted-user.test.mjs
@@ -0,0 +1,6 @@
4abc648140eef53c8cb841ae64c22afc4211d86b
bee007832071139bac9af318096710aeb95f1f79
6de7443b94d28676a42630986d86bac9de1479fb
f3ed47f0b12f628cdbf0efe66970e184eef74ae2
3cf8180c22ed655b4f163f7a35b06deb47b54493
d1689ae8ba689ab811560b5f8ae82d95cc745c3e
@@ -0,0 +1,6 @@
4abc648140eef53c8cb841ae64c22afc4211d86b
bee007832071139bac9af318096710aeb95f1f79
6de7443b94d28676a42630986d86bac9de1479fb
f3ed47f0b12f628cdbf0efe66970e184eef74ae2
3cf8180c22ed655b4f163f7a35b06deb47b54493
d1689ae8ba689ab811560b5f8ae82d95cc745c3e
@@ -0,0 +1,6 @@
1: c866a8a69 = 1: df21d2f4d launchpad: row 294 FED R6 build and plan, granted-user sign-in (unrun, #1800)
2: 338e93185 = 2: f392be6ac launchpad: row 294 rulings sage-3153 (boot refusal line, owner transport seam G9, C7 follow-up, access.test.mjs unchanged; unrun, #1800)
3: 77514b8b9 = 3: c22dcfdd0 launchpad: row 294 BUILD.md M4 kill names the moved test
4: 9450774cb = 4: 0622c2fc8 launchpad: row 294 sage-3157, owner-transport exception written out, userOptionsFor, G9 pins no user value, M10/M11 (unrun, #1800)
5: ca710eabd = 5: 65f1b81f3 launchpad: row 294 round 1 manifest (17 paths from 9450774cb) and notes with the owner-transport exception
6: ee77b3635 = 6: 024499fc2 launchpad: row 294 BUILD.md M1 expectation corrected (Duckworth C1), review recorded with N1-N4 dispositions
@@ -0,0 +1,3 @@
TMPDIR /mnt/storage/scratch/tmp/g8gFnfF head 685ff053b6336311668104d08826e923d9f4532d
webui rc=1 seconds=55.787 limit=600 04:58:35Z
STOP at webui
@@ -0,0 +1,13 @@
✖ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3039.999029ms)
✖ R6 G5 the bus refuses every owner verb over the user transport on its own (555.936822ms)
ℹ tests 365
ℹ suites 0
ℹ pass 362
ℹ fail 2
ℹ cancelled 0
ℹ skipped 1
ℹ todo 0
ℹ duration_ms 55747.039135
✖ failing tests:
✖ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3039.999029ms)
✖ R6 G5 the bus refuses every owner verb over the user transport on its own (555.936822ms)
+2 -2
View File
@@ -18,8 +18,8 @@ test('served Console browser: real board fixtures, keyboard, drafts, receipts, t
assert.equal(await b.evaluate('document.querySelector("#session-count").textContent'), '3 of 4');
await b.evaluate('document.querySelector("#hide-offline").click()');
assert.equal(await b.evaluate('document.querySelectorAll("table.sessions tbody tr").length'), 4);
// Rows 129, 154, 191 and 194: chat.js, editor.js, processing.js and agents.js are the scripts added, same origin; the list is the pin, so another script is a visible change.
assert.deepEqual(await b.evaluate('[...document.querySelectorAll("script")].map(s => s.getAttribute("src"))'), ['/editor.js', '/processing.js', '/brand.js', '/app.js', '/markdown-preview.js', '/chat.js', '/agents.js', '/bus.js']);
// Rows 129, 154, 191, 194 and 294: chat.js, editor.js, processing.js, agents.js and federation.js are the scripts added, same origin; the list is the pin, so another script is a visible change.
assert.deepEqual(await b.evaluate('[...document.querySelectorAll("script")].map(s => s.getAttribute("src"))'), ['/editor.js', '/processing.js', '/federation.js', '/brand.js', '/app.js', '/markdown-preview.js', '/chat.js', '/agents.js', '/bus.js']);
assert.equal(await b.evaluate(`document.querySelectorAll('script[src="/processing.js"]').length`), 1);
assert.equal(await b.evaluate(`document.querySelectorAll('script[src="/chat.js"]').length`), 1);
assert.equal(await b.evaluate('!!window.injected'), false);
+16 -4
View File
@@ -123,6 +123,9 @@ async function signIn(env, sub) {
return { r, session: sessionOf(r) };
}
const events = env => env.store.get('SELECT count(*) n FROM events').n;
// Every table's row count but events', for a "nothing else written" pin.
const tables = env => Object.fromEntries(env.store.all("SELECT name FROM sqlite_master WHERE type='table' AND name NOT IN ('events', 'sqlite_sequence') ORDER BY name")
.map(({ name }) => [name, env.store.get(`SELECT count(*) n FROM "${name}"`).n]));
test('R6 G1 a granted user signs in, gets the user page and reaches the broker as itself', async t => {
const env = await setup(t);
@@ -247,8 +250,8 @@ test('R6 G4 every owner route answers 403 owner-only before any bus call', async
test('R6 G5 the bus refuses every owner verb over the user transport on its own', async t => {
const env = await setup(t);
const o = consoleBus(env.userTransport('alice'), { send: true, owner: env.ownerCall });
const before = events(env);
for (const [why, run] of [
const before = env.store.get('SELECT max(seq) n FROM events').n, rest = tables(env);
const refusals = [
['inbox', () => o.bus.inbox()], ['tasks', () => o.bus.tasks()], ['agents', () => o.bus.agents()], ['trail', () => o.bus.trail()],
['decisions', () => o.bus.decisions()], ['instances', () => o.bus.instances()], ['routes', () => o.bus.routes()], ['thread.claims', () => o.bus['thread.claims']()],
['message.send', () => o.send({ to: 'chief', body: 'as the owner' })], ['limits.set', () => o.settingsWrite({ revision: 'x' })],
@@ -258,8 +261,17 @@ test('R6 G5 the bus refuses every owner verb over the user transport on its own'
['instance.launch', () => o.agentWrite('instance.launch', {})], ['processing.status', () => o.processing.read()],
['processing.halt', () => o.processing.halt({})], ['library.status', () => o.libraryStatus({})],
['project.create', () => o.chat.createProject({ name: 'mine' })],
]) await assert.rejects(Promise.resolve().then(run), e => e.code === 'access-refused', why);
assert.equal(events(env), before, 'a refused verb wrote');
];
for (const [why, run] of refusals) await assert.rejects(Promise.resolve().then(run), e => e.code === 'access-refused', why);
// The broker records each refusal (row 37): one action.refused per verb, its body the code
// alone (#refused names no verb). No other table gains or loses a row.
const added = env.store.all('SELECT kind, body FROM events WHERE seq > ? ORDER BY seq', before);
assert.equal(added.length, refusals.length, 'one event per refused verb');
for (const e of added) {
assert.equal(e.kind, 'action.refused');
assert.deepEqual(JSON.parse(e.body), { code: 'access-refused' });
}
assert.deepEqual(tables(env), rest, 'a refused verb wrote');
});
// sage-3153 (C6): in a user's chat the owner transport carries `plugins` with {} and nothing else,