From 66c18171766ec35d2e84440bd4e62b13cc494dc9 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Fri, 23 Oct 2026 00:03:51 -0500 Subject: [PATCH] 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 --- .../queue-294/ASSERTION-PRESERVATION.json | 22 ++++++++++ agents/launchpad/work/queue-294/BUILD.md | 43 ++++++++++++++++++- agents/launchpad/work/queue-294/MANIFEST.md | 31 ++++++++----- .../launchpad/work/queue-294/MANIFEST.sha256 | 3 +- .../launchpad/work/queue-294/run1/pid-new.txt | 6 +++ .../launchpad/work/queue-294/run1/pid-old.txt | 6 +++ .../work/queue-294/run1/range-diff.txt | 6 +++ .../launchpad/work/queue-294/run1/summary.txt | 3 ++ .../work/queue-294/run1/webui-result.txt | 13 ++++++ packages/webui/tests/browser.test.mjs | 4 +- packages/webui/tests/granted-user.test.mjs | 20 +++++++-- 11 files changed, 139 insertions(+), 18 deletions(-) create mode 100644 agents/launchpad/work/queue-294/ASSERTION-PRESERVATION.json create mode 100644 agents/launchpad/work/queue-294/run1/pid-new.txt create mode 100644 agents/launchpad/work/queue-294/run1/pid-old.txt create mode 100644 agents/launchpad/work/queue-294/run1/range-diff.txt create mode 100644 agents/launchpad/work/queue-294/run1/summary.txt create mode 100644 agents/launchpad/work/queue-294/run1/webui-result.txt diff --git a/agents/launchpad/work/queue-294/ASSERTION-PRESERVATION.json b/agents/launchpad/work/queue-294/ASSERTION-PRESERVATION.json new file mode 100644 index 000000000..304d8f56d --- /dev/null +++ b/agents/launchpad/work/queue-294/ASSERTION-PRESERVATION.json @@ -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" +} diff --git a/agents/launchpad/work/queue-294/BUILD.md b/agents/launchpad/work/queue-294/BUILD.md index 3d784d5b3..8a2f8f935 100644 --- a/agents/launchpad/work/queue-294/BUILD.md +++ b/agents/launchpad/work/queue-294/BUILD.md @@ -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. diff --git a/agents/launchpad/work/queue-294/MANIFEST.md b/agents/launchpad/work/queue-294/MANIFEST.md index bdf9e1961..7ee2b51a8 100644 --- a/agents/launchpad/work/queue-294/MANIFEST.md +++ b/agents/launchpad/work/queue-294/MANIFEST.md @@ -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) diff --git a/agents/launchpad/work/queue-294/MANIFEST.sha256 b/agents/launchpad/work/queue-294/MANIFEST.sha256 index 641514c7b..b4b58e2dc 100644 --- a/agents/launchpad/work/queue-294/MANIFEST.sha256 +++ b/agents/launchpad/work/queue-294/MANIFEST.sha256 @@ -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 diff --git a/agents/launchpad/work/queue-294/run1/pid-new.txt b/agents/launchpad/work/queue-294/run1/pid-new.txt new file mode 100644 index 000000000..848872a53 --- /dev/null +++ b/agents/launchpad/work/queue-294/run1/pid-new.txt @@ -0,0 +1,6 @@ +4abc648140eef53c8cb841ae64c22afc4211d86b +bee007832071139bac9af318096710aeb95f1f79 +6de7443b94d28676a42630986d86bac9de1479fb +f3ed47f0b12f628cdbf0efe66970e184eef74ae2 +3cf8180c22ed655b4f163f7a35b06deb47b54493 +d1689ae8ba689ab811560b5f8ae82d95cc745c3e diff --git a/agents/launchpad/work/queue-294/run1/pid-old.txt b/agents/launchpad/work/queue-294/run1/pid-old.txt new file mode 100644 index 000000000..848872a53 --- /dev/null +++ b/agents/launchpad/work/queue-294/run1/pid-old.txt @@ -0,0 +1,6 @@ +4abc648140eef53c8cb841ae64c22afc4211d86b +bee007832071139bac9af318096710aeb95f1f79 +6de7443b94d28676a42630986d86bac9de1479fb +f3ed47f0b12f628cdbf0efe66970e184eef74ae2 +3cf8180c22ed655b4f163f7a35b06deb47b54493 +d1689ae8ba689ab811560b5f8ae82d95cc745c3e diff --git a/agents/launchpad/work/queue-294/run1/range-diff.txt b/agents/launchpad/work/queue-294/run1/range-diff.txt new file mode 100644 index 000000000..affc545f3 --- /dev/null +++ b/agents/launchpad/work/queue-294/run1/range-diff.txt @@ -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 diff --git a/agents/launchpad/work/queue-294/run1/summary.txt b/agents/launchpad/work/queue-294/run1/summary.txt new file mode 100644 index 000000000..5da968202 --- /dev/null +++ b/agents/launchpad/work/queue-294/run1/summary.txt @@ -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 diff --git a/agents/launchpad/work/queue-294/run1/webui-result.txt b/agents/launchpad/work/queue-294/run1/webui-result.txt new file mode 100644 index 000000000..600daa149 --- /dev/null +++ b/agents/launchpad/work/queue-294/run1/webui-result.txt @@ -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) diff --git a/packages/webui/tests/browser.test.mjs b/packages/webui/tests/browser.test.mjs index 1cb973169..20ffc6d37 100644 --- a/packages/webui/tests/browser.test.mjs +++ b/packages/webui/tests/browser.test.mjs @@ -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); diff --git a/packages/webui/tests/granted-user.test.mjs b/packages/webui/tests/granted-user.test.mjs index 7e1b08d12..4edf30412 100644 --- a/packages/webui/tests/granted-user.test.mjs +++ b/packages/webui/tests/granted-user.test.mjs @@ -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,