feat(aura-runner, aura-cli): reproduce returns its report; mismatch guard replaces silent DIVERGED

reproduce_family returns Result<ReproduceReport, RunnerError> — divergence
is a result the embedding caller reads (all_identical()), never an error;
the CLI renders the per-member lines and summary byte-identically and owns
the exit (1 on divergence, no stderr line). The library's print block and
the empty-message refusal are gone; exit_on_runner_error always prints
(no empty producer remains).

reproduce_family_in gains the identity/pip guard, firing before any store
fetch: an instrument mismatch (incl. synthetic-for-real) and a broker/pip
mismatch — forward-built label compare against the stored broker string
(RunManifest carries no pip field; the mint's label constructors became
shared pub(crate) helpers, so guard and stamp cannot drift). The class is
context-borne: the explicit-source seam refuses 2 (caller-named source),
the derived simple path refuses 1 (data drift), same prose. A window
guard is deliberately absent — no reproduce path takes a caller window.
In-process tests pin the promise: divergence returns Ok, drift refuses
class 1, the host survives. Fork minutes: issues/299#issuecomment-4875,
-4877, -4879.

closes #299
This commit is contained in:
2026-07-26 19:23:44 +02:00
parent fd303de94d
commit 58d5345a75
4 changed files with 389 additions and 41 deletions
+6 -1
View File
@@ -857,7 +857,12 @@ error; only its environment refusals (a tap-trace store write failure)
exit 1. The no-data family (no local data, no data in the requested window,
no recorded geometry) belongs to the real-data verbs — `aura run`,
`reproduce`, the campaign legs — where it likewise exits 1 (#297; the full
partition lives in [C14](design/contracts/c14-headless-two-faces.md)).
partition lives in [C14](design/contracts/c14-headless-two-faces.md)). `aura
reproduce`'s identity/pip guard (a stored member's recorded instrument or
broker/pip label contradicting the source it re-derives against) is
likewise class 1 on the plain verb — its source is derived from the
family's own manifest, so a mismatch there is data drift, not a caller
error (Fork 6, #299).
The class boundary is FORM vs VALUE, not "environment/data/IO vs everything
else": an `--override` value that is well-formed but out of the node's own