78a7bbf4f9f808795b354ca83ff77a47f29e24b4
90 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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
|
||
|
|
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 |
||
|
|
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 |
||
|
|
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
|
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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
|
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
65e8f2fb42 | Merge remote-tracking branch 'gh/docs/copilot-gate' | ||
|
|
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 |
||
|
|
cd094b6dfb |
fix(kb): the dj1l cases discriminate, and a replaced rule cannot silently become an add
Five findings from the second review round, and the first is this PR's own standard applied to its own P1. **The two fixes improvise-dj1l names had no discriminating test.** Reverting `has_key` to unification, or dropping `canon_key` from the duplicate gate, left kb-test at 27 passed. Case 11 was carried by `check_total` refusing with a DIFFERENT message, and case 10 by the other half of the fix. Both now assert which refusal fired (`said()`), plus two cases aimed at each half: a rm key with a variable in a non-final position must be refused as ABSENT rather than matching everything, and a keyed FACT whose key holds a variable must ADD without excluding the siblings it would unify with. Each proved by reverting exactly one fix and watching exactly that case fail. **Keying a rule on its whole clause made `replace` on an edited rule silently become `add`** -- both arms live, the stale one still firing, and `check_total` cannot see it because `NO + NF` is correct arithmetic for an add. Reachable on the 15 `kb_error/1` arms and the `kb_text/2` rules, so editing the check improvise-2f97 adds is the first thing to hit it. `check_rule_replace` refuses and names the route (rm, then add); the negative arm -- replace of a rule present verbatim -- is tested, or the refusal would just be "replace never works on rules". **The `decision(` arm was dead code.** `cited_name` took the first field, and the repo spells `decision(<ticket>, <name>)`, whose ticket id fails `name_shaped/1` on the hyphen -- so that marker could never fire for a real citation. A second `cited_name` clause takes the second field. All three markers are now exercised. Minor, from the same round: `_JS_TEST` no longer accepts `test.only`, which disables every other test in its file, with a case asserting a heading cannot be satisfied by one; and `node-test-test.sh`'s last case no longer duplicates an earlier one. Filed rather than fixed: improvise-w8ih, extracting `web/assemble.sh`'s gate so its own absence is visible. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
67ce2df421 |
docs: the Copilot gate is gone, and AGENTS.md told agents to wait for it
Measured: PRs #12, #21 and #27 carry 2, 8 and 4 Copilot reviews; #61, #66, #68 and #70 carry none. Both request paths report success and register nothing -- the GraphQL mutation returns clientMutationId null, the REST call returns 200 with requested_reviewers empty, and no review_requested event appears. So "merge only once Copilot passes" was an instruction to wait forever on a review that was never requested. An absent review and an unrequested one look identical from outside, which is review_is_requested_not_inherited seen from the requester's side. Review is now an adversarial agent the orchestrator dispatches, naming the head SHA it reviewed; the Copilot mechanics are kept for the day it returns. Found by the PR #70 agent, which noticed its own review request had produced nothing rather than assuming the review was queued. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
5c3c796308 |
docs: a wave skill, so the brief stops being retyped
Four agents were dispatched without worktree isolation and all edited the same working tree: one git status held one agent's effect.rs, another's harness/build.sh and a third's scripts/node-test.sh. Any commit would have swept up three units' half-finished work. The brief had carried that rule before and lost it, which is what a retyped brief does. It is now a skill: worktree isolation first, partition by crate rather than ticket count, the base commit by name, the baseline, the never-write list, the injection discipline, pr-watch --expect, and attribution. Two doctrines: every_wave_agent_gets_its_own_worktree records the tell and the per-agent recovery (copy only what an agent can PROVE it touched -- two units can legitimately both be in improvise-protocol); the_orchestrator_delegates_substantial_work records the user's rule and the non-obvious half of it, that orchestrator work lands in the shared primary tree and collides with agents who own that ground. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
50de0a8fd2 |
fix(kb): keys are compared as variants, and a cited clause cannot be silently retired (improvise-dj1l, improvise-2f97)
dj1l (P1, found by review of PR #68 after it merged). kb-merge.pl matched clause keys by UNIFICATION, which both lost and corrupted clauses. check_self_consistent compared keys with ==, but findall hands back fresh variables, so two clauses with variant heads were never == and passed the duplicate gate; foldl_merge then matched by unification and the second removed the first. Reproduced: 536 before, 2 in delta, 537 after. Worse, adding `probe_fact(X) :- doctrine(X,_).` over a kb holding probe_fact(a) and probe_fact(b) deleted probe_fact(a) AND wrote `probe_fact(a):-doctrine(a,A)` -- the match bound X, so the clause written was not the clause supplied. The round-trip verify cannot see that: it compares the file against an intended list already corrupted by the same unification. same_key/2 (copy_term + numbervars) in has_key, conflicts and absent; canonicalize before duplicate detection; a RULE keys on the whole clause, since one head shape with different bodies is ordinary Prolog; and check_total/2 asserts the arithmetic the tool already PRINTED beside the delta size -- "2 in delta, 537 after" was visible in its own output twice and nothing compared them. 2f97. kb_error(dangling_citation/3): a name cited inside another clause's text must resolve as a doctrine/2, invariant/2 or decision/3, so retiring a clause can no longer dangle every clause naming it. The token rule is narrow on purpose -- a name-shaped token directly inside doctrine(, invariant( or decision( -- so prose cannot false-positive. kb_error/1 is a gate predicate, so this was written with KB_ALLOW_GATE=1 deliberately: the refusal exists so a write cannot disarm its own gate, and an intentional change to the gate is supposed to be a greppable act rather than an impossible one. Seven cases added to kb-test.sh, each proved by injection: two variant-headed rules both land; a non-ground rule deletes nothing and is written as supplied; a duplicate key is still refused; an injected dropping fold is caught by the total; a cited clause cannot be retired; and the citation arm fires on a name that resolves to nothing without firing on one that resolves. scripts/kb gains a KB_MERGE seam so a broken merge can be injected. One pre-existing case moved off doctrine(bug_first), which the new arm correctly refuses to retire. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
fc6d229dda |
kb: design against the model before implementing, and fix the key rule it exposed
AGENTS.md has always said Prolog is a design tool for reasoning about tickets; it was the least-used line in the file, because kb.pl was only ever written retrospectively. `kb check --with <design.pl>` merges proposed facts into a throwaway candidate and runs kb_consistent over the union, so a design can be refused before any code exists. Nothing is written either way. The model already derives rather than records -- illegal_dependency, may_use, depends_transitively, portable, snapshot_safe, view_state_admits, record_obligation, and eleven kb_error classes. Three proposals exercised it in one sitting: one added dependency edge produced SIX layering violations through the transitive closure; a proposal to declare decision/3 functional was refused, correctly, because improvise-907 carries two decisions; and a mis-ordered layer/2 argument was named rather than accepted. Trying to model a design found a real defect in the tool. Keys were the functor plus all arguments but the last, which is right for doctrine(Name,Text) and wrong for any RELATION: crate_depends_on(A,B) keyed on A, so a crate depending on two crates read as one key twice and was unaddable. It cannot be read off the KB's functional/1 -- that keys an arity-3 predicate on its first argument, right for crate/3 and wrong for decision/3 -- so key_arity/2 is a table, and anything unlisted keys on the whole head, which is the safe direction. kb-test.sh is 20 cases. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
eaaf9d935a |
kb: a write cannot disarm its own gate, and cannot silently lose another's
Second review pass on PR #68. All three findings real; the first two reproduced by injection before fixing. The candidate is validated by CONSULTING it, so the thing being checked got to influence the check. Three ways through, all demonstrated: - `:- halt(0).` as a delta -- fixed last round by refusing directives - REMOVING kb_consistent: it then throws existence_error, and tpl exits 0 when a goal throws before reaching halt, so the gate passed by not existing. The error was printed and the tool still reported success. - REPLACING it with the fact `kb_consistent.`, which passes forever after. CHECK_GOAL now catches, so a throw exits non-zero, and writes touching the gate predicates are refused unless KB_ALLOW_GATE makes it deliberate. That list is hand-maintained and a new gate predicate is unprotected until named -- stated rather than hidden. Writes were read/validate/mv with nothing in between, so two agents -- ordinary here, waves run in parallel -- would both read the same file, both validate, and the later mv would discard the earlier addition. The lost-update class this tool exists to remove, reintroduced in the tool. Closed by stamping content at read time and refusing to commit if it moved, plus an mkdir lock. The stamp is the part that matters; the lock only makes the collision rare. AGENTS.md's top-level instruction still said to save facts through the MCP. The wave section had been fixed; the authoritative line had not. kb-test.sh is 17 cases. The race is deterministic via KB_TEST_RACE. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
7fd57c06b3 |
docs: say what to do; attribute what agents post
Two user rulings. Documentation should not spend itself on history -- that is bloat. Prose docs now lead with the rule and keep only the line that stops it looking arbitrary; the worked examples and the how-we-found-it move into doctrine/2 text, which is what that predicate is for and where a reader goes deliberately rather than while looking for a command. Trimmed: both skills, context/code/kb-tool.md, and the kb paragraph in AGENTS.md. Anything an agent posts to GitHub goes out under the owner's account, so every comment, review and issue body now opens with a line naming the model and that an agent wrote it. A PR body's generated-with footer already did this; comments carried nothing, and an unattributed one reads as his own words to every reader -- including a reviewer deciding how much weight to give it. The reply on PR #68 has been amended in place. improvise-xfsb files the structural fix: a GitHub App or machine user so agents post under their own identity. An attribution line is a convention an agent can forget; a separate identity cannot be. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
805bae7a15 |
kb: a clause can be retired, and the docs stop naming the MCP
Three gaps in the tool as first written, each found by asking what it could not do rather than by running it: - There was no way to REMOVE a clause. Every correction could add or overwrite, so a fact that went false could only be rewritten, never dropped. `kb rm` takes keys and refuses when any is absent -- a typo'd key would otherwise report success and leave the clause in place. - `doctrine(kb_is_maintained_through_the_mcp)` is retired for kb_is_maintained_by_scripts_kb. The NAME was the claim that went false, which is the repair opfs_is_run_but_bindings_is_not needed for the same reason. The replacement records why nobody should go back, and that READING through the MCP is unaffected. - AGENTS.md said kb.pl was "MCP-maintained, whole-predicate replacement" and told agents to strip host_rpc shims after each save. Both described the retired mechanism. This is a_fact_stated_twice_is_changed_by_grep landing inside the PR that depends on that doctrine being true. Also fixes a printed value that was an unevaluated expression: `rm` reported "530-529 removed" rather than 1. kb-test.sh is 11 cases now, both new ones proved by injection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
3405fc4def |
kb: retire the Prolog MCP for a tool that costs the clause, not the predicate
loadProgram REPLACES a whole predicate, so adding one clause meant re-sending every existing clause of it through an agent's context window. Measured on the wave-3 batch: ~113KB read and ~113KB written to deliver ~25KB of new text. That sets the behaviour -- writing becomes a thing you batch and do rarely -- and the batch is where a short payload silently drops the rest of a predicate, which has cost this repo 22 decisions and 19 doctrines once already. scripts/kb reads clauses as DATA and never consults them, so the cost of adding a clause is the clause. Canonical form is read_term in, portray_clause out -- measured, not designed: all 495 existing facts round-trip byte-identically and the form is a fixed point in one pass. Rules move to one line, which is why the reformat lands here rather than earlier: the MCP would re-expand them on its next save and the two would thrash. trealla moves into the devShell. Reaching it through `nix shell` per invocation took the tool's first real use past a two-minute timeout for a write that takes 0.42s with tpl on PATH. Four guards, each added because injecting its fault showed the tool accepting what it should refuse. None was found by reading: - an unparseable delta dropped trealla into its REPL, which HANGS with a terminal and EXITS 0 without one -- a refusal that reads as acceptance - `-g main,halt` exits 0 on a throw AND on a failure, because a goal that fails never reaches the halt beside it; halt(2) alone exits 2, so the default is the hazard. The goal now guarantees a halt on every path (0/2/1) - `42.` parses, is not callable, and landed as a fact whose head is a number; kb_consistent has no opinion about stray terms - fmt discarded the merge's exit code and would have committed a failed canonicalization Plus the two that were designed in: the result is read back and required to be the clauses intended (variant equality -- == compares variable identity and reports every rule as different), and kb_consistent runs on the CANDIDATE, so a bad delta leaves the knowledge base untouched rather than needing a revert. scripts/kb-test.sh proves all nine by injection. context/code/kb-tool.md carries the argument, including what it does not reach. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
2d22b65d1f |
kb: a Record is the settable arm, not the unsettable one
invariant(shipped_demo_cells_are_settable_or_derived) described the CellId::Record arm as "editable false". The boolean in the cited test is expected_derived, not editability, and the assertion message beside it says the two raw columns "must be Records the page offers" -- so a Record is precisely the SETTABLE arm and the clause stated the inverse permission. That is the failure doctrine(a_stale_gotcha_asserts_the_negation) names: a wrong doc does not merely omit, it tells the reader not to assume the thing that is true. Costly here because ADR 002 makes permission a fact about the CellId variant, so a reader trusting this clause had both permissions backwards. The replacement names the error rather than only avoiding it, so it cannot come back quietly. Verified against tests/web_demo_model.rs, not from memory. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
9fdf39dda2 |
kb: the wave-3 batch, and three corrections to clauses that had gone false
Applied through the MCP cycle (loadSession, four loadProgram calls, saveSession),
not by editing the file. Counts verified against the live file immediately before
writing, because the first read of them came from a working tree six merges behind
and would have deleted three clauses while reporting a larger total.
doctrine 56 -> 95 (+39)
invariant 51 -> 64 (+13, one of them a rename)
decision 48 -> 64 (+16)
work_done 20 -> 23 (+3)
Verified: kb_consistent passes (exit 0, the exact CI invocation); unique names
equal totals for all three keyed predicates; a name-by-name diff against
|
||
|
|
6378551641 |
Merge main into docs/wave2-batch-e
Only .beads/issues.jsonl conflicted; restored to main's export so the branch carries no beads diff. kb.pl auto-merged cleanly: doctrine/decision/ invariant counts 56/48/51 before and after. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |