From 3475b029560d4c5417cc3f977fe5470fffe60ea4 Mon Sep 17 00:00:00 2001 From: Edward Langley Date: Wed, 23 Sep 2026 08:39:57 -0700 Subject: [PATCH] improvise-9trl: pin the remove-formula refusal and its exit code A script that removes a formula that is not there now refuses and exits 1, where it used to exit 0. The None arm had no test, so reverting it to a silent no-op left the suite green. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze --- context/code/cli.md | 10 +++++++ context/test-evidence/command.md | 10 +++++++ .../src/command/cmd/effect_cmds.rs | 28 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/context/code/cli.md b/context/code/cli.md index 0200feca..ba99b444 100644 --- a/context/code/cli.md +++ b/context/code/cli.md @@ -319,3 +319,13 @@ are listed in improvise-i3o5. `q` on a dirty document is deliberately left a report: headless, its text is false — the CLI saves anyway (improvise-ep5o). The two rivals udt2 named both stay green: a successful `:w` and a successful `fit-measure` report through `set_status` and exit 0. + +**`remove-formula` of a formula that is not there now exits 1** (improvise-tej1, +improvise-9trl). It used to exit 0: the effect was keyed by names and removing +nothing was a silent no-op. Since tej1, `RemoveFormula` names its formula by +`FormulaId`, and `remove-formula ` resolves the two names +to an id in `execute`. When nothing matches it `refuse`s with `No formula for + in `, so a script that removes a formula it never added now +fails where it used to pass. That is the §10 rule applied: nothing changed, so +the request was not met. `remove_formula_of_a_missing_formula_is_a_refusal` +pins it, with a present formula as the control. diff --git a/context/test-evidence/command.md b/context/test-evidence/command.md index 156de170..2b2029ba 100644 --- a/context/test-evidence/command.md +++ b/context/test-evidence/command.md @@ -6008,3 +6008,13 @@ from the landed cell and untouched. flag. This test fails alone. Every other test stays green, which was the gap. Once improvise-fy9o re-seeds the reopened editor, a stale `touched` would make every untouched Tab or Enter write its seed. + +### remove_formula_of_a_missing_formula_is_a_refusal + +improvise-9trl, from the review of #223. The script command's `None` arm refuses, +which is what makes `main.rs` exit 1, and nothing tested it. Rival: `None => +vec![]`, the silent no-op the command had before. With it, the whole suite +stayed green, and this test now fails on `last_batch_refused`. The control +arm, a formula that is present, must not refuse and must remove it, so a +command that refused every call cannot pass. + diff --git a/crates/improvise-command/src/command/cmd/effect_cmds.rs b/crates/improvise-command/src/command/cmd/effect_cmds.rs index 645a587c..44d93e32 100644 --- a/crates/improvise-command/src/command/cmd/effect_cmds.rs +++ b/crates/improvise-command/src/command/cmd/effect_cmds.rs @@ -67,6 +67,34 @@ mod tests { assert_eq!(view.categories_on(Axis::Column), vec!["Type", "Month"]); } + /// improvise-9trl: a script naming a formula that is not there is refused, + /// so `main.rs` exits 1. It was a silent no-op that exited 0. + #[test] + fn remove_formula_of_a_missing_formula_is_a_refusal() { + let mut m = two_cat_model(); + let tax = crate::formula::parse_formula("Tax = Food * 0.1", "Type").unwrap(); + m.model.add_formula(tax); + let layout = make_layout(&m); + let reg = make_registry(); + let ctx = make_ctx(&m, &layout, ®); + let run = |args: [&str; 2]| { + let args = args.iter().map(|s| s.to_string()).collect(); + let mut app = crate::ui::app::App::new(m.clone(), None); + app.apply_effects(RemoveFormulaCmd(args).execute(&ctx)); + app + }; + let missing = run(["Type", "Profit"]); + assert!( + missing.last_batch_refused(), + "{}", + missing.view_state.status_msg + ); + assert_eq!(missing.model_state.workbook.model.formulas().len(), 1); + let present = run(["Type", "Tax"]); + assert!(!present.last_batch_refused(), "the control must not refuse"); + assert!(present.model_state.workbook.model.formulas().is_empty()); + } + #[test] fn write_cmd_without_args_saves() { let m = two_cat_model();