From a9f0b53f345f3daf864466cb920dc69be612d404 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 29 Oct 2026 22:30:14 +0000 Subject: [PATCH 1/5] fix(governance): move canonical STATE to descriptile path --- .github/pull_request_template.md | 2 +- .github/workflows/openssf-compliance.yml | 12 +++++--- .machine_readable/0.1-AI-MANIFEST.a2ml | 2 +- .machine_readable/README.adoc | 19 ++++++------- .machine_readable/ai/.clinerules | 2 +- .machine_readable/ai/.windsurfrules | 2 +- .machine_readable/ai/AI.a2ml | 4 +-- .machine_readable/ai/README.adoc | 2 +- .machine_readable/descriptiles/PLAYBOOK.a2ml | 2 +- .../{ => descriptiles}/STATE.a2ml | 0 0-AI-MANIFEST.a2ml | 8 ++++-- Justfile | 28 +++++++++++-------- docs/RSR_OUTLINE.adoc | 2 +- docs/practice/AI-CONVENTIONS.adoc | 4 +-- 14 files changed, 49 insertions(+), 40 deletions(-) rename .machine_readable/{ => descriptiles}/STATE.a2ml (100%) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 57cec2a..d5888b7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -26,7 +26,7 @@ ### As Applicable -- [ ] `.machine_readable/STATE.a2ml` updated (if project state changed) +- [ ] `.machine_readable/descriptiles/STATE.a2ml` updated (if project state changed) - [ ] `.machine_readable/descriptiles/ECOSYSTEM.a2ml` updated (if integrations changed) - [ ] `.machine_readable/descriptiles/META.a2ml` updated (if architectural decisions changed) - [ ] Documentation updated for user-facing changes diff --git a/.github/workflows/openssf-compliance.yml b/.github/workflows/openssf-compliance.yml index cac65f8..5237af4 100644 --- a/.github/workflows/openssf-compliance.yml +++ b/.github/workflows/openssf-compliance.yml @@ -74,11 +74,15 @@ jobs: exit 1 fi - if [ ! -f ".machine_readable/STATE.a2ml" ]; then - echo "::error::.machine_readable/STATE.a2ml is required" + if [ -e ".machine_readable/STATE.a2ml" ]; then + echo "::error::Legacy STATE.a2ml duplicate must not be recreated" exit 1 fi - echo ".machine_readable/STATE.a2ml: OK" + if [ ! -f ".machine_readable/descriptiles/STATE.a2ml" ]; then + echo "::error::.machine_readable/descriptiles/STATE.a2ml is required" + exit 1 + fi + echo ".machine_readable/descriptiles/STATE.a2ml: OK" - name: Check CHANGELOG exists run: | @@ -96,7 +100,7 @@ jobs: # Collect all required files that exist for f in SECURITY.md SECURITY.adoc .github/SECURITY.md LICENSE LICENSE.txt \ CONTRIBUTING.md CONTRIBUTING.adoc README.md README.adoc \ - .machine_readable/STATE.a2ml .machine_readable/META.a2ml \ + .machine_readable/descriptiles/STATE.a2ml .machine_readable/META.a2ml \ .machine_readable/ECOSYSTEM.a2ml CHANGELOG.md CHANGELOG.adoc; do [ -f "$f" ] && REQUIRED_FILES="$REQUIRED_FILES $f" done diff --git a/.machine_readable/0.1-AI-MANIFEST.a2ml b/.machine_readable/0.1-AI-MANIFEST.a2ml index 9d2bc7a..23b7252 100644 --- a/.machine_readable/0.1-AI-MANIFEST.a2ml +++ b/.machine_readable/0.1-AI-MANIFEST.a2ml @@ -12,7 +12,7 @@ description: | automation scripts. canonical_locations: - state: "STATE.a2ml" + state: "descriptiles/STATE.a2ml" meta: "META.a2ml" ecosystem: "ECOSYSTEM.a2ml" agentic: "AGENTIC.a2ml" diff --git a/.machine_readable/README.adoc b/.machine_readable/README.adoc index cd15ecc..dbb749b 100644 --- a/.machine_readable/README.adoc +++ b/.machine_readable/README.adoc @@ -8,18 +8,15 @@ directories is intentional; they are not interchangeable copies. == Canonical project state -* `STATE.a2ml` is the *single canonical project checkpoint*. +* `.machine_readable/descriptiles/STATE.a2ml` is the *single canonical project checkpoint*. + Update this file only; do not create a second STATE checkpoint at the old path. * `.machine_readable/6a2/STATE.a2ml` was a byte-identical stale mirror and has - been removed. Do not recreate it; update only `STATE.a2ml`. -* `.machine_readable/descriptiles/` holds `META.a2ml`, `ECOSYSTEM.a2ml`, - `AGENTIC.a2ml`, `NEUROSYM.a2ml`, and `PLAYBOOK.a2ml`. The `6a2/` location - is retired. -* `STATE.a2ml` remains here temporarily because - `.github/workflows/openssf-compliance.yml` requires this exact path. - Moving it to `.machine_readable/descriptiles/STATE.a2ml` requires updating - that workflow and the remaining state references together. Until then, - Hypatia's `SD004` finding for STATE remains unresolved; do not create a - duplicate checkpoint or suppress the finding. + been removed. The former `.machine_readable/STATE.a2ml` path is also retired. +* `.machine_readable/descriptiles/` holds `STATE.a2ml`, `META.a2ml`, + `ECOSYSTEM.a2ml`, `AGENTIC.a2ml`, `NEUROSYM.a2ml`, and `PLAYBOOK.a2ml`. +* `.github/workflows/openssf-compliance.yml`, the Justfile and agent guidance + now consume the canonical descriptile path. Hypatia structural-drift rule + `SD004` must be rechecked against this move rather than suppressed. == Contractile locations diff --git a/.machine_readable/ai/.clinerules b/.machine_readable/ai/.clinerules index eb95175..32565bc 100644 --- a/.machine_readable/ai/.clinerules +++ b/.machine_readable/ai/.clinerules @@ -2,7 +2,7 @@ # Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) # Authoritative source: docs/AI-CONVENTIONS.md -# STARTUP: Read 0-AI-MANIFEST.a2ml first, then .machine_readable/STATE.a2ml. +# STARTUP: Read 0-AI-MANIFEST.a2ml first, then .machine_readable/descriptiles/STATE.a2ml. # LICENSE # All original code: MPL-2.0. diff --git a/.machine_readable/ai/.windsurfrules b/.machine_readable/ai/.windsurfrules index eb95175..32565bc 100644 --- a/.machine_readable/ai/.windsurfrules +++ b/.machine_readable/ai/.windsurfrules @@ -2,7 +2,7 @@ # Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) # Authoritative source: docs/AI-CONVENTIONS.md -# STARTUP: Read 0-AI-MANIFEST.a2ml first, then .machine_readable/STATE.a2ml. +# STARTUP: Read 0-AI-MANIFEST.a2ml first, then .machine_readable/descriptiles/STATE.a2ml. # LICENSE # All original code: MPL-2.0. diff --git a/.machine_readable/ai/AI.a2ml b/.machine_readable/ai/AI.a2ml index e451319..fe8aba4 100644 --- a/.machine_readable/ai/AI.a2ml +++ b/.machine_readable/ai/AI.a2ml @@ -5,12 +5,12 @@ ## Repository Focus - This repository is VCL-UT, the VeriSim Consonance Language, Usage-Tracked project; follow its actual product scope and the governance files under `.machine_readable/`. -- `.machine_readable/STATE.a2ml` is the single canonical project checkpoint. +- `.machine_readable/descriptiles/STATE.a2ml` is the single canonical project checkpoint. - Machine-readable state and policy live under `.machine_readable/`; documentation templates are not live project state. - Prefer to keep generated files out of source control, and regenerate them with the documented commands before committing. ## Workflow -1. Inspect `.machine_readable/STATE.a2ml` for current status, known limitations, and next actions. +1. Inspect `.machine_readable/descriptiles/STATE.a2ml` for current status, known limitations, and next actions. 2. Respect constraints in `.machine_readable/descriptiles/AGENTIC.a2ml` when tooling changes are requested. 3. After finishing edits, update STATE with outcomes and commit with a concise, imperative message. diff --git a/.machine_readable/ai/README.adoc b/.machine_readable/ai/README.adoc index 4e2f1d8..a031f00 100644 --- a/.machine_readable/ai/README.adoc +++ b/.machine_readable/ai/README.adoc @@ -21,5 +21,5 @@ Recommended machine read order: * `.machine_readable/policies/MAINTENANCE-AXES.a2ml` * `.machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml` * `.machine_readable/policies/SOFTWARE-DEVELOPMENT-APPROACH.a2ml` -* `.machine_readable/STATE.a2ml` +* `.machine_readable/descriptiles/STATE.a2ml` * `.machine_readable/descriptiles/META.a2ml` diff --git a/.machine_readable/descriptiles/PLAYBOOK.a2ml b/.machine_readable/descriptiles/PLAYBOOK.a2ml index d768f71..dd90793 100644 --- a/.machine_readable/descriptiles/PLAYBOOK.a2ml +++ b/.machine_readable/descriptiles/PLAYBOOK.a2ml @@ -13,7 +13,7 @@ last-updated = "2026-03-16" # target = "container" # container | binary | library | wasm [incident-response] -# 1. Check .machine_readable/STATE.a2ml for current status +# 1. Check .machine_readable/descriptiles/STATE.a2ml for current status # 2. Review recent commits and CI results # 3. Run `just validate` to check compliance # 4. Run `just security` to audit for vulnerabilities diff --git a/.machine_readable/STATE.a2ml b/.machine_readable/descriptiles/STATE.a2ml similarity index 100% rename from .machine_readable/STATE.a2ml rename to .machine_readable/descriptiles/STATE.a2ml diff --git a/0-AI-MANIFEST.a2ml b/0-AI-MANIFEST.a2ml index 248c50b..8eb3ff5 100644 --- a/0-AI-MANIFEST.a2ml +++ b/0-AI-MANIFEST.a2ml @@ -56,11 +56,15 @@ If VCL-total succeeds, it replaces VCL-DT entirely. ### Machine-Readable Metadata: `.machine_readable/` ONLY -These a2ml files MUST exist in `.machine_readable/` directory ONLY: -1. **STATE.a2ml** - Project state, progress, blockers +These A2ML descriptile files MUST live under `.machine_readable/descriptiles/`: +1. **STATE.a2ml** - Canonical project state, progress, blockers 2. **META.a2ml** - Architecture decisions, governance 3. **ECOSYSTEM.a2ml** - Position in ecosystem, relationships +The old `.machine_readable/STATE.a2ml` checkpoint path is retired. Do not +recreate it as a mirror: `.machine_readable/descriptiles/STATE.a2ml` is +canonical. + **CRITICAL:** If ANY of these files exist in the root directory, this is an ERROR. ### Source Code diff --git a/Justfile b/Justfile index a85f289..88b470f 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/descriptiles/META.a2ml .machine_readable/descriptiles/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/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 @@ -697,13 +697,17 @@ 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 && \ - echo "STATE.a2ml: valid" || echo "STATE.a2ml: INVALID (missing required sections)"; \ - else \ - echo "No .machine_readable/STATE.a2ml found"; \ - fi + @file=".machine_readable/descriptiles/STATE.a2ml"; \ + if [ -e ".machine_readable/STATE.a2ml" ]; then \ + echo "STATE.a2ml: DUPLICATE legacy location" >&2; exit 1; \ + fi; \ + if [ ! -f "$file" ]; then \ + echo "STATE.a2ml: MISSING ($file)" >&2; exit 1; \ + fi; \ + if ! grep -q '^\[metadata\]' "$file" || ! grep -Eq '^[[:space:]]*project[[:space:]]*=' "$file"; then \ + echo "STATE.a2ml: INVALID (missing required sections or project)" >&2; exit 1; \ + fi; \ + echo "STATE.a2ml: structural fields present" # Validate AI installation guide completeness (finishbot pre-release check) validate-ai-install: @@ -779,14 +783,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/docs/RSR_OUTLINE.adoc b/docs/RSR_OUTLINE.adoc index a1cefe6..ef3fd15 100644 --- a/docs/RSR_OUTLINE.adoc +++ b/docs/RSR_OUTLINE.adoc @@ -218,7 +218,7 @@ project/ * `Justfile` * `README.adoc` * `LICENSE` (MPL-2.0) -* `.machine_readable/STATE.a2ml` +* `.machine_readable/descriptiles/STATE.a2ml` * `.well-known/security.txt` * `.well-known/ai.txt` * `.well-known/humans.txt` diff --git a/docs/practice/AI-CONVENTIONS.adoc b/docs/practice/AI-CONVENTIONS.adoc index 203cfda..bc2f7ab 100644 --- a/docs/practice/AI-CONVENTIONS.adoc +++ b/docs/practice/AI-CONVENTIONS.adoc @@ -10,7 +10,7 @@ Per-tool config files (.cursorrules, .clinerules, etc.) reference this document. ## Session Startup 1. Read `0-AI-MANIFEST.a2ml` FIRST (mandatory gatekeeper). -2. Read `.machine_readable/STATE.a2ml` for current status and blockers. +2. Read `.machine_readable/descriptiles/STATE.a2ml` for current status and blockers. 3. Read `.machine_readable/anchors/ANCHOR.a2ml` for canonical authority boundaries. 4. Read `.machine_readable/policies/MAINTENANCE-AXES.a2ml` for maintenance/audit sequencing. 5. Read `.machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml` for baseline controls. @@ -80,7 +80,7 @@ Use `just` (Justfile) for all build, test, lint, and format tasks. - `0-AI-MANIFEST.a2ml` -- universal AI entry point - `.machine_readable/descriptiles/AGENTIC.a2ml` -- agent permissions and constraints -- `.machine_readable/STATE.a2ml` -- current project state +- `.machine_readable/descriptiles/STATE.a2ml` -- current project state - `.machine_readable/anchors/ANCHOR.a2ml` -- canonical authority and policy boundary - `.machine_readable/policies/MAINTENANCE-AXES.a2ml` -- canonical axis sequencing and audit requirements - `.machine_readable/policies/MAINTENANCE-CHECKLIST.a2ml` -- baseline maintenance checklist policy From b4025cbc2f813fd961c95cf0fdd0d41616b3ed74 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 29 Oct 2026 22:39:07 +0000 Subject: [PATCH 2/5] docs(governance): align STATE layout and sample with validation --- docs/RSR_OUTLINE.adoc | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/docs/RSR_OUTLINE.adoc b/docs/RSR_OUTLINE.adoc index ef3fd15..0b836f4 100644 --- a/docs/RSR_OUTLINE.adoc +++ b/docs/RSR_OUTLINE.adoc @@ -162,12 +162,13 @@ project/ │ ├── humans.txt │ └── security.txt ├── .machine_readable/ # ALL machine-readable content -│ ├── STATE.a2ml # Project state, progress, blockers -│ ├── META.a2ml # Architecture decisions, governance -│ ├── ECOSYSTEM.a2ml # Ecosystem position, relationships -│ ├── AGENTIC.a2ml # AI agent interaction patterns -│ ├── NEUROSYM.a2ml # Neurosymbolic integration config -│ ├── PLAYBOOK.a2ml # Operational runbook +│ ├── descriptiles/ # Canonical typed project records +│ │ ├── STATE.a2ml # Project state, progress, blockers +│ │ ├── META.a2ml # Architecture decisions, governance +│ │ ├── ECOSYSTEM.a2ml # Ecosystem position, relationships +│ │ ├── AGENTIC.a2ml # AI agent interaction patterns +│ │ ├── NEUROSYM.a2ml # Neurosymbolic integration config +│ │ └── PLAYBOOK.a2ml # Operational runbook │ ├── bot_directives/ # Per-bot rules and constraints │ └── contractiles/ # Policy enforcement contracts │ ├── k9/ # Security levels (Kennel/Yard/Hunt) @@ -235,30 +236,35 @@ project/ == STATE.a2ml -The STATE.a2ml file tracks project state: +The canonical `.machine_readable/descriptiles/STATE.a2ml` tracks project +state. This minimal TOML-shaped A2ML example satisfies `just validate-state`: -[source] +[source,toml] ---- +# SPDX-License-Identifier: MPL-2.0 # STATE — Project State Checkpoint -# Format: a2ml (AI-readable markup) -project: v-graphql -version: 0.1.0 -last-updated: 2026-02-14 -status: active +[metadata] +project = "v-graphql" +version = "0.1.0" +last-updated = "2026-02-14" +status = "active" + +[project-context] +phase = "implementation" +maturity = "beta" -phase: implementation -maturity: beta +[ecosystem] +part-of = "RSR Framework" +depends-on = [] -ecosystem: - part-of: RSR Framework - depends-on: [] +[[milestones]] +name = "Initial setup" +completion = 100 -milestones: - - name: Initial setup - completion: 100 - - name: Core implementation - completion: 0 +[[milestones]] +name = "Core implementation" +completion = 0 ---- == Badge Schema From d0f3d73bbd9ca524450836cf1f1b3450710931ca Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 29 Oct 2026 22:32:09 +0000 Subject: [PATCH 3/5] fix(ci): call canonical pinned secret scanner with least privilege --- .github/workflows/secret-scanner.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index 63078c0..ad7e1f4 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -15,9 +15,9 @@ permissions: jobs: scan: - uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@c65436ee3351cd6b0fa14b142938b195efc77586 - secrets: inherit + # Canonical standards owner after transfer; exact reviewed commit pin. + # The reusable runs pinned local scanners with contents: read only and + # explicitly declares no workflow_call secrets. Do not inherit secrets. + uses: metadatastician/standards/.github/workflows/secret-scanner-reusable.yml@8e48b1caade08a552646adeab66558ac43b4360d permissions: - actions: read contents: read - security-events: write From 40cb09d019c12f6d17752d655055883396c9d8d0 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 29 Oct 2026 22:37:36 +0000 Subject: [PATCH 4/5] fix(ci): replace redundant per-prover matrix with genuine transport gate --- .github/workflows/backend-matrix.yml | 120 +++++++++++++-------------- 1 file changed, 58 insertions(+), 62 deletions(-) diff --git a/.github/workflows/backend-matrix.yml b/.github/workflows/backend-matrix.yml index 077b241..9000e73 100644 --- a/.github/workflows/backend-matrix.yml +++ b/.github/workflows/backend-matrix.yml @@ -1,25 +1,19 @@ # SPDX-License-Identifier: MPL-2.0 -# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) # -# backend-matrix.yml — Per-prover smoke matrix for vcl-ut → echidna wire. +# backend-matrix.yml — Echidna catalogue validation + real wiremock transport. # -# One matrix job per ProverKind variant. Authoritative list comes from -# echidna's .machine_readable/provers.a2ml (source-of-truth: the -# ProverKind enum in echidna/src/rust/provers/mod.rs). The prep job -# parses provers.a2ml and emits a matrix JSON ephemerally as a GHA -# output — no committed JSON artefact (memory rule: tools emit A2ML, -# not JSON). +# Previously this expanded every entry in echidna's provers.a2ml to a separate +# Rust job (142 jobs on the 2026-10-29 PR run; max-parallel=3). Each job ran +# precisely the same wiremock transport suite. ECHIDNA_PROVER was set, but +# neither the client nor its tests read it. The matrix therefore produced +# identical evidence many times, at high latency and runner cost. # -# Current scope of per-job work: -# - Runs the vcltotal-echidna-client wiremock integration suite -# with the target prover slug injected as ECHIDNA_PROVER env. -# - When echidna's REST surface expands to all 105 backends (today -# it exposes 17), each job can diverge per slug to exercise a -# live echidna container. That upgrade is tracked as Package 4 -# step 7; the matrix shape here is ready for it. -# -# Resource budget: max-parallel=3 per the user's standing constraint -# on parallel subagents / bash invocations applied to CI. +# Keep the authoritative Echidna prover inventory check. Run the one transport +# suite once. Do NOT label a mock transport check as per-prover verification. +# If the client starts consuming ECHIDNA_PROVER, the guard below fails and the +# real per-prover matrix must be restored, with distinct per-prover assertions +# (ideally against the live Echidna implementations). Do not bypass the guard. name: Backend Matrix @@ -35,57 +29,72 @@ permissions: jobs: prep: - name: Derive matrix from echidna provers.a2ml + name: Validate Echidna prover catalogue runs-on: ubuntu-latest timeout-minutes: 15 - outputs: - provers: ${{ steps.parse.outputs.provers }} - count: ${{ steps.parse.outputs.count }} steps: - name: Checkout vcl-ut uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Checkout echidna (authoritative ProverKind source) + - name: Checkout Echidna authoritative prover source uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: hyperpolymath/echidna path: echidna fetch-depth: 1 + persist-credentials: false - - name: Parse provers.a2ml → matrix JSON (ephemeral GHA output only) - id: parse + - name: Validate prover slugs from provers.a2ml run: | set -euo pipefail a2ml=echidna/.machine_readable/provers.a2ml - test -f "$a2ml" - # Extract `slug = "..."` values from each [prover.X] section. - # Keep only the slug; nothing else is needed by the matrix yet. - slugs=$(grep -E '^slug = ' "$a2ml" | sed -E 's/slug = "(.+)"/\1/') - count=$(echo "$slugs" | wc -l | tr -d ' ') - # Convert to JSON array for GitHub Actions matrix consumption. - # (GHA matrix strategies require JSON; this is runtime - # marshalling, not a persisted artefact.) - json=$(printf '%s\n' "$slugs" | jq -R . | jq -sc .) - echo "provers=$json" >> "$GITHUB_OUTPUT" - echo "count=$count" >> "$GITHUB_OUTPUT" - echo "Derived matrix: $count provers" + test -s "$a2ml" + slugs="$(grep -E '^slug = ' "$a2ml" | sed -E 's/^slug = "(.+)"$/\1/')" + count="$(printf '%s\n' "$slugs" | wc -l | tr -d ' ')" + if [ "$count" -eq 0 ]; then + echo "::error::Echidna prover catalogue contains no slugs" + exit 1 + fi + if printf '%s\n' "$slugs" | grep -Ev '^[a-z][a-z0-9_]*$'; then + echo "::error::Echidna catalogue contains an invalid slug" + exit 1 + fi + declared="$(sed -nE 's/^count[[:space:]]*=[[:space:]]*([0-9]+)$/\1/p' "$a2ml" | head -1)" + if [ "$declared" != "$count" ]; then + echo "::error::Echidna catalogue count mismatch: declared=$declared parsed=$count" + exit 1 + fi + unique="$(printf '%s\n' "$slugs" | sort -u | wc -l | tr -d ' ')" + if [ "$count" -ne "$unique" ]; then + echo "::error::Echidna prover catalogue contains duplicate slugs" + exit 1 + fi + echo "Echidna inventory: $count distinct prover slugs; verified, not individually tested." smoke: - name: Smoke (${{ matrix.prover }}) + name: Client wiremock transport (prover-independent) needs: prep runs-on: ubuntu-latest timeout-minutes: 15 - strategy: - fail-fast: false - max-parallel: 3 - matrix: - prover: ${{ fromJson(needs.prep.outputs.provers) }} - env: - ECHIDNA_PROVER: ${{ matrix.prover }} steps: - name: Checkout vcl-ut uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Assert transport tests remain independent of prover selection + run: | + set -euo pipefail + # If future source/tests begin reading the selector, a single suite + # cannot certify them. Fail rather than silently lose coverage. + test -d src/interface/echidna-client/src + test -d src/interface/echidna-client/tests + if grep -RFn 'ECHIDNA_PROVER' \ + src/interface/echidna-client/src \ + src/interface/echidna-client/tests; then + echo "::error::ECHIDNA_PROVER is now consumed: restore a genuine per-prover test matrix" + exit 1 + fi + echo "Prover selector unused; one wiremock transport suite is sufficient." + - name: Install Rust toolchain uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable @@ -94,23 +103,10 @@ jobs: with: shared-key: backend-matrix - # The vcl-ut workspace has a path-dependency - # `echidna-core = { path = "../../../echidna/crates/echidna-core" }` - # (src/interface/Cargo.toml), so the whole workspace fails to load - # unless echidna is present as a sibling of the checkout. Provide it. - - name: Provide echidna sibling (echidna-core path-dependency) + # This client is not a root workspace member and depends on Echidna + # source as a sibling path-dependency. + - name: Provide Echidna sibling for echidna-core path dependency run: git clone --depth 1 https://github.com/hyperpolymath/echidna ../echidna - - name: Client wiremock suite (ECHIDNA_PROVER=${{ matrix.prover }}) - # `vcltotal-echidna-client` is intentionally NOT a member of the root - # workspace (v0.2.0 workspace cleanup: its transitive echidna-core - # path-dep breaks standalone CI), so `-p` cannot select it. It is its - # own standalone workspace root; run it by manifest path now that the - # echidna sibling has been cloned above. - # NOTE: echidna-client is a standalone workspace with NO committed - # Cargo.lock — its transitive `echidna-core` path-dep only exists once - # the sibling is cloned (step above), so a lockfile cannot be committed - # and `--locked` can never be satisfied: it fails before the tests even - # build ("cannot create the lock file ... because --locked was passed"). - # Resolve fresh against the just-cloned sibling instead (omit --locked). + - name: Client wiremock transport suite run: cargo test --manifest-path src/interface/echidna-client/Cargo.toml --tests From 8f3692b1f51a9e6a9192cc7045444148c7ab01db Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Thu, 29 Oct 2026 22:42:12 +0000 Subject: [PATCH 5/5] fix(ci): cancel superseded PR backend runs without dropping main evidence --- .github/workflows/backend-matrix.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/backend-matrix.yml b/.github/workflows/backend-matrix.yml index 9000e73..2cbf7e8 100644 --- a/.github/workflows/backend-matrix.yml +++ b/.github/workflows/backend-matrix.yml @@ -24,6 +24,12 @@ on: branches: [main, master] workflow_dispatch: {} +# Each PR revision supersedes only earlier revisions of the same PR. Pushes +# to main retain their independent verification history. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + permissions: contents: read