Skip to content

feat(registry): R-0a — BackendRegistry probes and enumerates cpu/cuda/wgpu at startup and apr devices prints every kind as a line (PMAT-989, #2904) - #3004

Open
noahgift wants to merge 25 commits into
mainfrom
agent/R-0
Open

feat(registry): R-0a — BackendRegistry probes and enumerates cpu/cuda/wgpu at startup and apr devices prints every kind as a line (PMAT-989, #2904)#3004
noahgift wants to merge 25 commits into
mainfrom
agent/R-0

Conversation

@noahgift

@noahgift noahgift commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

PP-066 DAG row R-0 — after the design quorum's split, R-0a: the registry EXISTS and PRINTS.

Ticket

PMAT-989 · issue #2904 (inst:B) · epic #2873 · spec §5 R-0, REG-1..14 · row label R-0.
Resolution — refusing a --backend that is not Ready, effective-config, zero cfg! reads in decisions — is R-0b (#3002, PMAT-1060), the design quorum's split.

Claim

BackendRegistry::discover() runs at startup before any engine or model and yields one entry per discovered device plus one explicit Unavailable(reason) line for every kind of {cpu, cuda, wgpu, metal, hip} that discovered nothing (REG-11: absence is a line); apr devices [--json] prints it, or the apr-devices-v1 JSON, and discovery never fails the process (REG-1).

  • trueno::registrycpu always Ready; CUDA through the dlopen'd driver (libcuda.so.1, never cudart — REG-2); wgpu adapters with their transport (a software rasteriser is NoBackend, never a GPU); the object-safe BackendFactory + MockBackendFactory (REG-13 — ComputeBackend is not object-safe); entries carry api + device_uid, so one card seen through two APIs is two entries and ONE device; vendor_id: Option (Apple silicon has no PCI id); mem_kind: Unified { working_set_limit }; the REG-7 reserve (3,584 MiB, basis [U] until master row 6) as ReserveExceedsFree{reserve, free} propagated across every entry of the refused device; REG-8 selection printed with its reason; REG-12 nothing persisted, a fixture-built registry says source=fixture(path).
  • apr devices [--json] — category hardware, an ExtendedCommands variant; overrides APR_RESERVE_BYTES / APR_REGISTRY_FIXTURE are printed when active; a malformed override is exit 4 by name.

RED test (sha)

1ef2a22b3crates/aprender-compute/tests/registry_case_table.rs committed before any registry code; 5795ccc46 turns it green. Row 10 (two_different_cards_with_one_name_stay_two_devices) is RED-first too, at 871fd49e4, for the intel four-host finding.

Acceptance (.pr/R-0/accept.sh)

$ bash .pr/R-0/accept.sh          # reverted tree, this box (lambda-vector), 2026-09-06
ok    case-table-nofeatures                          rc=0
ok    case-table-gpu                                 rc=0
ok    case-table-cuda                                rc=0
ok    failure-catalogue                              rc=0
ok    cli-commands                                   rc=0
ok    compute-lib                                    rc=0
ok    pv-registry                                    rc=0
ok    pv-devices-schema                              rc=0
ok    write-set                                      rc=0
ok    baseline-ratchets                              rc=0
ok    complexity-ratchet                             rc=0
ok    fmt                                            rc=0
ok    clippy-compute                                 rc=0
ok    clippy-apr-cli                                 rc=0
ok    apr-devices-ready                              rc=0
ACCEPT: every A_i green

A8 (apr-devices-ready) runs the binary built from HEAD via . scripts/apr_bin.sh — never a bare apr — and asserts [.entries[]|select(.status.state=="ready")]|length>=1.

Mutation (RED run id → GREEN run id)

commit mutation run result
RED 4a66e20a7 apply_reserve's pass-1 refusals cleared before pass 2 — a reserve refusal stops propagating to the same device's other-API entries 34049785730 — job workspace-test 101531455145, step 11 "Integration tests" FAILURE, exit 101 — fx7_reserve_exceeding_free_memory_is_a_named_refusal FAILED (9 passed; 1 failed). The block it printed names the defect: cuda unavailable reason=ReserveExceedsFree{reserve=1072668082176, free=21474836480} followed by selected: wgpu device[0] — the library picked the wgpu twin of the very RTX 4090 the driver had just refused
GREEN fae3b7f35 mutant reverted, nothing else changed 34054230827 gate + workspace-test SUCCESS (the two required checks)

One line. Two independent tests catch it — the catalogue's FX-7 row and the case table's a_reserve_refusal_propagates_to_the_devices_other_api_entries (the one that fails locally) — and the && chain short-circuits at the first, so CI reports FX-7. Nothing else in the run moved.

The mutant was aimed at the job that actually runs them: the integration line carrying --test registry_case_table is in workspace-test (ci.yml:408), not in ci / test. ci / test was GREEN on the mutant commit and proves nothing about it — worth stating, because that is the job a reader would check first.

Ledger re-audit (check_dogfood_coverage.sh, new on main with G-10/G-11)

G2.1 freshness is RED when a branch edits a file the surface ledger cites and leaves the ledger behind. This PR inserts 7 lines at extended_commands.rs:631 and 5 at dispatch_analysis.rs:484 — both cited. The guard is satisfied by touching docs/audits/surface_audit.csv, which is the shape worth refusing, so:

  • 64 citations re-pointed through an exact old→new line map (difflib, origin/main's copy vs HEAD's). All 2,160 + 1,832 old lines map — pure insertions — so 0 unmapped, and the two citations a text search called AMBIGUOUS are resolved by the map. Row order preserved, no row lost (G2.2: "833 comparand rows all present").
  • One new row for apr devices (cluster 10 apr-core-commands, evidence extended_commands.rs:636). in_dogfood_skill=yes is measured, not asserted: dogfood_surfaces.sh enumerates subcommands from the BUILT binary's --help, and its own awk parser lists devices among 111 subcommands of a binary reporting fae3b7f35 = HEAD. The first attempt at this measured a binary from b83c2313b — an ancestor of this branch that already had devices — and would have "proven" the claim while measuring nothing; scripts/apr_bin.sh refused it, and two others, before APR_BIN was pinned to a build of HEAD.
  • The stated counts that move with the ledger: the contract's overall block (833/143/0.1717 → 834/144/0.1727, as its own scripts/dogfood_baseline.py command measures), its two T2 pairing lines, and the same line in .claude/skills/apr-dogfood/SKILL.md.
DOGFOOD COVERAGE GATE: PASS      G2.1-G2.6 green, 144/834 covered (17.3%), 28 per-binary floors held

Two more guards, new on main with G-10/G-11, were red on this branch and are fixed here. Both were found by running all 77 non-self-test guard invocations of guard-runner-labels locally rather than discovering them one ~2 h CI cycle at a time:

  • python3 scripts/dogfood_baseline.py --check compares every baseline block in the contract against the ledger, not just overall. The new row moves three more: per_binary apr 370/143 → 371/144, per_cluster apr-core-commands 109/38 → 110/39, per_band q7_8 9/9 → 10/10 (the row is quality 8).
  • G-11 DERIVES the DAG row status from the receipt's front matter. So flipping this row's receipt to status: complete — which the driver asks for before arming — takes render_dag.py --check to DRIFT and check_dag_invariants.sh to D7: typed status open disagrees with the receipt (derived complete); status is derived, never typed. The protocol both guards state is that a row PR ships partial and the orchestrator docs commit flips the marker and re-renders the spec block in one commit. The marker is therefore partial, with that as its stated partial_reason, and the receipt's Verdict says plainly that the work is done. render_dag --check rc=0, check_dag_invariants rc=0 (91 rows, 0 violations).

Contract

contracts/apr-backend-registry-v1.yaml (invariants (i) and (iii) discharged; (ii), (iv), (v) are R-0b's and are not claimed) and contracts/apr-devices-schema-v1.yaml; JSON schema contracts/schemas/apr-devices-v1.schema.json, validated with the jsonschema crate on the fixtures and on the running machine. Page contract contracts/apr-page-cli-devices-v1.yaml for book/src/cli/devices.md.

$ . scripts/pv_bin.sh && "$PV" validate contracts/apr-backend-registry-v1.yaml
0 error(s), 0 warning(s)
Contract is valid.

$ . scripts/pv_bin.sh && "$PV" validate contracts/apr-devices-schema-v1.yaml
0 error(s), 0 warning(s)
Contract is valid.

Quorum

  • Design quorum, before P2 (the row requires it): 3 lanes, 3/3 implement-with-changes, 3/3 split, no lane said do-not-implement. The record docs/audits/pp-066-r0-design-quorum.md is the ORCHESTRATOR's — docs(PP-066): R-0 design quorum (3/3 implement-with-changes) — split into R-0a registry + R-0b resolution (#3002, PMAT-1060), expiries moved under §12, spec §12 llamafile citation corrected #3003 was closed and folded into agent/pp-066-spec (0aa5a38d5), because G-11 forbids a non-orchestrator branch from writing the DAG, the spec block or the roadmap. Cited here, not carried.
  • Review quorum, at P3: 3 lanes, 3/3 mergeable-with-changes; four claims TRUE and fixed at 3c6cbea07 (devices listed twice in the CLI contract; the CUDA factory's NoDevice/ProbeFailed arms dead behind a three-into-one bool; the JSON schema accepting documents serde refuses; override: lines echoing the env instead of the registry), one FALSE (help-parser decomposition), two recorded as limitations. Adjudication in the receipt.

Receipt

docs/audits/impl-PMAT-989-receipt.mdstatus: partial by the G-11 rule above, not because anything is unfinished, with a Resume section recording what this session found: gate was RED via guard-runner-labelscheck_complexity_ratchet.sh 2 STALE rows (this PR's own --help-parser decomposition dropped them under both thresholds), and G-11 (#3020) landed check_row_pr_write_set.sh after this branch was cut, so the branch's README count bump had to go.

Stated, not routed around: the README now UNDERSTATES (1811 claimed against 1814 present; 110 against 111). That is the G-11 design — the counts are a ratchet, "may lag, never overstate" (FALSIFY-README-005/007), regenerated by the orchestrator docs commit with --exact. And present (pr-review-quorum) stays RED for want of a signed receipt at evidence/pr-review/3004; it is not one of the two required checks and #3020 merged with it red.

Writes

.github/workflows/ci.yml (two --test targets appended to the integration line — a new tests/*.rs is dark until it is on that line), Cargo.lock, book/src/SUMMARY.md, book/src/cli/devices.md, contracts/{apr-backend-registry-v1,apr-cli-commands-v1,apr-devices-schema-v1,apr-page-cli-devices-v1}.yaml, contracts/schemas/apr-devices-v1.schema.json, crates/apr-cli/**, crates/aprender-compute/**, docs/audits/impl-PMAT-989-receipt.md, docs/audits/impl-estimates.jsonl, docs/audits/surface_audit.csv, contracts/apr-dogfood-coverage-v1.yaml, .claude/skills/apr-dogfood/SKILL.md, scripts/complexity_baseline.txt (2 STALE rows deleted — shrink-only, 2 removed).
No shared file: check_row_pr_write_set.sh --branch agent/R-0 --event pull_requestPASS, "row PR agent/R-0 writes no shared file (31 changed paths)". Ruleset and branch protection unchanged.

…/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
@noahgift
noahgift enabled auto-merge September 6, 2026 05:14
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

§13.11 rung 1 — quorum shadow verdict

S13-SHADOW pr=3004 head=fffdfa3089edb465d17c4c7222e658a1a122ce8a 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.

…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
…; this branch is code + receipt only

Pmat-Ticket: PMAT-989
…s branch leaves roadmap.yaml untouched

Pmat-Ticket: PMAT-989
noahgift added a commit that referenced this pull request Sep 6, 2026
…pv-only release assets, nightly is the only prebuilt apr, decision surfaces still cfg!-driven until R-0b, in-place fleet pmat flip at 07:47Z, #3004 stalled on its own concurrency group, queue timeout risk)

Pmat-Ticket: PMAT-1017
crates/apr-cli/tests/cli_commands.rs::get_help_commands and ::help_subcommands
fell under both thresholds when the registry test was rewritten; the ratchet
refuses a kept row for a fixed function (the next regression at that coordinate
would land for free). Verified locally: check_complexity_ratchet.sh rc=0,
689 recorded offenders, 2 removed, none new, none grown, none stale.

Also drops this branch's README count bump: G-11 (#3020) makes the README counts
a ratchet the orchestrator regenerates, and check_row_pr_write_set.sh refuses a
count line on a row branch. PASS: row PR agent/R-0 writes no shared file.

(PMAT-989, #2904)
@noahgift noahgift added pp-066 PP-066 (0.66) DAG row inst:B PP-066 instance claim (I14): inst:B R-0 PP-066 DAG row R-0 (BackendRegistry) labels Sep 6, 2026
…does not propagate across a device's APIs (reverted in the next commit)

Driver v6 P2 requires the mutant to be PUSHED and the PR's own CI to go RED,
not a local run. Local pre-push result at this commit:
  cargo test -p aprender-compute --test registry_case_table
  9 passed; 1 failed - a_reserve_refusal_propagates_to_the_devices_other_api_entries
  'the twin carries the sibling's measured free memory: Ready'
Exactly one test moves, so the RED is attributable to this one line.

(PMAT-989, #2904)
…ion run ids

Reverts 4a66e20. The mutant was PUSHED and the PR CI went RED on it, as
driver v6 P2 requires:

  RED   run 34049785730, job workspace-test 101531455145, step 11
        "Integration tests" - FAILURE, exit 101.
        fx7_reserve_exceeding_free_memory_is_a_named_refusal FAILED
        (9 passed; 1 failed). The printed block names the defect:
          cuda unavailable reason=ReserveExceedsFree{reserve=..., free=21474836480}
          selected: wgpu device[0]
        i.e. the library selected the wgpu twin of the very RTX 4090 the
        cuda driver had just refused for the reserve.
  GREEN this commit.

Two independent tests catch the one-line mutant; CI short-circuits at the
first, so the catalogue row fires before the case-table row that fails
locally. The mutant was aimed at the job that actually runs them: the
integration line carrying --test registry_case_table is in workspace-test
(ci.yml:408), NOT in ci / test - ci / test was GREEN on the mutant commit
and proves nothing about it.

Receipt flipped to status: complete with turns, and a Resume section
recording the two blockers this session found (the complexity ratchet STALE
rows this PR created, and G-11 landing the row write-set guard after this
branch was cut).

(PMAT-989, #2904)
@noahgift noahgift changed the title feat(R-0a): BackendRegistry — probe, enumerate, print: every backend kind is a line, cpu always Ready, cuda via the dlopen'd driver, wgpu with transport, REG-7 reserve propagated across a device's APIs; apr devices [--json] + schema + hermetic failure catalogue (PMAT-989, #2904; split per the design quorum, R-0b #3002) feat(registry): R-0a — BackendRegistry probes and enumerates cpu/cuda/wgpu at startup and apr devices prints every kind as a line (PMAT-989, #2904) Sep 6, 2026
…dogfood coverage gate G2.1)

check_dogfood_coverage.sh landed on main with G-10/G-11 and is RED on this
branch: G2.1 freshness refuses a ledger left behind the code it describes, and
this PR inserts 7 lines at extended_commands.rs:631 and 5 at
dispatch_analysis.rs:484 - both cited evidence files.

  - 64 citations re-pointed through an EXACT old->new line map (difflib over
    origin/main's copy vs HEAD's; every one of the 2160 + 1832 old lines maps,
    0 unmapped, 2 that a text search called AMBIGUOUS resolved by the map).
    Row order is preserved and no row is lost - G2.2 reconciliation reads 833
    comparand rows all present.
  - one new row: apr devices, cluster 10 apr-core-commands, evidence
    extended_commands.rs:636, in_dogfood_skill=yes. That is measured, not
    asserted: dogfood_surfaces.sh enumerates subcommands from the BUILT
    binary's --help, and its own awk parser lists 'devices' among 111
    subcommands of a binary that reports fae3b7f == HEAD (pinned through
    APR_BIN + scripts/apr_bin.sh, which refuses a stale one - it refused
    three).
  - the stated counts that must move with the ledger: the contract's overall
    block (833/143/0.1717 -> 834/144/0.1727, as scripts/dogfood_baseline.py
    now measures), its two T2 pairing lines, and the same line in the
    apr-dogfood skill.

DOGFOOD COVERAGE GATE: PASS (G2.1-G2.6 all green, 144/834 covered, 28
per-binary floors held). pv validate on the contract: 0 errors.

(PMAT-989, #2904)
…oves, and the receipt marker G-11 derives the DAG status from

Two guards this branch had not yet seen, both new on main with G-10/G-11:

1. `python3 scripts/dogfood_baseline.py --check` (guard-runner-labels step 46)
   compares EVERY baseline block in contracts/apr-dogfood-coverage-v1.yaml
   against the ledger, not just `overall`. The `apr devices` row moves three
   more: per_binary apr 370/143 -> 371/144, per_cluster apr-core-commands
   109/38 -> 110/39, per_band q7_8 9/9 -> 10/10 (the row is quality 8).
   CHECK PASSED: every baseline in the contract matches the ledger.

2. G-11 DERIVES the DAG row status from this receipt's front matter, so
   flipping it to `complete` in a ROW PR takes render_dag.py --check to DRIFT
   and check_dag_invariants.sh to D7 'typed status open disagrees with the
   receipt (derived complete); status is derived, never typed'. The protocol
   both guards state is that a row PR ships `partial` and the ORCHESTRATOR
   docs commit flips the marker AND re-renders the spec block together. Marker
   restored to partial with that as its stated reason; the Verdict section
   says plainly that the work is done and why the marker reads as it does.
   render_dag --check rc=0, check_dag_invariants rc=0 (91 rows, 0 violations).

Found by running all 77 non-self-test guard invocations of guard-runner-labels
locally instead of discovering them one CI cycle at a time.

(PMAT-989, #2904)
@noahgift

noahgift commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Status at 6fecabe4f: this PR's own work is green; the merge is blocked by a defect on main that no row branch may fix.

required check result
workspace-test SUCCESS — run 34062437191
guard-runner-labels (in gate's needs) SUCCESS — all ~150 steps, including the two that were red here earlier
gate FAILURE, and only because ci / security failed
ci / security → step 5 roadmap-valid FAILURE — 19 duplicate ids in docs/roadmaps/roadmap.yaml on origin/main

git diff origin/main HEAD -- docs/roadmaps/roadmap.yaml is empty on this branch, the duplicates are present at 027ed889d, and ci / security is failing identically on agent/pp-066-spec, agent/L0-1 and agent/L0-1b. So this is repo-wide, not this PR's. Filed as #3033; under G-11 the roadmap is the orchestrator's file and check_row_pr_write_set.sh refuses a row PR that writes it, so the dedup needs one orchestrator commit.

Auto-merge stays armed — this merges by itself once #3033 lands. Nothing here needs re-running: gh run rerun would replay the same stale merge base and fail the same way.

What this PR fixed since it was last reviewed (each verified by re-running the guard, not by inspection):

  1. check_complexity_ratchet.sh — 2 STALE rows this PR's own --help-parser decomposition created. Deleted; 689 offenders, 2 removed, none new/grown/stale.
  2. The README count bump — G-11 landed check_row_pr_write_set.sh after this branch was cut. Dropped; the README may lag, never overstate.
  3. check_dogfood_coverage.sh G2.1 — the surface ledger re-audited: 64 citations re-pointed through an exact old→new line map (0 unmapped), one new apr devices row whose in_dogfood_skill=yes is measured against a binary built from HEAD.
  4. dogfood_baseline.py --check — the three further baseline blocks the new row moves (per_binary apr, per_cluster apr-core-commands, per_band q7_8).
  5. render_dag.py --check + check_dag_invariants.sh D7 — G-11 derives the DAG row status from the receipt, so a row PR must ship status: partial; the marker is restored with that as its stated reason.

(3)–(5) were found by running all 77 non-self-test guard invocations of guard-runner-labels locally in one pass rather than one ~2 h CI cycle at a time.

@noahgift
noahgift added this pull request to the merge queue Sep 7, 2026
@noahgift
noahgift removed this pull request from the merge queue due to a manual request Sep 7, 2026
@noahgift
noahgift added this pull request to the merge queue Sep 7, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

inst:B PP-066 instance claim (I14): inst:B pp-066 PP-066 (0.66) DAG row R-0 PP-066 DAG row R-0 (BackendRegistry)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant