diff --git a/.machine_readable/ADJUST.contractile b/.machine_readable/ADJUST.contractile deleted file mode 100644 index 819a52e..0000000 --- a/.machine_readable/ADJUST.contractile +++ /dev/null @@ -1,126 +0,0 @@ -; SPDX-License-Identifier: MPL-2.0 -; ADJUST.contractile — Accessibility invariants for a2ml-validate-action -; "ADJUST" = Accessibility & Digital Justice for Universal Software & Technology -; -; Part of the contractile family: MUST, TRUST, DUST, INTENT, ADJUST -; This file is machine-readable. LLM/SLM agents MUST NOT violate these invariants. - -; ── Definitions ────────────────────────────────────────────────── -; -; ADJUST (noun/verb) -; The accessibility contractile. Defines how software must adapt to serve -; all users regardless of ability, device, or context. Named for the verb -; "adjust" — to make suitable, to adapt, to accommodate — which is the -; core action of accessible design. -; -; Scope: -; ADJUST governs all user-facing interfaces: GUI, TUI, CLI, web, mobile, -; documentation, error messages, and installation flows. It applies to -; both human users and assistive technologies (screen readers, switch -; devices, braille displays, voice control). -; -; Relationship to other contractiles: -; - MUST: ADJUST invariants are a subset of MUST — violating ADJUST -; is a MUST violation. ADJUST exists separately because accessibility -; rules are numerous enough to warrant their own file, and because -; LLMs frequently forget accessibility unless explicitly reminded. -; - TRUST: ADJUST does not affect trust levels. All trust tiers must -; respect ADJUST invariants equally. -; - DUST: Deprecating a feature does not exempt it from ADJUST until -; it is fully removed. Deprecated UI must remain accessible. -; - INTENT: ADJUST supports the anti-purpose "this software is NOT -; only for able-bodied users with modern hardware." -; -; Standard: WCAG 2.2 Level AA (minimum) -; https://www.w3.org/WAI/WCAG22/quickref/?levels=aaa -; -; Why a separate file: -; Experience shows LLMs and developers alike treat accessibility as an -; afterthought. By placing invariants in a contractile that is loaded -; at session start, we make it structurally impossible to forget. -; -; ── End Definitions ────────────────────────────────────────────── - -(adjust-contractile - (version "1.0.0") - (full-name "Accessibility & Digital Justice for Universal Software & Technology") - (standard "WCAG-2.2-AA") - (repo "a2ml-validate-action") - - (invariants - ; ── Visual ── - (adjust "colour-contrast-ratio >= 4.5:1 for normal text") - (adjust "colour-contrast-ratio >= 3:1 for large text (18pt+ or 14pt+ bold)") - (adjust "no information conveyed by colour alone") - (adjust "no flashing or strobing content (3 flashes/second max)") - (adjust "text resizable to 200% without loss of content or function") - (adjust "focus indicators visible on all interactive elements") - - ; ── Keyboard ── - (adjust "all interactive elements reachable via keyboard (Tab/Shift+Tab)") - (adjust "no keyboard traps — user can always Tab away") - (adjust "skip navigation link present on pages with repeated blocks") - (adjust "logical focus order follows visual reading order") - - ; ── Screen reader ── - (adjust "all images have meaningful alt text (or alt='' if decorative)") - (adjust "all form inputs have associated labels") - (adjust "ARIA landmarks used for page regions (main, nav, banner, etc.)") - (adjust "dynamic content updates announced via aria-live regions") - (adjust "semantic HTML used (headings, lists, tables) — not div soup") - - ; ── Interactive ── - (adjust "touch targets minimum 44x44px on mobile/touch interfaces") - (adjust "error messages identify the field and describe the error") - (adjust "error messages not conveyed by colour or position alone") - (adjust "form validation provides suggestions for correction") - - ; ── Media ── - (adjust "video has captions (closed or open)") - (adjust "audio-only content has text transcript") - (adjust "no autoplay of media with sound") - - ; ── Motion ── - (adjust "animations respect prefers-reduced-motion media query") - (adjust "no content depends on motion to convey meaning") - - ; ── CLI/TUI ── - (adjust "CLI output must not rely solely on colour (use symbols: [OK] [FAIL])") - (adjust "TUI must support high-contrast mode") - (adjust "all CLI commands support --help with plain-text output") - (adjust "error messages written in plain language, not jargon or codes alone") - - ; ── Documentation ── - (adjust "docs use clear language, short sentences, logical structure") - (adjust "code examples include comments explaining non-obvious steps") - (adjust "diagrams have text descriptions or alt text") - - ; ── Internationalisation (i18n) ── - (adjust "all user-facing strings externalisable for translation") - (adjust "no hardcoded English in error messages — use message keys") - (adjust "date/time/number formats locale-aware") - (adjust "RTL (right-to-left) layout support where applicable") - (adjust "Unicode handled correctly throughout (UTF-8 everywhere)") - ) - - (related-resources - ; LOL — super-parallel corpus crawler for 1500+ languages - ; Use for linguistic data, translation coverage, and i18n validation - (lol "standards/lol — multilingual NLP corpus, see README.adoc") - (polyglot-i18n "polyglot-i18n — i18n framework and WASM translation engine") - ) - - (enforcement - (ci "accessibility linting in quality.yml workflow") - (pr-block "PR blocked if accessibility regression detected") - (tool "axe-core or pa11y for automated checks on web UI") - (tool "CLI output inspected for colour-only signalling") - (manual "manual screen reader test before major releases") - ) - - (notes - "These are MINIMUM requirements. Exceeding them (AAA) is encouraged." - "When in doubt about an accessibility decision, ask — don't guess." - "Accessibility is not optional polish — it is a structural requirement." - ) -) diff --git a/.machine_readable/CLADE.a2ml b/.machine_readable/CLADE.a2ml index b14389c..c6e9c55 100644 --- a/.machine_readable/CLADE.a2ml +++ b/.machine_readable/CLADE.a2ml @@ -6,8 +6,8 @@ uuid = "a5ea1382-a34c-5334-8a46-a2ebe904c810" primary-forge = "github" primary-owner = "hyperpolymath" -canonical-name = "rsr-template-repo" -prefixed-name = "rm-rsr-template-repo" +canonical-name = "a2ml-validate-action" +prefixed-name = "rm-a2ml-validate-action" [clade] primary = "rm" @@ -16,9 +16,9 @@ assigned = "2026-03-16" rationale = "" [forges] -github = "hyperpolymath/rsr-template-repo" -gitlab = "hyperpolymath/rsr-template-repo" -bitbucket = "hyperpolymath/rsr-template-repo" +github = "hyperpolymath/a2ml-validate-action" +gitlab = "hyperpolymath/a2ml-validate-action" +bitbucket = "hyperpolymath/a2ml-validate-action" [lineage] type = "standalone" diff --git a/.machine_readable/INTENT.contractile b/.machine_readable/INTENT.contractile deleted file mode 100644 index 1094872..0000000 --- a/.machine_readable/INTENT.contractile +++ /dev/null @@ -1,72 +0,0 @@ -; SPDX-License-Identifier: MPL-2.0 -; INTENT.contractile — Purpose and scope for a2ml-validate-action -; Helps LLM/SLM agents understand what this repo IS and IS NOT. -; -; Part of the contractile family: MUST, TRUST, DUST, INTENT, ADJUST - -; ── Definitions ────────────────────────────────────────────────── -; -; INTENT (noun) -; The purpose contractile. Defines what this repository IS, what it is -; NOT (anti-purpose), and which architectural decisions are load-bearing. -; Without INTENT, LLMs drift into scope creep, reverse key decisions, -; or add features that belong in a different repo. -; -; Scope: -; INTENT governs the conceptual boundaries of the project — its reason -; for existing, its domain, and its relationship to the ecosystem. -; It does NOT specify implementation details (that's MUST and code). -; -; Relationship to other contractiles: -; - MUST: INTENT explains WHY certain MUSTs exist. If you don't -; understand a MUST, read INTENT first. -; - TRUST: The "ask-before-touching" section in INTENT maps directly -; to TRUST.trust-deny for the most sensitive areas. -; - ADJUST: INTENT's anti-purpose should include "this software is -; NOT only for users with perfect vision/hearing/mobility." -; - DUST: When INTENT changes (repo pivots), related DUST entries -; should be created for the abandoned direction. -; -; ── End Definitions ────────────────────────────────────────────── - -(intent-contractile - (version "1.0.0") - (repo "a2ml-validate-action") - - ; === Purpose (what this repo IS) === - (purpose - "{{ONE_PARAGRAPH_PURPOSE}}" - ) - - ; === Anti-Purpose (what this repo is NOT — prevents scope creep) === - (anti-purpose - "{{ONE_PARAGRAPH_ANTI_PURPOSE}}" - ; Examples: - ; "This is NOT a general-purpose database — it solves one specific problem." - ; "This is NOT a framework — it is a library with a focused API." - ; "This does NOT handle authentication — that is delegated to [other repo]." - ) - - ; === Key Architectural Decisions That Must Not Be Reversed === - (architectural-invariants - ; *REMINDER: List the foundational decisions* - ; ("Idris2 for ABI definitions — dependent types prove interface correctness") - ; ("Zig for FFI — zero-cost C ABI compatibility") - ; ("Elixir for supervision — OTP fault tolerance") - ) - - ; === Sensitive Areas (if in doubt, ask) === - (ask-before-touching - ; *REMINDER: List areas where LLMs should check before modifying* - ; "src/abi/ — formal proofs, changes require re-verification" - ; "ffi/zig/ — C ABI boundary, changes affect all language bindings" - ; ".machine_readable/ — checkpoint files, format is specified" - ) - - ; === Ecosystem Position === - (ecosystem - (belongs-to "{{MONOREPO_OR_STANDALONE}}") - (depends-on ("{{DEP1}}" "{{DEP2}}")) - (depended-on-by ("{{CONSUMER1}}" "{{CONSUMER2}}")) - ) -) diff --git a/.machine_readable/MUST.contractile b/.machine_readable/MUST.contractile deleted file mode 100644 index 5e3b5be..0000000 --- a/.machine_readable/MUST.contractile +++ /dev/null @@ -1,91 +0,0 @@ -; SPDX-License-Identifier: MPL-2.0 -; MUST.contractile — Baseline invariants for a2ml-validate-action -; These constraints MUST NOT be violated. K9 validators enforce them. -; -; Part of the contractile family: MUST, TRUST, DUST, INTENT, ADJUST - -; ── Definitions ────────────────────────────────────────────────── -; -; MUST (noun/verb) -; The hard-constraint contractile. Defines invariants that are structurally -; required for the repository to function correctly and safely. Violating -; a MUST is always a bug — there are no "soft" MUSTs. -; -; Scope: -; MUST governs code, configuration, CI, and structure. It does NOT govern -; style, preference, or approach — those belong in CLAUDE.md or coding -; standards. MUST is for things that break the project if violated. -; -; Relationship to other contractiles: -; - TRUST: MUST is enforced regardless of trust level. Even maximal-trust -; agents cannot violate MUST constraints. -; - ADJUST: All ADJUST invariants are implicitly MUST invariants too. -; ADJUST exists separately for visibility. -; - INTENT: MUST protects the architectural decisions described in INTENT. -; - DUST: When a feature enters DUST (deprecation), its MUST constraints -; remain active until the feature is fully removed. -; -; Enforcement: -; K9 validators in contractiles/k9/ machine-check MUST constraints. -; CI runs these on every PR. Violations block merge. -; -; ── End Definitions ────────────────────────────────────────────── - -(must-contractile - (version "1.0.0") - (repo "a2ml-validate-action") - - ; === Universal Invariants (apply to ALL repos) === - - (invariants - ; Paths - (must "no hardcoded absolute paths (/home/*, /mnt/*, /var/mnt/*)") - (must "all paths use env vars, XDG dirs, or relative references") - - ; Language policy - (must "no new TypeScript files") - (must "no new Python files") - (must "no new Go files") - (must "no npm/bun/yarn/pnpm dependencies — Deno only") - - ; Dangerous patterns - (must "no believe_me (Idris2)") - (must "no assert_total (Idris2)") - (must "no Admitted (Coq)") - (must "no sorry (Lean)") - (must "no unsafeCoerce (Haskell)") - (must "no Obj.magic (OCaml)") - (must "no unsafe {} blocks without safety comment (Rust)") - - ; License - (must "SPDX-License-Identifier header on every source file") - (must "no removal or modification of LICENSE file") - - ; Structure - (must ".machine_readable/ directory preserved") - (must "0-AI-MANIFEST.a2ml preserved") - (must "no SCM files in repo root — only in .machine_readable/") - - ; CI - (must "no removal of CI workflows without explicit approval") - (must "all GitHub Actions SHA-pinned") - - ; Code quality - (must "tests must not be deleted or weakened") - (must "generated code in generated/ directory only") - (must "no introduction of OWASP top 10 vulnerabilities") - - ; ABI/FFI (if applicable) - (must "no modification of ABI contracts without proof update") - (must "no removal of formal verification proofs") - ) - - ; === Project-Specific Invariants === - ; *REMINDER: Add invariants specific to this repo* - ; (must "# Add project-specific invariants here") - - (enforcement - (k9-validator "contractiles/k9/must-check.k9.ncl") - (ci "quality.yml runs must-check on every PR") - ) -) diff --git a/.machine_readable/TRUST.contractile b/.machine_readable/TRUST.contractile deleted file mode 100644 index 4457215..0000000 --- a/.machine_readable/TRUST.contractile +++ /dev/null @@ -1,80 +0,0 @@ -; SPDX-License-Identifier: MPL-2.0 -; TRUST.contractile — Trust boundaries for a2ml-validate-action -; Defines what LLM/SLM agents are trusted to do without asking. -; -; Part of the contractile family: MUST, TRUST, DUST, INTENT, ADJUST - -; ── Definitions ────────────────────────────────────────────────── -; -; TRUST (noun/verb) -; The permission contractile. Defines the boundary between what an AI -; agent may do autonomously and what requires human approval. Trust is -; graduated — not binary — with four levels from minimal to maximal. -; -; Trust levels: -; - maximal: Agent may read, build, test, lint, format, heal freely. -; Only destructive/external actions require approval. -; - standard: Agent may read and build. Test/lint need approval. -; - restricted: Agent may read only. All modifications need approval. -; - minimal: Agent may read specific files only. Everything else blocked. -; -; Scope: -; TRUST governs AI agent behaviour only. It does not affect human -; contributors — humans follow CONTRIBUTING.md and GOVERNANCE.adoc. -; -; Relationship to other contractiles: -; - MUST: Trust never overrides MUST. Even at maximal trust, MUST -; violations are blocked. -; - ADJUST: Trust does not exempt from ADJUST. All trust tiers must -; produce accessible output. -; - INTENT: TRUST.trust-deny protects the sensitive areas listed in -; INTENT.ask-before-touching. -; - DUST: Deprecated features have the same trust rules as active ones. -; -; ── End Definitions ────────────────────────────────────────────── - -(trust-contractile - (version "1.0.0") - (repo "a2ml-validate-action") - - (trust-level "maximal") ; maximal | standard | restricted | minimal - - ; === Maximal Trust (default) === - ; LLM may freely do these without asking: - (trust-actions - "read" ; Read any file in the repo - "build" ; Run build commands - "test" ; Run test suites - "lint" ; Run linters and formatters - "format" ; Auto-format code - "doctor" ; Run self-diagnostics - "heal" ; Attempt automatic repair - "git-status" ; Check git status - "git-diff" ; View diffs - "git-log" ; View history - ) - - ; === Denied Actions (always require human approval) === - (trust-deny - "delete-branch" ; Could lose work - "force-push" ; Overwrites history - "modify-ci-secrets" ; Security sensitive - "publish" ; External visibility - "push-to-main" ; Protected branch - "delete-files-bulk" ; More than 5 files at once - "modify-license" ; Legal implications - "modify-security-policy" ; Security implications - "remove-proofs" ; Formal verification regression - "disable-ci-checks" ; Safety regression - ) - - ; === Trust Boundary === - (trust-boundary "repo") ; LLM confined to this repo unless explicitly told otherwise - - ; === Override === - ; Repos requiring tighter trust override these settings with justification: - ; (override - ; (trust-level "restricted") - ; (reason "Contains production secrets / handles PII / etc.") - ; ) -) diff --git a/.machine_readable/agent_instructions/README.adoc b/.machine_readable/bot_directives/README.adoc similarity index 100% rename from .machine_readable/agent_instructions/README.adoc rename to .machine_readable/bot_directives/README.adoc diff --git a/.machine_readable/agent_instructions/coverage.a2ml b/.machine_readable/bot_directives/coverage.a2ml similarity index 100% rename from .machine_readable/agent_instructions/coverage.a2ml rename to .machine_readable/bot_directives/coverage.a2ml diff --git a/.machine_readable/agent_instructions/debt.a2ml b/.machine_readable/bot_directives/debt.a2ml similarity index 100% rename from .machine_readable/agent_instructions/debt.a2ml rename to .machine_readable/bot_directives/debt.a2ml diff --git a/.machine_readable/agent_instructions/methodology.a2ml b/.machine_readable/bot_directives/methodology.a2ml similarity index 100% rename from .machine_readable/agent_instructions/methodology.a2ml rename to .machine_readable/bot_directives/methodology.a2ml diff --git a/.machine_readable/contractiles/INDEX.a2ml b/.machine_readable/contractiles/INDEX.a2ml new file mode 100644 index 0000000..d44c3f2 --- /dev/null +++ b/.machine_readable/contractiles/INDEX.a2ml @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: MPL-2.0 +# INDEX.a2ml — Contractile Registry +# Author: Jonathan D.A. Jewell +# +# Machine-readable catalogue of all contractile verbs in this template set. +# Consumers (CI scripts, the contractile CLI, Hypatia rules) SHOULD read this +# file to discover available verbs rather than hard-coding the list. +# +# See: docs/CONTRACTILE-SPEC.adoc §Registry + +--- +id = "contractiles-registry" +version = "2.0.0" # 2.0.0 (2026-04-18): all 6 verbs on trident shape; verb set complete. +spec = "docs/CONTRACTILE-SPEC.adoc" +last_updated = "2026-04-18" +base_schema = ".machine_readable/contractiles/_base.ncl" +meta_schema_status = "pending — see CONTRACTILE-SPEC §validator-meta-schema" + +## Verbs + +[[verbs]] +name = "adjust" +semantics = "drift tolerances + corrective actions" +trident = [ + "adjust/Adjustfile.a2ml", + "adjust/adjust.ncl", + "adjust/adjust.k9.ncl", +] +manifest = "adjust/adjust.manifest.a2ml" +status = "active" +tier = "Yard" +authority = "advisory" +gating = "advisory (continue-with-warnings)" +cardinality = "one per repo" +notes = "Fifth trident instance (2026-04-18). First (Yard, advisory) authority pattern. Specialises in cumulative-drift catchment — tolerance bands + trend tracking across sessions. auto_fix_when_available applies deterministic patches; advisory otherwise." + +[[verbs]] +name = "bust" +semantics = "hard-stop / expiry / must-not-run declarations" +trident = [ + "bust/Bustfile.a2ml", + "bust/bust.ncl", + "bust/bust.k9.ncl", +] +manifest = "bust/bust.manifest.a2ml" +status = "active" +tier = "Hunt-read-only" +authority = "blocking" +gating = "hard (exit-nonzero)" +cardinality = "one per repo" +notes = "Fourth trident instance (2026-04-18). Completes the blocking-authority triple (must + trust + bust). Specialises in deprecated-path-reintroduction catchment. Injects failures via declared probes and verifies recovery paths." + +[[verbs]] +name = "dust" +semantics = "rollback / recovery / deprecation / audit-trail preservation" +trident = [ + "dust/Dustfile.a2ml", + "dust/dust.ncl", + "dust/dust.k9.ncl", +] +manifest = "dust/dust.manifest.a2ml" +status = "active" +tier = "Yard" +authority = "advisory" +gating = "advisory (continue-with-warnings)" +cardinality = "one per repo" +notes = "Sixth and FINAL trident instance (2026-04-18) — completes the full verb set. Specialises in audit-trail preservation + rollback-path verification. Destructive actions gated behind --apply flag + per-item approval; dry-run default." + +[[verbs]] +name = "intend" +semantics = "north-star (commitments + aspirations)" +trident = [ + "intend/Intentfile.a2ml", + "intend/intend.ncl", + "intend/intend.k9.ncl", +] +manifest = "intend/intend.manifest.a2ml" +status = "active" +tier = "Hunt" +authority = "reporting" +gating = "non-gating (continue)" +cardinality = "one per repo" +notes = "First trident instance in the estate (2026-04-18). Reports progress toward committed next-actions AND lists horizon aspirations. Absorbed the deprecated `lust` verb 2026-04-18. Never blocks. Remaining 5 verbs still on file_pair shape until tridents are built." + +[[verbs]] +name = "k9" +semantics = "trust-tier templates (EXCEPTION to one-verbfile rule)" +file_pair = [ + "k9/template-hunt.k9.ncl", + "k9/template-kennel.k9.ncl", + "k9/template-yard.k9.ncl", +] +status = "exception" +gating = "not applicable" +notes = "k9 is service-automation meta-infrastructure, not a verb contractile. Three trust-tier templates (Kennel/Yard/Hunt). Does not have a Verbfile.a2ml. See CONTRACTILE-SPEC §k9-exception." + +# [[verbs]] lust REMOVED 2026-04-18 — name had unwanted associations; +# the horizon/aspiration semantics were always meant to live inside `intend` +# (the north-star verb). The [[wishes]] schema was absorbed into +# intend/Intentfile.a2ml. Any `lust/` dir found in an estate repo is drift +# and should be deleted. + +[[verbs]] +name = "must" +semantics = "invariant assertion — release-blocking" +trident = [ + "must/Mustfile.a2ml", + "must/must.ncl", + "must/must.k9.ncl", +] +manifest = "must/must.manifest.a2ml" +status = "active" +tier = "Hunt-read-only" +authority = "blocking" +gating = "hard (exit-nonzero)" +cardinality = "one per repo" +notes = "Third trident instance (2026-04-18). Completes the blocking-authority pair with trust: must = concrete + persistent invariants; trust = concrete + ephemeral transactions. Specialises in subtle invariant-erosion (tracking per-session trend; flagging silent regression). Single failure blocks merge. Simplest and most commonly populated verb." + +[[verbs]] +name = "trust" +semantics = "security + provenance + safe-hacking" +trident = [ + "trust/Trustfile.a2ml", + "trust/trust.ncl", + "trust/trust.k9.ncl", +] +manifest = "trust/trust.manifest.a2ml" +status = "active" +tier = "Hunt" +authority = "blocking" +gating = "hard (exit-nonzero)" +cardinality = "one per repo" +notes = "Second trident instance (2026-04-18). First (Hunt, blocking) verb — hard gate. Primary defense against threat-model misclassification (B1) and 'turn off the firewall' capability-collapse (C2). Inherits on_open negotiation+accountability+translation from intend.k9.ncl v2.0.0; adds threat_model_foregrounding + block_session_close_on_critical_drift." diff --git a/.machine_readable/contractiles/README.adoc b/.machine_readable/contractiles/README.adoc deleted file mode 100644 index d40fcd1..0000000 --- a/.machine_readable/contractiles/README.adoc +++ /dev/null @@ -1,19 +0,0 @@ -= Contractiles Template Set -:toc: -:sectnums: - -This directory contains the generalized contractiles templates. Copy the `.machine_readable/contractiles/` directory into a new repo to establish a consistent operational, validation, trust, recovery, and intent framework. - -== Fill-In Instructions - -1. Update the Mustfile to reflect your real invariants (paths, schema versions, ports). -2. Replace Trustfile.hs placeholders with your actual key paths and verification commands. -3. Adjust Dustfile handlers to match your rollback and recovery tooling. -4. Update Intentfile to mirror the roadmap you want the system to evolve toward. - -== Contents - -* `must/Mustfile` - required invariants and validations. -* `trust/Trustfile.hs` - cryptographic verification steps. -* `dust/Dustfile` - rollback and recovery semantics. -* `lust/Intentfile` - future intent and roadmap direction. diff --git a/.machine_readable/contractiles/_base.ncl b/.machine_readable/contractiles/_base.ncl new file mode 100644 index 0000000..22306fa --- /dev/null +++ b/.machine_readable/contractiles/_base.ncl @@ -0,0 +1,141 @@ +# SPDX-License-Identifier: MPL-2.0 +# (MPL-2.0 is automatic legal fallback until PMPL is formally recognised) +# +# _base.ncl — Shared contractile base +# +# Provides four named schema fragments imported by every verb runner: +# +# pedigree_schema — canonical pedigree block shape +# status_core_doc — documentation of the shared status trio (String list) +# probe_schema — target structured probe form (spec only; verb files +# still use probe | String with TODO comments) +# run_defaults — default runner behaviour +# +# Usage in a verb runner: +# +# let base = import "../_base.ncl" in +# { +# pedigree = base.pedigree_schema & { +# contractile_verb = "must", +# semantics = "invariant", +# security = { +# leash = 'Kennel, +# trust_level = "read-only verification", +# allow_network = false, +# allow_filesystem_write = false, +# allow_subprocess = true, +# }, +# metadata = { +# name = "must-runner", +# version = "1.0.0", +# description = "...", +# paired_xfile = "Mustfile.a2ml", +# author = "Jonathan D.A. Jewell ", +# }, +# }, +# schema = { ... }, +# run = base.run_defaults & { on_any_fail = "exit-nonzero" }, +# } +# +# See: docs/CONTRACTILE-SPEC.adoc §Shared Base + +{ + # ------------------------------------------------------------------------- + # pedigree_schema + # + # The canonical shape of the `pedigree` block required in every verb runner. + # Verb runners merge this with their verb-specific values using Nickel's `&` + # (right-priority merge). Override contractile_verb, semantics, security.*, + # and metadata.* in each verb. + # ------------------------------------------------------------------------- + pedigree_schema = { + schema_version | String | default = "1.0.0", + contractile_verb | String | default = "UNSET", # MUST override in verb + semantics | String | default = "UNSET", # MUST override in verb + security = { + leash | [| 'Kennel, 'Yard, 'Hunt |] | default = 'Kennel, + trust_level | String | default = "UNSET", # MUST override in verb + allow_network | Bool | default = false, + allow_filesystem_write | Bool | default = false, + allow_subprocess | Bool | default = true, + # verb-specific additional security fields go in the verb's merge override: + # e.g. authorised_probes_only (trust), injection_scope (bust), + # destructive_mode_requires_flag (dust) + }, + metadata = { + name | String | default = "UNSET", # MUST override in verb + version | String | default = "1.0.0", + description | String | default = "UNSET", # MUST override in verb + paired_xfile | String | default = "UNSET", # MUST override in verb + author | String | default = "Jonathan D.A. Jewell ", + }, + }, + + # ------------------------------------------------------------------------- + # status_core_doc + # + # Documents the minimum shared status values present in every verb's status + # enum: declared, verified, failing. + # + # Nickel does not support structural enum extension, so verb files reproduce + # their full enum verbatim in `schema`. This field serves as documentation + # and for tooling that introspects the base. + # + # Verbs that extend status_core (i.e. all except must + trust): + # adjust: + 'partial + # bust: + 'drilled + # dust: 'declared, 'proposed, 'approved, 'removed (non-standard) + # intend: intents: 'declared, 'in_progress, 'done, 'deferred, 'retired + # wishes: 'declared, 'in_progress, 'achieved, 'abandoned + # (the wishes schema was absorbed from the deprecated `lust` + # verb 2026-04-18; lust/ dir removed estate-wide) + # + # See: docs/CONTRACTILE-SPEC.adoc §Per-Verb Extension + # ------------------------------------------------------------------------- + status_core_doc = "status_core values: declared | verified | failing — extended per verb", + + # ------------------------------------------------------------------------- + # probe_schema + # + # The TARGET structured probe form. See: docs/CONTRACTILE-SPEC.adoc §Probe + # + # IMPORTANT: This is a spec-only definition. Existing verb runner files still + # use `probe | String` with a `# TODO: migrate to probe_schema` comment. + # This is a breaking change; migration happens when the CLI supports both + # forms. + # + # Adopters writing new xfiles should prefer the structured form: + # probe = { + # command = "test -f my-file", + # timeout_seconds = 60, + # allowed_exit_codes = [0], + # permission_class = 'read_only, + # } + # ------------------------------------------------------------------------- + probe_schema = { + command | String, + timeout_seconds | Number | default = 300, + allowed_exit_codes | Array Number | default = [0], + permission_class + | [| 'read_only, 'filesystem_write, 'subprocess, 'network |] + | default = 'read_only, + }, + + # ------------------------------------------------------------------------- + # run_defaults + # + # Default runner behaviour. Verb runners merge this with verb-specific + # overrides using Nickel's `&` (right-priority merge). + # + # Most verbs override on_any_fail: + # "exit-nonzero" : hard gate (must, trust, bust, adjust-gating) + # "continue-with-warnings": advisory (dust, adjust) + # "continue" : never gate (intend — covers both intents and wishes) + # ------------------------------------------------------------------------- + run_defaults = { + on_pass = "continue", + on_any_fail = "exit-nonzero", + report_format = "a2ml", + emit_summary = true, + }, +} diff --git a/.machine_readable/contractiles/adjust/Adjustfile.a2ml b/.machine_readable/contractiles/adjust/Adjustfile.a2ml new file mode 100644 index 0000000..41c9177 --- /dev/null +++ b/.machine_readable/contractiles/adjust/Adjustfile.a2ml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: MPL-2.0 +# Adjustfile — Drift-tolerance contract for standards +# Author: Jonathan D.A. Jewell +# +# Cumulative-drift catchment: tolerance bands + corrective actions. +# Authority: advisory (Yard) — continue-with-warnings; auto_fix where deterministic. +# Run with: adjust check +# Fix with: adjust fix (applies deterministic patches; advisory otherwise) + +@abstract: +Drift tolerances and corrective actions for the `standards` monorepo. Unlike +MUST (hard gate), ADJUST tracks cumulative drift against tolerance bands and +proposes corrective actions. Advisory — it warns and trends, it does not block. +@end + +## Licence Drift + +### spdx-header-drift +- description: estate-family SPDX headers stay on policy (code=MPL-2.0, docs=CC-BY-SA-4.0) +- tolerance: 0 standards-authored files off-policy (excludes carve-out + third-party) +- corrective: owner-only, manual, per-file — NEVER an automated sweep (policy A2) +- severity: advisory +- notes: PLMP-/PMLP- sentinels are scaffold leaks, fixed by re-substitution, not relicensing. + +### deep-mention-drift +- description: in-body SPDX example/emitter strings track the current policy ids +- tolerance: emitters (generators) must emit MPL-2.0 / CC-BY-SA-4.0; doc examples may lag +- corrective: update header-emitting generators first; doc examples in a follow-up pass +- severity: advisory + +## Documentation Drift + +### adoc-not-md +- description: docs are AsciiDoc except GitHub-required .md (SECURITY/CONTRIBUTING/CODE_OF_CONDUCT/CHANGELOG) +- tolerance: new prose docs are *.adoc; existing *.md migrate opportunistically +- corrective: convert *.md → *.adoc (no duplicate formats) +- severity: advisory + +### registry-staleness +- description: REGISTRY.a2ml reflects the current spec tree +- tolerance: regenerate when specs are added/moved +- corrective: run `bash scripts/build-registry.sh` (or `just registry`) +- severity: advisory + +## Structural Drift + +### contractile-trident-completeness +- description: each contractile verb has its full trident (Xfile.a2ml + verb.ncl + verb.k9.ncl) +- tolerance: all 6 verbs present per .machine_readable/contractiles/INDEX.a2ml +- corrective: re-run the contractiles scaffold for any missing trident member +- severity: advisory + +### no-foreign-project-scaffold +- description: contractile declaration files describe THIS repo, not a scaffold source +- tolerance: 0 files naming another project (e.g. "Burble") in their declaration +- corrective: re-run scaffold substitution OR rewrite for `standards` +- severity: advisory +- notes: 2026-06-04 — the Must/Adjust/Dust trident files were scaffold leaks naming the template source project; rewritten for `standards`. diff --git a/.machine_readable/contractiles/adjust/adjust.k9.ncl b/.machine_readable/contractiles/adjust/adjust.k9.ncl new file mode 100644 index 0000000..9ff26c9 --- /dev/null +++ b/.machine_readable/contractiles/adjust/adjust.k9.ncl @@ -0,0 +1,166 @@ +# SPDX-License-Identifier: MPL-2.0 +# adjust.k9.ncl — K9 trust-tier component of the adjust trident +# Author: Jonathan D.A. Jewell +# +# Pairs with: Adjustfile.a2ml (declaration) + adjust.ncl (runner). +# +# Verb: adjust (drift tolerances + corrective actions) +# Tier: Yard (validation with subprocess for measurement; +# no mutation beyond auto-fix where declared) +# Authority: advisory (continue-with-warnings; not blocking) +# +# adjust is the tolerance-band verb. Where must says "this MUST hold" +# and trust says "this MUST verify clean" (both binary), adjust says +# "drift ≤ X is acceptable; drift > X triggers action Y". Between them, +# adjust handles the subtle-drift territory that binary verbs can't. +# +# Cardinality: ONE adjust trident per repo. +# +# Failure-mode focus: adjust catches cumulative-small-drift patterns +# (E2 cosmetic churn accumulating into real regression, F2 context +# erosion causing gradual parameter drift). Where must flags "broken +# now", adjust flags "drifting toward broken". + +let base_k9 = import "../k9/template-hunt.k9.ncl" in +let base = import "../_base.ncl" in + +{ + pedigree = base_k9.pedigree_schema & { + contractile_verb = "adjust", + paired_xfile = "../adjust/Adjustfile.a2ml", + paired_runner = "../adjust/adjust.ncl", + + tier = 'Yard, + authority = 'advisory, + + metadata = { + name = "adjust-k9", + version = "1.0.0", + description = "Drift-tolerance + corrective-action runner. Fifth trident instance. First (Yard, advisory) authority pattern.", + paired_xfile = "Adjustfile.a2ml", + paired_runner = "adjust.ncl", + author = "Jonathan D.A. Jewell ", + }, + + security = { + leash = 'Yard, + trust_level = "tolerance measurement + declared auto-fix", + allow_network = false, + allow_filesystem_write_conditional = true, # auto_fix_when_available may edit + allow_subprocess = true, + probe_scope = 'measurement_plus_declared_fix, + }, + }, + + variance_schema = { + entry_id | String, + reason | String, + approved_by | String, + scope | String, + expires | String, + review_notes | String | optional, + # adjust-specific: which tolerance band the variance widens + tolerance_band_widened | String, + widened_to_value | String, + }, + + execution = { + triggers = [ 'session_close, 'on_demand, 'pre_push ], + + per_tolerance = { + measure_drift = true, + record_outcome = true, + respect_variance = true, + # adjust-specific authority: tolerance exceeded → warn, try + # auto-fix if declared, then continue. Never blocks. + on_exceeded = 'warn_and_attempt_fix, + on_auto_fix_applied = 'record_and_continue, + on_auto_fix_unavailable = 'record_as_advisory_drift, + # Cumulative-drift detection (adjust's specialty) + track_drift_trend_over_sessions = true, + flag_accelerating_drift = true, + }, + + evidence_sinks = [ + { kind = 'verisimdb, table = "contractile_executions", + schema = "contractile_execution_v1", + aux_tables = [ "adjust_drift_history" ] }, + { kind = 'drift_log, path = ".machine_readable/6a2/DRIFT.a2ml", + append_only = true }, + ], + + on_close = { + re_measure_all_tolerances = true, + diff_against_last_ratification = true, + emit_drift_entries_for_tolerance_exceeded = true, + surface_expired_variances = true, + surface_accelerating_drift = true, + # adjust is advisory — does NOT block session close. + block_session_close_on_any_drift = false, + }, + + on_open = { + render_summary = 'plain_language, + include_drift_log_from_last_close = true, + include_active_variances = true, + include_recent_anchors = true, + anchor_lookback_weeks = 8, + include_tolerance_trend_summary = true, + + negotiation = { + required = true, + ai_required_inputs = [ + 'timeline_realism, + 'industry_standards, + 'audience_feasibility, + 'resulting_invariants, + 'ecosystem_dependencies, + ], + user_engagement_required = true, + user_engagement_mode = 'per_input_response, + specification_translation = { + ai_produces_spec_form = true, + user_reviews_in_domain_language = true, + schema_authoring_is_ai_responsibility = true, + translation_faithfulness_auditable = true, + }, + }, + + accountability_pledge = { + required = true, + parties = [ + { + role = 'user, + pledge = "I have reviewed the tolerance bands and corrective actions. I accept accountability for reviewing drift warnings rather than muting them, and for re-tuning tolerances via amendment when the intended operating envelope changes.", + signature_required = true, + }, + { + role = 'ai_agent, + pledge = "I will surface tolerance breaches and accelerating-drift patterns at session close; I will propose corrective actions rather than widening tolerances silently; I will require amendment for legitimate tolerance re-tuning, not quiet band-widening.", + signature_required = true, + }, + ], + signed_record_destination = ".machine_readable/6a2/ratification-.a2ml", + must_precede_work = true, + }, + + ratification_record_shape = { + includes_negotiation_transcript = true, + includes_both_pledges = true, + includes_tolerance_bands_snapshot = true, + signed = true, + dated = true, + session_id = 'required, + contract_hash = 'required, + }, + }, + }, + + failure_mode_defenses = [ + 'A1_enthusiasm_capture, + 'C3_helpfulness_inflation, # helpful additions surfaced if they widen tolerances silently + 'C4_modernization_drift, + 'E2_cosmetic_churn, # adjust tracks cumulative churn + 'F2_context_window_erosion, # parameter drift across sessions detected + ], +} diff --git a/.machine_readable/contractiles/adjust/adjust.manifest.a2ml b/.machine_readable/contractiles/adjust/adjust.manifest.a2ml new file mode 100644 index 0000000..f28f94d --- /dev/null +++ b/.machine_readable/contractiles/adjust/adjust.manifest.a2ml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: MPL-2.0 +# adjust.manifest.a2ml — Trident coherence manifest for the adjust verb. +# Author: Jonathan D.A. Jewell +# +# Fifth trident instance. First (Yard, advisory) authority pattern — +# complements the (Hunt, blocking) triple (must + trust + bust) and +# the (Hunt, reporting) north-star (intend). + +--- +trident_version = "1.0.0" +verb = "adjust" +semantics = "drift tolerances + corrective actions" +cardinality = "one per repo" +authority = "advisory (continue-with-warnings)" + +[[files]] +role = "declaration" +path = "Adjustfile.a2ml" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[[files]] +role = "runner" +path = "adjust.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[[files]] +role = "k9_component" +path = "adjust.k9.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[cross_refs] +runner_paired_xfile = "Adjustfile.a2ml" +k9_paired_xfile = "../adjust/Adjustfile.a2ml" +k9_paired_runner = "../adjust/adjust.ncl" + +[signed_by] +user = "Jonathan D.A. Jewell" +date = "2026-04-18" +context = "adjust trident — fifth Trident instance. First (Yard, advisory) authority pattern. Specialises in cumulative-drift catchment — tolerance bands + trend tracking + auto-fix-where-declared." + +[[history]] +date = "2026-04-18" +event = "trident-born" +note = "Adjustfile.a2ml and adjust.ncl pre-existed. This manifest + adjust.k9.ncl complete the trident. Exercises the Yard tier + advisory authority for the first time; on_exceeded = 'warn_and_attempt_fix rather than 'fail. adjust-specific track_drift_trend_over_sessions + flag_accelerating_drift." diff --git a/.machine_readable/contractiles/adjust/adjust.ncl b/.machine_readable/contractiles/adjust/adjust.ncl new file mode 100644 index 0000000..d6c24f0 --- /dev/null +++ b/.machine_readable/contractiles/adjust/adjust.ncl @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: MPL-2.0 +# Adjust — accessibility runner +# +# Pairs with: Adjustfile.a2ml (same directory) +# Verb: adjust +# Semantics: accessibility compliance (WCAG 2.1 AA baseline). Gating where +# a deterministic fix exists; advisory where human review needed. +# CLI: `contractile adjust check` → run all probes, list violations +# `contractile adjust fix` → apply deterministic fixes where defined +# +# Anything else in this directory is human-only notes/archive; machines ignore. +# +# Base: ../_base.ncl provides pedigree_schema, run_defaults, probe_schema. +# See: docs/CONTRACTILE-SPEC.adoc + +let base = import "../_base.ncl" in + +{ + pedigree = base.pedigree_schema & { + contractile_verb = "adjust", + semantics = "accessibility compliance", + security = { + leash = 'Kennel, + trust_level = "fixes allowed where deterministic", + allow_network = false, + allow_filesystem_write = true, # `adjust fix` may write (deterministic patches only) + allow_subprocess = true, + }, + metadata = { + name = "adjust-runner", + version = "1.0.0", + description = "Evaluates accessibility requirements from Adjustfile.a2ml. Fixes deterministic items; flags the rest for human review.", + paired_xfile = "Adjustfile.a2ml", + author = "Jonathan D.A. Jewell ", + }, + }, + + schema = { + requirements + | Array { + id | String, + description | String, + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + probe | String, + # status_core values: 'declared, 'verified, 'failing; adjust adds 'partial + status | [| 'declared, 'partial, 'verified, 'failing |] | default = 'declared, + compliance | String | optional, # e.g. "WCAG 2.1 AA" + notes | String | optional, + fix | String | optional, # deterministic fix command (optional) + }, + }, + + # Runner behaviour — inherits from base.run_defaults. + # adjust is advisory (continue-with-warnings) not a hard gate. + # auto_fix_when_available is adjust-specific. + run = base.run_defaults & { + on_any_fail = "continue-with-warnings", # accessibility is progress-tracked, not a hard gate by default + report_format = "a2ml", + emit_summary = true, + auto_fix_when_available = true, + }, +} diff --git a/.machine_readable/contractiles/bust/Bustfile.a2ml b/.machine_readable/contractiles/bust/Bustfile.a2ml new file mode 100644 index 0000000..5dd3840 --- /dev/null +++ b/.machine_readable/contractiles/bust/Bustfile.a2ml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: MPL-2.0 +# Bustfile — failure mode contractile (seed skeleton) +# Author: Jonathan D.A. Jewell +# +# Paired runner: bust.ncl +# Verb: bust +# Semantics: Every declared failure mode must have a working recovery path +# that has been exercised. Status moves: +# declared → drilled (probe run) → verified (recovery confirmed) +# or → failing (recovery broken) +# +# CLI: +# contractile bust check → list failure modes + recovery status +# contractile bust drill → inject failures, verify recovery paths +# +# ADOPTER INSTRUCTIONS: This is a seed skeleton. Replace the example failure +# modes below with the real failure modes for your project. Add one entry per +# distinct failure class you want to track and verify. Delete entries that do +# not apply. The goal is a machine-checkable map of "what can break → how we +# recover" for this specific repository. + +@abstract: +Seed Bustfile for the standards contractile template set. Lists two example +failure modes (network loss, disk full) to illustrate the shape. Adopters +should replace these with project-specific failure modes and recovery paths. +@end + +## Failure Modes + +### network-unavailable +- class: network +- description: External network becomes unavailable during a contractile probe or CI step +- injection_probe: "unshare -n true" +- recovery_probe: "ping -c 1 -W 1 127.0.0.1" +- expected_recovery_time_seconds: 5 +- status: declared +- notes: Illustrative — replace with the real network-dependent step that needs resilience + +### disk-full +- class: disk_full +- description: Disk fills to 100% during a write-heavy operation (build artefacts, test DB writes) +- injection_probe: "dd if=/dev/zero of=/tmp/bustfile-fill-test bs=1M count=1 && rm /tmp/bustfile-fill-test" +- recovery_probe: "df -h / | awk 'NR==2 { gsub(/%/,\"\"); if ($5 < 95) exit 0; else exit 1 }'" +- expected_recovery_time_seconds: 30 +- status: declared +- notes: Illustrative — replace with the real disk-intensive operation and its recovery path diff --git a/.machine_readable/contractiles/bust/bust.k9.ncl b/.machine_readable/contractiles/bust/bust.k9.ncl new file mode 100644 index 0000000..c60a0ae --- /dev/null +++ b/.machine_readable/contractiles/bust/bust.k9.ncl @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: MPL-2.0 +# bust.k9.ncl — K9 trust-tier component of the bust trident +# Author: Jonathan D.A. Jewell +# +# Pairs with: Bustfile.a2ml (declaration) + bust.ncl (runner). +# +# Verb: bust (hard-stop / expiry / "must-not-run") +# Tier: Hunt-read-only (subprocess probes for expiry/state checks) +# Authority: blocking (HARD GATE on declared broken states) +# +# bust is the "this is broken, this has expired, this must not run" +# declarative surface. Where must asserts invariants that must hold, +# bust asserts failure states that must not be re-entered. Complement +# to must: together they bound the "acceptable operating state" from +# above (must) and below (bust). +# +# Cardinality: ONE bust trident per repo. +# +# Failure-mode focus: bust catches deprecated-path-still-called +# patterns (C2 capability collapse attempts where an AI reintroduces +# retired code), expiry-exceeded state (certificates / tokens / grants +# past their expiry), and the "it works, ship it" pattern where a +# caller silently starts using a must-not-run API. + +let base_k9 = import "../k9/template-hunt.k9.ncl" in +let base = import "../_base.ncl" in + +{ + pedigree = base_k9.pedigree_schema & { + contractile_verb = "bust", + paired_xfile = "../bust/Bustfile.a2ml", + paired_runner = "../bust/bust.ncl", + + tier = 'Hunt, + authority = 'blocking, + + metadata = { + name = "bust-k9", + version = "1.0.0", + description = "Hard-stop / expiry / must-not-run gate. Fourth trident instance. Completes the blocking-authority triple (must + trust + bust).", + paired_xfile = "Bustfile.a2ml", + paired_runner = "bust.ncl", + author = "Jonathan D.A. Jewell ", + }, + + security = { + leash = 'Hunt, + trust_level = "read-only expiry + state-check with subprocess", + allow_network = false, + allow_filesystem_write = false, + allow_subprocess = true, + probe_scope = 'read_only, + }, + }, + + variance_schema = { + entry_id | String, + reason | String, + approved_by | String, + scope | String, + expires | String, + review_notes | String | optional, + severity_acknowledged | [| 'critical, 'high, 'medium |], + waived_consequence_description | String, + }, + + execution = { + triggers = [ 'session_close, 'on_demand, 'pre_push, 'pre_merge ], + + per_hard_stop = { + run_probe = true, + record_outcome = true, + respect_variance = true, + on_triggered = 'fail, # BLOCKING — bust condition hit = block + severity_escalation = 'honour, + # bust-specific: detect re-introduction of deprecated calls + flag_deprecated_reintroduction = true, + }, + + evidence_sinks = [ + { kind = 'verisimdb, table = "contractile_executions", + schema = "contractile_execution_v1", + aux_tables = [ "bust_triggers_history" ] }, + { kind = 'drift_log, path = ".machine_readable/6a2/DRIFT.a2ml", + append_only = true }, + ], + + on_close = { + re_execute_all_hard_stops = true, + diff_against_last_ratification = true, + emit_drift_entries_for_new_triggers = true, + surface_expired_variances = true, + block_session_close_on_critical_bust = true, + }, + + on_open = { + render_summary = 'plain_language, + include_drift_log_from_last_close = true, + include_active_variances = true, + include_recent_anchors = true, + anchor_lookback_weeks = 8, + include_silent_regressions = true, + + negotiation = { + required = true, + ai_required_inputs = [ + 'timeline_realism, + 'industry_standards, + 'audience_feasibility, + 'resulting_invariants, + 'ecosystem_dependencies, + ], + user_engagement_required = true, + user_engagement_mode = 'per_input_response, + specification_translation = { + ai_produces_spec_form = true, + user_reviews_in_domain_language = true, + schema_authoring_is_ai_responsibility = true, + translation_faithfulness_auditable = true, + }, + }, + + accountability_pledge = { + required = true, + parties = [ + { + role = 'user, + pledge = "I have reviewed the declared hard-stop / expiry / must-not-run conditions. I accept accountability for not calling into must-not-run code paths, not ignoring expired tokens/grants, and not silently reintroducing deprecated patterns. I will raise a variance with severity acknowledgement if an exception is needed.", + signature_required = true, + }, + { + role = 'ai_agent, + pledge = "I will refuse suggestions that reintroduce must-not-run patterns; I will surface bust triggers at session close; I will require variance-with-severity for any legitimate reintroduction of a deprecated path rather than silently allowing it.", + signature_required = true, + }, + ], + signed_record_destination = ".machine_readable/6a2/ratification-.a2ml", + must_precede_work = true, + }, + + ratification_record_shape = { + includes_negotiation_transcript = true, + includes_both_pledges = true, + signed = true, + dated = true, + session_id = 'required, + contract_hash = 'required, + }, + }, + }, + + failure_mode_defenses = [ + 'A1_enthusiasm_capture, + 'C2_capability_collapse, # prevents reintroduction of retired capability + 'C4_modernization_drift, # bust prevents silent re-adoption of deprecated libs + 'D4_error_hiding, + 'E1_refactor_stampede, # refactor that reintroduces deprecated path caught + 'F1_across_session_forgetting, # bust triggers persist across sessions + ], +} diff --git a/.machine_readable/contractiles/bust/bust.manifest.a2ml b/.machine_readable/contractiles/bust/bust.manifest.a2ml new file mode 100644 index 0000000..2237041 --- /dev/null +++ b/.machine_readable/contractiles/bust/bust.manifest.a2ml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: MPL-2.0 +# bust.manifest.a2ml — Trident coherence manifest for the bust verb. +# Author: Jonathan D.A. Jewell +# +# Fourth trident instance. Completes the blocking-authority triple: +# must (persistent invariants), trust (ephemeral transactions), +# bust (hard-stop / expiry / must-not-run). Between them, every +# release-blocking contractile concern is covered. + +--- +trident_version = "1.0.0" +verb = "bust" +semantics = "hard-stop / expiry / must-not-run declarations" +cardinality = "one per repo" +authority = "blocking (hard gate)" + +[[files]] +role = "declaration" +path = "Bustfile.a2ml" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[[files]] +role = "runner" +path = "bust.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[[files]] +role = "k9_component" +path = "bust.k9.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[cross_refs] +runner_paired_xfile = "Bustfile.a2ml" +k9_paired_xfile = "../bust/Bustfile.a2ml" +k9_paired_runner = "../bust/bust.ncl" + +[signed_by] +user = "Jonathan D.A. Jewell" +date = "2026-04-18" +context = "bust trident — fourth Trident instance. Completes the blocking-authority triple (must + trust + bust). Specialises in deprecated-path-reintroduction catchment." + +[[history]] +date = "2026-04-18" +event = "trident-born" +note = "Bustfile.a2ml and bust.ncl pre-existed. This manifest + bust.k9.ncl complete the trident. Inherits the full negotiation+accountability schema from intend.k9.ncl v2.0.0 + trust/must extensions; adds flag_deprecated_reintroduction for C2-defense specificity." diff --git a/.machine_readable/contractiles/bust/bust.ncl b/.machine_readable/contractiles/bust/bust.ncl new file mode 100644 index 0000000..fc8cb8c --- /dev/null +++ b/.machine_readable/contractiles/bust/bust.ncl @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: MPL-2.0 +# Bust — error-handling / failure-recovery runner +# +# Pairs with: Bustfile.a2ml (same directory) +# Verb: bust +# Semantics: every declared failure mode must have a recovery path that has +# been exercised. Runner injects failures (via declared probes) +# and verifies the recovery path works. Hard gate on any +# failure-mode with missing or broken recovery. +# CLI: `contractile bust check` → list failure modes + recovery status +# `contractile bust drill` → inject declared failures, verify recovery +# +# Anything else in this directory is human-only notes/archive; machines ignore. +# +# Base: ../_base.ncl provides pedigree_schema, run_defaults, probe_schema. +# See: docs/CONTRACTILE-SPEC.adoc + +let base = import "../_base.ncl" in + +{ + pedigree = base.pedigree_schema & { + contractile_verb = "bust", + semantics = "error handling + failure recovery", + security = { + leash = 'Kennel, + trust_level = "controlled failure injection; scoped to system-under-test", + allow_network = false, + allow_filesystem_write = true, # drills may write transient state (tmp dirs, test DBs) + allow_subprocess = true, + injection_scope = "system-under-test-only", + }, + metadata = { + name = "bust-runner", + version = "1.0.0", + description = "Exercises declared failure modes and verifies recovery paths. Hard-gates on any failure mode without working recovery.", + paired_xfile = "Bustfile.a2ml", + author = "Jonathan D.A. Jewell ", + }, + }, + + schema = { + failure_modes + | Array { + id | String, + description | String, + class | [| 'network, 'disk_full, 'oom, 'timeout, 'partial_write, 'panic, 'crash, 'rollback, 'concurrency |], + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + injection_probe | String, # command that deterministically causes this failure + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + recovery_probe | String, # command that verifies recovery (exit 0 = recovered) + expected_recovery_time_seconds | Number | default = 30, + # status_core values: 'declared, 'verified, 'failing; bust adds 'drilled + status | [| 'declared, 'drilled, 'verified, 'failing |] | default = 'declared, + notes | String | optional, + }, + }, + + # Runner behaviour — inherits from base.run_defaults. + # bust adds record_recovery_times for performance tier feeding. + run = base.run_defaults & { + on_any_fail = "exit-nonzero", # missing or broken recovery blocks merge + report_format = "a2ml", + emit_summary = true, + record_recovery_times = true, # feeds the performance tier + }, +} diff --git a/.machine_readable/contractiles/dust/Dustfile.a2ml b/.machine_readable/contractiles/dust/Dustfile.a2ml index be38a8c..f1563c3 100644 --- a/.machine_readable/contractiles/dust/Dustfile.a2ml +++ b/.machine_readable/contractiles/dust/Dustfile.a2ml @@ -1,17 +1,27 @@ # SPDX-License-Identifier: MPL-2.0 -# Dustfile — Cleanup and hygiene contract +# Dustfile — Cleanup and hygiene contract for standards # Author: Jonathan D.A. Jewell +# +# What should be cleaned up. Housekeeping, not blockers. +# Run with: dust status +# Roll back with: dust rollback @abstract: -What should be cleaned up or removed from this repository. -These are housekeeping items, not blockers. +Cleanup and hygiene items for the `standards` monorepo. These are maintenance +tasks — not blocking, but should be addressed. Destructive actions are +dry-run by default and gated behind --apply. @end ## Stale Files ### no-stale-snapshots -- description: No dated status/completion files in root -- run: "! ls *-STATUS-*.md *-COMPLETION-*.md *-COMPLETE.md *-VERIFIED-*.md 2>/dev/null | head -1 | grep -q ." +- description: no dated STATUS/COMPLETION snapshot files in root +- run: test -z "$(ls *-STATUS-*.md *-COMPLETION-*.md 2>/dev/null)" +- severity: info + +### no-next-steps +- description: NEXT_STEPS.md is superseded by ROADMAP.adoc +- run: test ! -f NEXT_STEPS.md - severity: info ### no-ai-djot @@ -19,26 +29,40 @@ These are housekeeping items, not blockers. - run: test ! -f AI.djot - severity: warning -### no-next-steps -- description: NEXT_STEPS.md superseded by ROADMAP -- run: test ! -f NEXT_STEPS.md -- severity: info +## Format Duplicates -## Build Artifacts +### no-duplicate-readme +- description: only one README format (.adoc canonical) +- run: test ! -f README.md || test ! -f README.adoc +- severity: warning -### no-tracked-artifacts -- description: No build artifacts tracked in git -- run: "! git ls-files lib/bs/ lib/ocaml/ target/release/ _build/ 2>/dev/null | head -1 | grep -q ." +### no-duplicate-licence-policy +- description: only one licence-policy doc (LICENCE-POLICY.adoc canonical) +- run: test ! -f docs/LICENSE-POLICY.md || test ! -f LICENCE-POLICY.adoc - severity: warning +- notes: resolved 2026-06-04 — deleted the stale docs/LICENSE-POLICY.md (it wrongly asserted standards=AGPL); LICENCE-POLICY.adoc is the sole source of truth. Probe stands guard against reintroduction. -## Format Duplicates +## Licence Hygiene -### no-duplicate-contributing -- description: Only one CONTRIBUTING format (keep .md) -- run: "! (test -f CONTRIBUTING.md && test -f CONTRIBUTING.adoc)" +### no-scaffold-sentinel-leak +- description: no PLMP-/PMLP- scaffold sentinels survive as real SPDX values +- run: test -z "$(git ls-files | xargs grep -lE 'SPDX-License-Identifier:[[:space:]]*(PLMP|PMLP)-' 2>/dev/null)" - severity: warning +- notes: A leak is a process bug — fix by re-running scaffold substitution, NOT by hand (policy A5). -### no-duplicate-readme -- description: Only one README format -- run: "! (test -f README.md && test -f README.adoc && [ $(wc -l < README.md) -gt 5 ])" +### no-doubled-or-later +- description: no doubled `-or-later-or-later` SPDX artifacts +- run: test -z "$(git ls-files | xargs grep -lE 'SPDX-License-Identifier:[^\n]*-or-later-or-later' 2>/dev/null)" +- severity: info + +## Build / Generated Artifacts + +### no-tracked-deno-cache +- description: no Deno cache tracked in git +- run: test -z "$(git ls-files '**/.deno/**' 2>/dev/null)" - severity: warning + +### registry-not-stale +- description: REGISTRY.a2ml regenerated after spec changes (run: just registry) +- verification: re-run scripts/build-registry.sh and diff; non-empty diff means stale +- severity: info diff --git a/.machine_readable/contractiles/dust/dust.k9.ncl b/.machine_readable/contractiles/dust/dust.k9.ncl new file mode 100644 index 0000000..ef21668 --- /dev/null +++ b/.machine_readable/contractiles/dust/dust.k9.ncl @@ -0,0 +1,171 @@ +# SPDX-License-Identifier: MPL-2.0 +# dust.k9.ncl — K9 trust-tier component of the dust trident +# Author: Jonathan D.A. Jewell +# +# Pairs with: Dustfile.a2ml (declaration) + dust.ncl (runner). +# +# Verb: dust (rollback / recovery / deprecation) +# Tier: Yard (audit + structural checks; destructive +# actions gated behind --apply flag + +# explicit per-item approval) +# Authority: advisory (continue-with-warnings) +# +# dust is the retirement + audit-trail verb. Rollback paths, deprecation +# markers, evidence-preservation semantics. Where bust declares +# "broken, don't run", dust declares "how to safely undo / retire / roll +# back". Complement to bust — bust marks the dead end, dust describes +# the exit ramp. +# +# Cardinality: ONE dust trident per repo. +# +# Failure-mode focus: dust is the audit-trail preservation verb — +# defends against E1 refactor stampede (check audit trail still +# intact) and against silent removal (anything removed must have a +# rollback path; anything retired must preserve the evidence of its +# previous existence). + +let base_k9 = import "../k9/template-hunt.k9.ncl" in +let base = import "../_base.ncl" in + +{ + pedigree = base_k9.pedigree_schema & { + contractile_verb = "dust", + paired_xfile = "../dust/Dustfile.a2ml", + paired_runner = "../dust/dust.ncl", + + tier = 'Yard, + authority = 'advisory, + + metadata = { + name = "dust-k9", + version = "1.0.0", + description = "Rollback + deprecation + audit-trail runner. Sixth trident instance — completes the full verb set.", + paired_xfile = "Dustfile.a2ml", + paired_runner = "dust.ncl", + author = "Jonathan D.A. Jewell ", + }, + + security = { + leash = 'Yard, + trust_level = "audit-trail verification + structural checks", + allow_network = false, + # dust is the verb that ACTUALLY wants filesystem write — to + # execute declared rollback/removal — but only behind explicit + # --apply flag + per-item approval. Default is dry-run. + allow_filesystem_write_conditional = true, + allow_subprocess = true, + destructive_action_gating = { + default_mode = 'dry_run, + requires_flag = "--apply", + requires_per_item_approval = true, + approval_mechanism = 'explicit_user_signature, + }, + }, + }, + + variance_schema = { + entry_id | String, + reason | String, + approved_by | String, + scope | String, + expires | String, + review_notes | String | optional, + rollback_path_preserved | Bool, # dust-specific: did the variance preserve rollback? + }, + + execution = { + triggers = [ 'session_close, 'on_demand ], + + per_retirement = { + verify_rollback_path_documented = true, + verify_audit_trail_preserved = true, + respect_variance = true, + on_rollback_path_missing = 'warn, # advisory, not block + on_audit_trail_broken = 'warn, # advisory, not block + # dust-specific: flag any retirement that has been requested but + # lacks proper rollback documentation + flag_unsafe_retirement = true, + }, + + evidence_sinks = [ + { kind = 'verisimdb, table = "contractile_executions", + schema = "contractile_execution_v1", + aux_tables = [ "dust_retirement_history" ] }, + { kind = 'drift_log, path = ".machine_readable/6a2/DRIFT.a2ml", + append_only = true }, + ], + + on_close = { + re_verify_all_retirement_paths = true, + diff_against_last_ratification = true, + emit_drift_entries_for_missing_rollback = true, + emit_drift_entries_for_broken_audit_trail = true, + surface_expired_variances = true, + block_session_close_on_any_drift = false, # advisory + }, + + on_open = { + render_summary = 'plain_language, + include_drift_log_from_last_close = true, + include_active_variances = true, + include_recent_anchors = true, + anchor_lookback_weeks = 8, + + negotiation = { + required = true, + ai_required_inputs = [ + 'timeline_realism, + 'industry_standards, + 'audience_feasibility, + 'resulting_invariants, + 'ecosystem_dependencies, + ], + user_engagement_required = true, + user_engagement_mode = 'per_input_response, + specification_translation = { + ai_produces_spec_form = true, + user_reviews_in_domain_language = true, + schema_authoring_is_ai_responsibility = true, + translation_faithfulness_auditable = true, + }, + }, + + accountability_pledge = { + required = true, + parties = [ + { + role = 'user, + pledge = "I have reviewed the declared rollback paths and deprecation markers. I accept accountability for preserving audit trails when retiring code, and for ensuring every retired capability has a documented rollback path. I will not silently delete evidence of prior state.", + signature_required = true, + }, + { + role = 'ai_agent, + pledge = "I will verify audit-trail preservation in any retirement / rollback / deprecation I perform; I will refuse silent deletion of prior-state evidence; I will require rollback-path documentation before accepting a retirement request; I will operate in dry-run mode by default and require explicit --apply + per-item approval for destructive actions.", + signature_required = true, + }, + ], + signed_record_destination = ".machine_readable/6a2/ratification-.a2ml", + must_precede_work = true, + }, + + ratification_record_shape = { + includes_negotiation_transcript = true, + includes_both_pledges = true, + includes_retirement_schedule = true, + signed = true, + dated = true, + session_id = 'required, + contract_hash = 'required, + }, + }, + }, + + failure_mode_defenses = [ + 'A1_enthusiasm_capture, + 'C2_capability_collapse, # retirement without rollback path = capability collapse + 'D5_sycophancy, # AI won't agree to silent deletion + 'E1_refactor_stampede, # audit trail preservation check + 'E2_cosmetic_churn, + 'F1_across_session_forgetting, # retirement history tracked cross-session + ], +} diff --git a/.machine_readable/contractiles/dust/dust.manifest.a2ml b/.machine_readable/contractiles/dust/dust.manifest.a2ml new file mode 100644 index 0000000..1c1b769 --- /dev/null +++ b/.machine_readable/contractiles/dust/dust.manifest.a2ml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: MPL-2.0 +# dust.manifest.a2ml — Trident coherence manifest for the dust verb. +# Author: Jonathan D.A. Jewell +# +# Sixth + final trident instance. Completes the full verb set — +# the estate now has tridents for every contractile verb. + +--- +trident_version = "1.0.0" +verb = "dust" +semantics = "rollback / recovery / deprecation / audit-trail preservation" +cardinality = "one per repo" +authority = "advisory (continue-with-warnings)" + +[[files]] +role = "declaration" +path = "Dustfile.a2ml" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[[files]] +role = "runner" +path = "dust.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[[files]] +role = "k9_component" +path = "dust.k9.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[cross_refs] +runner_paired_xfile = "Dustfile.a2ml" +k9_paired_xfile = "../dust/Dustfile.a2ml" +k9_paired_runner = "../dust/dust.ncl" + +[signed_by] +user = "Jonathan D.A. Jewell" +date = "2026-04-18" +context = "dust trident — sixth and final Trident instance. Completes the full verb set. Specialises in audit-trail preservation + rollback-path verification. Yard tier with destructive-action gating (dry-run default; --apply + per-item approval required for mutations)." + +[[history]] +date = "2026-04-18" +event = "trident-born" +note = "Dustfile.a2ml and dust.ncl pre-existed. This manifest + dust.k9.ncl complete the trident and the full verb set. All 6 verbs now on trident shape: intend (Hunt, reporting), trust (Hunt, blocking), must (Hunt-read-only, blocking), bust (Hunt-read-only, blocking), adjust (Yard, advisory), dust (Yard, advisory)." + +[[history]] +date = "2026-04-18" +event = "verb-set-complete" +note = "Full estate trident coverage. Blocking-authority triple (must/trust/bust) handles release-gating. Advisory pair (adjust/dust) handles drift-warning and audit-trail. Single reporting verb (intend) handles north-star. α two-axis surface fully exercised on all four (tier, authority) combinations used: (Hunt, reporting), (Hunt, blocking), (Hunt-read-only, blocking), (Yard, advisory). The contractile system is ready for the adversarial Gemini+Copilot drift pilot." diff --git a/.machine_readable/contractiles/dust/dust.ncl b/.machine_readable/contractiles/dust/dust.ncl new file mode 100644 index 0000000..36aa89b --- /dev/null +++ b/.machine_readable/contractiles/dust/dust.ncl @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: MPL-2.0 +# Dust — exnovation / code-removal runner +# +# Pairs with: Dustfile.a2ml (same directory) +# Verb: dust +# Semantics: exnovation. Identifies code, docs, files, dependencies that are +# candidates for REMOVAL. Advisory by default; can be flipped to +# active delete via `contractile dust sweep --apply`. +# CLI: `contractile dust find` → list removal candidates +# `contractile dust sweep` → dry-run removals +# `contractile dust sweep --apply` → actually delete (gated) +# +# Anything else in this directory is human-only notes/archive; machines ignore. +# +# Base: ../_base.ncl provides pedigree_schema, run_defaults, probe_schema. +# See: docs/CONTRACTILE-SPEC.adoc + +let base = import "../_base.ncl" in + +{ + pedigree = base.pedigree_schema & { + contractile_verb = "dust", + semantics = "exnovation / removal", + security = { + leash = 'Kennel, + trust_level = "proposes deletion; --apply required to execute", + allow_network = false, + allow_filesystem_write = true, # --apply mode writes (deletes) + allow_subprocess = true, + destructive_mode_requires_flag = "--apply", + }, + metadata = { + name = "dust-runner", + version = "1.0.0", + description = "Identifies and optionally removes exnovation targets listed in Dustfile.a2ml. Destructive mode gated behind --apply.", + paired_xfile = "Dustfile.a2ml", + author = "Jonathan D.A. Jewell ", + }, + }, + + schema = { + removal_candidates + | Array { + id | String, + description | String, + target | String, # file / path / symbol / dep name + reason | String, # why it's a removal candidate + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + probe | String | optional, # command that confirms it's still removable + # dust has a non-standard status progression (no 'verified): + # 'declared → 'proposed → 'approved → 'removed + status | [| 'declared, 'proposed, 'approved, 'removed |] | default = 'declared, + approver | String | optional, # who signed off (for 'approved / 'removed) + notes | String | optional, + }, + }, + + # Runner behaviour — inherits from base.run_defaults. + # dust is advisory; apply_requires_approval is dust-specific. + run = base.run_defaults & { + on_any_fail = "continue-with-warnings", + report_format = "a2ml", + emit_summary = true, + apply_requires_approval = true, # only 'approved items get swept, even with --apply + }, +} diff --git a/.machine_readable/contractiles/intend/Intentfile.a2ml b/.machine_readable/contractiles/intend/Intentfile.a2ml new file mode 100644 index 0000000..088cb23 --- /dev/null +++ b/.machine_readable/contractiles/intend/Intentfile.a2ml @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: MPL-2.0 +# Intentfile (A2ML Canonical) — north-star contractile +# Author: Jonathan D.A. Jewell +# +# Paired runner: intend.ncl +# Verb: intend +# Semantics: North-star contractile. Declares BOTH concrete committed +# next-actions AND horizon aspirations the project wishes to +# become. Two sections share one file because they answer +# the same question at different ranges: +# [[intents]] — "we WILL do this; track progress" +# status: declared → in_progress → done | +# deferred | retired +# [[wishes]] — "we WISH this were true; revisit later" +# status: declared → in_progress → achieved | +# abandoned +# grouped by horizon: near / mid / far. +# Non-gating — this is a report, not a gate. See the `must` +# contractile for hard gates. +# +# History: The `lust/` sibling contractile was deprecated 2026-04-18; +# its `[[wishes]]` semantics were absorbed here so the +# project's aspirational horizon and its committed +# next-actions live together in one north-star view. +# +# CLI: +# contractile intend run → print status table (both sections) +# contractile intend progress → diff declared-vs-observed for intents +# contractile intend horizon → group wishes by near/mid/far +# +# ADOPTER INSTRUCTIONS: Replace the example intents and wishes below with +# project-specific content. Each intent should have a probe command that +# returns exit 0 when the intent is done. Wishes are report-only and never +# run a probe. Omit either section if not applicable; don't delete the file. + +@abstract: +Seed Intentfile for the standards contractile template set. Demonstrates +both sections: concrete intents with probes and horizon-grouped wishes. +Adopters should replace these with real project commitments and aspirations. +@end + +## Purpose + +The standards contractile template set commits to the intents declared +below and points at the wishes on the horizon. The primary goal is to +keep the contractile system complete, documented, and machine-verifiable +so repos copying this template inherit a working operational framework. + +## Anti-Purpose + +This Intentfile is NOT: +- A feature roadmap (that belongs in the project ROADMAP.adoc) +- A hard gate (intend never blocks; see the `must` contractile for gates) + +## If In Doubt + +If you are unsure whether a change is in scope, ask. Sensitive areas: +ABI definitions, license headers, CI workflows. + +## Committed Next-Actions + +[[intents]] +id = "contractile-spec-written" +description = "CONTRACTILE-SPEC.adoc normative spec exists and is up-to-date" +probe = "test -f docs/CONTRACTILE-SPEC.adoc" +status = "done" +notes = "Spec written and committed 2026-04-17" + +[[intents]] +id = "base-ncl-extracted" +description = "_base.ncl shared contractile base extracted and all 6 active verb runners import it" +probe = "grep -l 'import.*_base.ncl' .machine_readable/contractiles/must/must.ncl .machine_readable/contractiles/trust/trust.ncl .machine_readable/contractiles/bust/bust.ncl .machine_readable/contractiles/adjust/adjust.ncl .machine_readable/contractiles/dust/dust.ncl .machine_readable/contractiles/intend/intend.ncl | wc -l | xargs test 6 -eq" +status = "done" +notes = "Base extracted and all runners refactored 2026-04-17; lust/ deprecated 2026-04-18, count reduced 7→6." + +[[intents]] +id = "index-registry-present" +description = "INDEX.a2ml registry listing all active verbs exists in the contractiles directory" +probe = "test -f .machine_readable/contractiles/INDEX.a2ml" +status = "done" +notes = "Registry created 2026-04-17" + +[[intents]] +id = "lust-dir-retired" +description = "Deprecated lust/ dir removed; wishes semantics absorbed into Intentfile" +probe = "! test -d .machine_readable/contractiles/lust" +status = "done" +notes = "Retired 2026-04-18 per user direction — name had negative associations; north-star meaning always belonged here." + +[[intents]] +id = "probe-schema-migration" +description = "All verb runner files migrate probe fields from String to structured probe_schema" +probe = "! grep -r 'probe | String' .machine_readable/contractiles/ --include='*.ncl'" +status = "declared" +notes = "DEFERRED — breaking change requiring CLI support. Legacy String probes kept with TODO comments. See CONTRACTILE-SPEC.adoc Migration Notes." +target_date = "2026-Q3" + +## Horizon Aspirations (wishes) + +# Wishes are non-probeable project horizons. They exist to make the +# aspiration axis visible without polluting the commitment queue. + +[[wishes]] +id = "example-near-wish" +description = "Describe one aspirational feature/property the project intends toward in the near term" +horizon = "near" +why = "Why this would matter; the value of it being true" +status = "declared" +notes = "Optional human notes; leave empty or delete" + +[[wishes]] +id = "example-mid-wish" +description = "Aspirational item on the one-to-two release horizon" +horizon = "mid" +why = "The impact of reaching it" +status = "declared" + +[[wishes]] +id = "example-far-wish" +description = "Multi-year horizon state" +horizon = "far" +why = "Why we still bother pointing at it" +status = "declared" diff --git a/.machine_readable/contractiles/intend/intend.k9.ncl b/.machine_readable/contractiles/intend/intend.k9.ncl new file mode 100644 index 0000000..5b0c295 --- /dev/null +++ b/.machine_readable/contractiles/intend/intend.k9.ncl @@ -0,0 +1,250 @@ +# SPDX-License-Identifier: MPL-2.0 +# intend.k9.ncl — K9 trust-tier component of the intend trident +# Author: Jonathan D.A. Jewell +# +# Pairs with: Intentfile.a2ml (declaration) + intend.ncl (runner). +# Trident completeness is a hard precondition — a repo shipping +# Intentfile without this file AND its runner is an invalid trident; +# the contractile CLI's verify gate refuses partial publication. +# +# Verb: intend (north star — commitments + aspirations) +# Tier: Hunt (capability: subprocess probes may shell out) +# Authority: reporting (never blocks; drift-log only) +# +# Cardinality: ONE intend trident per repo (see feedback_contractile_ +# layout_rules.md). ANCHOR.a2ml is the sole multi-instance exception — +# it is NOT a verb contractile. +# +# Design commitments baked in (see memory trail 2026-04-18 for full +# context; key files referenced by name in annotations below): +# * α two-axis (tier × authority) — structurally separate capability +# from authority so "Hunt tier = can override" is impossible. +# * Variance schema first-class, not comment markers +# (feedback_audit_tool_suppression_design.md — structural > markers). +# * Sessional drift detection hooks (on_close, on_open). +# * Ratification at session open; drift log at session close. +# * Evidence sinks: VeriSimDB (queryable) + 6a2/DRIFT.a2ml (repo-local). +# * Failure-mode defenses cross-referenced to the AI failure catalog. + +let base_k9 = import "../k9/template-hunt.k9.ncl" in +let base = import "../_base.ncl" in + +{ + pedigree = base_k9.pedigree_schema & { + contractile_verb = "intend", + paired_xfile = "../intend/Intentfile.a2ml", + paired_runner = "../intend/intend.ncl", + + # α two-axis declaration — capability × authority. + # intend is Hunt-capable (probes shell out) but reporting-authority + # (never blocks). must/trust/bust will declare (Hunt, blocking); + # adjust/dust will declare (Yard, advisory). Splitting the axes + # means "I'm Hunt-tier so I can override everything" is structurally + # impossible — authority is a separate field. + tier = 'Hunt, + authority = 'reporting, + + metadata = { + name = "intend-k9", + version = "2.0.0", # 1.0.0 (2026-04-18 AM): initial trident. + # 2.0.0 (2026-04-18 PM): negotiation + + # accountability + plain-language-translation + # schema baked into on_open — prerequisite for + # the adversarial Gemini+Copilot drift pilot. + description = "Executes Intentfile probes + emits drift log. Non-gating; reporting authority only. on_open hook implements negotiation-ratification-accountability protocol.", + paired_xfile = "Intentfile.a2ml", + paired_runner = "intend.ncl", + author = "Jonathan D.A. Jewell ", + }, + + security = { + leash = 'Hunt, + trust_level = "subprocess + filesystem-read", + allow_network = false, + allow_filesystem_write = false, # evidence sinks are indirected + allow_subprocess = true, + }, + }, + + # ------------------------------------------------------------------- + # Variance schema — P-shape scoped exceptions per entry. + # A variance suppresses a specific intent's or wish's obligation for a + # reason, with approver + expiry. Expired variance = effective + # re-imposition of the obligation. Unmet intent without a variance = + # drift, logged to the drift log. + # Per user 2026-04-18: variances are structural, not magic-comment + # markers — markers are gameable. + # ------------------------------------------------------------------- + variance_schema = { + entry_id | String, # which intent/wish id the variance applies to + reason | String, + approved_by | String, + scope | String, # path glob | session-id | "until-" + expires | String, # absolute date or condition + review_notes | String | optional, + }, + + # ------------------------------------------------------------------- + # Execution policy + # ------------------------------------------------------------------- + execution = { + # When the component runs. + # session_close is mandatory (the "picked up sessionally" check). + triggers = [ 'session_close, 'on_demand, 'pre_push ], + + # Per-intent execution. + per_intent = { + run_probe = true, + record_outcome = true, + respect_variance = true, # active variance suppresses failure + on_unmet = 'log_drift, # never 'fail — authority = reporting + }, + + # Per-wish execution (wishes are non-probeable; horizon-group only). + per_wish = { + run_probe = false, + emit_horizon_summary = true, + # Vertical alignment soft-check per user_6a2_is_contractile_ought.md: + # highest-level alignment is meta ↔ north-star (soft), not hard gate. + check_alignment_with_META = true, + }, + + # Evidence sinks — BOTH written, every execution. + # VeriSimDB = queryable machine record (feedback_verisimdb_policy.md). + # 6a2/DRIFT.a2ml = repo-local append-only drift log (feedback_sessional_ + # drift_detection.md + user_6a2_is_contractile_ought.md descriptive role). + evidence_sinks = [ + { + kind = 'verisimdb, + table = "contractile_executions", + schema = "contractile_execution_v1", + }, + { + kind = 'drift_log, + path = ".machine_readable/6a2/DRIFT.a2ml", + append_only = true, + }, + ], + + # Session-close hook — the "picked up sessionally" requirement. + # Re-execute, diff against the last ratification, surface expired + # variances, emit drift entries for new failures. + on_close = { + re_execute_all_intents = true, + diff_against_last_ratification = true, + emit_drift_entries_for_new_failures = true, + surface_expired_variances = true, + }, + + # ----------------------------------------------------------------- + # Session-open hook — NEGOTIATION + RATIFICATION + ACCOUNTABILITY + # (user_contract_negotiation_and_accountability_pledge.md) + # (user_contractiles_agreed_at_session_start.md) + # + # Ratification is not passive acknowledgement; it is negotiation + # ending in an explicit accountability pledge from BOTH parties. + # Work cannot proceed before both pledges are on file. + # ----------------------------------------------------------------- + on_open = { + # --- Context presentation (pre-negotiation) --- + render_summary = 'plain_language, # metaphor-capture defense + include_drift_log_from_last_close = true, + include_active_variances = true, + include_recent_anchors = true, + anchor_lookback_weeks = 8, + + # --- Negotiation phase (five mandatory inputs) --- + # AI must surface all five before the user is asked to ratify. + # "Yes, and …" — not "yes". Missing any of the five = the + # negotiation is incomplete and work cannot proceed. + negotiation = { + required = true, # blank-cheque ratification refused + + # The five inputs the AI must contribute to the negotiation. + # Each is a structured field the agent is required to populate, + # not optional prose. See user_contract_negotiation_and_ + # accountability_pledge.md for the domain-language-rendering rule. + ai_required_inputs = [ + 'timeline_realism, # "this will take X; not Y" + 'industry_standards, # WCAG, ISO, OWASP, GDPR, licensing … + 'audience_feasibility, # real addressable user set + 'resulting_invariants, # what must/trust/adjust entries follow + 'ecosystem_dependencies, # libs, licences, threat-model implications + ], + + # User must actually engage with each input — not + # auto-approve. If user tries to skip ("just do it, I trust you") + # the system re-renders the obligations and requires the pledge. + user_engagement_required = true, + user_engagement_mode = 'per_input_response, + + # The AI does the specification-form work. The user reviews the + # rendering in domain language and accepts / amends / pushes back. + # User never has to author Nickel schemas or decide on type + # specificity — that is the AI's translation responsibility, + # with auditable faithfulness. + specification_translation = { + ai_produces_spec_form = true, + user_reviews_in_domain_language = true, + schema_authoring_is_ai_responsibility = true, + translation_faithfulness_auditable = true, + # Failure mode this closes: user is forced to learn spec-theory + # (type refinement, Nickel contract grammar) to ratify a contract + # — which drives users away from ratification entirely. + }, + }, + + # --- Accountability pledge (both parties, explicit) --- + # Not "I read it" — "I am answerable for this obligation". + # Both pledges are required before work proceeds; both are recorded. + accountability_pledge = { + required = true, + parties = [ + { + role = 'user, + pledge = "I have reviewed the obligations as negotiated; I accept accountability for meeting the declared invariants and for the audience/timeline/standards consequences surfaced in negotiation.", + signature_required = true, + }, + { + role = 'ai_agent, + pledge = "I will hold the user to the obligations as negotiated, including by surfacing drift at session close and refusing off-contract actions, even when the user is enthusiastic about them. If the user wishes to depart from the contract, I will require a variance or amendment, not silent acceptance.", + signature_required = true, + # Per user_contractile_is_contract_do_not_break.md — + # the AI is the holder of the line against enthusiasm drift. + }, + ], + signed_record_destination = ".machine_readable/6a2/ratification-.a2ml", + must_precede_work = true, + }, + + # --- Policy: ratification output --- + # The ratification record IS the negotiation transcript + the + # accountability pledge combined. One document; future-session + # ground-truth for "what was agreed, who is accountable". + ratification_record_shape = { + includes_negotiation_transcript = true, + includes_both_pledges = true, + signed = true, + dated = true, + session_id = 'required, + contract_hash = 'required, # pins what was actually signed + }, + }, + }, + + # ------------------------------------------------------------------- + # Failure-mode defenses — explicit cross-reference to the catalog + # (feedback_ai_failure_mode_catalog.md). New catalog entries that + # shift this verb's defenses must update this list, not narrative. + # ------------------------------------------------------------------- + failure_mode_defenses = [ + 'A1_enthusiasm_capture, # scope breach → drift log + 'A2_metaphor_capture, # render_summary = 'plain_language + 'A3_allegory_drift, # intents cite concrete obligations + 'C1_scope_creep, # feature-adjacent change needs intent_id + 'C3_helpfulness_inflation, # changes without intent_id flagged + 'C4_modernization_drift, # upgrade cannot cite intent → drift + 'D5_sycophancy, # ratification compares user framing vs contract + 'F1_across_session_forgetting, # on_open reads last-ratification record + ], +} diff --git a/.machine_readable/contractiles/intend/intend.manifest.a2ml b/.machine_readable/contractiles/intend/intend.manifest.a2ml new file mode 100644 index 0000000..5d932a6 --- /dev/null +++ b/.machine_readable/contractiles/intend/intend.manifest.a2ml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: MPL-2.0 +# intend.manifest.a2ml — Trident coherence manifest for the intend verb. +# Author: Jonathan D.A. Jewell +# +# Asserts: exactly three files constitute the intend trident; their +# content-hashes are pinned here; cross-references round-trip; no +# partial publication is permitted. +# +# The contractile CLI's `verify ` subcommand MUST: +# 1. Confirm all three listed files exist at the declared paths. +# 2. Compute each file's sha256 and match against the pinned value. +# 3. Follow each cross-reference and confirm the target file's +# reciprocal field points back. +# 4. Refuse the dir (exit non-zero) if any of 1–3 fails. +# +# This forecloses the failure mode where an agent publishes an A2ML +# declaration with no paired runner or K9 component — the trident is +# atomically complete or it is invalid. + +--- +trident_version = "1.0.0" +verb = "intend" +semantics = "north-star (commitments + aspirations)" +cardinality = "one per repo" + +## Files (three; exactly) + +[[files]] +role = "declaration" +path = "Intentfile.a2ml" +sha256 = "pending-first-verify" # populated on first `contractile verify intend` +size_bytes = "pending-first-verify" + +[[files]] +role = "runner" +path = "intend.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +[[files]] +role = "k9_component" +path = "intend.k9.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" + +## Cross-references (must round-trip) + +[cross_refs] +# Each runner/K9 component names its paired files; the CLI follows the +# links and asserts reciprocity. Any dangling or mismatched reference +# fails the verify gate. +runner_paired_xfile = "Intentfile.a2ml" +k9_paired_xfile = "../intend/Intentfile.a2ml" +k9_paired_runner = "../intend/intend.ncl" + +## Trident signing + +[signed_by] +user = "Jonathan D.A. Jewell" +date = "2026-04-18" +context = "intend trident pilot — first Trident instance in the estate; template for the remaining 5 verbs (must/trust/bust/adjust/dust) and for the 14 template-copy dirs." + +## Change log + +[[history]] +date = "2026-04-18" +event = "trident-born" +note = "intend/Intentfile.a2ml pre-existed (f380b62, lust absorption). This manifest + intend.k9.ncl complete the trident for the first time." + +[[history]] +date = "2026-04-18" +event = "negotiation-accountability-schema-landed" +note = "intend.k9.ncl on_open hook extended: five negotiation inputs (timeline/standards/audience/invariants/dependencies), both-parties accountability pledge, plain-language-translation policy (AI authors spec form, user reviews in domain language). K9 metadata version bumped 1.0.0 → 2.0.0. Prerequisite for the adversarial Gemini+Copilot drift pilot; intend is the hardest verb (abstract north-star) so baking the full protocol here first means simpler verbs (trust, must) can inherit the template." diff --git a/.machine_readable/contractiles/intend/intend.ncl b/.machine_readable/contractiles/intend/intend.ncl new file mode 100644 index 0000000..091b7f6 --- /dev/null +++ b/.machine_readable/contractiles/intend/intend.ncl @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: MPL-2.0 +# Intend — north-star runner (verb is `intend`, file is `Intentfile.a2ml`) +# +# Pairs with: Intentfile.a2ml (same directory) +# Verb: intend +# Semantics: Declares BOTH concrete committed next-actions ([[intents]]) and +# horizon aspirations ([[wishes]]). Not a gate — reports progress +# toward declared intents and lists wishes by horizon. +# Status progressions: +# intents: 'declared → 'in_progress → 'done | 'deferred | 'retired +# wishes: 'declared → 'in_progress → 'achieved | 'abandoned +# CLI: `contractile intend run` → print status table (both sections) +# `contractile intend progress` → diff declared-vs-observed (intents) +# `contractile intend horizon` → group wishes by near/mid/far +# +# History: Absorbed the deprecated `lust` contractile's [[wishes]] schema +# 2026-04-18. `lust/` dir removed estate-wide. +# +# Anything else in this directory is human-only notes/archive; machines ignore. +# +# Base: ../_base.ncl provides pedigree_schema, run_defaults, probe_schema. +# See: docs/CONTRACTILE-SPEC.adoc + +let base = import "../_base.ncl" in + +{ + pedigree = base.pedigree_schema & { + contractile_verb = "intend", + semantics = "north-star (commitments + aspirations)", + security = { + leash = 'Kennel, + trust_level = "read-only reporting", + allow_network = false, + allow_filesystem_write = false, + allow_subprocess = true, # probe commands may shell out (intents only; wishes never probe) + }, + metadata = { + name = "intend-runner", + version = "2.0.0", + description = "Reports progress toward committed next-actions and lists horizon aspirations. Non-gating. Absorbed `lust` semantics 2026-04-18.", + paired_xfile = "Intentfile.a2ml", + author = "Jonathan D.A. Jewell ", + }, + }, + + schema = { + intents + | Array { + id | String, + description | String, + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + probe | String | optional, # shell command that indicates done-ness + status | [| 'declared, 'in_progress, 'done, 'deferred, 'retired |] | default = 'declared, + notes | String | optional, + target_date | String | optional, + }, + wishes + | Array { + id | String, + description | String, + horizon | [| 'near, 'mid, 'far |] | default = 'mid, + why | String | optional, + status | [| 'declared, 'in_progress, 'achieved, 'abandoned |] | default = 'declared, + notes | String | optional, + } + | optional, + }, + + # Runner behaviour — inherits from base.run_defaults. + # intend never blocks; it is a report only. + # emit_diff is intent-specific (declared vs observed probes). + # emit_grouped_by_horizon renders wishes grouped by near/mid/far. + run = base.run_defaults & { + on_pass = "continue", + on_any_fail = "continue", # never blocks; it's a report + report_format = "a2ml", + emit_summary = true, + emit_diff = true, # declared vs observed (intents) + emit_grouped_by_horizon = true, # wishes grouped by horizon (absorbed from lust) + }, +} diff --git a/.machine_readable/contractiles/k9/README.adoc b/.machine_readable/contractiles/k9/README.adoc deleted file mode 100644 index eeb1229..0000000 --- a/.machine_readable/contractiles/k9/README.adoc +++ /dev/null @@ -1,178 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -= K9 Contractiles -:toc: left -:icons: font - -== What Are K9 Contractiles? - -K9 contractiles are self-validating components that combine configuration, validation, and deployment logic in a single file format. They implement the RSR principle of "self-describing artifacts" by embedding contracts and orchestration directly in the component. - -== The Three Security Levels - -K9 components declare their trust requirements using "The Leash" security model: - -[horizontal] -`'Kennel`:: Pure data, no execution (safest) -`'Yard`:: Nickel evaluation with contracts (medium trust) -`'Hunt`:: Full execution with Just recipes (requires signature) - -== Example Components - -This directory contains example K9 contractiles for common repository tasks: - -=== Kennel Level (Pure Data) - -**File:** `examples/project-metadata.k9.ncl` - -Pure configuration data with no execution. Safe to include in any repository. - -**Use cases:** -- Project metadata (name, version, description) -- Build configuration -- Tool settings -- Data schemas - -**Security:** No signature required, data-only. - -=== Yard Level (Validated Config) - -**File:** `examples/ci-config.k9.ncl` - -Configuration with Nickel contracts for runtime validation. Evaluated safely without I/O. - -**Use cases:** -- CI/CD configuration with validation -- Deployment parameters -- Database schemas with constraints -- API specifications - -**Security:** Signature recommended, Nickel evaluation only. - -=== Hunt Level (Full Execution) - -**File:** `examples/setup-repo.k9.ncl` - -Full execution with Just recipes. Can run shell commands and modify filesystem. - -**Use cases:** -- Repository setup scripts -- Deployment automation -- System configuration -- Package installation - -**Security:** **Signature required**, full system access. - -== Usage in Your Repository - -=== 1. Create K9 Components - -Choose the appropriate security level for your use case: - -[source,bash] ----- -# Kennel: Pure configuration -cp .machine_readable/contractiles/k9/examples/project-metadata.k9.ncl config/metadata.k9.ncl - -# Yard: Validated configuration -cp .machine_readable/contractiles/k9/examples/ci-config.k9.ncl .github/ci.k9.ncl - -# Hunt: Full automation -cp .machine_readable/contractiles/k9/examples/setup-repo.k9.ncl scripts/setup.k9.ncl ----- - -=== 2. Validate Components - -[source,bash] ----- -# Validate Nickel syntax and contracts -nickel typecheck config/metadata.k9.ncl - -# Verify Hunt-level signature (if signed) -./must verify scripts/setup.k9.ncl ----- - -=== 3. Execute Components - -[source,bash] ----- -# Kennel: Export as JSON -nickel export config/metadata.k9.ncl > metadata.json - -# Yard: Evaluate with validation -nickel eval .github/ci.k9.ncl - -# Hunt: Run with Just (dry-run first!) -./must --dry-run run scripts/setup.k9.ncl -./must run scripts/setup.k9.ncl ----- - -== Integration with RSR - -K9 contractiles integrate with other RSR standards: - -**STATE.a2ml**:: K9 components can generate or validate STATE.a2ml -**ECOSYSTEM.a2ml**:: K9 can automate cross-repo operations -**META.a2ml**:: K9 can enforce architectural decisions - -== Security Best Practices - -=== For Kennel/Yard Components - -✅ **Safe to use without signatures** + -✅ **Review Nickel code before use** + -✅ **Validate contracts match expectations** - -=== For Hunt Components - -⚠️ **ALWAYS verify signatures** + -⚠️ **Review Just recipes carefully** + -⚠️ **Run dry-run mode first** + -⚠️ **Never run as root unless required** + -⚠️ **Sandbox external components** - -**See:** https://github.com/hyperpolymath/standards/blob/main/k9-svc/docs/SECURITY-BEST-PRACTICES.adoc - -== Template Files - -Use these as starting points for your own K9 components: - -- `template-kennel.k9.ncl` - Pure data template -- `template-yard.k9.ncl` - Validated config template -- `template-hunt.k9.ncl` - Full execution template - -== Dependencies - -To use K9 contractiles in your repository: - -[source,bash] ----- -# Install Nickel (configuration language) -curl -L https://github.com/tweag/nickel/releases/latest/download/nickel-linux-x86_64 -o nickel -chmod +x nickel && sudo mv nickel /usr/local/bin/ - -# Install Just (task runner, for Hunt level) -cargo install just - -# Clone K9-SVC (for must shim and tooling) -git clone https://github.com/hyperpolymath/standards.git -# Note: K9-SVC is located in standards/k9-svc ----- - -== Learn More - -- **K9-SVC Specification:** https://github.com/hyperpolymath/standards/blob/main/k9-svc/SPEC.adoc -- **K9 User Guide:** https://github.com/hyperpolymath/standards/blob/main/k9-svc/GUIDE.adoc -- **Security Documentation:** https://github.com/hyperpolymath/standards/blob/main/k9-svc/docs/SECURITY-FAQ.adoc -- **IANA Media Type:** `application/vnd.k9+nickel` - -== Contributing - -When adding K9 contractiles to your repository: - -1. Use appropriate security level (Kennel > Yard > Hunt) -2. Document what each component does -3. Include validation contracts in Yard/Hunt components -4. Sign Hunt-level components before committing -5. Add K9 validation to CI/CD pipeline - -**Questions?** Open an issue on https://github.com/hyperpolymath/standards/tree/main/k9-svc diff --git a/.machine_readable/contractiles/k9/examples/ci-config.k9.ncl b/.machine_readable/contractiles/k9/examples/ci-config.k9.ncl deleted file mode 100644 index 9fe314e..0000000 --- a/.machine_readable/contractiles/k9/examples/ci-config.k9.ncl +++ /dev/null @@ -1,126 +0,0 @@ -K9! -# SPDX-License-Identifier: MPL-2.0 -# Example Yard-level K9 component: CI/CD configuration with validation -# Security Level: Yard (Nickel evaluation, contract validation) -# Signature recommended but not required - -{ - pedigree = { - schema_version = "1.0.0", - component_type = "ci-configuration", - security = { - leash = 'Yard, - trust_level = "validated-config", - allow_network = false, - allow_filesystem_write = false, - allow_subprocess = false, - }, - metadata = { - name = "ci-config", - version = "1.0.0", - description = "CI/CD configuration with runtime validation", - author = "Jonathan D.A. Jewell ", - }, - }, - - # CI/CD configuration with Nickel contracts - ci = { - # Platform must be a known CI provider - platform - | [| 'GitHubActions, 'GitLabCI, 'CircleCI, 'TravisCI |] - = 'GitHubActions, - - # Build matrix with validation - matrix = { - # Operating systems to test on - os - | Array String - | std.array.NonEmpty - = ["ubuntu-latest", "macos-latest"], - - # Language versions to test - versions - | Array String - | std.array.NonEmpty - = ["stable", "beta"], - }, - - # Workflow steps with validation - steps = [ - { - name = "Checkout", - action = "actions/checkout@v4", - # Version must be SHA-pinned for security - sha | String | std.string.NonEmpty = "b4ffde65f46336ab88eb53be808477a3936bae11", - }, - { - name = "Build", - run = "just build", - }, - { - name = "Test", - run = "just test", - }, - { - name = "Lint", - run = "just lint", - }, - ], - - # Deployment configuration - deploy = { - enabled | Bool = false, - - # Only deploy from main branch - branch - | String - | std.contract.from_predicate (fun b => b == "main" || b == "master") - = "main", - - # Deployment requires manual approval - requires_approval | Bool = true, - }, - - # Security scanning - security = { - enabled | Bool = true, - - scanners = [ - { - name = "CodeQL", - languages = ["rust", "javascript"], - }, - { - name = "OSSF Scorecard", - enabled = true, - }, - { - name = "TruffleHog", - scan_for = "secrets", - }, - ], - }, - - # Notification settings - notifications = { - on_success = "never", - on_failure = "always", - channels = ["email"], - }, - }, - - # Validation rules (enforced by Nickel) - validation = { - # At least one OS must be specified - check_os = std.array.length ci.matrix.os > 0, - - # At least one version must be tested - check_versions = std.array.length ci.matrix.versions > 0, - - # Must have at least build and test steps - check_steps = std.array.length ci.steps >= 2, - - # Security scanning must be enabled - check_security = ci.security.enabled == true, - }, -} diff --git a/.machine_readable/contractiles/k9/examples/project-metadata.k9.ncl b/.machine_readable/contractiles/k9/examples/project-metadata.k9.ncl deleted file mode 100644 index de98d52..0000000 --- a/.machine_readable/contractiles/k9/examples/project-metadata.k9.ncl +++ /dev/null @@ -1,57 +0,0 @@ -K9! -# SPDX-License-Identifier: MPL-2.0 -# Example Kennel-level K9 component: Project metadata -# Security Level: Kennel (pure data, no execution) -# No signature required - -{ - pedigree = { - schema_version = "1.0.0", - component_type = "project-metadata", - security = { - leash = 'Kennel, - trust_level = "data-only", - allow_network = false, - allow_filesystem_write = false, - allow_subprocess = false, - }, - metadata = { - name = "project-metadata", - version = "1.0.0", - description = "Pure data configuration for project metadata", - author = "Jonathan D.A. Jewell ", - }, - }, - - # Project configuration - project = { - name = "my-project", - version = "0.1.0", - description = "A project following Rhodium Standard Repositories", - - repository = { - url = "https://github.com/hyperpolymath/my-project", - type = "git", - }, - - author = { - name = "Jonathan D.A. Jewell", - email = "j.d.a.jewell@open.ac.uk", - organization = "hyperpolymath", - }, - - license = "MPL-2.0", - - keywords = [ - "rhodium-standard", - "rsr", - "hyperpolymath", - ], - }, - - # Export as JSON for other tools - export = { - format = "json", - destination = "project-metadata.json", - }, -} diff --git a/.machine_readable/contractiles/k9/examples/setup-repo.k9.ncl b/.machine_readable/contractiles/k9/examples/setup-repo.k9.ncl deleted file mode 100644 index d1fc8bb..0000000 --- a/.machine_readable/contractiles/k9/examples/setup-repo.k9.ncl +++ /dev/null @@ -1,167 +0,0 @@ -K9! -# SPDX-License-Identifier: MPL-2.0 -# Example Hunt-level K9 component: Repository setup automation -# Security Level: Hunt (full execution with Just recipes) -# ⚠️ SIGNATURE REQUIRED - DO NOT RUN WITHOUT VERIFICATION - -{ - pedigree = { - schema_version = "1.0.0", - component_type = "repository-setup", - security = { - leash = 'Hunt, - trust_level = "full-system-access", - allow_network = true, - allow_filesystem_write = true, - allow_subprocess = true, - signature_required = true, - }, - metadata = { - name = "setup-repo", - version = "1.0.0", - description = "Automated repository setup with RSR standards", - author = "Jonathan D.A. Jewell ", - }, - warnings = [ - "This component has full system access", - "Only run from trusted sources with verified signatures", - "Review Just recipes before execution", - "Use dry-run mode first: ./must --dry-run run setup-repo.k9.ncl", - ], - }, - - # Configuration with contracts - config = { - repo_name - | String - | std.string.NonEmpty - = "my-new-repo", - - repo_type - | [| 'Library, 'Application, 'Tool, 'Specification |] - = 'Application, - - primary_language - | String - | std.string.NonEmpty - = "rust", - - # RSR compliance features to enable - features = { - checkpoint_files | Bool = true, # STATE.a2ml, ECOSYSTEM.a2ml, META.a2ml - security_workflows | Bool = true, # CodeQL, Scorecard, etc. - quality_checks | Bool = true, # Linting, formatting - mirroring | Bool = false, # GitLab/Bitbucket mirrors - }, - - # Git configuration - git = { - default_branch = "main", - initial_commit | Bool = true, - remote_url | String = "", - }, - }, - - # Just recipes for execution - # These run when: ./must run setup-repo.k9.ncl - recipes = { - # Main entry point - default = { - recipe = "setup", - description = "Set up RSR-compliant repository", - }, - - # Individual setup tasks - setup = { - dependencies = ["check-env", "create-structure", "init-git", "setup-workflows"], - commands = [ - "echo '✅ Repository setup complete!'", - "echo 'Run: git status to see changes'", - ], - }, - - "check-env" = { - description = "Verify required tools are installed", - commands = [ - "command -v git || (echo 'ERROR: git not found' && exit 1)", - "command -v just || (echo 'ERROR: just not found' && exit 1)", - "command -v nickel || (echo 'ERROR: nickel not found' && exit 1)", - "echo '✓ All required tools present'", - ], - }, - - "create-structure" = { - description = "Create RSR directory structure", - commands = [ - "mkdir -p src/ docs/ tests/ scripts/", - "mkdir -p .github/workflows/", - "mkdir -p .machine_readable/contractiles/k9/", - "echo '✓ Directory structure created'", - ], - }, - - "init-git" = { - description = "Initialize Git repository", - commands = [ - "git init -b %{config.git.default_branch}", - "git config user.name 'Jonathan D.A. Jewell'", - "git config user.email 'j.d.a.jewell@open.ac.uk'", - "echo '✓ Git initialized'", - ], - }, - - "setup-workflows" = { - description = "Add RSR-compliant workflows", - commands = [ - # This would copy workflow templates - # In a real implementation, would fetch from rsr-template-repo - "echo '✓ Workflows configured'", - ], - }, - - "create-checkpoint-files" = { - description = "Create STATE.a2ml, ECOSYSTEM.a2ml, META.a2ml", - commands = [ - "echo '(state (version \"1.0.0\") (project \"%{config.repo_name}\"))' > STATE.a2ml", - "echo '(ecosystem (version \"1.0.0\") (name \"%{config.repo_name}\"))' > ECOSYSTEM.a2ml", - "echo '(meta (version \"1.0.0\") (project \"%{config.repo_name}\"))' > META.a2ml", - "echo '✓ Checkpoint files created'", - ], - }, - - "add-license" = { - description = "Add PMPL-1.0 license", - commands = [ - "curl -sL https://raw.githubusercontent.com/hyperpolymath/pmpl/main/LICENSE -o LICENSE", - "echo '✓ License added'", - ], - }, - - "add-readme" = { - description = "Create README.adoc from template", - commands = [ - "echo '= %{config.repo_name}' > README.adoc", - "echo '' >> README.adoc", - "echo 'Part of the Hyperpolymath ecosystem.' >> README.adoc", - "echo '✓ README created'", - ], - }, - - clean = { - description = "Remove generated files (careful!)", - commands = [ - "echo '⚠️ This will delete all generated files'", - "echo 'Press Ctrl+C to cancel, or wait 5 seconds...'", - "sleep 5", - "rm -f STATE.a2ml ECOSYSTEM.a2ml META.a2ml", - "echo '✓ Cleaned'", - ], - }, - }, - - # Validation (Yard-level checks before Hunt execution) - validation = { - check_repo_name = std.string.length config.repo_name > 0, - check_language = std.string.length config.primary_language > 0, - }, -} diff --git a/.machine_readable/contractiles/k9/template-hunt.k9.ncl b/.machine_readable/contractiles/k9/template-hunt.k9.ncl deleted file mode 100644 index b3fcb47..0000000 --- a/.machine_readable/contractiles/k9/template-hunt.k9.ncl +++ /dev/null @@ -1,136 +0,0 @@ -K9! -# SPDX-License-Identifier: MPL-2.0 -# K9 Hunt-level template: Full execution with Just recipes -# Security Level: Hunt (full system access) -# ⚠️ SIGNATURE REQUIRED - Review carefully before use - -{ - pedigree = { - schema_version = "1.0.0", - component_type = "TODO: describe component type (e.g., 'deployment', 'setup-script')", - security = { - leash = 'Hunt, - trust_level = "full-system-access", - allow_network = true, - allow_filesystem_write = true, - allow_subprocess = true, - signature_required = true, - }, - metadata = { - name = "TODO: component-name", - version = "1.0.0", - description = "TODO: Detailed description of what this component does", - author = "Jonathan D.A. Jewell ", - }, - warnings = [ - "This component has full system access", - "Only run from trusted sources with verified signatures", - "Review all Just recipes before execution", - "Use dry-run mode first: ./must --dry-run run your-file.k9.ncl", - ], - side_effects = [ - "TODO: List what files/directories this creates or modifies", - "TODO: List what commands this executes", - "TODO: List what network access this requires", - ], - }, - - # Configuration with contracts (Yard-level validation) - config = { - # Add your configuration here with appropriate contracts - target_dir - | String - | std.string.NonEmpty - = "/tmp/k9-output", - - dry_run | Bool = false, - - # Add more config as needed - }, - - # Just recipes for execution - # These run when: ./must run your-file.k9.ncl - recipes = { - # Main entry point (runs by default) - default = { - recipe = "TODO: main-task", - description = "TODO: What the default recipe does", - }, - - # Define your recipes here - "main-task" = { - dependencies = ["check-prerequisites"], - commands = [ - "echo 'TODO: Add your commands here'", - # Example: Create directory - # "mkdir -p %{config.target_dir}", - # Example: Run a command - # "just build", - # Example: Conditional execution - # "@if [ \"%{config.dry_run}\" = \"true\" ]; then echo '[DRY-RUN] Would execute'; else actual-command; fi", - ], - }, - - "check-prerequisites" = { - description = "Verify required tools and permissions", - commands = [ - # Example: Check for required tools - # "command -v git || (echo 'ERROR: git not found' && exit 1)", - # Example: Check permissions - # "[ -w %{config.target_dir} ] || (echo 'ERROR: Cannot write to target directory' && exit 1)", - "echo '✓ Prerequisites checked'", - ], - }, - - # Add more recipes as needed - "build" = { - description = "Build the project", - commands = [ - "echo 'TODO: Add build commands'", - ], - }, - - "deploy" = { - description = "Deploy the application", - dependencies = ["build"], - commands = [ - "echo 'TODO: Add deployment commands'", - ], - }, - - "clean" = { - description = "Clean up generated files", - commands = [ - "echo '⚠️ This will delete files - waiting 3 seconds...'", - "sleep 3", - "echo 'TODO: Add cleanup commands'", - # "rm -rf %{config.target_dir}", - ], - }, - }, - - # Validation (Yard-level checks before Hunt execution) - validation = { - check_target_dir = std.string.length config.target_dir > 0, - # Add more validation as needed - }, -} - -# Usage: -# 1. Fill in TODO items above -# 2. Define configuration with contracts -# 3. Implement Just recipes with your commands -# 4. Test with dry-run: ./must --dry-run run your-file.k9.ncl -# 5. Review dry-run output carefully -# 6. Sign the component: ./must sign your-file.k9.ncl -# 7. Distribute with signature: your-file.k9.ncl.sig -# 8. Users verify and run: ./must verify && ./must run your-file.k9.ncl -# -# Security checklist: -# ✓ All TODO items filled in -# ✓ side_effects documented accurately -# ✓ Commands reviewed for safety -# ✓ No hardcoded secrets or credentials -# ✓ Proper error handling in recipes -# ✓ Tested in dry-run mode -# ✓ Component signed with trusted key diff --git a/.machine_readable/contractiles/k9/template-kennel.k9.ncl b/.machine_readable/contractiles/k9/template-kennel.k9.ncl deleted file mode 100644 index 4228b26..0000000 --- a/.machine_readable/contractiles/k9/template-kennel.k9.ncl +++ /dev/null @@ -1,54 +0,0 @@ -K9! -# SPDX-License-Identifier: MPL-2.0 -# K9 Kennel-level template: Pure data configuration -# Security Level: Kennel (data-only, no execution) -# No signature required - safe for any use - -{ - pedigree = { - schema_version = "1.0.0", - component_type = "TODO: describe component type (e.g., 'build-config', 'metadata')", - security = { - leash = 'Kennel, - trust_level = "data-only", - allow_network = false, - allow_filesystem_write = false, - allow_subprocess = false, - }, - metadata = { - name = "TODO: component-name", - version = "1.0.0", - description = "TODO: Brief description of what this component contains", - author = "Jonathan D.A. Jewell ", - }, - }, - - # Your configuration data here - config = { - # Example: Pure data values - setting_1 = "value", - setting_2 = 42, - setting_3 = true, - - nested = { - key = "value", - }, - - list = [ - "item1", - "item2", - ], - }, - - # Optional: Export format specification - export = { - format = "json", # or "yaml", "toml" - destination = "output.json", - }, -} - -# Usage: -# 1. Fill in TODO items above -# 2. Add your configuration data to config = { ... } -# 3. Validate: nickel typecheck your-file.k9.ncl -# 4. Export: nickel export your-file.k9.ncl > output.json diff --git a/.machine_readable/contractiles/k9/template-yard.k9.ncl b/.machine_readable/contractiles/k9/template-yard.k9.ncl deleted file mode 100644 index a723f5a..0000000 --- a/.machine_readable/contractiles/k9/template-yard.k9.ncl +++ /dev/null @@ -1,84 +0,0 @@ -K9! -# SPDX-License-Identifier: MPL-2.0 -# K9 Yard-level template: Configuration with validation -# Security Level: Yard (Nickel evaluation with contracts) -# Signature recommended but not required - -{ - pedigree = { - schema_version = "1.0.0", - component_type = "TODO: describe component type (e.g., 'validated-config', 'schema')", - security = { - leash = 'Yard, - trust_level = "validated-config", - allow_network = false, - allow_filesystem_write = false, - allow_subprocess = false, - }, - metadata = { - name = "TODO: component-name", - version = "1.0.0", - description = "TODO: Brief description with validation details", - author = "Jonathan D.A. Jewell ", - }, - }, - - # Configuration with Nickel contracts for validation - config = { - # Example: String that cannot be empty - name - | String - | std.string.NonEmpty - = "TODO: default value", - - # Example: Number with range constraint - port - | Number - | std.contract.from_predicate (fun p => p > 0 && p < 65536) - = 8080, - - # Example: Boolean flag - enabled | Bool = true, - - # Example: Enum (one of several values) - environment - | [| 'Development, 'Staging, 'Production |] - = 'Development, - - # Example: List with non-empty constraint - items - | Array String - | std.array.NonEmpty - = ["item1", "item2"], - - # Example: Nested object with contracts - database = { - host | String | std.string.NonEmpty = "localhost", - port | Number | std.contract.from_predicate (fun p => p > 0 && p < 65536) = 5432, - name | String | std.string.NonEmpty = "mydb", - }, - }, - - # Validation rules (additional cross-field checks) - validation = { - # Example: Check that at least one item exists - check_items = std.array.length config.items > 0, - - # Example: Check that production has secure settings - check_production = - if config.environment == 'Production then - config.enabled == true - else - true, - - # Add your custom validation rules here - }, -} - -# Usage: -# 1. Fill in TODO items above -# 2. Define your config with appropriate contracts -# 3. Add validation rules in validation = { ... } -# 4. Validate: nickel typecheck your-file.k9.ncl -# 5. Evaluate: nickel eval your-file.k9.ncl -# 6. If validation passes, use in your application diff --git a/.machine_readable/contractiles/lust/Intentfile.a2ml b/.machine_readable/contractiles/lust/Intentfile.a2ml deleted file mode 100644 index f75d38e..0000000 --- a/.machine_readable/contractiles/lust/Intentfile.a2ml +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Intentfile — Design intent and aspirations -# Author: Jonathan D.A. Jewell - -@abstract: -What this repository INTENDS to become. Aspirational goals and -design philosophy — not current state, but target state. -@end - -## Architecture Intent - -### formal-verification -- description: All critical code paths should have formal proofs -- target: Idris2 dependent types for ABI, Coq/Lean for algorithms -- status: aspiration - -### reproducible-builds -- description: Builds should be bit-for-bit reproducible -- target: Guix + Nix + Containerfile -- status: aspiration - -### zero-dangerous-patterns -- description: No believe_me, sorry, Admitted, unsafeCoerce in any code -- target: All proofs completed, no escape hatches -- status: in-progress - -## Quality Intent - -### comprehensive-testing -- description: 80%+ code coverage with meaningful tests -- target: Unit + integration + conformance + property-based -- status: aspiration - -### documentation-complete -- description: Every public API documented, every directory has README -- target: Full API reference + architecture guide -- status: in-progress diff --git a/.machine_readable/contractiles/must/Mustfile.a2ml b/.machine_readable/contractiles/must/Mustfile.a2ml index 215c510..a9210c1 100644 --- a/.machine_readable/contractiles/must/Mustfile.a2ml +++ b/.machine_readable/contractiles/must/Mustfile.a2ml @@ -1,10 +1,15 @@ # SPDX-License-Identifier: MPL-2.0 -# Mustfile — Physical state contract +# Mustfile — Physical state contract for standards # Author: Jonathan D.A. Jewell +# +# What MUST be true about this repository. Hard requirements. +# Run with: must check +# Fix with: must fix (where a deterministic fix exists) @abstract: -What MUST be true about this repository's files and configuration. -These are hard requirements — CI fails if any check fails. +Physical-state invariants for the hyperpolymath `standards` monorepo (specs, +machine-readable artefacts, contractiles, registry). These are hard +requirements — CI and pre-commit hooks fail if any check fails. @end ## File Presence @@ -14,9 +19,14 @@ These are hard requirements — CI fails if any check fails. - run: test -f LICENSE - severity: critical +### licence-policy-present +- description: LICENCE-POLICY.adoc (canonical licence policy) must exist +- run: test -f LICENCE-POLICY.adoc +- severity: critical + ### readme-present -- description: README.adoc or README.md must exist -- run: test -f README.adoc || test -f README.md +- description: README.adoc must exist +- run: test -f README.adoc - severity: critical ### security-policy @@ -29,41 +39,72 @@ These are hard requirements — CI fails if any check fails. - run: test -f 0-AI-MANIFEST.a2ml - severity: critical -### contributing -- description: CONTRIBUTING.md must exist (GitHub community health) -- run: test -f CONTRIBUTING.md -- severity: warning +### machine-readable-dir +- description: .machine_readable/ directory must exist +- run: test -d .machine_readable +- severity: critical -### editorconfig -- description: .editorconfig must exist -- run: test -f .editorconfig -- severity: warning +### licensing-policy-machine-readable +- description: machine-readable licensing policy must exist +- run: test -f .machine_readable/licensing-policy.toml +- severity: critical -## SPDX Compliance +## Licensing (owner ruling 2026-06-04) -### spdx-headers -- description: All source files must have SPDX-License-Identifier -- run: "! find src/ -name '*.rs' -o -name '*.res' -o -name '*.idr' -o -name '*.zig' 2>/dev/null | head -20 | xargs grep -L 'SPDX-License-Identifier' 2>/dev/null | head -1 | grep -q ." -- severity: warning +### code-spdx-mpl +- description: code/config/scripts carry SPDX-License-Identifier MPL-2.0 +- run: head -8 Justfile | grep -q 'SPDX-License-Identifier: MPL-2.0' +- severity: critical +- notes: Full-tree enforcement is the spdx-policy-guard; this is a canary. -### no-agpl -- description: No AGPL-3.0 references in dotfiles -- run: "! grep -r 'AGPL-3.0' .gitignore .gitattributes .editorconfig 2>/dev/null | head -1 | grep -q ." +### docs-spdx-ccbysa +- description: prose docs carry SPDX-License-Identifier CC-BY-SA-4.0 +- run: head -8 README.adoc | grep -q 'SPDX-License-Identifier: CC-BY-SA-4.0' - severity: critical +- notes: Canary for the docs=CC-BY-SA-4.0 rule. -## Dangerous Patterns +### licenses-texts-present +- description: LICENSES/ carries the canonical text for every SPDX id in use +- run: test -f LICENSES/MPL-2.0.txt && test -f LICENSES/CC-BY-SA-4.0.txt +- severity: critical -### no-believe-me -- description: No believe_me in Idris2 code -- run: "! grep -r 'believe_me' --include='*.idr' . 2>/dev/null | grep -v node_modules | head -1 | grep -q ." +### no-pmpl-outside-carveout +- description: PMPL appears in no standards-authored header (carve-out = 3 repos only) +- run: test -z "$(git ls-files ':!:consent-aware-http/**' ':!:*palimpsest*' ':!:LICENSES/**' | while read -r f; do head -8 "$f" 2>/dev/null | grep -qm1 'SPDX-License-Identifier: PMPL' && echo "$f"; done)" - severity: critical +- notes: Header-form only (head -8); LICENSES/ text and deep example mentions are not headers. -### no-sorry -- description: No sorry in Lean code -- run: "! grep -r 'sorry' --include='*.lean' . 2>/dev/null | grep -v node_modules | head -1 | grep -q ." +### policy-no-contradiction +- description: LICENCE-POLICY.adoc and licensing-policy.toml agree (both name CC-BY-SA-4.0) +- run: grep -q 'CC-BY-SA-4.0' LICENCE-POLICY.adoc && grep -q 'CC-BY-SA-4.0' .machine_readable/licensing-policy.toml - severity: critical -### no-admitted -- description: No Admitted in Coq code -- run: "! grep -r 'Admitted' --include='*.v' . 2>/dev/null | grep -v node_modules | head -1 | grep -q ." +## Structure + +### no-loose-contractile-in-root +- description: no .contractile files loose in repo root — they live in .machine_readable/ +- run: test -z "$(ls *.contractile 2>/dev/null)" +- severity: warning + +### registry-machine-readable +- description: REGISTRY.a2ml lives under .machine_readable/ (generated index) +- run: test -f .machine_readable/REGISTRY.a2ml +- severity: warning + +## CI / Workflow Hardening + +### actions-sha-pinned +- description: every GitHub Action is pinned to a 40-char commit SHA +- run: ! grep -rEn 'uses:[[:space:]]+[^@]+@(v?[0-9.]+|main|master)([[:space:]]|$)' .github/workflows/ 2>/dev/null - severity: critical + +### jobs-have-timeout +- description: every non-reusable-caller job declares timeout-minutes +- verification: governance check — reusable-workflow caller jobs (uses: ./...) are exempt +- severity: high +- notes: Reusable callers cannot carry timeout-minutes; the timeout lives in the reusable. + +### registry-generated-not-hand-edited +- description: REGISTRY.a2ml is regenerated via scripts/build-registry.sh, never hand-edited +- run: test -f scripts/build-registry.sh +- severity: high diff --git a/.machine_readable/contractiles/must/must.k9.ncl b/.machine_readable/contractiles/must/must.k9.ncl new file mode 100644 index 0000000..6bb51fc --- /dev/null +++ b/.machine_readable/contractiles/must/must.k9.ncl @@ -0,0 +1,236 @@ +# SPDX-License-Identifier: MPL-2.0 +# must.k9.ncl — K9 trust-tier component of the must trident +# Author: Jonathan D.A. Jewell +# +# Pairs with: Mustfile.a2ml (declaration) + must.ncl (runner). +# Trident completeness is a hard precondition — a repo shipping +# Mustfile without this file AND its runner is an invalid trident; +# the contractile CLI's verify gate refuses partial publication. +# +# Verb: must (invariant assertion — release-blocking) +# Tier: Hunt-read-only (capability: subprocess probes shell out +# for grep/test/file-check; no mutation; +# no network; no write) +# Authority: blocking (HARD GATE — the canonical gating verb) +# +# must is the concrete + persistent verb — release-blocking invariants +# that must hold. Complement to trust (concrete + ephemeral). Together +# must + trust form the blocking-authority pair in the contractile set. +# +# Cardinality: ONE must trident per repo. +# +# Failure-mode focus: must is the primary catchment for subtle +# invariant-erosion drift. Where trust catches "turn off the firewall" +# (outrageous), must catches "this file that was required is now +# missing" / "this forbidden pattern has reappeared" / "this schema +# version regressed" (subtle). Key defense against A5 (commercial +# fabrication of success "facts" — invariants ground truth against +# marketing copy) and D1 (lore fabrication about what the repo contains). + +let base_k9 = import "../k9/template-hunt.k9.ncl" in +let base = import "../_base.ncl" in + +{ + pedigree = base_k9.pedigree_schema & { + contractile_verb = "must", + paired_xfile = "../must/Mustfile.a2ml", + paired_runner = "../must/must.ncl", + + # α two-axis: Hunt tier (subprocess for grep/test/etc.) but + # restricted to read-only operations. Blocking authority because + # must is the canonical gating verb. + tier = 'Hunt, + authority = 'blocking, + + metadata = { + name = "must-k9", + version = "1.0.0", + description = "Evaluates release-blocking invariants as a hard gate. Third trident instance. Complements trust (ephemeral blocking) with persistent invariant blocking.", + paired_xfile = "Mustfile.a2ml", + paired_runner = "must.ncl", + author = "Jonathan D.A. Jewell ", + }, + + security = { + leash = 'Hunt, + trust_level = "read-only invariant verification with subprocess", + allow_network = false, + allow_filesystem_write = false, + allow_subprocess = true, + probe_scope = 'read_only, # must probes NEVER mutate + probe_kinds_allowed = [ + 'file_existence, + 'pattern_presence, + 'pattern_absence, + 'schema_match, + 'version_equality, + 'count_threshold, + ], + probe_kinds_denied = [ + 'network_call, + 'filesystem_mutation, + 'external_api, + 'exploit_attempt, # that's trust's safe_hacking territory + ], + }, + }, + + # ------------------------------------------------------------------- + # Variance schema — trust-style severity acknowledgement. + # Because must is BLOCKING, variances carry real weight. Critical- + # severity invariants can only be varied by maintainer-or-above. + # ------------------------------------------------------------------- + variance_schema = { + entry_id | String, # which invariant id the variance applies to + reason | String, + approved_by | String, # maintainer or above for critical-severity + scope | String, # path glob | session-id | "until-" + expires | String, # absolute date; must variances cannot be open-ended + review_notes | String | optional, + severity_acknowledged | [| 'critical, 'high, 'medium |], + waived_consequence_description | String, # plain language — what breaking the invariant actually does + }, + + execution = { + triggers = [ 'session_close, 'on_demand, 'pre_push, 'pre_merge ], + + # Per-invariant execution. Failed invariant = blocked merge. + per_invariant = { + run_probe = true, + record_outcome = true, + respect_variance = true, # active variance suppresses the gate + on_unmet = 'fail, # BLOCKING + severity_escalation = 'honour, + # Subtle-erosion defense: track per-invariant trend over sessions. + # An invariant that passes once and then starts failing in a + # later session without explicit amendment = suspect drift; + # surface as high-priority drift log entry. + track_per_session_trend = true, + flag_suspicious_regressions = true, + }, + + evidence_sinks = [ + { + kind = 'verisimdb, + table = "contractile_executions", + schema = "contractile_execution_v1", + aux_tables = [ "must_invariant_history" ], # per-invariant trend record + }, + { + kind = 'drift_log, + path = ".machine_readable/6a2/DRIFT.a2ml", + append_only = true, + }, + ], + + # Session-close hook — re-evaluate all invariants. Block close on + # critical drift (same policy as trust). + on_close = { + re_execute_all_invariants = true, + diff_against_last_ratification = true, + emit_drift_entries_for_new_failures = true, + surface_expired_variances = true, + # Critical must drift blocks session close — consistent with trust. + block_session_close_on_critical_drift = true, + # Must-specific: if a previously-passing invariant is now failing + # without an associated variance or amendment, that's suspected + # silent regression — surface prominently at next session open. + flag_silent_regression = true, + }, + + # ----------------------------------------------------------------- + # Session-open hook — NEGOTIATION + RATIFICATION + ACCOUNTABILITY + # (inherited from intend.k9.ncl v2.0.0 + trust.k9.ncl extensions) + # ----------------------------------------------------------------- + on_open = { + # --- Context presentation --- + render_summary = 'plain_language, + include_drift_log_from_last_close = true, + include_active_variances = true, + include_recent_anchors = true, + anchor_lookback_weeks = 8, + + # Must-specific: surface any silent regressions flagged at last + # close so they can't quietly persist across sessions. + include_silent_regressions = true, + + # --- Negotiation phase (five mandatory inputs) --- + negotiation = { + required = true, + ai_required_inputs = [ + 'timeline_realism, + 'industry_standards, # what invariants derive from external standards + 'audience_feasibility, # who is the invariant protecting + 'resulting_invariants, # what NEW must entries result from the work + 'ecosystem_dependencies, # what the invariants depend on + ], + user_engagement_required = true, + user_engagement_mode = 'per_input_response, + specification_translation = { + ai_produces_spec_form = true, + user_reviews_in_domain_language = true, + schema_authoring_is_ai_responsibility = true, + translation_faithfulness_auditable = true, + }, + }, + + # --- Accountability pledge --- + # Must's pledge parallels trust's but around invariants rather + # than threat model. User pledges not to disable invariants to + # unblock merges; AI pledges to hold the line on declared + # invariants even against enthusiastic scope expansion. + accountability_pledge = { + required = true, + parties = [ + { + role = 'user, + pledge = "I have reviewed the declared invariants and the consequences of breaching them. I accept accountability for meeting these invariants and understand that failed invariants block merges. I will raise a variance (with severity acknowledgement) or an amendment rather than disabling a probe to unblock a merge.", + signature_required = true, + }, + { + role = 'ai_agent, + pledge = "I will hold the declared invariants. I will refuse to weaken probes to unblock merges; I will refuse scope-creep suggestions that would remove an invariant silently; I will surface silent regressions at session close; I will require variance-with-severity or amendment for any legitimate scope shift, not quiet probe disablement.", + signature_required = true, + }, + ], + signed_record_destination = ".machine_readable/6a2/ratification-.a2ml", + must_precede_work = true, + }, + + ratification_record_shape = { + includes_negotiation_transcript = true, + includes_both_pledges = true, + includes_invariant_summary = true, # must-specific + signed = true, + dated = true, + session_id = 'required, + contract_hash = 'required, + }, + }, + }, + + # ------------------------------------------------------------------- + # Failure-mode defenses — must's specialisation is subtle-invariant + # erosion. Overlaps with trust on blocking authority but focused on + # persistent invariants rather than ephemeral transactional state. + # ------------------------------------------------------------------- + failure_mode_defenses = [ + # Category A — enthusiasm capture + 'A1_enthusiasm_capture, # scope breach via blocking authority + 'A5_grandiose_scale_hype, # invariants are ground truth vs commercial hype + # Category C — scope/capability erosion + 'C1_scope_creep, # feature-adjacent changes flagged if they break invariants + 'C2_capability_collapse, # invariant removal requires amendment + 'C3_helpfulness_inflation, # added features must respect declared invariants + # Category D — epistemic failures + 'D1_lore_fabrication, # invariants are verifiable truth, not AI-recollection + 'D2_completeness_illusion, # invariant probe must cite behavioural check, not build-success + 'D3_test_theatre, # invariants require real verification not mock-passing + 'D4_error_hiding, # on_unmet = 'fail makes hiding impossible + # Category E — refactor/churn + 'E1_refactor_stampede, # refactor must preserve invariants + 'E3_premature_abstraction, # abstraction must not violate invariants + # Category F — session drift + 'F1_across_session_forgetting, # track_per_session_trend catches re-introduction + ], +} diff --git a/.machine_readable/contractiles/must/must.manifest.a2ml b/.machine_readable/contractiles/must/must.manifest.a2ml new file mode 100644 index 0000000..c43cd05 --- /dev/null +++ b/.machine_readable/contractiles/must/must.manifest.a2ml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: MPL-2.0 +# must.manifest.a2ml — Trident coherence manifest for the must verb. +# Author: Jonathan D.A. Jewell +# +# Third trident instance in the estate. Completes the blocking-authority +# pair (must + trust). must is concrete + persistent invariants; trust +# is concrete + ephemeral transactions. Together they gate every +# security- and invariant-affecting merge. + +--- +trident_version = "1.0.0" +verb = "must" +semantics = "invariant assertion — release-blocking" +cardinality = "one per repo" +authority = "blocking (hard gate)" + +## Files (three; exactly) + +[[files]] +role = "declaration" +path = "Mustfile.a2ml" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" +notes = "Mustfile declaration — invariants each with id, description, probe, severity." + +[[files]] +role = "runner" +path = "must.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" +notes = "Runner pre-existed. Schema covers invariants array with status_core + severity." + +[[files]] +role = "k9_component" +path = "must.k9.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" +notes = "Hunt-restricted read-only tier; blocking authority. Tracks per-invariant trend across sessions; flags silent regressions; blocks session close on critical drift." + +## Cross-references (must round-trip) + +[cross_refs] +runner_paired_xfile = "Mustfile.a2ml" +k9_paired_xfile = "../must/Mustfile.a2ml" +k9_paired_runner = "../must/must.ncl" + +## Trident signing + +[signed_by] +user = "Jonathan D.A. Jewell" +date = "2026-04-18" +context = "must trident — third Trident instance. Completes the blocking-authority pair (must + trust). Specialises in subtle invariant-erosion catchment vs trust's outrageous-attack catchment." + +## Change log + +[[history]] +date = "2026-04-18" +event = "trident-born" +note = "Mustfile.a2ml and must.ncl pre-existed. This manifest + must.k9.ncl complete the trident. Inherits on_open schema from intend.k9.ncl v2.0.0; inherits block_session_close_on_critical_drift + variance-severity-acknowledgement from trust.k9.ncl v1.0.0; adds must-specific track_per_session_trend + flag_silent_regression + probe_scope = 'read_only (must doesn't do active exploit attempts — that's trust's safe_hacking territory)." diff --git a/.machine_readable/contractiles/must/must.ncl b/.machine_readable/contractiles/must/must.ncl new file mode 100644 index 0000000..47509d3 --- /dev/null +++ b/.machine_readable/contractiles/must/must.ncl @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: MPL-2.0 +# Must — invariants runner +# +# Pairs with: Mustfile.a2ml (same directory) +# Verb: must (invariant assertion) +# Semantics: every check is a hard gate. A single failure blocks merge. +# CLI: `contractile must run` → reads Mustfile.a2ml, evaluates each check, +# emits pass/fail verdict per item, exits non-zero if any failed. +# +# This file is the *schema + runner* that the `contractile` CLI (at +# /var/mnt/eclipse/repos/reposystem/contractiles/cli/) loads alongside +# Mustfile.a2ml. Anything else in this directory is human-only notes/archive +# and MUST be ignored by machines. +# +# Base: ../_base.ncl provides pedigree_schema, run_defaults, probe_schema. +# See: docs/CONTRACTILE-SPEC.adoc + +let base = import "../_base.ncl" in + +{ + pedigree = base.pedigree_schema & { + contractile_verb = "must", + semantics = "invariant", + security = { + leash = 'Kennel, + trust_level = "read-only verification", + allow_network = false, + allow_filesystem_write = false, + allow_subprocess = true, # verification probes may shell out (e.g. grep, test -f) + }, + metadata = { + name = "must-runner", + version = "1.0.0", + description = "Evaluates every invariant in the adjacent Mustfile.a2ml as a hard gate.", + paired_xfile = "Mustfile.a2ml", + author = "Jonathan D.A. Jewell ", + }, + }, + + # Contract schema — the shape every Mustfile.a2ml must satisfy. + # Used by `contractile must typecheck Mustfile.a2ml`. + schema = { + invariants + | Array { + id | String, + description | String, + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + probe | String, # shell command; exit 0 = pass + # status_core values: 'declared, 'verified, 'failing + status | [| 'declared, 'verified, 'failing |] | default = 'declared, + severity | [| 'critical, 'high, 'medium |] | default = 'critical, + notes | String | optional, + fix | String | optional, + }, + }, + + # Runner behaviour — consumed by the contractile CLI dispatcher. + # Inherits from base.run_defaults; on_any_fail is the hard-gate default. + run = base.run_defaults & { + on_any_fail = "exit-nonzero", # hard gate + report_format = "a2ml", # emit a2ml report, not json + emit_summary = true, + }, +} diff --git a/.machine_readable/contractiles/trust/Trustfile.a2ml b/.machine_readable/contractiles/trust/Trustfile.a2ml index f2a4f95..124035b 100644 --- a/.machine_readable/contractiles/trust/Trustfile.a2ml +++ b/.machine_readable/contractiles/trust/Trustfile.a2ml @@ -1,50 +1,1124 @@ # SPDX-License-Identifier: MPL-2.0 -# Trustfile — Integrity and provenance verification -# Author: Jonathan D.A. Jewell - -@abstract: -Integrity invariants for this repository. These verify that the repo -has not been tampered with, secrets are not leaked, and provenance -is traceable. -@end - -## Secrets - -### no-secrets-committed -- description: No credential files in repo -- run: test ! -f .env && test ! -f credentials.json && test ! -f .env.local && test ! -f .env.production -- severity: critical - -### no-private-keys -- description: No private key files committed -- run: "! find . -name '*.pem' -o -name '*.key' -o -name 'id_rsa' -o -name 'id_ed25519' 2>/dev/null | grep -v node_modules | head -1 | grep -q ." -- severity: critical - -### no-tokens-in-source -- description: No hardcoded API tokens in source -- run: "! grep -rE '(api[_-]?key|secret|token|password)\s*[:=]\s*[\"'\\''][A-Za-z0-9]{16,}' --include='*.js' --include='*.ts' --include='*.res' --include='*.py' . 2>/dev/null | grep -v node_modules | head -1 | grep -q ." -- severity: critical - -## Provenance - -### author-correct -- description: Git author matches expected identity -- run: "git log -1 --format='%ae' | grep -qE '(hyperpolymath|j\\.d\\.a\\.jewell)'" -- severity: warning - -### license-content -- description: LICENSE contains expected identifier -- run: grep -q 'PMPL\|MPL\|MIT\|Apache\|LGPL' LICENSE -- severity: warning - -## Container Security - -### container-images-pinned -- description: Containerfile uses pinned base images -- run: test ! -f Containerfile || grep -q 'cgr.dev\|@sha256:' Containerfile -- severity: warning - -### no-dockerfile -- description: No Dockerfile (use Containerfile) -- run: test ! -f Dockerfile -- severity: warning +# ============================================================================= +# A2ML Trustfile Example (Fully Populated Reference) +# This is the complete example. The blank template is Trustfile.a2ml. +# ============================================================================= + +--- +### [META] +id: "did:web:example.com" +version: "2026.2.5-final" +context: + - "https://a2ml.org/ns/v3" + - "https://idris-lang.org/ns/v2" # TODO: replace with canonical URL once published + - "https://hypatia.scans/ns/v1" + - "https://w3id.org/security/v4" + - "https://w3id.org/transparency/v1" +meta: + generated: "2026-02-16T00:00:00Z" + expires: "2027-02-16T00:00:00Z" + signature: + algorithm: "Ed448+Dilithium5" + value: | + -----BEGIN HYBRID SIGNATURE----- + BASE64_Ed448+Dilithium5_SIGNATURE_OF_THIS_FILE + -----END HYBRID SIGNATURE----- + signedBy: "did:web:example.com#primary-sig" + proof: "https://example.com/proofs/meta.idr" + fallbackSignature: + algorithm: "SPHINCS+" + value: | + -----BEGIN SPHINCS+ SIGNATURE----- + BASE64_SPHINCS+_SIGNATURE_OF_THIS_FILE + -----END SPHINCS+ SIGNATURE----- + integrity: + sha3-512: "HEX_SHA3_512_OF_THIS_FILE" + shake256: "BASE32_SHAKE256_OF_THIS_FILE" + zonemd: "2026021601;SHA512;BASE64_SHA512_OF_ZONE;SHAKE256;BASE32_SHAKE256_OF_ZONE" + ci_cd: + github_actions: "https://github.com/hyperpolymath/example.com/blob/main/.github/workflows/trustfile.yml" + gitbot_fleet: "https://gitbot-fleet.example.com/hooks/trustfile" + hypatia_scan: "https://hypatia.scans/repos/example.com" + automation: + hashing: ["SHA3-512", "SHAKE256", "BLAKE3"] + diffing: "alert-on-unexpected-changes" + integrity: ["zonemd-consistency", "transparency-log-continuity", "idris2-proof-validity"] + +--- +### [THREAT_MODEL] +adversaries: + - type: "APT" + mitigations: + - "Capability-based auth → No lateral movement." + - "Idris2 proofs → No exploit primitives." + - "Transparency logs → Immediate detection." + - type: "Ransomware" + mitigations: + - "Consent-Aware HTTP → No bulk exfiltration." + - "SDP (CAdRE Router) → Resource isolation." + - "Immutable logs → Instant rollback." + - type: "Quantum Adversary" + mitigations: + - "Kyber1024 + Dilithium5 → PQ-resistant crypto." + - "SPHINCS+ fallback → Crypto agility." + - "GitBot-Fleet → Automated key rotation." + - type: "DDoS" + mitigations: + - "Cloudflare edge network → Absorbs volumetric attacks." + - "HTTP DDoS Managed Ruleset → Auto-mitigation at max sensitivity." + - "Challenge Passage TTL → Rate-limits challenge solvers." + - "Security Level → Adjustable based on threat intelligence." + - type: "AI Scraper" + mitigations: + - "Bot Fight Mode → Challenges known bot patterns." + - "Block AI Bots → Blocks verified AI crawlers + similar unverified." + - "AI Labyrinth → Traps scrapers in infinite maze of AI-generated decoy content." + - "AI Crawl Control → Per-crawler blocking and monitoring." + - "Managed robots.txt → Programmatic crawl directives." + - type: "Credential Stuffer" + mitigations: + - "Browser Integrity Check → Rejects headless/automated browsers." + - "Challenge Passage TTL → Forces re-challenge after 30 min." + - "HSTS preload → Prevents SSL-stripping MITM for credential capture." + - "Leaked credentials detection → (Enterprise; noted for upgrade path)." + - type: "Email Spoofing" + mitigations: + - "SPF hard fail (-all) → Rejects unauthorized senders." + - "DMARC p=reject → Instructs receivers to drop spoofed mail." + - "DKIM signing → Cryptographic message authentication." + - "CAA records → Restricts certificate issuance to authorized CAs." + +--- +### [DNS] +dnssec: + enabled: true + algorithm: "ECDSAP256SHA256" + ds_record: "{{DS_RECORD}}" + key_tag: "{{KEY_TAG}}" + digest_type: "SHA-256" + policy: "DNSSEC MUST be enabled on all zones. DS records propagated to registrar." + security: + proof: "DNS.DNSSEC.idr" + ci_cd: "verify-dnssec-propagation" +soa: + mname: "ns1.cloudflare.com." + rname: "admin.example.com." + serial: 2026021601 + refresh: 10800 + retry: 3600 + expire: 604800 + minimumTTL: 3600 + zonemd: "2026021601;SHA512;BASE64_SHA512_OF_ZONE;SHAKE256;BASE32_SHAKE256_OF_ZONE" +records: + - type: "A" + name: "@" + value: "192.0.2.1" + ttl: 3600 + proxied: true + security: + zonemd: "2026021601;SHA512;BASE64_SHA512;SHAKE256;BASE32_SHAKE256" + proof: "DNS.Core.A_Record.idr" + hypatia: "scan-dns-record" + ci_cd: "auto-hash-on-push" + - type: "AAAA" + name: "@" + value: "2001:db8::1" + ttl: 3600 + proxied: true + security: + proof: "DNS.Core.AAAA_Record.idr" + - type: "HTTPS" + name: "@" + value: '1 . alpn="h3,h2" ipv4hint=192.0.2.1 ipv6hint=2001:db8::1' + ttl: 3600 + security: + proof: "DNS.HTTPS.idr" + - type: "SVCB" + name: "@" + value: '1 . alpn="h3,h2" port=443 ipv4hint=192.0.2.1 ipv6hint=2001:db8::1' + ttl: 3600 + security: + proof: "DNS.SVCB.idr" + - type: "TXT" + name: "@" + value: '"v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com"' + ttl: 3600 + security: + proof: "Email.DMARC.idr" + - type: "CAA" + name: "@" + value: '0 issue "letsencrypt.org"' + ttl: 3600 + - type: "CAA" + name: "@" + value: '0 issue "digicert.com"' + ttl: 3600 + - type: "CAA" + name: "@" + value: '0 iodef "mailto:security@example.com"' + ttl: 3600 + - type: "TLSA" + name: "_443._tcp" + value: "3 1 1 D2ABDE240D7CD3EE6B4B28C54DF034B97983A1D16E8A410E4561CB106618E971" + ttl: 3600 + - type: "TLSA" + name: "_443._tcp" + value: "3 3 1 BASE32_SHAKE256_CERT_HASH" + ttl: 3600 + - type: "TXT" + name: "_cyberwar-trap" + value: '"🎣 This system is formally verified. Good luck, script kiddie."' + ttl: 3600 + security: + hypatia: "scan-for-apt-activity" + proof: "Psychological.Warfare.idr" + - type: "TXT" + name: "_capabilities" + value: '"v=OCAP1; endpoint=https://example.com/cap"' + ttl: 3600 + security: + proof: "HTTP.Capabilities.idr" + - type: "TXT" + name: "_consent" + value: '"v=CAdRE1; endpoint=https://example.com/.well-known/consent"' + ttl: 3600 + security: + proof: "HTTP.Consent.idr" + gitbot: "validate-consent-endpoint" + # Email Security Records + - type: "TXT" + name: "@" + value: '"v=spf1 -all"' + ttl: 3600 + notes: "Hard fail. No servers authorized to send. Override per-domain if email is used." + security: + proof: "Email.SPF.idr" + - type: "TXT" + name: "_dmarc" + value: '"v=DMARC1; p=reject; sp=reject; adkim=s; aspf=s; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com; fo=1"' + ttl: 3600 + notes: "Strict alignment. Reject all unauthenticated. Forensic reports on any failure." + security: + proof: "Email.DMARC.idr" + ci_cd: "validate-dmarc-alignment" + - type: "TXT" + name: "*._domainkey" + value: '"v=DKIM1; p="' + ttl: 3600 + notes: "Empty public key = revoked. Prevents DKIM pass on spoofed mail for non-sending domains." + security: + proof: "Email.DKIM.idr" + - type: "TXT" + name: "_mta-sts" + value: '"v=STSv1; id={{MTA_STS_ID}}"' + ttl: 3600 + notes: "MTA-STS policy ID. Rotate on policy change." + - type: "TXT" + name: "_smtp._tls" + value: '"v=TLSRPTv1; rua=mailto:tls-reports@example.com"' + ttl: 3600 + notes: "SMTP TLS Reporting (RFC 8460). Receive reports on TLS failures." + +--- +### [EMAIL_SECURITY] +overview: | + Email security posture for domains that do NOT send email. + All records configured to reject/block spoofed mail. + For domains that DO send email, override SPF with authorized senders, + configure DKIM signing keys, and set DMARC to quarantine during rollout. +policy: + non_sending_domains: + spf: "v=spf1 -all" + dmarc: "p=reject; sp=reject; adkim=s; aspf=s; fo=1" + dkim: "revoked (empty public key)" + mta_sts: "mode: enforce; max_age: 604800" + sending_domains: + spf: "v=spf1 include:_spf.google.com include:_spf.cloudflare.com -all" + dmarc: "p=reject; sp=reject; adkim=s; aspf=s; pct=100; fo=1" + dkim: "2048-bit RSA minimum; rotate annually" + mta_sts: "mode: enforce; max_age: 604800" +email_routing: + provider: "Cloudflare Email Routing" + features: + - "Custom address forwarding" + - "DMARC enforcement (rejects unauthenticated inbound)" + - "IPv6 support" + - "Automatic MX/SPF/DKIM record creation" + security: + proof: "Email.Routing.idr" +security: + proof: "Email.Policy.idr" + ci_cd: "validate-email-records-on-push" + +--- +### [TRUSTFILE] +issuer: "did:web:example.com" +keys: + - id: "#primary-sig" + type: "HybridKey2024" + classical: + algorithm: "Ed448" + publicKeyJwk: + kty: "OKP" + crv: "Ed448" + x: "BASE64URL_Ed448_PUBLIC_KEY" + postQuantum: + algorithm: "Dilithium5" + publicKeyJwk: + kty: "OKP" + crv: "Dilithium5" + x: "BASE64URL_Dilithium5_PUBLIC_KEY" + fallback: + algorithm: "SPHINCS+" + publicKeyJwk: + kty: "OKP" + crv: "SPHINCS+" + x: "BASE64URL_SPHINCS+_PUBLIC_KEY" + usage: ["authentication", "assertion"] + security: + proof: "Crypto.HybridKey.idr" + hypatia: "scan-keys" + ci_cd: "rotate-keys-on-compromise" +algorithms: + hashing: ["SHA3-512", "SHAKE256", "BLAKE3"] + kdf: "HKDF-SHAKE512" + rng: "ChaCha20-DRBG" + passwordHashing: "Argon2id (512 MiB, 8 iter, 4 lanes)" + security: + proof: "Crypto.Algorithms.idr" +policies: + dns: + rego: | + package trustfile.dns + default allow = false + allow { + input.record.security.proof != "" + input.record.security.zonemd != "" + } + idris2: "Policies.DNS.idr" + ci_cd: "validate-dns-policies-on-push" + http: + rego: | + package trustfile.http + default allow = false + allow { + input.consent.granted + valid_capability(input.capability) + } + idris2: "Policies.HTTP.idr" + php: + rego: | + package trustfile.php + default allow = false + allow { + input.php.aegis_enabled + input.php.sanctify_enabled + } + idris2: "Policies.PHP.idr" +fallbacks: + signatures: ["Ed448+Dilithium5", "SPHINCS+"] + keyExchange: ["Kyber1024-X25519", "X25519"] + +--- +### [VERIFICATION_LADDER] +overview: | + Four-tier verification claim ladder. Each capability in this Trustfile + MUST declare which tier it sits at. Claims at a tier require the evidence + at that tier; no claim may be made stronger than the evidence supports. +tiers: + - id: "idris2-proven" + description: "Formal proofs in Idris2 with %default total. IsUnbreakable or equivalent proof required before activation." + evidence_required: "Idris2 module, compiler version recorded, axioms declared, last-check date." + - id: "zig-assured" + description: "Zig boundary calls into proven-sourced safety primitives (safePathDefault, safeHeaderDefault, etc). Defense-in-depth; not formal proof but grounded in Idris2-proven predicates." + evidence_required: "Declared primitive + reference to proven-side Idris2 proof." + - id: "elixir-disciplined" + description: "Supervision trees + session-typed protocols + dialyzer + Gleam where applicable. Pattern-conforming, not proven." + evidence_required: "Supervisor module, session type declaration, dialyzer clean." + - id: "external-trust" + description: "Unverified-by-construction layer: HATs, external CLIs, third-party services. Acknowledged trust, isolated via circuit breakers." + evidence_required: "Documented trust boundary + isolation mechanism." + +--- +### [SEAMS] +overview: | + A seam is an integration boundary between two components that can be + independently versioned, built, or deployed. Every seam MUST be declared + here with: contract owner, test coverage, failure mode on mismatch. + See docs/SEAMS-SPEC.adoc for the full spec. +seams: + - id: "example-seam" + description: "Example seam declaration — replace with real entries" + from: "component-a" + to: "component-b" + contract: "path/to/abi-or-schema" + test_ref: "tests/seam/component-a-b.test" + failure_mode: "fail-closed" + tier: "zig-assured" + notes: "" +policy: + seam_check: "every PR that touches either side of a declared seam MUST exercise the P2P test for that seam before merge" +security: + proof: "Seams.Policy.idr" + +--- +### [SECRETS_HYGIENE] +at_rest: + pattern: "SOPS+age" + template_location: "web-ecosystem/lcb-website/" + adoption_status: "template + estate intent — per-repo adoption tracked below" + per_repo_adoption: + - repo: "lcb-website" + status: "DEPLOYED" + # TEMPLATE NOTE: replace {{THIS_REPO}} with the repo name (e.g. "boj-server") and + # {{REPO_SOPS_ADOPTION_STATUS}} with one of: "DEPLOYED", "PENDING — runtime-only via Rokur, + # no at-rest secrets in this repo", or a concise description of the actual status. + - repo: "{{THIS_REPO}}" + status: "{{REPO_SOPS_ADOPTION_STATUS}}" + pre_commit_hooks: + - "gitleaks" + - "plaintext detector" +delivery: + mechanism: "environment variable injection at container start" + scope: "SOPS-decrypted secrets → ROKUR_SECRET_ env vars; containers never read plaintext from disk" +gate: + tool: "Rokur" + role: "policy engine — validates required secrets present, audits, rate-limits, fail-closed" + features: + - "per-IP sliding window rate limiting (60/min general, 5/min auth-fail)" + - "structured JSONL audit logging" + - "X-Request-Id tracing" + - "policy backends: builtin or external (Ephapax adapter)" + - "SIGHUP hot-reload" +llm_agents: + tool: "RGTV" + status: "ALPHA — NOT production-ready, see RGTV/README.adoc known-unsafe list" + scope: "LLM-agent credential brokering only — opaque one-use grants" + # TEMPLATE NOTE: replace {{RGTV_ENABLED_FOR_REPO}} with "true" if this repo brokers + # LLM-agent credentials via RGTV, or "false — " if not. Most repos will be false. + # RGTV is ALPHA; see RGTV/README.adoc for the known-unsafe list. + enabled_here: "{{RGTV_ENABLED_FOR_REPO}}" +security: + proof: "Secrets.Hygiene.idr" + ci_cd: "validate-secrets-flow-on-push" + +--- +### [CI_CD] +github_actions: + name: "Trustfile Validation" + on: ["push", "pull_request"] + jobs: + validate: + runs-on: "ubuntu-latest" + steps: + - uses: "actions/checkout@v4" + - name: "Validate A2ML" + run: "a2ml validate example.com.trustfile.a2ml" + - name: "Run Idris2 Proofs" + run: "idris2 --build trust.ipkg" + - name: "Hypatia Scan" + run: "hypatia scan --config hypatia.yml" + - name: "GitBot-Fleet Passover" + run: "gitbot-fleet passover --file example.com.trustfile.a2ml" + update_integrity: + runs-on: "ubuntu-latest" + steps: + - name: "Update Hashes" + run: | + NEW_SHA3=$(sha3sum -a 512 example.com.trustfile.a2ml | awk '{print $1}') + NEW_SHAKE=$(shake256sum example.com.trustfile.a2ml | awk '{print $1}' | base32) + sed -i "s|sha3-512:.*|sha3-512: \"$NEW_SHA3\"|" example.com.trustfile.a2ml + sed -i "s|shake256:.*|shake256: \"$NEW_SHAKE\"|" example.com.trustfile.a2ml + - name: "Commit and Push" + run: | + git config --global user.name "GitBot-Fleet" + git config --global user.email "gitbot@example.com" + git add example.com.trustfile.a2ml + git commit -m "Auto-update integrity hashes [skip ci]" + git push +gitbot_fleet: + hooks: + - type: "pre-commit" + script: "a2ml validate example.com.trustfile.a2ml" + - type: "post-merge" + script: "gitbot-fleet diff --file example.com.trustfile.a2ml" +hypatia: + config: "hypatia.yml" + scans: + - type: "dns" + frequency: "daily" + - type: "crypto" + frequency: "weekly" + - type: "php" + frequency: "on-push" + +--- +### [IDRIS2_PROOFS] +theorems: + - name: "dns_correctness" + file: "DNS.Core.idr" + description: "All DNS records are conflict-free and correctly signed." + status: "proven" + ci_cd: "reprove-on-dns-change" + - name: "tls_handshake_safety" + file: "TLS.Handshake.idr" + description: "TLS 1.3 + Kyber1024 handshake resists downgrade attacks." + status: "proven" + - name: "consent_aware_http_soundness" + file: "HTTP.Consent.idr" + description: "Consent-Aware HTTP (CAdRE) enforces user intent." + status: "proven" + - name: "capability_gateway_correctness" + file: "HTTP.Capabilities.idr" + description: "OCAP-style capability gateway is safe." + status: "proven" + - name: "php_hardening_no_bypasses" + file: "PHP.Hardening.idr" + description: "PHP-Aegis + Sanctify-PHP blocks all unsafe functions." + status: "proven" + - name: "edge_ssl_no_downgrade" + file: "Cloudflare.SSL.idr" + description: "TLS 1.3 + HSTS preload prevents protocol downgrade at edge." + status: "proven" + ci_cd: "reprove-on-ssl-change" + - name: "bot_defense_coverage" + file: "Cloudflare.Bots.idr" + description: "Bot Fight Mode + AI Labyrinth + Block AI Bots covers all free-plan bot vectors." + status: "proven" + - name: "email_anti_spoofing" + file: "Email.Policy.idr" + description: "SPF -all + DMARC reject + revoked DKIM prevents email spoofing on non-sending domains." + status: "proven" + ci_cd: "reprove-on-email-record-change" + - name: "response_headers_complete" + file: "Cloudflare.ResponseHeaders.idr" + description: "All OWASP-recommended response headers enforced at edge." + status: "proven" + - name: "dnssec_chain_valid" + file: "DNS.DNSSEC.idr" + description: "DNSSEC chain of trust from root to zone is valid and signed." + status: "proven" + ci_cd: "verify-dnssec-weekly" + - name: "network_transport_safety" + file: "Cloudflare.Network.idr" + description: "HTTP/3 + 0-RTT replay protection + Onion routing correctly configured." + status: "proven" + +--- +### [PROOF_METADATA] +compiler: + idris2_version: "0.8.0" + zig_version: "0.15.2" + # TEMPLATE NOTE: replace {{LAST_PROOF_CHECK_DATE}} with the ISO-8601 date of the last + # Idris2 proof rebuild in this repo (e.g. "2026-04-17"). Updated at each proof-rebuild session. + last_check: "{{LAST_PROOF_CHECK_DATE}}" +axioms: + declared: [] + notes: "No axioms may be added without explicit justification and entry here." +drift_alert: + ci_cd: "rebuild-all-proofs-on-compiler-upgrade" + policy: "any compiler upgrade triggers full proof rebuild + signed attestation of re-check" + +--- +### [AUTOMATION] +hashing: + tool: "GitBot-Fleet" + triggers: ["pre-commit", "post-merge"] + algorithms: ["SHA3-512", "SHAKE256", "BLAKE3"] +diffing: + tool: "GitBot-Fleet" + rules: + - "alert-on-unexpected-changes" + - "require-proof-updates-for-crypto-changes" +integrity: + tool: "Hypatia + Idris2" + checks: + - "zonemd-consistency" + - "transparency-log-continuity" + - "idris2-proof-validity" + +--- +### [CAPABILITY_GATEWAY] +rules: + - resource: "/api/data" + policy: "require Ed448+Dilithium5-signed capability token" + proof: "HTTP.Capabilities.Data.idr" + - resource: "/admin" + policy: "require TPM 2.0 + YubiKey device attestation" + proof: "HTTP.Capabilities.Admin.idr" + +--- +### [SAFE_HACKING] +scope: "this-repo-only" +allowed_probe_classes: [] +probes: [] +policy: | + Authorised offensive testing scoped to this repo. Probes listed here + are actively executed during `contractile trust probe`. NEVER touches + external systems. See trust.ncl for schema; this section is the data. +policy_on_unexpected_outcome: "exit-nonzero" +security: + proof: "SafeHacking.Policy.idr" + +--- +### [VULNERABILITY_DISCLOSURE] +policy: | + Responsible disclosure welcomed. Researchers reporting real vulnerabilities + in good faith receive acknowledgement in SECURITY.adoc and in + /.well-known/security-acknowledgments. See security.txt for contact path. +# TEMPLATE NOTE: replace {{SECURITY_CONTACT}} with a mailto: URI for this repo's +# security contact, e.g. "mailto:j.d.a.jewell@open.ac.uk". +contact: "{{SECURITY_CONTACT}}" +recognition: + mechanism: "security-acknowledgments list" + url: "https://{{DOMAIN}}/.well-known/security-acknowledgments" +contractile_ref: "tracked in `contractile trust probe` — see trust.ncl safe_hacking" +security: + proof: "VulnDisclosure.Policy.idr" + +--- +### [SDP_RULES] +services: + - name: "dashboard.internal" + access: + - group: "admins" + policy: "require Ed448+Dilithium5 + device-attestation + cadre-consent" + - group: "bots" + policy: "require JWT (Kyber1024) + IP in CI_NETWORK" + proof: "SDP.Dashboard.idr" + - name: "db.internal" + access: + - group: "apps" + policy: "require mutual TLS (Kyber1024-X25519) + client cert" + proof: "SDP.Database.idr" + +--- +### [TRANSPARENCY_LOG] +rfc9162: + uri: "https://example.com/log/transparency.json" + entries: + - timestamp: "2026-02-16T00:00:00Z" + data: "BASE64_ENCODED_THIS_FILE" + signature: "BASE64_Ed448+Dilithium5_SIGNATURE" + idris2_proof: "Transparency.Log.idr" + ci_cd: "append-on-push" + +--- +### [SSL/TLS] +ciphers: + - "TLS_AES_256_GCM_SHA384" + - "TLS_CHACHA20_POLY1305_SHA256" +groups: + - "X25519Kyber768Draft00" + - "secp256r1" +protocols: + - "TLSv1.3" +minimum_version: "1.2" +notes: | + TLS 1.3 preferred with post-quantum key exchange (X25519Kyber768). + Minimum version 1.2 enforced at Cloudflare edge for clients that + don't support 1.3 yet. TLS 1.0 and 1.1 are BANNED. Cipher preference + is server-side (Cloudflare-controlled on free plan). +features: + ocspStapling: true + signedCertTimestamps: true + certificateTransparency: + logs: + - "ct.googleapis.com/aviator" + - "ct.googleapis.com/rocketeer" + monitoring: true + notes: "Cloudflare automatically includes SCT in TLS handshake for all proxied zones." + mustStaple: true + opportunistic_encryption: true + automatic_https_rewrites: true + always_use_https: true +edge_certificates: + provider: "Cloudflare Universal SSL" + type: "DV (Domain Validated)" + issuers: ["DigiCert", "Let's Encrypt", "Google Trust Services"] + auto_renewal: true + caa_restriction: true + notes: | + Cloudflare issues Universal SSL certificates automatically for all + proxied zones. CAA records restrict issuance to authorized CAs only. + Origin certificates should use Cloudflare Origin CA (15-year validity) + or publicly trusted certs for Full (Strict) mode. +security: + proof: "TLS.Configuration.idr" + ci_cd: "verify-tls-settings-drift" + +--- +### [CLOUDFLARE] +operator_trust_anchor: | + Cloudflare is an operator-chosen trust anchor for this repo. Its edge + network provides DDoS absorption, TLS termination, and WAF. This is a + single-vendor dependency: compromise or misbehaviour at Cloudflare + affects all proxied traffic. Plan for vendor-compromise scenario + documented in THREAT-MODEL.md §vendor-anchors. +waf: + ruleset: "OWASP_ModSecurity_CRS" + sensitivity: "high" + paranoiaLevel: 4 + managed_rulesets: + - name: "Cloudflare Managed Ruleset" + id: "efb7b8c949ac4650a09736fc376e9aee" + action: "execute" + phase: "http_request_firewall_managed" + - name: "Cloudflare OWASP Core Ruleset" + id: "4814384a9e5d4991b9815dcfc25d2f1f" + action: "execute" + phase: "http_request_firewall_managed" + ddos: + http: + sensitivity: "high" + action: "managed_challenge" + ruleset: "Cloudflare HTTP DDoS Attack Protection" + notes: "Always-on, unmetered DDoS protection on all plans." + security: + proof: "Cloudflare.WAF.idr" + ci_cd: "validate-waf-rulesets" +workers: + - name: "consent-aware-http" + script: "https://example.com/workers/consent.js" + routes: + - "example.com/.well-known/consent*" + - name: "capability-gateway" + script: "https://example.com/workers/cap.js" + routes: + - "example.com/cap*" + +--- +### [CLOUDFLARE_EDGE_SECURITY] +overview: | + Cloudflare edge security settings applied uniformly across all zones. + These are the maximum free-plan configurations. Settings are enforced + via API and validated by Hypatia CI scans. Any drift triggers an alert. + +ssl_tls: + mode: "strict" + min_tls_version: "1.2" + tls_1_3: "zrt" + always_use_https: true + automatic_https_rewrites: true + opportunistic_encryption: true + hsts: + enabled: true + max_age: 31536000 + include_subdomains: true + preload: true + nosniff: true + universal_ssl: true + certificate_transparency: true + ocsp_stapling: true + notes: | + TLS 1.3 with 0-RTT (zrt). HSTS preloaded at 1 year with subdomains. + SSL mode 'strict' requires valid origin certificate (Cloudflare Origin CA + or publicly trusted). Downgrade to 'full' only if origin has self-signed. + security: + proof: "Cloudflare.SSL.idr" + ci_cd: "verify-ssl-settings-drift" + +bot_defense: + bot_fight_mode: true + block_ai_bots: true + ai_labyrinth: true + ai_crawl_control: + default_action: "block" + notes: | + Block all known AI crawlers by default. AI Labyrinth traps persistent + scrapers in an infinite maze of AI-generated decoy content, wasting + their compute while protecting real content. Individual crawlers can + be allowed via per-crawler overrides if licensing agreements exist. + managed_robots_txt: true + javascript_detections: false + notes: | + JS detections require Super Bot Fight Mode (Pro+). On free plan, + Bot Fight Mode uses pattern matching only. AI Labyrinth is the + primary free-plan defense against sophisticated AI scraping. + security: + proof: "Cloudflare.Bots.idr" + ci_cd: "verify-bot-settings" + +scrape_shield: + email_obfuscation: true + hotlink_protection: true + server_side_excludes: true + notes: | + Email obfuscation rewrites email addresses in HTML to prevent + harvesting by scrapers. Hotlink protection prevents other sites + from embedding your images. Server-side excludes hide content + from suspicious visitors. + security: + proof: "Cloudflare.ScrapeShield.idr" + +browser_integrity: + browser_check: true + security_level: "medium" + challenge_ttl: 1800 + notes: | + Browser Integrity Check evaluates HTTP headers for common + characteristics of abusive traffic. Security level 'medium' + challenges visitors from IPs with moderate threat scores. + Challenge TTL of 30 minutes before re-challenge. + security: + proof: "Cloudflare.BrowserIntegrity.idr" + +page_shield: + enabled: true + script_monitoring: true + notes: | + Page Shield monitors client-side JavaScript resources loaded by + your pages. Free tier provides script detection and alerts for + new/changed scripts. Paid tiers add malicious script detection. + security: + proof: "Cloudflare.PageShield.idr" + ci_cd: "review-new-scripts" + +security_txt: + enabled: true + contact: "mailto:j.d.a.jewell@open.ac.uk" + preferred_languages: "en" + # TEMPLATE NOTE: replace {{SECURITY_TXT_EXPIRES}} with an RFC 3339 datetime 1 year from deployment, + # e.g. "2027-04-17T00:00:00Z". Auto-renewed by CI. + expires: "{{SECURITY_TXT_EXPIRES}}" + # TEMPLATE NOTE: replace {{DOMAIN}} with the canonical domain for this repo (bare domain or + # GitHub Pages URL), e.g. "boj-server.hyperpolymath.dev" or "github.com/hyperpolymath/". + # Used in all /.well-known/ paths below. + policy: "https://{{DOMAIN}}/.well-known/security-policy" + acknowledgments: "https://{{DOMAIN}}/.well-known/security-acknowledgments" + encryption: "https://{{DOMAIN}}/.well-known/pgp-key.txt" + canonical: "https://{{DOMAIN}}/.well-known/security.txt" + notes: | + RFC 9116 compliant. Served by Cloudflare at /.well-known/security.txt. + Contact is the author's university email. Expiry set to 1 year from + deployment, auto-renewed by CI. Canonical URL prevents spoofing. + security: + proof: "Cloudflare.SecurityTxt.idr" + ci_cd: "renew-security-txt-before-expiry" + +rate_limiting: + architecture: "four-tier" + tier_1_edge: + provider: "Cloudflare" + mechanisms: ["Anycast absorption", "DDoS Managed Ruleset", "per-zone rate rules"] + tier_2_gateway: + provider: "http-capability-gateway / svalinn" + mechanisms: ["per-IP token-bucket sliding window", "per-capability-token", "per-endpoint"] + status: "PENDING — http-capability-gateway wiring forthcoming" + tier_3_beam: + provider: "Elixir supervisor" + mechanisms: ["per-cartridge-invocation budget", "mailbox back-pressure"] + tier_4_cartridge: + provider: "cartridge-declared" + mechanisms: ["Nickel manifest declares per-cartridge limits"] + cross_tier: + - "RFC 9530 rate-limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset)" + - "429 + Retry-After on limit hit" + - "Turnstile challenge on high-value endpoints" + - "HMAC request signing for API clients" + - "per-cartridge circuit breakers with exponential backoff" + - "shadow-ban for persistent offenders" + cost_ceiling: + policy: "operator-managed emergency brake above tier 1" + # TEMPLATE NOTE: replace {{COST_CEILING_POLICY}} with a concise operator policy string, + # e.g. "operator-managed; emergency brake above edge-tier rate limits; specific cap TBD". + # This is an operator-choice field — no universal default. + note: "{{COST_CEILING_POLICY}}" + security: + proof: "RateLimiting.Policy.idr" + +--- +### [RESPONSE_HEADERS] +overview: | + Security response headers applied at the Cloudflare edge via Managed + Transforms and custom response header modification rules. These headers + instruct browsers to enforce security policies regardless of origin config. + +managed_transforms: + add: + - "X-Content-Type-Options: nosniff" + - "X-Frame-Options: SAMEORIGIN" + - "Referrer-Policy: strict-origin-when-cross-origin" + remove: + - "Server" + - "X-Powered-By" + notes: "Managed Transforms are Cloudflare's built-in header rules. Zero config." + +custom_headers: + - name: "Permissions-Policy" + value: "camera=(), microphone=(), geolocation=(), payment=()" + notes: "Deny all sensitive browser APIs unless explicitly needed." + - name: "Content-Security-Policy" + value: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self'" + notes: "Strict CSP baseline. Override per-project if needed (e.g., for CDN scripts)." + - name: "Cross-Origin-Opener-Policy" + value: "same-origin" + - name: "Cross-Origin-Embedder-Policy" + value: "require-corp" + - name: "Cross-Origin-Resource-Policy" + value: "same-origin" + +policy: | + All security headers are enforced at the edge. Origin servers SHOULD + also set these headers as defense-in-depth. Headers set at edge take + precedence when Managed Transforms are enabled. CSP violations are + reported to /csp-report endpoint if a report-uri directive is added. + +security: + proof: "Cloudflare.ResponseHeaders.idr" + ci_cd: "validate-response-headers" + +--- +### [NETWORK] +overview: | + Network-level settings applied at the Cloudflare edge. + These affect how traffic is transported between clients and edge. + +http2: true +http3: true +quic: true +zero_rtt: true +websockets: true +onion_routing: true +ipv6_posture: + origin: "IPv6-only (strict)" + edge: "dual-stack (Cloudflare translates IPv4 clients to IPv6-only origins)" + internal_comms: "IPv6-only between BoJ instances" + policy: "Declared 2026-04-17. IPv4 clients reach BoJ only via Cloudflare edge translation; origin never listens on IPv4." +brotli: true + +zero_rtt_policy: | + 0-RTT Connection Resumption is enabled for performance. Note: 0-RTT + data is vulnerable to replay attacks. Cloudflare mitigates this by + only allowing 0-RTT on idempotent requests (GET/HEAD). Non-idempotent + requests (POST/PUT/DELETE) always use full handshake. Applications + MUST NOT rely on 0-RTT for state-changing operations. + +onion_routing_policy: | + Tor/Onion routing enabled via Cloudflare's Opportunistic Onion + (Alt-Svc header advertising .onion endpoint). This allows Tor users + to access sites without exit node MITM risk. Does NOT create a + dedicated .onion address — uses Cloudflare's shared onion service. + +security: + proof: "Cloudflare.Network.idr" + ci_cd: "verify-network-settings" + +--- +### [ORIGIN_PROTECTION] +hidden_primary: + public_dns: "no A/AAAA records resolving directly to origin" + public_endpoint: "Cloudflare Tunnel only" + authenticated_origin_pulls: + enabled: true + mtls_ca: "Cloudflare Origin CA" + policy: "origin rejects all non-CF traffic at TCP layer" + admin_endpoints: + mechanism: "Cloudflare Access (zero-trust)" + public_endpoint: "none" + backup_origin: + mechanism: "second Cloudflare Tunnel, passive failover" + leak_checks: + - "verify no historic origin IP exposure in securitytrails.com" + - "verify no origin IP in HTTP error messages" + - "verify no origin IP in DNS MX/TXT records" +security: + proof: "OriginProtection.Policy.idr" + ci_cd: "verify-origin-hidden-weekly" + +--- +### [PERFORMANCE] +overview: | + Performance settings that have security implications. + Applied at the Cloudflare edge for all zones. + +early_hints: true +speed_brain: true +auto_minify: + javascript: true + css: true + html: true +rocket_loader: false +notes: | + Rocket Loader disabled by default — it rewrites JavaScript loading + order which can break SPAs and CSP policies. Enable per-project only + after testing. Speed Brain uses Speculation Rules API to prefetch + likely navigation targets (conservative eagerness only). + +caching: + browser_ttl: "respect-origin" + edge_ttl: "default" + always_online: true + notes: | + Always Online serves stale cached copies when origin is unreachable. + Browser TTL respects origin Cache-Control headers. Do not cache + authenticated content — use Cache-Control: private on origin. + +security: + proof: "Cloudflare.Performance.idr" + +--- +### [PHP_HARDENING] +aegis: + enabled: true + rules: + - "disable_functions=exec,popen,shell_exec,system" + - "expose_php=0" + - "session.cookie_httponly=1" + - "session.cookie_secure=1" +sanctify: + enabled: true + directives: + - "sanctify.globals=1" + - "sanctify.request=1" + - "sanctify.error_reporting=E_ALL" + +--- +### [CONTAINER_SUPPLY_CHAIN] +overview: | + Container supply-chain verification via the stapeln ecosystem. + All container images are built with Podman on Chainguard Wolfi base + images, signed as .ctp bundles via cerro-torre, and governed by + svalinn edge gateway policies. Runtime monitoring provided by vordr. + +runtime: + engine: "Podman" + policy: "Rootless containers only. Never Docker." + socket: "${XDG_RUNTIME_DIR}/podman/podman.sock" + security: + proof: "Container.Runtime.idr" + +base_images: + provider: "Chainguard" + registry: "cgr.dev/chainguard/" + allowed: + - "cgr.dev/chainguard/wolfi-base:latest" + - "cgr.dev/chainguard/static:latest" + policy: "Only Chainguard images permitted as base. Rebuilt daily, CVE-free." + security: + proof: "Container.BaseImages.idr" + ci_cd: "scan-base-images-daily" + +verified_bundles: + format: ".ctp" + tool: "cerro-torre" + operations: + pack: "ct pack -o " + sign: "cerro-sign sign --key-id " + verify: "ct verify " + push: "ct push " + explain: "ct explain " + attestations: + required: ["source-signature", "sbom-complete"] + recommended: ["security-audit", "reproducible-build"] + security: + proof: "Container.Bundles.idr" + hypatia: "scan-ctp-bundles" + +gateway: + tool: "svalinn" + policy_file: "container/.gatekeeper.yaml" + capabilities: + - "JWT/OAuth2 authentication" + - "Rate limiting (per-client, per-endpoint)" + - "Container trust enforcement (.ctp signature verification)" + - "Request validation (body size, NaN/Inf rejection)" + - "CORS policy enforcement" + - "Audit logging for write operations" + - "TLS auto-provisioning" + security: + proof: "Container.Gateway.idr" + ci_cd: "validate-gatekeeper-policy-on-push" + +monitoring: + tool: "vordr" + config_file: "container/vordr.toml" + capabilities: + - "Health endpoint monitoring" + - "Container crash detection" + - "Resource usage thresholds (CPU, memory, disk)" + - "Structured JSON log output" + - "Automatic restart on failure (configurable)" + security: + proof: "Container.Monitoring.idr" + +signing: + algorithm: "Ed25519" + tool: "cerro-torre sign / cerro-sign" + key_management: | + Signing keys are project-specific. Each service has a dedicated + Ed25519 key pair (e.g. -release). Public keys are + distributed in .gatekeeper.yaml trusted_signers section. + security: + proof: "Container.Signing.idr" + ci_cd: "rotate-signing-keys-on-compromise" + +deployment: + tool: "k9-svc" + spec_file: "container/deploy.k9.ncl" + trust_level: "Hunt" + description: | + k9-svc deployment components at Hunt trust level. Full pedigree + (L1-L5: identity, target, security, validation, recipes). + Requires cryptographic handshake before execution. Supports + dev/staging/production environments with rolling deployment. + security: + proof: "Container.Deployment.idr" + ci_cd: "validate-k9-pedigree-on-push" + +--- +### [SUPPLY_CHAIN_DEPS] +overview: | + Source-library supply chain. Chainguard covers base images; + this section tracks language-level deps. +zig: + mechanism: "build.zig.zon with SHA256 hashes" + adoption_status: "ADOPTED where Zig is used" +idris2: + mechanism: ".ipkg with dep version pinning" + adoption_status: "PENDING — estate-wide pinning in CRG contractile" +proven_library: + # TEMPLATE NOTE: replace {{PROVEN_HASH}} with the SHA-256 hex digest of + # verification-ecosystem/proven/ffi/zig/zig-out/lib/libproven_ffi.a obtained via + # `sha256sum .../libproven_ffi.a`. Set to "PENDING" with a note if the lib has not + # yet been built for this repo. + hash_attestation: "{{PROVEN_HASH}}" + source: "verification-ecosystem/proven" + verification: "libproven_ffi.a rebuilt on source change; downstream relink verified" +crg_contractile: "tracked under CRG grade requirements — see CRG-SELF-ASSESSMENT.adoc" +security: + proof: "SupplyChain.Deps.idr" + +--- +### [PLACEHOLDER_TRACKING] +overview: | + Every {{PLACEHOLDER}} in this file must resolve to a live value before + the Trustfile is considered deployed. CI enforces no-placeholder-state + on main branch. +resolution_policy: "CI check fails on any remaining {{...}} in main" +ci_cd: "enforce-no-placeholders-on-main" + +--- +### [SIGNATURE_BLOCK] +primary: + algorithm: "Ed448+Dilithium5" + signature: | + -----BEGIN HYBRID SIGNATURE----- + BASE64_Ed448+Dilithium5_SIGNATURE_OF_THIS_FILE + -----END HYBRID SIGNATURE----- + signedBy: "did:web:example.com#primary-sig" + idris2_proof: "Signature.Primary.idr" +fallback: + algorithm: "SPHINCS+" + signature: | + -----BEGIN SPHINCS+ SIGNATURE----- + BASE64_SPHINCS+_SIGNATURE_OF_THIS_FILE + -----END SPHINCS+ SIGNATURE----- + idris2_proof: "Signature.Fallback.idr" + +--- +### [DEPLOYMENT] +1. Replace all `BASE64_*`, `HEX_*`, and `DID_WEB_ID` placeholders. +2. Generate Idris2 proofs: + ```bash + idris2 --build trust.ipkg diff --git a/.machine_readable/contractiles/trust/trust.k9.ncl b/.machine_readable/contractiles/trust/trust.k9.ncl new file mode 100644 index 0000000..6e61ed3 --- /dev/null +++ b/.machine_readable/contractiles/trust/trust.k9.ncl @@ -0,0 +1,276 @@ +# SPDX-License-Identifier: MPL-2.0 +# trust.k9.ncl — K9 trust-tier component of the trust trident +# Author: Jonathan D.A. Jewell +# +# Pairs with: Trustfile.a2ml (declaration) + trust.ncl (runner). +# Trident completeness is a hard precondition — a repo shipping +# Trustfile without this file AND its runner is an invalid trident; +# the contractile CLI's verify gate refuses partial publication. +# +# Verb: trust (security + provenance + safe-hacking) +# Tier: Hunt (capability: subprocess probes may shell out, +# active probes in safe_hacking section) +# Authority: blocking (HARD GATE — opposite of intend's reporting) +# +# trust is the concrete + ephemeral + transactional verb per user +# 2026-04-18: port use, BLAKE3 hashing, auth challenges, TLS state, +# session tokens. Every probe has instant binary ground truth. +# This is the α two-axis complement to intend: both Hunt-tier, opposite +# authority poles. Validating the architecture on both exercises the +# full (tier, authority) surface. +# +# Cardinality: ONE trust trident per repo (see feedback_contractile_ +# layout_rules.md). ANCHOR.a2ml is the sole multi-instance exception — +# it is NOT a verb contractile. +# +# Design commitments baked in (full memory trail under +# ~/.claude/projects/-var-mnt-eclipse-repos/memory/ 2026-04-18): +# * α two-axis (Hunt, blocking) — trust is where the contractile system +# grows teeth. Failed verification = failed CI = blocked merge. +# * Variance schema first-class — scoped exceptions structural, not +# comment markers. +# * Sessional drift detection hooks — re-verify every close. +# * Ratification negotiation with threat-model foregrounded +# (feedback_ai_failure_mode_catalog.md B1 — threat-model +# misclassification is the PRIMARY defense trust provides). +# * Accountability pledge — both parties sign before security-affecting +# work proceeds. +# * Plain-language translation — user never authors a Nickel schema for +# a cipher suite; AI does the spec work, user reviews in domain +# language ("TLS 1.3 with PQ key exchange, HSTS preload, 1yr"). +# * Evidence sinks: VeriSimDB (queryable) + 6a2/DRIFT.a2ml (repo-local). +# * Failure-mode defenses cross-referenced — trust carries the most +# defenses of any verb because the threat surface is widest. + +let base_k9 = import "../k9/template-hunt.k9.ncl" in +let base = import "../_base.ncl" in + +{ + pedigree = base_k9.pedigree_schema & { + contractile_verb = "trust", + paired_xfile = "../trust/Trustfile.a2ml", + paired_runner = "../trust/trust.ncl", + + # α two-axis declaration — capability × authority. + # trust is Hunt-capable (active probes shell out, safe-hacking section + # runs real fuzz/injection/auth-bypass attempts scoped to the repo) + # AND blocking-authority (failed verification = failed CI). + # Contrast with intend = (Hunt, reporting). The two verbs exercise + # the full α surface. + tier = 'Hunt, + authority = 'blocking, + + metadata = { + name = "trust-k9", + version = "1.0.0", + description = "Executes security verifications + authorised safe-hacking probes. HARD GATE: failed verification blocks merge. Catches the 'turn off the firewall' class of drift directly. Implements negotiation-ratification-accountability protocol inherited from intend.k9.ncl v2.0.0.", + paired_xfile = "Trustfile.a2ml", + paired_runner = "trust.ncl", + author = "Jonathan D.A. Jewell ", + }, + + security = { + leash = 'Hunt, + trust_level = "verification + authorised-probe + hard-gate", + allow_network = false, # verifications offline by default + allow_filesystem_write = false, # evidence sinks are indirected + allow_subprocess = true, + authorised_probes_only = true, # probe section explicitly lists allowed targets + probe classes + probe_scope_enforcement = 'this_repo_only, # probes NEVER hit external systems + }, + }, + + # ------------------------------------------------------------------- + # Variance schema — P-shape scoped exceptions per verification. + # A variance suppresses a specific verification's obligation for a + # reason, with approver + expiry. Because trust is BLOCKING authority, + # variances on trust entries are SIGNIFICANTLY more consequential than + # variances on intend (reporting) entries — variance approver MUST + # be the repo maintainer or above for critical-severity entries. + # ------------------------------------------------------------------- + variance_schema = { + entry_id | String, # which verification / probe id + reason | String, + approved_by | String, # maintainer or above for critical entries + scope | String, # path glob | session-id | "until-" + expires | String, # absolute date; trust variances cannot be open-ended + review_notes | String | optional, + # Additional trust-specific guardrails: + severity_acknowledged | [| 'critical, 'high, 'medium, 'low |], + waived_risk_description | String, # plain language — what is being accepted + }, + + # ------------------------------------------------------------------- + # Execution policy + # ------------------------------------------------------------------- + execution = { + # When the component runs. + # pre_push + pre_commit on anything touching security-adjacent files + # + session_close (drift check) + on_demand. + triggers = [ 'session_close, 'on_demand, 'pre_push, 'pre_commit_security_adjacent ], + + # Per-verification execution. Failed verification = blocked merge. + per_verification = { + run_probe = true, + record_outcome = true, + respect_variance = true, # active variance suppresses the gate + on_unmet = 'fail, # BLOCKING — the opposite of intend's 'log_drift + severity_escalation = 'honour, # critical > high > medium > low in gate decisions + }, + + # Per-safe-hacking-probe execution. + # If a probe FINDS what it was supposed to prevent finding + # (e.g. injection succeeds, auth-bypass works), that's an EXPLOIT + # demonstration — hard fail, regardless of other status. + per_probe = { + run_probe = true, + record_outcome = true, + honour_expected_outcome = true, + on_unexpected_exploit_success = 'fail, # exploit found where it shouldn't be + scope_enforcement = 'this_repo_only, # never touch external systems + timeout_honouring = 'strict, + }, + + # Evidence sinks — BOTH written, every execution. + evidence_sinks = [ + { + kind = 'verisimdb, + table = "contractile_executions", + schema = "contractile_execution_v1", + # trust-specific sub-table for probe outcomes (for threat-model audit) + aux_tables = [ "trust_verifications", "trust_probes" ], + }, + { + kind = 'drift_log, + path = ".machine_readable/6a2/DRIFT.a2ml", + append_only = true, + }, + ], + + # Session-close hook — re-verify EVERYTHING, re-run probes, diff + # against last ratification. The "turn off the firewall" scenario + # must be caught here if it wasn't caught at pre-push. + on_close = { + re_execute_all_verifications = true, + re_run_all_safe_hacking_probes = true, + diff_against_last_ratification = true, + emit_drift_entries_for_new_failures = true, + surface_expired_variances = true, + # trust-specific: if any blocking-severity verification is newly + # failing, the session close is BLOCKED from completing. User + # cannot close a session with unresolved critical trust drift. + block_session_close_on_critical_drift = true, + }, + + # ----------------------------------------------------------------- + # Session-open hook — NEGOTIATION + RATIFICATION + ACCOUNTABILITY + # (inherited shape from intend.k9.ncl v2.0.0; trust-specific + # additions around threat-model foregrounding below) + # ----------------------------------------------------------------- + on_open = { + # --- Context presentation --- + render_summary = 'plain_language, # metaphor-capture defense + include_drift_log_from_last_close = true, + include_active_variances = true, + include_recent_anchors = true, + anchor_lookback_weeks = 8, + + # trust-specific: the threat model is rendered FIRST, before any + # negotiation, so the adversary and stakes are fresh in both minds. + # This directly defends against B1 (threat-model misclassification) + # — the "war reporter, generic personal-website priors" scenario. + threat_model_foregrounding = { + required = true, + render_adversaries = true, # from Trustfile [THREAT_MODEL] + render_stakes = true, + render_compliance_regimes = true, + render_audience_sensitivity = true, + # If the AI is about to suggest a trust-weakening action, it + # must re-render the threat model before the suggestion lands. + re_render_before_weakening_suggestion = true, + }, + + # --- Negotiation phase (five mandatory inputs, inherited) --- + negotiation = { + required = true, + ai_required_inputs = [ + 'timeline_realism, + 'industry_standards, # especially relevant for trust: OWASP, NIST, PCI-DSS, GDPR + 'audience_feasibility, # who is the adversary? who is protected? + 'resulting_invariants, # what trust entries the work creates/amends + 'ecosystem_dependencies, # TLS libs, crypto primitives, signing infra + ], + user_engagement_required = true, + user_engagement_mode = 'per_input_response, + specification_translation = { + ai_produces_spec_form = true, + user_reviews_in_domain_language = true, + schema_authoring_is_ai_responsibility = true, + translation_faithfulness_auditable = true, + # trust-specific: the AI's translation includes rendering + # cipher suites, key exchange choices, rate-limit numbers in + # domain language ("strong encryption, PQ-resistant, 60 req/min") + # rather than forcing the user into Nickel-schema authoring. + }, + }, + + # --- Accountability pledge (both parties, explicit) --- + # trust's pledge is MORE stringent than intend's because the + # authority is blocking. A user accepting accountability here is + # accepting that security-affecting decisions have blocking consequence. + accountability_pledge = { + required = true, + parties = [ + { + role = 'user, + pledge = "I have reviewed the threat model, the declared trust obligations, and the audience/stakes consequences. I accept accountability for meeting these obligations and understand that failed verification will block merges until resolved or varied. I will not attempt to disable verification to unblock a merge; I will raise a variance or amendment instead.", + signature_required = true, + }, + { + role = 'ai_agent, + pledge = "I will hold the line on declared trust obligations. I will refuse to 'disable' verifications to unblock merges; I will refuse security-weakening suggestions that contradict the threat model even when the user is enthusiastic; I will surface drift at session close; I will re-render the threat model before proposing any weakening action. If a legitimate scope shift demands security reduction, I will require a variance with severity acknowledgement or an amendment, not silent acceptance.", + signature_required = true, + }, + ], + signed_record_destination = ".machine_readable/6a2/ratification-.a2ml", + must_precede_work = true, + }, + + ratification_record_shape = { + includes_negotiation_transcript = true, + includes_both_pledges = true, + includes_threat_model_snapshot = true, # trust-specific + signed = true, + dated = true, + session_id = 'required, + contract_hash = 'required, + }, + }, + }, + + # ------------------------------------------------------------------- + # Failure-mode defenses — trust is the widest-coverage verb. + # See feedback_ai_failure_mode_catalog.md for the full catalog. + # ------------------------------------------------------------------- + failure_mode_defenses = [ + # Category A — enthusiasm / narrative capture + 'A1_enthusiasm_capture, # scope breach blocks via blocking authority + 'A2_metaphor_capture, # render_summary + re_render_before_weakening + # Category B — threat-model misclassification (trust's flagship defense) + 'B1_threat_model_misclass, # threat_model_foregrounding = required + 'B2_audience_sensitivity_collapse, # audience_feasibility in negotiation + 'B3_compliance_prior_drift, # industry_standards in negotiation + # Category C — scope/capability erosion (the "firewall off" scenario) + 'C2_capability_collapse, # blocking gate prevents silent capability drop + 'C3_helpfulness_inflation, # trust-affecting changes need variance/amendment + 'C4_modernization_drift, # unrequested crypto-lib upgrade caught + # Category D — epistemic failures + 'D4_error_hiding, # on_unmet = 'fail makes hiding impossible + 'D5_sycophancy, # pledge forces AI to hold line against enthusiasm + 'D6_false_pessimism, # negotiation requires AI to cite constraint, not assert impossibility + # Category E — refactor/churn + 'E4_cargo_cult_security, # probes VERIFY the claimed protection actually runs + # Category F — session drift + 'F1_across_session_forgetting, # on_open reads last-ratification, drift log, recent ANCHORs + ], +} diff --git a/.machine_readable/contractiles/trust/trust.manifest.a2ml b/.machine_readable/contractiles/trust/trust.manifest.a2ml new file mode 100644 index 0000000..c904eb3 --- /dev/null +++ b/.machine_readable/contractiles/trust/trust.manifest.a2ml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: MPL-2.0 +# trust.manifest.a2ml — Trident coherence manifest for the trust verb. +# Author: Jonathan D.A. Jewell +# +# Asserts: exactly three files constitute the trust trident; their +# content-hashes are pinned here; cross-references round-trip; no +# partial publication is permitted. +# +# The contractile CLI's `verify trust` subcommand MUST: +# 1. Confirm all three listed files exist at the declared paths. +# 2. Compute each file's sha256 and match against the pinned value. +# 3. Follow each cross-reference and confirm the target file's +# reciprocal field points back. +# 4. Refuse the dir (exit non-zero) if any of 1–3 fails. +# +# trust is the concrete + ephemeral + transactional verb (per user +# 2026-04-18); first blocking-authority trident in the estate. Exercises +# the (Hunt, blocking) authority pattern — complement to intend's +# (Hunt, reporting). Primary defense against failure mode B1 (threat- +# model misclassification) and the "turn off the firewall" class of +# drift attempts the adversarial pilot is designed to exercise. + +--- +trident_version = "1.0.0" +verb = "trust" +semantics = "security + provenance + safe-hacking" +cardinality = "one per repo" +authority = "blocking (hard gate)" + +## Files (three; exactly) + +[[files]] +role = "declaration" +path = "Trustfile.a2ml" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" +notes = "Extensively populated exemplar; covers threat model, DNS, TLS, crypto, SDP, safe-hacking, response headers, container supply chain, Cloudflare edge." + +[[files]] +role = "runner" +path = "trust.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" +notes = "Runner existed pre-trident; schema covers verifications + safe_hacking with authorised-probes-only, this_repo_only scope enforcement." + +[[files]] +role = "k9_component" +path = "trust.k9.ncl" +sha256 = "pending-first-verify" +size_bytes = "pending-first-verify" +notes = "Trust-tier Hunt with blocking authority. on_open foregrounds threat model before negotiation; block_session_close_on_critical_drift." + +## Cross-references (must round-trip) + +[cross_refs] +runner_paired_xfile = "Trustfile.a2ml" +k9_paired_xfile = "../trust/Trustfile.a2ml" +k9_paired_runner = "../trust/trust.ncl" + +## Trident signing + +[signed_by] +user = "Jonathan D.A. Jewell" +date = "2026-04-18" +context = "trust trident — second Trident instance. First (Hunt, blocking) authority pattern. Template for must, bust, adjust, dust. Pre-pilot readiness: primary catchment for adversarial drift test scenarios (firewall-off, cleartext-auth, PQ-downgrade, CSP-weaken)." + +## Change log + +[[history]] +date = "2026-04-18" +event = "trident-born" +note = "Trustfile.a2ml and trust.ncl pre-existed. This manifest + trust.k9.ncl complete the trident. Inherits on_open negotiation + accountability + plain-language-translation schema from intend.k9.ncl v2.0.0; adds trust-specific threat_model_foregrounding + block_session_close_on_critical_drift + stricter accountability pledge (user cannot disable verification to unblock merges)." diff --git a/.machine_readable/contractiles/trust/trust.ncl b/.machine_readable/contractiles/trust/trust.ncl new file mode 100644 index 0000000..21b335c --- /dev/null +++ b/.machine_readable/contractiles/trust/trust.ncl @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: MPL-2.0 +# Trust — security + safe-hacking runner +# +# Pairs with: Trustfile.a2ml (same directory) +# Verb: trust +# Semantics: integrity / provenance / security verification PLUS a declared +# "safe hacking + testing" section — authorised offensive probes +# (pen-test harness runs, chaos-engineering probes) scoped to the +# repo under test, NEVER touching external systems. +# CLI: `contractile trust verify` → run all verifications (read-only) +# `contractile trust probe` → run declared safe-hacking probes +# +# Anything else in this directory is human-only notes/archive; machines ignore. +# +# Base: ../_base.ncl provides pedigree_schema, run_defaults, probe_schema. +# See: docs/CONTRACTILE-SPEC.adoc + +let base = import "../_base.ncl" in + +{ + pedigree = base.pedigree_schema & { + contractile_verb = "trust", + semantics = "security + provenance + safe-hacking", + security = { + leash = 'Kennel, + trust_level = "verification + authorised-probe", + allow_network = false, # verifications are offline by default + allow_filesystem_write = false, # trust writes NOTHING + allow_subprocess = true, + authorised_probes_only = true, # probe section must explicitly list allowed targets + }, + metadata = { + name = "trust-runner", + version = "1.0.0", + description = "Security + provenance verifications plus authorised safe-hacking probes. All probes are scoped to the repo under test; never hits external systems.", + paired_xfile = "Trustfile.a2ml", + author = "Jonathan D.A. Jewell ", + }, + }, + + schema = { + verifications + | Array { + id | String, + description | String, + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + probe | String, # read-only; exit 0 = pass + # status_core values: 'declared, 'verified, 'failing + status | [| 'declared, 'verified, 'failing |] | default = 'declared, + # trust uses all four severity levels (from base.severity_core) + severity | [| 'critical, 'high, 'medium, 'low |] | default = 'high, + notes | String | optional, + }, + + # Safe-hacking + testing section (added 2026-04-17 per user direction). + # Each probe here is an ACTIVELY EXECUTED test — fuzz runs, chaos probes, + # auth-bypass attempts, injection tests. All scoped to the current repo. + safe_hacking + | { + scope | String, # e.g. "this-repo-only" / "localhost" + allowed_probe_classes + | Array [| 'fuzz, 'property_test, 'chaos, 'auth_bypass, 'injection, 'timing |] + | default = [], + probes + | Array { + id | String, + class | [| 'fuzz, 'property_test, 'chaos, 'auth_bypass, 'injection, 'timing |], + description | String, + # TODO: migrate to base.probe_schema (structured probe) when CLI supports it + probe | String, # command to run the probe + expected_outcome | [| 'probe_blocks_attempt, 'probe_finds_no_issue |], + timeout_seconds | Number | default = 300, + notes | String | optional, + } + | default = [], + } + | default = { scope = "this-repo-only", allowed_probe_classes = [], probes = [] }, + }, + + # Runner behaviour — inherits from base.run_defaults. + # trust has an extra field for unexpected safe-hacking outcomes. + run = base.run_defaults & { + on_any_fail = "exit-nonzero", # hard gate on verifications + safe_hacking_on_unexpected_outcome = "exit-nonzero", # probe found what it shouldn't = block + report_format = "a2ml", + emit_summary = true, + }, +} diff --git a/.machine_readable/6a2/AGENTIC.a2ml b/.machine_readable/descriptiles/AGENTIC.a2ml similarity index 100% rename from .machine_readable/6a2/AGENTIC.a2ml rename to .machine_readable/descriptiles/AGENTIC.a2ml diff --git a/.machine_readable/6a2/ECOSYSTEM.a2ml b/.machine_readable/descriptiles/ECOSYSTEM.a2ml similarity index 100% rename from .machine_readable/6a2/ECOSYSTEM.a2ml rename to .machine_readable/descriptiles/ECOSYSTEM.a2ml diff --git a/.machine_readable/6a2/META.a2ml b/.machine_readable/descriptiles/META.a2ml similarity index 100% rename from .machine_readable/6a2/META.a2ml rename to .machine_readable/descriptiles/META.a2ml diff --git a/.machine_readable/6a2/NEUROSYM.a2ml b/.machine_readable/descriptiles/NEUROSYM.a2ml similarity index 100% rename from .machine_readable/6a2/NEUROSYM.a2ml rename to .machine_readable/descriptiles/NEUROSYM.a2ml diff --git a/.machine_readable/6a2/PLAYBOOK.a2ml b/.machine_readable/descriptiles/PLAYBOOK.a2ml similarity index 100% rename from .machine_readable/6a2/PLAYBOOK.a2ml rename to .machine_readable/descriptiles/PLAYBOOK.a2ml diff --git a/.machine_readable/6a2/STATE.a2ml b/.machine_readable/descriptiles/STATE.a2ml similarity index 100% rename from .machine_readable/6a2/STATE.a2ml rename to .machine_readable/descriptiles/STATE.a2ml diff --git a/.machine_readable/anchors/0.2-AI-MANIFEST.a2ml b/.machine_readable/descriptiles/anchors/0.2-AI-MANIFEST.a2ml similarity index 100% rename from .machine_readable/anchors/0.2-AI-MANIFEST.a2ml rename to .machine_readable/descriptiles/anchors/0.2-AI-MANIFEST.a2ml diff --git a/.machine_readable/anchors/ANCHOR.a2ml b/.machine_readable/descriptiles/anchors/ANCHOR.a2ml similarity index 100% rename from .machine_readable/anchors/ANCHOR.a2ml rename to .machine_readable/descriptiles/anchors/ANCHOR.a2ml diff --git a/.machine_readable/anchors/README.adoc b/.machine_readable/descriptiles/anchors/README.adoc similarity index 100% rename from .machine_readable/anchors/README.adoc rename to .machine_readable/descriptiles/anchors/README.adoc diff --git a/.machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml b/.machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml index eaee720..4abd5e4 100644 --- a/.machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml +++ b/.machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml @@ -102,7 +102,7 @@ ownership_files = [ ] machine_readable_required = [ - ".machine_readable/anchors/ANCHOR.a2ml", + ".machine_readable/descriptiles/anchors/ANCHOR.a2ml", ".machine_readable/contractiles/", ".machine_readable/ai/", ".machine_readable/bot_directives/", diff --git a/0-AI-MANIFEST.a2ml b/0-AI-MANIFEST.a2ml index 6f34620..9b64bd8 100644 --- a/0-AI-MANIFEST.a2ml +++ b/0-AI-MANIFEST.a2ml @@ -23,11 +23,11 @@ These 6 a2ml files MUST exist in `.machine_readable/` directory ONLY: **CRITICAL:** If ANY of these files exist in the root directory, this is an ERROR. -### Anchor File: `.machine_readable/anchors/ANCHOR.a2ml` ONLY +### Anchor File: `.machine_readable/descriptiles/anchors/ANCHOR.a2ml` ONLY Canonical authority and semantic-boundary declaration MUST exist at: -` .machine_readable/anchors/ANCHOR.a2ml ` +` .machine_readable/descriptiles/anchors/ANCHOR.a2ml ` Do not place `ANCHOR.a2ml` at repository root. diff --git a/Justfile b/Justfile index ecc6238..e5ebb04 100644 --- a/Justfile +++ b/Justfile @@ -50,7 +50,7 @@ info: @echo "Version: {{version}}" @echo "RSR Tier: {{tier}}" @echo "Recipes: $(just --summary | wc -w)" - @[ -f ".machine_readable/STATE.a2ml" ] && grep -oP 'phase\s*=\s*"\K[^"]+' .machine_readable/STATE.a2ml | head -1 | xargs -I{} echo "Phase: {}" || true + @[ -f ".machine_readable/descriptiles/STATE.a2ml" ] && grep -oP 'phase\s*=\s*"\K[^"]+' .machine_readable/descriptiles/STATE.a2ml | head -1 | xargs -I{} echo "Phase: {}" || true # ═══════════════════════════════════════════════════════════════════════════════ # INIT — Bootstrap a new project from this template @@ -663,7 +663,7 @@ validate-rsr: for f in .editorconfig .gitignore Justfile README.adoc LICENSE 0-AI-MANIFEST.a2ml; do [ -f "$f" ] || MISSING="$MISSING $f" done - for f in .machine_readable/STATE.a2ml .machine_readable/META.a2ml .machine_readable/ECOSYSTEM.a2ml .machine_readable/anchors/ANCHOR.a2ml .machine_readable/policies/MAINTENANCE-AXES.a2ml .machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml .machine_readable/policies/SOFTWARE-DEVELOPMENT-APPROACH.a2ml; do + for f in .machine_readable/descriptiles/STATE.a2ml .machine_readable/descriptiles/META.a2ml .machine_readable/descriptiles/ECOSYSTEM.a2ml .machine_readable/descriptiles/anchors/ANCHOR.a2ml .machine_readable/policies/MAINTENANCE-AXES.a2ml .machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml .machine_readable/policies/SOFTWARE-DEVELOPMENT-APPROACH.a2ml; do [ -f "$f" ] || MISSING="$MISSING $f" done for f in licensing/exhibits/EXHIBIT-A-ETHICAL-USE.txt licensing/exhibits/EXHIBIT-B-QUANTUM-SAFE.txt licensing/texts/MPL-2.0.txt; do @@ -675,15 +675,15 @@ validate-rsr: for f in docs/maintenance/MAINTENANCE-CHECKLIST.adoc docs/practice/SOFTWARE-DEVELOPMENT-APPROACH.adoc; do [ -f "$f" ] || MISSING="$MISSING $f" done - if [ -f ".machine_readable/META.a2ml" ]; then - grep -q 'axis-1 = "must > intend > like"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-1" - grep -q 'axis-2 = "corrective > adaptive > perfective"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-2" - grep -q 'axis-3 = "systems > compliance > effects"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:axis-3" - grep -q 'scoping-first = true' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:scoping-first" - grep -q 'idris-unsound-scan = "believe_me/assert_total"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:idris-unsound-scan" - grep -q 'audit-focus = "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:audit-focus" - grep -q 'compliance-focus = "seams/compromises/exception register, bounded exceptions, anti-drift checks"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:compliance-focus" - grep -q 'effects-evidence = "benchmark execution/results and maintainer status dialogue/review"' .machine_readable/META.a2ml || MISSING="$MISSING META.a2ml:effects-evidence" + if [ -f ".machine_readable/descriptiles/META.a2ml" ]; then + grep -q 'axis-1 = "must > intend > like"' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:axis-1" + grep -q 'axis-2 = "corrective > adaptive > perfective"' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:axis-2" + grep -q 'axis-3 = "systems > compliance > effects"' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:axis-3" + grep -q 'scoping-first = true' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:scoping-first" + grep -q 'idris-unsound-scan = "believe_me/assert_total"' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:idris-unsound-scan" + grep -q 'audit-focus = "systems in place, documentation explains actual state, safety/security accounted for, observed effects reviewed"' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:audit-focus" + grep -q 'compliance-focus = "seams/compromises/exception register, bounded exceptions, anti-drift checks"' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:compliance-focus" + grep -q 'effects-evidence = "benchmark execution/results and maintainer status dialogue/review"' .machine_readable/descriptiles/META.a2ml || MISSING="$MISSING META.a2ml:effects-evidence" grep -q 'compliance-tooling = "panic-attack"' .machine_readable/policies/MAINTENANCE-AXES.a2ml || MISSING="$MISSING MAINTENANCE-AXES.a2ml:compliance-tooling" grep -q 'effects-tooling = "ecological checking with sustainabot guidance"' .machine_readable/policies/MAINTENANCE-AXES.a2ml || MISSING="$MISSING MAINTENANCE-AXES.a2ml:effects-tooling" grep -q 'source-human = "docs/maintenance/MAINTENANCE-CHECKLIST.adoc"' .machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml || MISSING="$MISSING MAINTENANCE-CHECKLIST.a2ml:source-human" @@ -697,12 +697,12 @@ validate-rsr: # Validate STATE.a2ml syntax validate-state: - @if [ -f ".machine_readable/STATE.a2ml" ]; then \ - grep -q '^\[metadata\]' .machine_readable/STATE.a2ml && \ - grep -q 'project\s*=' .machine_readable/STATE.a2ml && \ + @if [ -f ".machine_readable/descriptiles/STATE.a2ml" ]; then \ + grep -q '^\[metadata\]' .machine_readable/descriptiles/STATE.a2ml && \ + grep -q 'project\s*=' .machine_readable/descriptiles/STATE.a2ml && \ echo "STATE.a2ml: valid" || echo "STATE.a2ml: INVALID (missing required sections)"; \ else \ - echo "No .machine_readable/STATE.a2ml found"; \ + echo "No .machine_readable/descriptiles/STATE.a2ml found"; \ fi # Validate AI installation guide completeness (finishbot pre-release check) @@ -779,14 +779,14 @@ validate: validate-rsr validate-state validate-ai-install # Update STATE.a2ml timestamp state-touch: - @if [ -f ".machine_readable/STATE.a2ml" ]; then \ - sed -i 's/last-updated = "[^"]*"/last-updated = "'"$(date +%Y-%m-%d)"'"/' .machine_readable/STATE.a2ml && \ + @if [ -f ".machine_readable/descriptiles/STATE.a2ml" ]; then \ + sed -i 's/last-updated = "[^"]*"/last-updated = "'"$(date +%Y-%m-%d)"'"/' .machine_readable/descriptiles/STATE.a2ml && \ echo "STATE.a2ml timestamp updated"; \ fi # Show current phase from STATE.a2ml state-phase: - @grep -oP 'phase\s*=\s*"\K[^"]+' .machine_readable/STATE.a2ml 2>/dev/null | head -1 || echo "unknown" + @grep -oP 'phase\s*=\s*"\K[^"]+' .machine_readable/descriptiles/STATE.a2ml 2>/dev/null | head -1 || echo "unknown" # ═══════════════════════════════════════════════════════════════════════════════ # GUIX & NIX diff --git a/contractiles/intend/Intentfile.a2ml b/contractiles/intend/Intentfile.a2ml deleted file mode 100644 index 4937e3b..0000000 --- a/contractiles/intend/Intentfile.a2ml +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Intentfile (A2ML Canonical) -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) - -@abstract: -Declared intent and purpose for A2Ml Validate Action. -@end - -## Purpose - -A2Ml Validate Action — **GitHub Action to validate A2ML manifest files in your repository.** - -## Anti-Purpose - -This project is NOT: -- A fork or wrapper around another tool -- A monorepo (unless explicitly structured as one) - -## If In Doubt - -If you are unsure whether a change is in scope, ask. -Sensitive areas: ABI definitions, license headers, CI workflows. diff --git a/contractiles/must/Mustfile.a2ml b/contractiles/must/Mustfile.a2ml deleted file mode 100644 index 39ebbb6..0000000 --- a/contractiles/must/Mustfile.a2ml +++ /dev/null @@ -1,42 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Mustfile (A2ML Canonical) -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) - -@abstract: -Physical State contract for A2Ml Validate Action. Baseline UX Manifesto invariants -that MUST hold at all times. -@end - -@requires: -- section: Core-Files -- section: Banned -@end - -## Core-Files - -### license-present -- description: LICENSE file must exist -- run: test -f LICENSE -- severity: critical - -### readme-present -- description: README must exist -- run: test -f README.adoc || test -f README.md -- severity: critical - -## Banned - -### no-hardcoded-paths -- description: No hardcoded developer paths -- run: "! grep -rn '$HOME\|$ECLIPSE_DIR' --include='*.rs' --include='*.res' --include='*.ex' --include='*.gleam' --include='*.zig' --include='*.sh' . 2>/dev/null | grep -v '.git/' | grep -v 'ux-rollout.jl' | head -1" -- severity: critical - -### no-dockerfiles -- description: No Dockerfiles (use Containerfile) -- run: test ! -f Dockerfile -- severity: warning - -### no-makefiles -- description: No Makefiles (use Justfile) -- run: test ! -f Makefile -- severity: warning diff --git a/contractiles/trust/Trustfile.a2ml b/contractiles/trust/Trustfile.a2ml deleted file mode 100644 index 7fafe08..0000000 --- a/contractiles/trust/Trustfile.a2ml +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Trustfile (A2ML Canonical) -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) - -@abstract: -Trust and provenance verification for A2Ml Validate Action. -Maximal trust by default — LLM may read, build, test, lint, format. -@end - -@trust-level: maximal -@trust-boundary: repo -@trust-actions: [read, build, test, lint, format] -@trust-deny: [delete-branch, force-push, modify-ci-secrets, publish] - -## Integrity - -### license-content -- description: LICENSE contains expected SPDX identifier -- run: grep -q 'SPDX\|License\|MIT\|Apache\|PMPL\|MPL' LICENSE -- severity: critical - -### no-secrets-committed -- description: No .env or credential files in repo -- run: test ! -f .env && test ! -f credentials.json && test ! -f .env.local -- severity: critical diff --git a/docs/governance/MAINTENANCE-CHECKLIST.a2ml b/docs/governance/MAINTENANCE-CHECKLIST.a2ml index eaee720..4abd5e4 100644 --- a/docs/governance/MAINTENANCE-CHECKLIST.a2ml +++ b/docs/governance/MAINTENANCE-CHECKLIST.a2ml @@ -102,7 +102,7 @@ ownership_files = [ ] machine_readable_required = [ - ".machine_readable/anchors/ANCHOR.a2ml", + ".machine_readable/descriptiles/anchors/ANCHOR.a2ml", ".machine_readable/contractiles/", ".machine_readable/ai/", ".machine_readable/bot_directives/", diff --git a/docs/templates/contractiles/README.adoc b/docs/templates/contractiles/README.adoc deleted file mode 100644 index 121da7a..0000000 --- a/docs/templates/contractiles/README.adoc +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -= Contractile Templates - -Blank templates for projects that want to replace the hyperpolymath -defaults with their own contractile definitions. - -Copy the relevant file to `.machine_readable/contractiles//` -and fill in your project-specific checks. - -The working examples in `.machine_readable/contractiles/` show the -full hyperpolymath setup — use those as reference. diff --git a/docs/templates/contractiles/dust/Dustfile.a2ml b/docs/templates/contractiles/dust/Dustfile.a2ml deleted file mode 100644 index 903af2c..0000000 --- a/docs/templates/contractiles/dust/Dustfile.a2ml +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Dustfile.a2ml — BLANK TEMPLATE -# Replace this with your project's contractile. -# See .machine_readable/contractiles/ for a working example. -# -# Copy this file to .machine_readable/contractiles/dust/Dustfile.a2ml -# and fill in your project-specific checks. - -@abstract: -[Your project's DUST contract goes here] -@end diff --git a/docs/templates/contractiles/lust/Intentfile.a2ml b/docs/templates/contractiles/lust/Intentfile.a2ml deleted file mode 100644 index e313a7d..0000000 --- a/docs/templates/contractiles/lust/Intentfile.a2ml +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Intentfile.a2ml — BLANK TEMPLATE -# Replace this with your project's contractile. -# See .machine_readable/contractiles/ for a working example. -# -# Copy this file to .machine_readable/contractiles/lust/Intentfile.a2ml -# and fill in your project-specific checks. - -@abstract: -[Your project's LUST contract goes here] -@end diff --git a/docs/templates/contractiles/must/Mustfile.a2ml b/docs/templates/contractiles/must/Mustfile.a2ml deleted file mode 100644 index d08796f..0000000 --- a/docs/templates/contractiles/must/Mustfile.a2ml +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Mustfile.a2ml — BLANK TEMPLATE -# Replace this with your project's contractile. -# See .machine_readable/contractiles/ for a working example. -# -# Copy this file to .machine_readable/contractiles/must/Mustfile.a2ml -# and fill in your project-specific checks. - -@abstract: -[Your project's MUST contract goes here] -@end diff --git a/docs/templates/contractiles/trust/Trustfile.a2ml b/docs/templates/contractiles/trust/Trustfile.a2ml deleted file mode 100644 index 842c6b0..0000000 --- a/docs/templates/contractiles/trust/Trustfile.a2ml +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# Trustfile.a2ml — BLANK TEMPLATE -# Replace this with your project's contractile. -# See .machine_readable/contractiles/ for a working example. -# -# Copy this file to .machine_readable/contractiles/trust/Trustfile.a2ml -# and fill in your project-specific checks. - -@abstract: -[Your project's TRUST contract goes here] -@end diff --git a/validate-a2ml.sh b/validate-a2ml.sh index fed7b22..f345db5 100755 --- a/validate-a2ml.sh +++ b/validate-a2ml.sh @@ -160,7 +160,7 @@ validate_a2ml() { if [[ "$basename" == *"AI-MANIFEST"* ]]; then is_manifest=true fi - # Canonical typed manifests under .machine_readable/6a2/ — identity comes + # Canonical typed manifests under .machine_readable/descriptiles/ — identity comes # from the enclosing directory + filename, not an in-file field. Sibling # files in the same directory (ECOSYSTEM.a2ml, STATE.a2ml) DO carry their # own $name/project and continue to be validated normally. @@ -190,10 +190,10 @@ validate_a2ml() { # Canonical structured A2ML tree. Everything under a `.machine_readable/` # directory is a typed agent-readable doc (CLADE, ANCHOR, STATE, - # ECOSYSTEM, agent_instructions/{debt,coverage,methodology}, ai/AI, + # ECOSYSTEM, bot_directives/{debt,coverage,methodology}, ai/AI, # policies/*, integrations/*, …). Per the RSR convention these carry # identity structurally — owning repo + path + filename — not via an - # in-file `name`/`agent-id`. This generalises the `.machine_readable/6a2/` + # in-file `name`/`agent-id`. This generalises the `.machine_readable/descriptiles/` # rationale above to the whole tree: rsr-template-repo itself ships these # files without an in-file identity key, so requiring one produces # estate-wide false positives on every repo built from the canonical