Skip to content

PMAT-3430: M1 plan + quorum history (0/3, 1/3, 1/3, 1/3) — draft, no code, awaiting a ruling - #3452

Closed
noahgift wants to merge 6 commits into
mainfrom
PMAT-3430-one-ggml-type
Closed

noahgift wants to merge 6 commits into
mainfrom
PMAT-3430-one-ggml-type

Conversation

@noahgift

Copy link
Copy Markdown
Member

Draft — plan and receipt only, no code. Refs #3430 (does not close it). Parent #3421.

The plan for PP-QUANT-001 M1 (one GgmlType + TRAITS[43], homed in aprender-quant) went through four plan-quorum rounds: 0/3, 1/3, 1/3, 1/3. The operator's rule on #3421 is no code before 3/3 and no v5 if an objection survives two rounds; two Q1 objection classes survived three. The grid, every lane reason verbatim, and the repeat analysis are in docs/audits/impl-PMAT-3430-receipt.md and posted on #3421 for a ruling.

What the lanes did not dispute in any round: the target, the home crate (aprender-quant is a leaf under core, compute and serve — derived from cargo metadata), Table E after v1, and X1 ordering.

Found on re-runs, independent of the ruling:

  • core GgufTensor::byte_size sizes Q4_1 at 18 bytes/block; upstream is 20.
  • Q8_1 is 36 by ggml's C static_assert and 40 in gguf-py at the pinned sha, so the ticket's falsifier cannot be met as worded.

Verdict: PARTIAL(escalate). This PR stays draft and must not merge as is.

🤖 Generated with Claude Code

noahgift and others added 6 commits September 17, 2026 15:37
…olved, not yet reviewed

Home crate derived from cargo metadata: aprender-quant is a leaf under core, compute and serve. No code until the plan quorum is 3/3 (operator rule on #3421).

Pmat-Ticket: PMAT-3430
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hen answered

rustc reproduces E0308 for an associated-const pattern on &self, so the Bf16 alias is withdrawn. Upstream read at the pinned sha: block_q8_1 is static_asserted at 36 bytes, gguf-py says 40. Admission moves from the GGUF parser to all 7 serve boundaries, proven by characterization tests taken before the change.

Pmat-Ticket: PMAT-3430
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s byte_size sizes Q4_1 at 18

All three lanes found the exhaustive match in GgufTensor::byte_size; re-running it showed its Q4_1 arm is 18 bytes per block where upstream is 20. Delegating to the single table fixes that, so it is named as the one intended behaviour delta and pinned by a test that flips.

Pmat-Ticket: PMAT-3430
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…fix leaves M1 and lands first

No lane disputes the architecture any more. Adopted from the dissent: a size fix riding a refactor breaks the refactor's own behaviour-preserving claim, so core byte_size Q4_1 18 to 20 becomes Phase 0b, its own issue and PR. The leaf API block is declared a contract with clippy -D warnings in the acceptance command.

Pmat-Ticket: PMAT-3430
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… classes survived three rounds, so no v5

The lanes never disputed the target or the home crate. They dispute that a source-compatible, behaviour-preserving shim can be enumerated in advance. That is the operator's to rule on; no code was written.

Pmat-Ticket: PMAT-3430
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…unning_peak=1

Run from the worktree the gate reads the wrong project directory and passes on zero subagents.

Pmat-Ticket: PMAT-3430
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

§13.11 rung 1 — quorum shadow verdict

S13-SHADOW pr=3452 head=b5eb08cece6179c84e44356aecfe92974725573a 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

Copy link
Copy Markdown
Member Author

RULING (operator, 2026-09-20) — PMAT-3430 M1

Recorded verbatim. Lane A is unblocked; no fifth quorum round.

  1. Settled, no further quorum: target (one #[repr(u32)] GgmlType, 43 rows: 35 live + 8 Removed), home crate aprender-quant, Table E, X1 ordering. Undisputed in rounds 1-4; they are closed.

  2. Oracle: upstream ggml at the pinned llama.cpp sha (3173a5647) is the reference [X]. In-tree enums are the defendant, never the reference. Where they disagree, in-tree is a defect.

  3. Falsifier, re-worded. Old wording (agreement with the existing core/compute/serve values) is unsatisfiable: core Q4_1 = 18 bytes/block vs upstream 20 (2xf16 + 16); Q8_1 upstream is 36 by static_assert vs 40 in-tree (pre-f16 layout).
    New: for every live row i, TRAITS[i].{blck_size,type_size} equals the value extracted from ggml at the pinned sha by a committed command; the extraction output is a checked-in fixture; mutation of any one row turns the test RED (shown in the PR body).

  4. Every in-tree disagreement is a row in the reconciliation table (PMAT-3431), each with: upstream value, in-tree value, call sites, and a verdict of NEVER-WORKED or REGRESSION, measured on the v0.68.1 binary - not inferred.

  5. Fix-or-refuse per type: a type whose in-tree size was wrong ships in M1 with the upstream value AND a one-line refusal + exit code on load, until a round-trip fixture for that type is green. No silent behaviour change for Q4_1/Q8_1 consumers.

  6. Remaining disputed D-rows: one amendment round, then HRQ. No fifth open round.

One clause needs a correction before it can be executed — clause 2's sha

The ruling makes the pinned llama.cpp sha the oracle, so every number in M1's fixture is extracted from whatever that sha resolves to. It does not resolve here. Measured on the release tree:

sha status
d1d3c3396 the pin of record — scripts/llama_pin.toml build_commit, pinned_on = 2026-09-15, pin_expiry = 2026-12-01, 216 references in-tree
39173bcac an older comparator pin, still referenced 124 times (e.g. the CPU-leg parity basis in evidence/parity/thresholds.yaml)
3173a5647 (the ruling's) appears nowhere in the tree — grep -rl over the repo returns nothing

I am not substituting a sha into the ruling by inference: the whole point of clause 2 is that the oracle is named, and an oracle resolved by guessing is not an oracle. The implementer needs one line back: is the oracle d1d3c3396 (the pin of record), or a deliberate new pin? If it is a new pin, note that bumping the comparator invalidates every ratio measured against the old one — llama_pin.toml says so itself, and that is a decision with a named cost rather than a bump.

Second-order finding, independent of the answer: two comparator pins are live in-tree at once — 216 references to d1d3c3396 and 124 to 39173bcac. Some committed artifacts are therefore measured against a superseded oracle. That deserves its own row regardless of how clause 2 resolves.

What proceeds now, unblocked

Refs #3080, #3430, #3431, #3421, #3562

@noahgift

Copy link
Copy Markdown
Member Author

AMENDMENT (operator, 2026-09-20) — clause 2 of the M1 ruling, recorded verbatim

2'. The oracle is scripts/llama_pin.toml build_commit, by reference, never a literal sha. Today that resolves to d1d3c3396. No pin bump is ordered by this ruling. "3173a5647" in the original clause is struck: it was the checkout the 43/35/8 count was first measured at, not a pin.

2a. The TRAITS fixture records the sha it was extracted from. A test asserts fixture.sha == llama_pin.toml build_commit. A pin bump therefore turns the fixture RED until it is regenerated by the committed extraction command — the bump's cost is visible in the bump PR, not discovered later.

2b. Row counts are derived, not ruled. Re-extract at d1d3c3396; if live/Removed differs from 35/8, the extraction wins and the PMAT-3430 title is corrected. "43" is [U] until then.

2b is now measured — the ticket's numbers hold. [U] cleared.

Extracted from the pinned checkout at /home/noah/src/llama.cpp-d1d3c3396 (git rev-parse HEAD → d1d3c3396aa1…, matching llama_pin.toml build_commit), from ggml/include/ggml.h:

count ids
live 35 0–3, 6–30, 34, 35, 39–42
Removed (commented out) 8 4 Q4_2, 5 Q4_3, 31 Q4_0_4_4, 32 Q4_0_4_8, 33 Q4_0_8_8, 36 IQ4_NL_4_4, 37 IQ4_NL_4_8, 38 IQ4_NL_8_8
total slots 43 GGML_TYPE_COUNT = 43, ids 0…42, and 35 + 8 = 43 ✓

So 43 rows: 35 live + 8 Removed is confirmed at the pin. No title correction is needed and the count can stop being [U].

Method note, because it nearly went the other way. A first pass with a one-line grep returned 44/41/3 and looked like a disagreement. It was wrong twice: it counted GGML_TYPE_COUNT as a type, and it classified a commented row as live whenever the comment did not contain the word "removed" (// GGML_TYPE_Q4_0_4_8 = 32, says nothing). Reading the enum settled it. Worth stating because clause 3's fixture will be generated by a command, and a sloppy extractor produces a fixture that is confidently wrong on exactly these rows — the commented block at 31–33 and 36–38 is the trap.

Four live types are recent — MXFP4 (39), NVFP4 (40), Q1_0 (41), Q2_0 (42). Whether in-tree carries them at all is part of clause 4's reconciliation, and a NEVER-WORKED verdict is the likely shape there rather than REGRESSION.

What clause 3's committed extraction command must do

  1. Parse enum ggml_type from ggml/include/ggml.h at the resolved pin, taking commented rows as Removed by position, not by comment wording.
  2. Take blck_size / type_size from ggml's own type-traits table, not from the header comment, and not from any in-tree value.
  3. Emit the fixture with the sha it read, so 2a's assertion has something to compare.
  4. Prove it can fail: mutate one row, expect RED (in the PR body, per clause 3).

2a generalises, and there is already a ticket for the general case

2a — an artifact derived from the pin records the pin, and a test asserts they match, so a bump's cost surfaces in the bump PR — is exactly the mechanism #3563 asks for repo-wide, where two comparator pins are live at once (216 references to d1d3c3396, 124 to the earlier 39173bcac). The TRAITS fixture should be the first artifact built to this shape, and #3563's guard should be written as the general form of it rather than as a separate idea.

Refs #3080, #3430, #3431, #3452, #3563

@noahgift

noahgift commented Sep 20, 2026 •

Copy link
Copy Markdown
Member Author

done_when

(Fixed heading, written by the cop for tab 2. pmat work add derives no acceptance_criteria and pmat work edit cannot set them on a planned ticket — paiml-mcp-agent-toolkit#1414. The ticket authorizes; this heading is the definition of done. Tabs write their own done_when only for rows they mint.)

This is Band 0. It and the tag-path move (#3459/#3461) are the two gates on 0.69's T-0 — 06x-release-schedule.md §1.1a makes slice M the must-carry row and APR-RELEASE-001 §0 row 1a puts it above everything.

The plan quorum ran 0/3, 1/3, 1/3, 1/3 and was closed by operator ruling 2026-09-20, amended the same day (recorded in this issue's comments). No fifth round: remaining disputed D-rows get one amendment round, then HRQ (#3562).

STOP: any threshold or size typed into a test instead of extracted from the pin · a second quorum round on the settled items · touching contracts/census.json or contracts/lint-baseline.json without the touches-shared-contracts label (group of one, behind this row).

Measure in a fresh worktree off origin/main, never the driver checkout — four wrong claims came from that mistake today.

@noahgift

Copy link
Copy Markdown
Member Author

Two of the ruling's own premises are wrong — measured by the correctness lane, and they change clause 5

Recorded here because the ruling lives in this issue and an implementer will read it before #3430's comments.

1. There is no Q8_1 = 40 anywhere in the tree. The ruling states "Q8_1 is 36 by ggml's static_assert and 40 in gguf-py at the pinned sha" and clause 4 asks for a reconciliation row with call sites. The 40 is gguf-py's, reached through a document — not in-tree code. So there is no in-tree disagreement to reconcile for Q8_1.

2. Clause 5 has no Q4_1 case either. GgufTensor::byte_size does size Q4_1 at 18 bytes/block against upstream's 20 — but it has no non-test caller. Clause 5 says a type whose in-tree size was wrong ships with the upstream value plus a one-line refusal on load; there is no load path for that refusal to sit on.

Consequence: clause 5 ships with no refusal — stated, not skipped. That distinction is the whole point: a refusal nobody can reach is a refusal that reads as coverage while providing none, which is the defect class this train is clearing. The reconciliation row for Q4_1 is therefore NEVER-WORKED with no live consumer, not a fix-or-refuse row.

Full measurement in #3430 comment 5749705532.

And the ruling's real casualty turned up while deriving the table

aprender-core::ggml_dtype_element_size is ordered by its own comment rather than by ggml id and is wrong in 10 of 31 rows — BF16 reads 0.375 B/elem instead of 2.0, which makes the #2569 truncation check fail-open on BF16 GGUFs. Filed #3583, P0, verified here by reading the table on origin/main.

That is the argument for slice M with a user-visible casualty attached: a hand-maintained mirror of an upstream table, partially repaired once by PMAT-869 in June, wrong ever since in the rows nobody re-checked. #3583 lands immediately after #3581 as its first consumer — a lookup into TRAITS, never an eleventh hand-typed row.

@noahgift

Copy link
Copy Markdown
Member Author

Closed: superseded by #3581. Operator ruling 2026-09-20 ~14:00Z.

This is a draft plan PR (272 lines, two files, no code) for PP-QUANT-001 M1. The ruling it says it awaits was recorded this morning on #3452 / #3430 / #3431 — it is not waiting on anything, and #3581 is executing the plan it holds. A draft plan PR is not a T-0 gate; the code PR is.

Nothing is lost by closing: the quorum history (0/3, 1/3, 1/3, 1/3), every lane reason verbatim, and the repeat analysis live in docs/audits/impl-PMAT-3430-receipt.md and on #3421, and the ruling is preserved in the issue body of #3430. The branch is kept.

Carried forward so it does not die with this PR — one finding here was independent of the ruling and is not in #3581's scope as filed: core GgufTensor::byte_size sizes Q4_1 at 18 bytes/block; upstream is 20. That belongs to the same table family as #3583's BF16 size row (ggml id 30 sized 0.375 instead of 2.0) — two wrong rows in id-indexed size tables, found separately, which is the partial-repair class. If #3581 does not already fold the Q4_1 row in, it needs its own row against the TRAITS table.

T-0 blocker count on 0.69 drops by one.

@noahgift noahgift closed this Sep 20, 2026
@noahgift

Copy link
Copy Markdown
Member Author

The ruling landed. This PR's header is stale, and nothing is blocked on it.

Answering the question directly, because two readers have now re-derived it: the operator ruled on #3430 on 2026-09-20, with an amendment the same day (the ruling sits above my execution report). So the "no code before 3/3" rule on #3421 is discharged for M1 — not waived, and not routed around by narrowing scope. Clause 1 closed the design questions outright: "Settled, no further quorum: target (one #[repr(u32)] GgmlType, 43 rows: 35 live + 8 Removed), home crate aprender-quant, Table E, X1 ordering. Undisputed in rounds 1-4; they are closed." Clause 6 disposed of the remainder: "one amendment round, then HRQ. No fifth open round."

The two Q1 objection classes that survived three rounds did not survive the ruling either. Both were about the falsifier, and clause 3 replaced it: the old wording (agreement with the existing core/compute/serve values) is unsatisfiable, so it was struck in favour of extraction-plus-mutation against upstream ggml at the pinned commit. A quorum cannot converge on a falsifier that cannot be met; that is what the four rounds were actually measuring.

M1 is implemented in #3581, running full CI now. It is not a narrower scope: it is clauses 1-6 as written, with the amended 2'/2a/2b. The leaf, TRAITS[43], the committed extraction command, the fixture recording its sha, the pin-agreement invariant, and six mutations RED with every control GREEN.

This PR's own content is still worth keeping

Plan v4 and the four-round grill record are the provenance for #3581 and are cited by its receipt. Three things in them were correct and load-bearing: the home-crate derivation from cargo metadata (aprender-quant is the leaf under core, compute and serve), the boundary inventory behind Q1-c, and round 3's ruling that the Q4_1 fix must not ride the refactor — which #3581 honours by changing no consumer at all.

Two things in it are now superseded and should not be implemented as written:

  1. The Q8_1 exception list is void. Q1-d proposed "TRAITS equals gguf-py GGML_QUANT_SIZES except a named list, today exactly [Q8_1]". gguf-py is no longer consulted at all, so there is no list to maintain and no list to rot. Upstream's C table says 36 and that is simply the value.
  2. The premise that in-tree carries 40 for Q8_1 is false. Measured across the tree: aprender-compute's block_bytes, aprender-core's shape.rs:230 and the GPU dp4a kernels all say 36. The 40 came from Table S of the PMAT-3427 receipt, which read gguf-py — a document, not code. Clause 5 therefore has no Q8_1 case, and (measured separately) no Q4_1 case either, since GgufTensor::byte_size has no non-test caller.

Disposition

Nothing depends on this PR. #3581 does not need it merged, and the milestone gate counts it as an open item. Recommend close it, or take it out of draft as a docs-only provenance merge — tab 1's call, either way. If it closes, the plan and grill record survive in #3581's receipt (docs/audits/impl-PMAT-3430-m1-leaf-receipt.md §6 lists every deviation from plan v4 with its reason), so nothing is lost.

What should not happen is a fifth quorum round on this plan. Clause 6 forecloses it, and the objections it would re-litigate are objections to a falsifier that no longer exists.

Refs #3430, #3421, #3581

@noahgift
noahgift deleted the PMAT-3430-one-ggml-type branch September 23, 2026 16:15
guyernest pushed a commit to guyernest/aprender that referenced this pull request Sep 29, 2026
…her than typed (paiml#3581)

* PMAT-3430 M1: one ggml tensor-type table, extracted from upstream rather than typed (paiml#3430)

Three enums named ggml tensor types here and disagreed — serve 16 ids, core 12,
compute 15, against 35 live upstream — and at least three separate tables gave
their byte sizes. Nothing compared any of them to ggml, so NVFP4 (40), Q1_0 (41)
and Q2_0 (42) arrived upstream with no signal in this tree.

This lands the leaf the three will re-export: `trueno_quant::GgmlType` (35 live
variants at their upstream ids) and `TRAITS[43]`, dense and indexed by id, with
the 8 removed slots kept so the index is the id.

EVERY NUMBER IS EXTRACTED, NOT WRITTEN. ggml's own table says
`.type_size = sizeof(block_q4_1)`; every in-tree table that got these numbers
wrong got them wrong by hand. scripts/extract_ggml_traits.sh compiles a probe
against the pinned checkout's libggml-base and asks ggml
(ggml_type_size/ggml_blck_size/ggml_type_name/ggml_is_quantized), then writes
crates/aprender-quant/fixtures/ggml_traits.json.

The oracle is named BY REFERENCE (operator ruling 2026-09-20, clause 2'): the
extractor reads `build_commit` from scripts/llama_pin.toml through the repo's
one reader for it, refuses a checkout that is not at that commit (exit 3) or is
dirty (exit 4), and records the sha in the fixture. FALSIFY-GGML-001 then fails
if that sha stops being the pin — so a comparator bump turns this RED in the
bump's own PR (clause 2a; the general case is paiml#3563).

The header is still parsed, as a cross-check that can FAIL. `enum ggml_type`
has 8 commented-out rows and only some say "removed" — `// GGML_TYPE_Q4_0_4_8 =
32,` says nothing — and a pass that classified by wording returned 44/41/3
instead of 43/35/8 during the ruling. A row is Removed because its line is
commented, and that must agree with the compiled table's blck_size == 0 or the
extractor emits nothing (exit 7). Seven synthetic cases pin both polarities, and
falsify_ggml_003 refuses a zero-case run.

MUTATION (clause 3), all RED, controls GREEN:
  TRAITS[9].type_size 36 -> 40 (gguf-py's Q8_1, refuted by ggml's static_assert)
  TRAITS[30].name BF16 -> Bf16 · TRAITS[4].family Removed -> Affine
  a fake id in the fixture · the fixture's pin -> 39173bcac · a row deleted

Measured while extracting, and NOT fixed here (clause 4 input for paiml#3431):
  core's ggml_dtype_element_size is wrong in 10 of 31 rows — from index 16 it
  follows the order of its own COMMENT instead of ggml id order, so BF16 read
  0.375 B/elem instead of 2.0 and the paiml#2569 truncation check was fail-open on
  BF16 GGUFs. PMAT-869 fixed four K-quant rows of that same table and stopped.
  core's GgufTensor::byte_size sizes Q4_1 at 18 (upstream 20) while core's own
  shape.rs says 20 — two tables in one crate disagreeing. It has no non-test
  caller, so nothing was written wrong by it.
Both fixes land next, as lookups into TRAITS rather than a fourth hand-typed
table. Receipt: docs/audits/impl-PMAT-3430-m1-leaf-receipt.md.

Behaviour: unchanged. No consumer imports the leaf yet; serve's 16 strings and
compute's 15 sizes are asserted identical, and aprender-quant's six published
K-quant constants are now const-asserted against TRAITS, so a drift is a
compile error.

Refs paiml#3430, paiml#3421, paiml#3431, paiml#3452, paiml#3563

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

* PMAT-3430: the extractor's case table asked git where it was, and CI's container refuses to say

`workspace-test-shard (3/3)` turned red on `falsify_ggml_003` — not on anything
it judges, but on `git rev-parse --show-toplevel` inside the container:

    fatal: detected dubious ownership in repository at '/workspace'

The bind-mounted tree is owned by uid 1000 and the container runs as root, so
git refuses the repo. Neither script ever needed git for this: the self-test
locates its sibling emitter, and the extractor locates scripts/llama_pin.toml.
Both now derive the root from `$0` and ask git only about the llama.cpp
checkout, which is the one question that IS about a repository.

Proved under the container's exact condition, with `git` shadowed by a stub
that exits 128 with that message: the self-test still reports 7 cases 0
failures, and the extractor now fails where it should — at the checkout, after
resolving the root and reading the pin.

Refs paiml#3430

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

* PMAT-3430: quorum verdict 3/3 on 9bbcaa4 (AD-04)

Three independent lanes, none in the author's family, all PASS, no dissent:
gemini-3.1-pro-high, gemini-3.8-flash-high, gemini-3.7-flash-high (each model
MEASURED from its own agy log line, not merely declared). receipt-lint accepts.

It took four rounds and none of the three losses was the diff: round 1 lost
lanes 1 and 2 to `UNAVAILABLE (503)` while both carried PASS text the reducer
correctly refused to count; round 2 and 3 lost lane 2 to a SUCCESS envelope
with no verdict object; round 3 I also cut short at my own 570 s cap. No lane
in any round returned FAIL or named a finding.

Refs paiml#3430, paiml#3562

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

* PMAT-3430: one new contract obliges two derived artifacts — regenerate both

Adding contracts/ggml-type-v1.yaml turned three CI checks red, all the same
omission: the contract CORPUS has tracked derivatives, and a PR that adds a
contract owes them in the same commit.

  guard-cargo   contracts/census.json .n_files=1799 but HEAD carries 1800
  shard (1/3)   contracts/contracts.nt differs from a fresh extraction (R-18)

Regenerated with the tools that own them, not by hand: `pv census contracts`
and `pv extract contracts`. Both diffs are exactly the one contract —
census +1 file, +1 kernel, +1 unanchored, new id_set_sha256; the graph +6
triples. Local: `cargo test -p aprender-contracts-cli --test ont4b_shapes_gate`
11 passed.

Worth stating because it is not discoverable from the failure: the census red
named its own remedy ("run make contracts"), the graph red named its own
("run pv extract"), and neither names the other — so a contributor who fixes
the first still gets the second on the next run, one CI round later.

Refs paiml#3430

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

* PMAT-3430: the case table must run where the code runs — awk, not python3; and a third derivative

Two reds on 3c0f4b3, both mine, both from assuming an environment.

1. shard (3/3): `python3: command not found`. The classifier behind the
extractor was python and the self-test drove it with python3. The
CONTAINERIZED workspace-test job has no python. I had reasoned it did, from
ci.yml running `python3 scripts/lib/roadmap_merge.py --selftest` — a step in a
DIFFERENT job, on the host runner. A case table that cannot execute where the
code executes proves nothing about it, so the interpreter had to go rather than
the check.

Ported scripts/extract_ggml_traits.py -> scripts/extract_ggml_traits.awk, and
took python3 out of the self-test's assertions too (sed on the emitted JSON;
the real parser is serde_json in the Rust consumer). awk is in the container
and in every base image this fleet uses.

PROOF THE PORT IS FAITHFUL: regenerating the fixture with awk produces a file
BYTE-IDENTICAL to the committed one that python wrote (`cmp` clean). PROOF IT
RUNS WHERE CI RUNS: executed under `env -i PATH=<coreutils only>` with python3
absent from PATH entirely — 7 cases, 0 failures.

2. guard-cargo: `FALSIFY-README-002 contract_count: the CONTRACT_COUNT block
states 1799, the merge tree carries 1800`. A THIRD tracked derivative of adding
one contract file, after census.json and contracts.nt — and it was MASKED by
the census red until that one was fixed, so it could not have been found in the
same round. `make readme-sync` (2 blocks).

The self-test's row 4 red is confirmed gone: it was the documented downstream
effect of the stale census (aprender#3516), not a structural failure of
contract-adding PRs. Measured 7/7 with the census regenerated, not assumed.

Refs paiml#3430, paiml#3587

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

* PMAT-3430: receipt §6a — what adding ONE contract file actually cost

Three tracked derivatives and a fourth guard, surfaced one per CI round because
each was masked by the one before it (paiml#3587):

  census.json -> guard-cargo · contracts.nt -> shard 1/3 (R-18)
  README CONTRACT_COUNT -> guard-cargo, INVISIBLE until the census was fixed
  §11.1 ont-delta -> guard-tree, because touching README.md at all reclassifies
                     the PR as a sweep

The fourth is the one worth recording: it is not a derivative of the contract,
it is a consequence of the REMEDY for the third. `make readme-sync` is
mandatory (guard-cargo refuses without it) and README.md is a §11.1 prose sink,
so fixing guard-cargo is what made guard-tree fail. Neither guard can see the
other and neither message says so.

Also records the two environment assumptions that cost a round each — git
refusing the bind-mounted tree, and python3 being absent from the container —
both of which I reasoned about instead of measuring.

The PR body now carries the `ont-delta: none` line §11.1 requires. Verified
against the real guard in both polarities: with it PASS, without it
`FAILED: §11.1 — a sweep that ends in prose and nothing else is not finished`.

Re-checked after editing the contract's reference line: contracts.nt and
census.json are both still byte-identical to a fresh extraction, so that edit
does not feed either derivative.

Refs paiml#3430, paiml#3587

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.

1 participant