Repository navigation
post-release ALWAYS updates README.md and apr-cookbook with SHACL-validated recipes — rendered from the release's own green cells, never typed #3769
Description
Operator, verbatim, 2026-09-21: "ensure our post-release always updated README.md and apr-cookbook with SHACL validated recipes"
Measured today: paiml/apr-cookbook (496 recipes, cargo run --example) has a README banner still at aprender 0.67.0. Its only recipe check is a deterministic recipe TABLE (scripts/generate-recipe-table.sh --check, on a hosted ubuntu-latest runner). Nothing validates that a recipe's command still exists or works on the released binary. aprender's README is gated for counts (readme_contract.rs) but not for the release's verified matrix. No release step touches either one.
Decided design (cop ruling; the operator's line is the requirement)
-
A recipe is data, validated by a shape. Each cookbook recipe declares: its argv (an
aprcommand), the model role(s) it needs, its inputs, its expected check (exit code, output predicate, schema), and the minimum apr version. A pv SHACL shapecookbook-recipe-v1requires:- the argv parses against the release binary's surface (P0: release cells are hand-coded, not DERIVED from apr's interface — the gate cannot see a verb, flag or input shape nobody typed into a list (run --prompt --chat, serve, code all leaked) #3745 S1 JSON), so a recipe citing a removed verb or flag is a violation;
- a receipt from THAT release's binary, with its
--versionsha, on a declared host, showing the expected check passed; - coverage derived from the surface: every model-taking verb has ≥1 recipe, and a verb with no recipe is a violation.
-
The README is rendered, not typed. The release section (version, date, the verified model × verb × thinking × context matrix, known REPORT rows) is rendered from the release-readiness receipt at the tag.
readme_contract.rsgains a check that the rendered section equals the tag's receipts. -
The post-release step does both, every release, fail-closed. A new autopilot step after
ledger:- runs every cookbook recipe against the just-published binary on lambda + gx10 (GPU lock, choom);
- writes the receipts;
- opens a PR on apr-cookbook (recipes + receipts + README banner) and a PR on aprender (the README release section), both unarmed.
A recipe that fails on the release binary STOPs close. It is never skipped, and either the recipe or the release gets a filed row.
-
First-green before it blocks: a dry-run against the published v0.68.2, rendering both PRs' diffs to the ledger only.
done_when
-
cookbook-recipe-v1shape + extractor with a planted pc_extract control (the PMAT-3704 / ONT-4c3: pc_extract draws one planted defect per implemented extractor — parity-receipt, json and pv-contract gain their controls, and the set is tied to Σ #3706 Σ-tie). Mutants: a recipe citing a flag absent from the surface → RED; a recipe with no receipt → RED; a model-taking verb with no recipe → RED. - README release section rendered from receipts; a hand edit that disagrees with the receipts → RED.
- Autopilot
docsstep: case table + mutants (recipe fails → STOP; PR not opened → STOP; armed PR → RED). - First-green dry-run on v0.68.2 committed as evidence.
- apr-cookbook's recipe workflow moves off the hosted
ubuntu-latestrunner (the operator's no-hosted-runners rule).
Refs #3745 #3715 #3731 #3768 #3710
AMENDMENT 2026-09-22 (proposed, UNRATIFIED — written by aprender-fc at the cop's direction during the wind-down)
Not a ruling. The cop (aprender-3e) declined to rule D1 in a wind-down, and directed that the proposal be written into this body so the next cop ratifies or replaces it against a real reviewer. Nothing below is decided. The full design note is issuecomment-5768819987, the f0-agreed step interface is issuecomment-5768898696, and the C5 groundwork is issuecomment-5770405739.
D1 (proposed): a recipe is a data file, and the 496 Rust examples are not recipes under it
apr-cookbook/recipes/apr/<verb>/<id>.yaml, schema cookbook-recipe/v1:
schema: cookbook-recipe/v1
id: run-greedy-qwen-1_5b # unique; the receipt is keyed by it
title: Run a Q4_K_M GGUF on one prompt, greedily
argv: ["apr", "run", "{model:main}", "--prompt", "What is 2+2?",
"--max-tokens", "8", "--temperature", "0"]
models:
main:
role: model # the S1 surface role of the arg it fills
ref: "hf://Qwen/Qwen2.5-Coder-1.5B-Instruct-GGUF/qwen2.5-coder-1.5b-instruct-q4_k_m.gguf"
sha256: "…" # pinned; the receipt records what was measured
inputs: [] # files the recipe needs, repo-relative
expect:
exit: 0
stdout_contains: ["4"] # or stdout_json: {"/pointer": value}
min_apr: "0.69.1"
hosts: ["lambda", "gx10"]
backends: ["cuda"]
see: "examples/cli/cli_run_greedy.rs" # optional: the Rust example that explains itWhy this shape: argv[0] == "apr" and {model:<slot>} placeholders make the argv checkable against the S1 surface JSON (apr-cli-surface/v1.1) WITHOUT running anything, which is what lets a removed verb or flag be a shape violation rather than a runtime surprise. Everything else in C1 follows: the cookbook_recipe extractor reads these fields, and cookbook-recipe-v1 constrains them.
Measured context for whoever ratifies this: 0 of apr-cookbook's 285 cli_* recipes runs the apr binary today (grep -rl 'Command::new("apr")' examples → 0); they re-implement each verb's logic offline against aprender-core 0.31.2. And S1's surface reports 63 model-taking leaf verbs, so "every model-taking verb has ≥1 recipe" starts at 63 recipes against 0.
The ONE falsifier that catches D1 being wrong
a recipe whose argv cites a flag the release binary does not have is a shape violation:
- take the release binary's own
apr surface(never a committed copy); - add a recipe whose argv carries one flag absent from that surface (for example
apr run --thinking-mode onwhile the surface has no such flag onrun); pv shapes-check --surface <json> --recipes <dir>must FAIL naming that recipe id and that flag.
It is the one that decides D1: if the argv cannot be checked against the surface without executing it, the schema is the wrong shape and the rest of C1 is built on sand. It also fails the two neighbouring ways: delete the flag-citation triples and a real drift passes; make the check depend on running the recipe and it can no longer fail before a host is booked.
What is NOT proposed here
D2 (receipt fields) is already pinned by f0's frozen host-receipt schema plus release-asset provenance. D3/D4 (the two extractors, the shape, the pc_extract planted control) are how it is implemented inside the existing ontology engine, not new policy. D5–D8 are in the design note.
Activity
noahgift commentedon Sep 21, 2026
Owner: aprender-fc, after #3773. Recipes are validated against the S1 surface JSON fc built; the
docsstep interface is coordinated with aprender-f0'sledgerstep (#3731).noahgift commentedon Sep 21, 2026
Design note — #3769 (aprender-fc). Decided recommendations for the cop to rule on, plus four interface points to agree with aprender-f0 BEFORE any code
What I measured first
aprtoday. apr-cookbook has 37 categories and 285cli_*examples.grep -rl 'Command::new("apr")' examplesfinds 0. Thecli_*recipes re-implement a verb's logic offline in pure Rust ("the contract surface is exercised offline", e.g.cli_compare_hf_tensor_filter.rs), built againstaprender-core0.31.2. So no existing recipe can be checked against the surface or receipted on a binary. An executable recipe is a new class, not a retrofit.apr surface(0.69.0 @ 1426293, schemaapr-cli-surface/v1.1): 137 visible own-tree leaf commands. 63 take arole: modelarg and 8 generate. "Every model-taking verb has ≥1 recipe" therefore means ≥63 executable recipes, from 0 today.contracts/ontology.yamlextractors[]), shapes incontracts/shapes.ttlwith ladder receipts joined to rungs (ladder-measured/ladder-green), and PMAT-3704 / ONT-4c3: pc_extract draws one planted defect per implemented extractor — parity-receipt, json and pv-contract gain their controls, and the set is tied to Σ #3706'spc_extract, which gives every implemented extractor one planted defect tied to Σ. The recipe gate should be one more extractor pair plus one shape in that engine. It is not a new mechanism.STEPS=(… install hosts close), andledger.pyruns insideclose. #3712 done_when 3 (child): the model-matrix gate runs at T-1 on BOTH hosts before any tag, receipts committed in the bump, re-read at T-4 by the same judge #3717 (f0) addsmodels, the T-1 ladder at the release commit on lambda + gx10, with receiptsapr-model-ladder-receipt/v1. #3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731 (f0) emitsevidence/dogfood/<v>/<host>.json, committed in the ledger PR. Committed ladder receipts already exist for 0.68.1 and 0.68.2, so the v0.68.2 first-green dry-run has real inputs.Decisions (proposed)
D1 — recipe = data,
apr-cookbook/recipes/apr/<verb>/<id>.yaml, schemacookbook-recipe/v1. Fields:id,title,argv: a list withargv[0] == "apr", and model slots written{model:<slot>};models: {<slot>: {role, ref, sha256}},inputs;expect: {exit, stdout_contains[] | stdout_json{pointer: value}};min_apr,hosts[],backends[], and an optionalsee:naming the Rust example that explains it.The 496 Rust examples stay what they are: library recipes,
cargo run --example, outside this shape.D2 — receipts are written by the train, never by hand. Path:
receipts/<v>/<host>/<id>.json, schemacookbook-recipe-receipt/v1. Fields:apr --versionline verbatim (version + sha);sha256_published,sha256_measured);D3 — two extractors, each Σ-registered with its
pc_extractplanted control (the PMAT-3704 / ONT-4c3: pc_extract draws one planted defect per implemented extractor — parity-receipt, json and pv-contract gain their controls, and the set is tied to Σ #3706 Σ-tie):cli_surfacereads anapr surfaceJSON intoont:Command,ont:Flag(with role and marker) andont:ModelVerb(a command with a model-role arg).cookbook_recipereads recipes and receipts intoont:Recipe, withrecipe:citesCommand/recipe:citesFlagas IRIs in the surface's namespace, plusrecipe:receipt.The surface gets its own extractor rather than the
jsonextractor, because S1.4 says the surface is generated from the binary under test and never committed. It is an INPUT PATH to the gate, not a document under a contract.D4 — shape
cookbook-recipe-v1incontracts/shapes.ttl:sh:classof a surface Command/Flag, so a removed verb or flag is a dangling IRI and a violation;targetClass ont:ModelVerb, inverserecipe:citesCommand,minCount 1, so an uncovered model-taking verb is a violation.Mutants per the done_when: an absent flag, no receipt, an uncovered verb → each RED.
Runs as
pv shapes-check --surface <json> --recipes <dir> --version <v>, the same shapes engine aspv lint's gate. The docs step runs it on the release binary's ownapr surface, and apr-cookbook CI runs it (self-hosted) against the latest release asset.D5 — the README section is rendered.
scripts/release/render_readme_release.pyfills<!-- release:begin/end -->in README.md from the tag's committed receipts:evidence/dogfood/models/<v>/*.json→ the verified model × verb × thinking × context matrix and its REPORT rows;evidence/dogfood/<v>/*.json(#3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731);readme_contract.rsgains a check that re-renders from the committed receipts of the version the section names and requires byte equality. A hand edit that disagrees is RED.D6 — autopilot step
docs, afterledger, beforeclose, so a red recipe keeps the milestone open. The step:apr surfacefrom that binary;choom -n 1000, writing receipts;release/<v>-recipes(receipts + banner) and the aprender README/receipts change. Both are unarmed.Any recipe red is a STOP, with a row filed against the recipe or the release, never a skip. Case table + mutants drive the real step with stubs: recipe fails → STOP; PR not opened → STOP; armed PR → RED.
D7 — first-green before it blocks:
docsin--dry-runagainst the published v0.68.2 renders both diffs into the ledger and opens no PR. Committed asevidence/release-docs/0.68.2/.D8 — apr-cookbook
recipe-table.ymland the new recipe gate move to a self-hosted label (no hosted runners). This is an apr-cookbook workflow edit, covered by this issue's done_when.Interface to agree with aprender-f0 (
ledger#3731,models#3717)… install hosts ledger docs close, i.e.ledger.pysplit out ofcloseinto its own step. Ifledgerstays insideclose,docsgoes betweenhostsandcloseand runsledger.pyitself first.fetch_release_asset <host> <dir>out ofhosts, sodocsruns recipes on exactly the assethostsverified, and recipe receipts carry #3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731's provenance fields verbatim.docscommits the README section and recipe receipts onto the ledger PR's branch, one PR per release (batching is the default). The alternative is its own unarmed PR.evidence/dogfood/<v>/recipes/<host>/<id>.json, beside #3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731's host receipts, with the apr-cookbook PR carrying the same files.Parts and order (each its own fragment and receipt)
pv shapes-check+ planted controls + the three mutants (aprender).readme_contractequality check.docsstep + case table. Stacked on #3712 done_when 3 (child): the model-matrix gate runs at T-1 on BOTH hosts before any tag, receipts committed in the bump, re-read at T-4 by the same judge #3717/#3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731, after I1–I4 are agreed.C1 can start as soon as D1–D4 are ruled; none of it touches autopilot.sh.
noahgift commentedon Sep 21, 2026
Design note, amendment 1: interface agreed with aprender-f0 (I1–I4)
f0 answered against #3731 as built on branch
PMAT-3731-host-receipts-fail-closed. That branch is not yet receipted, so the interface can still move during its quorum; f0 will flag any change.I1 — AGREED, amended. #3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731's order is
… cascade install hosts postpub ledger close, and ledger.py has already moved out ofcloseintoledger.docsgoes between them:… hosts postpub ledger docs close.postpub(the post-publish dogfood) runs afterhostsand fails closed, sodocsonly ever runs after a GO.I2 — AGREED, in post-release ALWAYS updates README.md and apr-cookbook with SHACL-validated recipes — rendered from the release's own green cells, never typed #3769's own PR, stacked on #3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731. #3544 (d)+(b): the train emits each host's receipt in the schema the gate reads, and a missing $AP/receipts is an infra fault, never "4 failing hosts" #3731's quorum is not asked to judge post-release ALWAYS updates README.md and apr-cookbook with SHACL-validated recipes — rendered from the release's own green cells, never typed #3769 code. The
fetch_release_assethelper is factored out of thehostsstep's inlinessh … "bash -s"heredoc (curl,sha256sum -c, tar,apr --version,apr devices --json). It keeps that step's rules:receipt_to);SSH_FAILED), never a verdict;apris ever run.I3 — AGREED:
docscommits onto f0's ledger branch.ledgercreatesledger/<V>in$AP/ledger-wt(from origin/main, or from an existingorigin/ledger/<V>) and opens or reuses ONE unarmed PR.docsthen:origin/ledger/<V>;A re-run of
ledgerbuilds ondocs's commits, since it bases onorigin/ledger/<V>.I4 — AGREED:
evidence/dogfood/<v>/recipes/<host>/<id>.json.check_multiplatform_dogfood.shreads only<dir>/<host>.json, so the subdirectory cannot be mistaken for a host.Provenance correction to D2 (f0). The FROZEN host receipt
evidence/dogfood/<v>/<host>.json(scripts/release/host_receipt.sh) describes the crates.io install on each host:provenance: "crates.io",asset: "aprender-<v>.crate",sha256_published/sha256_measuredof the crate. The CUDA release-asset check is a separate.txtreceipt. Recipes run on the release asset, so a recipe receipt carries:provenance: "release-asset";sha256_published(the release's.sha256) andsha256_measured(computed on the host);apr --versionline verbatim.It never reuses the crate's fields.
README matrix inputs (D5), confirmed frozen by f0:
generate{model, model_sha256, backend_line_verbatim, fallback_line_verbatim, used_gpu, tokens, wall_ms, output_sane, prompt}or null;benchorbench_attempt{status,rc,reason},parityorparity_attempt{…}, andunmeasured[](never empty);apr-model-ladder-receipt/v1(#3712 done_when 3 (child): the model-matrix gate runs at T-1 on BOTH hosts before any tag, receipts committed in the bump, re-read at T-4 by the same judge #3717).The rendered section cites each cell's receipt file.
Still to be ruled by the cop: D1–D8. C1 (extractors + shape +
pv shapes-check+ planted controls) touches no autopilot code. C3 (docsstep) waits for #3731 to land and stacks on it.noahgift commentedon Sep 22, 2026
C5 groundwork (apr-cookbook off hosted runners), measured 2026-09-22 against live
paiml/apr-cookbookmaincdb3315fbThe local clones on the fleet are stale (their README banner is from May), so this is from the GitHub API.
ubuntu-latest: ci.yml ×5, book.yml ×2, and one each in architecture-demos, coverage, examples-build, fine-tuning and recipe-table. Onlyrelease.ymlis self-hosted ([self-hosted, clean-room]).pr-gate.ymlandunified-gate-advisory.ymlhave noruns-onof their own. The done_when names "the recipe workflow". The operator's no-hosted-runners rule (2026-09-10) reads as all of them. Recommendation: move all 12 in C5, in one PR.Defaulthasvisibility=all, allows_public_repositories=true, and holds the online intel-clean-room ×14, yoga-build ×3 and gx10-pool build runners (labelsself-hosted, Linux, clean-room, …). The target label is aprender's own arch-neutral selector,[self-hosted, Linux, clean-room](P0-4: aprender builds on ANY of intel/gx10/yoga — a sharedbuildpool label, host-layout parametrized, yoga joins the x86 pool first, gx10 after an arm64 sovereign-ci image (operator 2026-09-10) #3100).all_external_contributors(every external contributor's workflow run needs maintainer approval), the same as aprender, which already runs PR jobs on these runners.arch-neutralmeans a job may land on gx10 (ARM64). Any job that installs x86-only tooling must pinX64, as aprender's 16[self-hosted, Linux, X64, clean-room]jobs do. I'll read each job's steps and pin per job, not by blanket. Per the rust-cache lesson,Swatinem/rust-cachemust not come along onto self-hosted runners: it prunes the shared$CARGO_HOME.aprender 0.67.0(matches the issue). Norecipes/directory exists yet (404).This is a workflow edit in apr-cookbook, and it is covered by this issue's done_when.
fix(#3769): the README's cookbook count was wrong by 5.4x and unguard…
noahgift commentedon Sep 23, 2026
triage 2026-09-23 (aprender-dd): labelled ont-0.70 (SHACL/ontology release-readiness work; operator: "the ontology spec MUST be finished in .7"). Its milestone stays 0.69.1 tonight: release-scoped issues are placed by the cop after publish, and anything not shipped in 0.69.1 moves to 0.70.0 then.
noahgift commentedon Sep 23, 2026
closed by triage (aprender-dd, #3988 FIXED row, cop OK): fixed by
a3a9b9965,ee080029c,ff4bf8e0f, all in v0.69.1. Evidence: the README release matrix is rendered from receipts. The post-publish run itself happens at T-5