Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
126 changes: 64 additions & 62 deletions .github/workflows/backend-matrix.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
# 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

Expand All @@ -30,62 +24,83 @@ 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

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

Expand All @@ -94,23 +109,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
12 changes: 8 additions & 4 deletions .github/workflows/openssf-compliance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,15 @@
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

Check failure on line 77 in .github/workflows/openssf-compliance.yml

View workflow job for this annotation

GitHub Actions / Hypatia neurosymbolic scan

[hypatia] CI policy requires a retired descriptile path; align the check with .machine_readable/descriptiles/
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: |
Expand All @@ -88,7 +92,7 @@
fi
echo "CHANGELOG: OK"

- name: Check no unfilled placeholder tokens in required files

Check warning on line 95 in .github/workflows/openssf-compliance.yml

View workflow job for this annotation

GitHub Actions / Hypatia neurosymbolic scan

[hypatia] workflow .github/workflows/openssf-compliance.yml:95 step `Check no unfilled placeholder tokens in required files` swallows non-zero exit via `|| true` — failures will be masked
run: |
ERRORS=0
REQUIRED_FILES=""
Expand All @@ -96,7 +100,7 @@
# 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
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/secret-scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion .machine_readable/0.1-AI-MANIFEST.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
19 changes: 8 additions & 11 deletions .machine_readable/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion .machine_readable/ai/.clinerules
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
# 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.
Expand Down
2 changes: 1 addition & 1 deletion .machine_readable/ai/.windsurfrules
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
# 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.
Expand Down
4 changes: 2 additions & 2 deletions .machine_readable/ai/AI.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion .machine_readable/ai/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`
2 changes: 1 addition & 1 deletion .machine_readable/descriptiles/PLAYBOOK.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions 0-AI-MANIFEST.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 16 additions & 12 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
@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
Expand Down Expand Up @@ -663,7 +663,7 @@
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
Expand Down Expand Up @@ -697,13 +697,17 @@

# 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 \

Check failure on line 701 in Justfile

View workflow job for this annotation

GitHub Actions / Hypatia neurosymbolic scan

[hypatia] CI policy requires a retired descriptile path; align the check with .machine_readable/descriptiles/
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; \
Comment thread
hyperpolymath marked this conversation as resolved.
Resolved
fi; \
echo "STATE.a2ml: structural fields present"

# Validate AI installation guide completeness (finishbot pre-release check)
validate-ai-install:
Expand Down Expand Up @@ -779,14 +783,14 @@

# 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
Expand Down
Loading
Loading