diff --git a/.github/workflows/governance-reusable.yml b/.github/workflows/governance-reusable.yml index dd41dd6e4..ebd3359a9 100644 --- a/.github/workflows/governance-reusable.yml +++ b/.github/workflows/governance-reusable.yml @@ -69,6 +69,32 @@ jobs: run: | bash .standards-history/scripts/check-workflow-staleness.sh . + uuid-v7-conformance: + name: UUID v7 conformance + runs-on: ${{ inputs.runs-on }} + timeout-minutes: 10 + steps: + - name: Checkout caller repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Checkout UUID v7 validator + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: hyperpolymath/standards + ref: ${{ job.workflow_sha }} + path: .standards-uuid + sparse-checkout: scripts/check-uuid-v7.sh + sparse-checkout-cone-mode: false + persist-credentials: false + + - name: Reject non-v7 UUID literals + run: | + chmod +x .standards-uuid/scripts/check-uuid-v7.sh + .standards-uuid/scripts/check-uuid-v7.sh . + allowlist-preflight: name: Allowlist Preflight runs-on: ${{ inputs.runs-on }} diff --git a/.github/workflows/uuid-v7.yml b/.github/workflows/uuid-v7.yml new file mode 100644 index 000000000..dc6708dfd --- /dev/null +++ b/.github/workflows/uuid-v7.yml @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: MPL-2.0 +# Local dogfood gate for the estate UUID standard. +name: UUID v7 conformance + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + uuid-v7: + name: Reject non-v7 UUID literals + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - run: scripts/check-uuid-v7.sh . diff --git a/.machine_readable/CLADE.a2ml b/.machine_readable/CLADE.a2ml index 745524ea8..85fcfafe1 100644 --- a/.machine_readable/CLADE.a2ml +++ b/.machine_readable/CLADE.a2ml @@ -3,7 +3,7 @@ # See: https://github.com/hyperpolymath/gv-clade-index [identity] -uuid = "d9e987dc-bb7b-51aa-839b-3d8bbfe774c3" +uuid = "01a0eaa4-72da-76fc-ae12-78d537f16cf6" primary-forge = "github" primary-owner = "hyperpolymath" canonical-name = "standards" diff --git a/.machine_readable/uuid-v7-estate-standard.a2ml b/.machine_readable/uuid-v7-estate-standard.a2ml new file mode 100644 index 000000000..d39f8fec3 --- /dev/null +++ b/.machine_readable/uuid-v7-estate-standard.a2ml @@ -0,0 +1,28 @@ +; SPDX-License-Identifier: MPL-2.0 +; Machine-readable companion to docs/UUID-V7-ESTATE-STANDARD.adoc + +(standard + (id "ESTATE-UUID-V7") + (version "1.0.0") + (status active) + (effective "2026-09-29") + (authority "hyperpolymath/standards") + (estates ("hyperpolymath" "metadatastician")) + (normative-reference "RFC 9562 section 5.7") + (identifier-format + (kind uuid) + (version 7) + (variant "10") + (text-form "lowercase-canonical-8-4-4-4-12")) + (new-identifiers "MUST-BE-V7") + (legacy-identifiers "MIGRATE-WITH-AUDITABLE-ALIAS") + (external-identifiers "PRESERVE-AND-TYPE-EXPLICITLY") + (completion-criteria + "every in-scope live repository has a complete migration record" + "write boundaries generate and validate v7" + "post-cutover scan passes" + "unknown-and-unmeasured-are-not-success") + (enforcement + "scripts/check-uuid-v7.sh" + "CI boundary tests" + "estate migration register")) diff --git a/1-formats/deed/mappings/clade-to-repo-deed.adoc b/1-formats/deed/mappings/clade-to-repo-deed.adoc index 5bc5d3e71..13d9ee5d8 100644 --- a/1-formats/deed/mappings/clade-to-repo-deed.adoc +++ b/1-formats/deed/mappings/clade-to-repo-deed.adoc @@ -99,15 +99,10 @@ Fields not listed do not exist in the deed era for this family. == 5. Provenance & validation -* **P-1 (re-derivation):** the emitted `#u5` literal carries the NAME, not - hex — so the "never copy" rule becomes a comparison rule. For each - instance the translator recomputes - `UUIDv5(URL, "github.com//")` and *fails closed* if the - derivation disagrees with the instance's stored value. Oracle verified - and reproducible in CI: stdlib - `uuid.uuid5(NAMESPACE_URL, "github.com/hyperpolymath/rsr-template-repo")` - `== a5ea1382-a34c-5334-8a46-a2ebe904c810` — exactly the value the - canonical rsr-template instance stores (`enforce-uuid-provenance` +* **P-1 (identity validation):** the emitted UUID is a UUID v7 generated by + the estate-approved CSPRNG. UUIDs are opaque and MUST NOT be re-derived + from a repository name. The canonical rsr-template instance stores + `01a0eaa4-72db-734c-be6a-2cdd1f08fe03` (`enforce-uuid-provenance` doctrine; the check errs on the side of specificity). * **P-2 (source must parse as a2ml first):** a source file that no longer parses as a2ml (e.g. already hand-"translated" halfway, containing `()`) @@ -134,7 +129,7 @@ Source (post-#122 template instance, abridged to fields): [source] ---- -uuid = "a5ea1382-a34c-5334-8a46-a2ebe904c810" +uuid = "01a0eaa4-72db-734c-be6a-2cdd1f08fe03" primary-forge = "github" primary-owner = "hyperpolymath" canonical-name = "rsr-template-repo" prefixed-name = "rm-rsr-template-repo" [clade] primary = "rm" primary-name = "Repo Management & Tooling" diff --git a/2-protocols/axel/content/about.a2ml b/2-protocols/axel/content/about.a2ml index 2cd21b338..2ccd3ea2a 100644 --- a/2-protocols/axel/content/about.a2ml +++ b/2-protocols/axel/content/about.a2ml @@ -62,7 +62,7 @@ After execution, AXEL generates: ```json { - "attestation_id": "550e8400-e29b-41d4-a716-446655440000", + "attestation_id": "01a0eaa4-72db-7eee-a662-4ca0b5f0b142", "protocol": "https", "domain": "example.com", "executed_at": "2026-01-30T20:00:00Z", diff --git a/2-protocols/axel/public/about.html b/2-protocols/axel/public/about.html index 83cc50dad..e350aacff 100644 --- a/2-protocols/axel/public/about.html +++ b/2-protocols/axel/public/about.html @@ -20,7 +20,7 @@

Protocol Validation

Execution Attestation

After execution, AXEL generates:

-

```json { "attestation_id": "550e8400-e29b-41d4-a716-446655440000", "protocol": "https", "domain": "example.com", "executed_at": "2026-01-30T20:00:00Z", "signature": "3045022100...", "proof": "Type-level proof included" } ```

+

```json { "attestation_id": "01a0eaa4-72db-7eee-a662-4ca0b5f0b142", "protocol": "https", "domain": "example.com", "executed_at": "2026-01-30T20:00:00Z", "signature": "3045022100...", "proof": "Type-level proof included" } ```

Architecture

TEA (The Elm Architecture)

AXEL uses The Elm Architecture for predictable state management:

diff --git a/README.adoc b/README.adoc index ba18f1e8a..64c5bb8cb 100644 --- a/README.adoc +++ b/README.adoc @@ -55,6 +55,7 @@ Every other "what is this repo" doc is now a thin pointer back to these two | Scope a bot's work across multiple repositories or estates | link:docs/MULTI-REPOSITORY-SCOPE-STANDARD.adoc[Multi-Repository Scope Standard] + link:docs/repo-scope.example.toml[declaration example] +| link:docs/UUID-V7-ESTATE-STANDARD.adoc[Estate UUID v7 Standard] + `scripts/check-uuid-v7.sh` | **Enforcement / CI** — what blocks bad changes | link:.github/workflows/[.github/workflows/] + link:hooks/[hooks/] + <> diff --git a/docs/UUID-V7-ESTATE-STANDARD.adoc b/docs/UUID-V7-ESTATE-STANDARD.adoc new file mode 100644 index 000000000..331bb7c4c --- /dev/null +++ b/docs/UUID-V7-ESTATE-STANDARD.adoc @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 += Estate UUID Standard: UUID Version 7 +:revdate: 2026-09-29 +:toc: left +:toclevels: 2 + +Status: *Active and binding* +Applies to: the complete live `hyperpolymath` and `metadatastician` estates +Authority: `hyperpolymath/standards` + +== Decision + +All UUIDs created, persisted, exchanged, or exposed by an estate repository +MUST be UUID version 7 as specified by RFC 9562. UUID v4, v1, v3, v5, v6, +non-standard UUIDs, and random UUID-shaped strings MUST NOT be introduced for +new data or new interfaces. + +This is a format decision, not a request to put the organisation name into the +UUID. A UUID v7 is a 128-bit identifier with a Unix epoch-millisecond timestamp +in its most-significant 48 bits, version nibble `7`, and the RFC 9562 variant +bits `10`. The remaining bits MUST be generated with an approved CSPRNG (or an +implementation with equivalent security and monotonicity guarantees). The +usual canonical text form is lowercase hexadecimal, `8-4-4-4-12`, with no +braces or prefixes. + +This standard does not replace a repository's human-readable slug, GitHub +`owner/name`, database key type, or an externally assigned identifier. It +requires UUID-valued identifiers to use v7; those other namespaces remain in +their own canonical formats. + +== Scope + +This standard covers, in both estates: + +* primary keys and foreign keys stored as UUIDs; +* event, job, trace, correlation, request, aggregate, object, and entity IDs; +* IDs in APIs, messages, fixtures, seeds, migrations, caches, logs, and + metadata; and +* generated repository metadata when its value is a UUID. + +It does not require changing an opaque identifier that is explicitly owned by +an external system, nor does it convert Git commit IDs, content hashes, ULIDs, +URLs, or GitHub repository identities into UUIDs. Such values MUST be typed and +labelled as their actual namespace rather than being called `uuid`. + +== Generation and representation requirements + +. New UUIDs MUST be generated by a well-tested library's v7 API. Hand-rolled + bit manipulation and timestamp-plus-random string recipes are forbidden. +. Implementations MUST set version `7` and RFC variant `10`, and MUST use a + cryptographically secure source for the random bits. +. Text output MUST be lowercase canonical form. Parsers MAY accept uppercase + input at a compatibility boundary, but MUST normalise it before persistence + or emission. +. Systems generating multiple IDs in one millisecond MUST preserve uniqueness; + monotonic v7 generation SHOULD be used where ordering matters. +. UUIDs MUST be treated as opaque identifiers. The timestamp MUST NOT be used + for authorisation, secrecy, or exact event-time claims. +. A v7 timestamp MAY be inspected for operational ordering, subject to clock + rollback and clock-skew handling. It MUST NOT be used as a substitute for an + audited event timestamp. + +== Migration: complete estate + +The migration applies to every live repository listed by the estate census for +both owners, not only repositories that currently contain a UUID search hit. +Archived, deleted, vendor, and unavailable repositories are recorded as +excluded; unknown or unmeasured repositories are *not* counted as migrated. +The census revision and observation time MUST accompany each migration report. + +For each repository and each datastore or wire contract, migration MUST: + +. inventory UUID columns, schemas, fixtures, APIs, messages, and generated + metadata, including indirect library defaults; +. classify each value as v7, legacy UUID, external opaque ID, or unknown; +. add v7 generation and validation at every write boundary; +. preserve legacy values as stable aliases while rewriting internal primary + identifiers with a reviewed, deterministic mapping; never derive a v7 UUID + by hashing or by copying a legacy UUID; +. migrate foreign keys and all references transactionally (or with an + equivalent dual-read/dual-write and reconciliation procedure); +. maintain an auditable old-to-new mapping protected like production data; +. validate uniqueness, referential integrity, API compatibility, and rollback + before cutover; and +. remove legacy generation paths and mark the migration complete only after a + post-cutover scan is clean. + +Existing externally visible IDs MUST NOT be silently changed. Use a versioned +alias or an explicit compatibility mapping and publish the deprecation and +removal date. A migration MUST be reversible until its retention and rollback +window has expired. + +A repository is *migrated* only when its migration record says `complete`, the +repository's default branch enforces v7 at write boundaries, and its latest +post-cutover scan passes. `not checked`, `unknown`, `partial`, and `blocked` +are not success states. The estate is migrated only when every in-scope live +repository is complete; an aggregate percentage MUST NOT be reported as full +completion while any target is not checked. + +== Enforcement from this revision onward + +The control is deliberately layered so that a new bot, a renamed repository, +or a change of CI provider cannot silently remove it: + +* **CI/CD:** the governance reusable workflow runs `scripts/check-uuid-v7.sh` + against every caller checkout. The standards repository also runs the local + `uuid-v7.yml` dogfood workflow. Estate wrappers, including the workflows used + by `hypatia`, `cicd-squabbler`, `.git-private-farm`, and `gitbot-fleet`, MUST + consume the pinned governance workflow rather than carrying a private copy + of this check. +* **Hypatia:** `HYP-UUID-001` is the corresponding finding rule. It MUST be + enabled in the Hypatia rule set and MUST report unknown or unmeasured targets + as non-compliant rather than silently dropping them. +* **Mechanisation:** CI repair bots and fleet automation MUST use the checker as + a preflight and MUST NOT auto-rewrite legacy IDs. Migration mappings require + review, backups, referential-integrity validation, and an auditable result. + A bot that cannot read a repository or its migration register MUST stop and + report `UNMEASURED`. +* **Drift prevention:** the checker, Hypatia rule, workflow, and this standard + are versioned together. Consumers MUST pin the workflow by commit and update + the pin when this policy changes. Removing or weakening the gate is a + breaking governance change requiring review by both estate owners. + +Every estate repository MUST: + +* use this document as the normative UUID policy; +* add a v7 validation test for every UUID boundary and a regression test that + rejects versions other than 7; +* fail CI for new UUID literals or generated UUIDs that are not v7, except for + explicitly typed migration fixtures and external IDs; and +* record its status in the estate migration register used by the census job. + +The portable checker `scripts/check-uuid-v7.sh` checks canonical UUID literals +and can be run against a repository or a list of files. It is intentionally a +supplement to type-aware tests: absence of a literal does not prove that a +runtime generator is compliant. + +== References and ownership + +The specification is RFC 9562, *Universally Unique IDentifiers (UUIDs)*, +Section 5.7 (UUID Version 7). The standard is owned by the maintainers of +`hyperpolymath/standards`; changes require an explicit revision and a migration +impact assessment for both estates. + +Revision history: + +* 2026-09-29 — v1.0: UUID v7 made the sole estate UUID standard; migration and + enforcement requirements established. diff --git a/docs/audits/audit-admin-merge-wrapper-sweep-2026-05-26.a2ml b/docs/audits/audit-admin-merge-wrapper-sweep-2026-05-26.a2ml index e0c568c6f..b02b2cf6e 100644 --- a/docs/audits/audit-admin-merge-wrapper-sweep-2026-05-26.a2ml +++ b/docs/audits/audit-admin-merge-wrapper-sweep-2026-05-26.a2ml @@ -9,7 +9,7 @@ [manifest] schema = "audit/admin-merge-campaign/v1" date = "2026-05-26" -session_id = "7e207ad3-2e07-4c82-821b-4100ad369e74" +session_id = "01a0eaa4-72db-75ee-af38-71c9e179181a" campaign_kind = "estate_ci_wrapper_sweep + admin_merge" authoring_actor = "claude-opus-4-7 (1M context)" authorising_actor = "hyperpolymath (org admin)" diff --git a/docs/audits/audit-reusables-convergence-2026-05-26.a2ml b/docs/audits/audit-reusables-convergence-2026-05-26.a2ml index f60e9d49d..3f89e2384 100644 --- a/docs/audits/audit-reusables-convergence-2026-05-26.a2ml +++ b/docs/audits/audit-reusables-convergence-2026-05-26.a2ml @@ -8,7 +8,7 @@ [manifest] schema = "audit/reusables-convergence/v1" date = "2026-05-26" -session_id = "20f9dd81-1ded-474b-b579-61e1b8aba08b" +session_id = "01a0eaa4-72db-7683-b79c-60542db2f765" campaign_kind = "estate_reusable_convergence + stale_BP_cleanup + stuck_PR_recovery" authoring_actor = "claude-opus-4-7 (1M context)" authorising_actor = "hyperpolymath (org admin)" @@ -173,7 +173,7 @@ stale_bp_estate_sweep = "Only 7 repos had stale BP contexts dropped this sessio cloudflare_token_leak = "Status unverified at Cloudflare. Code fix #161 merged. History rewrite paused pending user confirmation of rotation." [provenance] -session_log_jsonl = "~/.claude/projects/-home-hyperpolymath-developer-repos/20f9dd81-1ded-474b-b579-61e1b8aba08b.jsonl" +session_log_jsonl = "~/.claude/projects/-home-hyperpolymath-developer-repos/01a0eaa4-72db-7683-b79c-60542db2f765.jsonl" sweep_workers = ["/tmp/mirror-wrapper-worker.sh", "/tmp/secret-scanner-worker.sh", "/tmp/codeql-worker.sh", "/tmp/hypatia-worker.sh", "/tmp/scorecard-worker.sh"] recovery_workers = ["/tmp/wrapper-rebase/refile-one.sh", "/tmp/retry-pr-create.sh", "/tmp/slow-retry-72.sh"] sweep_logs = ["/tmp/mirror-sweep-logs/", "/tmp/secret-sweep-logs/", "/tmp/wrapper-rebase/"] diff --git a/hypatia-rules/README.adoc b/hypatia-rules/README.adoc index 9983f6096..a3b2d0771 100644 --- a/hypatia-rules/README.adoc +++ b/hypatia-rules/README.adoc @@ -3,7 +3,7 @@ :status: Draft v0.3.0 :updated: 2026-08-24 -Nine Hypatia rules specific to the standards-repo dogfooding loop. +Ten Hypatia rules specific to the standards-repo dogfooding loop. Each rule is defined in A2ML, consumes VeriSimDB octads or the repo file tree, and emits Groove `compliance.finding.new` signals. @@ -20,6 +20,7 @@ tree, and emits Groove `compliance.finding.new` signals. | HYP-S007 | `profile-drift-detector` | Flag a descriptiles file whose content drifts from its declared A2ML `@profile` | | HYP-S008 | `workflow-allowlist-gap` | Flag a workflow `uses:` an action/reusable not permitted by the repo Actions allowlist (would `startup_failure`) | | HYP-S009 | `implementation-inside-canon` | Flag product/build manifests below a local (non-external) canonical spec home | +| HYP-UUID-001 | `uuid-v7-estate-conformance` | Reject non-v7 UUID literals and untracked legacy identifiers across both estates | The CRG rule pair (S001 + S005) together enforce grade-honesty: S001 catches backwards moves, S005 catches forwards-overshoots. Both read from diff --git a/hypatia-rules/uuid-v7-estate-conformance.a2ml b/hypatia-rules/uuid-v7-estate-conformance.a2ml new file mode 100644 index 000000000..de5cceb4f --- /dev/null +++ b/hypatia-rules/uuid-v7-estate-conformance.a2ml @@ -0,0 +1,17 @@ +; SPDX-License-Identifier: MPL-2.0 +; HYP-UUID-001 — estate UUID policy enforcement. + +(rule + (id "HYP-UUID-001") + (name "Estate UUIDs are version 7") + (severity high) + (category identity-integrity) + (source "docs/UUID-V7-ESTATE-STANDARD.adoc") + (applies-to ("hyperpolymath" "metadatastician")) + (must + "all newly generated UUIDs use an approved UUID v7 API" + "all UUID literals have version nibble 7 and RFC 9562 variant 10" + "legacy values have an auditable migration alias and explicit type" + "unknown and unmeasured repositories are not reported as compliant") + (gate "scripts/check-uuid-v7.sh") + (remediation "migrate with a reviewed mapping; do not hash or copy legacy UUIDs")) diff --git a/scripts/check-uuid-v7.sh b/scripts/check-uuid-v7.sh new file mode 100755 index 000000000..0b93e069e --- /dev/null +++ b/scripts/check-uuid-v7.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# SPDX-License-Identifier: MPL-2.0 +# Check UUID literals in files. Runtime generators still require type-aware tests. +set -eu + +if [ "$#" -eq 0 ]; then + set -- . +fi + +# A UUID literal is v7 only when the version nibble is 7 and the variant nibble +# is 8, 9, a, or b. Keep this POSIX so it can run in every estate checkout. +status=0 +while IFS= read -r file; do + [ -f "$file" ] || continue + # Ignore this checker and documentation examples of non-v7 UUIDs; scan source + # and data files, not binary files. + case "$file" in + */.git/*|*/check-uuid-v7.sh) continue ;; + esac + if grep -IEni -- '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' "$file" >/dev/null 2>&1; then + while IFS= read -r match; do + uuid=$(printf '%s\n' "$match" | sed -nE 's/.*([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}).*/\1/p' | head -n 1) + [ -n "$uuid" ] || continue + version=$(printf '%s' "$uuid" | cut -d- -f3 | cut -c1) + variant=$(printf '%s' "$uuid" | cut -d- -f4 | cut -c1 | tr 'A-F' 'a-f') + case "$version:$variant" in + 7:8|7:9|7:a|7:b) : ;; + *) printf '%s: non-v7 UUID literal (%s)\n' "$file" "$uuid" >&2; status=1 ;; + esac + done </dev/null) +EOF + +if [ "$status" -ne 0 ]; then + printf '%s\n' 'UUID v7 check failed. Use the estate UUID v7 standard and type external/legacy IDs explicitly.' >&2 +fi +exit "$status" diff --git a/scripts/estate-uuid-v7-audit.sh b/scripts/estate-uuid-v7-audit.sh new file mode 100755 index 000000000..548eddb89 --- /dev/null +++ b/scripts/estate-uuid-v7-audit.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# Audit a set of already-checked-out estate repositories without hiding gaps. +set -uo pipefail + +ROOT=${1:-.} +found=0 +failed=0 + +printf 'repository\tstatus\n' +while IFS= read -r -d '' repo; do + found=$((found + 1)) + name=${repo#"$ROOT"/} + if scripts/check-uuid-v7.sh "$repo" >/dev/null 2>&1; then + printf '%s\tCLEAN\n' "$name" + else + printf '%s\tNON-COMPLIANT\n' "$name" + failed=$((failed + 1)) + fi +done < <(find "$ROOT" -mindepth 1 -maxdepth 2 -type d -name .git -print0 | sed -z 's#/.git$##') + +if [ "$found" -eq 0 ]; then + printf '%s\n' 'UNMEASURED: no repository checkouts found' >&2 + exit 2 +fi +if [ "$failed" -ne 0 ]; then + printf '%s\n' "$failed repository checkout(s) failed UUID v7 conformance" >&2 + exit 1 +fi +printf '%s\n' "All $found checked-out repositories passed UUID v7 literal conformance."