074569e1503d9b3c67185a6c1280674ebd6f55fe
1261 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
074569e150 | chore: add skills in less claude-specific locations | ||
|
|
856a5f84eb | chore: update issues.jsonl | ||
|
|
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 |
||
|
|
532c7f2405 |
docs: the gotcha-44 gap list named two closed tickets as open
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
improvise-h0iv and improvise-1wl0 are both fixed — group_runs coalesces by
header identity via ptr::eq, and AxisFrame::first carries no serde(default),
its doc comment saying why. The repo map listed both as 'still open beside
it'. Verified against the code before correcting.
That is the second time this exact paragraph has done it, and
doctrine(a_stale_list_of_what_is_missing_is_worse_than_no_list) was written
about its previous instance — by me, two days ago, after which I committed
the next one. A list of what is missing decays in the one direction that
reads as a to-do.
Also files the bug-hunt findings. Six hunters over six territories produced
five P1s, every one demonstrated rather than reasoned:
dy3j a Label category is not persisted, so a document with 12 categories
plus a label can NEVER BE REOPENED
o9uq in records mode edits someone else's record and can rename it
away — silent data corruption from a documented key
pv3g fit-measure panics on large finite values; a hard crash in the TUI
bd9o the browser reaches records mode through the tile bar, and everything
it can do there is silent
(plus the P2 set: prune_empty never persisted, the browser drawing neither
page bar nor totals, two prune_axis_items group bugs, an inline-edit
commit addressing the current cache while the screen is frozen)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
|
||
|
|
70025e2e33 |
chore: close PR #98's three tickets
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
improvise-lltt (P1), improvise-e5pf and improvise-ac2z all landed in #98 and were left open — I closed #96's tickets on merge and not #98's. Each verified against merged main rather than the PR body: App::view_mut() is gone and view_mut_of is present; resolve::changed_mode is gone and settled_mode is in improvise-protocol; grid_in::rederived_for is present. Second occurrence of this gap. The first was 26 tickets at once, and the cause is the same: .beads is orchestrator-only, so an agent cannot close what it fixed, and closing is a separate step I have to remember after every merge. 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
|
||
|
|
ae4ba44d60 |
Merge pull request #98 from fiddlerwoaroof/wave/operandless-commands
Wave L: operandless commands name their operand (lltt, e5pf, ac2z) |
||
|
|
787e354b9b |
doc-site: name context/code/pr-review.md as an omission
The `build` job fails on main and on every branch merged from it: doc-site: context/code/pr-review.md is neither published nor a named omission NOT a merge loss -- scripts/build-doc-site.mjs in this branch is byte-identical to main's, and neither lists the file. PR #96 added context/code/pr-review.md without a manifest line, which is exactly the gate improvise-res9 added: a doc added without a line publishes nothing and says nothing, so the generator refuses. Omitted rather than published, and the line is cloud-agents.md's rather than tooling.md's. tooling.md explains checkers a reader of the code will meet; pr-review.md is about THIS REPOSITORY'S PROCESS -- where a Codex review appears, how to tell it from our own agents' comments, why absence is not approval. Nobody visiting a website is about to read a PR thread. Both homes updated, because an omission is restated beside the manifest AND in doc-site.md section 2, and the prose there counted them ("Neither is referenced...") so it went stale at three. This strays into scripts/, which is Wave N's ground. Flagged in the hand-back; it is a one-line data entry either way if the orchestrator would rather publish it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
3d0850c132 |
Merge main (d7bfcbb, PR #96) into wave/operandless-commands
Two textual conflicts, and one the merge resolved cleanly and wrongly. effect.rs: #96 extracted the LayoutGeometry list into layout_geometry_cases() shared by two tests, one of which compares it against the wire vocabulary; my side had added ViewTarget arguments and carried the base's assert_eq!(cases.len(), 13). Kept #96's structure with my arguments and dropped the count -- the list-versus-vocabulary check is strictly stronger and a count beside it would be a second answer to the same question. Verified the count came from the merge base, not from my side, before dropping it. test-evidence/command.md: both sides appended entries at the same point. Kept both. app.rs auto-merged CLEANLY and did not compile: improvise-4dpj's new a_batch_that_leaves_records_settles_out_of_records_normal constructs effect::SetAxis, which now carries a view operand. Fixed with ViewTarget::Active -- the host's own key path, which is what that test is. Checked rather than assumed, per the brief: - Test names diffed BOTH ways against the union of the two parents, not the count. Union 1510, merged 1509, exactly one name absent and it is the intended one: a_hosts_none_cats_leak_into_another_views_formula_columns, the ac2z characterization test my own branch replaced with a_formulas_columns_survive_a_host_that_aggregates_differently. Nothing else lost, nothing unexpected gained. - #96's the_enumeration_names_every_variant_the_derive_declares is still discriminating against the reshaped ModelCommand variants: dropping TransposeAxes from every_model_command() fails it by name. - The test-support feature stays off in shipped builds: cargo tree --edges normal --target wasm32-unknown-unknown finds no serde_json. And the finding the brief asked for, which is the opposite of a disagreement: #96's switching_views_across_records_ness_settles_against_ the_view_switched_to is the HOST-side twin of the client fix in this branch. Same batch, same crossing in both directions, and independently the same phrase in its message. Neither is redundant -- nothing in the projection stream carries the host's ViewState, so a host-side guard cannot see a client's mode or the reverse. Cross-referenced in context/test-evidence/clients.md so neither is deleted as a duplicate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
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 |
||
|
|
d7bfcbbd93 | Merge gh/main (PR #96) into orchestrator main | ||
|
|
f1d98534f4 |
Merge pull request #96 from fiddlerwoaroof/wave/gate-and-coverage
Three checks that could not fail: duplicate evidence headings, the records-mode settle, the LayoutGeometry case list |
||
|
|
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 |
||
|
|
60bb3c56f1 | Merge gh/main (PR #97) into orchestrator main | ||
|
|
f5df19553e |
Merge pull request #97 from fiddlerwoaroof/wave/format-and-fit
Wave M: number-format precision (711n), preflight under-count (x1ns), e8no declined |
||
|
|
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 |
||
|
|
81fe546594 |
Settle the mode by observing the grid, not at each composition site
ChatGPT Codex's P1 on #98: switch_view_at composes [SwitchView(target), ChangeMode(Normal)], and changed_mode settled that against the grid the client STILL HOLDS -- the outgoing view's. Records -> pivot emitted RecordsNormal and pivot -> records emitted Normal, which is the cross-view drift this PR exists to close, by a second door. The hand-back predicted this as follow-up 3 and called it unreachable because R is a stranding decline in the browser. That is right about the TOGGLE route and wrong about this one: records-ness is auto-detected from the axes (gotcha 1), so a view switch changes it with nothing in the batch saying "records". One door was enumerated and there were two. So the remedy is general rather than a patch to switch_view_at. changed_mode is DELETED; every site emits the plain AppMode::Normal; and ClientState::fold settles after every fold against the grid it HOLDS. Route-independent, so no enumeration of composition sites is load-bearing any more -- the same shape the repo already prefers in cursor_epoch over matching on CycleAxis, document_generation over matching on LoadModel, and the dirty flag over a table of command variants. improvise_protocol::settled_mode is the one rule and all three ends call it: ClientState::fold, ClientSession::fold (the server's mirror, so the two cannot diverge in a field nobody currently reads today) and App::settle_normal_mode. App::normal_mode is gone -- it was that function's host-side duplicate, and my change orphaned it. Bidirectional coverage drives a real Host: a session connected to a records-mode host, the pair folded locally and sent as a ClientFrame::Commands, every reply delivered in arrival order. The composed ChangeMode carries the STALE answer deliberately, because composing the friendly value would let the records -> pivot direction pass under the fault. Both directions fail with settle_mode no-opped, each proved separately since the loop stops at the first. Evidence, the injections and why the first fix's unreachability argument was too narrow: context/test-evidence/clients.md, context/code/protocol.md. 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 |
||
|
|
67905d9440 |
scripts: pr-reviews, because twenty PRs merged with their reviews unread
Prints a PR's reviews and says whether each targets the CURRENT head or an earlier one, because that changes what you do: a finding against an old commit may be fixed or still live, and both have happened this week. --wait blocks until a review lands against the head. Observed latency is ten to fifteen minutes after a push, so a merge four minutes later races the review that was about to arrive. When it times out that is a decision to merge unreviewed, not a clean bill. The detection rule is placement, not authorship: Codex posts under the owner's account, the same one our agents use, and ENDS with its attribution where ours OPEN with theirs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
49c6af1978 |
Merge main (95657dc) into wave/operandless-commands
|
||
|
|
dedf9641cd |
Merge gh/main (95657dc) into wave/operandless-commands
|
||
|
|
498582deb1 |
Bound every_model_command() with the derive (improvise-26dm, Codex P1)
The right-hand side of the LayoutGeometry completeness diff was a second hand-written list. Both this branch's own review and ChatGPT Codex found it, and the previous commit corrected the PROSE; Codex asked for the FIX. This is it. the_enumeration_names_every_variant_the_derive_declares diffs every_model_command() against variants::declared::<ModelCommand>() -- serde's derive-generated variant list, improvise-5ubs's mechanism. The chain is now derive -> every_model_command() -> model_effects -> case list, every link checked, which is what the ticket asked for. Injection is Codex's own, run end to end: a ModelCommand::ProbeGeometry whose effect declares LayoutGeometry, with the model_effects and variant_name arms the compiler forces, omitted from BOTH lists. Before: the whole workspace green. After: staged, each stage naming the probe -- every_model_command() never constructs ["ProbeGeometry"] then, with the enumeration repaired and only the case list short, the_layout_geometry_cases_are_every_wire_effect_of_that_kind right: [... "ProbeGeometry" ...] The staging is the point: the two tests answer different questions. SCOPE OVERRUN, declared. `variants` was `#[cfg(test)] pub(crate)`, not merely `pub(crate)`, and `declared()` needs serde_json, which improvise-protocol carries only as a dev-dependency -- so the authorised one-token change could not work. What it took instead, all plumbing, no behaviour change: improvise-protocol/Cargo.toml serde_json optional + a `test-support` feature improvise-protocol/src/lib.rs #[cfg(any(test, feature = "test-support"))] pub improvise-command/Cargo.toml dev-dep enables that feature The feature is OFF in every shipped build: `cargo tree --edges normal --target wasm32-unknown-unknown` shows no serde_json, and all eight wasm-gated crates still check clean. Drop this commit if the crossing is unwanted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
c2bc939608 |
improvise-x1ns (2nd): the preflight counts a date measure's parts
P1 from ChatGPT Codex on #97, live at
|
||
|
|
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 |
||
|
|
730f39a514 |
Merge pull request #95 from fiddlerwoaroof/docs/read-the-reviews
docs: read the reviews before merging; authorship will not identify them |
||
|
|
7c72f60713 | Merge branch 'main' into wave/gate-and-coverage | ||
|
|
267769a497 | Merge commit 'ea206bf' into wave/format-and-fit | ||
|
|
ab6bb41da3 |
Review of this branch: two checks that could not fail, one drift left live
changed_mode settled only Normal -> RecordsNormal, but the host's
settle_normal_mode settles BOTH members of the pair, so a RecordsNormal
over an ordinary grid stayed put on the client and became Normal on the
host. Esc out of RecordsEditing resolves through entered() to
`enter-mode records-normal`, so the mirror-image drift was reachable by
the same route the fixed one was. Now total, with the pass-through arm
and both negative rows asserted.
a_compacted_seed_folds_to_the_same_cache_as_the_whole_history left
GridCache::records at its default, so a seed() that OMITTED the arm
compacted to an equal cache and the check could not see the omission.
The history now sets it; deleting the arm from seed() fails the test.
grid_updates' records arm had no test at all: grid_of setting the field
is covered by lockstep, but a client that connects before records mode is
entered learns only through the diff.
Evidence for all three, with the injected faults:
context/test-evidence/{clients,command}.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
|
||
|
|
f6fca7ec98 |
A formula is evaluated for the view being projected (improvise-ac2z)
rebuild_layout recomputes formulas for the HOST's none_cats, and grid_in's elsewhere path built another view's GridLayout against that cache. The cache is keyed by the coordinates the recompute used, so a Total keyed without a Product coordinate is not found by a view with Product on Column, and prune_empty drops the formula's columns entirely. Absent columns, not wrong numbers. grid_in::rederived_for clones the model and recomputes for the target view's none_cats. Three conditions gate the clone -- another view, different none_cats, at least one formula -- so a client on the host's own view pays nothing and a formula-free document pays nothing ever. This is an interim and the cost is why: a whole-model clone plus a fixed-point recompute per projection on exactly the broken path. The ticket's first candidate, keying formula_cache by none_cats so one Model holds more than one view's derived values, is the durable answer and is an improvise-core change outside this wave's ground. The characterization test is replaced by the positive one, and the none_cats carve-out is dropped from a_clients_grid_does_not_depend_on_which_view_its_host_is_on -- which is the general property this is an instance of, and which fails under the same injection. Evidence: context/test-evidence/command.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
618801701e |
The browser asks the grid what kind of grid it is (improvise-e5pf)
One substitution at three decision points: wherever the host asks layout.is_records_mode(), resolve.rs asked state.view.mode.is_records(). The two agree only while the mode and the layout agree, and Command::ChangeMode(AppMode::Normal) is the message that separates them -- the host settles Normal against the layout the batch ends on, reduce_view folds the variant it was handed. GridCache::records carries the fact, projected by grid_of off layout.is_records_mode() and diffed like the extent. Deriving it on the client from row_frame.cats would have been a second implementation of is_records_mode (improvise-edp's disease); deriving it from the mode is the bug. Like Extent it frames nothing, so apply does not re-fit and its batch position is not load-bearing. The client's settling has one home, resolve::changed_mode, reached by every site that can emit AppMode::Normal -- including entered(), which is how a bound `enter-mode normal` gets there. The three decision points ask state.grid.records, so a commit at a records cell declines rather than composing typed_cell_command against a grid whose columns are [coords.., +cat, measures.., +]. lockstep now DRIVES the keys: in_lockstep presses on both ends and refreshes the client from a real projection rather than from the host's slice, which is what let the old records coverage start from agreement. The reachable path is Tab (category panel) then Esc; c/f/v are Ignored in RecordsNormal and R is a stranding decline, which a first draft of the test found the hard way. Two resolve.rs fixtures put a records mode over a non-records grid -- a state no host can produce -- and had to be corrected with the fix. Evidence and both injected faults: context/test-evidence/clients.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
7bc26f80d5 |
Review round 1: three checks that did not check what they named
All three found by the adversarial review of
|
||
|
|
f128087999 |
review: correct six prose claims, four of them false
An adversarial review of this branch found that the prose was worse than the diff — including, twice, in the exact genre the branch was congratulating itself for catching. Recorded rather than quietly rewritten, because that is the shape. Must-fix, all verified before correcting: - `fit.rs`'s comment on the exact check still read "this is the check that enforces the bound in both directions of a drift" — verbatim the sentence gp.md §14 now spends 25 lines refuting. Gotcha 48's third clause exactly: a fact stated twice is changed by grep, not by edit. I refuted the copy in the prose and left the copy in the code. - "false for eight months" was fabricated. `encoded_width` landed 2026-09-19, the sentence 2026-09-20; the repository itself is six months old. A paragraph whose point is that unchecked cost claims are checkable closed on one. - "NumericCategory was the one artefact family with no coverage" is false: it was one of three, and `ValueOfAMeasure` and `AbsentCoordinate` still have none. Corrected in both files that said it, and the remaining gap is named. The decline's stated reason was wrong, which matters most because a decline is the artefact nothing checks. It claimed one-hot is the only encoding of a category whose splits are spellable; `is_expr` is a `primary`, so an ordinal split IS spellable as a weighted indicator sum. Verified by running `parse_formula`, not by re-reading the grammar, and now pinned by `an_ordinal_split_on_a_category_is_spellable_as_an_indicator_sum` so the paragraph cannot go quietly wrong again. e8no stays declined on grounds that survive: a category's items carry insertion order rather than magnitude, and the emitted formula spells one IS per item either way, so the width is not saved. Also weakened two overclaims — "marking it a Label yields the same fit" (false: the feature count moves the RNG draw sequence, gotcha 37b) and "asserted rather than argued" (the dichotomy is argued from spell()'s exhaustive match; the test asserts one instance) — narrowed "the only coordinate predicate is is_expr" to what is true of it, corrected an uncheckable test count, named which two of the three consumers of parse_number_format are actually guarded, and moved an evidence block that had been inserted under the wrong module heading. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
1dd6950ed3 |
A view-scoped ModelCommand names its view (improvise-lltt)
Nine ModelCommand variants configure a view and named it implicitly: the effect read App::view_mut(), the HOST's slice. Since improvise-jytm made ViewState::active_view authoritative per client, a client on another view moved the host's view instead of its own -- its grid did not change and every other client's did. Each of the nine now carries `view: String`; model_effects maps it to effect::ViewTarget::Named, and the nine effects carry a ViewTarget rather than reading an ambient one. There is no operandless form left: App::view_mut() is deleted and replaced by view_mut_of(&ViewTarget), so a future geometry effect has to say which view it writes. The host's key path passes ViewTarget::Active, which is right -- the TUI is the host and has no session to ask. A Named view the document has not got is a no-op rather than resolve_view's fallback onto the default. Second half, which the ticket did not predict: naming the view made a reframe of a view the host is NOT on reachable, and adopt_cursor_epoch could not see one -- cursor_epoch is bumped only by the host's own reset_cursor, so those clients were reset by nobody and told nothing (gotcha 24's strictly-worse-than-nothing state). App::last_reframed_elsewhere is the second trigger; its opening frames are taken lazily inside view_mut_of, the one door such a write goes through, so the held-key path still hashes one view and improvise-mcq4's declined cost is not paid. Evidence and the three injected faults: context/test-evidence/command.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
019cbc1f72 |
Check the LayoutGeometry case list for completeness (improvise-26dm)
assert_eq!(cases.len(), 13) catches a case being DELETED from the list and never one being ABSENT from it, and the two are written identically as an assert_eq over a number. The adversarial review of PR #78 added a fourteenth pub struct declaring LayoutGeometry, pointed at by nothing, and the suite stayed green. doctrine(a_list_checked_for_length_reads_like_a_list_checked_ for_completeness). improvise-5ubs's mechanism cannot reach this one -- an effect is a struct implementing a trait, so serde has no derived enumeration to diff against. The WIRE vocabulary does have one, and model_effects maps each ModelCommand variant back to the effect it came from (gotcha 38), so the list is now diffed against the LayoutGeometry effects reachable through ModelCommand. The two sets are equal today, which is the evidence the substitution lost nothing. Injection: drop TogglePruneEmpty -- the old count said 12 != 13, this names the effect. reduce.rs's test module, every_model_command and effect_type_name become pub(crate) so the enumeration and the name reader have ONE home rather than a second copy in effect.rs. Residual, stated in the evidence rather than closed: total over the wire, not over the effects. An effect no ModelCommand names is still invisible -- exactly PR #78's probe. A second [...; 13] array survives one function away in every_layout_geometry_effect_is_visible_to_the_narrow_fingerprint; filed, not smuggled in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
aa06a9db84 |
improvise-711n: pin that a multibyte format string cannot split a char boundary
`format:` is `rest_of_line` in `improv.pest`, so the format string can hold any text. `leading_digits` slices at the byte index `str::find` returns, which is a char boundary by construction — but that is an argument, and this is the test. It also pins that a non-ASCII digit (U+0662) names no precision rather than one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
78ca25b5e0 |
Test both arms of the records-mode settle (improvise-4dpj)
settle_normal_mode matches `Normal | RecordsNormal`, and replacing that with a
one-way `Normal` left the ENTIRE workspace suite passing: the existing crossing
test drives the layout both ways, but both branches end in `enter-mode normal`,
so the settle is handed `AppMode::Normal` either way. It discriminates "settles
at all" and "settles against the ending layout", never "settles from either
mode".
Gap 1, a_batch_that_leaves_records_settles_out_of_records_normal: the
production repro -- SetAxis { "_Index", Axis::None } from a records grid.
Injection is the one-way guard; it is the only test in the workspace that fails.
Gap 2, switching_views_across_records_ness_settles_against_the_view_switched_to
(raised by ChatGPT Codex on PR #91, verified correct on main first): the batch
SwitchViewAtCursor emits, both ways. A genuinely different path -- records-ness
is auto-detected from the axes, so nothing in the batch says "records".
Injection is moving the settle back above rebuild_layout; both fail by name.
Scope note in the evidence: this drives the effects, not the view-panel key
path, which needs a CmdContext in another wave's ground this round.
Also carries the command.md half of improvise-hsoe's three duplicate headings.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
|
||
|
|
383e33a1a0 |
Refuse a duplicate test-evidence heading (improvise-hsoe)
--check-evidence verified that a heading names a test that RUNS, and a duplicate names one just as well, so both copies pass. PR #92 shipped two entries under one heading; the older described a fixture the test no longer had. Refuse rather than warn, on the improvise-rm4s precedent, naming the file and every line in file order. Keyed by the RESOLVED test, so `### f` beside `### m::tests::f` collides too -- the case rm4s's qualification repair creates. Six SELF_TEST_DUPLICATES cases, including the three clean arms: two different tests sharing a leaf are ambiguous and not duplicate, prose repeats freely, and two headings naming two tests are fine. Resolves the two tui.md duplicates: the older column-header copy called THE_MEMBERSHIP_CORRECT_SPANS a live tripwire three hundred lines above the entry recording its removal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH |
||
|
|
e045f9871b |
improvise-x1ns: the preflight counts the (missing) one-hot; improvise-e8no declined
improvise-x1ns (found by ChatGPT Codex on PR #90, live on main at
|
||
|
|
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 |
||
|
|
3775d4ea1a |
improvise-711n: a trailing conversion letter no longer erases the precision
`parse_number_format` read the precision as `fmt[i+1..].parse::<u8>()` over
everything after the last `.`, so `,.2f` — the printf spelling the repo-map's
own `.improv` example carries — failed to parse and fell through to zero
decimals, silently, in the TUI, the browser projection and CSV export.
The precision is now the leading digit run after the last `.`, with any
conversion letter ignored. The spellings that are legal are stated once, in
`context/code/core.md`, along with why the trailing `f` is accepted rather than
refused (the grammar takes the format line as an opaque `rest_of_line`, so
refusing it rejects documents this repo already writes) and why the reading is
printf's rather than Excel's (`.00` is the spelling the two disagree on).
`export_csv_quotes_commas_per_rfc4180` asserted the value `starts_with("1,200")`
against a `,.2f` fixture, so it could not tell two decimals from none. It is now
an exact equality, and reverting the fix fails it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
|
||
|
|
ce895ff560 |
Merge pull request #94 from fiddlerwoaroof/docs/ext-diff-and-ci
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
kb: a check that returns empty for the wrong reason passes |
||
|
|
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 |
||
|
|
950c16bceb | Merge gh/main (PR #92) into orchestrator main | ||
|
|
be0be40b5a |
Merge pull request #92 from fiddlerwoaroof/wave/protocol-render-gaps
wave I: protocol render and basis gaps (t6db, 5ubs, 1wl0, h0iv, jmjz, 1l9o, 44ad, 9v0j) |
||
|
|
d41c8b8e6f |
Merge main (1a9f45a) into wave/protocol-render-gaps
#91 and #93 landed while this wave was in flight and appended to the same four context/ files. That conflict is why CI never ran: a pull_request workflow builds refs/pull/N/merge, and a CONFLICTING PR has no merge ref, so no run is ever created. Neither the close/reopen nor the empty commit could have helped. Resolution: keep both sides. Only context/test-evidence/protocol.md conflicted textually; the other three auto-merged. Verified with --no-ext-diff that nothing of this branch was dropped -- the only removals are main's own rewrites, of the frame-basis paragraph in context/code/command.md and of the minibuffer-exit entry (renamed _to_plain_normal -> _to_records_normal) in test-evidence/command.md. NOTE the first three "nothing was dropped" checks were WORTHLESS and read as clean: an external diff tool is configured, so `git diff | grep '^-'` was grepping a side-by-side format for unified-diff markers and matched nothing whatever the content. --no-ext-diff is what actually answers the question. A check that returns empty for the wrong reason is indistinguishable from one that passes. Fixed while re-reading, and pre-dating the merge: this branch had TWO entries headed a_window_narrows_the_cells_and_neither_the_totals_nor_the_widths -- the original, describing a fixture that no longer exists and repeating the claim the PR #92 review measured false, and the superseding one. Merged into a single entry whose subject is what each of the three fixtures was blind to. The evidence checker cannot see this: it verifies that a heading names a real test, and a duplicate heading names one just as well. Merging gh/main ( |
||
|
|
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 |
||
|
|
1a9f45a438 |
Merge pull request #93 from fiddlerwoaroof/docs/wave-j-facts
docs+kb: the map pointed at the wrong file, and that manufactured a false claim |
||
|
|
8acce9dfa8 |
ci: nudge — the pull_request event for 902a77c was never delivered
No workflow run exists for |
||
|
|
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 |