Commit Graph

102 Commits

Author SHA1 Message Date
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 c0368123fd docs(context): drop the grid_width location fact that kb-test counts against
scripts/kb-test.sh case 18 expects exactly 35 location/3 facts; the
location is kept in the repo map and in decision(scroll_measured_where_drawn).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 20:18:45 -07:00
Edward Langley d5fd1ec824 docs(context): record #303-#307 in the kb and answer improvise-at5k
Facts for gtn7.1, cgqt/9bit/4klp, felo.1 and the merge-only history
rule; the two doctrines that read as licensing a rewrite now forbid it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-24 20:16:36 -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 e9f7327328 docs: the fmt gate every brief prescribed, and the collapse ruling
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
AGENTS.md's brief template now carries the gate list, because the one I had
been handing agents said `cargo fmt --all`, which reaches only one of this
repo's two workspace roots — and `cargo fmt -p opfs-contract` from the root
exits 1 as a usage error indistinguishable from a real verdict
(improvise-b4ks). Both spellings fail in the direction that looks like
success. The gate is `scripts/fmt-workspaces.sh`.

kb: the improvise-6qet ruling (a collapsed group is one aggregate row), and
the CI lane's doctrine on stubs and fixtures.

Also recovers kb.pl from a truncation: the working tree had lost 276 of 801
facts, most likely to a `kb replace` killed mid-write at a session boundary,
and `kb add` had written onto it with kb_consistent passing. Restored from
HEAD; this commit is 6 insertions, 0 deletions. Filed as improvise-usus.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 20:21:05 -07:00
Edward Langley 29e41a32e0 docs(kb): what adversarial review found, and four vacuity shapes
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
From PRs #143/#146/#147/#150/#152/#156/#157 and the adversarial review of the
first five.

The finding worth the review's cost: `Repr::Nonfinite(&'a str)` could only be
produced by a deserializer that borrows from its input, so the new wire
spelling round-tripped through `from_str` and `from_slice` and nothing else —
the same JSON document escaped as `inf` was refused, and `to_value` did
not round-trip its own output. Both of the PR's tests used `from_str`, which
is precisely the one path that borrows.

Four vacuity shapes, each confirmed by injection rather than argued:

- A disjunctive assertion can accept the bug it guards — one branch here was
  exactly the error message the defect produces.
- A law asserted over an immutable `CmdContext` is a tautology: a `Cmd` is
  pure over its context by construction, so `execute` twice without applying
  effects asserts `f(x) == f(x)` and no rival can fail it. Applying the
  effects REFUTED this one rather than rescuing it.
- A rival must fail the property, not the setup — `AddFormula` and
  `RemoveItem` are both `CellData`, so the obvious test proved the neighbour.
- Every agent appends to the same evidence file at EOF: four conflicts in ten
  PRs. Loud, but the resolution is the hazard, since `--check-evidence` cannot
  see a dropped entry.

kb_consistent: TRUE, 803 facts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-22 19:49:23 -07:00
Edward Langley b1a989d8cf docs(kb): the command lane's doctrine, and a second vector for the base trap
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
From PRs #144/#148/#151. `AGENTS.md`'s remote note gains the worktree-base
vector: a branch cut from the orchestrator's local `main` inherits whatever
that checkout merged but did not push, and nothing in the branch says so —
which is how #148's diff came to name the three orchestrator-only files and
read as a rule violation rather than a base problem.

Four facts. A fold test must fold the batch the producer really emits — a
`Binding::Sequence` flattens into one vec, and a per-step batching cannot see
intra-batch order at all. A type name is not a field, measured: one 14-site
rival left 14 of 16 assertions passing, while an assertion on a *fieldless*
effect is complete rather than smoke. A registry with two arms demotes the
weaker caller, and neither direction is safe by default. And a clean text
merge can delete an evidence entry that no gate checks.

Two gate traps: `--check-evidence` prints the comment cap FIRST, so reading it
through `tail -1` drops the half that was always there; and a compound command
refused by the worktree shell guard runs NEITHER part.

kb_consistent: TRUE, 798 facts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-22 19:34:07 -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 286c09960a kb: what the integration role learned that no branch could
Four doctrines from the wave q/r/s/t integration, each measured rather than
reasoned:

a_merge_prints_pop_whether_or_not_it_stashed -- git invites a stash pop on a
conflicted merge even with an empty autostash. Three occurrences, twice with
stash@{0} being another session's WIP, on a stack shared across nine worktrees.

a_missing_loose_ref_is_not_a_deleted_branch -- a watcher reading refs/heads
directly cannot tell a deleted branch from a packed one. Both happened in one
event.

rebuild_the_integration_on_the_new_base_and_diff_the_trees -- when three PRs
merged upstream mid-integration, rebuilding on the new base gave a BYTE-IDENTICAL
tree, which proves the upstream merges lost nothing rather than inferring it.

a_reported_sha_is_correct_and_short_lived -- three stale SHA tables in one
session; the remedy is a watcher, not diligence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 21:28:15 -07:00
Edward Langley 8eb93628b2 kb: the view/server split exists so clients can differ, and that is a test
User: 'The whole point of the view / server split is that multiple clients can
have different views of the model.'

Recorded as the RATIONALE rather than a fact, because it is the single premise
the day's four rulings follow from -- client-local view stack, ephemeral drill,
client-only view switching, and identical staging. gotcha 29 already said 'the
model is shared and the UI is not'; this says why, and converts the split from a
fact into a test: does the proposal force two clients into the same view?

Plus the two integration doctrines: an autostash instruction is not permission to
pop (the stash stack is shared across six other sessions), and a capability and
its key can land in different tickets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 21:18:01 -07:00
Edward Langley 0cfbc6f373 kb: browser drill stages identically, because staging and the basis check answer different questions
User ruling. An agent proposed that a browser write through with ordinary
SetCell commands rather than staging, since those are already basis-checked.
The substitution does not hold: the basis check is anti-staleness coordination
between clients and answers whether a picture is CURRENT; staging is an
editing-session abstraction for one user and answers whether they want to KEEP
what they typed. Write-through would silently remove the ability to abandon a
drill -- invisible to any test that asks only whether an edit lands.

The convergence that makes it cheap: clause 4 is delivered, so a staged commit
is a batch of SetCells taking its atomicity from the transaction that already
exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 19:50:37 -07:00
Edward Langley e3fc2210b8 kb: the doctrine this wave's four agents earned
Twelve facts across four PRs. The ones that generalise furthest:

a_completeness_check_closed_over_the_omitting_artefact_is_blind -- the parity
guard asked whether every RenderModel field is painted, and its domain was
RenderModel, the very thing that can omit a field. It reported a clean bill for
a whole wave while totals and page_coords were painted by nothing.

an_escape_hatch_is_where_a_new_check_goes_vacuous -- both bugs in a new guard
were in its exemptions, never its check. '&state.grid' is a substring of
'&state.grid.row_frame'.

a_cursor_rule_copies_between_panels_only_if_the_list_is_homogeneous -- the
obvious repair for uej8 is worse than the bug.

a_ticket_can_be_one_level_too_high_and_its_fix_unimplementable -- g3no's stated
fix could not work on the browser side twice over.

deliberate_slack_can_become_load_bearing_with_nobody_editing_it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 19:32:56 -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 1f2886873b kb: a derivation protects only what it derives
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 the UX audit, which found the product mostly coherent and
the incoherence concentrated in two places.

The help pages are DERIVED from the keymap and a row naming a nonexistent key
is dropped — good architecture, working. The ex-command rows are Literal and
escaped it, and that is exactly where the worst content bug lives: every
documented spelling of :formula fails, on the quick-start page, for the
headline feature, because the parser splits on whitespace and nothing says to
quote. Verified. When a derivation lands, enumerate what it does not cover,
because the covered part now looks trustworthy and the uncovered part looks
identical.

The browser paints the host's hints and help over a smaller capability set:
four advertised keys decline out loud, ten more are silent, and help page 2's
whole Search section is taught to a browser user who cannot use it. A shared
vocabulary still owes a per-surface capability filter.

And the status bar contradicts the wizard overlay on four of eight steps —
on Done it says Esc cancels where Esc goes back. Two writers of one fact,
improvise-edp's disease in the UI layer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 13:30:40 -07:00
Edward Langley aeda06a182 kb: a worktree agent merges the orchestrator's uncommitted local main
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
I committed context/code/pr-review.md straight to local main without a
build-doc-site manifest entry. Agents in worktrees share the repository's local
refs, so 'git merge main' takes my local main INCLUDING commits never pushed —
and PR #98's branch went red on the doc-site gate, which is improvise-res9
working exactly as designed.

The agent diagnosed it as 'main has been red since #96'. Both halves were
wrong: CI on #96's merge was green, and the doc was not in main when #96's
agent merged at ea206bf. It entered between, so only the later branch saw it.
Recording that because the wrong attribution is the interesting part — the
cost lands on whoever merges next, who then debugs somebody else's change.

My local main is an unreviewed publishing channel into every running agent. A
commit there is subject to the same gates as a PR without getting them.

Also filed as a doctrine: a manifest gate over a repository-wide invariant
should run where the violation is AUTHORED, not only where the tree is
assembled. It sits in the build job, so the author never sees the failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 11:18:37 -07:00
Edward Langley 26456c698e kb: editing a shell script corrupts the instances already running it
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
bash reads a script incrementally rather than loading it whole, so editing a
file while an instance executes it shifts the byte offsets underneath that
instance. Two background pr-reviews watchers, started ten minutes earlier and
sleeping in their poll loops, both died with 'syntax error near unexpected
token do' the moment I appended a paragraph to the usage text. bash -n
confirmed the file itself was fine.

The failure is in the RUNNING instance, not the file, so it is invisible to
every check you would think to run afterwards. And worse than a crash here:
each watcher exited having printed only the EARLIER review, so the wait it
existed to perform silently did not happen. I re-ran both cleanly before
merging rather than counting them.

Closes improvise-hsoe, improvise-4dpj and improvise-26dm from PR #96.
Backlog: 32 open.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 11:04:36 -07:00
Edward Langley c73df4b5a1 kb: a pipe discards the exit code you meant to read
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
Fourth occurrence in one campaign, and this one was in a tool I wrote TO BE
the reliable answer. scripts/pr-reviews --wait correctly exited 1 on a
timeout, and my invocation ended in '| tail -20; echo', so the harness
reported 0 — a review window that had EXPIRED read as a review that had
ARRIVED, which is the dangerous direction.

The earlier three: pr-watch reading tr's status through a pipe; a probe
reporting EXIT=0 from a checker that had exited 1; and PIPESTATUS in zsh,
where the array is lowercase pipestatus — the two shells differ, which is its
own trap.

The script's usage now says not to pipe it.

Closes improvise-711n (,.2f yielded zero decimals — the spelling our own docs
show) and improvise-x1ns (the preflight undercount ChatGPT Codex found on a
PR I had already merged unread).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 10:56:36 -07:00
Edward Langley 0466da173d kb: an unreachability claim is only as wide as the routes enumerated
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 from Wave L's Codex round. The first is the campaign's cleanest
statement of a recurring failure.

PR #98 predicted its own composition-time mode drift and declared it
unreachable because the toggle route (R) is a stranding decline in the
browser. True of that route. A VIEW SWITCH reached the same drift, because
records-ness is auto-detected from the axes so a switch changes it with
nothing in the batch saying 'records'. The enumeration of routes is the part
nothing checks, so an unreachability argument is evidence about the routes you
thought of and nothing else.

The remedy is the thing worth copying: close the CLASS by observation rather
than patch the route. resolve::changed_mode is deleted; ClientState::fold
settles against the grid it holds, so no enumeration of composition sites is
load-bearing. Read-time derivation was rejected for having the same window and
for moving the enumeration to readers, where a missed reader is silent. Same
shape the repo already prefers: cursor_epoch over matching on CycleAxis,
document_generation over matching on LoadModel.

And a test-construction trap found by the author in its own bidirectional
test: a precondition computed from the same tuple element as the assertion
cannot be relaxed one iteration at a time, so the test fails for the wrong
reason — which reads exactly like the bug.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 10:49:35 -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 23c81977eb kb: an invariant generalised from a fix generalises the fix
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 M's Codex round, and the middle one is about the kind of
mistake that is hard to see from inside.

Having repaired the categorical under-count, the agent proposed a
never-under-counts invariant WHILE THE TREE ALREADY HELD A COUNTER-EXAMPLE —
the missing Date arm, which Codex then found. An invariant written immediately
after a fix tends to state what the fix established rather than what the code
guarantees, because the evidence in front of you is the defect you just
closed. The question that would have caught it is about the OTHER function:
'what else does the thing I approximate do that I have not mirrored?'

The agent retracted it unprompted, before it was ever recorded.

Its structural fix is the right shape: encoded_width now matches Forced with
NO WILDCARD, so a fourth variant is a compile error rather than a silent
categorical fallback — which is exactly how Date was missed.

And the reason both bugs were invisible to a green suite: an advisory bound
over another function is a duplicated derivation, and nothing compared the two
at all. A width asserted against a constant passes at every stage while the
approximation drifts. The only honest test is to run the thing it approximates
and compare against what it actually produced.

Noted while filing: scripts/kb refused the first draft with dangling_citation,
because the doctrine named an invariant that was retracted and never recorded.
The same class as a dead ticket id, caught by the tool.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 10:41:14 -07:00
Edward Langley 95657dc90b kb: inject the rival fix, and a preflight inherits every branch it guards
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
Both from the first use of the read-the-reviews rule, which found a P1 Codex
review on each open PR.

The preflight one is the sharper. encoded_width guards preprocess, which
dispatches Numeric -> Date -> Categorical, and it mirrored two of three.
improvise-x1ns was the categorical arm undercounting the (missing) one-hot;
Codex then found the DATE arm missing entirely — a date column takes the
categorical fallback because '2024-01-15' does not parse as f64, so a column
holding one distinct date promises 1 where build_date materialises 5, or 7
with a time. Two findings, one shape, one inference branch apart.

A preflight is a second implementation of the thing it guards, so it inherits
every branch of it, and the branch nobody mirrored is the one nobody was
thinking about. Note the second finding contradicts an invariant proposed in
the same hand-back that fixed the first: the counter-example was already in
the tree.

And the Wave M agent's own best insight: check_the_checker proves a test sees
the BUG, not that it encodes the RULE. Two implementations both repair ',.2f'
and differ only on '.2f3', so the discriminating injection is the other
plausible fix rather than the original fault.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 10:34:12 -07:00
Edward Langley ea206bf8de docs: read the reviews before merging; authorship will not identify them
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
I merged twenty PRs this campaign without reading their REVIEWS. CI green plus
a dispatched adversarial agent felt like the whole gate and was not. Two
ChatGPT Codex reviews were sitting on merged PRs; both were correct.

improvise-x1ns (P2, filed, live on main): encoded_width's categorical branch
counts only distinct PRESENT values, while build_categorical maps every
missing cell to MISSING_CAT and emits an additional one-hot. A forced category
with N present values plus one missing coordinate passes the preflight as N
and materializes N+1 — caught only by the later exact check, which is the
allocation the preflight exists to prevent.

The keeper from that review: 'bounded by the later exact check' is not a
defence, because the exact check runs AFTER the allocation. It bounds the
error message, not the cost. Our own review had seen the shape and reasoned it
away on exactly that ground.

The PR #91 review described round 1 and round 2 fixed it — verified with a
probe rather than assumed, both directions. But the regression it asked for
does not exist, so improvise-4dpj now carries it.

Three things make a Codex review easy to miss, all now in AGENTS.md: it
arrives as a review rather than a comment; it posts under the owner's account,
the same one our agents use, so authorship cannot distinguish it — the tell is
the TRAILING '_Automated review by ChatGPT Codex_' where ours OPEN with
'_Posted by Claude_'; and it may target an earlier head, so a finding can be
already fixed or still live and you must check which.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 10:15:30 -07:00
Edward Langley d72d7558d3 kb: a check that returns empty for the wrong reason passes
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
Two doctrines, both about checks that cannot fail, both found this round.

This repo configures diff.external = difftastic, which prints side-by-side
output carrying no unified-diff markers — so 'git diff | grep "^-"' matches
nothing regardless of content. An agent verifying that a merge dropped nothing
read three consecutive empty outputs as three clean bills. I reproduced it: on
a file with one real deletion, git diff | grep -c '^-' gives 0 and
--no-ext-diff gives 1. Use --no-ext-diff, or --numstat/--name-only which are
unaffected.

That is the sharpest form of check_the_checker in the campaign: an empty
result is the one outcome nobody investigates.

And the CI diagnosis, recorded with my own error in it. A pull_request
workflow builds refs/pull/N/merge; a CONFLICTING PR has none, so no run is
created and it looks identical to a dropped webhook. 34 minutes of polling, a
close/reopen and an empty commit produced nothing; one merge produced a run in
seconds. Ask gh pr view --json mergeable first.

Filed improvise-hsoe: --check-evidence cannot see a duplicate heading, and
three exist on main — verified. Both copies pass, because a duplicate names a
running test just as well, and one of them is stale by construction.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 05:41:31 -07:00
Edward Langley 1ec43a7aa0 kb: a conflicting PR runs no CI, because it has no merge ref
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
I diagnosed PR #92's missing CI as a dropped webhook and was wrong. A
pull_request workflow runs against refs/pull/N/merge, and GitHub cannot build
that ref for a CONFLICTING PR — so no run is ever created and the PR shows
zero checks, which looks exactly like a dropped event. #91 had merged and both
PRs appended to the same four context/ files.

The control I ran was sound and the conclusion was not: pushing to another PR
produced a run in five seconds, which correctly proved delivery works
repo-wide. I read that as 'therefore the event was dropped', when the truth
was that no event was ever generated. A control discriminates only between the
hypotheses you listed, and ours had two entries.

Diagnosis order, now written down: before theorising about delivery, ask
gh pr view N --json mergeable. One call, and it answers first.

The agent was right to refuse to guess and right that its evidence could not
separate its two hypotheses. Neither of us listed the third.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 05:30:02 -07:00
Edward Langley 99ec32d6f3 kb: comparing a function against itself tests nothing
Two facts from the adversarial review of PR #92, both about checks that
cannot fail.

improvise-jmjz guarded its width half with col_widths == compute_col_widths,
but compute_col_widths IS grid_body with an empty window — the same function
twice — so windowing degrades both sides identically and the assertion cannot
fail. Injecting the fault left 1476 tests passing. A consolidation is exactly
when such a check gets written, because the second implementation has just
been deleted.

And a negative result is only as good as the setup that produced it: the
none_cats hazard was reported 'argued and unobserved' from a fixture whose
stated condition was absent, because add_category defaults a category to
Column and nothing moved it. Setting the axis explicitly failed the property
on the first run and found improvise-ac2z.

Filed from the same review: improvise-711n (parse_number_format yields zero
decimals for the ,.2f spelling our own docs show, P2) and improvise-swre
(memoise the grid across frames). improvise-jmjz closed on its own criterion;
improvise-6nsd lowered to P4 with the severity note.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 05:11:52 -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 d9d456c890 kb: serde's derive is the one enumeration the compiler maintains
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-5ubs is solved, and not the way anyone proposed. Closing a
length-not-completeness check needs an enumeration INDEPENDENT of the
derivation, and stable Rust has none for an enum carrying data: variant_count
is nightly, strum::EnumIter cannot construct a variant holding a
MinibufferConfig. Serde can — the Deserialize derive builds the complete
variant-name list from the enum definition and publishes it in its
unknown-variant message. variants.rs reads it back and diffs it against what
the cycle reached.

The dependency on serde's message format is made loud rather than silent: it
panics naming the message if the split fails and asserts the parsed list has
more than one name, so a format change cannot degrade into a vacuous pass.
Verified by reading it rather than taking the report.

Also: a consolidation's frozen behaviour is a date, not a decision. A
consolidation must preserve what it moves or its agreement test cannot tell
'both ends agree' from 'both ends changed together' — so the rule is frozen
for the duration of the move, and afterwards a single home reads as decided.
improvise-8qlr froze name-only group coalescing; the test still pinning it
justified itself with 'because that is what src/ui/grid.rs uses', a clause
8qlr had already made false.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 04:19:41 -07:00
Edward Langley fe816c9734 kb: a mitigation that names the wrong file is not a mitigation
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 #91 deferred a wire-level gap because 'keys.rs emits no ChangeMode at
all'. True, and irrelevant: keys.rs holds only BrowserKey, and the live
browser resolver is improvise_protocol::resolve, which emits
ChangeMode(AppMode::Normal) at five sites. The browser front end kept the very
bug the PR fixed for the TUI, and the suite was green over a divergence the PR
created.

I copied that false clause straight into improvise-e5pf when I filed it.
Corrected, and raised to P2: it is live, not latent.

The rule: before writing 'X does not do Y' as the reason a gap may be
deferred, grep for Y rather than for X. The claim that matters is about the
behaviour, and the file you happen to have open is not the only place it lives.

Also records that improvise-sihr's prose defended its staleness with an
example that works for a different reason — toggle-records-mode overwrites
normal_mode()'s answer in both directions, so the staleness is neutralised
there rather than exercised, and the case that would have tested it regressed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-21 04:15:16 -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 d7f2786711 kb: a narrowing owes the correctness test its predecessor passed
Both from the adversarial review of PR #78. The first is the sharpest finding
of the campaign: improvise-mcq4's narrowing had already been measured as
buying nothing (12.41ms to 12.56ms) and was kept only as 'the honest shape' —
and it turned out to cost a multi-client invalidation no test named. A change
with no measured benefit carried an unmeasured cost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:52:49 -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 565edc5964 kb: the obvious fix bought nothing, and the clean merge kept both mechanisms
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-mcq4's obvious narrowing — fingerprint the active view rather than
every view — was the ticket's first option, the orchestrator's suggestion and
the author's plan, and moved 12.41ms to 12.56ms. Nothing. The per-view
multiplier was never the cost; two expensive builds were, and the bench's
second view was a fresh one costing nothing to build. It would have shipped as
the fix had the author not re-measured after implementing. A fix three people
agree is obvious has had its plausibility checked and not its effect.

And the merge note: when two branches replace one mechanism with two different
ones, the dangerous file is the one that does NOT conflict. app.rs conflicted
loudly and was resolved by hand; effect.rs auto-merged clean and left both
cursor mechanisms live, 1435 tests green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 21:38:27 -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
Edward Langley 9976486d69 docs: the help entry no longer contradicts itself
Found by review on #75. Renaming the heading to the test PR #72 restored made
check-evidence green, and left the body three paragraphs down still saying
"The test no longer exists" and "nothing replaced the assertion" -- one entry
making mutually exclusive claims about whether the coverage exists.

The checker could not see it, and that is not a gap in the checker: it
validates heading-to-test and says nothing about the prose beneath, which is
what a human reads. A mechanical check licenses exactly the claim it makes and
no neighbouring one.

The paragraph now records the gap as history -- gone for a release, invisible
because the checker then read only ### headings and only Rust names, restored
by #72 with improvise-igxp's stronger assertions -- and points at
help.spec.js's own entry rather than promising or denying coverage itself.

doctrine(a_checker_that_reads_headings_cannot_see_a_contradicting_body):
a rename is a read of the whole entry, not an edit of its first line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 19:55:31 -07:00
Edward Langley d2a54ac320 kb: restore six doctrines a hard reset discarded, and record how
Consolidates four doc branches and restores what resyncing lost.

I wrote doctrines to kb.pl on local main, pushed each as a branch, then ran
`git reset --hard gh/main` twice to resync -- discarding six clauses that
existed only in the unmerged local commits. Nothing failed: kb_consistent
passed on the reduced file, the counts simply read lower, and the loss was
found only by grepping for clause names I happened to remember writing.

That is the same shape as everything else this wave found. A count that looks
plausible is not evidence, and the check that would have caught it -- diff the
clause NAMES, not the total -- is the one this repo already applies to tests
after a merge.

doctrine(a_hard_reset_discards_knowledge_written_to_the_working_branch) states
the two rules: write a fact once, on the branch that will carry it to main, not
on a local main that is going to be resynced; and after any reset or force-move
of a branch holding knowledge, re-count and diff clause names.

Restored: every_wave_agent_gets_its_own_worktree,
the_orchestrator_delegates_substantial_work,
a_message_assertion_is_a_uniqueness_claim_about_the_whole_vocabulary,
run_the_gate_ci_runs,
an_observation_correct_about_what_changed_can_be_wrong_about_when_it_is_read,
a_siblings_unmerged_pr_is_invisible_to_bd_search.

Also carries: the wave skill, the Copilot-gate correction to AGENTS.md, the
help evidence rename, and the code-review skill's missing -D warnings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 19:40:33 -07:00
Edward Langley 65e8f2fb42 Merge remote-tracking branch 'gh/docs/copilot-gate' 2026-09-20 19:40:02 -07:00
Edward Langley debad21556 docs: run the gate CI runs, and bindings.rs is run
Two one-line corrections the wave's last review surfaced, both about a claim
being stated in more than one place.

.claude/skills/code-review/SKILL.md told every reviewer and every wave agent to
run `cargo clippy --workspace --all-targets` with no `-D warnings`. Clippy exits
0 on warnings, so the committed local gate was green on exactly the input CI is
red on. This is not one person's shell mistake, it is the instruction: a
reviewer following the skill as written would report clean and be wrong, which
happened on PR #71. Also adds --no-fail-fast, since fail-fast hides blast radius.

README.md was a sixth copy of "bindings.rs is never run", which PR #70 corrected
in five places -- its grep missed README, and PR #72 then rewrote the sentence
four lines above and carried the wrong half forward. Neither PR is at fault
individually; it is an interaction between two branches, and it is the exact
failure the corrected fact is a monument to.

Plus doctrine(a_weak_check_and_a_strong_one_agree_until_the_defect): five
instances this wave, one mistake -- a check written against the failure you
imagined rather than the outcome the user sees. The weak and strong checks agree
on every input anyone tried and diverge only on the input that is the defect.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
2026-09-20 17:24:17 -07:00