Skip to content

PMAT-3430 Phases 3-4: three ggml enums become one (M1 complete) - #3621

Merged
noahgift merged 5 commits into
mainfrom
PMAT-3430-m1-phases-3-4
Sep 21, 2026
Merged

noahgift merged 5 commits into
mainfrom
PMAT-3430-m1-phases-3-4

Conversation

@noahgift

@noahgift noahgift commented Sep 20, 2026 •

Copy link
Copy Markdown
Member

This is the half of #3430 that makes its title true. #3581 landed the leaf and the upstream-extracted TRAITS[43]; this collapses the three enums into it.

Rebased onto main after #3581 merged (840c9c789). The diff is now exactly the three commits that belong here: Phase 1, Phases 3-4, and the receipt. 18 files, net +518.

The falsifier, met

#3430's acceptance criterion is "exactly 1 ggml tensor-type enum definition under crates/*/src":

$ grep -rnE '^\s*pub enum (GgmlType|GgmlQuantType)\b' crates/*/src --include='*.rs'
crates/aprender-quant/src/ggml_type.rs:140:pub enum GgmlType {

Four declarations of one fact are gone: serve's GgmlQuantType (16 ids), core's GgmlType (12), compute's GgmlType (15), and QTYPE_LABELS — the private 13-row table #3405 added while three enums of it already existed.

Behaviour preservation is measured, not asserted

Phase 1 wrote 12 characterization tests against unchanged code, and all 12 pass unchanged through Phases 3-4. That is the whole argument that this is safe, and the only part of it a reviewer can check without re-deriving the boundaries by hand.

crate boundaries sweep
serve 7 — gguf/dtype ×2, infer, apr/mod's from_binary dtype arm, apr/special_tokens, apr/dequant, the loader test mirroring the predicate ids 0..=255, every admitted name, its lower-case form, 8 names that must stay unrecognised
compute 1 ids 0..=255, all 15 rows of block geometry, partial-block rounding
core 0 — measured: nothing in core turns an integer or a string into a GgmlType 24 (dtype, elements) points through byte_size

The id sweep is 0..=255 and not "the interesting ids" because the property is about what is refused as much as what is accepted, and a sweep over the admitted set cannot see a widening.

Exactly two edits to those tests, both named in advance: compute's GgmlType::from_u32(x) → from_u32(x) (an inherent method cannot follow a foreign type; the admitted set is untouched), and core's Q4_1 row below.

Each crate keeps its own admitted set

The leaf knows all 35 live ggml types. No crate may start accepting an id it used to refuse — that is how a loader begins decoding bytes it has no kernel for. compute → ADMITTED[15]; serve → ADMITTED[16] with admitted_from_id/admitted_from_name at all seven boundaries; core → none, and none is needed.

The one value that changes

core sized Q4_1 at 18 bytes/block; ggml says 20, and core's own format/gguf/shape.rs already said 20 — two tables in one crate disagreeing. It was never reachable: export_tensors_to_gguf uses data.len(), and byte_size() has no non-test caller. A unit test had asserted the 18 since it was written — a test pinning a defect.

Phase 1 anticipated it, asserted the disagreement directly so it could not be fixed by accident, and instructed its own deletion once fixed. Both happened in one commit: two expectations moved (36→40, 54→60), the companion test went, and the other 22 assertions passed untouched — evidence that delegation changed one value, not twelve.

What the collapse was worth, counted honestly

Four tables → one; one wrong value removed and one omission (QTYPE_LABELS had no Q8_1 row, so a refusal printed qtype 9). That is smaller than the collapse deserves credit for, and the reason matters: the big find is not in this diff. Measuring in-tree tables against the extracted one is what exposed ggml_dtype_element_size, a fifth id-indexed table, wrong in 10 of 31 rows including BF16 at 0.375 B/elem instead of 2.0 — which makes the #2569 truncation check fail-open on BF16 GGUFs. That is #3583, deliberately not folded in.

The guard

scripts/check_one_ggml_type_enum.sh — green here, 15-row case table (a re-export, a commented-out definition, GgmlTypeError, GgufValue, QuantType and a private enum all correctly not matched), and a zero-match arm that fails rather than passing vacuously. Mutation: re-adding a second definition to compute turns it RED naming both files; restoring turns it GREEN. guard_tree discovers it via git ls-files 'scripts/check_*.sh', so committing it is what wires it. Its root comes from $0, not git rev-parse — the container refuses the bind-mounted tree (#3586).

Verification

cargo nextest run --profile ci -p aprender-serve -p aprender-core -p aprender-quant --lib
                                              30,168 passed, 61 skipped
cargo test -p aprender-compute --lib           3,514 passed
cargo check --workspace --all-targets          clean
cargo clippy -p {quant,compute,core,serve} --lib -- -D warnings  clean
cargo fmt --all -- --check                     clean
check_one_ggml_type_enum.sh / --self-test      1 definition / 15 cases, 0 failures

Net -35 lines while adding a 111-line guard.

The stop condition did not fire

I said before starting that if a boundary's behaviour could not be preserved I would stop and surface it rather than widen an admitted set to make a test pass — and that under automatic publishing, widening would be a fabricated green feeding a release. It did not come up: all 12 snapshots passed unchanged, and both edits to them were named before the work began. The admitted sets were reproduced from measured behaviour, not chosen.

Receipt: docs/audits/impl-PMAT-3430-phases-3-4-receipt.md.

keep-open: #3421 is the epic, #3431 is M2 (not started), #3583 is the fifth table this work exposed and is deliberately separate; #3430 itself is closed by this PR.

Closes #3430

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

§13.11 rung 1 — quorum shadow verdict

S13-SHADOW pr=3621 head=6931c01135821512312811ae9dcbe7b859629fec 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 and others added 3 commits September 20, 2026 20:37
#3430 Q1-c claims Phases 3-4 are behaviour-preserving: no crate accepts an id
or a name it refused before. This makes that a measurement instead of a promise.

12 tests, all written against UNCHANGED code and all green on it now. They
must pass UNCHANGED after the re-exports and admission functions land, with
ONE edit named in advance (below).

  serve, 7 boundaries — the id sweep is 0..=255 at every one, because the
  property is about what is REFUSED as much as what is accepted and a sweep
  over the admitted set alone cannot see a widening:
    gguf/dtype.rs      apr_qtype_to_dtype (+ its refusal names the id),
                       apr_dtype_to_byte
    infer/mod.rs       qtype_to_dtype_str
    apr/mod.rs         the dtype_byte arm of TensorEntry::from_binary —
                       exercised through the REAL parser with a minimal entry,
                       not a re-typed copy of the expression, which would pass
                       while the real path changed
    apr/special_tokens MappedAprModel::dtype_to_qtype
    apr/dequant        dtype_to_ggml_qtype, which deliberately admits LESS
                       than the enum knows (F32/F16/BF16 -> None)
  compute, 1 boundary — from_u32 over 0..=255, plus all 15 rows of block
    geometry and the partial-block rounding, since compute is the only one of
    the three enums that carried sizes and the extraction agreed with it exactly
  core, 0 boundaries — measured, not assumed: nothing in core turns an integer
    or a string into a GgmlType. Its whole exposure is ONE exhaustive match,
    GgufTensor::byte_size, snapshotted here at 24 (dtype, elements) points

Each lives in a #[cfg(test)] child module of the boundary's own module, so the
private items are reachable without widening anything; the only non-test edits
in this commit are four `mod` lines.

THE ONE ROW EXPECTED TO MOVE, named now so the diff cannot hide it: core sizes
Q4_1 at 18 bytes/block where upstream says 20 AND core's own shape.rs already
says 20. A second test asserts that disagreement DIRECTLY, so it cannot be
fixed by accident; Phase 3 deletes that test and moves one row in the case
table, 54 -> 60, in the same commit.

Refs #3430

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

The ticket's headline. `crates/aprender-serve` (16 ids), `crates/aprender-core`
(12) and `crates/aprender-compute` (15) each declared their own ggml
tensor-type enum; a fourth private table, QTYPE_LABELS (13 rows, #3405), named
the same ids again. All four are gone. The tree now holds ONE definition:

  $ grep -rnE '^\s*pub enum (GgmlType|GgmlQuantType)\b' crates/*/src
  crates/aprender-quant/src/ggml_type.rs:140:pub enum GgmlType {

BEHAVIOUR IS PRESERVED, AND THAT IS MEASURED, NOT ASSERTED. Phase 1's 12
characterization tests were written against the unchanged code and sweep every
boundary over ids 0..=255. All of them pass UNCHANGED through this commit,
with exactly the two edits named in advance:

  - compute: `GgmlType::from_u32(x)` -> `from_u32(x)`, because an inherent
    method cannot follow a type defined in another crate. The admitted SET is
    untouched — still exactly 15 ids, now stated once in `const ADMITTED`.
  - core: the Q4_1 row, below.

Each crate keeps its own admitted set, stated once and enforced at every
boundary, because the leaf knows all 35 live ggml types and no crate may start
accepting an id it used to refuse:

  compute  ADMITTED[15] + `from_u32`, at its one GGUF parse boundary
  serve    ADMITTED[16] + `admitted_from_id` / `admitted_from_name`, at all
           SEVEN boundaries (gguf/dtype x2, infer, apr/mod's from_binary arm,
           apr/special_tokens, apr/dequant, and the loader test that mirrors
           the predicate)
  core     none, and none is needed — measured: nothing in core turns an
           integer or a string into a GgmlType

THE ONE VALUE THAT CHANGES, AND THE COUNT THE COLLAPSE IS WORTH. core sized
Q4_1 at 18 bytes per block where ggml says 20 (2 x f16 for scale AND min, plus
16 nibble bytes) and where core's OWN other size table, format/gguf/shape.rs,
already said 20. Two tables in one crate disagreeing, and the wrong one was the
one nothing called — `export_tensors_to_gguf` sizes tensors with data.len(), so
no GGUF was ever written wrong by it. A unit test had asserted the 18-byte
value since it was written, pinning the defect.

So the honest ledger for this collapse: four tables -> one, ONE wrong value
removed (Q4_1) and one omission (QTYPE_LABELS had no row for Q8_1, so a refusal
printed `qtype 9`). The larger find is not in this diff: measuring against the
extracted table is what exposed `ggml_dtype_element_size`, a FIFTH id-indexed
table, wrong in 10 of 31 rows including BF16 at 0.375 B/elem instead of 2.0 —
that is #3583, deliberately not folded in here.

QTYPE_LABELS's replacement goes through `from_id`, never `TRAITS[id]`: it takes
an arbitrary u32 from a file and a raw index would panic for any id >= 43. It
is also deliberately NOT filtered by the admitted set — it is a diagnostic, and
naming id 21 in a refusal beats printing `qtype 21`.

GUARD: scripts/check_one_ggml_type_enum.sh, green on this tree, with a 15-row
case table (a re-export, a commented-out definition, GgmlTypeError, GgufValue,
QuantType and a private enum all correctly NOT matched) and a zero-match arm
that FAILS rather than passing vacuously. Mutation: re-adding a second
definition to compute turns it RED naming both files; restoring turns it GREEN.
guard_tree discovers it automatically via `git ls-files 'scripts/check_*.sh'`,
so committing it is what wires it.

Verified: 30,168 tests across serve+core+quant (nextest, ci profile) and 3,514
in compute, all passing; `cargo check --workspace --all-targets` clean; clippy
-D warnings clean on all four crates; fmt clean.

Refs #3430, #3421, #3583

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The falsifier met, the 12 characterization tests that make behaviour
preservation a measurement, the one value that changed and why it was never
reachable, and an honest count of what the collapse was worth.

Refs #3430

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@noahgift
noahgift force-pushed the PMAT-3430-m1-phases-3-4 branch from 5e329db to 5420b7e Compare September 20, 2026 18:39
@noahgift

Copy link
Copy Markdown
Member Author

quorum-review (AD-04): three PASS — agreed (auto_merge: checked=true was_armed=false disarmed=false)

{
 "ticket": "PMAT-3430",
 "head": "5420b7e982a47ab1073870efb04aedce7e22ea86",
 "width": 3,
 "executor": "agy",
 "agreed": true,
 "auto_merge": {
  "checked": true,
  "was_armed": false,
  "disarmed": false,
  "note": "auto-merge not armed"
 },
 "lanes": [
  {
   "lane": 1,
   "verdict": "PASS",
   "findings": 5
  },
  {
   "lane": 2,
   "verdict": "PASS",
   "findings": 0
  },
  {
   "lane": 3,
   "verdict": "PASS",
   "findings": 4
  }
 ]
}

gemini-3.1-pro-high, gemini-3.1-pro-low, gemini-3.6-flash-high — each model
measured from its own agy log, none in the author's family, no dissent. One
round: the Pro variants and 3.6-flash returned a verdict object first time,
where 3.8/3.7-flash-high had returned none in five of six lane-runs on #3581.

Refs #3430, #3562

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@noahgift
noahgift added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit 79a3af7 Sep 21, 2026
31 of 32 checks passed
@noahgift
noahgift deleted the PMAT-3430-m1-phases-3-4 branch September 21, 2026 06:35
@noahgift noahgift mentioned this pull request Sep 21, 2026
guyernest pushed a commit to guyernest/aprender that referenced this pull request Sep 29, 2026
…0 theorem was false where the generator reaches (paiml#3631)

* PMAT-3627 step 1 (RED): the input that killed paiml#3621, as a committed regression case

RED FIRST. Only the regression test lands; the proptest, the contract and the header
are untouched. On THIS commit:

  test regression_3627_scale_invariance_in_the_eps_dominated_regime ... FAILED
  3627 regression: sign*y[1]=-1.414158 vs y_scaled[1]=-1.1461217, diff=0.26803625

Input: data = [0.0, -0.15964308], alpha = 0.012254778. alpha^2 * mean(x^2) = 1.91e-6,
eps = 1e-6 (RMSNorm::without_affine, group_norm.rs:275). Ratio 1.91: the eps term is
not negligible and RMSNorm(alpha*x) != sign(alpha)*RMSNorm(x), by design of eps. The
numbers were re-derived in f64 independently of the CI log and match to six digits;
the eps>0 identity y_scaled = sign(a)*y*sqrt((m+eps)/(m+eps/a^2)) predicts -1.146122
with relative error 2e-16. The implementation is right; the assertion was wrong.

Refs paiml#3627, paiml#3621

Pmat-Ticket: PMAT-3627
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* PMAT-3627 step 2 (GREEN): assert the eps>0 scale-invariance property, not the eps=0 theorem

Same regression case as the RED commit, now green, plus the proptest, the contract and
the file's header.

THE PROPERTY. With eps in the denominator,
    RMSNorm(a*x) = sign(a) * RMSNorm(x) * sqrt((m+eps) / (m+eps/a^2)),  m = mean(x^2),
exactly (re-derived in f64: relative error 2e-16 on the killing input). The eps=0
theorem RMSNorm.rms_scale_zero_eps is the k -> 1 limit and is false whenever a^2*m is
comparable to eps. The proptest and the regression case now assert the eps>0 form with
a relative tolerance of 1e-4 -- testing what the implementation computes, in every
regime the generator reaches -- and the guessed `tol = 0.05 if |alpha| < 0.1` branch
is gone. Option 1 from the issue, chosen over the precondition: it is the stronger
property and excludes nothing.

  regression_3627_...                              ok
  prop_scale_invariance x 20 runs, fresh seed each  20/20 ok
  MUTATION (k := 1, the eps=0 form restored)       RED: rel=0.18953769 -- the 19%
  the whole rmsnorm suite                          12 passed, 0 failed

The regression case also pins y_scaled[1] = -1.146122 and k = 0.810462, so it is
anchored to the incident's numbers, not only to the identity.

THE CONTRACT. RN-INV-005's formal now states the eps>0 property (carries Sigma symbols:
forall, ne, sqrt, arrows), and its Lean notes say precisely which regime the eps=0
theorem covers. FALSIFY-RN-002 names both tests and the mutation. pv validate clean;
cargo test -p aprender-contracts --lib 1666/1666 (sigma armed). The edit adds no file
and no triple, so census/graph/README are unchanged -- checked by regenerating.

THE HEADER. This file said "DO NOT EDIT -- regenerate with `pv probar --binding`". That
is false: the in-tree pv probar emits seven `#[ignore = "no binding available"]` stubs
for this contract and cannot produce these bodies, which came from the pre-monorepo
generator (20dda94, 2026-02-18). Obeying the header would have replaced five real
property tests with seven ignored stubs. This is a declared HAND EDIT, and the header
now says so; the issue's "regenerated, no hand edit" item was withdrawn on that
measurement. The same false header stands on ~50 other tests/contracts/ files: paiml#3630.

RETRIES ARE THEATER FOR PROPERTY TESTS. nextest [profile.ci] retries = 2 replayed the
case proptest persisted to proptest-regressions/ on TRY 1, so TRY 2 and 3 failed in
0.005 s each: three tries, one failure. A retry cannot un-persist a counterexample.

Refs paiml#3627, paiml#3621, paiml#3630

Pmat-Ticket: PMAT-3627
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* PMAT-3627: register the ticket (fragment + aggregate) so the AD-04 quorum can run

docs/roadmaps/entries/PMAT-3627.yaml hand-entered from issue paiml#3627 (title, done_when as
notes), roadmap.yaml regenerated by make roadmap-aggregate. quorum-review.sh refuses
unless `pmat work status PMAT-3627` resolves, and the item existed only as a GitHub
issue. Four roadmap guards rc=0. No renumbering, no separate PR.

Pmat-Ticket: PMAT-3627
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* PMAT-3627: AD-04 quorum receipt — 3/3 PASS, three independent lanes

docs/audits/quorum-PMAT-3627.json from quorum-review.sh --base origin/main --pr 3631, executor
agy, width 3, models gemini-3.1-pro-high / gemini-3.8-flash-high / gemini-3.7-flash-high,
none in the author's family. Independence inspected: every lane file has zero
references to a sibling lane, $WORK or the .lanes/ dir. Dissent: none.

Pmat-Ticket: PMAT-3627
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
guyernest pushed a commit to guyernest/aprender that referenced this pull request Sep 29, 2026
…dicts discarded, measured (paiml#3626)

* PMAT-3587 nextest half, step 1 (RED): the guard that refuses a fail-fast [profile.ci]

RED FIRST. Only the guard lands; .config/nextest.toml is untouched, so on this commit:

  $ bash scripts/check_nextest_ci_profile_no_fail_fast.sh
  FAIL  .config/nextest.toml: [profile.ci].fail-fast = True -- a failing test cancels
        every test still queued and their verdicts are discarded                   rc=1
  $ bash scripts/check_nextest_ci_profile_no_fail_fast.sh --self-test
  ok    rows 1-9 (every polarity: false / true / absent / wrong profile / no profile /
        false-in-a-comment / the string "false" / unparseable / missing file)
  FAIL  row 10  the real .config/nextest.toml is RED                                rc=1

Row 10 is deliberate: the case table judges the real config too, so a red tree cannot
hide behind green fixtures.

paiml#3616 landed --no-fail-fast as the default for the explicit-command runner. The
workspace-test shards run under nextest's OWN profile, where fail-fast = true still
stands, and that is the half the operator's "on the shard" most plausibly meant.

The behaviour, measured on a 6-test probe whose 2nd test fails (~60 ms), the rest
400-550 ms, -j 2 -- not read from docs:

  fail-fast = true    Summary  3/6 tests run: 2 passed, 1 failed
                      Cancelling due to test failure: 1 test still running
  fail-fast = false   Summary  6 tests run: 5 passed, 1 failed          (still rc 100)
  (key absent)        Summary  3/6 tests run  -- nextest's DEFAULT is fail-fast ON

So an absent key is RED, not neutral, and the guard says so. The tree's own number for
this class is the prior instance, not tonight's: "nextest fail-fast hid every other
dark failure: 7 rounds for 4 tests." Tonight's 11,757 on paiml#3621 were NOT this -- that
log reads `Cancelling due to signal`, nextest's wording for receiving SIGTERM itself,
which fail-fast does not govern; the probe above produced fail-fast's actual wording,
`Cancelling due to test failure`, and the two are distinct. Those 11,757 are a receipt
row (a signal-killed shard must read as Unknown), filed separately.

The guard reads the key STRUCTURALLY (tomllib, [profile.ci], the bool) and runs no
build tool, so guard_tree.sh --no-cargo picks it up with two rows and no ci.yml step
is needed. Its first draft's header comment named the build tool with a space after
it and matched CARGO_RE on its own -- a substring test satisfied by the documentation
of the thing it looks for, in a guard written the day that class was named.

Refs paiml#3587, paiml#3616, paiml#3621, paiml#3607

Pmat-Ticket: PMAT-3587
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* PMAT-3587 nextest half, step 2 (GREEN): [profile.ci] fail-fast = false

One line in .config/nextest.toml, plus the comment that says why. Same guard as the
RED commit, unchanged: now `run` PASS and `--self-test` 10/10.

Every workspace-test shard runs `cargo nextest run --profile ci`, so this is the
setting they inherit. A red shard now still measures every test it was going to
measure, and the Summary line counts them -- which is exactly when the data is most
wanted. The failure is still a failure (rc 100); it is just no longer the only thing
the shard knows.

nextest re-reads the config cleanly (`cargo nextest show-config version` rc 0).

Not touched: ci.yml:497's comment "[profile.ci]: retries=0, fail-fast" -- a workflow
file, and already stale on retries (paiml#2616). It now drifts on both keys; noted in the
PR body rather than edited here.

Refs paiml#3587, paiml#3616

Pmat-Ticket: PMAT-3587
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* PMAT-3587: register the ticket (fragment + aggregate) so the AD-04 quorum can run

docs/roadmaps/entries/PMAT-3587.yaml hand-entered from issue paiml#3587, roadmap.yaml
regenerated by make roadmap-aggregate. Four roadmap guards rc=0.

Pmat-Ticket: PMAT-3587
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* PMAT-3587: AD-04 quorum receipt for paiml#3626 — 3/3 PASS, three independent lanes

docs/audits/quorum-PMAT-3587.json, executor agy, width 3, judged at head 0981864,
author model claude-opus-5, lane models gemini-3.1-pro-high / gemini-3.7-flash-high /
gemini-3.6-flash-high (the trio ruled for everyone tonight after 3.8-flash's silences,
paiml-implement#311). Three distinct conversation ids, verdicts via structured_output,
zero sibling-lane or $WORK references. Dissent: none. First attempt.

Pmat-Ticket: PMAT-3587
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(guard): the nextest fail-fast guard read a missing tomllib as "the config is RED" -- ENV is never 1

Measured on intel-clean-room-6 (paiml#3626, guard-tree job 106169486109, head 2be40b4):

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ModuleNotFoundError: No module named 'tomllib'
    FAIL (rc=1)

and the self-test on the same runner: rows 1, 8, 10 FAIL, rows 2-7 "ok" -- because
those rows WANTED rc=1 and a dead interpreter delivers rc=1 too. tomllib is python
3.11+; the runner's python3 is older; lambda's is 3.13, which is why every local run
was green. The `import tomllib` sat at module level, outside the try, so the import
error was never classified: an environment death was reported as a code defect, on a
guard that exists to stop verdicts being discarded.

Reproduced locally against the old guard with /usr/bin/python3.10 -S (no tomllib,
no tomli): identical traceback, `FAIL (rc=1)`.

What changes (all in scripts/check_nextest_ci_profile_no_fail_fast.sh):

- Readers, in order: tomllib, tomli, then a purpose-built reader for the ONE
  question this guard asks (under [profile.ci], what is fail-fast?). The reader
  refuses -- ENV rc=2, never a guess -- anything outside its scope: multi-line
  strings, values continuing past the line, dotted keys, top-level keys, duplicate
  tables, [[profile.ci]] as an array of tables, a fail-fast value it cannot type.
  The real .config/nextest.toml (inline tables, [[...overrides]], sub-tables)
  judges GREEN through it: `NEXTEST_GUARD_PYTHON=python3.10
  NEXTEST_GUARD_FORCE_FALLBACK=1` -> `reader=purpose-built reader`, rc=0.
- The judge SAYS its verdict (a `VERDICT ok|FAIL|ENV` line). The shell accepts
  rc 0/1 only with that line; rc=1 without it -- a traceback before the first
  statement, a SyntaxError on an old python, no python3 at all (rc=127) -- is ENV
  rc=2 naming the interpreter and $RUNNER_NAME. A BaseException catch-all inside
  the judge classifies the rest as ENV too.
- Self-test: 10 -> 30 rows. The case table runs twice, once per reader
  (NEXTEST_GUARD_FORCE_FALLBACK=1 sets sys.modules['tomllib'] = sys.modules['tomli']
  = None so the imports fail for real, not a flag that skips around them); three
  refusal rows for the purpose-built reader; two death rows (/bin/false as the
  interpreter, a missing interpreter) that want ENV 2; two new table rows
  (false under [[profile.ci.overrides]] only -> RED; the real file's shape ->
  PASS). Passes under python 3.13.1 and 3.10.12 on this box.

Mutants, each turning the self-test RED (baseline PASSED 30 rows):
  M1 rc=1 accepted with no VERDICT line            row 28 rc=1 (wanted 2)
  M2 purpose-built reader removed                  10 rows
  M3 multi-line string opener skipped, not refused  1 row  (fixture: `note = """title"`,
                                                     which a quote-count check passes)
  M4 [[profile.ci]] read as the profile             1 row
  M5 the string "false" typed as the bool           1 row
  M6 judge always returns 0                        21 rows
  M8 continuation lines not refused                 1 row
  M7 (library reader: a list profile.ci not refused explicitly) SURVIVES and is
     equivalent by construction: the catch-all classifies the AttributeError as the
     same ENV 2. Kept for the message it gives.

Gates on the tree: bashrs-gate PASS (354 files), pipe-into-grep-q 75/75, hardcoded
paths delta +0, apr pinned OK; the guard's --help still says self-test, so guard_tree
runs both rows; no `cargo ` substring, so it stays inside the --no-cargo run.

AD-04: docs/audits/quorum-PMAT-3587.json was judged at head 0981864 with
diff_sha256 428d6936d2f8478c7de2da67b93566df08a18f2f43eb78ba6314027eff16a772. This
commit MOVES diff_sha256 (the guard is inside the judged diff); the receipt is left
as judged, per the cop's ruling that a fix on the same intent stands on it and says
so here. New value: 41cdea8a2e887122bfa3e3d2ec8d37166ae1b52a88532d3f21f980e0e24e71c9.

Refs paiml#3587 paiml#3626

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

* PMAT-3587: AD-04 quorum receipt round 2 for paiml#3626 at 3df1c64 — 3/3 PASS

Round 1 (0981864, diff_sha256 428d6936…) attested a diff that the tomllib fix
(0464c2d) replaced; the cop disarmed on that ground. Round 2 judges the merge
head 3df1c64 against origin/main (diff_sha256 e54d3397…): lanes
gemini-3.1-pro-high / gemini-3.1-pro-low / gemini-3.6-flash-high, PASS/PASS/PASS.
Independence: lane 1 ran `--self-test` itself, lane 3 ran the guard against its
own fixture under NEXTEST_CONF_OVERRIDE, lane 2 read only; no lane transcript
reads a sibling lane file (lane-3's one match is the receipt named as a diff
item, not a verdict).

Refs paiml#3587 paiml#3626

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

PP-QUANT-001 M1: one #[repr(u32)] GgmlType (43 rows: 35 live + 8 Removed) + TRAITS[43] below core/compute/serve — ggml enums 3 → 1

1 participant