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
This commit is contained in:
Edward Langley
2026-09-21 05:11:52 -07:00
parent 20322ada6f
commit 99ec32d6f3
2 changed files with 11 additions and 3 deletions
+7 -3
View File
File diff suppressed because one or more lines are too long
+4
View File
@@ -279,6 +279,10 @@ doctrine(a_list_checked_for_length_reads_like_a_list_checked_for_completeness,'a
doctrine(a_consolidations_frozen_behaviour_is_a_date_not_a_decision,'A consolidation must PRESERVE the behaviour it moves, or its agreement test cannot tell \"both ends agree\" from \"both ends changed together\" -- so the moved rule is frozen FOR THE DURATION OF THE MOVE. Afterwards a single home reads as decided, and nothing in the tree says otherwise. improvise-8qlr froze name-only group coalescing because both prior copies did it; improvise-h0iv later changed it once for both ends, and found the test still pinning the old rule justifying itself with \"because that is what src/ui/grid.rs uses\" -- a clause 8qlr had already made false, since grid.rs calls group_run_heads now. When a consolidation lands, say in context/ WHICH of its behaviours were preserved for evidence rather than on merit; otherwise the next reader inherits a frozen date as a decision.').
doctrine(a_claim_in_context_must_name_the_file_it_was_checked_against,'PR #91 wrote \"keys.rs emits no ChangeMode\" into context/code/command.md to argue a divergence was latent. True and irrelevant: keys.rs holds only BrowserKey, and the live resolver is improvise_protocol::resolve, which emits it five times (improvise-e5pf). Nothing checks a claim in context/, which design-principles section 6 names as exactly why a reason must not be wrong there. So a NEGATIVE claim grepped from one file must name that file, and a reviewer must re-derive it from the CALL GRAPH rather than from the name. ROOT CAUSE, and it was the orchestrator: repo-map row \"Change what a browser resolves without the host\" pointed at wasm-client/src/keys.rs, so the author consulted the map, opened the named file and grepped it honestly. A stale pointer in the map does not merely fail to help -- it manufactures confident false claims, because the reader has done the work the map told them to do.').
doctrine(a_per_element_resolution_cannot_fix_a_per_batch_property,'improvise-sihr round 1 resolved AppMode::Normal inside each effect that sets it, and got the CROSSING case wrong -- a batch that leaves records and then sets Normal landed in RecordsNormal. Not an oversight: gotcha 23 means any SET-TIME read sees the batch OPENING layout, so no per-effect resolution can answer a question about where the batch ENDS. Round 2 moved it to one call, settle_normal_mode after rebuild_layout in apply_effects, and DELETED MORE THAN IT ADDED: three writers became one, ChangeMode went back to the simple_effect! macro, and the uncovered-edit finding dissolved rather than being patched. Ask \"where is the one place this can be answered\" BEFORE \"which writers must I teach\" -- and note the tell that the first answer was wrong: the author was writing a DEFENCE of the staleness rather than a test of it.').
doctrine(a_guard_seeded_on_agreement_cannot_detect_drift,'lockstep.rs records coverage sets host.view_state.mode = AppMode::records_editing() BY ASSIGNMENT and then seeds the client with client.view = app.view_state.clone(), so it begins from a state where the mode and the layout already AGREE. Every divergence it exists to catch requires them to DISAGREE, so the whole class is invisible to it by construction (improvise-e5pf). Same vacuity shape as gotcha 36 bystander already sitting on the relayed value, and as the improvise-t6db property whose two views differed only by having nothing to prune. A lockstep or agreement test must DRIVE THE INPUTS that produce the state, never hand-place the state -- hand-placing is what makes the fixture agree, and agreement is the thing under test.').
doctrine(a_substitution_is_a_defect_at_every_site_that_makes_it,'improvise-e5pf was filed as one command folded without a resolution. A sweep found the real fault is ONE SUBSTITUTION AT THREE DECISION POINTS: wherever the host asks layout.is_records_mode(), the client asks state.view.mode.is_records(). The wire command is only how the client REACHES the bad state; the substitution is why the bad state does damage, and it decides whether enriching the projection is even sufficient. Worse, the first site inverts its own failure mode: commit() is written to DECLINE a records commit it cannot compose, and with the mode wrong it does not decline -- it composes a typed_cell_command and a Basis claim against a records grid whose columns are [coords, +cat, measures, +], which is a WRONG WRITE rather than the intended black hole. When a ticket names a symptom, grep for the PROXY the symptom rests on; a proxy used once is used everywhere the same question is asked.').
doctrine(comparing_a_function_against_itself_tests_nothing,'improvise-jmjz fused three grid passes into one and guarded the width half with \`one_row.col_widths == compute_col_widths(model, &app.layout, false, 0)\`. But compute_col_widths IS grid_body with an empty window -- the same function twice -- so windowing the widths degrades BOTH SIDES IDENTICALLY (both collapse to the MIN_COL_WIDTH clamp) and the assertion cannot fail. Injecting \`if drawn { widen(..) }\` left 1476 tests passing. The fixture hid it a second way: the column header \"Revenue\" is wider than the value \"300021\", so the width assertion passed on the header alone. A check whose two sides share an implementation is a tautology wearing the shape of a comparison -- and a consolidation is exactly when one gets written, because the second implementation has just been deleted. The discriminating fixture puts the widest DATA value outside the window and makes it exceed both the header and the total (values 1, 888888888, -888888888: the total cancels to 1.0 so it cannot supply the answer).').
doctrine(a_negative_result_is_only_as_good_as_the_setup_that_produced_it,'PR #92 reported that a none_cats hazard was \"argued and unobserved at this shape\" after widening a fixture to probe it. Printing the actual axes showed Product on COLUMN in every view -- add_category defaults it there and nothing moved it -- so none_cats was {_Index, _Dim} identically everywhere and THE STATED INPUT TO THE HAZARD WAS ABSENT. The path was unprobed, reported as a negative result. This is an_injection_that_does_not_fail_names_an_untested_path applied to a SETUP rather than to an injection, and it is worse, because a recorded negative stops the next person looking. Before writing \"probed and not reproduced\", ASSERT THE PRECONDITION IN THE TEST -- print or assert the condition the hazard needs, so a fixture that drifted out of the shape fails loudly instead of reporting absence.').
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.').