feat(R-0b): backend resolution reads the registry — a forced accelerator never downgrades to cpu - #3041
Open
noahgift wants to merge 75 commits into
Open
feat(R-0b): backend resolution reads the registry — a forced accelerator never downgrades to cpu#3041noahgift wants to merge 75 commits into
noahgift wants to merge 75 commits into
Conversation
Pmat-Ticket: PMAT-989
…/3 split) — DAG: R-0 = R-0a, new R-0b (#3002, PMAT-1060), R-2/B-G1 gain R-0b and move under the §12 rule, I-18 anchor +14; spec §12 llamafile citation corrected (lane 3); §5.0 re-rendered Pmat-Ticket: PMAT-989
…t; cpu always Ready, every kind a line, NotCompiled/NoBackend named, REG-4/7/9/12 and the two-API device_uid dedup (PMAT-989, #2904) Pmat-Ticket: PMAT-989
…s Ready, every kind of {cpu,cuda,wgpu,metal,hip} an explicit entry (NotCompiled / NoBackend / DriverNotFound / NoDevice / ProbeFailed), CUDA through the dlopen'd driver API, wgpu adapters with transport, REG-7 reserve as ReserveExceedsFree, REG-8 selection printed, device_uid dedup across APIs, object-safe BackendFactory + MockBackendFactory, JSON + printed block, fixtures never mistaken for the machine (PMAT-989, #2904)
Pmat-Ticket: PMAT-989
… line, selection with its reason, overrides loud: APR_RESERVE_BYTES, APR_REGISTRY_FIXTURE); hermetic failure catalogue with must-RED twins (FX-7, FX-11, REG-4/9/12, schema) on fixture registries; contracts/schemas/apr-devices-v1.schema.json; a reserve refusal propagates to the device's other-API entries; both integration targets wired into ci.yml; cli_commands.rs --help parsers decomposed (pre-existing cognitive 47/36 blocked the file) (PMAT-989, #2904) Pmat-Ticket: PMAT-989
…ged; ii/iv/v are R-0b's and not claimed) + apr-devices-schema-v1 (one shape on every host, absence is a line); README contract count 1813 (PMAT-989, #2904) Pmat-Ticket: PMAT-989
…e rows Pmat-Ticket: PMAT-989
…e; the CUDA factory's DriverNotFound / ProbeFailed / NoDevice are all reachable (dlopen first, then count); the schema refuses documents serde refuses (strict nested objects, per-kind reason payloads, no kind on ready) with a twin row; override lines print what the registry holds; two non_goals recorded (a context per device during discovery; uid normalisation across APIs) (PMAT-989, #2904) Pmat-Ticket: PMAT-989
…cation (four claims true, two false, two limitations recorded) Pmat-Ticket: PMAT-989
… devices (intel's two W5700X both enumerate as 'AMD Unknown (RADV NAVI10)' and collapsed into one device_uid — found by the four-host dogfood); case-table row 10; receipt: dogfood blocks from lambda, gx10, intel, mini — every host Ready>=1 (PMAT-989, #2904) Pmat-Ticket: PMAT-989
…ws) — rendered blocks drift on the queue's 3-way merge Pmat-Ticket: PMAT-989
…age-cli-devices-v1 (FALSIFY-BOOK-CLI-PARITY-001 red on #3004: apr devices had no chapter) Pmat-Ticket: PMAT-989
Pmat-Ticket: PMAT-989
…; this branch is code + receipt only Pmat-Ticket: PMAT-989
Pmat-Ticket: PMAT-989
…s branch leaves roadmap.yaml untouched Pmat-Ticket: PMAT-989
… binary c642576eecb62daa) — apr parity --json over 78 positions: qwen2.5-coder-1.5b min cosine 0.9508 at position 0 (|Δlogit|max 11.97), qwen2.5-coder-7b min 0.9986; under the horizon rule (min over >= 64 positions >= 0.98 [U]) 1.5B RED / 7B GREEN before any kernel edit (#3017) Pmat-Ticket: PMAT-1065
…est.sh -> evidence/models/supported.yaml, 18 models, every entry cites file:line; --check refuses a hand-typed entry; 6-row case table); C14 scripts/check_model_parity.sh --manifest (apr parity over >= 64 positions per manifest model, min cosine vs evidence/parity/thresholds.yaml — 0.98 [U] until item 5 measures it; UNMEASURED reported, README-cited unmeasured RED; SKIP_PARITY_GATE is an override that prints and refuses; 6-row case table over the lambda records: 1.5B RED, 7B GREEN, must-RED twin, < 64 positions refused) (#3017, PMAT-1065) Pmat-Ticket: PMAT-1065
…tree already does (cited), the five-whys hypothesis for the N-lane quorum; threshold basis = PARITY_GATE_COSINE_MIN (mod.rs:803), itself [U] Pmat-Ticket: PMAT-1065
…S (record corrected); the fused Q8_1 FFN is off by default (gpu_profile.rs:238), so the five-whys step 3 is refuted on default config and the 1.5B/7B asymmetry on the unfused path is the open question; the surviving zero-risk fix is REG-15's selected: line; lanes were one family (gap) Pmat-Ticket: PMAT-1065
…s its duplicate under driver v5.1) — receipt, record, scripts and manifest cite it Pmat-Ticket: PMAT-1065
…izon gate, the derived manifest, REG-15 admission); ci.yml guard-runner-labels runs the manifest case table + --check and C14's case table; every 0.65.2 (1.5B, cuda) dogfood receipt relabelled INVALID-CORRECTNESS citing #2971 (PMAT-1065) Pmat-Ticket: PMAT-1065
… a forced backend never downgrades — CliError::ParityFailed with its own code read at test time; unforced prints selected: cpu (reason: parity FAILED …); PASS prints selected: cuda …), override_line() for SKIP_PARITY_GATE, parse_gate_error over the load-time gate's message; 7 hermetic tests (worker-written, orchestrator-verified) (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…oad failure: a parity-gate failure prints selected: cpu (reason: parity FAILED cosine=… threshold=…) when unforced (apr chat today) and refuses when forced (R-0b's --backend); apr compare prints the override line only when the user set SKIP_PARITY_GATE (diff-benchmark's silent set_var waits for its own decomposition — the file is over the complexity gate) (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…pare override), the worker ledger, the cuda type-check on lambda, and the gaps (diff-benchmark decomposition, effective-config block, apr devices --model, dogfood C14, threshold measurement, gx10) Pmat-Ticket: PMAT-1065
…lsifier (FAILs the run if it ever passes), then check_model_parity.sh --manifest over the built binary: PASS when measured, FAIL on a measured failure or an override, REPORT with the reason on a host that holds no manifest model (the pre-publish proof is make fleet-verify ROW=release on lambda and gx10) (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…e lambda 1.5B record must be RED and the 7B record GREEN under evidence/parity/thresholds.yaml (read by regex, no default), both over >= 64 positions; the full manifest runs only in dogfood, the release and R-8 (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…ambda) sits at min cosine 0.9986 in all five runs and the known-bad pair (1.5B@lambda) at 0.9508 in all five (both deterministic, stdev 0.0); 0.98 lies between; [U] until the gx10 pair (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…ositions,threshold,basis} — the load-time gate returns the cosine it measured, the CUDA model carries a ParityGateRecord (PASS | skipped under the SKIP_PARITY_GATE override | not-run) set by one admission helper, the report is never absent (not-run on cpu residency or a non-cuda build); shape test (#2971, PMAT-1065) Pmat-Ticket: PMAT-1065
…ution reads the registry once #3004 lands Pmat-Ticket: PMAT-1073
…ccelerator never downgrades to cpu (#3002, PMAT-1073); partial (2 cfg reads await a dispatch/lib decomposition) apr_cli::registry::resolve (declared from commands_enum.rs to dodge lib.rs's include! debt): a request → a Selection or a refusal over trueno::registry; not-compiled ⇒ FeatureDisabled(9), compiled-but-not-Ready ⇒ BackendUnavailable(14, new), only the default may fall to cpu. accel/serve/bench/handler/finetune route through it. RED test backend_refusal_case_table 5/5; mutations both flip (not-ready→cpu RED, cfg@accel.rs:28 RED). check_backend_registry.sh (self-test wired). Contract REG-OB-004/REG-F-003 valid. dispatch.rs:173 + lib.rs:230 cfg reads are the residual (hook charges include! debt; decomposition filed). Pmat-Ticket: PMAT-1073
|
§13.11 rung 1 — quorum shadow verdict Shadow mode: this records a verdict and merges nothing. A refusal |
…e type is already must_use (clippy double_must_use under deny(clippy::all)) Pmat-Ticket: PMAT-1065
…backend_registry.sh --static armed in ci/gate (#3002, PMAT-1073; closes #3040) dispatch.rs:173 (apr run --backend <kind>, now cuda AND wgpu) and lib.rs:230 (version-json build report) route through crate::registry. The pre-commit complexity hook charges a staged file for its whole include! expansion, so three pre-existing over-threshold functions are decomposed in the same commit: dispatch_runtime_commands (cog 43 → run_preflight + run_batch_if_requested), dispatch_diagnostic_commands (30 → trace_save_tensor_dispatch + DiffOpts/diff_dispatch), help_producer_truth::resolve (73 → a Walk cursor); oracles 3/3 + 278/278 + check default/cuda. Four serve-guard tests encoded the cfg premise (a build without cuda/wgpu features is CPU-only) — false: apr-cli's wgpu feature is an inference alias and this host has Ready AMD adapters; they now run over fixture registries via ensure_accelerator_available_in, with a new no-accelerator-compiled fixture. Static guard now 0; accept.sh 5/5; clippy --lib clean. Pmat-Ticket: PMAT-1073
…he CUDA load; refusal exit codes proven end to end (#3002, PMAT-1073) registry::announce() resolves and prints the selected line once per process; accel::ensure_available_for(gpu, no_gpu, backend) announces the request as run/chat honour it (GH-326 gpu wins); serve's gate does the same with its own precedence. The first cut announced the registry default under --no-gpu — the line said wgpu while the run used cpu — caught only by the binary (cargo captures test stderr). The CUDA load sites print parity: <status> cosine= positions= threshold= basis= from the gate record. Measured with the debug apr over fixture registries: run/chat/serve --gpu on cpu-only ⇒ 14, on no-accelerator-compiled ⇒ 9, --backend wgpu on cpu-only ⇒ 14 (the old cuda-only check let it through), --no-gpu ⇒ selected: cpu; one selected line per process. cuda check, clippy --lib, apr-cli lib 7228/0. Pmat-Ticket: PMAT-1073
…lution — resolved {kind, device, reason, discovered_at_unix, matches_loaded} beside the measured compute_class (REG-12, #3002, PMAT-1073)
A process-wide BackendResolution (first write wins) that the serve gate sets from its Resolved; the response gains a resolved key, matches_loaded null until a model is resident. Route test + REQUIRED_TOP_LEVEL_KEYS 14; contract REG-OB-004/REG-F-003 extended; accept.sh A6. aprender-serve effective_config 29/0, apr-cli 278/0, cuda check, clippy --lib on both crates clean.
Pmat-Ticket: PMAT-1073
…d before any output; a default fallback corrects its selected: line — the review lane's axis-6 finding, measured (#3002, PMAT-1073; follow-up #3042) Measured before the fold: apr run --gpu announced selected: wgpu, the wgpu path failed on a Q6_K tensor (Unsupported quantization type 6), the run finished on CPU and exited 0 with no notice unless --verbose. realizar already returns used_gpu, so registry::after_generation(forced, announced, used_gpu) runs in run_entry before any output mode: forced ⇒ BackendUnavailable (14), no output; default ⇒ a corrective selected: cpu (fallback …) line. apr chat's CUDA-init failure carries the real forced flag and refuses when forced (cuda_fallback_or_refuse). Quorum record in .pr/R-0b/quorum.md + docs/audits/quorum/; the receipt's stated cause for compiled(wgpu) corrected per the delegate. Measured after: run --gpu ⇒ 14 (also --format json, --stream: no body/no token events); default ⇒ 0 with the fallback line; --no-gpu unchanged. Pmat-Ticket: PMAT-1073
…eet-verify and the merge Pmat-Ticket: PMAT-1073
…s into guard-tree BSE-001 M2 split the old guard-runner-labels job into guard-tree (cargo-free, dispatched by scripts/guard_tree.sh) and guard-cargo. The four L0-1a steps (derive_model_manifest.sh --self-test/--check, check_model_parity.sh --self-test) are cargo-free by `grep -cE '(^|[^a-z_-])cargo '` == 0 on both scripts, so they re-anchor into guard-tree after check_row_pr_write_set.sh, the same neighbour they had before the split. Also drops unfused_test.json — a 0-byte file left at the repo root by the round-2 mutation run (193d626) and committed by accident. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…hold [U] lifted, the divergence is model-selected not device-selected Card items (iv) and (vi). `make fleet-verify` does not exist (BSE's G-11b), so the measurement was taken rather than waited on. gx10-a5b5, aarch64, NVIDIA GB10 (sm_121), driver 590.48.01, apr 0.65.2 (c04eda8) sha256 21d182d69505159c. Mechanism engaged, not intended: every run's stderr carries `[GH-480] Patched N backward branch(es) for sm_121 JIT workaround`, a path lambda's sm_89 build does not have. model positions<0.98 min cosine max|dlogit|@0 verdict qwen2.5-coder-1.5b-instruct-q4_k_m 1 0.950611 12.0087 RED qwen2.5-coder-7b-instruct-q4_k_m 0 0.998465 0.8032 GREEN n=5 per cell, stdev 0.0 in all four cells across both hosts. THE FINDING. Two GPU generations, two ISAs, two host architectures, one running a JIT workaround the other does not have — and the known-bad pair lands within 2.2e-4 of the same cosine (lambda 0.950827, gx10 0.950611) while the known-good pair on the same silicon is 0.9985+. The divergence is selected by the MODEL (hidden 1536/heads 12/kv 2 /GQA 6 vs 3584/28/4/7), not by the device. Every "an sm_89 kernel is wrong" or "the sm_121 JIT patch corrupts a branch" hypothesis is refuted before L0-1b dispatches a lane. It is asserted, not merely written down: the_two_hosts_agree_on_each_model_to_ within_a_thousandth goes RED if that stops holding. The driver's 0.9418 / 5.38 were guessed to be gx10's numbers by all three earlier lanes. They are not: gx10 measures 0.950611 / 12.0087. The source report's provenance stays [U]; the defect it names is confirmed on both required hosts. Item (iv) CLOSED, the [U] on evidence/parity/thresholds.yaml lifted: 0.98 now separates two measured known-good pairs from two measured known-bad pairs with 0.0185 of margin under the lower good floor, asserted at >= 0.01 on each side, because a gate that passes with no headroom is a finding (0.63.0 hansei) and a near-tie once inverted a whole diagnosis (#2359). Falsifiers added: check_model_parity.sh --self-test 7 -> 9 rows (both polarities on BOTH hosts); sentinel_tests 4 -> 8 (1.5B RED / 7B GREEN per host, cross-host agreement, threshold margin on both sides). Refs #2971, PMAT-1065 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…d steps into guard-tree BSE-001 M2 split guard-runner-labels into guard-tree (cargo-free, dispatched by scripts/guard_tree.sh) and guard-cargo. check_backend_registry.sh and the two L0-1a scripts carry zero `cargo ` tokens, so all five steps re-anchor into guard-tree; the two new integration targets (registry_failure_catalogue, registry_case_table) go back on the single gated test line beside cli_commands. Also drops unfused_test.json, the 0-byte file the round-2 mutation run left at the repo root and the stack carried forward. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…ies is one file
check_hardcoded_paths.sh refused +25 shipped machine-specific paths — 24 of them
`"model": "/home/noah/models/…"` inside the apr parity --json output, one a hardcoded
cargo in accept.sh. That guard has no allowlist by design, and its own header sets the
precedent for evidence: redacting a host path "would delete the evidence and fabricate a
cleaner history".
Neither redaction nor an exemption was needed, because the path was never part of the
measurement.
* Every canonical record RE-TAKEN with the model named relatively (`cd ~/models &&
apr parity ./<model>.gguf …`), same pinned binaries (lambda c642576eecb62daa, gx10
21d182d69505159c), same prompt. The metrics array and every other key are
BYTE-IDENTICAL to the absolute-path run; only `model` differs — compared field by
field, not asserted.
* n5/ drops its ten JSONs per host. All five runs of each model were byte-identical to
each other AND to the canonical record — stdev 0 understates it, the whole file was
the same file — so five copies carried nothing their sha256 does not. DETERMINISM.md
records the hashes and the distinct-count; runs.log keeps the ten exit codes.
* accept.sh: CARGO="${CARGO:-$HOME/.cargo/bin/cargo}" — still never a bare `cargo`
(a shell function of that name overrides CARGO_TARGET_DIR), no longer a machine path.
Also `make readme-sync`: the CONTRACT_COUNT block stated 1815 and the merge tree carries
1816 (main's contracts/patterns/ratchet-verdict-d2-v1.yaml plus this row's
apr-gpu-cpu-parity-v1.yaml). That block is GENERATED, so it is an equality, not a ratchet.
check_hardcoded_paths.sh --full: delta +0. sentinel_tests 8/8. accept.sh 12/12.
Refs #2971, PMAT-1065
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…achine path check_hardcoded_paths.sh refused +25 shipped paths; the resolution was neither a redaction nor an exemption — the records were re-taken with the model named relatively (byte-identical metrics, same pinned binaries) and the n=5 series collapsed to its sha256, because all five runs were byte-identical to the canonical record. delta +0. Refs #2971, PMAT-1065 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…s a tree-reading test target workspace-test refused with `scripts/tree_reader_tests.txt drifted from the sources (> apr-cli --test registry_failure_catalogue)`, exit 2. That file is DERIVED by scripts/check_tree_reader_tests.sh from the test sources (include_str!, fs::read*, project_root, CARGO_MANIFEST_DIR) and drives BSE-17's quick tier: a target that reads the tree must be in it or the PR tier is weaker than the full tier. This row adds exactly such a target, so the registry is regenerated rather than the drift silenced — `--update`, then `check` PASS: 41 tree-reader targets, registry equals the derived set. Refs #3002, PMAT-1073, PMAT-1077 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…ow's own falsifier never ran Regenerating the derived tree-reader registry surfaced it: the ledger of "tree-reading test targets that no workflow runs" GREW by a line, and the line was `apr-cli --test backend_refusal_case_table` — R-0b's own case table, five tests, the ones that assert a forced backend is never resolved to cpu and that every BACKEND_VALUES entry resolves on every fixture. Nothing in .github/workflows named it, so the row's central claim had no executing falsifier: gates or theater (I3), and this was theater. Ledgering it was the other option the guard offers and is the wrong one here — the ledger is for targets nobody has wired YET, and this one is the reason the row exists. It joins ci.yml's gated test line beside registry_failure_catalogue and registry_case_table; the registry then moves it out of the unwired ledger by derivation, not by hand: 41 -> 42 wired, 40 -> 39 unwired, both checks PASS. Locally: `cargo test -p apr-cli --test backend_refusal_case_table` 5 passed. Refs #3002, PMAT-1073, PMAT-1077 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…refusal proof never ran on main Found by asking of this row what R-0b's regenerated tree-reader ledger asked of its sibling: which of this PR's test targets does a workflow actually execute? $ grep -rc reg15_admission .github/workflows/ -> no match crates/apr-cli/tests/reg15_admission.rs is card item (i)'s falsifier — seven hermetic tests, among them forced_backend_over_a_failed_parity_gate_refuses_with_the_code_from_ error_rs, which is the whole claim of REG-15: a forced backend never silently downgrades. BSE-17's quick tier runs it on a PR that touches apr-cli, but the full tier and every push to main run `--lib` plus ONE explicit list of --test targets, and it was not on that list. Merged as it stood, nothing on main would ever have executed it again — the exact trap recorded for the beats line (a new test target is theater until it is added there). It joins that line beside cli_commands. Note the scale of the standing problem while passing: apr-cli carries 64 integration targets and the line names 7 of them (#2341). Refs #2971, PMAT-1065 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…N of both rows' falsifiers Both rows edit the one line ci.yml uses to gate integration targets, which is why the convention is that only one PR touches it at a time; here the stack forces both. The resolution is the union, verified by count rather than by eye: reg15_admission (L0-1a), registry_failure_catalogue + registry_case_table + backend_refusal_case_table (R-0b), one occurrence each. Tree-reader registry unchanged and PASS at 42 wired / 39 unwired. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
…from // to /// The claims ratchet refused three entries in dispatch.rs and one in serve/mod.rs. They are NOT new numbers: main carries the same prose. What this row did was move it from `//` line comments into `///` doc comments, and the guard's aperture is exactly that boundary — `///` is rustdoc, a surface a user reads. A private rationale comment became a published speed claim, in a release whose notes say no speed was delivered. The figures are removed from the doc comments and the reader is pointed at FALSIFY-BACKEND-CUDA-HONESTY-001 and #2696, where the measurements carry their basis and can be re-measured — which an API doc cannot. One `//` comment records why the numbers live there and not here, so the next edit does not re-promote them. RE-BASELINING WAS TRIED FIRST AND IS STRUCTURALLY REFUSED, correctly. serve/mod.rs's entry was baselined at :209 and this row's edits moved the line to :210; `--update` rewrites the entry, but the ratchet is SET-based, not count-based — an entry may only LEAVE — so 209 -> 210 reads as growth even at an identical count. The guard says so: "Fix the finding instead of recording it." Fixing it shrinks the baseline 452 -> 451. Also `.pr/R-0b/discover.json` carried this worktree's absolute path; generalised. check_no_claim_literals PASS (451 known, 0 new) · check_baseline_ratchets PASS (1 removed) · check_hardcoded_paths delta +0 · cargo check -p apr-cli --lib clean. Refs #3002, PMAT-1073 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RouwmUL7vFfJyCx9qLEoH
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Row R-0b (#3002, PP-066 #2873, claim 1) — backend resolution reads the registry. Not armed:
status: partial(two cfg reads await the #3040 decomposition) and the base R-0a (#3004) is not on main yet — this PR is stacked and cannot merge before it.Ticket
PMAT-1073 (minted in #3025). Issue #3002 (inst:A). Blockers: R-0 (#3004), G-11 ✓, L0-1a (#3026).
Claim
apr-cli turns a backend request into a
Selectionor a refusal by reading the registry, nevercfg!; a forced accelerator (--gpu,--backend cuda|wgpu) that this host has not Ready refuses and is never downgraded to cpu.RED test
crates/apr-cli/tests/backend_refusal_case_table.rs(5 rows over R-0a's fixtures) — GREEN on the resolution; the falsifiers are the two mutations below.Acceptance (
.pr/R-0b/accept.sh)A2 case table 5/5, A3 guard self-test 3/3, A4 registry unit tests, A5
pv validate— GREEN. A1 (--static== 0) is RED:dispatch.rs:173andlib.rs:230still read cfg (residual; #3040).Mutation (measured this tree; CI pair owed once the PR runs)
resolve_in→ cpu: case table RED (…never_downgrades,every_backend_value…).cfg!ataccel.rs:28:check_backend_registry.sh --staticRED naming the line.Contract
contracts/apr-backend-registry-v1.yamlREG-OB-004 + REG-F-003 (extends R-0a's);pv validate: 0/0, valid.Quorum
Review-only (the design was judged with R-0a's 3-lane quorum, 2026-09-06); the resolution half is a diff review, owed before arm.
Receipt
docs/audits/impl-PMAT-1073-receipt.md—status: partial.Writes
crates/apr-cli/src/registry.rs(new, declared viacommands_enum.rs#[path]),error.rs(+BackendUnavailable/14),accel.rs,commands/serve/mod.rs,commands/bench.rs,commands/serve/handler_gpu_completion.rs,commands/finetune.rs,commands/serve/tests_offload_report_pp14.rs,commands/devices.rs(reserve_overridepub(crate));tests/backend_refusal_case_table.rs;scripts/check_backend_registry.sh;contracts/apr-backend-registry-v1.yaml;.github/workflows/ci.yml(+ guard self-test); receipt. No shared files.dispatch.rs/lib.rspristine (their conversion is #3040).Residual
#3040 decomposes
dispatch_runtime_commands/dispatch_diagnostic_commands/help_producer_truth::resolveso the last two cfg reads convert and--staticarms. A3's effective-configbackend/discovered_atandmake fleet-verify ROW=R-0balso owed.🤖 Generated with Claude Code