fix: what an audit of the documented behaviour found

An independent check of every behaviour AGENTS.md was to describe:
- `--units ,` and `--only ,` skipped their empty items and so had no
  filter left: a typo started a run of every unit. They are usage errors
  now (exit 3).
- Two fixes the plan lists were missing: a dry run now clears the prompts
  a dry run before it left in the dir they share (the report counted
  them), and `config` reports an absolute functional.mcp.command that is
  no program here - /usr/bin/npx inside the Flatpak, whose /usr is the
  Sdk's.
- A patch that is not UTF-8 stops `run` at preflight (exit 3), as the
  plan has it; it exited 1.
- An exception no command caught aborted the process (134), e.g. a home
  that holds no lenses: it ends with its message and exit 1. An error
  escaping `run` or `freeze` now also clears the signal handler's run and
  sweeps what is left below the subreaper.
- `config -h` printed "unrecognized arguments" (exit 3): it prints the
  usage, exit 0.
- An API seat's .claude.json is linked into place, so a second writer
  never replaces the first's file and what claude wrote to it since.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-10-31 16:45:53 +01:00
commit 32a0de1a07
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
7 changed files with 114 additions and 11 deletions

View file

@ -220,6 +220,15 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"ok","total
&& badFile.err.contains("UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte"),
none.out + noFile.err + badFile.err);
// What escapes a command ends it with exit 1, never an abort; config's
// help.
const Process::Captured noHome = Self({"doc", "prepush"}, base, {{"CRAFTER_REVIEW_HOME", (base / "nowhere").string()}});
const Process::Captured configHelp = Self({"config", "-h"}, base);
Check("an error no command catches ends it with exit 1 and its message, never an abort; config -h prints its usage, exit 0",
noHome.returnCode == 1 && noHome.err.starts_with("crafter-review: ") && noHome.err.contains("holds no process/lenses") && configHelp.returnCode == 0
&& configHelp.out.starts_with("usage: crafter-review config [-h]"),
noHome.err + configHelp.out + configHelp.err);
// browser: its usage (an install fetches from npm).
const Process::Captured noAction = Self({"browser"}, base);
const Process::Captured badAction = Self({"browser", "remove"}, base);