Commit Graph

130 Commits

Author SHA1 Message Date
Claude (bookkeeping2) 745d179402 docs(context): correct Model::over's file, the staged unit count, what moves seen, and who catches a panicking turn
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-10 22:33:51 -07:00
Claude (bookkeeping2) 482f7178d1 docs(context): bookkeeping for ADR 009 steps 4-7, zset rollback, threads, edges and the scheduler
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-10 22:24:53 -07:00
Edward Langley 0b261165d1 docs(context): the dirty flag is per-effect; only the record tier uses the batch delta
Also record the improvise-command to improvise-gp and improvise-gp to improvise-core edges.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-10 15:49:04 -07:00
Edward Langley 1bd665a754 docs(context): bring the repo map, gotchas and kb up to ADR 005/009 crates
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-10 15:28:08 -07:00
Edward Langley 16f40314fd docs(context): act on the adversarial review of the repo-map split
- AGENTS.md: "Three files" is now "These files"; the table lists five.
- Digests 43 and 45 regain the traps the review found missing.
- protocol.md and formula-and-io.md cite file-inventory.md for the Wasm
  appendix and the inventory, which moved there.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 22:23:59 -07:00
Edward Langley f0119a437d docs(context): condense repo-map to a digest; move gotchas and inventory to their own pages
repo-map.md was 173 KB (~43k tokens), too long to be part of every new
agent's context. The full gotcha text moves verbatim to context/gotchas.md
and the per-file inventory (with the old Wasm/CLI/Testing sections) to
context/file-inventory.md; the map keeps a one-or-two-line digest per
gotcha under the same numbers, so every `gotcha N` citation still resolves.

The doc-site manifest publishes the two new pages, and `gotchas` gets the
same gotcha-N anchors as `repo-map`.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 21:13:55 -07:00
Claude (bookkeeping) 91d9925494 docs(context): name the tests that guard the registry's name literals
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 23:21:49 -07:00
Claude (bookkeeping) 942888e0dc docs(context): correct gotchas 15 and 16 and drop the duplicate 8jk6.6 kb fact
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 23:15:02 -07:00
Claude (bookkeeping) dd1bf96e00 docs(context): fix the inventory rows and stale text the review blocked #334 on
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 23:07:47 -07:00
Claude (bookkeeping) 1da2695f1f docs(context): repo-map and kb bookkeeping for felo.13, 31oe.2/.3, 8jk6.3/.6 and stale-text fixes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-10-02 22:57:38 -07:00
Edward Langley c673fa3b61 docs(context): record #303, #304 and #307 in the repo map
The cap is 24 with one home, the grid width is one derivation shared by
draw and keypress, and the import wizard asks about colliding records.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 20:14:48 -07:00
Edward Langley 95d4814bd1 docs: record ADR 007 in the repo map and kb
Add ADR 007 (stable identities, accepted 2026-09-25 on PR #210) and the
missing ADR 004 to the repo map's context-docs list, noting that no ADR
005/006 file exists. Add decision(improvise-sboz, ...) for clause 12:
a formula edit's display names are mapped to ids when the editor opens.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 17:49:20 -07:00
Edward Langley d25efa2a0f docs: #300 review fixes — fdk1 clause, stacked-PR rule, run: shell scope, §7 heuristic, fifteen not sixteen
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 15:19:59 -07:00
Edward Langley 78e2676451 docs: bookkeeping for PRs #229-#299 (2026-09-24)
AGENTS.md and the wave skill: Copilot reviews again and is answered like
Codex; check baseRefName before merging a stacked PR; land a batch as one
integration PR; never resolve with --ours/--theirs, diff against both
parents; a clean merge of one test file can still fail together; CI takes
its tools from the .#ci dev shell; watch open ADR PRs; fmt-workspaces must
not be piped; Playwright serves the assembled harness/serve/.

repo-map: gotchas 1, 3, 18, 19, 38, 42, 44 and 47 brought up to gh/main
(view-named record resolution and Grids, nested group runs and remark,
the fold's spanned narrowing, uneditable/NonItem, the browser editor's
opened cell, NEEDS_THE_HOST, notify/settle_status); recounted the wire
vocabulary (28 model effects, 26 ModelCommand variants); File Inventory
line counts refreshed at c1772ca9; the median-binary ratio is degenerate.

kb.pl, through scripts/kb: 19 new facts; five stale ones replaced (the
checker's bash pin, the nix-shebang premise, the Copilot lapse, the
dev-shell environment, the fmt pipe).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 15:04:19 -07:00
Edward Langley 810398e4a4 docs(kb): the TUI composed-row rule, and a trap in our own remote topology
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
PRs #145/#149. New gotcha 50: `fill_line` takes a `Keeps` because the three
rows sharing a line disagree about which side yields, and the one key table on
screen is the one derived from the keymap — with the import wizard as the
deliberate inverse, since its derived line comes from the mode keymap while
the real keys are per-step.

AGENTS.md gains the remote trap, and it is the orchestrator's fault: briefs
said "merge `main`", and because `origin`/`gitea` take `main` directly while
GitHub gets branches, `origin/main` runs ahead of `gh/main`. An agent doing
the habitual thing pulled four unmerged commits — another PR's whole diff —
into a branch based on `gh/main`. Nothing in CI can see it; the result
compiles and passes. Codex caught it. The window is transient, which makes it
worse: the hazard is absent exactly when you would think to check.

Closes improvise-t14d, improvise-rr8n and improvise-vgp4 — the last
stale-open, fixed by 94a3d17 two days before it was filed.

Measured on main at 78a7bbf: 1700 passed / 0 failed / 7 ignored over 38
binaries, longest single binary 0.69s. kb_consistent: TRUE, 792 facts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-22 19:01:31 -07:00
Edward Langley 755e3477c5 docs(kb): drill decomposition, aggregate scope, and a closed ticket read as open
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
PRs #140/#141. Gotcha 27 gains the one home for what a virtual view must BE
(`view::{records_spine,records_steps,drill_steps}` as data; `cmd/grid.rs::
steps_into_active_view` as the TUI's translation). Gotcha 44 gains the
finding: `RecordHash` is document-scoped and `AggregateHash` is layout-scoped
and cannot be otherwise, so `App::resolve_aggregate` answers only where the
host stands — that, not ADR 001 layer 2, is what blocks browser drill.

Gotcha 29 described improvise-lltt as an open gap. It is CLOSED, and verified
so: every view-scoped `ModelCommand` carries `view: String` and `model_effects`
maps it to `ViewTarget::Named`. A closed ticket cited as an open gap is the
mirror of a dead ID — it reads as a promise that work remains.

improvise-gd28 closed by REMOVING its dependency on improvise-7b8v rather than
forcing past it: the dependency encoded the premise #141 disproved. Files
improvise-t0ma, improvise-obtu, improvise-t219.

kb_consistent: TRUE, 788 facts. Dead-ID audit: 360 ids, all resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-22 18:38:51 -07:00
Edward Langley db6593b1b2 docs(kb): gotcha 40 was stale in three sentences (improvise-ilvl)
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
The replay audit found `layout_version` documented as bumping "per
`ModelChange::LayoutGeometry` effect". It does not: `observe_reshape` diffs
`view_shapes` before and after the batch and bumps only where a view's shape
actually moved, so an idempotent `set-axis` bumps nothing. The source comment
at `apply_effects` has said so since improvise-pdvm; the repo map was the
stale copy, and it said the opposite in three sibling sentences — the
parenthetical, the "both tiers are read off the `EffectKind`" claim, and the
"bumps inside the loop" claim, which is also false (it runs once, after).

The observed form subsumes the gotcha 21 argument rather than restating it:
an aborted batch moved no shape, so there is nothing to not-claim.

Also files improvise-6uva (P1) and improvise-up8g, and records the audit on
improvise-ilvl. kb_consistent: TRUE, 783 facts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-22 18:27:02 -07:00
Edward Langley 3be1653385 docs(kb): the session's rulings, deferrals and doctrine
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Records the campaign's accumulated facts: the Pages-tracks-main ruling, the
reserve-space-do-not-fit-it rule behind the header stability work, the
decimals-by-default decision and its grammar placement, and the doctrine
learned from this session's failures — a ready ticket may already be fixed,
a prose count is checked by no one, a clean merge is not a tested merge.

kb_consistent: TRUE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-22 18:23:34 -07:00
Edward Langley 06f847bb66 docs: four more stale facts in repo-map, found by the h3y7 audit
An audit that had to read the code to answer a completeness question kept
tripping over the map. Each of these is a fact the map states that the tree
does not support, verified before applying:

- gotcha 3 said model_effects sends 28 ModelCommand variants. A brace-matched
  count of the enum's top-level variants returns 24. Same staleness class as
  the gotcha 38 arithmetic corrected in the previous commit.
- gotcha 43 named `reduce_full` twice in the present tense. It has been DELETED;
  `reduce_key` is the survivor. Note the paragraph's own argument PREDICTED
  this ("no production caller anywhere in the workspace, so pub(crate) would
  have made it dead code") -- so the deletion vindicates the reasoning and
  falsifies only the tense. Recorded that way rather than quietly renamed.
- the File Inventory's counts for ui/reduce.rs (1411 -> 1080), ui/effect.rs
  (2731 -> 3034) and resolve.rs (2477 -> 2765) had drifted, two of them by
  more than the 10% the inventory's own preamble warns about.
- "50+ effect types" is now 58, with the number that matters recorded beside
  it: a brace-match over `impl Effect for` in effect.rs finds only 49, missing
  8 simple_effect! expansions and SetTransientPrefix in command/keymap.rs. All
  9 it misses are ViewOnly -- the half the ViewBack bug lived in. gotcha 38
  warns that the naive awk OVER-reports; the brace-matcher it recommends
  instead UNDER-reports, and nothing said so until now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 21:48:33 -07:00
Edward Langley 5a3d1d1109 docs: gotcha 38's own arithmetic was stale in the same way (Codex P2)
The paragraph's head says 26 model effects and 24 ModelCommand variants; its
tail still said "29 - SwitchView - these two = 26", which subtracts SwitchView
and forgets ViewBack/ViewForward. So the corrected gotcha contradicted itself
and the enum's own variant count.

Verified independently before applying: a brace-matched count of ModelCommand's
top-level variants in improvise-protocol/src/reduce.rs returns 24.

Worth noting what this is: the correction landed in the same commit range as the
sentence it contradicted, which is exactly the "one copy of an argument updated
and not its siblings" failure gotcha 48 names. A paragraph about a derivation
going unchecked for completeness had its own sum go unchecked.

Found by ChatGPT Codex reviewing PR #116.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 21:47:32 -07:00
Edward Langley 05a3e3f490 docs: gotcha 38 said ViewBack left for a reason that was false
It claimed ViewBack/ViewForward were excluded from the wire as session-local
residue, like ApplyAndClearDrill and AcceptWizardModel. But view_back_stack IS
in ViewState -- the portable slice -- so by the view half's own derivation rule
they were always Commands and were simply MISSING.

The cost was a live divergence: effect::SwitchView pushes the leaving frame
while reduce_view's arm set active_view and nothing else, so no client ever had
a back history. That, not the drill commit the declined() comment blames, is why
view-back was dead in a browser.

Found by the agent on improvise-gd28 (PR #115) while checking the derivation for
COMPLETENESS -- it had only ever been checked for correctness.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 19:32:38 -07:00
Edward Langley 132728d269 docs: the sync-access-handle premise is dedicated-worker-only
Two agents' findings, filed and recorded.

Gotcha 28 read as though "a browser worker" were one thing. Measured in a
module SharedWorker on Chromium and Firefox, createSyncAccessHandle is ABSENT
-- getDirectory and getFileHandle both succeed and the method is not on the
object -- so a SharedWorker cannot host OpfsFs and the synchronous Storage
trait rests on a narrower premise than the paragraph stated. OpfsFs::open's
own guard does not enforce it either: it dyn_into's WorkerGlobalScope, which
a SharedWorkerGlobalScope satisfies.

Also adds web/shell.js and web/serial.js to the File Inventory. shell.js holds
gridPlan/frameCostOf/documentTitle, so some of the browser's render decisions
are no longer in the file gotchas 42 and 46 name.

Beads filed: g3no i0v9 uej8 s8h7 lut7 wk18 0ygd hs0u pcje 7xyx 7gip 12ha

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 13:41:33 -07:00
Edward Langley 532c7f2405 docs: the gotcha-44 gap list named two closed tickets as open
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
improvise-h0iv and improvise-1wl0 are both fixed — group_runs coalesces by
header identity via ptr::eq, and AxisFrame::first carries no serde(default),
its doc comment saying why. The repo map listed both as 'still open beside
it'. Verified against the code before correcting.

That is the second time this exact paragraph has done it, and
doctrine(a_stale_list_of_what_is_missing_is_worse_than_no_list) was written
about its previous instance — by me, two days ago, after which I committed
the next one. A list of what is missing decays in the one direction that
reads as a to-do.

Also files the bug-hunt findings. Six hunters over six territories produced
five P1s, every one demonstrated rather than reasoned:

  dy3j  a Label category is not persisted, so a document with 12 categories
        plus a label can NEVER BE REOPENED
  o9uq   in records mode edits someone else's record and can rename it
        away — silent data corruption from a documented key
  pv3g  fit-measure panics on large finite values; a hard crash in the TUI
  bd9o  the browser reaches records mode through the tile bar, and everything
        it can do there is silent
  (plus the P2 set: prune_empty never persisted, the browser drawing neither
   page bar nor totals, two prune_axis_items group bugs, an inline-edit
   commit addressing the current cache while the screen is frozen)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 13:26:29 -07:00
Edward Langley e7c63e9530 kb+docs: strengthen the check, do not settle for correcting the prose
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Three facts from Wave N's Codex round.

The first is the one that generalises. improvise-26dm's round 1 found its OWN
defect — the right-hand side of a completeness diff was a second hand-written
list, not the derived enumeration its prose claimed — and shipped an honest
correction of the prose. Codex asked for the fix instead and was right: the
disclosure was accurate and still the weaker artefact, because the fix was
four lines of plumbing. Correcting prose is the fallback, not the deliverable.

Two traps, both of which caught someone:

cfg(test) and pub(crate) are different walls, and only one is a visibility
keyword. The follow-up said 'pub(crate) -> pub' — filed by the agent that
wrote it and repeated by me when I authorised 'one token' — because both of us
read the item line and not the attribute above it.

And cargo tree shows DEV edges by default, so asking whether a new feature
leaked serde_json into the wasm bundle reports it PRESENT. --edges normal
reports 0. I verified both readings myself. Same class as the difftastic grep
trap: a command that looks like it answers the question, answering a
neighbouring one, in the direction that reads as a finding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 10:44:05 -07:00
Edward Langley 40ce4bcbee docs: the map pointed at the wrong file, and that manufactured a false claim
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Root cause of PR #91's blocker 1, and it was mine. The row 'Change what a
browser resolves without the host' named improvise-wasm-client/src/keys.rs.
That file is 187 lines holding only BrowserKey — a KeyboardEvent flattened to
an improvise key. The resolve function and KeyOutcome live in
improvise-protocol/src/resolve.rs and are shared by both front ends.

So the author consulted the map, opened the file it named, grepped it
honestly, and wrote a true-and-irrelevant negative claim into context/ — the
one place design-principles §6 says a reason must not be wrong, because
nothing can find it later. A stale pointer does not merely fail to help. It
manufactures confident false claims, because the reader has done exactly the
work the map told them to do.

The whole wasm-client inventory block was stale with it: keys.rs listed at
1597 lines against an actual 187 with a description of what resolve.rs does,
render.rs 669 against 888, socket.rs 444 against 289, lockstep 606 against
1126 — and state.rs listed at all, when ClientState moved to
improvise-protocol/src/client.rs. My earlier line-count refresh missed every
one of them for the reason I documented at the time: the wasm-client/
shorthand prefix resolves to no path, so a path-walking refresh skips the
block silently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 04:25:30 -07:00
Edward Langley 27399b6a28 kb+docs: prose that calls a change free is a claim, and it is checkable
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Wave K's own prose said improvise-zv8t cost nothing — "no document that
fitted before stops fitting" — reasoning that a tree splitting on a numeric
category was refused as an artefact anyway. False: the refusal is conditioned
on used_features, so a fit that never split on the column SUCCEEDED, and the
wide columns are exactly the ones a fit has least reason to split on. Measured
with a throwaway probe on both sides. The sentence sat one paragraph below the
"permanent refusal" claim the previous wave had just corrected, in the same
section, green on either reading.

So prose_that_calls_something_permanent_forecloses_the_ticket has a sibling. A
cost claim is as checkable as a permanence claim and is checked the same way:
construct the document the claim says does not exist. Filed improvise-e8no for
the cost, with a note not to close it by making the forcing conditional on
cardinality — that is inference by another name.

The branch's own adversarial round found a bug the branch introduced: forcing
by column NAME while budgeting by column INDEX, and a document may legally
name a category and a measure the same thing. Repaired as a data dependency
rather than a moved line, so the injection is a compile error.

GridLayout::new has now caused FOUR bugs. improvise-iot6 was the last
production instance — every remaining call site is test code, which I verified
rather than took on report: two of them sit inside cfg(test) blocks well below
the module head and neither was named in the hand-back.

Suite re-measured here: 1464 over 35 binaries, 1 ignored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 04:10:12 -07:00
Edward Langley 3e3ebec25a kb+docs: an injection that does not fail names an untested path
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Five facts from Wave J. The one worth reading is the first: check_the_checker
is written as "inject the fault and watch it fail", and the case where it
PASSES is the more informative result, because it is evidence about the test
rather than about the code. On improvise-sihr, forcing
ReturnToNormalUnlessMoved alone back to Normal left the characterization test
green — which is how the untested path was found. An empty colon line takes
ExecuteCommand's is_empty branch and settles through ChangeMode, so the effect
settling every colon line that actually runs had no test. There are two tests
rather than one because of it.

Also records why ChangeMode could hide the bug at all: it was a simple_effect!,
which declares a one-field newtype writing one place, so there was nowhere for
a rule to live and the exit mode had to be a constant in the keymap and in
each commit command. Gotcha 16 already warns the macro's kind argument must be
mandatory; this is a second cost of the same shape.

And that improvise-9c9o's ticket pre-diagnosed its own fix as a protocol
change, and was wrong — the basis is App's own bookkeeping, so it was achieved
by moving where the re-base happens. A pre-diagnosis is a hypothesis wearing
the authority of a decision.

Inventory: three protocol files were absent entirely — help.rs (925),
client.rs (255) and resolve.rs, which at 2477 lines and 46 tests is the
largest file in the crate.

Filed improvise-e5pf: Command::ChangeMode(Normal) is on the wire and
reduce_view folds it without the records resolution. Latent — keys.rs emits no
ChangeMode and a view-half command never reaches the host's slice, both
verified rather than assumed — and closeable only by enriching the projection.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 04:06:44 -07:00
Edward Langley ada16d211a kb+docs: the Pages artifact is reaped by a foreign successful deploy
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
improvise-864a diagnosed over all 100 push-to-main runs rather than the three
the ticket named — and the three-run framing was mine, a sampling artefact
that made a two-day, sixteen-failure pattern look like a concurrency race
between queued deploys. 12/12 artifact-not-found failures had another run's
SUCCESSFUL deploy complete inside their own upload-to-deploy window, against
2/56 successes.

The decisive observation was a negative one already sitting in a log: a run
seeing its own harness-serve and wasm-bundles but not its own github-pages.
Same run, same token, same call, same retention — which kills flakiness,
eventual consistency, retention, token scope and a v3/v4 mismatch together.

One clause of the ticket's own correction is falsified: PR #46's guard aimed
at the right quantity for the wrong reason. It still must not ship, because
the association is not a mechanism and one run survived a foreign deploy in
its own window.

improvise-ijql closed additive. The author argued against the precedent I
pointed it at and was right: a provenance line qualifies an answer the run
gave, a disclaimer qualifies one it did not, and exit 0 is what CI branches
on. The rule is now stated over the exit code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 22:24:32 -07:00
Edward Langley 7df602de18 docs: no effect calls reset_cursor now, and two beads from the #78 review
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Gotcha 24 rewritten. Since improvise-ni6k the cursor is invalidated by
OBSERVING the grid's frame in apply_effects, inside the loop; no effect calls
reset_cursor at all, where this paragraph said thirteen did two days ago and
two before that. Total over EffectKind::Model(_) by construction rather than
by a maintained list — but totality is conditional on classification, and
nothing makes classification total.

Records the two-arm asymmetry and why it exists: narrowing the CellData arm
to one view measured as free and silently lost a multi-client invalidation.
The absolute is stated beside the ratio.

Two beads filed from the re-review, neither blocking the merge:

improvise-iot6 (P2) — render_csv builds GridLayout::new, so CSV export writes
rows the view prunes. FOURTH instance of that trap and the first in
production a user can see; reachable from :export and the CLI, and none of
export.rs's three tests mentions pruning, which is why it has been shipping.

improvise-9c9o (P2) — a geometry effect immediately after a mid-batch
SwitchView skips the check entirely. Passes on pre-PR main and on round 1,
fails at the merged head. Under-reporting, which gotcha 35 says is the
expensive direction.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 22:17:06 -07:00
Edward Langley 1ba2d839ed docs: improvise-8shu closed, and its diagnosis was the wrong half
The ticket blamed an unbounded grammar walk. Instrumenting the halves
separately: load_grammar() x1000 = 2.50s against a 15.7ms walk, so the walk
was 0.6% of the cost and improv_file() was re-parsing improv.pest once per
generated case. A OnceLock took improvise-io's lib from 1.42s to 0.21s with
the strategy's input space unchanged; constraining it would have moved 15.7ms
and shipped as the fix.

Re-measured here rather than taking the hand-back's figure, which differed:
1445 tests over 34 binaries, longest single binary 0.6-1.0s across two runs on
one machine. That spread, on one machine in one sitting, is its own argument
for reading your own run.

Also corrects the repo map's bug-fix workflow line, which said to document a
bug in the test's doc comment — the two-line comment cap forbids exactly that
and design-principles §7 says the opposite. A fact stated twice, changed by an
edit rather than a grep.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 22:14:25 -07:00
Edward Langley 862bd0371a kb+docs: a leaf is not an identity, and the CI graph is a gate
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Facts from PR #83, including two that replace text I had not yet applied —
the earlier phrasing said evidence names are "leaf names", which the merged
work makes wrong.

The finding worth carrying is one the review did not contain and the author
found while fixing it: NEITHER HALF SUFFICES. Refusing an ambiguous leaf does
not survive a rename — rename one of a colliding pair and the leaf is unique
again and resolves silently to the survivor. Qualification is the fix; the
refusal is only what forces someone to write it. Verified here independently:
un-qualifying the cited heading exits 1 naming both candidates, restoring it
exits 0.

improvise-ijql is NOT closed. The docs half is done, but line 1010 still
early-returns on the flag, so --check-evidence still selects rather than adds
and still says nothing about the cap it skipped. Recorded on the ticket with
the two candidate shapes.

Filed improvise-sxsf: `cargo test -- --list` does not name the binary, so two
crates sharing a module path remain indistinguishable. Not reachable today,
not guarded, and "verified latent" ages the moment anyone adds a crate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:52:02 -07:00
Edward Langley 38a270ac70 docs: the door is Sessions::apply_checked, and close 26 landed tickets
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
improvise-ahdf. Gotchas 36 and 43 named Sessions::apply as the production
door. It is not pub, it delegates to apply_checked after Checked::against,
and its only call sites are tests — Host calls apply_checked. Verified by
reading the signatures rather than the prose: apply at project.rs:878 has no
pub, apply_checked at :887 does. design-principles.md §5 already said
apply_checked, so the repo map was the stale copy of a fact stated twice.

Two of the four remaining mentions were live claims and are corrected; one is
historical ("demonstrated against ... before removal") and stands, and one is
the new sentence saying apply is not pub.

Also closes 26 tickets whose fixes are in merged main, each verified against
the code or against an evidence entry rather than against a PR body. Left
open deliberately: h074 (reported half-done), s17o (a decision in #78's
ground), mcq4 (fixed to 1.9x, residual documented), lltt (P1, detector only).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:44:32 -07:00
Edward Langley 95839fce43 docs: gotcha 49 for the origin check, and the inventory is a dated snapshot
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
Gotcha 49 records improvise-kc7n: a websocket handshake is exempt from the
same-origin policy, so no network control can see cross-site hijacking — an
IP allow-list, a private network and loopback binding all answer "may this
client reach the endpoint" and the honest answer is yes. Loopback is the
least protected case, not the safest. Records why all three arms are decided
rather than defaulted, and that none of it is authentication.

The File Inventory line counts were audited: 26 of 61 resolvable entries had
drifted past 10%, several by a third. Refreshed, and relabelled as a dated
snapshot with the method, because false precision in a carefully-checked
document is worse than an obvious estimate. Two traps found while doing it,
both recorded: a path-walking refresh resolves a bare name like lib.rs
against the first matching crate and rewrites the wrong number, and the
ws-server/ entries use a shorthand prefix no such walk resolves at all.

The code-review skill's gate list now runs BOTH spellings of
check-comment-runs.py. The flag selects rather than adds, so --check-evidence
never runs the comment cap and does not say so; three separate agents hit it
in one campaign (improvise-ijql).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:36:29 -07:00
Edward Langley 1351ecc9b8 kb: five facts from PR #82, and the negative arm's own anti-vacuity guard
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
PR #82 disproved the replacement claim this orchestrator had handed its
author, not only the original: of the four prepare steps documented as
"the reason the test is not vacuous", only DeleteView and ShowItem are.
ToggleGroup::apply toggles collapse unconditionally — the membership check
gates only reset_cursor — and TransposeAxes' step restates a precondition
View::on_category_added already establishes. Verified against the source
before recording.

Also records the detector half of the N-1-guarded-edits shape, named by
the PR #79 reviewer: a comment explaining why something is correct is weak
evidence that anything checks it, and the more carefully argued the
comment, the more likely it is standing in for a test. Five instances
across two independent reviews.

The two new keys are dated slugs rather than improvise- ids, because bd
issued none. An ID-shaped non-ID is worse than a dead id: the diagnosis is
identical and the repair is not.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:23:06 -07:00
Edward Langley 381a2f55d3 docs: the two thirteens differ in both directions, and my own awk proved why
Verifying the correction before merging it found the claim true but
understated. The reset_cursor set and the LayoutGeometry set are both
thirteen and differ THREE EACH WAY: CreateView, DeleteView and
SetNumberFormat declare the kind and never reset; AddItem, AddItemInGroup
and RemoveItem reset while declaring CellData, because adding or removing
an item renumbers the grid even though the change is data.

The naive awk over LayoutGeometry reported fourteen, picking up
HelpPageSet — the exact artefact this document already warns about two
paragraphs away, walked into while writing the correction. That warning
is now attached to the derivation it applies to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:17:31 -07:00
Edward Langley 2afbf37b67 docs: correct two stale gotchas, and record the N-1-guarded-edits shape
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
repo-map gotcha 24 named TransposeAxes and CycleAxis as the only effects
calling reset_cursor, and listed nine others as renumbering the grid without
resetting. improvise-9mo9 closed that the day before: all of them reset,
thirteen in total, SetPageSelection conditionally. The paragraph named as
absent the exact set that was by then present, so it read as a survey of
outstanding work. Re-derived by brace-matching impl Effect blocks, and the
derivation is published beside the list so the next reader can re-run it
rather than trust it.

gotcha 44's group_of sentence said "nearest preceding header ... changing
that means changing AxisEntry and is filed, not smuggled in". improvise-gd83
landed that change in PR #77: AxisEntry::GroupEnd exists and group_of answers
membership. Names the two that are still open beside it, h0iv and 1wl0.

Three doctrines added. The one worth the space is
name_the_test_that_fails_when_only_this_edit_is_reverted: three independent
reviews in one wave found the same shape, a repair of N edits where N-1 are
guarded and the last carries a careful comment instead of a test — and the
unguarded edit is reliably the one the author understood best.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:11:56 -07:00
Ed Langley 6b4689443c Merge pull request #45 from fiddlerwoaroof/docs/orchestrator-doc-pass
docs: correct two stale gotchas, and an assertion message that lied
2026-09-20 14:01:43 -07:00
Edward Langley ddfc06ed66 docs: follow the active_view split through repo-map and kb.pl
The batched instruction-file edits owed by improvise-jytm (PR #48), applied now
that it has merged. Text supplied by the WU-E agent and audited before applying:
97 ticket IDs across both files, all resolve.

repo-map gotcha 29 is replaced entirely — the two copies of "which view is
active" are now ALLOWED to differ, and the gotcha said the opposite. Gotcha 36's
`apply_switch` half is inverted: it now takes a `SessionId` and is addressed to
exactly one session, where the paragraph said its taking no SessionId "is the
statement". Gotcha 38's counts move 29 → 26 model effects and 28 → 24
ModelCommand variants, and its `ViewBack`/`ViewForward` sentence is deleted for
being wrong on all three clauses. Gotchas 3 and 44 gain a clause each.

One paragraph needed more than a correction. Gotcha 36's `ToOthers` trap
describes a mechanism this PR deletes — but the lesson outlives the mechanism,
so it is rewritten in the past tense with the two rules that survive: assert the
`Broadcast` ITSELF, because the audience is the message rather than something to
infer from folded state; and seat a bystander where a wrong relay can move it
FROM, because a bystander already on the relayed value cannot see a wrongly
WIDENED audience — the wrong relay folds to a no-op. Review demonstrated that
vacuity twice on #48, in tests whose evidence file had stated the risk in one
sentence and claimed the assertion covered it in the next.

kb.pl: four clauses replaced, two added. `lockstep_binds_every_session_not_the_asker`
changes shape rather than wording — active_view was the example that taught it
and is now out of its scope, so what remains under it is the document half and
the doctrine becomes a test for whether a value is shared AT ALL before it is a
test for who hears about it.

The addition worth reading is `an_injection_that_did_not_compile_reads_as_a_clean_run`,
caught by #48's reviewer in its OWN tooling: a grep for `^error[` that misses a
bare `error:` turns a failed compile into a green read — the defect injection
exists to catch, one level up in the instrument. The rule is deliberately not
"widen the grep", since a pattern can always be one case short: require a
POSITIVE signal that the injected build ran. A count cannot be silently empty.

Counted before and after, on the predicate that has been silently wiped before:
doctrines 55 → 56, decisions 47 → 48, invariants 51 → 51. kb_consistent exits 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 11:55:35 -07:00
Edward Langley 86fd5dcb2a docs: bindings.rs and web/worker.js are run, and five places said otherwise
Found by adversarial review of PR #47; I verified the chain rather than taking
it. shell.spec.js's "the standalone deployment" loads the app with no ?ws=,
which spawns the worker (app.js:112), which imports the glue (worker.js:4),
which calls bindings.rs::start (:30) and OpfsFs::open (:35) — and the spec then
asserts a grid draws and a cell is editable. So the whole chain has executed
under Chromium in CI since improvise-vvl3 landed the harness.

Five places claimed it never runs: gotcha 45, the File Inventory line, two
kb.pl facts, and improvise-bck's grooming note. Two of those are corrected here;
kb.pl goes with the wave-end batch, and the bead belongs to the WU-P agent.

Every copy was written before the harness landed and none was re-read after —
gotcha 48's rule ("when a fact is stated in more than one place, changing it is
a grep, not an edit") aimed at exactly this and did not fire, because nobody
grepped for a claim they had no reason to doubt.

The sharper lesson is in the gotcha now: a "never run" written in prose is
unfalsifiable by any check this repo has. kb.pl's CI gate verifies the knowledge
base is CONSISTENT, not that it is TRUE, so a false invariant passes it forever.
And this one understated coverage, so nothing failed and nobody looked — the
comfortable direction to be wrong in, and the reason it lasted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 11:22:13 -07:00
Edward Langley dc2f4a06ad docs: complete the corrections, per adversarial review of this PR
Four findings, all verified against the tree before acting.

F10 — this PR's own edit to design-principles §5 made a sibling note in
context/code/command.md false: it said §5 "still names Sessions::apply" and
recommended apply_checked. A PR whose whole subject is stale prose had left a
new stale copy behind, which is gotcha 48 exactly ("changing it is a grep, not
an edit"). Note deleted; the verified claim above it stands.

F11 — §5 named both apply and apply_checked as "the one door". apply has no
production caller anywhere in the workspace; Host calls apply_checked. Naming
two weakens the claim §5 makes, so it now names the one production uses.

F12 — gotcha 17 said "four call sites". There are six uses across the two
evaluators: a div/0 guard plus the Eq and Ne arms in each. In a file agents
follow literally, a reader who greps and finds six cannot tell whether the
prose or the code moved.

F13 — gotcha 17's sibling said the Dirty::of doc comment "keeps only the
one-line reason LayoutGeometry is spelled out rather than EVERYTHING". It says
no such thing: it points at context/code/command.md, and the EVERYTHING reason
is a two-line comment inside the match body. A correction to prose that
asserted the negation of the code should not itself misdescribe the code.

Two findings deliberately not fixed here and filed instead: improvise-ahdf
(repo-map gotchas 36 and 43 carry the same stale Sessions::apply claim —
pre-existing, and inside long paragraphs that need reading rather than a sed)
and improvise-rm4s (--check-evidence accepts headings naming tests that never
run).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 11:06:10 -07:00
Edward Langley 56ff51e444 docs: correct two stale gotchas, and an assertion message that lied
Orchestrator doc pass over the comment wave. Each claim was verified against
the tree rather than taken from the queue.

Gotcha 17 recorded the *opposite* of the code: it said float equality was
"currently mixed", with `=`/`!=` on a 1e-10 epsilon and the div-by-zero guard
checking `rv == 0.0` exactly. Both now go through FLOAT_EQ_EPSILON, at four
call sites across eval_expr and its aggregated twin. Rewritten to say so and
to point at context/code/core.md §4.

Gotcha 35 called the doc comment on `Dirty::of` "the only record" of its
derivation. The comment wave moved that reasoning into
context/code/command.md and left the comment holding one line, so the
instruction to re-read on reclassification now names the prose.

design-principles §5 named `Sessions::apply` as dispatch; `apply_checked` is
what `Host` actually calls since improvise-955n answered a whole frame at
once. Both are real, so the row names both.

improvise-mbmf: the_ranking_is_ordered_shares_with_the_unused_features_dropped
asserted a length of 2 from three features — the zero-importance one dropped —
under the message "the zero-importance feature is listed". The message is read
only on failure, which is precisely when it would have described the wrong
behaviour as the requirement. The test name and doc comment were already right.

cargo test --workspace: 1311 passing, unchanged.

Closes improvise-mbmf.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 10:50:30 -07:00
Edward Langley 6f9efcf2e8 docs: improvise-xps8 describes a bug that does not exist — turn it into a guard
Review findings on PR #30, all three applied.

1 [P1]. The claim that the handshake watchdog overwrites a genuine mid-session
disconnect 8s later is FALSE on any tree that has PR #21. `close` routes BOTH
arms through `setShellFailure` (app.js:248-250), which clears the timer
synchronously (app.js:165-169).

It was believed because it was measured honestly — against a tree predating
PR #21 — and then reported as "surviving" that PR on the strength of a
simulation that re-created only the `opened` flag and not the other half of the
fix, the routing. A simulated fix that is not the fix you named reproduces a
bug the real code does not have, and reads exactly like a confirmation.

Rather than delete the claim, execute the property it denied: the
open-then-dropped test now runs past HANDSHAKE_TIMEOUT_MS + 2s and asserts
"sent no document" never appears. Proved discriminating by removing
`setShellFailure`'s `clearTimeout` — the assertion then fails with exactly the
message xps8 described. gotcha 48 and the spec's comment block corrected; the
ticket is cited in neither. Recorded as
doctrine(a_simulated_fix_must_be_the_fix_you_named), the sibling of
an_injected_fault_must_be_the_fault_you_named that fails the other way: a wrong
fault proves a check that cannot fire, a wrong simulated fix proves a bug that
does not exist.

2 [P1]. The previous commit created the contradiction it was meant to remove:
design-principles recorded the measured ~2.2s while kb.pl still said "under 2
seconds". The ambiguity between per-binary and wall clock is what let it drift,
so both now state two numbers — no single binary over 2s, wall clock is the
sum, measured 1309 tests / 33 binaries / ~2.2s / longest 1.42s — in kb.pl,
design-principles and repo-map alike. Also 16 -> 17 in doctrine(binding_dump_diff).

3 [P2]. The new audit exclusion was unanchored, so `improvise-gp` was a prefix
match that would silently exclude a real future ticket. Anchored `^…$`. It
immediately caught the example id the explanatory paragraph itself spelled out
— a recipe is code, twice over.

CLAUDE.md: declined, with evidence. Both copies of the duplicated tail sit
inside `<!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:ca08a54f -->`
markers written by `bd setup claude` and `bd setup codex` and refreshed against
that hash. A process change there is one tool invocation, not two hand edits,
and a pointer makes `bd setup <recipe> --check` report it modified. Recorded as
kb_issue_found(claude_md_tail_is_generated_not_duplicated) so it is not
re-proposed.

kb.pl: doctrine 54->55, kb_issue_found 11->12; invariant 51, decision 47,
location 34 unchanged. kb_consistent passes.

cargo test --workspace: 1309 passed, 0 failed, 2 ignored.
harness (Playwright): 12 passed, 3 skipped (webkit has no OPFS).
Dead-ID audit with the anchored recipe: 157 tokens, all resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 01:11:46 -07:00
Edward Langley 34e5bd5902 docs: gotcha 33/47 still spelled the retired RowLabels/ColLabels
The fold rule is intact under the new field names (improvise-anr9 renamed
the GridUpdate arms to RowFrame/ColFrame and GridCache's fields to
row_frame/col_frame), but three sentences still named the old ones.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 00:58:04 -07:00
Edward Langley f12a2d3517 docs: reconcile the docs with the code after wave 1
An independent review checked every factual claim in the docs against the
code at 22d43b2, after eight PRs landed in one wave. This applies its
replacement text.

context/repo-map.md
  - gotcha 44 rewritten: the cache DOES frame the grid now (improvise-anr9,
    AxisFrame/FrameEntry/header_level_widths). The surviving half — the TUI
    builds at offsets zero, so a cache position is absolute — is kept,
    because four code comments cite gotcha 44 for exactly that.
  - gotcha 45: ClientFrame::Save exists (improvise-368h); MarkDirty is gone
    and dirtiness is read off EffectKind::Model(_); Rc<T>: Storage lives in
    improvise-io (improvise-hmws); OpfsFs::list joins dir (improvise-vhcz);
    OpfsFs is run by harness/ and bindings.rs is now the dark corner.
  - gotcha 47: Host::commands answers the frame whole (improvise-955n); the
    open hole is clause 4, not a per-command Checked. set_viewport "must"
    -> "does".
  - gotcha 43: the frame, not the command, is what is answered; two of three
    tiers hoist.
  - gotcha 21 widened: three effects abort, and tidy-up goes at the head.
  - gotcha 48: web/app.js is executed by harness/tests/shell.spec.js;
    improvise-m18f -> improvise-taxx (fixed); the open half is improvise-xps8.
  - gotcha 42: the never-rendered / improvise-hwpi sentence pair deleted.
  - gotcha 18: live_records and analyze_records are both decided now.
  - gotcha 1: the records columns are [coords…, +cat, measures…, +].
  - AppMode is 17 variants, ModeKey is 17, eight text-entry modes; the keymap
    table moved to improvise-protocol/src/keymap.rs (six references).
  - the Wasm section: the mirror is gone; the wasm gate covers eight crates.
  - the File Inventory regenerated rather than patched (57/79 rows were
    stale); the duplicate ws-server/host.rs collapsed to a pointer at the
    23-line shim; harness/, protocol keymap.rs/viewmodel.rs, improvise-gp
    fit.rs/dataset.rs, cmd/fit.rs, model/record.rs and the integration tests
    added.
  - the suite speed re-measured rather than re-asserted.

README.md — the four "no browser here" sites narrowed to what is still true;
17 modes; the browser section names the Playwright harness.

AGENTS.md — the dead-ID audit recipe was itself defective: two paths, a
character class blind to a commit SHA, and a two-name exclusion list. Widened,
made runnable under the worktree shell guard, and its own prose no longer
spells any id.

prolog-sessions/kb.pl — seven invariants replaced in place (they were false),
five location/3 facts re-sited plus three new, six doctrines and seven
invariants added. doctrine 48->54, invariant 44->51, decision 47 unchanged,
location 31->34. kb_consistent passes.

Comment-only Rust changes: a duplicated sentence in worker.rs, records_columns'
doc omitting NewCategory, improvise-709f2df -> commit 709f2df, and three more
copies of "OpfsFs has never been run".

cargo test --workspace: 1309 passed, 0 failed, 2 ignored — unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 00:56:33 -07:00
Edward Langley d175b9934f docs(principles): a front end displays state; it does not reimplement behaviour
User ruling 2026-09-20: minimise the amount of new code a new UI framework
needs. Centralise logic in a redux-like store so a second or third front end
is a function from state to pixels plus a wire for events, not a second
implementation of how the application behaves.

Names the pieces that already exist as what they are -- Command is the
action, reduce_view and WidgetCache::apply are the reducer, ViewState plus
the caches are the store, Sessions::apply is dispatch -- and gives the
question to ask of any front-end code: would a third front end have to write
this again?

Three things make it concrete: the measure is lines of framework-specific
code and should trend to 'paint and wire'; a derivation done twice is the
defect even when both copies are correct today (improvise-edp is the worked
example, gotcha 44 is the same defect still open); and sharing a table beats
testing two copies of it, which is why the keymap is shared rather than
mirrored. Also says what legitimately stays local: painting, event wiring,
and a semantic-value-to-framework-type lookup like AxisColor -> axis_fg.

Sections 5-7 renumbered; the §6 testing references in repo-map.md and the
code-review skill updated with them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
2026-09-19 21:31:58 -07:00
Edward Langley b7dcde56d5 docs: gotcha 48, and the gh graphql workaround
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Browser bundle + static site (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
The browser JavaScript is argued, not tested, and the two rules it can break
are both about WHEN: an async message listener does not serialize, and a
watchdog must be disarmed rather than pre-empted. Both found by review
rather than by a test, because nothing here runs a browser.

Plus the third thing no test can see: three comments in one range said 'not
built yet' about work that landed in that same range, each because a
follow-up commit updated one copy of an argument and not its siblings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
2026-09-19 20:36:15 -07:00
Edward Langley 190c440be6 docs(repo-map): three waves of debt, and a row pointing at a deleted file
The 'Change a browser<->server frame' row still named
improvise-ws-server/src/wire.rs, which improvise-xks6 deleted -- the first
place the next agent looks. Flagged by a reviewer and missed twice.

improvise-worker-server appeared nowhere in the map at all: not the crate
list, not the how-to-find table, not the inventory, and the Wasm section
still said six bundle crates.

Gotchas 45-47 for the three undocumented waves -- the worker host (and the
three gaps it found in the SHARED layer, which the socket server also has),
the page's two transports plus the assertion the demo was built against, and
client-side key resolution. Each was proposed by its agent and never applied.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
2026-09-19 20:22:32 -07:00
Edward Langley 4f5894db66 docs: the basis exemption is no longer a door
Gotcha 43 and ADR 001 both described apply_command/reduce_full as a
deliberate exemption with a hole in it. improvise-ondj closed the hole with
a type: Checked<'_>, whose only constructor runs the check. The principle is
unchanged -- a host holding the App is the truth, not a claimant -- but the
unchecked path is now unconstructible rather than discouraged.

Records why visibility was the weaker option (reduce_full has no production
caller, so pub(crate) would have made it dead code), that the regression
guard is the signature rather than a test, and the residual hole: a Checked
does not name which App it was checked against.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
2026-09-19 18:54:44 -07:00
Edward Langley 5a6c35d4b6 docs(repo-map): gotcha 42 loses the mirror it was written to explain
improvise-xks6 consolidated three envelope vocabularies into one pair, so
the 'socket.rs is not wire.rs' half of gotcha 42 is now history. Replaced
with the question that had to be answered first -- do the worker and the
socket want the same vocabulary -- and the test applied to each difference:
whether the ARGUMENT for it names the thing they differ in. None did.

Also records why deleting both mirror tests was the measure of success: what
they checked is now type identity, and a surviving compatibility test after
a merge is evidence the merge did not happen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
2026-09-19 18:52:59 -07:00
Edward Langley 1f4e5354de docs: six invented ticket IDs, and what the PR loop actually needs
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
Six improvise-* IDs cited in repo-map and ADR 001 never existed -- filed
with output suppressed and then written into the docs from memory. A dead ID
is worse than no ID, because it reads as a promise the follow-up exists. All
six corrected to the real tickets, and AGENTS.md gains the audit loop.

AGENTS.md also gains what PR #12 learned: requestReviews takes botIds and not
userIds, gh is shell-aliased to a different tool here, a Copilot review takes
about six minutes, and a finding can be CORRECT and still be wrong to fix in
that PR -- #12 applied a truncate panic (byte-identical on ASCII, so it cost
no evidence) and declined a padding bug in the same file that would have
rewritten the characterization tests which were the PR's only evidence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EoW5BB87ZZdm96SvBTWawH
2026-09-19 18:26:59 -07:00