Files
jason.woltje 158205c5cc lead: commit darkwing's untracked evidence (348 files: queue-137 queue-141 queue-150 queue-162 queue-165 queue-166 queue-167 queue-169 queue-179 queue-180 queue-181 queue-182 queue-185 queue-186 queue-187 queue-188 queue-190 queue-93)
Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
2026-11-02 15:05:14 -06:00

8.8 KiB

Row 167 (#1664): Settings page reads and snapshots after Q169

Owner: Darkwing. Reviewer: Filbert. Gate owner: Sage. Brief: docs/plans/2026-10-18_settings-reads-after-q169.md. Base: 81f26551b. origin/refactor is 0434ecfef, and git diff 81f26551b 0434ecfef touches only docs/SESSIONS.md. Worktree: ~/darkwing-scratch/r167/wt.

Files

File Change
packages/webui/src/public/bus.js items (a) and (b), +15/-11
packages/webui/tests/settings-form.test.mjs three tests: (a) and two of (b)
packages/webui/tests/limits-browser.test.mjs the :54 flip, its comment, and the (b) reset test
packages/webui/tests/assistant.test.mjs the F1 null-body test
this packet

public.diff is the public/ part alone, for Mos's decision 123 go. File sha256 1110e2e80cd4880c2fd7b683035f270fec48bf278a8982140c38fa6478adb556. The +/- digest is grep '^[+-]' public.diff | grep -vE '^(\+\+\+|---) ' | sha256sum, which gives 82a8a810686282942833b667c18f6ecb758aa485ec4a386c13684c35950ce984 over 26 lines.

No server file changes, and no route, write or wording changes. TOOLS.md stays as it is.

Items

(a) The names read rethrows. settingsView (:733) now catches the names read the way it catches usage, limits and instances. A 403 or signed-out is thrown on, so the page gets the refused view ("Bus refused the read", forget() clears the kept reads). Any other failure stays local, and the Assistant section shows the empty name field with "The current name could not be read."

(b) One snapshot. assistantSnapshot is gone. settingsSnapshot holds the launch settings for the launch form, the token-limit reset and the Assistant section.

  • takeSnapshot(value) (:565) replaces the snapshot only when it is empty or no form has a draft. A draft is settingsInputs set or any key in assistantDrafts (launchDrafts, :564). The launch form and the Assistant section both read through it.
  • The launch save (:591), the assistant save (:670) and the reset (:613) set the snapshot from their answer, drafts or not. The reset used to do that only with no launch draft open.
  • The reload button (:588) clears the snapshot, so the next read takes the current settings.
  • assistantPayload (:646, :657) builds from settingsSnapshot.

Drafts stay per form, so typed values survive a new snapshot. The launch payload sends the snapshot's models plus its own inputs, and an assistant or reset answer carries the launch fields unchanged, so a launch draft's full send doesn't overwrite another form's write.

Tradeoff: while any draft is open, both sections render from the frozen snapshot, not from a newer read. A write from elsewhere (another tab, the CLI) still ends in revision-conflict, which keeps the draft and asks for a reread. That is row 155's behavior for foreign writes.

(F1) Null bodies. One test in assistant.test.mjs posts null to /api/name and to /api/assistant-stop in turn. Each gets 400 invalid-request with sent:false, makes no bus call, and the valid request that follows is answered and makes its one call. Every assertion carries the route as its message, so a failure names the route. The brief asks for one test per route; this is one test that covers both, each route on its own lines. If Filbert wants two test() calls I'll split it. It passes on row 155's code, as the brief expects, since it pins body()'s check.

For Dewey and row 126: limits-browser.test.mjs

Row 167 changes this file in two places, and row 126 changes it too. Whichever row lands second rebases.

  1. The REQ-LIMIT-3/4 test. The comment at :41-42 now reads "A draft typed before the reset stays, and its save carries the revision the reset returned (row 167)." At :54, assert.equal(save.revision,'a'.repeat(64)) becomes 'b'.repeat(64). The brief says every successful reset sets the snapshot from its answer, so a launch draft open across a reset now saves with the reset's revision b. Row 155 kept a.
  2. A new test at the end of the file (:64-85, after the REQ-LIMIT test's closing });): 'Row 167 with an assistant draft open, a token limit reset gives the assistant submit its revision'. Nothing else in the file changes.

Shell pins

shell.test.mjs pins the POST fetch(...) expressions, the count of method: (6) and the first arguments of assistantPost(. Row 167 changes code on the two lines that hold the settings fetch calls, but not the expressions. I ran the test's three regexes over row 155's bus.js (931a32d7f0d1) and the candidate's (c2a0dffc54df), and the output is byte-identical, so shell.test needs no change. That check evaluates the regexes directly. The test itself runs on Sage's gate. No test pins a hash of public/bus.js or names the snapshot variables.

Out of scope: P19 369

The instance form from row 165 keeps its own revision. A settings save while an instance draft is open, or the reverse, still ends in revision-conflict. Sage made that P19 369 for a later row, which will need its own decision 123 go (sage-0968).

Runs

All on Sage's slot (sage-0968), the three touched files run singly with the spec reporter, TMPDIR ~/darkwing-scratch/r167/tmp. Totals come from the awk sum over the logs.

Run Tree assistant settings-form limits-browser Total
cand-20261019T002107Z candidate 6/6 5/5 2/2 pass 13, fail 0
base-20261019T002118Z 81f26551b with the candidate's tests 6/6 2 pass, 3 fail 0 pass, 2 fail pass 8, fail 5

Each base failure is the intended mismatch. The names test waits for "Bus refused the read" and times out. Both settings-form snapshot tests and the new reset test post a where b is expected. The REQ-LIMIT test fails the :54 flip (a for b). The F1 test passes on base, as the brief says it will.

Mutants

~/darkwing-scratch/r167/mutants.py, out mutants-20261019T002338Z. Each mutant is one exact edit to bus.js, run against all three test files. bus.js was restored and sha-checked after each mutant (c2a0dffc54df at the end), and the sweep found none of my processes left.

Mutant Edit Killed by
M1 the names catch swallows a 403 and signed-out settings-form: the names test
M2 takeSnapshot always replaces limits-browser: REQ-LIMIT (:54) and the reset test
M3 the reset sets the snapshot only with no launch draft limits-browser: REQ-LIMIT (:54)
M4 the assistant save doesn't set the snapshot settings-form: limits draft, assistant save
M5 the launch save doesn't set the snapshot settings-form: assistant draft, launch save
M6 launchDrafts ignores assistantDrafts limits-browser: the reset test
M7 the !settingsSnapshot clause is dropped settings-form: assistant draft, launch save (reload step)
M8 reload keeps the snapshot settings-form: assistant draft, launch save (reload step)

8 of 8 killed.

Candidate manifest

candidate-manifest.sha256:

c2a0dffc54dfe98b9b1ac1315879fc370e1c15135b931fc15791b07e17d854e7  packages/webui/src/public/bus.js
3223914f9419e1c256cc706a07f64223b7502c455c53e376f6e6c6ac72b287f0  packages/webui/tests/assistant.test.mjs
52c8763573dce256ac38c18310ca05ab9304ee9e4e830e2cfb4e139f7b4a005a  packages/webui/tests/limits-browser.test.mjs
cf7fa330d979b9ee253ac5099f3a2532bac79604bf389a1c68fcc454a94cc3bf  packages/webui/tests/settings-form.test.mjs

build.patch sha256 f022d1bca934fc9b2c4d889b24c29d97dab6542e846a1477357b5b40a67c9cfc.

Full webui singles (mos-0836 condition 1)

On the slot Dewey handed over (dewey-0661), ~/darkwing-scratch/r167/singles-all.sh ran all 38 webui test files on the candidate, each one alone. Out dir all-20261019T002730Z. The awk sum gives pass 231, fail 0, skipped 1. The skip is editor-provenance's rebuild test, which needs esbuild 0.28.2 where the canonical node_modules has 0.28.1. The skip comes from the environment and predates this row. shell.test passed 5/5. The mutants ran again on the same slot (mutants-20261019T003056Z) and all 8 were killed. Afterwards the candidate files matched the manifest.

Status

Mos gave the decision 123 go on public.diff 1110e2e8 with +/- digest 82a8a810 (mos-0836, relayed in sage-0976). The go holds on three conditions: the full webui singles and the mutants green (done, above), reviewer approvals, and the digest unchanged at landing. Any later public/ change goes back to Mos with its delta. Mos's F1 is that assistantPayload throws a raw TypeError when a save answer lacks the open form's instance. Row 155 had the same exposure. It is P19 370 and no part of this row.

Filbert is the only reviewer. sage-0979 corrected sage-0976, which had named Dewey too. Round 1 went in-review at rev 1915. The request is comment 29060, the candidate manifest digest is dba383306a9e7d71f03af8e1da45b4fbb7542e22555fb156aa0c064d8adf59cc, and comment 29061 cites the mos-0836 go.