diff --git a/.machine_readable/template-capability-gates.toml b/.machine_readable/template-capability-gates.toml index d99d652d..99f023ef 100644 --- a/.machine_readable/template-capability-gates.toml +++ b/.machine_readable/template-capability-gates.toml @@ -10,12 +10,16 @@ # Arrays are kept single-line so the checker can parse them with grep. [meta] -version = "0.1.0" +version = "0.2.0" policy = "TEMPLATE-APPLICABILITY-POLICY.adoc" [capabilities] # Every capability a profile may declare. -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" = code hosted inside a third-party extension host (WordPress, +# 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"] [baseline] # Always carried (gate = empty). Globs/dirs allowed; not capability-gated. @@ -55,3 +59,9 @@ rust-service = ["rust", "api-service", "container", "reproducible-build"] formal-proof-lib = ["formal-proofs", "library"] docs-site = ["docs-site"] affinescript-app = ["affinescript", "web-ui"] +# Archetype presets (rsr-template-repo archetypes/ carry the matching name; +# see spec/SCAFFOLD-LIFECYCLE.adoc and rsr-template-repo ADR-0003). +julia-library = ["julia", "library", "docs-site", "published-package"] +wordpress-plugin = ["plugin", "web-ui"] +zotero-plugin = ["plugin"] +userscript = ["plugin"] diff --git a/rhodium-standard-repositories/spec/REPO-STANDARD-MUST-INTEND-LIKE.adoc b/rhodium-standard-repositories/spec/REPO-STANDARD-MUST-INTEND-LIKE.adoc new file mode 100644 index 00000000..1499b7f2 --- /dev/null +++ b/rhodium-standard-repositories/spec/REPO-STANDARD-MUST-INTEND-LIKE.adoc @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// Relocated 2026-07-21 from rsr-julia-library-template-repo (its VARIANT.a2ml +// lists it under paths.added). The document is explicitly language-agnostic +// and belongs in the canon; the variant-side copy is retired separately. += Universal Repo Standard (Must / Intend / Like) + +This document is designed as a reusable baseline for *every* repository (Julia and non-Julia). +It combines dependability, security, accessibility, interoperability, functionality, performance, +and data/information governance into one operational standard. + +Use this as: + +* A repo bootstrap checklist +* A release-readiness checklist +* A policy reference for CI/CD gates + +== Top-Level Principles (Apply To Every Repo) + +1. Dependability: deterministic behavior, graceful failure, and observable recovery. +2. Security: secure-by-default design, supply-chain integrity, least privilege. +3. Accessibility: inclusive UX and docs, equivalent access to critical workflows. +4. Interoperability: stable contracts, versioned interfaces, compatibility guarantees. +5. Functionality: features are complete, correct, and match documented claims. +6. Performance: measurable baselines, regression protection, explicit budgets. +7. Data/Information Governance: data classification, minimization, lineage, retention, and deletion controls. + +== Minimum Files In Every Repo + +Must include: + +* `README` (what it does, supported scope, quickstart, known limits) +* `ROADMAP` (Must/Intend/Like or equivalent staged plan) +* `CHANGELOG` (user-visible changes and migration impact) +* `SECURITY.md` (reporting + hardening posture) +* `LICENSE` +* `CONTRIBUTING` (workflow and quality gates) +* `CODEOWNERS` or `MAINTAINERS` +* CI workflow(s) for test + lint + dependency/security checks +* Reproducible dependency lock strategy (language-specific) +* Operational runbook or `docs/ops` for incident response + +== MUST (Non-Negotiable Baseline) + +=== Dependability + +* No silent corruption or "fake" token values for critical outputs. +* Explicit failure modes and fallback policy per critical path. +* Health checks and structured diagnostics for runtime paths. +* Fault counters (errors, fallbacks, recoveries) with alert thresholds. +* Deterministic CI tests for happy path + failure path + fallback behavior. + +=== Security + +* Threat model exists and is reviewed periodically. +* Secrets never committed; managed via secure runtime secret injection. +* Dependency scanning + SAST + license checks in CI. +* Signed releases/artifacts where supported. +* Principle of least privilege for CI, runtime identities, and tokens. + +=== Containers And Images (High-Security Ready) + +* Pinned base images by digest; avoid floating tags in production. +* Non-root runtime user; read-only root filesystem when possible. +* Drop unnecessary Linux capabilities; avoid privileged containers. +* SBOM generation + vulnerability scanning + policy gate. +* Image signing and provenance attestation in release pipeline. +* Explicit runtime constraints (seccomp/AppArmor/SELinux as applicable). + +=== Interoperability And API Contracts + +* Versioned API/ABI contracts with compatibility expectations. +* Contract tests for REST/gRPC/GraphQL/FFI boundaries. +* Backward-compatibility policy and deprecation lifecycle. +* Clear error taxonomy (retryable vs non-retryable) and status semantics. + +=== Functionality And Correctness + +* Documentation claims must match tested behavior. +* Acceptance tests for each "shipped" feature claim. +* No unresolved critical work markers in production code paths. +* Release checklist gates must pass before merge/release. + +=== Performance + +* Baseline benchmarks for critical operations and key backends. +* Regression thresholds enforced in CI where baselines exist. +* Performance evidence artifacts retained from CI runs. +* Resource budgets (latency, memory, CPU, I/O) defined for critical flows. + +=== Data/Information Governance + +* Data classification policy (public/internal/confidential/restricted). +* Data minimization and purpose limitation documented. +* Retention and deletion policy documented and testable. +* Audit trails for critical decisions and transformations. +* Encryption requirements for data at rest/in transit documented. + +=== Accessibility + +* User-facing interfaces meet baseline accessibility criteria. +* Docs include plain-language quickstarts and operational troubleshooting. +* Keyboard-only and screen-reader considerations for web UI repos. + +== INTEND (Planned, High-Value Next Layer) + +=== Dependability + +* Circuit breakers and adaptive retry with backoff/jitter. +* Chaos/fault-injection tests in non-production environments. +* Automatic quarantine of persistently failing backends/providers. +* Error budget policy tied to SLOs. + +=== Security + +* Mandatory security review for high-impact changes. +* Ephemeral credentials and workload identity adoption. +* Continuous policy-as-code validation (admission controls, OPA, etc.). +* Signed commits/tags and stricter branch protection. + +=== Containers/Runtime + +* Distroless/minimal images for production workloads. +* Runtime sandboxing for untrusted workloads. +* Dedicated hardened node pools for sensitive workloads. +* Provenance verification at deploy time. + +=== Interoperability + +* Multi-version compatibility test matrix (N-1, N, N+1 where applicable). +* Golden test vectors for serialization/protocol compatibility. +* SDK/client conformance tests against reference server behavior. + +=== Functionality + +* Formalized "definition of done" templates by feature type. +* Auto-generated API docs from source contracts. +* Domain-specific invariants/property tests. + +=== Performance + +* Automated trend dashboards with release-over-release comparisons. +* Capacity modeling and saturation testing. +* Hardware-specific tuning profiles validated by CI evidence. + +=== Data Governance + +* Data lineage map and classification tagging automation. +* Policy checks that block non-compliant schema/data changes. +* Differential privacy/redaction controls where needed. + +=== Accessibility + +* Automated accessibility checks in CI for UI repos. +* Accessibility issue triage and SLA policy. + +== LIKE (Aspirational Or Context-Dependent) + +* Formal verification for high-assurance modules. +* Multi-region active-active resilience for critical services. +* Reproducible builds with full hermetic toolchains. +* Runtime self-optimization under strict safety guards. +* Advanced provenance federation across polyrepo ecosystems. +* Organizational scorecards across all principles per repo. + +== Suggested CI Gates (Portable Template) + +Must gates: + +* Build + unit/integration tests +* Contract tests (APIs/ABI/FFI) +* Failure-mode and fallback tests +* Lint/style/static checks +* Vulnerability + license scans +* Performance regression checks (where baseline exists) +* Documentation claim alignment checks + +Evidence artifacts: + +* Test results +* Security scan reports +* Benchmark/performance evidence +* Capability/diagnostic snapshots +* SBOM + provenance attestations (release) + +== Practical Scope Control (To Avoid "Infinite Work") + +Apply this in tiers: + +1. Tier 1 (immediate): production-critical paths and externally exposed interfaces. +2. Tier 2 (next): high-usage internal paths and integration boundaries. +3. Tier 3 (later): low-risk or experimental components. + +Do not block all progress on full perfection. Gate by risk and blast radius. + +== Policy On Fallback Values + +For critical computation and security-sensitive flows: + +* Do not substitute dummy/token values silently. +* Prefer: retry -> alternate backend/path -> explicit failure. +* Every recovery or degradation event must be observable. + +For non-critical optional fields: + +* Defaults are acceptable only with clear provenance and policy. + +== How To Reuse In Other Repos + +Copy this file and then customize: + +* Language-specific tooling sections +* API and data governance specifics +* Backend matrix and performance budgets +* Regulatory/compliance requirements + +Keep the principle set and Must baseline intact unless a stronger control replaces it. diff --git a/rhodium-standard-repositories/spec/SCAFFOLD-LIFECYCLE.adoc b/rhodium-standard-repositories/spec/SCAFFOLD-LIFECYCLE.adoc new file mode 100644 index 00000000..b95c15dc --- /dev/null +++ b/rhodium-standard-repositories/spec/SCAFFOLD-LIFECYCLE.adoc @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) += Scaffold Lifecycle — Forge & Sustain +Jonathan D.A. Jewell +:toc: +:sectnums: + +*Status: draft* (companion to `RSR-SPEC-v2.adoc`; the decision record is +`hyperpolymath/rsr-template-repo` ADR-0003, _Forge and Sustain lifecycle_). +MUST NOT be cited as ratified until the owner accepts ADR-0003. + +== Purpose + +This document is the normative statement of the estate's repository +lifecycle: how a repository is *forged* from the template system — minted, +provisioned, configured, harnessed — and how it is *sustained* afterwards — +corrective, adaptive, perfective, preventive — with the owning tool named for +every stage. It exists because the machinery already exists but was +disconnected: each stage below cites the mechanism that implements it today +and, where the mechanism is missing, says so honestly rather than describing +an aspiration as fact. + +== Roles + +The scaffolding stack is `standards → rsr-template-repo → scaffoldia → +(estate repos)`, measured by hypatia and repaired by the fleet. Exactly one +repo owns each concern; a change belongs at its owning layer (doctrine: +solutions at source). + +[cols="1,2,4"] +|=== +| Role | Owner | Owns + +| *Canon* +| `hyperpolymath/standards` +| WHAT a conforming repo is: `rsr-criteria-v2.a2ml` (the criteria SSOT), + `TEMPLATE-APPLICABILITY-POLICY.adoc` + `template-capability-gates.toml` + (the capability vocabulary and presets), this document, the reusable + workflows every repo calls. + +| *Spine* +| `hyperpolymath/rsr-template-repo` +| HOW a repo is born: the canonical template tree, `just init`, the + archetype overlays (`archetypes/`), the variant/provenance contract + (ADR-0002 `VARIANT.a2ml`) and its drift gate. + +| *Composer* +| `hyperpolymath/scaffoldia` +| Composition and retrofit at scale (spine@pin × archetype/pack × features × + profile). Design phase; it *consumes* the spine's contracts as data and + MUST NOT define its own divergent contract formats. + +| *Oracle* +| `hyperpolymath/hypatia` (`rsr-conformance` rule family, + `mix hypatia.rsr_score`) +| MEASUREMENT: the ONE normative conformance checker (RSR-SPEC-v2 §oracle). + Applicable set comes from each repo's `.machine_readable/rsr-profile.a2ml`. + +| *Fleet* +| `hyperpolymath/gitbot-fleet` + `reposystem` megasweep +| SUSTAIN execution: read-only estate detectors, owner-gated `fix-*` + recipes, fan-out PR campaigns. +|=== + +== Forge — the four stages + +A repository is *forged* when all four stages are complete. The stages are +ordered; each has normative exit criteria. A repo that stops after Mint — the +historical norm — is exactly the "one-shot copy" failure named in the +rsr-template-repo-experiment review (05-ZIGZAG §2.2). + +=== Mint + +The repository tree comes into existence from the spine plus at most one +archetype overlay: GitHub "Use this template" or a clone, then `just init +[archetype]`, which renders every placeholder, derives identity +(UUIDv5 of `forge/owner/repo` — computed, never guessed), installs the +child's own `CLADE.a2ml`, writes the child's `rsr-profile.a2ml`, and records +provenance (see <>). + +Exit criteria (MUST): + +* zero `{{TOKEN}}` placeholders remain (`scripts/check-no-placeholders.sh` + passes); +* `CLADE.a2ml` carries the derived uuid; judgement-only fields read + `UNASSIGNED`, not invented values; +* `.machine_readable/rsr-profile.a2ml` exists and declares only capabilities + the tree actually carries (na-honesty, RSR-SPEC-v2 §scoring); +* the provenance record of <> exists. + +=== Provision + +Toolchains named by the repo's capability set are installed *and executed* — +`just build`/`just test` (or the archetype's recorded commands) run to +completion on the minting machine or in CI. Echoed advice is not +provisioning; a gate that exits 0 when its prover is absent is not +provisioning (the proof-gates lesson: 54 repo roots where `just +proof-check-*` could never fail). + +Exit criteria (MUST): every command recorded in the archetype's token table +(`BUILD_CMD`, `TEST_CMD`) has been run and observed to succeed, or the +failure is recorded in `STATE.a2ml` as a blocker — never silently skipped. + +=== Configure + +Repository identity and platform state are set *out of band*, exactly once: +name, description, homepage, visibility via `gh repo edit`/UI; branch +protection whose required contexts each equal an emitted job *id*; the +probot `settings.yml` inherited from the spine manages only child-safe +fields. This stage is out-of-band *by design*, not by omission: the `-REPO-` +incident (2026-07-20) proved that identity keys in a probot-managed template +file rename live repositories. + +Exit criteria (MUST): + +* `.github/settings.yml` contains no `name`, `description`, `homepage` or + `private` key; +* every required status-check context equals the job id of a workflow that + actually reports on this repo (an unreported context deadlocks the branch); +* visibility is a deliberate owner decision, fail-closed private by default; +* the repo is registered in `gv-clade-index`. + +=== Harness + +The sustain machinery is attached and observed working: CI green (or every +red accounted for), the drift gate armed against the recorded parent-pin, +dependabot/scorecard running, and the oracle able to score the repo. + +Exit criteria (MUST): + +* `scripts/check-variant-drift.sh ` runs and PASSes against the + provenance contract; +* `mix hypatia.rsr_score` produces a scorecard (provisional is acceptable; + absent is not); +* no gate uses `continue-on-error` or an always-zero fallback (a gate that + cannot fail is worse than no gate). + +[#provenance] +== The provenance requirement (keystone) + +Every forged repository MUST record, in +`.machine_readable/descriptiles/VARIANT.a2ml` (the ADR-0002 contract shape +with `direction = "generated-from-core"`): + +* `parent` — the template repo it was minted from; +* `parent-pin` — the template commit at mint (or `UNASSIGNED` until first + reconcile, never a guessed value); +* the archetype applied, if any; +* path lists (`added` / `removed` / `diverged`) as the repo diverges. + +Rationale: this is the estate's answer-file. External best practice (Copier's +`.copier-answers.yml`, Cruft's `.cruft.json`) shows that a template without +recorded provenance is structurally one-shot — improvements cannot be +propagated, drift cannot be detected, and the estate's recurring manual +standardisation campaigns are the direct symptom. A repo without a recorded +parent-pin is *un-sustainable* in the sense of this document: Adaptive +maintenance (below) has no defined input for it. One contract format serves +all three populations — variant templates (`direction = +"template-is-source"`), minted repos, and retrofitted repos (both +`generated-from-core`) — so the drift gate is also the estate's `cruft +check`. + +== Sustain — the four modes + +[cols="1,3,2"] +|=== +| Mode | Definition and normative rule | Owning tool + +| *Corrective* +| Restore a broken invariant: red CI, a failed gate, a hypatia finding. + Diagnose before acting — zero-step failures on private repos are billing, + not code; `startup_failure` has two known root causes (actions-policy + allowlist, reusable permissions). Fix at the owning layer (a template + defect is fixed in the spine, once, not in N children). +| gitbot-fleet `fix-*` recipes (owner-gated); hypatia findings + +| *Adaptive* +| Absorb upstream change: bump `parent-pin` after reconciling with the + spine, re-pin action SHAs, adopt new canon versions. The fan-out form is a + scheduled campaign producing one reviewable PR per repo — never an + unrecorded bulk mutation. Licence anything is FLAG-ONLY, never automated. +| drift gate (detect); megasweep (fan-out, audit-first); dependabot + +| *Perfective* +| Raise the tier: score with the oracle, close the gap to the next + threshold (Bronze 75 / Silver 90 / Gold 100), promote variant-first fixes + upstream (the `diverged-pending-upstream` list is a standing, exact + worklist), expand the declared capability set only when the module + actually lands. +| `mix hypatia.rsr_score`; the spine's change-lab + +| *Preventive* +| Keep gates honest before they are needed: canary-test every gate in both + directions (a gate is proven by making it fail), placeholder guard on + every push, drift-gate cron, no aspirational required contexts, probot + files identity-free. +| the spine's `scripts/check-*` suite; weekly drift-gate cron +|=== + +== Autonomy boundaries + +What may run unattended versus what requires the owner: + +* *Unattended (read-only)*: detectors, drift checks, scoring, audits, + report generation. megasweep's apply-mode is deliberately unbuilt; keep it + that way until each mutation class is individually owner-ratified. +* *Owner-gated (mutation)*: any fan-out PR campaign (audit first, apply on + approval), pin bumps that touch more than one repo, visibility or identity + changes, branch-protection changes. +* *Never automated*: licence and SPDX edits (flag-only, permanent estate + rule), history rewrites, deletion of repos or of `-REPO-`-style artefacts + without the owner reading the audit first. + +== Conformance + +The lifecycle stages map onto RSR v2.0 criteria (categories: Lifecycle +Management, CI/CD & Enforcement, Machine-Readable Substrate). The oracle +scores the artefacts this document mandates (`rsr-profile.a2ml` presence is +criterion 3.2.2; the provenance contract is surfaced to the composer). A +future MINOR of `rsr-criteria-v2.a2ml` MAY add a criterion for the +provenance record once the mechanism has shipped in the spine and been +exercised by at least one minted repo — criteria follow proven mechanisms, +not the reverse. diff --git a/scripts/check-rsr-profile.sh b/scripts/check-rsr-profile.sh index 35d34e78..838a6c4a 100755 --- a/scripts/check-rsr-profile.sh +++ b/scripts/check-rsr-profile.sh @@ -28,16 +28,31 @@ PROFILE="$REPO/.machine_readable/rsr-profile.a2ml" section() { awk -v s="[$1]" '$0==s{f=1;next} /^\[/{f=0} f && !/^[[:space:]]*#/ && NF' "$2"; } # "quoted" tokens on the line whose key is $1 (reads section body from stdin). quoted_on_key() { grep -E "^[[:space:]]*$1[[:space:]]*=" | grep -oE '"[^"]+"' | tr -d '"' || true; } +# Same, but the array may span lines (`key = [` … `]`) with trailing comments — +# the shape rsr-template-repo ships in its rsr-profile.a2ml, and one the +# oracle's record-dialect parser accepts, so this checker must too. The gates +# file itself stays single-line (its own header mandates that discipline). +array_on_key() { # $1 = key; section body on stdin + awk -v k="$1" ' + on { sub(/#.*/, ""); print; if (/\]/) on=0; next } + $0 ~ "^[[:space:]]*"k"[[:space:]]*=" { sub(/#.*/, ""); print; if (!/\]/) on=1 } + ' | grep -oE '"[^"]+"' | tr -d '"' || true +} # --- target profile --- # Capability declaration is primary: a profile may list `capabilities = [...]` # directly. `preset` is optional sugar — a named bundle expanded from the gate # data. A profile must provide at least one of the two. -PBODY="$(section profile "$PROFILE")" +# Section may be [rsr-profile] (what rsr-template-repo ships) or [profile] +# (the original spelling here) — the normative oracle +# (hypatia Hypatia.Rules.RsrConformance.load_capabilities/1) accepts both, +# and this reference checker must not be stricter than the oracle. +PBODY="$(section rsr-profile "$PROFILE")" +[ -n "$PBODY" ] || PBODY="$(section profile "$PROFILE")" PRESET="$(printf '%s\n' "$PBODY" | quoted_on_key preset | sed -n 1p)" -DIRECT="$(printf '%s\n' "$PBODY" | quoted_on_key capabilities)" -ADD="$(printf '%s\n' "$PBODY" | quoted_on_key add)" -REMOVE="$(printf '%s\n' "$PBODY" | quoted_on_key remove)" +DIRECT="$(printf '%s\n' "$PBODY" | array_on_key capabilities)" +ADD="$(printf '%s\n' "$PBODY" | array_on_key add)" +REMOVE="$(printf '%s\n' "$PBODY" | array_on_key remove)" [ -n "$PRESET$DIRECT" ] || { echo "ERROR: profile declares neither 'capabilities' nor 'preset'" >&2; exit 2; } # --- preset's base capabilities, if a preset is named ---