Skip to content

fix(features): 67 of the 100 red (crate, feature) pairs — 9 crates whose declarations never compiled - #3263

Open
noahgift wants to merge 12 commits into
mainfrom
PMAT-1098-feature-decls
Open

noahgift wants to merge 12 commits into
mainfrom
PMAT-1098-feature-decls

Conversation

@noahgift

Copy link
Copy Markdown
Contributor

What

A full sweep of all 430 (crate, feature) pairs in the workspace found 100 red — every one of them unreachable from any crate's default set, which is exactly why they were dark. Measurement and the full table: #3262.

This PR fixes 9 crates / 67 of those pairs. Every one is the same class: a feature is declared, code is gated on it, and the declaration does not supply what that code needs. cargo check --workspace never noticed because feature unification hands each crate whatever its siblings enabled.

crate what was wrong
aprender-orchestrate apr_serve gated native but calls super::realizar and libc::prctl, both from inference. Re-gated; its call site gets the cfg twin build_fallback_driver already had. Separately, the rag TUI gated on the implicit presentar-terminal dep-feature, which links presentar but not the crossterm it also uses — re-pointed at the tui composite.
apr-cli --no-default-features — documented in CLAUDE.md as how you build without inference — had never compiled: 8 errors in 7 files, all "definition gated, caller not". Also wgpu = ["inference"] enabled neither entrenar nor entrenar/gpu, so --features wgpu and --all-features failed too.
aprender-train tui = ["dep:presentar-terminal"] was declared in Cargo.toml and never applied in codegrep -rn 'feature = "tui"' --include='*.rs' returned nothing. 17 pairs on that one cause. Fixing it exposed a second: pre_warm_realizador_gemm re-exported under realizar while defined under all(realizar, cuda).
aprender-simulate CB-081 removed axum/jsonschema/z3 for Cargo.lock bloat and left the gated code. axum 0.7.9 and jsonschema 0.28.3 are already in the lock, so re-adding them costs zero new packages (verified: the lock diff is two edges, no new [[package]]). Plus three contract_pre_iterator! sites passing scalars to a slice precondition.
aprender-serve cuda supplied none of gpu, server, cli — all of which the CUDA path uses. Only the default set, which happens to carry all three, ever built that code.
aprender-data cli needs local (registry) and shuffle (cmd_mix); declared neither.
aprender-core showcase-profile needs renacer, a DEV-dependency here because renacer depends on aprender.
aprender-compute / aprender-viz gpu-wasm was broken on every target including wasm32, the one it exists for: shared_instance/gpu_backends were all(gpu, not(wasm32)) while their caller carries no cfg. Also added the Histogram::dimensions setter — the fields existed, were defaulted, and were read by to_framebuffer; only the setter was missing, while every sibling widget has one.
aprender-mcp / aprender-profile-core / aprender-rag-cli pmcp-dispatcher needs native; otlp = [] was an empty feature whose code needs opentelemetry (its sibling aprender-profile declares it correctly — -core copied the name, not the dependency); EvalAction lacked the Clone/Debug its parent enum derives.

Two features that cannot be built

aprender-simulate/z3-proofs and aprender-core/showcase-profile are declared but structurally unbuildable — z3 is not in the lock and needs libz3; renacer is circular. Each now emits one compile_error! naming the dependency and the exact edit that would enable it, with a private __z3-linked / __renacer-linked feature carrying the real gate so the refusal is the only diagnostic and aprender-core's existing stub still compiles.

Complexity debt paid down

Touching apr-cli/src/lib.rs and two other files put five PRE-EXISTING violations in front of the pre-commit complexity gate, none of them in code this PR wrote. Paid down in the same commits, as the gate requires — all behaviour-preserving, each following a split the files already document:

  • dispatch_runtime_commands 41 → under (the apr run arm extracted whole)
  • dispatch_diagnostic_commands 30 → under (apr trace arm + save-tensor pre-dispatch extracted; the diff arm's doubled and_then nesting factored out)
  • help_producer_truth::resolve 73 → under (token loop → a Walk state struct, one method per token kind)
  • explain_tensor 28 → under (the --json half extracted)
  • oracle::rag::tui::run_loop 32 → under (sync_size + handle_key)

Both extracted dispatch arms re-match behind a let ... else that refuses by name; neither panics.

Verified

Per-selection cargo check on every pair this PR touches, plus each crate's default and the suites:

  • apr-cli --lib 7242/7242 (including the three resolver behavioural tests covering the rewritten resolve); bare, --all-features, and 11 selections clean
  • aprender-train --lib 7624/7624; 24 selections clean
  • aprender-orchestrate --lib 6535/6535
  • aprender-compute --lib 3511/3511; aprender-simulate --lib 3677/3677; aprender-viz + aprender-rag-cli --lib 605/605
  • Cargo.lock gains zero new packages

Not in this PR

no-close: #3262 is the umbrella measurement and stays open until the four items above are green; #3257 and #3179 are owned elsewhere.

🤖 Generated with Claude Code

noahgift and others added 6 commits September 14, 2026 12:28
…bc from inference

cargo check -p aprender-orchestrate --no-default-features --features agents was
RED with 6 errors: apr_serve.rs calls super::realizar::parse_tool_calls_pub and
libc::prctl/PR_SET_PDEATHSIG. Both come from `inference = ["realizar", "native",
"libc"]`, but the module was gated `#[cfg(feature = "native")]` and `agents =
["native"]`. So every selection that turned on agents WITHOUT inference —
agents, agents-browser, agents-rag, agents-mcp, agents-contracts — could not
compile. The feature table already declares the intended split:
`agents-inference = ["agents", "inference"]` is "Agent with local inference
(RealizarDriver)". The gate just did not match the declaration.

Re-gate driver::apr_serve on `inference` and give its call site in code.rs the
same shape build_fallback_driver already has: a cfg twin returning None when
inference is off, so the caller falls through to the embedded/mock driver
exactly as it does when the `apr` binary is missing. No runtime behaviour
change on any selection that already built.

Found by the 430-pair (crate, feature) sweep behind night.yml — the nightly
would have been born red on this.

Pmat-Ticket: PMAT-1098

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…k since nothing builds it

CLAUDE.md documents `--no-default-features` as how you build the CLI without
inference. It has not compiled: `cargo check -p apr-cli --no-default-features`
was RED with 8 errors across 7 files, and so were 7 single-feature selections
(axum, code, dev, dhat-heap, futures-util, hf-hub, renacer) that inherit the
same lib. Found by the 430-pair (crate, feature) sweep behind the night lane;
the nightly would have been born red on this.

Every error is the same shape — a DEFINITION carries #[cfg(feature =
"inference")] and its CALLER does not. Nothing ever builds this crate without
inference, so no gate ever saw it:

  * lib.rs serve_auth re-exported `apply` (gated, axum middleware) and
    `AuthGate` (ungated struct) on one ungated line. Split.
  * chat.rs `detect_format_from_bytes` was gated though it only reads four
    magic bytes and returns the ungated ModelFormat. Ungated, not spread.
  * profile_ollama.rs `ROOFLINE_AI_UNMEASURED` — a `&str` sentinel — was gated
    while the ungated print_roofline_section compares against it. Ungated.
  * test_llm.rs `dispatch` builds a tokio runtime: cfg twin on `tokio` that
    refuses by name instead of failing to link.
  * test_llm_band.rs `cool` sleeps between lanes; the sleep is gated and the
    no-tokio arm is unreachable (dispatch refuses first) rather than a
    silently skipped §5.1 cooldown.
  * diff_05_aprt_stage.rs reads APRT bodies through realizar save_tensor: fn
    and call site gated on `realizar`, with a named error on the other side.
  * explain.rs took realizar only for `find_sibling_file`. `apr explain`
    reports metadata and must build without inference, so it gets a cfg shim:
    realizar when linked, literal parent-dir sibling otherwise.

Touching lib.rs and explain.rs made the pre-commit complexity gate refuse the
commit on four PRE-EXISTING violations in those files' module trees, none of
them in code this change wrote. Paid down in the same commit, as the gate
requires — behaviour-preserving, and each extraction follows the split this
file already documents for `CodeArgs`/`dispatch_code_command`:

  dispatch_runtime_commands   41 -> under   `apr run` arm extracted whole
  dispatch_diagnostic_commands 30 -> under  `apr trace` arm + save-tensor
                                            pre-dispatch extracted; the diff
                                            arm's doubled and_then nesting
                                            factored into with_resolved_pair
  resolve (help_producer)     73 -> under   token loop -> a Walk state struct
                                            with one method per token kind
  explain_tensor              28 -> under   the --json half extracted

Both extracted arms re-match the command behind a `let ... else` that refuses
by name; neither panics, and both are unreachable from their single call site.

11 selections now check clean (bare + the 7 broken + realizar/tokio/trueno/
inference); apr-cli --lib is 7242/7242, including the three resolver
behavioural tests that cover the rewritten `resolve`; fmt and clippy clean on
both default and bare. `--all-features` is still RED, on a separate
pre-existing wgpu defect in finetune.rs, tracked on its own.

Pmat-Ticket: PMAT-1098

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…plied in code

`tui = ["dep:presentar-terminal"]` (PMAT-507, "gated due to presentar API
drift") makes the dep optional, but no `#[cfg(feature = "tui")]` existed
anywhere in the crate — `grep -rn 'feature = "tui"' --include='*.rs'` returned
nothing. So `monitor/tui/dashboard.rs` and `TuiMonitor::run` used
`presentar_terminal` unconditionally, and every selection that did not happen
to enable the default `tui` failed to link it: 17 of the 430 (crate, feature)
pairs in the night sweep, all on this one cause.

Gate what actually needs the backend and nothing more. The module's metric-store
half — `TrainingStateWriter` and the state types — stays unconditional, which is
what the feature table's own comment says it is ("TUI IPC writer always
available"). Without `tui`, `TuiMonitor::run` returns an error naming the build
it needs rather than failing to compile.

Fixing that exposed a second defect the first was masking: `autograd/ops/mod.rs`
re-exported `pre_warm_realizador_gemm` under `#[cfg(feature = "realizar")]`
while the definition is `#[cfg(all(feature = "realizar", feature = "cuda"))]`
(C-PREWARM-001 — the pre-warm only exists on the CUDA path). Re-export now
carries the same pair.

24 selections check clean (axum, citl, cpu-fallback, cuda, dhat-heap,
getrandom, gguf, gpu, hub, hub-publish, js-sys, kani, monitor, nvml,
nvml-wrapper, parquet, realizar, renacer, ruchy-sessions, server, tracing, tui,
viz, wasm) plus default; aprender-train --lib is 7624/7624.

Pmat-Ticket: PMAT-1098

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…and two that never can

Continuing the (crate, feature) sweep behind the night lane. Same class as the
apr-cli and aprender-train fixes: a feature is declared, code is gated on it,
and the declaration does not supply what that code needs.

BUILDABLE NOW — the declaration was simply wrong:

  * apr-cli `wgpu = ["inference"]` — commands/finetune.rs uses
    `entrenar::finetune::wgpu_pipeline::WgpuInstructPipeline` and
    `entrenar::autograd::wgpu_training`, both gated on aprender-train's `gpu`.
    The feature enabled neither entrenar nor that gate, so `--features wgpu`
    AND `--all-features` did not compile. Now `["inference", "training",
    "entrenar/gpu"]`; `aprender --features wgpu` and `apr-cli --all-features`
    both check clean.
  * aprender-data `cli = ["dep:clap", "dep:crossterm"]` — cli/registry.rs
    imports `backend::LocalBackend` (gated `local`) and cli/mod.rs dispatches
    `cmd_mix` (gated `shuffle`). Added both. All 13 selections clean.
  * aprender-simulate `web` and `schema-validation` — CB-081 removed axum and
    jsonschema to cut Cargo.lock bloat and left the code gated behind features
    that pulled nothing. Both crates are ALREADY in Cargo.lock (axum 0.7.9 via
    7 other members; jsonschema 0.28.3 via aprender-train and aprender-mcp), so
    re-adding at those versions costs zero new lock entries — measured: the
    Cargo.lock diff is two dependency edges and no new [[package]]. That is the
    thing CB-081 was protecting. (The 0.29 jsonschema the old note suggested
    WOULD have added one; the note was not re-measured.)
  * aprender-simulate `wasm` — three sites in orbit/wasm.rs passed scalars
    (`f64`, `u32`) to `contract_pre_iterator!`, which asserts `input.len() > 0`
    on a SLICE. They never compiled, so they never checked anything. `0` steps
    and `0.0` days are both legitimate here, so they take the no-arg marker
    form the other 15 sites use rather than inventing a scalar precondition the
    contract does not state.

CANNOT BE BUILT — the dependency is deliberately absent, so the feature now
refuses by name instead of emitting a cascade of unresolved-import errors:

  * aprender-simulate `z3-proofs` — CB-081 removed `z3`. Unlike axum and
    jsonschema it is NOT in Cargo.lock and needs the libz3 system library, so
    re-adding it is a real cost and a real decision.
  * aprender-core `showcase-profile` — `renacer` is a DEV-dependency here
    because renacer depends on aprender; lib code can never link it. A stub
    profiler already existed for the off path.

Both get one `compile_error!` naming the dependency and the exact edit that
would enable it, plus a private `__z3-linked` / `__renacer-linked` feature that
actually gates the code — so the refusal is the ONLY diagnostic, and the
aprender-core stub still compiles.

aprender-simulate --lib 3677/3677; aprender-data and aprender-core default
builds clean.

Pmat-Ticket: PMAT-1098

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Continuing the (crate, feature) sweep. Same class throughout: the feature is
declared, code is gated on it, the declaration does not supply what that code
needs. None of these are reachable from the default set, which is why they went
dark.

  * aprender-serve `cuda` — the CUDA generate path reports
    `crate::api::PhaseTimings` (api is `server`-gated), the cached-weights path
    it shares uses `DequantizedWeightCache` and `crate::gpu` (both `gpu`-gated),
    and the q4k scheduler calls `cli::inference::{argmax,
    sample_with_temperature}`. `cuda = ["dep:trueno-gpu", "dep:tracing"]`
    supplied none of them, so `--features cuda` and `--features gpu,cuda` both
    failed — only the default set, which happens to carry server+cli+gpu, ever
    built this code. Declared as what it needs. Those two sampling helpers are
    PURE; moving them out of the cli-gated module would let `cuda` drop that
    edge and stop pulling clap and presentar-terminal — noted for follow-up,
    not done here.
  * aprender-mcp `pmcp-dispatcher = ["dep:pmcp"]` — server.rs's dispatcher uses
    `anyhow` and `tools::args::json_type_name`, both behind `native`. Added.
  * aprender-profile-core `otlp = []` — an EMPTY feature whose code converts to
    `opentelemetry::trace::{TraceId, SpanId}`. The sibling aprender-profile
    declares the same feature as `["dep:opentelemetry", …]`; -core copied the
    name without the dependency. Added at 0.31.0, the version already in
    Cargo.lock via that sibling, so no new locked package (verified: the
    Cargo.lock diff adds zero `[[package]]` entries).
  * aprender-compute `gpu-wasm` — `GpuDevice::new_async` is the wasm-capable
    constructor and carries no cfg, like the module (`any(gpu, gpu-wasm)`), but
    its helpers `shared_instance`/`gpu_backends` were `all(gpu, not(wasm32))`.
    So `gpu-wasm` was broken on every target INCLUDING wasm32, the one it
    exists for. Helpers widened to the module's own gate; their bodies are
    target-agnostic and `Backends::PRIMARY` already includes BROWSER_WEBGPU.
    The `gpu` path is untouched. This also unblocked aprender-viz `gpu-wasm`.
  * aprender-viz — `Histogram` had `width`/`height` fields, defaulted 800x600,
    read by `to_framebuffer`, and NO setter, while every sibling widget
    (sparkline, resource bar, ggplot) has `dimensions()`. aprender-serve's
    latency histogram called it. Added the missing builder rather than deleting
    the caller's intent.
  * aprender-rag-cli `eval` — `EvalAction` is a field of `Commands::Eval` and
    `Commands` derives `Subcommand, Clone, Debug`; `EvalAction` derived only
    `Subcommand`. Matched.

aprender-compute --lib 3511/3511, aprender-viz + aprender-rag-cli --lib
605/605; aprender-serve clean on cuda, full, gpu, server, cli, kv-cache,
visualization, registry, tui, trace and default.

Pmat-Ticket: PMAT-1098

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…site that supplies it

`oracle/rag/tui.rs` carried 20 `#[cfg(feature = "presentar-terminal")]` gates.
That is the IMPLICIT feature cargo creates for the optional dependency: it links
presentar-terminal and nothing else. The module also uses `crossterm`, which
only the composite `tui = ["presentar-terminal", "crossterm", "native"]`
supplies — so `--features presentar-terminal` compiled the module without a
crate it needs.

Re-pointed at `tui`, the feature that actually provides what the module uses.
The only behavioural change is that a selection which never compiled now
excludes the module instead; `--features tui` is unaffected. The other 16
`presentar-terminal` gates in this crate are left alone — they guard code that
needs only presentar.

Touching the file put its PRE-EXISTING `run_loop` (cognitive 32) in front of the
pre-commit complexity gate, so it is paid down here as the gate requires: the
resize block becomes `sync_size` and the key match becomes `handle_key`, which
returns `false` to quit. Behaviour-preserving — the `> 0` guard before a
decrement is exactly `saturating_sub(1)`, and a non-Press event still falls
through.

aprender-orchestrate --lib 6535/6535; presentar-terminal and tui both check
clean.

Pmat-Ticket: PMAT-1098

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown

§13.11 rung 1 — quorum shadow verdict

S13-SHADOW pr=3263 head=0f85f43b62e14492a1c57510c3fca06e1fa28a3a verdict=REFUSE class=Q1 arm_rc=1

Shadow mode: this records a verdict and merges nothing. A refusal
to arm is not a block (§13 adds zero rows to §7) — the pull request is
exactly as green as it was.

@noahgift noahgift added this to the 0.68.0 milestone Sep 14, 2026
@noahgift
noahgift disabled auto-merge September 14, 2026 17:42
@noahgift
noahgift enabled auto-merge September 14, 2026 18:38
@noahgift
noahgift disabled auto-merge September 14, 2026 22:41
@noahgift noahgift modified the milestones: 0.68.0, 0.70.0 Sep 16, 2026
@noahgift
noahgift enabled auto-merge September 16, 2026 12:04
@noahgift noahgift modified the milestones: 0.70.0, 0.71.0 Sep 17, 2026
@noahgift

Copy link
Copy Markdown
Contributor Author

Triage from the release babysit session (aprender-ba). I updated this armed branch with main (head 0f85f43) so its 09-15 checks stop being stale; the re-run shows two CODE reds and one ENV red:

  1. guard-tree, §6 R-2 body guard (CODE, body): no-close: #3262 is a hyphen-prefixed closing keyword — GitHub reads it as a real close #3262. Replace with keep-open: #3262 <reason> and push (the guard reads the frozen event payload; a body edit alone never re-runs it).
  2. guard-tree, dogfood coverage G2.1 freshness (CODE, tree): this branch changes crates/aprender-rag-cli/src/lib.rs, which is cited by docs/audits/surface_audit.csv, without re-running the audit for those rows. Re-run the audit for the rag-cli rows and commit the csv.
  3. cuda-unit (ENV): driver::cublas_tests::cta64_vs_cta32_vs_cublas_fp16 hit CUDA_ERROR_OUT_OF_MEMORY on yoga-eph (job 105944360104, 18:23Z, the 8 GB 4060 Laptop). The same job passed on yoga-eph for release: 0.68.2 #3498 (18:20Z) and PMAT-3477: CB-200 back under its baseline — 5 definitions lifted to grade B by extraction, no behaviour change (0.68.2 T-2 preflight) #3533 (17:07Z), so this is a transient VRAM squeeze, not this diff. Rerun once the run finishes (gh run rerun --job refused while sibling jobs were still queued).

Auto-merge stays armed; it merges on its own once 1–2 are pushed.

@noahgift

Copy link
Copy Markdown
Contributor Author

Correction to item 3 above: cuda-unit is not env. The rerun (attempt 2, job 105953179488, yoga-eph, 19:22Z) fails identically — driver::cublas_tests::cta64_vs_cta32_vs_cublas_fp16 at crates/aprender-gpu/src/driver/cublas_tests.rs:1046, CUDA_ERROR_OUT_OF_MEMORY after the 2048-row case — with the GPU otherwise idle (2 MiB of 8188 MiB in use, no other compute process). The same job passed on the same runner for #3498 (18:20Z) and #3533 (17:07Z), so it is the diff: this branch's feature-pair changes make that test allocate past the 4060 Laptop's 8 GB. Either the test needs a VRAM floor (skip-with-reason below N GB, like the other gpu tests) or the enabled feature set changed what it allocates. Owner's call; two occurrences with an idle card is no longer an anecdote.

@noahgift
noahgift disabled auto-merge September 20, 2026 23:48
@noahgift

Copy link
Copy Markdown
Contributor Author

Disarmed by the aprender cop (2026-09-20 23:50Z) under tonight's review-gate ruling: every PR needs a committed AD-04 quorum receipt (docs/audits/quorum-<PMAT-issue>.json, 3/3 PASS, cross-inspected by a non-author) before it is armed. This PR was armed before the ruling and carries no receipt. Its checks were also red on stale runs (see the guard-tree rows above), so nothing changes for the merge itself; when an owner picks it up: rebase onto main, mint the fragment on the branch if pmat work status PMAT-<issue> does not resolve, run ~/.claude/skills/quorum-review/quorum-review.sh (three distinct lane models), commit the receipt, and ask for the arm.

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.

The (crate, feature) matrix has never been built: 100 of 430 selections do not compile, all of them unreachable from any default set

1 participant