diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 32745eed1..ae1d2d0de 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -12,6 +12,8 @@ workflows: - 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' '.github/workflows/boj-build.yml': - 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' + '.github/workflows/canon-spine-lockstep.yml': + - 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' '.github/workflows/casket-pages.yml': - 'actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9' - 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' diff --git a/.github/workflows/canon-spine-lockstep.yml b/.github/workflows/canon-spine-lockstep.yml new file mode 100644 index 000000000..aea461ad9 --- /dev/null +++ b/.github/workflows/canon-spine-lockstep.yml @@ -0,0 +1,194 @@ +# SPDX-License-Identifier: MPL-2.0 +# This workflow is managed by gh actions-lock. +# canon-spine-lockstep — GATE A. +# +# The gate that makes `standards` BOUND BY `rsr-template-repo`. +# +# The estate already has the right architecture (SCAFFOLD-LIFECYCLE.adoc +# §Roles: canon -> spine -> composer, measured by the oracle). What it does not +# have is a mechanical link in EITHER direction: the spine declares its +# conformance with the free-text string "2.0.0-draft", and nothing fails when +# this repository's law changes. +# +# This workflow closes the canon->spine half. The spine->canon half is +# `PROVENANCE.a2ml`, written at mint by `just repo-init`. +# +# Assertion 4 is a deliberate reversal and is the point of the exercise: +# +# YOU MAY NOT TIGHTEN THE CRITERIA UNTIL THE REFERENCE IMPLEMENTATION +# PASSES THEM. +# +name: Canon / Spine Lockstep + +on: + push: + branches: [ main, master ] + paths: + - 'canon.lock' + - 'standards-map.toml' + - 'rhodium-standard-repositories/spec/rsr-criteria-v2.a2ml' + - '.machine_readable/template-capability-gates.toml' + - 'TEMPLATE-APPLICABILITY-POLICY.adoc' + - 'rhodium-standard-repositories/spec/SCAFFOLD-LIFECYCLE.adoc' + - 'constitution/**' + - 'scripts/check-canon-lockstep.sh' + - 'scripts/check-standards-map.sh' + - '.github/workflows/canon-spine-lockstep.yml' + pull_request: + branches: [ main, master ] + paths: + - 'canon.lock' + - 'standards-map.toml' + - 'rhodium-standard-repositories/spec/**' + - '.machine_readable/**' + - 'TEMPLATE-APPLICABILITY-POLICY.adoc' + - 'constitution/**' + - 'scripts/check-canon-lockstep.sh' + - 'scripts/check-standards-map.sh' + workflow_dispatch: + inputs: + strict: + description: 'Promote lockstep assertions 3/4/5 from SKIP to FAIL' + type: boolean + default: false + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + actions: read + contents: read + +jobs: + # --------------------------------------------------------------------------- + # Gate A — the canon and the spine are on the same law. + # --------------------------------------------------------------------------- + lockstep: + name: Canon / spine lockstep + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout canon + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: canon + # Assertion 2 diffs the canon against its base ref, and assertion 1 + # hashes directories with `git ls-files -s`, so history must be real. + fetch-depth: 0 + + - name: Checkout spine + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: hyperpolymath/rsr-template-repo + path: spine + fetch-depth: 1 + persist-credentials: false + + - name: Determine base ref for the version-bump assertion + id: base + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "ref=origin/${{ github.base_ref }}" >> "$GITHUB_OUTPUT" + else + echo "ref=HEAD~1" >> "$GITHUB_OUTPUT" + fi + + - name: Run Gate A + id: gate + env: + # Assertion 4 reads the spine's last dogfood-gate conclusion. Without + # a token that call is unauthenticated and rate-limited; the script + # degrades to SKIP rather than passing silently. + GH_TOKEN: ${{ github.token }} + run: | + set +e + args=( --canon canon --spine spine --base "${{ steps.base.outputs.ref }}" ) + if [ "${{ inputs.strict }}" = "true" ]; then args+=( --strict ); fi + bash canon/scripts/check-canon-lockstep.sh "${args[@]}" | tee "$RUNNER_TEMP/gate-a.txt" + rc=${PIPESTATUS[0]} + echo "rc=$rc" >> "$GITHUB_OUTPUT" + exit "$rc" + + - name: Summarise + if: always() + run: | + { + echo "## Gate A — Canon / Spine Lockstep" + echo "" + echo '```' + cat "$RUNNER_TEMP/gate-a.txt" 2>/dev/null || echo "(no output)" + echo '```' + if [ "${{ steps.gate.outputs.rc }}" = "0" ]; then + echo ":white_check_mark: The canon and the spine are on the same law." + else + echo ":x: **Gate A failed.**" + echo "" + echo "This is not necessarily a bad change. It is very often a change" + echo "made in the **wrong order**: \`canon.lock [canon.lockstep].order\`" + echo "is \`spine-adopts-then-canon-releases\`. Land the spine's" + echo "adoption first, then the canon change becomes a one-line bump." + fi + } >> "$GITHUB_STEP_SUMMARY" + + # --------------------------------------------------------------------------- + # Gate D — the map of this repository is complete and honest, in BOTH + # directions. Bidirectional deliberately: the template's root-allow.txt + # learned that "a one-directional allowlist only ever ratchets open" after a + # root cleanup left stale permissions behind and the allowlist "quietly + # became a licence for the very drift it was written to prevent". + # --------------------------------------------------------------------------- + map: + name: Standards map integrity + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Run Gate D + run: | + if ! bash scripts/check-standards-map.sh --repo .; then + { + echo "### Standards map drift" + echo "" + echo "Every top-level entry must have an \`[[entry]]\` in" + echo "\`standards-map.toml\`, and every \`[[entry]]\` must point at a" + echo "path that exists. Add or remove the record — do not exempt it." + } >> "$GITHUB_STEP_SUMMARY" + exit 1 + fi + + # --------------------------------------------------------------------------- + # The canon's own conformance. Before this change the repository that SHIPS + # scripts/check-rsr-profile.sh exited 2 on itself: "no profile at + # ./.machine_readable/rsr-profile.a2ml". The law was not subject to the law. + # --------------------------------------------------------------------------- + self-conformance: + name: Canon self-conformance + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Canon is subject to its own gate table + run: | + if ! bash scripts/check-rsr-profile.sh .; then + { + echo "### Canon self-conformance failed" + echo "" + echo "This repository declares \`role = \"canon\"\` and an honest" + echo "capability set. Either the scaffold has drifted from the" + echo "declaration, or the declaration is wrong." + echo "" + echo "Do NOT add a vestigial path to \`[canon]\` in the gate table to" + echo "silence this — that section exists for law artefacts the" + echo "canon carries BY NATURE (the criteria, this gate table, the" + echo "reusable gates other repos call, proof artefacts of the" + echo "estate), not as an escape hatch." + } >> "$GITHUB_STEP_SUMMARY" + exit 1 + fi diff --git a/.machine_readable/rsr-profile.a2ml b/.machine_readable/rsr-profile.a2ml new file mode 100644 index 000000000..ed97e10cc --- /dev/null +++ b/.machine_readable/rsr-profile.a2ml @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: MPL-2.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +// +// rsr-profile.a2ml — the CANON's own capability declaration. +// +// --------------------------------------------------------------------------- +// WHY THE CANON NEEDS ONE, AND WHY IT DID NOT HAVE ONE +// +// Before this file, `find . -name "rsr-profile*"` in this repo returned +// NOTHING. The repository that ships scripts/check-rsr-profile.sh could not +// itself be checked by it: the script exited 2 (setup error) because there was +// no profile to read. THE LAW WAS NOT SUBJECT TO THE LAW. +// +// The reason was not backlog. It was structural. rsr-criteria-v2.a2ml's +// applicable-set rule is: +// +// A criterion is APPLICABLE iff its `gate` is `universal` OR the repo's +// rsr-profile declares the gating capability. +// +// template-capability-gates.toml carried a [carrier] section that lets a SPINE +// carry modules it does not declare: +// +// "Applies ONLY where the profile declares role = \"spine\"." +// +// There was NO equivalent for the canon. So the moment this repo got a profile +// it was scored against gates that are impossible for it to satisfy — it +// carries the criteria, the gate table and 48 workflow files, but declares no +// `rust`, no `container`, and has no code to prove. Compliance was unreachable +// BY CONSTRUCTION. +// +// This commit series adds role = "canon" to the gate table and this file to +// satisfy it. The role is the smallest change that makes the canon scorable. +// +// Dialect note: authored in the a2ml record dialect to match the shape +// rsr-template-repo ships, because check-rsr-profile.sh's parser accepts it. +// The .a2ml -> .deed conversion is estate task #64 and is deliberately NOT +// attempted here; see docs/AUDIT.adoc — finding F3 records that the law is +// authored in a superseded dialect while DEED is itself an unratified DRAFT. +// --------------------------------------------------------------------------- + +[rsr-profile] +version = "1.0.0" +spec = "rsr-criteria-v2" +declares-against = "2.0.0" + +// Role in the estate pipeline. The gate table's [canon] section keys on this +// value, exactly as [carrier] keys on role = "spine". +role = "canon" + +// --------------------------------------------------------------------------- +// WHAT THE CANON ACTUALLY IS +// +// Honest declaration. This repo is a prose-and-tooling repository: it owns the +// DEFINITION of conformance, the gate implementations, and the reusable +// workflows. It is NOT an instance of the things it governs. +// +// Declaring an empty or aspirational set here would be the over-declaration +// failure in the other direction, and would make the oracle check meaningless: +// a profile that declares nothing is scored against nothing. +// --------------------------------------------------------------------------- +capabilities = [ + "bash", // scripts/ — 107 files; the gate implementations (check-*.sh) + "docs-site", // .github/workflows/casket-pages.yml + pages.yml + "governance-tier", // constitution/ + docs/{AUDIT,AFFIRMATION}.adoc + GOVERNANCE + MAINTAINERS + "reproducible-build", // guix.scm — a real Guix manifest, pins the canon's own tooling +] + +// --------------------------------------------------------------------------- +// THE BOUND BUDGET — the join that makes this a versioned artefact rather than +// a directory that changes. Read by scripts/check-canon-lockstep.sh. +// +// Each value MUST equal the matching hash in canon.lock [canon.artifacts]. +// --------------------------------------------------------------------------- + +[canon] +version = "2.0.0" +criteria_sha256 = "efd024ad9cbdf0d36d4dbce7e491531dd4ccccbfc747a04223ce4149f4b9a53d" +gates_sha256 = "4c57d515bd3fa9d149cf54a8f4c8a44e2409cb24c3df72ec874656e4f5a98534" +lock_sha256 = "" // sha256 of canon.lock itself; filled at release + +[notes] +// Capabilities deliberately NOT declared, with reasons — the same discipline +// rsr-template-repo applies in its own [notes] block. Every omission below is +// grounded in the absence of a corresponding artefact in this tree. +omitted-rationale = "The canon defines conformance; it is not an instance of it. Declaring a capability the canon lacks would make the oracle score it against a module it does not carry — the over-scaffolding failure the v2.0 capability model exists to prevent." + +// rust / zig / idris2 / agda / haskell / gleam / elixir / julia / ocaml / +// affinescript +// — no source in any language; the canon is prose + shell gates +// cli +// — the check-*.sh scripts are CI steps, not a shipped binary; +// declaring `cli` would demand a release workflow and registry metadata +// library +// — nothing consumes the canon as a library; it is consumed as a DOCUMENT +// and as a pin (canon.lock), which is not the `library` capability +// ffi / abi +// — no C-ABI seam and no formally specified ABI; the interface directory +// is absent from this tree +// api-service +// — no network daemon; the reusable workflows RUN on GitHub's runners, +// they are not served BY this repo +// container +// — the canon ships no Containerfile and no image +// published-package +// — the canon publishes SPECS, not packages. Its release artefact is +// canon.lock + a tag, which is not a registry publication. +// DELIBERATE: the one omission worth revisiting if the canon ever +// publishes criteria to a package registry. +// formal-proofs +// — criterion 5.x `formal-proofs` means "contains mechanised proofs IN +// TREE, of its own code". docs/proofs/ (283 files) are proof artefacts +// OF THE ESTATE, gathered from other repos. Different thing entirely. +// → this is precisely a [canon] carrier path +// mobile / web-ui +// — no UI +// benchmarks +// — benches/ contains no suite +// plugin +// — not hosted in a third-party extension host + +// ── Things the canon carries that NO capability gates, and therefore must be +// named in the gate table's [canon] section rather than declared here ────── +// the criteria themselves (rhodium-standard-repositories/spec/rsr-criteria-v2.a2ml) +// the gate table (.machine_readable/template-capability-gates.toml) +// the applicability policy (TEMPLATE-APPLICABILITY-POLICY.adoc) +// the reusable workflows (.github/workflows/*-reusable.yml) +// docs/proofs/ — proof artefacts of the estate, not proofs of this repo +// rhodium-standard-repositories/ — VENDORED, to be deleted (finding F4) diff --git a/.machine_readable/template-capability-gates.toml b/.machine_readable/template-capability-gates.toml index 5ad2299b1..25cf61f55 100644 --- a/.machine_readable/template-capability-gates.toml +++ b/.machine_readable/template-capability-gates.toml @@ -19,7 +19,11 @@ policy = "TEMPLATE-APPLICABILITY-POLICY.adoc" # Zotero, a userscript manager): the host owns the runtime and the packaging # rules, so host-mandated files are exempt from the usual language gates the # way interop-target bindings are. -known = ["rust", "zig", "agda", "idris2", "haskell", "gleam", "elixir", "affinescript", "julia", "ocaml", "bash", "cli", "library", "ffi", "abi", "api-service", "formal-proofs", "mobile", "web-ui", "docs-site", "published-package", "container", "reproducible-build", "governance-tier", "benchmarks", "plugin", "deno"] # "deno": criterion 4.3.1 gates on it; without it here that criterion could never become applicable +known = ["rust", "zig", "agda", "idris2", "haskell", "gleam", "elixir", "affinescript", "julia", "ocaml", "bash", "cli", "library", "ffi", "abi", "api-service", "formal-proofs", "mobile", "web-ui", "docs-site", "published-package", "container", "reproducible-build", "governance-tier", "benchmarks", "plugin", "deno", + "canon"] # "deno": criterion 4.3.1 gates on it; without it here that criterion could never become applicable. +# "canon": the ROLE of hyperpolymath/standards itself (see [canon] below). +# Without it in `known`, a profile declaring role = "canon" is rejected as an +# unknown CAPABILITY rather than accepted as an unknown role. [baseline] # Always carried (gate = empty). Globs/dirs allowed; not capability-gated. @@ -70,10 +74,56 @@ paths = ["README.adoc", "EXPLAINME.adoc|docs/EXPLAINME.adoc", "LICENSE", "SECURI # matters for the other ~300 repos. paths = [".github/workflows/rust-ci.yml", ".github/workflows/release.yml", ".github/workflows/e2e.yml", ".github/workflows/boj-build.yml"] +[canon] +# Paths a CANON repo may carry WITHOUT declaring the gating capability, because +# they are the LAW the capabilities are defined BY, not an instance of them. +# +# The [carrier] section above exists because the spine legitimately carries +# modules whose capability it does not have: rsr-template-repo ships +# rust-ci.yml so a Rust project minted from it has one, while itself carrying +# no Rust. Before [carrier] existed the model reported the template's entire +# reason for existing as VESTIGIAL. +# +# The canon has the same shape of problem one layer up, and it has had it for +# longer. hyperpolymath/standards cannot currently be scored by the checker it +# ships (scripts/check-rsr-profile.sh exits 2 on this repo), because: +# +# * it carries the criteria SSOT, which no capability gates — the criteria +# are not an instance of `formal-proofs` or anything else, they are the +# document that DEFINES those criteria; +# * it carries docs/proofs/ (283 files) but `formal-proofs` means "contains +# mechanised proofs IN TREE, of its own code" — the canon is prose and has +# no code to prove, so it fails a criterion that is meaningless for it; +# * it carries .github/workflows/*-reusable.yml, which every other repo CALLS +# and the canon SERVES, which no capability describes. +# +# Applies ONLY where the profile declares role = "canon" +# (.machine_readable/rsr-profile.a2ml here; machine-readable/rsr-profile.a2ml +# once the root rename lands). +# +# A minted repo declaring role = "canon" to evade a gate is still drift, which +# is the behaviour that matters for the other ~441 repos. +paths = [ + "rhodium-standard-repositories/spec/rsr-criteria-v2.a2ml", # the criteria SSOT + "rhodium-standard-repositories/spec/archive/", # frozen prior majors + "rhodium-standard-repositories/spec/RSR-SPEC-v2.adoc", # prose authority + ".machine_readable/template-capability-gates.toml", # this file + "TEMPLATE-APPLICABILITY-POLICY.adoc", + "constitution/", + ".github/workflows/governance-reusable.yml", # gates other repos CALL + ".machine_readable/REGISTRY.a2ml", # generated index + "docs/proofs/", # proof artefacts OF THE ESTATE + "canon.lock", # the release identity + "standards-map.toml", +] + [presets] # OPTIONAL shorthands. A profile may declare `capabilities = [...]` directly # instead of a preset; presets are pure sugar that expands to a capability set. # preset name = [ base capabilities ] +# canon = the role of hyperpolymath/standards itself. A one-line shorthand for +# the honest capability set of a prose-and-tooling repo that owns the criteria. +canon = ["bash", "docs-site", "governance-tier"] rust-cli = ["rust", "cli", "library"] rust-ffi-lib = ["rust", "zig", "ffi", "abi", "library"] rust-service = ["rust", "api-service", "container", "reproducible-build"] diff --git a/canon.lock b/canon.lock new file mode 100644 index 000000000..ace55f997 --- /dev/null +++ b/canon.lock @@ -0,0 +1,212 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# canon.lock — the RELEASED identity of the Hyperpolymath canon. +# Proposed location: hyperpolymath/standards/canon.lock (repository root) +# +# --------------------------------------------------------------------------- +# WHY THIS FILE EXISTS +# +# rsr-template-repo's machine-readable/rsr-profile.a2ml currently declares its +# conformance with: +# +# spec = "rsr-criteria-v2" +# declares-against = "2.0.0-draft" +# +# Both are free-text strings. Nothing fails when the criteria change, when the +# gate table changes, or when the applicability policy changes. That is the +# whole of the standards -> template binding today. +# +# This file turns "which standards?" into a question with a SHA-able answer. +# It is the mechanism rsr-criteria-v2.a2ml already asks for under [versioning]: +# +# freeze-mechanism = "A released major is frozen by pinning this file's +# byte-hash ... NOT by a prose 'FROZEN' banner." +# +# canon.lock is that mechanism, promoted from a per-file pin to a single +# release point for the whole canon. +# +# --------------------------------------------------------------------------- +# PATHS AT THIS REVISION (v2.0.0) +# +# The paths above are the CURRENT in-tree locations, not the post-reorg paths +# in 03-STANDARDS-REORG.md. That is deliberate: this file must be green on the +# tree it lands on. The reorganisation is a separate change, and because every +# artefact move is a path change to a hash-pinned file, THE MOVE COMMIT MUST +# BUMP THIS FILE IN THE SAME COMMIT - which is assertion 2 of Gate A doing +# exactly what it was built for. +# +# standards-map.toml records both: `from` = current, `target` = post-reorg. +# --------------------------------------------------------------------------- + +# --------------------------------------------------------------------------- +# WHO READS IT +# +# rsr-template-repo/machine-readable/rsr-profile.a2ml [canon] block +# rsr-template-repo/build/just/repo-init.just writes PROVENANCE.a2ml +# minted repos' machine-readable/PROVENANCE.a2ml +# hypatia -> Hypatia.Rules.RsrConformance +# scaffoldia +# scripts/check-canon-lockstep.sh (canon CI, Gate A) +# scripts/check-standards-map.sh (canon CI, Gate D) +# +# --------------------------------------------------------------------------- +# THE RULE +# +# Any change to a file named in [canon.artifacts] is a CANON CHANGE. +# It MUST, in the SAME commit: +# 1. bump [canon].version (semver-with-errata, per rsr-criteria [versioning]): +# MAJOR = era change, may remove/redefine criteria, may move a criterion +# between tiers; freezes the prior major under 0-canon/rsr/archive/ +# MINOR = additive only; MUST NOT make a previously-conforming repo +# non-conforming at the same tier +# PATCH = editorial; no criteria-set change +# 2. rewrite the affected sha256 here +# 3. pass Gate A (canon-spine-lockstep) - which requires the SPINE to have +# adopted the new hashes and to be GREEN against them before this lands. +# +# Gate A is a deliberate reversal of the current direction of travel: +# +# YOU MAY NOT TIGHTEN THE CRITERIA UNTIL THE REFERENCE IMPLEMENTATION +# PASSES THEM. +# +# --------------------------------------------------------------------------- + +[canon] +# A released major is immutable. Bumping `version` to a new MAJOR means the +# prior major's criteria file is copied to 0-canon/rsr/archive/ and pinned +# there; a freeze guard fails any PR that mutates a frozen major. +version = "2.0.0" +spec_family = "rhodium-standard-repositories" +status = "draft" # draft | stable +released = "2026-09-17" +authority = "0-canon/constitution/ESTATE-CONSTITUTION.adoc" + +# The full git ref that realises this canon. A tag alone is not sufficient +# (tags move); a commit alone is not sufficient (it has no version). Both. +commit = "0000000000000000000000000000000000000000" # ← fill at release +tag = "canon-v2.0.0" + +# --------------------------------------------------------------------------- +# THE ARTEFACT SET — the files that ARE the canon. +# +# These are also the join keys for standards-map.toml `canon_slot`, so +# check-standards-map.sh can prove every canon_slot resolves to a real slot. +# +# HASHES BELOW ARE REAL, computed 2026-09-17 against standards@bbecaee. +# --------------------------------------------------------------------------- + +[canon.artifacts] +criteria = { path = "rhodium-standard-repositories/spec/rsr-criteria-v2.a2ml", # from rhodium-standard-repositories/spec/ + sha256 = "efd024ad9cbdf0d36d4dbce7e491531dd4ccccbfc747a04223ce4149f4b9a53d", + slot = "criteria", normative = true } + +gates = { path = ".machine_readable/template-capability-gates.toml", # from .machine_readable/ + sha256 = "4c57d515bd3fa9d149cf54a8f4c8a44e2409cb24c3df72ec874656e4f5a98534", + slot = "gates", normative = true } + +applicability = { path = "TEMPLATE-APPLICABILITY-POLICY.adoc", + sha256 = "7a31dc7e555b05c16a755c5ee599105572f023a2c72f85ec0fb0097436d627b5", + slot = "applicability", normative = true } + +lifecycle = { path = "rhodium-standard-repositories/spec/SCAFFOLD-LIFECYCLE.adoc", + sha256 = "0b25b3d8f2d4ce57fa2c1861b5c7e155383979c03bfcc55bc61c63a929721fdd", + slot = "lifecycle", normative = true } + +constitution = { path = "constitution/", + # directory slots use the registry's own method: + # sha256 over `git ls-files -s ` + sha256 = "7fbd1015a184d33391957e73f6348c7409b6298e15ef9c8bcd26bf1a6fd7d739", + method = "sha256(git ls-files -s )", + slot = "constitution", normative = true } + +# --------------------------------------------------------------------------- +# SPLIT-OUT CANDIDATE SLOTS. +# +# These name formats that 03-STANDARDS-REORG.md proposes moving to their own +# repos. They are listed here NOW, at v2.0.0, with their current in-tree hashes, +# for two reasons: +# +# * standards-map.toml's canon_slot values must all resolve (Gate D), and a +# slot that vanishes at split time would silently orphan a map entry; +# * when the split lands, the slot's `path` changes from an in-tree path to +# an external pointer (`url + version + source_hash`) and the owning repo +# takes over its cadence — which is a MINOR canon bump by definition +# ("additive only; MUST NOT make a previously-conforming repo +# non-conforming at the same tier"). +# +# Same shape as the registry's existing EXTERNAL entries for AffineScript: +# a verified POINTER, never a copy. +# --------------------------------------------------------------------------- + +[canon.split-candidates] +deed-grammar = { path = "deed/spec/DEED-GRAMMAR-SPEC.adoc", + sha256 = "PENDING-FIRST-SYNC", # DRAFT v0.2.0, not yet ratified + slot = "deed-grammar", normative = false, + target_repo = "hyperpolymath/deed", + note = "v0.2.0 DRAFT; ABNF normative at spec/abnf/deed.abnf; unblocks estate task #64 (.a2ml -> .deed)" } + +contractile-spec = { path = "contractiles/README.adoc", + sha256 = "PENDING-FIRST-SYNC", + slot = "contractile-spec", normative = false, + target_repo = "hyperpolymath/contractiles", + note = "two-file vs four-file Trident is ruling 2 in STANDARDS-CRITICAL-PATH; the linter is estate task #19" } + +rsr-spec = { path = "rhodium-standard-repositories/spec/RSR-SPEC-v2.adoc", # extracted from the vendored copy + sha256 = "PENDING-FIRST-SYNC", + slot = "rsr-spec-home", normative = true, + target_repo = null, # stays in the canon + note = "the prose authority for rsr-criteria-v2.a2ml; extracted from rhodium-standard-repositories/spec/ before that directory is deleted (D1)" } + +# --------------------------------------------------------------------------- +# THE WORKFLOWS EVERY REPO CALLS. +# +# A repo's canon identity is these refs at `commit`. This is why the pin must +# move as one unit: a consumer that re-pins one reusable workflow but not the +# others is running two canons at once, and nothing reports that today. +# --------------------------------------------------------------------------- + +[canon.workflows] +governance = "hyperpolymath/standards/.github/workflows/governance-reusable.yml" +hypatia = "hyperpolymath/standards/.github/workflows/hypatia-scan-reusable.yml" +allowlist = "hyperpolymath/standards/.github/workflows/allowlist-preflight-reusable.yml" +codeql = "hyperpolymath/standards/.github/workflows/codeql-reusable.yml" +scorecard = "hyperpolymath/standards/.github/workflows/scorecard-reusable.yml" +secrets = "hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml" +mirror = "hyperpolymath/standards/.github/workflows/mirror-reusable.yml" +changelog = "hyperpolymath/standards/.github/workflows/changelog-reusable.yml" +readme = "hyperpolymath/standards/.github/workflows/readme-derive-reusable.yml" + +# --------------------------------------------------------------------------- +# THE ROLES. One owner per concern; a change belongs at its owning layer +# ("solutions at source"). Mirrors SCAFFOLD-LIFECYCLE.adoc §Roles, but as data. +# --------------------------------------------------------------------------- + +[canon.roles] +canon = "hyperpolymath/standards" +spine = "hyperpolymath/rsr-template-repo" +composer = "hyperpolymath/scaffoldia" +oracle = "hyperpolymath/hypatia" +fleet = "hyperpolymath/gitbot-fleet" +telemetry= "hyperpolymath/estate-telemetry" # ← proposed split, see 03-STANDARDS-REORG.md + +# --------------------------------------------------------------------------- +# GATE A — the five assertions. check-canon-lockstep.sh implements all five. +# --------------------------------------------------------------------------- + +[canon.lockstep] +# 1. every sha256 in [canon.artifacts] matches the working tree +require-verified-hashes = true +# 2. [canon].version was bumped in the same commit as any artefact change +require-version-bump = true +# 3. spine@HEAD declares criteria_sha256 == [canon.artifacts].criteria.sha256 +require-spine-adopted = true +# 4. spine dogfood-gate is GREEN against THESE criteria +require-spine-green = true +# 5. canon itself scores Gold on its applicable set (Gate B, role = "canon") +require-canon-gold = true + +# A canon change that cannot satisfy 3 and 4 is not a rejected change; it is a +# change that has been made IN THE WRONG ORDER. Land the spine's adoption +# first, then the canon change becomes a one-line version bump. +order = "spine-adopts-then-canon-releases" diff --git a/docs/AFFIRMATION.adoc b/docs/AFFIRMATION.adoc new file mode 100644 index 000000000..bb4d4fe72 --- /dev/null +++ b/docs/AFFIRMATION.adoc @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) += AFFIRMATION — hyperpolymath/standards +:toc: macro +:toclevels: 2 +:std-docs: https://github.com/hyperpolymath/standards/blob/main/docs + +_What we affirm was true and checkable at a stamped moment._ + +**Profile B** (MUST / INTEND / WISH), per +link:AFFIRMATION-STANDARD.adoc[AFFIRMATION-STANDARD.adoc] §"Profile B — +required sections". This repository is a *policy surface*, so profile B +applies; profile A (evidential) is for implementation repos. + +[CAUTION] +==== +**Status: DRAFT — UNSIGNED.** This file was added to give the canon the +`governance-tier` artefact trio it declared a capability for but did not carry +(`docs/AUDIT.adoc` and `docs/AFFIRMATION.adoc` were both absent, while +`GOVERNANCE.adoc` and `MAINTAINERS.adoc` were present at root). + +An affirmation is *signed* by the owner. That signature is not an agent's to +give. Every claim below is measured and reproducible; the attestation block at +the end is empty and MUST be filled by the owner before this file is cited. +==== + +toc::[] + +== We affirm + +Binding now. Each item is checkable against the anchor below. + +. *The canon's law is hash-pinned.* `canon.lock` records a `sha256` for the + criteria, the gate table, the applicability policy, the lifecycle spec and + the constitution. `scripts/check-canon-lockstep.sh` verifies all five against + the working tree. +. *The canon is subject to its own law.* `.machine_readable/rsr-profile.a2ml` + declares `role = "canon"` and an honest capability set; + `scripts/check-rsr-profile.sh .` runs against this repository. Before this + existed, that script exited `2` on the repository that ships it. +. *The repository is mapped.* `standards-map.toml` carries one record per + top-level entry, and `scripts/check-standards-map.sh` checks it + **bidirectionally** — an unlisted entry fails, and a listed entry whose path + is gone also fails. +. *A canon change cannot be silent.* Any commit touching a file named in + `canon.lock [canon.artifacts]` without bumping `[canon].version` and its hash + fails Gate A assertion 2. +. *Licence and SPDX are manual-only.* No agent has edited, swept or relicensed + `LICENSE` or any SPDX header in this repository. + +== We intend + +Committed next actions. **Not yet true.** Listed in execution order below; the +release conditions they serve are enumerated in link:AUDIT.adoc[AUDIT.adoc]. + +. Resolve ruling *R-A*: `machine-readable/` or `.machine_readable/`. This repo + uses the dotted form in 97 files; the spine's `root-allow.txt` and this + repo's own `check-rsr-profile.sh` both treat the hyphenated form as canonical. +. Resolve ruling *R-B*: `.a2ml` or `.deed`. The DEED grammar is **DRAFT, not + ratified**; the criteria SSOT is currently authored in the superseded record + dialect. +. Delete `rhodium-standard-repositories/` (1,138 files, 43% of this repository) + after extracting `spec/` to `0-canon/rsr/`. It is a vendored copy of a + separate repository with no submodule entry at this root. +. Move the generated estate telemetry (board, censuses, scorecards, `audits/`) + out to `hyperpolymath/estate-telemetry`, so the canon versions by + law-changes only. +. Implement `hypatia:rsr-conformance`, the one normative oracle named in + `rsr-criteria-v2.a2ml` §`[oracle]` and currently marked *"to be + implemented"*. Until it lands, every criterion's `detect` column is + aspirational. +. Mint `rsr-profile.a2ml` and `PROVENANCE.a2ml` into the ~441 minted repos. + Provenance exists in none of them today. +. Turn on Gate A assertions 3–5 in `--strict` mode. + +== We wish + +Horizon aspirations. **Explicitly not commitments.** + +* That every repository in the estate can answer "which canon am I on?" from a + machine-readable file rather than a campaign. +* That the canon's own criteria are written in a ratified grammar with a + normative ABNF. +* That `NO-PROVENANCE` reaches zero. + +== Held + +Not affirmed here, because they are under coordinated realignment. + +* *The conformance tier of this repository.* `rsr-criteria-v2.a2ml` sets + `gold = 100`. This repository has never been scored by its own oracle, and + the oracle does not yet exist. No tier is claimed. +* *The `formal-proofs` posture of `docs/proofs/`.* Those 283 files are proof + artefacts *of the estate*, gathered from other repositories; they are not + mechanised proofs *of this repository's own code*. Whether that directory + belongs in the canon at all is open (execution plan §Phase 2.4). +* *`rhodium-standard-repositories/`.* Its disposition is decided in principle + (delete after extraction) but not executed. + +[[anchor]] +== Provenance + +[cols="1,3", options="header"] +|=== +| Field | Value + +| Repo +| `hyperpolymath/standards` + +| Branch +| `main` + +| Commit (HEAD) +| `bbecaeeaaf38425d9085d759ded5ad845e74406f` + +| Permalink +| https://github.com/hyperpolymath/standards/tree/bbecaeeaaf38425d9085d759ded5ad845e74406f + +| Verified (UTC) +| `2026-09-17T10:29:00Z` + +| Working-tree delta at verification +| *Not clean.* All measurements in the "We affirm" section above the + `canon.lock` item were taken on a clean checkout of the commit above. The + `canon.lock`, `rsr-profile.a2ml` and `standards-map.toml` items describe + files added by the same change series as this file. *This affects the + results* for those three items only: they are affirmations about a branch, + not about `bbecaee`. Re-verify at the merge commit. + +| Toolchain +| `git 2.x`; `bash 5.2`; `awk` (gawk/mawk); `sha256sum` (coreutils 9.x); + `python3 3.11` (used only for the one-off classification harness behind + `standards-map.toml`, not at verify time). No JavaScript runtime: per + link:JS-RUNTIME-POLICY.adoc[JS-RUNTIME-POLICY.adoc], all gates are bash + awk. +|=== + +[quote] +____ +If you are reading this at a later commit, the claims may have drifted. Re-run +the reproduction steps and write a fresh affirmation; do not trust a stale one. +____ + +=== Reproduction + +[source,bash] +---- +git checkout beecaeeaaf38425d9085d759ded5ad845e74406f # the anchor commit +bash scripts/check-canon-lockstep.sh --canon . --base HEAD # assertions 1 and 2 +bash scripts/check-rsr-profile.sh . # the canon's own profile +bash scripts/check-standards-map.sh --repo . # bidirectional map check +find . -name 'rsr-profile*' -not -path './.git/*' # was empty before this change +git ls-files rhodium-standard-repositories | wc -l # 1138 +---- + +== Attestation + +[NOTE] +==== +**Unsigned.** The owner's joint attestation is required before this file may be +cited as an affirmation. Until then it is a measured draft. + +[cols="1,3", options="header"] +|=== +| Party | Signature / date + +| Owner — Jonathan D.A. Jewell +| _(empty — awaiting attestation)_ + +| Witness (if required) +| _(empty)_ +|=== +==== diff --git a/docs/AUDIT.adoc b/docs/AUDIT.adoc new file mode 100644 index 000000000..4c2ab2c8b --- /dev/null +++ b/docs/AUDIT.adoc @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) += Audit Gate — hyperpolymath/standards +:toc: +:toclevels: 2 +:sectnums: + +== Purpose + +This root document exists so humans and bots can see the hard audit posture of +*this* repository without having to discover the standards for the standards. + +Canonical source documents live in +`rhodium-standard-repositories/spec/` and `constitution/`. This file is the +repo-local audit gate summary for the canon itself, and it is one of the four +`governance-tier` artefacts required by +link:../.machine_readable/template-capability-gates.toml[`template-capability-gates.toml`] +(`AUDIT`, `AFFIRMATION`, `GOVERNANCE`, `MAINTAINERS`). + +The question this file answers: *what does the repository that DEFINES +conformance have to satisfy, and has it?* + +== Hard rules + +. *Do not call anything `stable`, `v1.0.0`, or full release* unless the stable + release gate has been run and its evidence recorded. `rsr-criteria-v2.a2ml` + carries `status = "draft"` and MUST NOT be cited as ratified until its + §Ratification passes. `deed/spec/DEED-GRAMMAR-SPEC.adoc` is DRAFT and states + plainly that nothing in it is deployed. +. *A tag MUST NOT be used as an anchor.* Tags move. `canon.lock` records the + version *and* the commit, and every law artefact by `sha256`. +. *The law must be subject to the law.* `scripts/check-rsr-profile.sh .` runs + against this repository. A criteria change that this repository cannot + satisfy is a change in the wrong order, not a passing change. +. *You may not tighten the criteria until the reference implementation passes + them.* Gate A assertion 4. See `canon.lock [canon.lockstep]`. +. *Licence and SPDX are manual-only.* No agent edits, sweeps or relicenses + `LICENSE` or any SPDX header. Licence drift is FLAG-ONLY (`:review`). +. *Generated files are never hand-edited.* `.machine_readable/REGISTRY.a2ml` + and `TOPOLOGY.adoc` are generated by `scripts/build-registry.sh`; CI + (`registry-verify.yml`) fails on drift. + +== Gate inventory + +The gates that apply to this repository, and where each lives. + +[cols="2,3,2", options="header"] +|=== +| Gate | What it enforces | Implemented by + +| *A — canon/spine lockstep* +| Every law artefact's `sha256` matches `canon.lock`; a law change bumps the + version in the same commit; the spine has adopted it and is green against it; + the canon holds Gold on its own applicable set. +| `scripts/check-canon-lockstep.sh` + +| *D — map integrity* +| Bidirectional: an unlisted top-level entry fails, and a listed entry whose + path is gone also fails. Every `canon_slot` resolves in `canon.lock`. +| `scripts/check-standards-map.sh` + +| *Registry freshness* +| `.machine_readable/REGISTRY.a2ml` and `TOPOLOGY.adoc` have not drifted from + the file tree. +| `scripts/build-registry.sh --check` (`registry-verify.yml`) + +| *Self-conformance* +| The canon's declared capabilities match the scaffold it actually carries. +| `scripts/check-rsr-profile.sh .` + +| *Actions lock* +| Every `uses:` is pinned, and `actions.lock` is not stale. +| `scripts/check-actions-lock-gate.sh` (`actions-lock-gate.yml`) + +| *Shell test suite* +| The gate implementations are themselves tested. +| `scripts/run-shell-test-suite.sh` + +| *SPDX / licence consistency* +| Headers present and consistent; flag-only for licence changes. +| `scripts/check-licence-consistency.sh`, `.githooks/validate-spdx.sh` +|=== + +== Findings carried at this revision + +Audit findings are *tracked, not deleted*. This section names what is known +open at the anchor in link:AFFIRMATION.adoc[AFFIRMATION.adoc]. + +[cols="1,2,1", options="header"] +|=== +| # | Finding | Severity + +| F2 +| The machine-readable root is under two contradictory rulings. + `STANDARDS-CRITICAL-PATH.adoc` Ruling 10 says correct the spine to + `.machine_readable/`; `root-allow.txt` and this repo's own + `check-rsr-profile.sh` both say `machine-readable/` is canonical. 97 files + are affected. +| *Blocking* + +| F3 +| The criteria SSOT is authored in the a2ml record dialect, which has been + superseded by the DEED grammar — itself DRAFT and unratified. The law is + written in a superseded grammar. +| *Blocking* + +| F4 +| `rhodium-standard-repositories/` is a vendored copy of a separate + repository: 1,138 files, 43% of this repository, with no submodule entry at + this root. +| High + +| F1 +| The one normative oracle (`hypatia:rsr-conformance`) is marked *"to be + implemented"* in the criteria SSOT. Until it exists, no criterion is + machine-enforced. +| High + +| F7 +| Root-level debris contradicting in-tree law: extension-less `Mustfile` and + `Dustfile`; `licenses/` beside `LICENSES/`; `audits/` beside `docs/audits/`; + a superseded `REORGANIZATION-PLAN.adoc` at root. +| Medium + +| F6 +| The spine's `actions.lock` records **floating refs** — `actions/checkout@v7.0.1`, + `hyperpolymath/deed-ecosystem@main` — where this repo's lock records SHAs. + The template that ~441 repos are minted from therefore *teaches* non-pinning + to every repo cut from it. Measured 2026-09-17: 54 `@vN`/`@main` references + across `rsr-template-repo/.github/workflows/`. This is upstream of the + estate-board columns `sha_pinning` and `allowed_actions`, not a downstream + lapse. +| High + +| — +| Root link scan: 7 of 72 distinct relative link targets in the root documents + do not resolve, including `a2ml/` (evicted from this repository on + 2026-08-28 by `24a12d6f`, but still routed to by `README.adoc`). +| Medium +|=== + +== What a release requires + +Before this repository may be tagged `canon-v*`: + +. `canon.lock` verified — assertion 1 green for all five artefacts. +. Assertion 2 green — no law artefact changed without a version bump. +. Assertions 3 and 4 green — the spine has adopted this canon *and* passes it. +. `docs/AFFIRMATION.adoc` **signed** by the owner. It is currently unsigned and + therefore not citable. +. `scripts/run-shell-test-suite.sh` green. +. `scripts/build-registry.sh --check` exits 0. +. `standards-map.toml` green and `entry_count` current. + +== See also + +* link:AFFIRMATION.adoc[AFFIRMATION] — the dated honesty snapshot +* link:../canon.lock[`canon.lock`] — the released identity and Gate A's assertions +* link:../standards-map.toml[`standards-map.toml`] — the map of this repository +* link:../constitution/ESTATE-CONSTITUTION.adoc[Estate Constitution] +* link:../rhodium-standard-repositories/spec/rsr-criteria-v2.a2ml[`rsr-criteria-v2.a2ml`] diff --git a/scripts/check-canon-lockstep.sh b/scripts/check-canon-lockstep.sh new file mode 100644 index 000000000..82137aab6 --- /dev/null +++ b/scripts/check-canon-lockstep.sh @@ -0,0 +1,373 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# check-canon-lockstep.sh — GATE A. +# +# Proposed location: hyperpolymath/standards/scripts/check-canon-lockstep.sh +# Runs from: .github/workflows/canon-spine-lockstep.yml +# +# This is the gate that makes `standards` BOUND BY `rsr-template-repo`. +# +# --------------------------------------------------------------------------- +# WHAT IT ENFORCES +# +# HARD (always): +# 1 every sha256 in canon.lock [canon.artifacts] matches the working tree +# 2 touching a canon artefact forces a version bump +# +# INFORMATIONAL unless --strict: +# 3 the spine declares criteria_sha256 == canon.lock's criteria hash +# 4 the spine is GREEN against those criteria +# 5 the canon itself scores Gold on its own applicable set +# +# See softfail() for why 3/4/5 must not be hard by default. +# +# Assertion 4 is the load-bearing one, and it is a deliberate reversal: +# +# YOU MAY NOT TIGHTEN THE CRITERIA UNTIL THE REFERENCE IMPLEMENTATION +# PASSES THEM. +# +# --------------------------------------------------------------------------- +# USAGE +# check-canon-lockstep.sh [--canon DIR] [--spine DIR] [--base REF] [--strict] +# +# --canon DIR path to hyperpolymath/standards (default: .) +# --spine DIR path to a cloned rsr-template-repo +# --base REF the ref to diff against for assertion 2 (default: origin/main) +# --strict promote assertions 3/4/5 from SKIP to FAIL +# +# EXIT +# 0 all enabled assertions passed +# 1 at least one assertion failed +# 2 setup error (missing file, unresolvable ref) +# +# DEPENDENCIES +# bash (no python - estate policy: see docs/JS-RUNTIME-POLICY.adoc, +# NO-JAVASCRIPT-SOURCE-POLICY.adoc; bash + awk + git only) +# awk, git, sha256sum, grep +# --------------------------------------------------------------------------- +set -uo pipefail + +CANON="." +SPINE="" +BASE_REF="origin/main" +STRICT=0 +FAILED=0 +PASSED=0 +SKIPPED=0 +NOT_VERIFIED="" + +while [ $# -gt 0 ]; do + case "$1" in + --canon) CANON="$2"; shift 2 ;; + --spine) SPINE="$2"; shift 2 ;; + --base) BASE_REF="$2"; shift 2 ;; + --strict) STRICT=1; shift ;; + -h|--help) sed -n '2,40p' "$0"; exit 0 ;; + *) echo "unknown argument: $1" >&2; exit 2 ;; + esac +done + +pass() { PASSED=$((PASSED + 1)); printf ' \033[32mPASS\033[0m %s\n' "$*"; } +fail() { FAILED=$((FAILED + 1)); printf ' \033[31mFAIL\033[0m %s\n' "$*"; } +# skip() — the check could not be RUN (missing tool, missing argument). +# Always informational. --strict MUST NOT promote this: an absent +# tool is not a lockstep deviation, and promoting it makes --strict +# permanently red in any environment without `gh`/`hypatia`, which +# trains people to ignore it. +skip() { + SKIPPED=$((SKIPPED + 1)) + NOT_VERIFIED="$NOT_VERIFIED\n - $*" + printf ' \033[33mSKIP\033[0m %s\n' "$*" +} + +# Assertions 3, 4 and 5 are INFORMATIONAL unless --strict. +# +# This is not leniency, it is the ordering rule made executable. canon.lock +# [canon.lockstep].order is "spine-adopts-then-canon-releases", but a canon +# change and the spine's adoption of it CANNOT both be first: the spine's +# adoption necessarily pins hashes that exist only in the unmerged canon PR. +# A hard check here therefore renders every canon release unmergeable, which is +# the opposite of the rule it was meant to enforce. +# +# Sequence this enables: +# 1. land the canon change with 3/4/5 informational -> releases canon.lock +# 2. land the spine's adoption against the released hashes +# 3. turn --strict on, so drift is a hard failure from then on +# See the [canon.lockstep] section of canon.lock, which states the order. +# +# softfail() — a REAL deviation. Promoted to a failure by --strict. +softfail() { + if [ "$STRICT" -eq 1 ]; then fail "$*" + else SKIPPED=$((SKIPPED + 1)); printf ' \033[33mINFO\033[0m %s\n' "$*"; fi +} + +LOCK="$CANON/canon.lock" +# Repo-relative twin of $LOCK. Assertion 2 passes the lock to `git diff`, whose +# pathspecs resolve against the repository root, not the filesystem: with +# --canon canon the pathspec "canon/canon.lock" matched nothing, `git diff +# --quiet` therefore reported "no change", and the gate accused a PR that had +# in fact bumped the lock of not bumping it. +LOCK_REL="${LOCK#"$CANON"/}" +[ -f "$LOCK" ] || { echo "ERROR: canon.lock not found at $LOCK" >&2; exit 2; } + +# --------------------------------------------------------------------------- +# A minimal TOML reader. The estate mandates bash+awk (no Python, no Deno), +# and canon.lock is authored in a deliberately flat, single-line shape so that +# this is sufficient. This is the same discipline template-capability-gates.toml +# already imposes on itself ("Arrays are kept single-line so the checker can +# parse them with grep"). +# --------------------------------------------------------------------------- + +# toml_get
-> last assignment wins, comments stripped +toml_get() { + awk -v want="[$1]" -v key="$2" ' + /^[[:space:]]*\[/ { cur=$0; gsub(/[[:space:]]/,"",cur); next } + cur == want { + line=$0; sub(/#.*/,"",line) + if (line ~ "^[[:space:]]*"key"[[:space:]]*=") { + sub(/^[^=]*=[[:space:]]*/,"",line); gsub(/[[:space:]]*$/,"",line) + gsub(/^"|"$/,"",line); v=line + } + } + END { if (v != "") print v } + ' "$LOCK" +} + +# The artefact records are inline tables that may SPAN LINES, e.g. +# +# criteria = { path = "0-canon/rsr/rsr-criteria-v2.a2ml", # from spec/ +# sha256 = "efd024ad…", +# slot = "criteria", normative = true } +# +# so both readers below accumulate a record: they open on ` = {`, take +# every line until the closing `}` (or a line that does not continue the +# record), strip comments, and join. Same problem, and the same solution, as +# check-rsr-profile.sh's array_on_key(). +record() { # $1 = key name (criteria|gates|applicability|lifecycle|constitution) + awk -v slot="$1" ' + /^[[:space:]]*#/ { next } + $0 ~ "^[[:space:]]*" slot "[[:space:]]*=[[:space:]]*\\{" { on=1 } + on { + line=$0; sub(/#.*/, "", line); rec = rec " " line + if (line ~ /}/) { on=0 } + } + END { sub(/^[[:space:]]*/, "", rec); print rec } + ' "$LOCK" +} + +# toml_hash -> sha256 from that record +toml_hash() { + record "$1" | grep -oE 'sha256[[:space:]]*=[[:space:]]*"[0-9a-f]{64}"' \ + | grep -oE '[0-9a-f]{64}' | head -1 +} + +# toml_path -> path from that record +toml_path() { + record "$1" | grep -oE 'path[[:space:]]*=[[:space:]]*"[^"]+"' \ + | sed 's/.*"\(.*\)"/\1/' | head -1 +} + +# sha256 of a path: file -> plain hash; directory -> git-ls-files method, +# matching the registry's own source_hash definition. +hash_path() { + # $1 is a FILESYSTEM path, e.g. "$CANON/constitution/". Git pathspecs are + # resolved relative to the repository root and know nothing about the + # --canon prefix, so handing git "$CANON/constitution/" matched NOTHING; + # `git ls-files` printed nothing and sha256sum faithfully hashed the EMPTY + # stream — a plausible-looking digest for a directory that was never read. + # + # That is exactly why this gate reported "passed 8 failed 0 GATE A PASSED" + # locally (invoked as `--canon .`, where "./constitution/" happens to match) + # and "passed 6 failed 2 GATE A FAILED" in CI (invoked as `--canon canon`). + # The verdict depended on the SPELLING of the argument, not on the repository. + # + # Two changes: strip the prefix before handing the path to git, and refuse to + # hash an empty listing, so a wrong pathspec can never again look like a hash. + local p="$1" rel="${1#"$CANON"/}" + if [ -d "$p" ]; then + local listing + listing="$( cd "$CANON" && git ls-files -s -- "$rel" )" + if [ -z "$listing" ]; then + echo " ERROR: git ls-files matched no files for '$rel' in $CANON" >&2 + return 1 + fi + printf '%s\n' "$listing" | sha256sum | cut -d' ' -f1 + else + sha256sum "$p" | cut -d' ' -f1 + fi +} + +CANON_VERSION="$(toml_get canon version)" +echo "canon.lock: version=$CANON_VERSION lock=$(sha256sum "$LOCK" | cut -d' ' -f1 | cut -c1-12)…" +echo + +# =========================================================================== +# ASSERTION 1 — declared hashes match the working tree +# =========================================================================== +echo "[1] canon artefact hashes match the working tree" +for slot in criteria gates applicability lifecycle constitution; do + want="$(toml_hash "$slot")" + path="$(toml_path "$slot")" + if [ -z "$want" ] || [ -z "$path" ]; then softfail "$slot: declared in [canon.artifacts] with no path/hash, or absent"; continue; fi + if [ ! -e "$CANON/$path" ]; then + fail "$slot: declared path does not exist: $path" + continue + fi + if ! got="$(hash_path "$CANON/$path")"; then + fail "$slot: could not hash '$path' — see the error above" + continue + fi + if [ "$want" = "$got" ]; then + pass "$slot ${path} $(echo "$got" | cut -c1-12)…" + else + fail "$slot ${path} + declared $(echo "$want" | cut -c1-16)… + actual $(echo "$got" | cut -c1-16)… + -> the law changed without re-releasing canon.lock (bump version + rewrite hash)" + fi +done +echo + +# =========================================================================== +# ASSERTION 2 — a canon artefact change forces a version bump +# =========================================================================== +echo "[2] canon artefact change forces a version bump" +if git -C "$CANON" rev-parse --verify --quiet "$BASE_REF" >/dev/null 2>&1; then + CHANGED="" + for slot in criteria gates applicability lifecycle constitution; do + p="$(toml_path "$slot")"; [ -n "$p" ] || continue + if ! git -C "$CANON" diff --quiet "$BASE_REF"...HEAD -- "$p" 2>/dev/null; then + CHANGED="$CHANGED $slot" + fi + done + if [ -z "$CHANGED" ]; then + pass "no canon artefact changed against $BASE_REF" + elif ! git -C "$CANON" diff --quiet "$BASE_REF"...HEAD -- "$LOCK_REL" 2>/dev/null; then + pass "canon artefacts changed ($CHANGED ) and canon.lock was bumped in the same PR" + else + fail "canon artefacts changed ($CHANGED ) but canon.lock is untouched + -> any change to a file named in [canon.artifacts] is a CANON CHANGE. + Bump [canon].version and rewrite the hash in the SAME commit." + fi +else + skip "cannot resolve $BASE_REF in $CANON" +fi +echo + +# =========================================================================== +# ASSERTION 3 — the spine has adopted this canon +# =========================================================================== +echo "[3] spine declares the same criteria hash" +if [ -z "$SPINE" ] || [ ! -d "$SPINE" ]; then + skip "no --spine DIR given (set --strict in CI release jobs)" +else + PROFILE="$SPINE/machine-readable/rsr-profile.a2ml" + [ -f "$PROFILE" ] || PROFILE="$SPINE/.machine_readable/rsr-profile.a2ml" + if [ ! -f "$PROFILE" ]; then + softfail "spine has no rsr-profile.a2ml at either machine-readable/ or .machine_readable/" + else + WANT="$(toml_hash criteria)" + GOT="$(grep -E '^[[:space:]]*criteria_sha256[[:space:]]*=' "$PROFILE" \ + | grep -oE '[0-9a-f]{64}' | head -1)" + if [ -z "$GOT" ]; then + softfail "spine rsr-profile.a2ml has no [canon] criteria_sha256 + -> the spine still declares conformance in free text. The binding + does not exist until this is a hash." + elif [ "$WANT" = "$GOT" ]; then + pass "spine criteria_sha256 == canon.lock criteria ($(echo "$GOT" | cut -c1-12)…)" + else + softfail "spine is on a DIFFERENT canon + canon.lock $(echo "$WANT" | cut -c1-16)… + spine $(echo "$GOT" | cut -c1-16)… + -> land the spine's adoption AFTER this canon release; run with + --strict to make this a hard failure once both are on main." + fi + fi +fi +echo + +# =========================================================================== +# ASSERTION 4 — the reference implementation passes the criteria +# =========================================================================== +echo "[4] the spine is GREEN against these criteria" +if [ -z "$SPINE" ] || [ ! -d "$SPINE" ]; then + skip "no --spine DIR given" +elif ! command -v gh >/dev/null 2>&1; then + skip "gh not available; cannot read the spine's last dogfood-gate conclusion" +else + # The oracle is hypatia's rsr-conformance family. Until it is implemented + # (rsr-criteria-v2.a2ml [oracle] marks it "to be implemented"), the closest + # available proxy is the spine's own dogfood-gate run. This assertion is + # written against the PROXY and must be repointed when the oracle lands. + SHA="$(git -C "$SPINE" rev-parse HEAD 2>/dev/null || true)" + if [ -z "$SHA" ]; then + skip "cannot resolve spine HEAD" + else + RC="$(gh run list --repo hyperpolymath/rsr-template-repo \ + --workflow dogfood-gate.yml --commit "$SHA" \ + --json conclusion --jq '.[0].conclusion' 2>/dev/null || true)" + case "$RC" in + success) pass "dogfood-gate is green at spine@$(echo "$SHA" | cut -c1-7)" + ;; + "") skip "no dogfood-gate run found for spine@$(echo "$SHA" | cut -c1-7)" + ;; + *) fail "dogfood-gate is '$RC' at spine@$(echo "$SHA" | cut -c1-7) + -> THE REVERSAL: you may not tighten the criteria until the reference + implementation passes them. Fix the spine, or revert this canon change." ;; + esac + fi +fi +echo + +# =========================================================================== +# ASSERTION 5 — the canon satisfies its own law +# =========================================================================== +echo "[5] the canon scores Gold on its own applicable set" +# Mirror scripts/check-rsr-profile.sh's own convention: the canonical machine +# tree is machine-readable/, but the LEGACY dotted form is still accepted +# "because the canon, scaffoldia, the julia variant and ~300 minted repos all +# still carry it". This repo is one of them until the rename lands. +CANON_PROFILE="$CANON/machine-readable/rsr-profile.a2ml" +[ -f "$CANON_PROFILE" ] || CANON_PROFILE="$CANON/.machine_readable/rsr-profile.a2ml" +if [ ! -f "$CANON_PROFILE" ]; then + softfail "the canon has NO rsr-profile.a2ml — it cannot be scored by the checker + it ships (scripts/check-rsr-profile.sh exits 2 on this repo). + -> see artefacts/rsr-profile.canon.a2ml; requires [canon] in the gate table." +else + ROLE="$(grep -E '^[[:space:]]*role[[:space:]]*=' "$CANON_PROFILE" | head -1 | grep -oE '"[^"]+"' | tr -d '"')" + [ "$ROLE" = "canon" ] || softfail "canon rsr-profile role is '${ROLE:-unset}', expected 'canon'" + [ "$ROLE" = "canon" ] && pass "canon rsr-profile declares role = \"canon\"" + + if command -v mix >/dev/null 2>&1 && [ -d "$CANON/../hypatia" ]; then + # mix hypatia.rsr_score reads the applicable set from the profile and emits + # a scorecard. Exit 0 = at or above the required tier. + if ( cd "$CANON/../hypatia" && mix hypatia.rsr_score "$CANON" --require gold ) >/dev/null 2>&1; then + pass "hypatia rsr-conformance: canon is at Gold" + else + fail "hypatia rsr-conformance: canon is BELOW Gold on its applicable set" + fi + else + skip "hypatia (the one normative oracle) not available; oracle is marked 'to be implemented'" + fi +fi +echo + +# =========================================================================== +echo "─────────────────────────────────────────────────────────────" +printf 'passed %d failed %d skipped %d\n' "$PASSED" "$FAILED" "$SKIPPED" +if [ -n "$NOT_VERIFIED" ]; then + printf '\n\033[33mNOT VERIFIED\033[0m (these assertions did not run — a green result is NOT a full verification):' + printf "$NOT_VERIFIED\n" +fi +if [ "$FAILED" -gt 0 ]; then + echo + echo "GATE A FAILED — the canon and the spine are not in lockstep." + echo "This is not necessarily a bad change. It is very often a change made" + echo "in the wrong ORDER. See [canon.lockstep].order in canon.lock:" + echo " spine-adopts-then-canon-releases" + exit 1 +fi +echo "GATE A PASSED" +exit 0 diff --git a/scripts/check-rsr-profile.sh b/scripts/check-rsr-profile.sh index 7baabb9c4..b64436e51 100755 --- a/scripts/check-rsr-profile.sh +++ b/scripts/check-rsr-profile.sh @@ -115,11 +115,34 @@ echo # using the [profile] spelling the script otherwise supports. ROLE="$(printf '%s\n' "$PBODY" | quoted_on_key role | sed -n 1p || true)" CARRIER="" -if [ "$ROLE" = "spine" ]; then - CARRIER="$(section carrier "$GATES" | quoted_on_key paths || true)" - echo "role: spine - [carrier] paths exempt from VESTIGIAL" - echo -fi +# role = "spine": a template legitimately carries modules it does not declare, +# because it ships them for the repos minted from it. +# role = "canon": hyperpolymath/standards legitimately carries modules whose +# gating capability cannot apply to it — the criteria SSOT is the document that +# DEFINES the gates, not an instance of one; docs/proofs/ holds proof artefacts +# OF THE ESTATE, not proofs of the canon's own code; and *-reusable.yml are the +# gates every other repo CALLS and the canon SERVES. +# +# Without this the canon is unscorable BY CONSTRUCTION, which is the mechanical +# reason it has never carried an rsr-profile.a2ml at all. See [canon] in the +# gate table for the full rationale. +case "$ROLE" in + spine) + CARRIER="$(section carrier "$GATES" | quoted_on_key paths || true)" + echo "role: spine - [carrier] paths exempt from VESTIGIAL" + echo + ;; + canon) + CARRIER="$(section canon "$GATES" | quoted_on_key paths || true)" + echo "role: canon - [canon] paths exempt from VESTIGIAL" + echo + ;; + "") + ;; + *) + echo "WARNING: unknown role '$ROLE' - no carrier exemption applied" >&2 + ;; +esac # A gate row may be an alternation ("a|b"); a carrier entry names ONE path. # Exact-matching the whole row would silently fail to exempt an alternation row # whose alternatives are carried, so test each alternative in turn. diff --git a/scripts/check-standards-map.sh b/scripts/check-standards-map.sh new file mode 100644 index 000000000..dbcabc77a --- /dev/null +++ b/scripts/check-standards-map.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# check-standards-map.sh — GATE D. +# +# Proposed location: hyperpolymath/standards/scripts/check-standards-map.sh +# Runs from: .github/workflows/standards-map-verify.yml +# +# Keeps standards-map.toml honest. BIDIRECTIONAL, deliberately — this is the +# single most transferable lesson in the estate, and it is the template's own: +# +# "The check is BIDIRECTIONAL: +# * anything at root that is not listed here is drift, and fails; +# * anything listed here WITHOUT the '?' marker must exist, and its +# absence fails. +# The second half is the important one. … A one-directional allowlist only +# ever ratchets open." +# — rsr-template-repo/machine-readable/root-allow.txt +# +# That comment was written after a root cleanup left stale PERMISSIONS behind, +# so the allowlist had "quietly become a licence for the very drift it was +# written to prevent". The same failure mode would apply to a map of this repo. +# +# --------------------------------------------------------------------------- +# ASSERTIONS +# 1 every [[entry]].from exists in the tree +# 2 every top-level entry in the tree has an [[entry]] +# 3 every canonical = true entry has a canonical_doc +# 4 every non-empty canon_slot resolves to a slot in canon.lock [canon.artifacts] +# 5 entry_count in [map] matches the number of [[entry]] records +# +# USAGE check-standards-map.sh [--repo DIR] [--map FILE] [--lock FILE] +# EXIT 0 ok | 1 violations | 2 setup error +# --------------------------------------------------------------------------- +set -uo pipefail + +REPO="." +MAP="" +LOCK="" +FAILED=0 + +while [ $# -gt 0 ]; do + case "$1" in + --repo) REPO="$2"; shift 2 ;; + --map) MAP="$2"; shift 2 ;; + --lock) LOCK="$2"; shift 2 ;; + -h|--help) sed -n '2,30p' "$0"; exit 0 ;; + *) echo "unknown argument: $1" >&2; exit 2 ;; + esac +done + +[ -n "$MAP" ] || MAP="$REPO/standards-map.toml" +[ -n "$LOCK" ] || LOCK="$REPO/canon.lock" +[ -f "$MAP" ] || { echo "ERROR: map not found: $MAP" >&2; exit 2; } + +# Fields, in the flat single-line shape the map is authored in. +map_field() { # $1 = field name + grep -E "^$1[[:space:]]*=" "$MAP" | sed 's/^[^=]*=[[:space:]]*//; s/^"//; s/"[[:space:]]*$//' +} + +bad() { FAILED=$((FAILED + 1)); printf ' \033[31mFAIL\033[0m %s\n' "$*"; } +ok() { printf ' \033[32mok\033[0m %s\n' "$*"; } + +# -------------------------------------------------------------------------- +echo "[1] every mapped source path exists" +MISSING=0 +for src in $(map_field from); do + if [ ! -e "$REPO/$src" ]; then bad "mapped path does not exist: $src"; MISSING=$((MISSING + 1)); fi +done +[ "$MISSING" -eq 0 ] && ok "all $(map_field from | wc -l) mapped paths exist" +echo + +# -------------------------------------------------------------------------- +echo "[2] every top-level entry is mapped" +UNMAPPED=0 +while IFS= read -r e; do + [ "$e" = ".git" ] && continue + if ! grep -qE "^from[[:space:]]*=[[:space:]]*\"$e\"[[:space:]]*$" "$MAP"; then + bad "unmapped top-level entry: $e" + UNMAPPED=$((UNMAPPED + 1)) + fi +done < <(cd "$REPO" && ls -A) +[ "$UNMAPPED" -eq 0 ] && ok "all $(ls -A "$REPO" | grep -vc '^\.git$') top-level entries are mapped" +echo + +# -------------------------------------------------------------------------- +echo "[3] every canonical entry names a canonical_doc" +NODOC=0 +awk ' + /^\[\[entry\]\]/ { if (path != "" && canonical == "true" && doc == "") print path; path=""; canonical=""; doc="" } + /^from[[:space:]]*=/ { v=$0; sub(/^[^=]*=[[:space:]]*"/,"",v); sub(/".*/,"",v); path=v } + /^canonical[[:space:]]*=/ { canonical=$3 } + /^canonical_doc[[:space:]]*=/ { doc=1 } +' "$MAP" | while read -r p; do bad "canonical = true but no canonical_doc: $p"; done +# the abort-on-last-record case +tail -20 "$MAP" | grep -q '^canonical_doc' || true +ok "(see violations above if any)" +echo + +# -------------------------------------------------------------------------- +echo "[4] every canon_slot resolves in canon.lock" +if [ ! -f "$LOCK" ]; then + bad "canon.lock not found at $LOCK — canon_slot cannot be verified" +else + SLOTS="$(grep -oE 'slot[[:space:]]*=[[:space:]]*"[^"]+"' "$LOCK" | sed 's/.*"\(.*\)"/\1/' | sort -u)" + BADSLOT=0 + for s in $(map_field canon_slot | grep -v '^$' | sort -u); do + if ! printf '%s\n' "$SLOTS" | grep -qx "$s"; then bad "canon_slot '$s' has no slot in canon.lock"; BADSLOT=$((BADSLOT+1)); fi + done + [ "$BADSLOT" -eq 0 ] && ok "all canon_slot values resolve ($(printf '%s\n' "$SLOTS" | tr '\n' ' '))" +fi +echo + +# -------------------------------------------------------------------------- +echo "[5] entry_count matches the record count" +DECLARED="$(grep -E '^entry_count[[:space:]]*=' "$MAP" | grep -oE '[0-9]+' | head -1)" +ACTUAL="$(grep -c '^\[\[entry\]\]' "$MAP")" +if [ "$DECLARED" = "$ACTUAL" ]; then + ok "entry_count = $ACTUAL" +else + bad "entry_count declares $DECLARED but the map holds $ACTUAL [[entry]] records" +fi +echo + +# -------------------------------------------------------------------------- +if [ "$FAILED" -gt 0 ]; then + echo "GATE D FAILED — $FAILED violation(s)." + echo "The map is the machine-readable shape of this repository. If it is" + echo "wrong, every reader that trusts it is wrong too." + exit 1 +fi +echo "GATE D PASSED" +exit 0 diff --git a/standards-map.toml b/standards-map.toml new file mode 100644 index 000000000..66b96c8eb --- /dev/null +++ b/standards-map.toml @@ -0,0 +1,1615 @@ +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# standards-map.toml - the machine-readable map of hyperpolymath/standards. +# +# WHY THIS EXISTS +# .machine_readable/REGISTRY.a2ml indexes 33 SPECS. This repo has 118 top-level +# entries. The other 85 have no declared domain, kind, lifecycle or gate, and +# THAT absence is what makes the repo unreadable by machine and by human. +# +# BIDIRECTIONAL, LIKE THE SPINE'S root-allow.txt +# An entry here MUST exist. A path that exists MUST be listed here. +# A one-directional allowlist only ever ratchets open - the template's own +# root-allow.txt learned this the expensive way. Checked by +# scripts/check-standards-map.sh in CI. +# +# GENERATED RENDERINGS - one map, two readers +# index.adoc per district (human) <- rendered from this file +# machine-readable/map.a2ml (machine) <- rendered from this file +# +# FIELDS +# from current path at time of writing (the migration source) +# target post-reorg path, "-> repo" for a split-out, "DELETE" to remove +# district the district this entry belongs to (see 03-STANDARDS-REORG.md) +# kind law | format-* | protocol | policy | grading | machinery | +# measured | onramp | archive | spine-mandated +# lifecycle versioned | generated | frozen | deprecated +# canonical true = may be linked normatively by other repos (the SSOT set) +# canon_slot join key into canon.lock [canon.artifacts]; "" if not law +# gate the CI gate that fails if this entry is wrong + +[map] +repo = "hyperpolymath/standards" +version = "1.0.0" +entry_count = 120 +generated = false # hand-curated; the district index.adoc files ARE generated +checked_by = "scripts/check-standards-map.sh" + +[[district]] +id = "0-canon" +question = "What must a conforming repo BE?" +[[district]] +id = "1-formats" +question = "What do we read and write?" +[[district]] +id = "2-protocols" +question = "How do systems and agents talk?" +[[district]] +id = "3-practice" +question = "How do we work?" +[[district]] +id = "4-readiness" +question = "How mature is it?" +[[district]] +id = "5-machine" +question = "What indexes and enforces all of that?" +[[district]] +id = "6-telemetry" +question = "What is the estate actually like right now?" +[[district]] +id = "9-archive" +question = "What did we used to think?" +[[district]] +id = "onramp" +question = "Where do I start?" +[[district]] +id = "root" +question = "(root entries mandated by the spine's root-allow.txt)" + + +[[entry]] +from = "rhodium-standard-repositories" +target = "0-canon/rsr/ (extract spec/ only)" +district = "0-canon" +kind = "law-vendored" +files = 1138 +lifecycle = "deprecated" +canonical = false +canon_slot = "rsr-spec-home" +canonical_doc = "0-canon/rsr//index.adoc" +gate = "canon-spine-lockstep" +note = "VENDORED COPY of hyperpolymath/rhodium-standard-repositories, 1138 files = 43% of this repo. Extract spec/ (11 files) then DELETE. Carries its own .gitmodules naming satellites/rsr-template-repo." + +[[entry]] +from = "constitution" +target = "0-canon/constitution/" +district = "0-canon" +kind = "law" +files = 9 +lifecycle = "versioned" +canonical = true +canon_slot = "constitution" +canonical_doc = "0-canon/constitution/index.adoc" +gate = "canon-self-conformance" +note = "highest estate rules, authority precedence, assurance" + +[[entry]] +from = "CANONICAL-NAMES.adoc" +target = "0-canon/CANONICAL-NAMES.adoc" +district = "0-canon" +kind = "law" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "0-canon/CANONICAL-NAMES.adoc" +gate = "canon-spine-lockstep" + +[[entry]] +from = "COMPLIANCE-DASHBOARD.adoc" +target = "0-canon/COMPLIANCE-DASHBOARD.adoc" +district = "0-canon" +kind = "law" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "0-canon/COMPLIANCE-DASHBOARD.adoc" +gate = "canon-spine-lockstep" + +[[entry]] +from = "CRG-SELF-ASSESSMENT.adoc" +target = "0-canon/CRG-SELF-ASSESSMENT.adoc" +district = "0-canon" +kind = "law" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "0-canon/CRG-SELF-ASSESSMENT.adoc" +gate = "canon-spine-lockstep" + +[[entry]] +from = "GOVERNANCE.adoc" +target = "0-canon/GOVERNANCE.adoc" +district = "0-canon" +kind = "law" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "0-canon/GOVERNANCE.adoc" +gate = "canon-spine-lockstep" + +[[entry]] +from = "PORT-REGISTRY.adoc" +target = "0-canon/PORT-REGISTRY.adoc" +district = "0-canon" +kind = "law" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "0-canon/PORT-REGISTRY.adoc" +gate = "canon-spine-lockstep" + +[[entry]] +from = "RSR-PHILOSOPHY.adoc" +target = "0-canon/RSR-PHILOSOPHY.adoc" +district = "0-canon" +kind = "law" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "0-canon/RSR-PHILOSOPHY.adoc" +gate = "canon-spine-lockstep" + +[[entry]] +from = "TEMPLATE-APPLICABILITY-POLICY.adoc" +target = "0-canon/TEMPLATE-APPLICABILITY-POLICY.adoc" +district = "0-canon" +kind = "law" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "applicability" +canonical_doc = "0-canon/TEMPLATE-APPLICABILITY-POLICY.adoc" +gate = "canon-spine-lockstep" + +[[entry]] +from = "k9-svc" +target = "1-formats/k9/ (pointer)" +district = "1-formats" +kind = "format-tooling" +files = 41 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/k9//index.adoc" +gate = "canon-self-conformance" +note = "implementations live in hyperpolymath/k9-ecosystem per this repo's own registry" + +[[entry]] +from = "meta-a2ml" +target = "1-formats/a2ml/ (pointer)" +district = "1-formats" +kind = "format-profile" +files = 38 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/a2ml//index.adoc" +gate = "registry-verify" +note = "a2ml/ evicted 2026-08-28 by 24a12d6f; these 7 profile dirs (191 files) stayed behind. Finish the eviction or revert it." + +[[entry]] +from = "agentic-a2ml" +target = "1-formats/a2ml/ (pointer)" +district = "1-formats" +kind = "format-profile" +files = 37 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/a2ml//index.adoc" +gate = "registry-verify" +note = "a2ml/ evicted 2026-08-28 by 24a12d6f; these 7 profile dirs (191 files) stayed behind. Finish the eviction or revert it." + +[[entry]] +from = "state-a2ml" +target = "1-formats/a2ml/ (pointer)" +district = "1-formats" +kind = "format-profile" +files = 30 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/a2ml//index.adoc" +gate = "registry-verify" +note = "a2ml/ evicted 2026-08-28 by 24a12d6f; these 7 profile dirs (191 files) stayed behind. Finish the eviction or revert it." + +[[entry]] +from = "did-you-actually-do-that" +target = "1-formats/sub-specs/did-you-actually-do-that/" +district = "1-formats" +kind = "sub-spec" +files = 28 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/sub-specs/did-you-actually-do-that/index.adoc" +gate = "canon-self-conformance" +note = "TRIAGE: <30 files each; none is a district" + +[[entry]] +from = "anchor-a2ml" +target = "1-formats/a2ml/ (pointer)" +district = "1-formats" +kind = "format-profile" +files = 25 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/a2ml//index.adoc" +gate = "registry-verify" +note = "a2ml/ evicted 2026-08-28 by 24a12d6f; these 7 profile dirs (191 files) stayed behind. Finish the eviction or revert it." + +[[entry]] +from = "ecosystem-a2ml" +target = "1-formats/a2ml/ (pointer)" +district = "1-formats" +kind = "format-profile" +files = 23 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/a2ml//index.adoc" +gate = "registry-verify" +note = "a2ml/ evicted 2026-08-28 by 24a12d6f; these 7 profile dirs (191 files) stayed behind. Finish the eviction or revert it." + +[[entry]] +from = "neurosym-a2ml" +target = "1-formats/a2ml/ (pointer)" +district = "1-formats" +kind = "format-profile" +files = 23 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/a2ml//index.adoc" +gate = "registry-verify" +note = "a2ml/ evicted 2026-08-28 by 24a12d6f; these 7 profile dirs (191 files) stayed behind. Finish the eviction or revert it." + +[[entry]] +from = "playbook-a2ml" +target = "1-formats/a2ml/ (pointer)" +district = "1-formats" +kind = "format-profile" +files = 15 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "1-formats/a2ml//index.adoc" +gate = "registry-verify" +note = "a2ml/ evicted 2026-08-28 by 24a12d6f; these 7 profile dirs (191 files) stayed behind. Finish the eviction or revert it." + +[[entry]] +from = "a2ml-templates" +target = "1-formats/templates/" +district = "1-formats" +kind = "template" +files = 10 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/templates/index.adoc" +gate = "canon-self-conformance" + +[[entry]] +from = "inline-annotations" +target = "1-formats/sub-specs/inline-annotations/" +district = "1-formats" +kind = "sub-spec" +files = 8 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/sub-specs/inline-annotations/index.adoc" +gate = "canon-self-conformance" +note = "TRIAGE: <30 files each; none is a district" + +[[entry]] +from = "contractiles" +target = "1-formats/contractiles/ -> hyperpolymath/contractiles" +district = "1-formats" +kind = "format-contract" +files = 6 +lifecycle = "versioned" +canonical = true +canon_slot = "contractile-spec" +canonical_doc = "hyperpolymath/contractiles/index.adoc" +gate = "check-mustfile-structure" +note = "absorbs machine-readable/contractiles/; own linter is estate task #19" + +[[entry]] +from = "deed" +target = "1-formats/deed/ -> hyperpolymath/deed" +district = "1-formats" +kind = "format-grammar" +files = 6 +lifecycle = "versioned" +canonical = true +canon_slot = "deed-grammar" +canonical_doc = "hyperpolymath/deed/index.adoc" +gate = "canon-spine-lockstep" +note = "own IANA media type; v0.2.0 DRAFT; successor to the a2ml record dialect" + +[[entry]] +from = "panll-panels" +target = "1-formats/sub-specs/panll-panels/" +district = "1-formats" +kind = "sub-spec" +files = 6 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/sub-specs/panll-panels/index.adoc" +gate = "canon-self-conformance" +note = "TRIAGE: <30 files each; none is a district" + +[[entry]] +from = "ensaid-config" +target = "1-formats/sub-specs/ensaid-config/" +district = "1-formats" +kind = "sub-spec" +files = 4 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/sub-specs/ensaid-config/index.adoc" +gate = "canon-self-conformance" +note = "TRIAGE: <30 files each; none is a district" + +[[entry]] +from = "cartridges" +target = "1-formats/sub-specs/cartridges/" +district = "1-formats" +kind = "sub-spec" +files = 3 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/sub-specs/cartridges/index.adoc" +gate = "canon-self-conformance" +note = "TRIAGE: <30 files each; none is a district" + +[[entry]] +from = "A2ML-REPO-TEMPLATE.adoc" +target = "1-formats/" +district = "1-formats" +kind = "index" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/index.adoc" +gate = "canon-self-conformance" + +[[entry]] +from = "SATELLITES.a2ml" +target = "1-formats/" +district = "1-formats" +kind = "index" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/index.adoc" +gate = "canon-self-conformance" + +[[entry]] +from = "bindings-haskell" +target = "1-formats/sub-specs/bindings-haskell/" +district = "1-formats" +kind = "sub-spec" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "1-formats/sub-specs/bindings-haskell/index.adoc" +gate = "canon-self-conformance" +note = "TRIAGE: <30 files each; none is a district" + +[[entry]] +from = "axel-protocol" +target = "2-protocols/axel/" +district = "2-protocols" +kind = "protocol" +files = 110 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "2-protocols/axel/index.adoc" +gate = "canon-self-conformance" +note = "consolidate, do NOT split: same owners, same cadence as the law" + +[[entry]] +from = "0-ai-gatekeeper-protocol" +target = "2-protocols/0-ai-gatekeeper/" +district = "2-protocols" +kind = "protocol" +files = 50 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "2-protocols/0-ai-gatekeeper/index.adoc" +gate = "canon-self-conformance" +note = "consolidate, do NOT split: same owners, same cadence as the law" + +[[entry]] +from = "k9-coordination-protocol" +target = "2-protocols/k9-coordination/" +district = "2-protocols" +kind = "protocol" +files = 19 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "2-protocols/k9-coordination/index.adoc" +gate = "canon-self-conformance" +note = "consolidate, do NOT split: same owners, same cadence as the law" + +[[entry]] +from = "overlay-protocol" +target = "2-protocols/overlay/" +district = "2-protocols" +kind = "protocol" +files = 10 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "2-protocols/overlay/index.adoc" +gate = "canon-self-conformance" +note = "consolidate, do NOT split: same owners, same cadence as the law" + +[[entry]] +from = "chora" +target = "2-protocols/chora/" +district = "2-protocols" +kind = "protocol" +files = 2 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "2-protocols/chora/index.adoc" +gate = "canon-self-conformance" +note = "consolidate, do NOT split: same owners, same cadence as the law" + +[[entry]] +from = "groove-protocol" +target = "2-protocols/groove/" +district = "2-protocols" +kind = "protocol" +files = 2 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "2-protocols/groove/index.adoc" +gate = "canon-self-conformance" +note = "consolidate, do NOT split: same owners, same cadence as the law" + +[[entry]] +from = "avow-protocol" +target = "2-protocols/avow/" +district = "2-protocols" +kind = "protocol" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "2-protocols/avow/index.adoc" +gate = "canon-self-conformance" +note = "consolidate, do NOT split: same owners, same cadence as the law" + +[[entry]] +from = "session-management-standards" +target = "3-practice/session-management-standards/" +district = "3-practice" +kind = "policy" +files = 51 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/session-management-standards/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "outreach" +target = "3-practice/outreach/" +district = "3-practice" +kind = "policy" +files = 23 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/outreach/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "ai-instruction" +target = "3-practice/ai-instruction/" +district = "3-practice" +kind = "policy" +files = 4 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/ai-instruction/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "publication-pre-flight" +target = "3-practice/publication-pre-flight/" +district = "3-practice" +kind = "policy" +files = 3 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/publication-pre-flight/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "release-pre-flight" +target = "3-practice/release-pre-flight/" +district = "3-practice" +kind = "policy" +files = 2 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/release-pre-flight/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "CODEOWNERS-POLICY.adoc" +target = "3-practice/CODEOWNERS-POLICY.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/CODEOWNERS-POLICY.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "CODE_OF_CONDUCT.adoc" +target = "3-practice/CODE_OF_CONDUCT.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/CODE_OF_CONDUCT.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "CONTRIBUTING.adoc" +target = "3-practice/CONTRIBUTING.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/CONTRIBUTING.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "LANGUAGE-POLICY.adoc" +target = "3-practice/LANGUAGE-POLICY.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/LANGUAGE-POLICY.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "LICENCE-POLICY.adoc" +target = "3-practice/LICENCE-POLICY.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/LICENCE-POLICY.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "MAINTAINERS.adoc" +target = "3-practice/MAINTAINERS.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/MAINTAINERS.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "PROOF-NEEDS.adoc" +target = "3-practice/PROOF-NEEDS.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/PROOF-NEEDS.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "REMOTE-URL-POLICY.adoc" +target = "3-practice/REMOTE-URL-POLICY.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/REMOTE-URL-POLICY.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "SECURITY-ADVISORIES.adoc" +target = "3-practice/SECURITY-ADVISORIES.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/SECURITY-ADVISORIES.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "SECURITY.adoc" +target = "3-practice/SECURITY.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/SECURITY.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "SECURITY.md" +target = "3-practice/SECURITY.md" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/SECURITY.md" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "TEST-NEEDS.adoc" +target = "3-practice/TEST-NEEDS.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/TEST-NEEDS.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "TOOLING-VERSION-INTEGRITY-POLICY.adoc" +target = "3-practice/TOOLING-VERSION-INTEGRITY-POLICY.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/TOOLING-VERSION-INTEGRITY-POLICY.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "TRUST-DEFAULTS-POLICY.adoc" +target = "3-practice/TRUST-DEFAULTS-POLICY.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/TRUST-DEFAULTS-POLICY.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "ZIGZAG-TESTING.adoc" +target = "3-practice/ZIGZAG-TESTING.adoc" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/ZIGZAG-TESTING.adoc" +gate = "canon-self-conformance" +note = "SPDX/licence policy is owner-only, flag-never-edit" + +[[entry]] +from = "accessibility" +target = "3-practice/accessibility/" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/accessibility/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "immaculate-guide" +target = "3-practice/immaculate-guide/" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/immaculate-guide/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "testing-and-benchmarking" +target = "3-practice/testing-and-benchmarking/" +district = "3-practice" +kind = "policy" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "3-practice/testing-and-benchmarking/index.adoc" +gate = "canon-self-conformance" +note = "outreach/ is a split-out candidate (non-normative)" + +[[entry]] +from = "toolchain-readiness-grades" +target = "4-readiness/toolchain-readiness-grades/" +district = "4-readiness" +kind = "grading" +files = 40 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "4-readiness/toolchain-readiness-grades/index.adoc" +gate = "canon-self-conformance" +note = "dashboard aggregates to nextgen-languages" + +[[entry]] +from = "adoption-readiness-grades" +target = "4-readiness/adoption-readiness-grades/" +district = "4-readiness" +kind = "grading" +files = 5 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "4-readiness/adoption-readiness-grades/index.adoc" +gate = "canon-self-conformance" +note = "dashboard aggregates to nextgen-languages" + +[[entry]] +from = "component-readiness-grades" +target = "4-readiness/component-readiness-grades/" +district = "4-readiness" +kind = "grading" +files = 5 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "4-readiness/component-readiness-grades/index.adoc" +gate = "canon-self-conformance" +note = "dashboard aggregates to nextgen-languages" + +[[entry]] +from = "foundations-readiness-grades" +target = "4-readiness/foundations-readiness-grades/" +district = "4-readiness" +kind = "grading" +files = 5 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "4-readiness/foundations-readiness-grades/index.adoc" +gate = "canon-self-conformance" +note = "dashboard aggregates to nextgen-languages" + +[[entry]] +from = "scripts" +target = "5-machine/scripts" +district = "5-machine" +kind = "machinery" +files = 107 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/scripts/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = ".machine_readable" +target = "machine-readable/" +district = "5-machine" +kind = "index" +files = 97 +lifecycle = "generated" +canonical = true +canon_slot = "" +canonical_doc = "machine-readable/index.adoc" +gate = "registry-verify" +note = "F2: spine's root-allow.txt says machine-readable/ is canonical (un-hidden 2026-08). This repo still uses the retired dotted form in 97 files." + +[[entry]] +from = ".github" +target = "5-machine/.github" +district = "5-machine" +kind = "machinery" +files = 72 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/.github" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "standards-update" +target = "5-machine/standards-update" +district = "5-machine" +kind = "machinery" +files = 20 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/standards-update/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = ".githooks" +target = "5-machine/.githooks" +district = "5-machine" +kind = "machinery" +files = 17 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/.githooks" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "config" +target = "5-machine/config" +district = "5-machine" +kind = "machinery" +files = 14 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/config/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "hypatia-rules" +target = "5-machine/hypatia-rules" +district = "5-machine" +kind = "machinery" +files = 10 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/hypatia-rules/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "hooks" +target = "5-machine/hooks" +district = "5-machine" +kind = "machinery" +files = 8 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/hooks/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "launcher" +target = "5-machine/launcher" +district = "5-machine" +kind = "machinery" +files = 6 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/launcher/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "tests" +target = "5-machine/tests" +district = "5-machine" +kind = "machinery" +files = 5 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/tests/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "LICENSES" +target = "5-machine/LICENSES" +district = "5-machine" +kind = "machinery" +files = 4 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/LICENSES/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "licenses" +target = "5-machine/licenses" +district = "5-machine" +kind = "machinery" +files = 4 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/licenses/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "_shared" +target = "5-machine/_shared" +district = "5-machine" +kind = "machinery" +files = 3 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/_shared/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "tasks" +target = "5-machine/tasks" +district = "5-machine" +kind = "machinery" +files = 3 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/tasks/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "templates" +target = "5-machine/templates" +district = "5-machine" +kind = "machinery" +files = 3 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/templates/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "tools" +target = "5-machine/tools" +district = "5-machine" +kind = "machinery" +files = 3 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/tools/index.adoc" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = ".hypatia" +target = "5-machine/.hypatia" +district = "5-machine" +kind = "machinery" +files = 2 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/.hypatia" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = ".claude" +target = "5-machine/.claude" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/.claude" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = ".gitleaks.toml" +target = "5-machine/ (root if spine-mandated): .gitleaks.toml" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = ".gitleaksignore" +target = "5-machine/ (root if spine-mandated): .gitleaksignore" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = ".governance-allowlist" +target = "5-machine/ (root if spine-mandated): .governance-allowlist" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = ".meta" +target = "5-machine/.meta" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine/.meta" +gate = "actions-lock-gate" +note = "licenses/ and LICENSES/ both exist; audits/ vs docs/audits/ both exist" + +[[entry]] +from = "CICD-WORKFLOW-CATALOG.md" +target = "5-machine/ (root if spine-mandated): CICD-WORKFLOW-CATALOG.md" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "CLAIMS.a2ml" +target = "5-machine/ (root if spine-mandated): CLAIMS.a2ml" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "Dustfile" +target = "DELETE" +district = "5-machine" +kind = "superseded-contractile" +files = 1 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "" +gate = "check-mustfile-structure" +note = "extension-less contractiles at root, superseded by machine-readable/contractiles/. Two naming conventions in one tree." + +[[entry]] +from = "Justfile" +target = "5-machine/ (root if spine-mandated): Justfile" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "Mustfile" +target = "DELETE" +district = "5-machine" +kind = "superseded-contractile" +files = 1 +lifecycle = "deprecated" +canonical = false +canon_slot = "" +canonical_doc = "" +gate = "check-mustfile-structure" +note = "extension-less contractiles at root, superseded by machine-readable/contractiles/. Two naming conventions in one tree." + +[[entry]] +from = "REGISTRY.adoc" +target = "5-machine/ (root if spine-mandated): REGISTRY.adoc" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "coordination.k9" +target = "5-machine/ (root if spine-mandated): coordination.k9" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "guix.scm" +target = "5-machine/ (root if spine-mandated): guix.scm" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "repo-catalog-template.toml" +target = "5-machine/ (root if spine-mandated): repo-catalog-template.toml" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "setup.sh" +target = "5-machine/ (root if spine-mandated): setup.sh" +district = "5-machine" +kind = "machinery" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "5-machine//index.adoc" +gate = "actions-lock-gate" + +[[entry]] +from = "docs" +target = "DISAGGREGATE" +district = "6-telemetry" +kind = "mixed" +files = 402 +lifecycle = "mixed" +canonical = false +canon_slot = "" +canonical_doc = "" +gate = "" +note = "402 files: proofs/ 283 + UX-standards/ 30 -> telemetry or split out; audits/ 27 -> 6-telemetry; archive/ 15 + migrations/ + reorg/ + handover/ -> 9-archive; decisions/ 5 + wikis/ 5 -> stay; ~28 loose policy .adoc files -> 3-practice" + +[[entry]] +from = ".verisimdb" +target = "6-telemetry/.verisimdb" +district = "6-telemetry" +kind = "measured" +files = 7 +lifecycle = "generated" +canonical = false +canon_slot = "" +canonical_doc = "6-telemetry/.verisimdb" +gate = "" +note = "SPLIT OUT -> hyperpolymath/estate-telemetry; generated data, not law" + +[[entry]] +from = "audits" +target = "6-telemetry/audits" +district = "6-telemetry" +kind = "measured" +files = 3 +lifecycle = "generated" +canonical = false +canon_slot = "" +canonical_doc = "6-telemetry/audits/index.adoc" +gate = "" +note = "SPLIT OUT -> hyperpolymath/estate-telemetry; generated data, not law" + +[[entry]] +from = ".hypatia-baseline.json" +target = "6-telemetry/.hypatia-baseline.json" +district = "6-telemetry" +kind = "measured" +files = 1 +lifecycle = "generated" +canonical = false +canon_slot = "" +canonical_doc = "6-telemetry/.hypatia-baseline.json" +gate = "" +note = "SPLIT OUT -> hyperpolymath/estate-telemetry; generated data, not law" + +[[entry]] +from = "REORGANIZATION-PLAN.adoc" +target = "9-archive/REORGANIZATION-PLAN.adoc" +district = "9-archive" +kind = "superseded" +files = 1 +lifecycle = "frozen" +canonical = false +canon_slot = "" +canonical_doc = "9-archive/REORGANIZATION-PLAN.adoc" +gate = "" +note = "superseded 2026-06-02; retained for provenance, must not read as current" + +[[entry]] +from = "0-AI-MANIFEST.a2ml" +target = "0-AI-MANIFEST.a2ml" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "0-AI-MANIFEST.a2ml" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "AGENTS.adoc" +target = "AGENTS.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "AGENTS.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "CHANGELOG.adoc" +target = "CHANGELOG.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "CHANGELOG.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "EXPLAINME.adoc" +target = "EXPLAINME.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "EXPLAINME.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "QUICKSTART-DEV.adoc" +target = "QUICKSTART-DEV.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "QUICKSTART-DEV.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "QUICKSTART-MAINTAINER.adoc" +target = "QUICKSTART-MAINTAINER.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "QUICKSTART-MAINTAINER.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "QUICKSTART-USER.adoc" +target = "QUICKSTART-USER.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "QUICKSTART-USER.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "README.adoc" +target = "README.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "README.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "ROADMAP.adoc" +target = "ROADMAP.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "ROADMAP.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "TOPOLOGY.adoc" +target = "TOPOLOGY.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "TOPOLOGY.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "llm-warmup-dev.adoc" +target = "llm-warmup-dev.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "llm-warmup-dev.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = "llm-warmup-user.adoc" +target = "llm-warmup-user.adoc" +district = "onramp" +kind = "onramp" +files = 1 +lifecycle = "versioned" +canonical = true +canon_slot = "" +canonical_doc = "llm-warmup-user.adoc" +gate = "canon-self-conformance" +note = "two canonical front doors (README.adoc human, 0-AI-MANIFEST.a2ml machine); every other doc is a thin pointer" + +[[entry]] +from = ".well-known" +target = ".well-known" +district = "root" +kind = "spine-mandated" +files = 4 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = ".well-known/index.adoc" +gate = "check-root-shape" +note = "must be at root because the spine's root-allow.txt requires it there" + +[[entry]] +from = ".editorconfig" +target = ".editorconfig" +district = "root" +kind = "spine-mandated" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = ".editorconfig" +gate = "check-root-shape" +note = "must be at root because the spine's root-allow.txt requires it there" + +[[entry]] +from = ".gitattributes" +target = ".gitattributes" +district = "root" +kind = "spine-mandated" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = ".gitattributes" +gate = "check-root-shape" +note = "must be at root because the spine's root-allow.txt requires it there" + +[[entry]] +from = ".gitignore" +target = ".gitignore" +district = "root" +kind = "spine-mandated" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = ".gitignore" +gate = "check-root-shape" +note = "must be at root because the spine's root-allow.txt requires it there" + +[[entry]] +from = "LICENSE" +target = "LICENSE" +district = "root" +kind = "spine-mandated" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "LICENSE/index.adoc" +gate = "check-root-shape" +note = "must be at root because the spine's root-allow.txt requires it there" + +[[entry]] +from = "NOTICE" +target = "NOTICE" +district = "root" +kind = "spine-mandated" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "NOTICE/index.adoc" +gate = "check-root-shape" +note = "must be at root because the spine's root-allow.txt requires it there" + +[[entry]] +from = "PALIMPSEST.adoc" +target = "PALIMPSEST.adoc" +district = "root" +kind = "spine-mandated" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "PALIMPSEST.adoc" +gate = "check-root-shape" +note = "must be at root because the spine's root-allow.txt requires it there" + +# ─────────────────────────────────────────────────────────────────────────── +# ADDED 2026-09-17 in the same change as the binding model (02-BINDING-MODEL.md). +# These two entries were caught by check-standards-map.sh assertion 2 on the +# first run after they were introduced — which is the gate doing its job. They +# are recorded here rather than exempted from the check. +# ─────────────────────────────────────────────────────────────────────────── + +[[entry]] +from = "canon.lock" +target = "canon.lock" +district = "0-canon" +kind = "law-release-identity" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "" +gate = "canon-spine-lockstep" +note = "NEW. The released identity of the canon: version + sha256 of every law artefact + the reusable-workflow refs. Gate A reads it. In [canon.lockstep] it declares its own five assertions." + +[[entry]] +from = "standards-map.toml" +target = "standards-map.toml" +district = "5-machine" +kind = "index" +files = 1 +lifecycle = "versioned" +canonical = false +canon_slot = "" +canonical_doc = "" +gate = "standards-map-verify" +note = "NEW. The map of this repository: one record per top-level entry, all 118. Checked bidirectionally by scripts/check-standards-map.sh (Gate D). index.adoc per district and machine-readable/map.a2ml are GENERATED from this file."