Whole-branch review by Fable, and what it changed — 0bab498
Done per AGENTS.md's highest-capability rule, read as one diff. It found one blocking problem, and it was not in this branch's code — which is exactly the class of thing a whole-branch review exists to catch and branch CI structurally cannot.
BLOCKING — the branch was stale, and the collision was semantic
origin/main had moved to cafb696 ("Impeccable pass") four seconds after this branch's previous merge point. cafb696 adds internal/docs/assets_test.go, whose TestExactlyOneEditorBundleIsEmbedded asserts static/ holds exactly one entry. This branch commits a second bundle.
Squash-merging as it stood would have put a red build on main — and no amount of green CI on this branch could have warned, because the failing test only exists on main. That is the argument for reading a branch against where it will land rather than where it started, stated better by an example than by the rule.
Merged, and the test reconciled rather than deleted. Its real job is not the number one: it is that static/ holds only the bundle build's output, because the tab icon was written there once and silently deleted by the gate's own cleanup — which is why it is a test and not a note. It is now "exactly one file per name in bundleKinds, and nothing present that no kind accounts for", which keeps the stray-file protection assets.go's registry cannot provide: the registry looks up names it knows and would never notice a third file nobody named. Verified by planting a stray file and watching it fail.
assets.go's conflict was both sides adding to the same two places — cafb696's icon serving and this branch's bundle registry. Both kept.
Fixed while in the files
- The palette hijacked IME composition keys. Mid-composition in Japanese, Chinese or Korean, Enter commits a conversion and Escape cancels it — so the palette navigated away while somebody was still typing the word they meant to search for, and closed when they tried to take it back. This app declares twelve base locales; that is not an edge case, it is most of them.
- A palette closed on "No documents match" reopened still saying it, over an empty query — and being a live region, announced the stale answer again.
- A catalog key nobody read (
docs.list.search.results). Twelve locales would have translated it for nothing.
One claim withdrawn
The plan's D4 said a browser-drive check holds the palette's keyboard contract. It does not. The checks exist and pass — seventeen of them — but in a scratch driver deliberately not committed, because the harness they belong in is on the other branch. What protects that behaviour today is one person having run it once, which is precisely what this repo does not count as a gate. The plan now says so.
Two comments citing an AGENTS.md entry that lives on the other branch now state their reasoning inline instead, so they hold whichever order the branches land in.
What the review checked and did not find
Scoping holds — owned() fails closed, the query string never reaches SQL, and the tests cover the store, the JSON route and the /?q= page route separately. Escaping holds on both surfaces. The ranking is deterministic. The assets.go invariant was generalised, not weakened. §6.4's spirit is respected: one field, one button, ungrouped ranked results, no filter chrome, and the no-JS path is primary.
Still yours
Tasks 20–22: the copy review, accent folding (cafe does not match café — a product decision, not a technical one), and folding the palette's checks into the shared harness.
Three non-blocking findings I have left alone deliberately, since each is a judgement rather than a defect: the 50-result cap truncates with no "more matched" signal; there is no NFC normalisation, so precomposed and decomposed forms of the same text do not match (rare, and distinct from the accent-folding decision); and an expired session makes the palette say "unavailable" rather than "sign in again".
— claude~paul@keymail.dev, session "checklist formatting and export"