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
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
This commit is contained in:
@@ -272,6 +272,8 @@ doctrine(a_control_you_already_have_is_cheaper_than_the_hypothesis_you_were_abou
|
||||
doctrine(an_injection_that_does_not_fail_names_an_untested_path,'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 AppMode::Normal left the three-mode characterization test GREEN. That is how the untested path was found: an empty colon line takes ExecuteCommand is_empty branch and settles through ChangeMode, so the effect that settles every colon line which actually RUNS had no test at all. Two tests exist rather than one because of it. When an injection passes, do not move on -- ask which path the test never reached.').
|
||||
doctrine(a_macro_effect_cannot_carry_a_derivation,'ChangeMode 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 instead. That is why improvise-sihr could hide: every minibuffer mode returned to a hard-coded Normal and nothing owned the question. Gotcha 16 already warns the macro kind argument must be mandatory; this is a second cost of the same shape. Reaching for simple_effect! forecloses any answer that needs a derivation, so if an effect ever might have to RESOLVE what it writes rather than copy it, write it out.').
|
||||
doctrine(a_ticket_that_pre_diagnoses_its_fix_as_a_protocol_change_deserves_checking,'improvise-9c9o was filed saying the honest fix needs the basis to follow active_view, which SwitchView being ViewOnly prevents -- i.e. a protocol change, not a one-liner. It was neither. The basis is App own bookkeeping and none of it is on the wire, so \"the basis follows active_view\" was achieved by moving WHERE the re-base happens -- into the loop, at the switch -- and SwitchView stayed ViewOnly. A pre-diagnosis in a ticket is a hypothesis wearing the authority of a decision, and the author of the ticket is usually the person with the least time to check it.').
|
||||
doctrine(prose_that_calls_a_change_free_is_a_claim_and_is_checkable,'The sibling of prose_that_calls_something_permanent_forecloses_the_ticket, found one paragraph below it in the same section. gp.md section 11 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 ignore-probe on both sides: 100 records, a 100-item numeric Year beside a Cost that predicts Score alone -- pre-fix the fit lands on IF(Cost < 48.015..) with Year never touched, post-fix the preflight refuses at 101 features. The suite was green on either reading. 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.').
|
||||
doctrine(forcing_by_name_while_budgeting_by_index_defeats_the_budget,'improvise-zv8t made fit_measure force header[..category_columns] to Forced::Categorical keyed by NAME, while encoded_width decides category-ness by INDEX. A document may legally name a regular category and a raw measure the same thing (a_category_and_a_measure_of_the_same_name_are_refused ships that fixture), so the MEASURE column was forced categorical by name match while the preflight still counted it numeric by index: measured 41 against 80 at 40 records. no_ambiguous_column_names ran AFTER preprocess, so the expansion the preflight exists to prevent was allocated and only then refused -- guard_the_cost_not_the_result defeated by an inconsistency the fix itself introduced, NOT the bounded approximation a_budget_check_is_advisory_or_exact_and_must_say_which licenses. Repair is a data dependency, not a moved line: as_categories runs the check and returns Result<Overrides>, so the Overrides preprocess needs cannot exist until the header is accepted. Guard is the SIGNATURE -- reordering the two statements is error[E0425], verified. Deliberate deletion of the check from as_categories is still possible and is stated rather than implied.').
|
||||
work_done('improvise-8tk',bug_fix,'ZZ/:wq quit even when the save failed, silently discarding the model. Save now aborts the effect batch on failure; save_to_current_path/1 returns Result<String,String>; three tests in ui/effect.rs.').
|
||||
work_done('improvise-907',bug_fix,'Import wizard step machine redesign: validation_error() gate at ReviewProposals (no-category and over-limit), history-stack previous() bound to Left on every step, and Done made a real confirmation step holding the built workbook. Superseded improvise-gfq, improvise-o1c, improvise-c6j.').
|
||||
work_done('improvise-6sq',wont_do,'Merging EditOrDrill and EnterEditAtCursorCmd into one EnterEdit{mode} is not safe: they differ in WHEN the cell value is read, not in a mode parameter. Added ui/app.rs::tests::i_and_o_diverge_on_an_empty_records_grid as executable evidence.').
|
||||
@@ -302,6 +304,7 @@ work_done('improvise-x4wv',bug_fix,'web/assemble.sh\'s stamped guard exited on t
|
||||
work_done('improvise-2f97',feature,'kb_error(dangling_citation/3): a name cited inside another clause\'s text must resolve as a doctrine/2, invariant/2 or decision/3. The token rule is narrow on purpose -- only a name-shaped token (lowercase, digits, underscores, at least one underscore) directly inside doctrine(, invariant( or decision( -- so prose cannot false-positive. Retiring doctrine(an_advisory_gate_is_not_a_gate) is now refused by name rather than silently dangling its citers. kb_text/2 is hand-maintained, like gate_predicate/1.').
|
||||
work_done('improvise-dj1l',bug_fix,'scripts/kb-merge.pl matched clause keys by unification, which lost and corrupted clauses: two variant-headed rules in one delta went two in, one out (536 before, 2 in delta, 537 after), and a non-ground rule over a predicate holding facts deleted one AND was written with its variable bound. See invariant(key_matching_is_variant_equality_never_unification). Five regression cases added to scripts/kb-test.sh, including one that injects a dropping fold to prove check_total fires; scripts/kb gained a KB_MERGE seam so a broken merge can be injected.').
|
||||
work_done('pr82-fingerprint-guards-2026-09-20',test,'PR #82, follow-up to #76. Added assert!(app.view().prune_empty) to selecting_the_page_already_selected_invalidates_no_cursor (paged_model(false) plus deleted moved-conjunct had left it GREEN); moved its page-selection precondition ahead of the effect and onto App::view(); corrected the test-evidence entry for every_layout_geometry_effect_is_visible_to_the_narrow_fingerprint, whose stated mechanism measurement contradicts, and recorded which two of its four prepare steps are load-bearing. 1425 passing, unchanged. Key is a dated slug and not an improvise- id, because bd issued none: an ID-shaped non-ID is worse than a dead id, the diagnosis being identical and the repair not.').
|
||||
work_done('pr90-io-gp-correctness-2026-09-21',fix,'PR #90, wave K. improvise-iot6: render_csv built GridLayout::new, which skips prune_empty, so :export and the CLI export path wrote rows AND columns the grid does not draw -- FOURTH instance of the trap and the first a user could see; fixed with with_frozen_records(m, v, None), the PR #78 grid_in fix line for line. A sweep of the remaining GridLayout::new call sites found all four are test code, so this was the last production instance. improvise-zv8t: fit_measure handed preprocess an Overrides::default(), so a numeric- or date-valued document category was inferred rather than forced categorical and the fit refused as an encoding artefact. Two self-review rounds and one adversarial round on the branch; the adversarial round found F2 (forcing by name, budgeting by index), which this PR itself introduced. 1458 -> 1464 passing.').
|
||||
work_followup('improvise-8tk','improvise-lae','no-file-path UX: prompt for a path rather than only erroring. ExportPrompt is CSV-only, so a new SavePrompt TextEntry mode committing to SaveAs is the likely shape.').
|
||||
work_followup('improvise-6sq','improvise-ct5','i on an empty records grid reports \'cannot drill\', leaking a pivot-mode concept into records mode').
|
||||
work_followup('improvise-h0b','improvise-a2x','ViewState field types (AppMode, MinibufferConfig, ViewFrame, KeyCode, KeyModifiers) still derive no Serialize, and improvise-command depends only on serde_json. Deferred: nothing serializes ViewState until improvise-cqi builds a Snapshot, so the derives would have no consumer.').
|
||||
@@ -379,6 +382,7 @@ decision('improvise-x7cq',every_check_job_gates_the_deploy_is_a_gate,'pages-depl
|
||||
decision('improvise-mcq4',cursor_frame_is_one_view_on_geometry_and_every_view_on_cell_data,'The LayoutGeometry arm hashes only the active view frame -- that is the held-key path the optimisation exists for, and other views cannot reframe there because view_mut() writes only the active view, with AddCategory/RemoveCategory/AddItem/RemoveItem already covered by view_shapes. The CellData arm hashes EVERY view, because a cell write can prune a row out of a view the host is not on. Measured: 0 percent on the held-key path, +5.7 percent on an 18k two-view SetCell, linear in view count and accepted. Absolute stated rather than only the ratio: the PR still roughly doubles held-key latency on large pruned documents, 3.04ms to 5.69ms at 18k, and 56ms at 90,000 cells is 3.4 frames.').
|
||||
decision('improvise-ni6k',cursor_invalidation_is_observed_not_declared,'No effect calls reset_cursor. apply_effects diffs the grid frame after every model effect, INSIDE the loop, because a batch that reframes and then places the cursor loses the placement otherwise (four records-mode tests pin that position; two after the arms were split). Total over EffectKind::Model(_) by construction rather than by a maintained list -- the thirteen per-effect calls it replaced are gone, and the \"a geometry effect that forgets to reset is invisible in both directions\" hazard is closed for model effects. Totality remains conditional on CLASSIFICATION, which nothing makes total: a ViewOnly effect that renumbers the grid is invisible to all of it.').
|
||||
decision('improvise-864a',pages_artifact_reaped_by_a_foreign_successful_deploy,'Measured over 100 push-to-main runs 2026-09-19..2026-09-21: 12 of 12 artifact-not-found deploy failures had ANOTHER run SUCCESSFUL Pages deployment complete inside their own upload-to-deploy window, against 2 of 56 successes. Direction proved by the oldest run of the 17:47Z batch failing BEFORE the next deploy started and before any deployment existed, since deploy-pages fetches artifact metadata before creating one. NOT queue depth, NOT supersession, NOT retention, NOT the action deleting it. PR #46 tip-of-main guard aimed at the right quantity for the WRONG REASON and still must not ship: the association is not a mechanism, and 5f871f7 survived a foreign deploy inside its own window. Reproduce deliberately before fixing.').
|
||||
decision('improvise-zv8t',a_document_category_is_never_inferred,'fit_measure now builds its Overrides from the same header[..category_columns] slice it already handed Features::of, forcing each to Forced::Categorical, so the one place the document own answer was known is the only place either caller reads it from. Closes Artefact::NumericCategory and DatePart-over-a-category from the only production entry point. The Artefact arms STAY: crate::dataset is pub and takes the caller Overrides, so a caller that builds one without forcing still produces a Numeric role over a category column -- deleting the arm would derive the classification from one caller habits rather than from the roles. Cost accepted and filed as improvise-e8no: a wide numeric category now one-hots past MAX_FEATURES and refuses a fit that used to ignore it. Do NOT close e8no by making the forcing conditional on cardinality -- that is inference by another name, and makes the ENCODING depend on a budget rather than on what the document says.').
|
||||
wire_carries(command,both_directions,'user intent up, projection commands down').
|
||||
wire_carries(snapshot,on_connect_only,'improvise-q08: full ViewState + render cache filled from current viewport').
|
||||
wire_carries(command,both_directions,'user intent client->server, projections server->client').
|
||||
|
||||
Reference in New Issue
Block a user