improvise-c5ip, improvise-udt2: exit 1 on a refusal, never on an abort

The headless exit code read `last_batch_aborted()`, which answers "did a chain
stop", not "did the request happen" — wrong both ways. `commit-cell-edit` at
bottom-right lands its write, saves, and then `EnterAdvance`'s `AbortChain`
exited 1 (c5ip); `add-item` into a missing category refuses without aborting
and exited 0 (udt2).

`App` gains a per-batch `batch_refused`, reset beside `batch_aborted` and
written only by `App::refuse(msg)`, which sets the status and the flag
together; commands reach it through `effect::refuse`. `main.rs` exits 1 on
`last_batch_refused()` only. Not a severity on `status_msg`: that would be
portable ViewState and would go stale across its ~60 writers.

Strays into ui/app.rs (four small additions) — flagged in the hand-back.
Unconverted refusals are filed as improvise-i3o5; headless `q` as improvise-ep5o.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Edward Langley
2026-09-22 21:28:44 -07:00
parent 487f0b6fef
commit ffe8aed6b4
14 changed files with 281 additions and 53 deletions
+6 -7
View File
@@ -203,13 +203,12 @@ improvise cmd 'formula Product "Total = Widget + Gadget"' -f model.improv
TUI's status line, and stdout is left empty. A run that had nothing to report
prints nothing, so `2>/dev/null` is the whole suppression story and there is
no quiet flag.
- **Exit 1** means a line did not parse, or an effect aborted the rest of its
batch — a failed `:w`, say. **Exit 0 means neither of those happened**, and
it does *not* promise every command did what it was asked: a refusal that
only writes a status message (`add-item` naming a category that does not
exist) is printed but still exits 0, because a status message carries no
severity for the exit code to read. Check stderr as well as `$?` when it
matters.
- **Exit 1** means a line did not parse, or a command refused what it was
asked — a failed `:w`, `add-item` naming a category that does not exist.
A command that did its work and then had nowhere further to go — a
`commit-cell-edit` on the last cell, whose advance stops — is not a refusal
and exits 0. A few refusals are not yet classified and still exit 0
(improvise-i3o5), so check stderr as well as `$?` when it matters.
- **A run behaves as if its terminal were 80x24, whatever it runs in.** A page
of rows is a real distance — `page-scroll` moves the cursor by one — so
reading the actual window would make the same script write a different record