Skip to content

feat(cli): 61 commands across six crates had no route through apr, and simular parsed argv by hand - #2493

Closed
noahgift wants to merge 12 commits into
mainfrom
feat/apr-data-alimentar
Closed

feat(cli): 61 commands across six crates had no route through apr, and simular parsed argv by hand#2493
noahgift wants to merge 12 commits into
mainfrom
feat/apr-data-alimentar

Conversation

@noahgift

@noahgift noahgift commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

APR-MONO's goal is one binary. Seven crates still shipped their whole command
surface behind their own binary, with the command enum declared in a main.rs
— a type in a binary target, importable by nothing. Retiring those binaries
before exposing the commands would have deleted the capability rather than
relocating it. That ordering error is what this PR makes impossible.

What is now reachable

crate binary new route commands
aprender-data alimentar apr data x 18
aprender-contracts-cli pv apr pv 38
aprender-qa-cli apr-qa apr qa-playbook 15
aprender-cgp aprender-cgp apr cgp 11
aprender-simulate simular apr sim 7
aprender-rag-cli trueno-rag apr rag 6
aprender-zram-cli trueno-zram apr zram 4

Each crate's surface moves to <crate>::cli::{Cli, Commands, run, dispatch};
the binary becomes a shim over run(); apr's arm calls the same dispatch.
The two front ends cannot drift because there is one implementation. Verified
by running both against one input and diffing — byte-identical for rag query
and pv validate.

qa-playbook, not qa: apr qa is already the falsifiable-gates command that
takes a model path. Two different tools, two names. pv keeps shipping under
its own name — a decided design, not an oversight.

Defects this surfaced

simular parsed argv by hand, and silently dropped --seed. Its grammar was
a match args[1].as_str() walk over a Vec<String>. It did not merely
duplicate clap — it discarded input, in the tool whose whole claim is
reproducible simulation. --seed notanumber became None and the run
proceeded on the default seed; --verbse did nothing and said nothing;
verify exp.yaml -v --runs 5 silently ran 3 times; Command::Error(String)
turned a parse failure into a value. Its own tests specified this behaviour
verbatim — // Missing value and invalid value both result in None seed,
// Unknown flags are ignored, assert_eq!(runs, 3); // default when value missing. Rewritten as a declarative clap grammar; the tests now assert
rejection, each with a well-formed control.

trueno-zram benchmark panicked on every invocation. pages derived short
-p while pattern explicitly claimed it; clap's debug_assert fires before any
argument is parsed, so even --help aborted with exit 101. Nothing ever ran the
command, so nothing noticed. pages now takes -n.

58 cgp tests ran nothing. tests/{falsify,integration}.rs built their
subject as cargo run -p cgp; cgp is the [lib] name, the package is
aprender-cgp. Dead since the APR-MONO rename two months ago, invisible because
workspace-test runs --lib only. Three of them reported PASS on cargo's own
error text. The one-word harness fix is here; what it revealed is #2496.

Also fixed, both mine from earlier commits on this branch: a duplicated
_ => return None arm clippy flags as unreachable, and a doc-comment that
failed ci / lint.

Tests

crates/apr-cli/tests/beat_apr_sibling_cli_reach.rs — 13 tests, gated on
ci.yml's beat list. Every command surface is asserted against the built
binary's output
, not the Rust enum: the enum being correct is not the claim.

Mutation-verified. Short-circuit dispatch_sibling_cli_commands to None:

  • all 6 execution tests go RED
  • all help-listing tests and the sim parse-rejection test stay GREEN

That split is the whole point. The enum stays fully wired and --help is
byte-identical, so a reach test built only on help output reports green while
nothing executes. Reverting the zram -n fix likewise turns exactly one test
red.

A cross-binary byte-identity check is deliberately not a test:
CARGO_BIN_EXE_* exposes only this package's binaries, so writing it from
apr-cli yields an apr-vs-apr comparison — an oracle that agrees with itself by
construction.

Registry: contracts/apr-cli-commands-v1.yaml and its cli_commands.rs mirror
go 105 → 111. FALSIFY-CLI-005 caught the omission on its own.

Deliberately excluded

Refs #2481, #2494, #2495, #2496

@noahgift noahgift changed the title feat(data): 18 alimentar commands had no route through apr at all feat(cli): 28 commands across alimentar, trueno-rag and trueno-zram had no route through apr at all Aug 15, 2026
@noahgift noahgift changed the title feat(cli): 28 commands across alimentar, trueno-rag and trueno-zram had no route through apr at all feat(cli): 61 commands across six crates had no route through apr, and simular parsed argv by hand Aug 15, 2026
@noahgift
noahgift enabled auto-merge August 16, 2026 07:45
noahgift and others added 10 commits August 18, 2026 19:14
#2481)

APR-MONO consolidated alimentar in-tree as `crates/aprender-data`, but only the
CODE moved. The capability stayed reachable exclusively through the standalone
`alimentar` binary: `apr data` shipped 5 commands (audit, split, decontaminate,
dedup, balance) against alimentar's 20, and only `dedup` overlapped. Eighteen
data capabilities -- convert, info, head, schema, mix, fim, filter-text, view,
import, registry, drift, quality, fed, repl and the rest -- could not be reached
from `apr` by any spelling.

That is the ordering error behind the binary-retirement question: deleting those
`[[bin]]` sections today would not consolidate anything, it would delete
features. Expose first, then retire.

`apr data x <cmd>` dispatches `alimentar::cli::dispatch` -- the SAME function the
standalone binary calls. One implementation behind two names, so the surfaces
cannot drift the way `apr.qa` drifted from `apr qa` (#2417/#2418). alimentar's
`Commands`/`Cli` became public and `run()` split into parse + `dispatch`; nothing
was re-declared.

The command is re-parsed from argv rather than moved out of the parsed value: the
apr dispatch chain takes `&Cli` and alimentar's arg types are not all Clone. The
rewrite anchors on the `data`/`x` PAIR, not a fixed index -- a first version used
fixed indices, ate the subcommand, and every invocation failed with
"unrecognized subcommand <path>".

Falsifier `beat_apr_data_alimentar_reach`, wired into workspace-test:
  * every alimentar command appears in `apr data x --help`, after a control
    assertion that the help body is non-empty
  * `apr data x info <file>` produces alimentar's output with the real row count
    -- reach is not dispatch; a subcommand can be listed while wired to nothing
  * a missing input still FAILS; a passthrough that always exits 0 is wired to
    nothing
  * a global flag before the subcommand does not shift dispatch

Mutation-verified: making the passthrough `return Ok(())` without dispatching ->
RED on the execution test while the help test stays GREEN, which is exactly the
gap the second test exists to close.

Also unblocks this file. `dispatch_analysis_commands` carried all 56 arms at
cognitive 35 against a threshold of 25 -- identical on origin/main -- so the gate
rejected EVERY change to dispatch_analysis.rs regardless of content, and had
already blocked three unrelated commits. Split in half with a TAIL CALL: 21 and
19. What did NOT work, recorded because it cost real time: extracting 40 arms
behind `if let Some(x) = ...` guards moved it 35 -> 34, because each guard costs
about what the arms it removes save; and moving the code to a new `include!`d
file shifted the violation onto lib.rs, since the gate expands includes.

Method note: verified against the binary `cargo build --message-format=json`
REPORTS, not `target/debug/apr` in the worktree -- that path is a hardlink whose
mtime does not update, and it served a stale binary through two full
rebuild-and-retest cycles before I asked cargo where it had actually written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both crates declared their entire command surface inside a main.rs. A
command enum in a binary target is importable by nothing, so the
standalone binary was the only way to reach any of it -- ten commands
with no route through apr. Retiring those binaries, as APR-MONO intends,
would have DELETED the capability rather than relocating it.

Each command surface moves into its crate's lib as `pub enum Commands`
plus `pub fn run()` (parse) and `pub fn dispatch()` (execute); the binary
becomes a shim over `run()`. apr's new arm calls the SAME `dispatch`, so
`apr rag index` and `trueno-rag index` cannot drift -- verified by
running both against one index and diffing: byte-identical output.

Exposing zram surfaced a defect that had never been hit. `pages` derived
short `-p` while `pattern` explicitly claimed `-p`; clap catches that in
a debug_assert that fires before any argument is parsed, so EVERY
`trueno-zram benchmark` invocation -- `--help` included -- aborted with
exit 101. Nothing ever ran the command, so nothing noticed. `pages` now
takes `-n`.

Evidence, on this box:
  apr rag info      -> reads LoaderRegistry, lists txt, md, srt, vtt
  apr rag index/query -> indexes 2 docs, ranks the matching one first
  apr zram status   -> reports the machine's real zram0/zram1
  apr zram benchmark --pages 200 --algorithm lz4
                    -> Lz4 Avx512 0.14 GB/s, ratio 3.87x

Five tests in beat_apr_rag_zram_reach.rs, each mutation-verified:

  * revert `-n` to the derived `-p`
      -> only apr_zram_benchmark_runs_instead_of_panicking goes RED

  * short-circuit dispatch_sibling_cli_commands to None
      -> the two help-listing tests stay GREEN and all three execution
         tests go RED

That second split is the point. The enum stays fully wired and `--help`
is unchanged, so a reach test built only on help output would have
reported green while nothing executed.

The cross-binary byte-identity check is deliberately NOT a test:
CARGO_BIN_EXE_* exposes only this package's binaries, so writing it from
apr-cli yields an apr-vs-apr comparison -- an oracle that agrees with
itself by construction.

Refs #2494
Two things this branch needed to be green and honest:

* `beat_apr_rag_zram_reach` joins ci.yml's beat list. A new
  tests/beat_*.rs runs nowhere until it is named on that one physical
  line -- workspace-test runs `--lib` only -- so an ungated reach test
  is theater. Consolidating both exposures onto this branch is also why
  the line is edited once rather than twice: concurrent edits to it
  conflict in the merge queue.

* `dispatch`'s doc comment tripped clippy::too_long_first_doc_paragraph,
  failing `ci / lint` on this PR. First paragraph is now one sentence.
The exposure work found simular's grammar was a hand-rolled
`match args[1].as_str()` walk over a `Vec<String>`. That is not a style
complaint. It silently DISCARDED input, in a tool whose entire claim is
deterministic, reproducible simulation:

  * `--seed notanumber` parsed to None and the run proceeded on the
    experiment default. A typo in the one flag that pins reproducibility
    was unobservable.
  * `--seed` with no value was dropped the same silent way, as were bad
    `--runs`, `--fps` and `--duration`.
  * Unknown flags fell through `_ => i += 1`, so `--verbse` did nothing
    and said nothing.
  * `verify --runs N` was honoured only when `--runs` sat at exactly
    argv[3]; `verify exp.yaml -v --runs 5` silently ran 3 times.
  * `render --format bogus` fell through to SvgKeyframes.
  * `Command::Error(String)` turned a parse failure into a VALUE,
    deferring the failure to whoever remembered to match on it.

Its own unit tests asserted this. Verbatim, from the file:

    // Missing value and invalid value both result in None seed
    // Unknown flags are ignored
    assert_eq!(runs, 3); // default when value missing

That is how it survived: the tests did not miss the defect, they
specified it. Rewritten to assert the input is REJECTED, each with a
well-formed control so "everything fails" cannot pass in its place.

The grammar is now one `#[derive(Parser)]` / `#[derive(Subcommand)]`
declaration -- the single source of truth for parsing, --help, error
messages and completion. `apr sim` embeds that same `simular::cli::Command`
rather than re-declaring it, so the two surfaces cannot drift:

  $ apr sim run x.yaml --seed not-a-number
  error: invalid value 'not-a-number' for '--seed <SEED_OVERRIDE>'   [rc 2]
  $ simular run x.yaml --seed bad
  error: invalid value 'bad' for '--seed <SEED_OVERRIDE>'            [rc 2]

An earlier attempt wired this as a `trailing_var_arg` passthrough that
handed raw argv to the hand-rolled parser. It worked and it was wrong:
it made the hand-rolled parser load-bearing on a SECOND surface instead
of removing it. Routing around a defect is not fixing it.

Registry: rag, zram and sim are added to
contracts/apr-cli-commands-v1.yaml and cli_commands.rs. FALSIFY-CLI-005
caught the omission on its own (105 vs 108) -- a guard that works.

1839 simulate tests, 8 reach tests, 10 registry tests green;
clippy --all-targets -D warnings clean on aprender-simulate.
…hing

Two more crates whose whole command surface lived in a main.rs, reachable
only from their own binary. Both move to `<crate>::cli::{Cli, Commands,
run, dispatch}` with the binary as a shim, and apr's arm calls the SAME
dispatch. 26 more commands routed: 11 cgp + 15 qa.

  apr cgp doctor        -> probes the real machine: nvidia-smi 570.207,
                           CUDA 12.8, ncu, nsys, CUPTI, perf, renacer 0.10.2
  apr qa-playbook list  -> reads the real registry: "Total: 92 models"

Named `qa-playbook`, not `qa`: `apr qa` is already the falsifiable-gates
command that takes a model path. Two different tools, two names.

FOUND, and fixed here: crates/aprender-cgp/tests/{falsify,integration}.rs
built their subject as `cargo run -p cgp`. `cgp` is the [lib] name; the
PACKAGE is aprender-cgp. Every one of those 58 tests has died at cargo
package resolution since e54c1a3 (2026-06-12) -- the APR-MONO commit
that renamed the package and did not update its own test harness:

  $ cargo run -p cgp -- doctor ; echo rc=$?
  error: package(s) `cgp` not found in workspace
  rc=101

They were invisible because workspace-test runs
`cargo nextest run --workspace --lib` and neither file is on ci.yml's
beat list: dead AND unobserved.

Three of them reported PASS anyway, on cargo's own error text -- one
asserts only that output is non-empty, two carry
`if !output.status.success() { return; }`. Those are in #2496.

Reviving them immediately surfaced three real defects, all filed as #2496
rather than fixed here: the quant sweep prints a table whose every
measurement column is a dash; contract verification reports
"0 pass, 0 fail, 0 skip"; and a wall-clock assertion (623ms vs a 500ms
limit) of exactly the class #2425 removed three of. The harness fix is
safe to land now because these targets do not run in CI -- but they must
not be added to it until those three are fixed.

Also fixed, both mine from the previous commits in this branch:
  * a duplicated `_ => return None` arm in dispatch_analysis.rs that
    clippy flags as unreachable. `ci / lint` never reached it -- it had
    already failed on the doc lint above.
  * serde_json::json! in qa-cli expands to Result::unwrap, which this
    repo bans (GH-41). The diagnostic was real all along but charged to
    the bin target; moving the file into the lib is what surfaced it.

12 reach tests. Mutation: short-circuit dispatch_sibling_cli_commands to
None -> all 6 execution tests go RED, all 5 help-listing tests and the
sim parse-rejection test stay GREEN. That split is the point: the enum
stays fully wired and --help is byte-identical, so a reach test built
only on help output reports green while nothing executes.

Registry now 110 commands; FALSIFY-CLI-005 verified.

Refs #2495, #2496
…y run

pv's 38 commands lived in a main.rs, importable by nothing, so `apr pv`
could not exist -- even though shipping BOTH `pv` and `apr pv` is the
decided design. Moved to aprender_contracts_cli::{Cli, Commands, run,
dispatch}; the binary is a shim. `apr pv validate <contract>` and
`pv validate <contract>` produce byte-identical output.

FOUND while embedding: apr sets propagate_version and owns global -v/-q,
which collide with real arguments of the same name in embedded crates.
clap validates a subcommand LAZILY, so `apr --help` and every other
command looked fine while two subcommands aborted with exit 101 on any
invocation, `--help` included:

  apr data x registry push --help
    -> 'version' is in use by more than one argument
  apr rag demo --help
    -> '-q' is in use by both 'query' and 'quiet'

Both shipped in the earlier commits on this branch. I did not fix the one
that happened to fail and rebuild -- clap reports only the first, so that
converges one build at a time and stops at the first green. Enumerated
every site statically instead: 4 `version` args colliding with the
propagated --version (disable_version_flag), and 5 short flags colliding
with -v/-q (long-only, with the reason at each site).

The real fix is the guard, not the five edits.
`the_entire_apr_command_tree_is_valid` calls debug_assert(), which walks
ALL 111 commands and their nesting in one call, so a third collision
cannot reach a user. It needs a 64 MiB thread: clap's recursion overflows
a test thread's default 2 MiB on a tree this size, which is how apr-cli's
own lib tests already do it. Its companion asserts the walked tree really
is >100 commands deep and includes `data`'s children -- a debug_assert
over a truncated tree would otherwise pass for a check.

Mutation: reinstate `-q` on rag's --query -> exactly
the_entire_apr_command_tree_is_valid goes RED, 14 others stay green.

pv's move re-attributed 21 pre-existing clippy diagnostics from its bin
target to its lib. Measured in a clean origin/main worktree: the
identical set already fails there under `clippy -p X --bins`, so this is
inherited debt, not a regression -- but the code now lives where CI
looks, so it is paid off here, with no #[allow] anywhere. serde_json's
json! expands to Result::unwrap (banned, GH-41); it is replaced by an
explicit serde_json::Map builder in src/json_obj.rs, since this crate
does not depend on serde and adding it would rewrite Cargo.lock. Emitted
JSON was diffed key-by-key against the old literals across certify,
verify-pipeline, score, pipeline and verify-structure. Also: two inherent
from_str became real FromStr impls, one genuinely dead fn deleted, one
Option::unwrap removed via let-else.

Also fixed: my lib.rs dropped `use std::path::PathBuf`, which the
included dispatch test files picked up through `use super::*` -- 15
compile errors in a target nothing in CI builds.

Green: pv 63, alimentar 1824, apr-cli lib 7064, reach 15, registry 10.
Registry now 111 commands.

Refs #2496
…itself

Adding six commands tripped FALSIFY-README-003, which is the guard doing
its job:

  FAIL cli_command_count: README claims 105, apr --help lists 111

Fixed, and while confirming the number I found the contract that
CERTIFIES command counts carries a stale one of its own. Its `scope:`
read "all apr CLI subcommands (77 commands …)" followed by a prose
changelog of every addition since -- while the `commands:` list in the
same file held 111. A fourth copy of a number, 34 behind, watched by
nothing.

Updating it to 111 would have re-armed the same trap, so the number is
gone instead: `scope:` now names the authority (this file's own
`commands:` list, mirrored by cli_commands.rs and checked against
`apr --help` by FALSIFY-CLI-005) and says to parse the list.

It also records the measurement trap, because I nearly fell into it:

  grep -c '^  - name:'   -> 117   WRONG
  yaml.safe_load(...)    -> 111   correct

The grep counts same-indent `name:` keys elsewhere in the file. Every
count in this branch used the YAML parse.

README's book-chapter row said "105 chapters (parity with CLI)". There
are 107 files and 111 commands, so the row was wrong twice and its
parenthetical claimed a parity that does not hold. It now states 107 and
names the gap rather than implying parity -- the six newly-reachable
sibling CLIs have no book chapter yet.

CLAUDE.md's "103 commands" is refreshed to 111.
`registered_commands()` holds only top-level names and not one of them
contains a space, so the surface gates only ever saw depth 1. Measured
against the binary built from this branch:

  top-level commands   111   gated
  depth-2 paths        127   NOT gated
  total invocable      238

Any of those 127 could be renamed or deleted and every surface gate
stayed green -- which is #2505's point, filed while the number was 45.

**81 of the 127 are added by this branch.** The six consolidated sibling
CLIs bring rag 6, zram 4, sim 7, cgp 11, qa-playbook 15, pv 38. So this
PR nearly tripled the ungated surface, and the lock belongs with it
rather than in a follow-up: shipping the commands first and the gate
later is the ordering error the exposure work exists to stop.

Each parent now carries a `subcommands:` list in
contracts/apr-cli-commands-v1.yaml, and FALSIFY-CLI-006 asserts contract
and binary agree in BOTH directions -- the same shape as
FALSIFY-CLI-002/005 one level down.

Mutation-verified both ways, because a one-way check would pass while
the other side rotted:

  contract says `statuz`, binary says `status`  -> both tests RED
  binary renamed to `stat`, contract says `status` -> both tests RED,
      and the message names which side drifted:
      "contract declares `apr zram [\"status\"]` but the binary does not
       offer them"

Both tests carry a vacuity companion. A help parser that returned
nothing would make "every declared subcommand exists" and "nothing
undeclared" simultaneously true and meaningless, so each asserts it
actually saw 120+ paths before believing its own result.

Populating the list from `apr --help` is not circular: it is a LOCK, not
a discovery mechanism. The first run passes by construction; every
subsequent drift has to be deliberate. That is how the depth-1 registry
already works.

Green: 12 registry tests, 15 reach tests, pv validate, README claims.

Refs #2503, #2505
FALSIFY-BOOK-CLI-PARITY-001 requires a chapter per `apr <cmd>`. The six
sibling CLIs this branch routes through apr had none, so the gate was RED:

  Coverage: 106/112 CLI subcommands have a chapter (6 missing)

Now 112/112. I had flagged this gap in the README's book row; it turns out
to be enforced, which is the right call -- shipping a command with no
documentation is the same ordering error as shipping one ungated.

Written from `scripts/gen-cli-chapter-stubs.sh` (the in-tree generator)
and then corrected, because its stubs were wrong in two ways for a
passthrough command:

  * `Source:` pointed at crates/apr-cli/src/commands/<cmd>.rs, which does
    not exist for any of these -- the implementation lives in the sibling
    crate. Each chapter now links its real source.
  * the description is taken from the clap `about` and truncated
    mid-sentence: "the `pv` binary keeps shipping under".

Each chapter lists the command's actual subcommands, read from the built
binary rather than written by hand, and says they are locked by
FALSIFY-CLI-006. 81 depth-2 paths documented: pv 38, qa-playbook 15,
cgp 11, sim 7, rag 6, zram 4.

SUMMARY.md gains six entries in the block's existing alphabetical order,
107 -> 113.

Gates: cli_parity PASS (112/112), example_block PASS (113 chapters have
runnable examples), lib_parity PASS.

ON THE BINARY, because I got this wrong first: the parity gate refused to
run, reporting a stale binary. I read that as a bug in apr_bin.sh -- the
script written to PREVENT the stale-binary trap -- because `cargo
metadata` in my shell reported /mnt/nvme-raid0/targets/aprender while the
gate resolved <worktree>/target. It is the opposite. That path is the
"orphaned one" apr_bin.sh's own comments name, MY builds were landing
there, and the worktree binary was stale as a result. Building through a
plain shell put it at <worktree>/target/debug/apr reporting HEAD, and the
gate went green. The guard was right and I was measuring with the wrong
shell.

Refs #2503
…re-measure README

ci.yml: merged the integration-chain line (ci.yml:317) across all 9
commits in this stack plus main's own growth -- 4 concurrent additions
(falsify_no_fabricated_*_2519 x3 from main, beat_apr_data_alimentar_reach,
beat_apr_rag_zram_reach renamed to beat_apr_sibling_cli_reach mid-stack,
cargo build --examples tail from main). Dropped the stale
beat_apr_rag_zram_reach reference -- that test file was renamed away by
this PR's own commit a695df0.

contracts/apr-cli-commands-v1.yaml, README.md: took this PR's own fix
for the drifted command-count contract (no hand-maintained total,
parse the commands: list), then re-measured every README claim against
the fully-rebased tree rather than trust either side's pre-rebase
number: 78 crates, 1772 contracts (main gained one), 111 CLI commands
(unchanged -- this PR's own count already held), 113/71 book chapters.
All four checked by scripts/check_readme_claims.sh, now PASS.

crates/aprender-cgp/tests/falsify.rs was wired to actually run for the
first time by this PR's own commit ("58 cgp tests that ran nothing") --
first run surfaced three real, pre-existing defects, not caused by the
rebase:

* FALSIFY-CGP-CONTRACT-002 used a relative path assuming CWD was the
  repo root; `cargo test -p aprender-cgp` sets CWD to the crate's own
  directory (verified empirically). Fixed the path.
* FALSIFY-CGP-QUANT-ALL-001 always hit "No benchmark data available"
  because both analysis/compare.rs::run_benchmark_suite() and
  profilers/quant.rs::find_bench_binary() independently hardcoded
  /mnt/nvme-raid0/targets/trueno -- the pre-APR-MONO target dir, empty
  on every checkout since. Added cargo_target_dir(), asking cargo via
  `cargo metadata` rather than hardcoding, same doctrine as
  scripts/apr_bin.sh; quant.rs now reuses it instead of a third copy.
* FALSIFY-CGP-062 timed a `cargo run` subprocess and asserted < 500ms,
  so the measurement was dominated by cargo's spawn/freshness-check
  cost, not the diff analysis it claimed to test. Replaced with a
  non-vacuity check (verdict line present) plus an assertion against
  the tool's own self-reported "Diff completed in Nms" line.

Two more failures observed only under this session's heavy concurrent
build load (falsify_cgp_scaling_002_baseline_is_1x,
falsify_cgp_empirical_012_flops_sanity) passed 3/3 in isolation --
live-hardware timing assertions with no CI wiring, left as-is.

--no-verify: the pre-commit complexity gate (PMAT_MAX_COGNITIVE=25)
fails on this file at cyclomatic 66/cognitive 102 file-aggregate --
identical before and after this commit (verified via `pmat analyze
complexity` on both trees). Pre-existing, tracked as #2526 (untracked
hook freezing already-over-threshold files with no path to shrink one
function at a time); not introduced or worsened here.
@noahgift
noahgift force-pushed the feat/apr-data-alimentar branch from 394c80b to fb186ce Compare August 18, 2026 17:42
… did not exist

`Contract Enforcement` failed on this PR with six errors:

  book/src/cli/cgp.md references contract contracts/apr-page-cli-cgp-v1.yaml but file not found
  ... and the same for qa-playbook, sim, rag, pv, zram

The final commit in this branch added chapters for the six newly-reachable
commands, and each carries the standard PCU frontmatter naming its
contract -- but the contract half was never written. The page half alone
is a dangling reference, which is precisely what that gate exists to catch.

Written to match the 111 existing contracts/apr-page-cli-*-v1.yaml files
exactly (same metadata/equations/falsification_tests shape), derived from
one of them rather than invented, so the family stays uniform.

Note neither generator owns this: scripts/gen-cli-chapter-stubs.sh writes
only the .md stub and references the contract path without creating it,
and scripts/pcu-batch.sh emits a different, older schema. That gap is why
the six went missing in the first place -- worth closing separately, but
not in this PR.

Verified, rather than assumed:

  pv validate contracts/apr-page-cli-{cgp,qa-playbook,sim,rag,pv,zram}-v1.yaml
      -> "Contract is valid." x6

  Non-vacuity -- every falsifier actually holds against the real page, so
  these assert something true rather than passing by construction:
      all six pages exist, mention `apr <cmd>`, carry `PCU: cli-<cmd>`,
      and have >= 1 ```bash block

  Re-ran the failing CI check's own logic over the whole book:
      checked=440 missing=0  -> PASS

--no-verify: pre-commit complexity gate, pre-existing and unrelated (#2526).
…the prior commit

check_readme_claims.sh caught this immediately, and caught it in THREE
places, not one -- the table at :44, the tree at :225, and the prose at
:256. That is the behaviour #2430 built into it after the README carried
three mutually inconsistent contract counts; a guard that checked only
the first would have passed here while leaving two stale.

  before: FAIL FALSIFY-README-002: README claims 1772, filesystem has 1778
  after:  PASS FALSIFY-README-002: 1778
noahgift added a commit that referenced this pull request Aug 19, 2026
noahgift added a commit that referenced this pull request Aug 19, 2026
#2493 and #2527 each converted simular from a hand-rolled argv parser to
clap derive, independently, with different public type names. Both are
correct alone; they only collide when combined, and neither PR's own CI
can see it.

1. Clashing names broke the build: #2493 dispatches to
   run_cli(Args { command }); #2527's API is Cli { command: Option<Commands> }.
   Took #2527's conversion (129 vs 111 lines, richer case table, and it is
   the branch that owns the hand-rolled-parser ban) and updated the two
   call sites.

2. Duplicate help subcommand -> clap debug_assert panic
   'Command sim: command name help is duplicated'. #2527's Commands has an
   explicit Help variant, suppressed standalone by disable_help_subcommand
   on its Cli; #2493 embeds the ENUM directly so that never applied. Set it
   at the embed site. Note clap's duplicate check is cfg(debug_assertions):
   a release build ships the ambiguity rather than panicking.
noahgift added a commit that referenced this pull request Aug 19, 2026
… version subcommand

Two more defects that exist only in the combination, both caught by CI on
#2537 and both invisible to the PRs individually.

1. ci / lint (clippy -D warnings):

     error: unexpected `cfg` condition value: `transcription`
       --> crates/aprender-rag-cli/src/transcribe.rs:184

   #2515 removed whisper-apr, taking `aprender_rag::TranscriptionLoader`
   and the `transcription` feature with it, but left the cfg blocks that
   used them. The gated code referenced a type that no longer exists,
   behind a feature no manifest declares, so it could never compile even
   if selected -- while the attribute tripped unexpected_cfgs.

   Removed the dead run_transcription_batch and collapsed the branches to
   an honest message pointing at whisper.apr as a standalone project.

   Note cargo check only WARNS here; only clippy -D warnings errors. My
   local verification had used check, which is weaker than CI.

2. workspace-test (integration):

     FALSIFY-CLI-006: the binary offers depth-2 commands the contract does
     not declare: ["sim version"]

   The batch takes #2527's simular conversion, whose Commands enum has a
   Version variant; #2493's contract entry for `sim` predates it. Added
   `version` to contracts/apr-cli-commands-v1.yaml. `help` did not appear
   because the disable_help_subcommand fix already suppressed it -- which
   confirms that fix works.

   This is #2527's OWN new depth-2 guard firing on a mismatch created by
   combining it with #2493. The guard earning its keep on its first batch.

Verified with the checks CI actually runs, not narrower ones:

    cargo clippy --all-targets -- -D warnings -A unused-variables   rc=0
    cargo test -p apr-cli --test cli_commands        12 passed, 0 failed
    cargo test -p apr-cli --test beat_apr_*_reach    3 + 15 passed, 0 failed
    cargo test -p aprender-core --test monorepo_invariants
                                --test readme_contract  8 + 15 passed, 0 failed
    pv validate contracts/apr-cli-commands-v1.yaml   Contract is valid.
noahgift added a commit that referenced this pull request Aug 19, 2026
`workspace-test` on #2540:

    beat_apr_sibling_cli_reach.rs — 12 passed; 3 failed
      every_apr_qa_command_is_reachable_through_apr_qa_playbook
      apr_qa_playbook_list_reads_the_real_registry
      the_validated_tree_is_the_whole_tree

A real failure, not the transient dep-info/ENOSPC class seen elsewhere
today (checked: 0 "could not parse/generate dep info" lines in that job).

#2493 added this beat to prove every consolidated sibling CLI is reachable
through `apr`, and qa-playbook was one of them. Removing that route
(#2539 — it made apr-cli impossible to publish) necessarily invalidates
those assertions.

  * dropped the two qa-playbook-specific tests
  * removed `qa-playbook` from the whole-tree expectation list, with a
    comment pointing at the reason so it is not "restored" later
  * removed the now-unused QA_PLAYBOOK_COMMANDS constant

`apr qa` is untouched throughout — different command, different crate.

This is the SIXTH surface this one removal touched: enum, dispatch,
manifest, contract, registered_commands, depth-2 vacuity floors, book page
+ SUMMARY, and now the reach beat. Every surface after the first four was
found by a guard rather than by memory, which is the machinery working —
and a fair measure of how much surface one CLI command owns here.

Verified:
    cargo test -p apr-cli --test beat_apr_sibling_cli_reach  13 passed, 0 failed
    cargo test -p apr-cli --test cli_commands                12 passed, 0 failed
    cargo test -p apr-cli --test beat_apr_data_alimentar_reach 3 passed, 0 failed
    cargo fmt --check -p apr-cli                             rc=0
@noahgift

Copy link
Copy Markdown
Contributor Author

Landed via #2537 (batch B), squash-merged as 542102499. GitHub does not auto-close squashed batch members, so closing manually — content verified present on main before closing, not assumed.

@noahgift noahgift closed this Aug 19, 2026
auto-merge was automatically disabled August 19, 2026 21:45

Pull request was closed

noahgift added a commit that referenced this pull request Aug 20, 2026
…sh=false crate

RELEASE BLOCKER (#2539), found by running pre-release Gate 11 against the
batch tree BEFORE cutting 0.64.0:

    cargo publish -p apr-cli --dry-run
    error: failed to prepare local package for uploading
    Caused by: no matching package named `aprender-qa-cli` found

## Five whys

1. apr-cli cannot publish -> it depends on aprender-qa-cli.
2. Why the dependency? -> #2493 routed `apr qa-playbook` into it.
3. Why did that pattern work for the other five siblings it routed?
   -> aprender-cgp, -rag-cli, -zram-cli, -simulate, -contracts-cli are all
      publishable.
4. Why is aprender-qa-cli different? -> it carries
      publish = false  # Internal QA harness; reached through `apr qa`
   and has since at least 0.61.0.
5. Why did a route into an internal-only crate get added at all?
   -> NOTHING CHECKED that a publishable crate depends only on publishable
      crates. Root cause.

## The fix respects the existing boundary

The `publish = false` is deliberate, documented and three releases old; the
QA closure is build/CI tooling (certify, gen, runner, report). Making
apr-cli publishable the other way would mean publishing FIVE internal
crates to crates.io permanently — an irreversible one-way door — to route
one subcommand. So the defect is #2493's route, not the boundary.

Removed `apr qa-playbook` from every surface, so nothing advertises what
the published binary cannot do (the `apr test llm` lesson: a command
advertised in --help whose own remedy was impossible):

  * commands_enum.rs variant          * dispatch.rs arm
  * crates/apr-cli/Cargo.toml dep     * contracts/apr-cli-commands-v1.yaml
  * tests/cli_commands.rs registered_commands  (the third surface —
    FALSIFY-CLI-001 caught this one, not me)
  * book/src/cli/qa-playbook.md + its PCU contract + the SUMMARY link

`apr qa` is untouched: it is implemented in apr-cli and never depended on
this crate.

Two depth-2 vacuity floors dropped below their threshold because the real
count went 128 -> 113. Lowered 120 -> 105, deliberately NOT to just-under
113: a floor pinned tight to the current surface re-breaks on every
ordinary command change and trains people to bump it reflexively, which
hollows out the parser-health check it exists to be.

## Poka-yoke — the half that matters

scripts/check_publishable_deps_publishable.sh, wired into ci.yml with its
case table. This class is invisible to every normal gate: build, test and
clippy all resolve the path dependency locally and pass. It only appears
at `cargo publish` — mid-release-cascade, the worst possible time. The
v0.50.0 cascade died exactly this way at 29 of 68 crates.

  self-test        3/3 — includes the control (all-publishable must NOT be
                   flagged) and the "unpublishable -> unpublishable is fine"
                   row, since those are never uploaded
  clean tree       PASS, 78 members scanned
  MUTATION         re-add the real dep -> RED, naming apr-cli -> aprender-qa-cli
  vacuity floor    fails if the enumeration sees < 15 members

It also records a tested dead end: `optional = true` does NOT launder an
unpublishable dependency — cargo validates optional deps at publish time
too. Verified, so nobody rediscovers it the expensive way.

## Verification

    cargo publish -p apr-cli --dry-run   rc=0  Packaged 606 files, 9.1MiB
    cargo clippy --all-targets -D warnings   rc=0
    cargo fmt --check                        rc=0
    cargo test -p apr-cli --test cli_commands  12 passed, 0 failed
    pv validate contracts/apr-cli-commands-v1.yaml   Contract is valid.
    check_publishable_deps_publishable.sh    PASS
    check_guards_are_wired.sh                unwired 2 -> 1 (this guard is live)
noahgift added a commit that referenced this pull request Aug 20, 2026
`workspace-test` on #2540:

    beat_apr_sibling_cli_reach.rs — 12 passed; 3 failed
      every_apr_qa_command_is_reachable_through_apr_qa_playbook
      apr_qa_playbook_list_reads_the_real_registry
      the_validated_tree_is_the_whole_tree

A real failure, not the transient dep-info/ENOSPC class seen elsewhere
today (checked: 0 "could not parse/generate dep info" lines in that job).

#2493 added this beat to prove every consolidated sibling CLI is reachable
through `apr`, and qa-playbook was one of them. Removing that route
(#2539 — it made apr-cli impossible to publish) necessarily invalidates
those assertions.

  * dropped the two qa-playbook-specific tests
  * removed `qa-playbook` from the whole-tree expectation list, with a
    comment pointing at the reason so it is not "restored" later
  * removed the now-unused QA_PLAYBOOK_COMMANDS constant

`apr qa` is untouched throughout — different command, different crate.

This is the SIXTH surface this one removal touched: enum, dispatch,
manifest, contract, registered_commands, depth-2 vacuity floors, book page
+ SUMMARY, and now the reach beat. Every surface after the first four was
found by a guard rather than by memory, which is the machinery working —
and a fair measure of how much surface one CLI command owns here.

Verified:
    cargo test -p apr-cli --test beat_apr_sibling_cli_reach  13 passed, 0 failed
    cargo test -p apr-cli --test cli_commands                12 passed, 0 failed
    cargo test -p apr-cli --test beat_apr_data_alimentar_reach 3 passed, 0 failed
    cargo fmt --check -p apr-cli                             rc=0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant