Skip to content

feat(registry): S3c — the startup Selection reaches GET /v1/effective-config, and a forced accelerator that fell to cpu at RUNTIME is refused - #3349

Open
noahgift wants to merge 5 commits into
mainfrom
PMAT-3041-s3c-effective-config
Open

noahgift wants to merge 5 commits into
mainfrom
PMAT-3041-s3c-effective-config

Conversation

@noahgift

Copy link
Copy Markdown
Contributor

Third slice of the #3041 split (docs/audits/pr-3041-split-plan.md, #3334). Stacked on #3344 (S3b), which stacks on #3342 (S3a) — until those merge, this PR's diff shows theirs too.

S3a added the library, S3b switched the call sites. S3c closes the loop at both ends: what the process resolved at startup becomes observable, and a forced accelerator that falls back at runtime is refused instead of quietly producing cpu output.

Two adaptations, both to make a claim falsifiable

#3041 published the startup resolution and then asserted it only from the route's own test, which supplied the value itself — that cannot witness the serve gate publishing the wrong thing. So:

  • run()'s mapping became a named seam, serve::publish_backend_resolution, read back field-for-field through realizar::api::effective_config::backend_resolution(). Publishing a constant kind: "cpu" turns that row RED; making resolved_report() return None turns the route row RED.
  • The runtime-refusal wiring test lives inside one of the files it scans, so a literal needle would contain itself and pass with the call site deleted. Every needle is assembled by format! from pieces.

Five mutations, each observed RED and restored byte-identically

mutation row that went red
delete the after_generation call in run_entry surface row, naming apr run
restore chat's silent on_cuda_load_error(…, false) fallback same row, naming apr chat
move the call below the --stream branch the positional row ("before the first output branch")
publish a constant kind: "cpu" the publish read-back row
resolved_report() → None the effective-config route row

Scope discipline

Only the two 5b5116d6c hunks were taken for chat_generate_session_02.rs; #3041's blob for that file also reverts main's later ShardedSafeTensors arm, which the plan marks "stale side, take main". The contract's effective-config and after_generation clauses are restored with obligation ids unchanged, and the mutation text was rewritten to the mutations actually observed here rather than the ones #3041 claimed.

No CI wiring is owed — both proving targets are --lib, already in workspace-test. No surface_audit.csv row cites any file this slice touches (0 of 838), so the ledger is untouched and G2.1 is unchanged.

Gate at the head commit, every leg measured with an unpiped exit code: apr-cli --lib 7255 passed / 0 failed, aprender-serve --lib effective_config 29 passed, clippy -D warnings clean on both crates, fmt clean, dogfood coverage PASS, pv validate 0 errors (built from the worktree — the PATH pv is two minor versions stale).

Refs #3041

no-close: #3041 stays open until S4 lands; it is then closed with a pointer, per the plan. The PRE-generation refusal stays a non-goal here and is #3042.

ont-delta: resolves REG-OB-004 — the effective-config half (the served process reports its startup Selection as resolved, and a forced accelerator that fell to cpu at runtime is refused before any output), discharged by REG-F-003's new effective-config and after_generation legs; obligation ids unchanged.

🤖 Generated with Claude Code

noahgift and others added 4 commits September 16, 2026 07:05
…registry, and a forced accelerator never downgrades to cpu (#3041)

Slice S3a of docs/audits/pr-3041-split-plan.md, cut fresh from origin/main; #3041 is not merged or rebased.

apr_cli::registry (declared #[path] from commands_enum.rs, not lib.rs, whose
include! tree carries pre-existing over-threshold functions the complexity hook
would charge): a Request becomes a Resolved or a refusal over trueno::registry.
Not compiled => FeatureDisabled (9); compiled but not Ready on this host =>
BackendUnavailable (14, new); only the default may fall to cpu. Purely additive:
no call site changes behaviour in this slice.

Falsifier tests/backend_refusal_case_table.rs 5/5 PASS. Mutation: both not-ready
branches of resolve_in returning cpu_resolved instead of Err turns
a_forced_accelerator_with_none_ready_refuses_and_never_downgrades and
every_backend_value_is_resolvable_on_every_fixture_and_forced_gpu_is_never_cpu
RED (observed); restored clean.

Contract REG-OB-004 + REG-F-003 + the two resolution bindings; pv validate 0
errors with the in-tree pv 0.67.0. The static-guard half of the original hunk is
NOT claimed here: check_backend_registry.sh is S3b and is not in this tree.

Wiring: ci/explicit-test-commands.d/400-apr-cli-backend-refusal-case-table.cmd
(free ordinal) and the regenerated scripts/tree_reader_tests.txt row. Removing
either turns check_tree_reader_tests.sh RED in both directions (observed).

Pmat-Ticket: PMAT-3041

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…registry, and a static guard keeps cfg! backend reads at zero (#3041)

Slice S3b of docs/audits/pr-3041-split-plan.md, stacked on S3a; #3041 is not merged
or rebased. S3a was additive — this is where behaviour moves.

Call sites. `apr run` (dispatch.rs run_preflight), `apr chat` (dispatch_analysis.rs),
`apr serve` (serve/mod.rs), bench compute_class/provenance, finetune wgpu_available,
lib.rs emit_version_json, serve list_devices/cli_build_features and
handler_gpu_completion now ask crate::registry instead of cfg!(feature=cuda|wgpu):
the decision becomes a fact about the HOST, not about what was compiled. The census
under crates/apr-cli/src goes 19 code reads -> 0 (the one survivor is prose in
registry.rs). dispatch.rs also carries 99589f9/#3040 decompositions of
dispatch_runtime_commands, dispatch_diagnostic_commands and help_producer_truth::resolve
(behaviour-preserving; the same tests are the oracle).

Guard. scripts/check_backend_registry.sh, 10/10 rows, both polarities. Ported off
ripgrep to grep -rnE per plan decision D4b — no scripts/check_*.sh on main invokes rg
and guard-runner-labels provisions none, so the rg form would have been an env-death
inside guard_tree. NO-ARG IS THE GATE, not --static: guard_tree.sh runs every tracked
check_*.sh BARE, so a gate hiding behind a flag would print usage, exit 2, and be a RED
row for a guard that never ran. Wiring is therefore guard_tree itself (verified: it is
a `run:` row of --dry-run --no-cargo, and check_guards_are_wired PASSes) — no workflow
edit. Row 10 is the real mutation: cfg!(any(feature=cuda,wgpu)) back in a COPY of the
real crates/apr-cli/src turns --static RED naming accel.rs. bashrs 0 errors.

Contract. The static half of REG-OB-004 / REG-F-003 that S3a dropped under decision D2
is restored now that the guard exists, ids unchanged; the effective-config half stays
out — it is S3c code and nothing here discharges it. pv validate 0 errors.

Tests for the switched paths, which had none on either side of the split:
accel::ensure_available_for and request_from_asked (cpu/default never refused in any
spelling; --gpu beats --no-gpu and --backend cpu, honoured or refused but never quietly
cpu) and dispatch::run_preflight (the effective_no_gpu GH-326 decision). The
three-surface scan stopped accepting the needle `accel::ensure_available`, which is a
SUBSTRING of `ensure_available_for` and so passed identically before and after the
switch; with the needle named per surface, reverting apr chat to the old spelling turns
every_accelerator_surface_calls_the_refusal RED (observed, rc 101) and restoring it
GREEN.

#3041 parked the pre-R-0b refusal text in accel::legacy_refusal, unreferenced, under
#[allow(dead_code)] — the lint that would have reported it. Dropped: registry::not_compiled
owns that message and is reached.

Left for S3c: serve/mod.rs a0269f3 (effective-config set_backend_resolution),
chat_generate_session_02 5b5116d (cuda_fallback_or_refuse), run_entry.rs.

Pmat-Ticket: PMAT-3041

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s rows S3b moved

S3b carries S3a's 6-line module declaration at the top of commands_enum.rs (+6
for all 42 distinct cited lines, 64 tokens) and, in dispatch_analysis.rs,
replaces the 4-line `accel::ensure_available(...)` call in the `apr chat` arm
with the 1-line `ensure_available_for(...)` (-3 below line 1676). 13 cited
lines in that file: 12 sit above the edit and do not move; one, :1699, sits
below it and moves to :1696.

Every token is re-pointed through a line-level diff (merge-base 7ee0eca ->
branch, difflib.SequenceMatcher over lines) and accepted ONLY where the cited
line's TEXT is byte-identical on both sides. No row was re-audited by hand, none
was dropped, and the file was not re-serialised: normalising every
`commands_enum.rs:NNN` and `dispatch_analysis.rs:NNN` token to a constant makes
the before and after byte-identical. 838 lines before and after.

HONEST NOTE, for the audit and not for this commit to fix: the row
`apr chat ... (ACCELERATOR_GUARD crates/apr-cli/src/dispatch_analysis.rs:1699)`
cites a line whose text is `            runs,` -- a field of the bench arm, not
an accelerator guard -- and it already did so at the merge base. This commit
moves that citation mechanically to the same text at :1696; it does not invent a
new target. The guard `apr chat` actually calls now lives at ~:1668. Re-aiming
that row is a re-audit, not a re-point, and is left for one.

  G2.1 freshness  PASS  78 cited evidence files, 2 changed by this branch
  G2.2 PASS (no row lost, 837 comparand rows) G2.3/G2.5/G2.6/G2.4 PASS

Pmat-Ticket: PMAT-3041
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-config, and a forced accelerator that fell to cpu at RUNTIME is refused (#3041)

Slice S3c of docs/audits/pr-3041-split-plan.md, stacked on S3b; #3041 is neither
merged nor rebased. The plan's S3c row and the list S3b left agree exactly, and this
is that list: serve/mod.rs (a0269f3), chat_generate_session_02.rs (5b5116d),
run_entry.rs, effective_config.rs + effective_config_route_pp2.rs, and the contract's
effective-config half.

PUBLISH. realizar::api::effective_config gains a process-wide BackendResolution
(OnceLock, first write wins) and the response gains `resolved` {kind, device_index,
device_uid, device_name, reason, discovered_at_unix, basis, matches_loaded} beside the
residency-MEASURED compute_class; matches_loaded stays null until a model is resident,
so nothing is compared that cannot be. REQUIRED_TOP_LEVEL_KEYS 13 -> 14.
ensure_accelerator_available/_in return the Resolved instead of dropping it.

READ BACK, BOTH HALVES. #3041 published this value and asserted it only from the route
side, with the route's own test supplying the value — which cannot witness the serve
gate publishing the wrong thing. Adapted: the mapping run() performs is a named seam,
serve::publish_backend_resolution, and
the_startup_resolution_serve_publishes_is_the_one_effective_config_reports reads it
back field for field through realizar's public accessor, the one the route calls.
Mutations, observed rc 101: publish a constant `kind: "cpu"` -> that row RED; make
resolved_report() return None -> effective_config_reports_the_startup_backend_resolution
RED.

RUNTIME REFUSAL. registry::after_generation arrived with S3a (registry.rs was taken
whole); what S3c adds is the CALLERS — run_entry.rs before any output mode, and apr
chat's CUDA-init Err arm through cuda_fallback_or_refuse, which carries the real forced
flag instead of the hardcoded `false` that predated --backend. A unit test of the
decision cannot see a call site that stopped asking, and that is precisely the defect
the review lane measured (apr run --gpu announced `selected: wgpu`, the wgpu path
failed on a Q6_K tensor, the run finished on CPU and exited 0). So the surfaces are
scanned by name — with every needle assembled by format! from pieces, because this
test lives IN one of the files it scans and would otherwise contain its own needle and
pass with the call site deleted. Mutations, observed rc 101: delete the run_entry call
-> every_generating_surface_reconciles_what_ran_with_what_was_announced RED naming
`apr run`; restore chat's silent on_cuda_load_error(..., false) fallback -> the same
row RED naming `apr chat`; move the run call below the --stream branch ->
the_run_reconciliation_happens_before_the_first_output_branch RED.

NOT TAKEN from #3041: its chat_generate_session_02.rs blob also reverts main's
ShardedSafeTensors arm, so only the two 5b5116d hunks were applied (git apply -3),
per the plan's "stale side, take main".

CONTRACT. REG-OB-004 and REG-F-003 keep their ids. The effective-config `resolved`
clause and the after_generation clause return, the test command gains its
`cargo test -p aprender-serve --lib effective_config_route_pp2` leg, and the non-goal
that said the serve half was "NOT claimed here" is replaced by what IS still a
non-goal: the PRE-generation refusal (#3042). apr-cli reconciles AFTER generation, so
the cpu run is already spent when a forced accelerator is refused — stated rather than
hidden. pv validate, built from this worktree because the PATH pv is stale: 0 errors.

No CI wiring is owed: both proving targets are `--lib`, which workspace-test already
runs, so there is no new --test target, no ci/explicit-test-commands.d fragment and no
tree_reader_tests.txt row. No surface_audit.csv row cites any file this slice touches
(0 of 838 rows), so no citation moves and the ledger is untouched.

apr-cli --lib 7255 passed / 0 failed / 12 ignored; aprender-serve --lib effective_config
29/0; clippy -D warnings clean on both libs; fmt clean; dogfood coverage gate PASS
(G2.1 78 cited evidence files).

Pmat-Ticket: PMAT-3041
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@noahgift noahgift added this to the 0.68.0 milestone Sep 16, 2026
@noahgift
noahgift enabled auto-merge September 16, 2026 07:18
@github-actions

github-actions Bot commented Sep 16, 2026

Copy link
Copy Markdown

§13.11 rung 1 — quorum shadow verdict

S13-SHADOW pr=3349 head=dde5d35c47d5e6584d58c4b7c4976d0675358659 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.

… adds

The registry is derived, so it is regenerated with its own --update rather than hand-merged. S3c's new test modules ride existing --lib targets; the drift the guard reported was the registry being behind the sources, not a missing wiring row.

Pmat-Ticket: PMAT-3041
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@noahgift noahgift modified the milestones: 0.68.0, 0.70.0, 0.71.0 Sep 16, 2026
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