From bfb8648925b94c90ee502e5a20b31d38d4667106 Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 16 Jul 2026 15:34:57 +0200 Subject: [PATCH] =?UTF-8?q?tidy:=20fieldtest=20follow-ups=20=E2=80=94=20do?= =?UTF-8?q?main=20prose=20for=20the=20zero=20bound,=20gate-emptied=20exit?= =?UTF-8?q?=20semantics=20documented?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two fieldtest findings, resolved: - friction: --parallel-instruments 0 now refuses in domain terms ("must be a whole number of at least 1 — it bounds how many distinct instruments are resident in parallel") via a custom clap value-parser, instead of leaking Rust's NonZeroUsize wording; the zero-bound test pins the prose. - spec_gap: the authoring guide's exit-code contract now states that a gate-emptied cell (a std::gate leaving no survivors) is a successful cell — exit 0 with an informational aura: note and a truncated realization — and that exit 3 is reserved for cells that could not be evaluated. Records observed behaviour; no code change. Gates re-verified: workspace suite green, clippy -D warnings clean. refs #277 --- crates/aura-cli/src/research_docs.rs | 17 ++++++++++++++++- crates/aura-cli/tests/research_docs.rs | 3 +++ docs/authoring-guide.md | 7 ++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/crates/aura-cli/src/research_docs.rs b/crates/aura-cli/src/research_docs.rs index 7c68e64..3504575 100644 --- a/crates/aura-cli/src/research_docs.rs +++ b/crates/aura-cli/src/research_docs.rs @@ -60,6 +60,17 @@ impl DocIntrospectCmd { } } +/// Parse `--parallel-instruments` in domain terms: clap's built-in +/// `NonZeroUsize` parser would leak the Rust type name ("number would be +/// zero for non-zero type") at exactly the moment a user needs guidance. +fn parse_parallel_instruments(s: &str) -> Result { + s.parse::().ok().and_then(std::num::NonZeroUsize::new).ok_or_else(|| { + "must be a whole number of at least 1 — it bounds how many distinct \ + instruments are resident in parallel" + .to_string() + }) +} + /// Exactly one introspect mode (the graph-introspect guard idiom: usage /// error on stderr, exit 2). fn guard_one_mode(cmd: &DocIntrospectCmd, family: &str) { @@ -320,7 +331,11 @@ pub enum CampaignSub { target: String, /// Bound on distinct instruments resident in parallel (the RAM /// lever; 1 reproduces the sequential loop's footprint). - #[arg(long, default_value_t = aura_campaign::DEFAULT_PARALLEL_INSTRUMENTS)] + #[arg( + long, + default_value_t = aura_campaign::DEFAULT_PARALLEL_INSTRUMENTS, + value_parser = parse_parallel_instruments, + )] parallel_instruments: std::num::NonZeroUsize, }, /// List stored campaign realizations, or dump one campaign's records diff --git a/crates/aura-cli/tests/research_docs.rs b/crates/aura-cli/tests/research_docs.rs index 75978e0..afb143a 100644 --- a/crates/aura-cli/tests/research_docs.rs +++ b/crates/aura-cli/tests/research_docs.rs @@ -4083,4 +4083,7 @@ fn campaign_over_a_gapped_archive_records_the_uncovered_cell_and_continues() { fn campaign_run_rejects_a_zero_parallel_instruments_bound() { let (out, code) = run_code(&["campaign", "run", "unused", "--parallel-instruments", "0"]); assert_eq!(code, Some(2), "clap usage error expected, got: {out}"); + // Domain prose, not clap's raw NonZeroUsize wording ("number would be + // zero for non-zero type") — the fieldtest friction finding. + assert!(out.contains("at least 1"), "domain guidance expected, got: {out}"); } diff --git a/docs/authoring-guide.md b/docs/authoring-guide.md index 74c09fb..4216c9e 100644 --- a/docs/authoring-guide.md +++ b/docs/authoring-guide.md @@ -609,4 +609,9 @@ Exit codes: a clean run exits 0; a usage error exits 2; a refusal before any cell runs (invalid document, missing project, unresolvable strategy) exits 1; a run that **completes with one or more failed cells** exits 3 — the run record and every healthy cell persist, and the failed cells are named on stderr -(#272). +(#272). A **gate-emptied cell** — a `std::gate` stage that filters out every +member — is a *successful* cell, not a failed one: the gate legitimately +answered "no survivors", so the run still exits 0, the cell's realization is +recorded as truncated at that stage, and an informational `aura:`-prefixed +note names the cell on stderr. Exit 3 is reserved for cells that could not be +evaluated (faults), never for an empty-but-valid result.