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
117 changes: 74 additions & 43 deletions .github/workflows/affinescript-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,20 @@ permissions:
# compiler (hyperpolymath/affinescript). The compiler is pinned to a commit
# SHA for reproducibility; bump COMPILER_REF deliberately.
#
# NON-BLOCKING (temporary): the initial ReScript->AffineScript port (PR #62)
# was done without a compiler, so `affinescript check` currently reports
# errors that need mechanical fixes. Until those are resolved this job
# REPORTS failures (job summary + warnings) but exits green so it does not
# block merges. Flip BLOCKING to "true" once the ports compile clean.
# SPLIT GATE (Wave 8, standards#446 honest-gating): the initial
# ReScript->AffineScript port (PR #62) predates the compiler, so some legacy
# ports still fail `affinescript check`. Blindly flipping the whole job to
# blocking would red every PR that touches a legacy port — manufactured noise.
# Instead the gate distinguishes:
# * ADDED .affine files (diff-filter=A) -> BLOCKING. New code has no excuse
# not to compile; a failing added file fails this job.
# * MODIFIED legacy files (diff-filter=CMR) -> advisory warnings until the
# port backlog clears (flip LEGACY_BLOCKING=true then).
# * Toolchain failures (compiler checkout/opam/build) -> advisory: the step
# reports "toolchain unavailable" and the verify step SKIPS (loudly) rather
# than blocking unrelated changes on OCaml infra flake.
env:
BLOCKING: "false"
LEGACY_BLOCKING: "false"
COMPILER_REPO: hyperpolymath/affinescript
COMPILER_REF: d2875a552f1d389b4a60c4adfdc02ae53e36aca3

Expand All @@ -40,12 +47,6 @@ jobs:
timeout-minutes: 20
name: AffineScript Verify
runs-on: ubuntu-latest
# advisory: see header note. continue-on-error keeps the
# whole job advisory — including the compiler checkout/setup-ocaml/build
# steps — so a toolchain/build problem cannot block merges or add
# estate-wide red noise while the ports + build are sorted in follow-up.
# Remove this (and flip BLOCKING=true) once the job is reliably green.
continue-on-error: true
permissions:
contents: read
steps:
Expand All @@ -66,15 +67,20 @@ jobs:
|| printf '%s' "$BASE" | grep -qE '^0+$'; then
BASE="$(git rev-parse HEAD^ 2>/dev/null || git rev-parse HEAD)"
fi
FILES="$(git diff --name-only --diff-filter=ACMR "$BASE" HEAD -- '*.affine' || true)"
# Split-gate inputs: ADDED files gate hard; modified legacy files are
# advisory until the port backlog clears (see header).
ADDED="$(git diff --name-only --diff-filter=A "$BASE" HEAD -- '*.affine' || true)"
MODIFIED="$(git diff --name-only --diff-filter=CMR "$BASE" HEAD -- '*.affine' || true)"
FILES="$(printf '%s\n%s\n' "$ADDED" "$MODIFIED" | sed '/^$/d')"
if [ -z "$FILES" ]; then
echo "any=false" >> "$GITHUB_OUTPUT"
echo "No changed .affine files — nothing to verify."
else
echo "any=true" >> "$GITHUB_OUTPUT"
echo "Changed .affine files:"
echo "Changed .affine files (added gate hard; modified advisory):"
echo "$FILES"
{ echo 'files<<EOF'; echo "$FILES"; echo 'EOF'; } >> "$GITHUB_OUTPUT"
{ echo 'added<<EOF'; echo "$ADDED"; echo 'EOF'; } >> "$GITHUB_OUTPUT"
fi

- name: Checkout AffineScript compiler
Expand All @@ -98,61 +104,86 @@ jobs:
ocaml-compiler: "5.1"

- name: Build compiler
id: build
if: steps.changed.outputs.any == 'true'
# advisory: compiler build failures are reported by this job, not yet
# merge-blocking, until the report-only porting phase ends.
# advisory: toolchain failures are infra flake, not code failures —
# they must not block unrelated changes. The verify step below skips
# LOUDLY (never a silent green claim) when the compiler is unavailable.
continue-on-error: true
working-directory: .affinescript-compiler
run: |
opam install . --deps-only
opam exec -- dune build
echo "ok=true" >> "$GITHUB_OUTPUT"

- name: Verify changed .affine files
- name: Verify changed .affine files (added files gate; legacy advisory)
if: steps.changed.outputs.any == 'true'
# advisory: verification findings are emitted as warnings and job
# summary entries until BLOCKING is intentionally enabled.
continue-on-error: true
working-directory: .affinescript-compiler
# No working-directory: if the (advisory) compiler checkout failed, the
# dir may not exist — the guard below must run BEFORE any cd.
run: |
set -u
rc=0
failed=""
if [ "${{ steps.build.outputs.ok }}" != "true" ] || [ ! -d .affinescript-compiler ]; then
echo "::warning::AffineScript toolchain unavailable (compiler checkout/opam/build failed) — verification SKIPPED, not passed."
{
echo "## AffineScript Verify"
echo "⚠️ **SKIPPED — toolchain unavailable.** The compiler did not build;"
echo "no \`.affine\` file was verified. This is an infra flake, not a pass."
} >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
cd .affinescript-compiler
# is_added <file>: is this file in the added set? (added files gate hard)
is_added() {
case $'\n'"${ADDED_SET}"$'\n' in *$'\n'"$1"$'\n'*) return 0 ;; *) return 1 ;; esac
}
ADDED_SET="$(cat <<'EOF'
${{ steps.changed.outputs.added }}
EOF
)"
ADDED_SET="$(printf '%s\n' "$ADDED_SET" | sed 's/^[[:space:]]*//' | sed '/^$/d')"
added_fail=""
legacy_fail=""
while IFS= read -r f; do
[ -z "$f" ] && continue
abs="$GITHUB_WORKSPACE/$f"
echo "::group::check $f"
if opam exec -- dune exec affinescript -- check "$abs" 2>&1; then
echo "✅ $f"
elif is_added "$f"; then
echo "::error file=$f::AffineScript check failed (ADDED file — blocking)"
echo "❌ $f failed (added file — blocking)"
added_fail="$added_fail$f"$'\n'
else
echo "::warning file=$f::AffineScript check failed"
echo "❌ $f failed AffineScript check"
failed="$failed$f"$'\n'
rc=1
echo "::warning file=$f::AffineScript check failed (legacy port — advisory until backlog clears)"
echo "⚠️ $f failed (legacy port — advisory)"
legacy_fail="$legacy_fail$f"$'\n'
fi
echo "::endgroup::"
done <<'EOF'
${{ steps.changed.outputs.files }}
EOF

{
echo "## AffineScript Verify"
if [ "$rc" -eq 0 ]; then
echo "## AffineScript Verify (split gate)"
if [ -z "$added_fail" ] && [ -z "$legacy_fail" ]; then
echo "All changed \`.affine\` files passed \`affinescript check\`."
else
echo "The following changed \`.affine\` files failed \`affinescript check\`:"
echo ""
echo "$failed" | sed '/^$/d' | sed 's/^/- /'
echo ""
echo "_See the per-file groups in the job log for the compiler errors._"
fi
if [ -n "$added_fail" ]; then
echo "### ❌ ADDED files failing (BLOCKING — new code must compile)"
echo "$added_fail" | sed '/^$/d' | sed 's/^/- /'
fi
if [ -n "$legacy_fail" ]; then
echo "### ⚠️ Legacy ports failing (advisory until the port backlog clears)"
echo "$legacy_fail" | sed '/^$/d' | sed 's/^/- /'
fi
} >> "$GITHUB_STEP_SUMMARY"

if [ "$rc" -ne 0 ]; then
if [ "$BLOCKING" = "true" ]; then
echo "AffineScript verification failed (blocking)."
exit 1
fi
echo "::warning::AffineScript verification found errors but is non-blocking (BLOCKING=false). See job summary."
exit 0
if [ -n "$added_fail" ]; then
echo "AffineScript verification failed for ADDED files (blocking)."
exit 1
fi
if [ -n "$legacy_fail" ] && [ "$LEGACY_BLOCKING" = "true" ]; then
echo "Legacy port failures are blocking (LEGACY_BLOCKING=true)."
exit 1
fi
echo "All changed .affine files passed AffineScript verification."
echo "Verification complete (added files clean)."
26 changes: 21 additions & 5 deletions .github/workflows/hypatia-scan-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,30 @@ jobs:
panic-attack-findings.json
retention-days: 90

- name: Gate on baseline (blocking when a baseline is committed)
if: steps.scan.outputs.findings_count > 0
run: |
# Wave-8 gate promotion: when the calling repo commits a
# .hypatia-baseline.json (schema: .machine_readable/hypatia-baseline.
# schema.json) AND ships scripts/apply-baseline.sh, findings are
# filtered against the baseline and any UNBASELINED finding at or
# above the blocking threshold FAILS this job. Repos without a
# baseline keep the honest ADVISORY behaviour below — the gate arms
# itself the moment a baseline lands (standards#399/#437/#446).
if [ -f scripts/apply-baseline.sh ] && [ -f .hypatia-baseline.json ]; then
echo "Baseline present — running BLOCKING gate (threshold: high)."
bash scripts/apply-baseline.sh hypatia-findings.json .hypatia-baseline.json blocking
else
echo "No committed baseline — gate stays advisory (see next step)."
fi

- name: Check for critical issues (ADVISORY — does not gate)
if: steps.scan.outputs.critical > 0
run: |
# This scan is ADVISORY / fix-forward: it never fails the build. The
# label and summary state that explicitly so a green check carrying
# critical findings is not mistaken for "no critical findings".
# (Promotion to blocking is tracked with the baseline reconciliation,
# standards#399/#437.)
# This scan is ADVISORY / fix-forward WHEN NO BASELINE IS COMMITTED
# (the step above becomes the blocking gate once .hypatia-baseline.json
# lands). The label and summary state that explicitly so a green check
# carrying critical findings is not mistaken for "no critical findings".
echo "::warning title=Hypatia (ADVISORY, non-blocking)::${{ steps.scan.outputs.critical }} critical finding(s). This scan does not gate — review hypatia-findings.json and fix forward."
{
echo "### Hypatia scan — ADVISORY (does not gate)"
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/registry-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,19 @@ jobs:
exit 1
fi

- name: Verify compliance dashboard is current
- name: Mustfile enforcement (structural + execute invariants)
run: |
if ! bash scripts/build-scorecards.sh --check --strict; then
# Wave-8 gate promotion: the Mustfile's invariants previously executed
# only on push-to-main (boj-build.yml). PRs now gate on them too —
# a change that breaks a MUST invariant fails before merge, not after.
bash scripts/check-mustfile-structure.sh
bash scripts/run-mustfile.sh

- name: Verify compliance dashboard is current (and pass-checks hold)
run: |
# --verify RUNS every pass-row's executable `check`: a claimed pass
# whose check does not hold fails this job (DYADT on the scorecards).
if ! bash scripts/build-scorecards.sh --check --strict --verify; then
{
echo "### Compliance dashboard drift"
echo ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ text = "The repository MUST contain exactly one AI manifest file, named 0-AI-MAN
system = "none (no automated validator script checks this in CI; verified manually via directory listing)"
status = "pass"
evidence = "find confirms exactly one manifest at /home/user/standards/0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml; no AI.a2ml, !AI.a2ml, or duplicate found at root."
check = "test -f 0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml && [ $(find 0-ai-gatekeeper-protocol -maxdepth 1 \\( -iname \"0-AI-MANIFEST.a2ml\" -o -iname \"AI.a2ml\" -o -iname \"!AI.a2ml\" \\) | wc -l) -eq 1 ]"
effects = "If violated, downstream MCP/FUSE parsers (mcp-repo-guardian, repo-guardian-fs) that assume a single canonical manifest path would pick an arbitrary or wrong file, breaking attestation for every consuming repo/agent."

[[must]]
Expand All @@ -23,6 +24,7 @@ text = "The manifest MUST contain all required sections defined by AI-MANIFEST-S
system = "none (no parser/linter script in this repo enforces the spec against 0-AI-MANIFEST.a2ml; mcp-repo-guardian's manifest_test.js only tests inline reimplementations of parsing logic, not a repo-facing validator CLI)"
status = "pass"
evidence = "Manual read of /home/user/standards/0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml confirms presence of '# ⚠️ STOP', '## WHAT IS THIS?', '## CANONICAL LOCATIONS', '## CORE INVARIANTS', '## REPOSITORY STRUCTURE', and '## ATTESTATION PROOF' headings."
check = "grep -q '# ⚠️ STOP' 0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml && grep -q '## WHAT IS THIS?' 0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml && grep -q '## CANONICAL LOCATIONS' 0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml && grep -q '## CORE INVARIANTS' 0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml && grep -q '## REPOSITORY STRUCTURE' 0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml && grep -q '## ATTESTATION PROOF' 0-ai-gatekeeper-protocol/0-AI-MANIFEST.a2ml"
effects = "Missing sections would leave AI agents without required guardrail information, defeating the protocol's stated purpose across all adopting repos."

[[must]]
Expand All @@ -38,6 +40,7 @@ text = "Core manifest-parsing/session/guard logic (as implemented for FFI/offlin
system = "cargo test --manifest-path repo-guardian-fs/tests-offline/Cargo.toml (Rust unit tests for manifest parsing, session management, and path-guard invariant enforcement)"
status = "pass"
evidence = "Ran `cargo test` in /home/user/standards/0-ai-gatekeeper-protocol/repo-guardian-fs/tests-offline: 29 passed; 0 failed (manifest hashing, canonical-location extraction, invariant detection, session ack/expiry, path-traversal/SCM-duplication guard tests, and a dogfood test parsing the repo's real 0-AI-MANIFEST.a2ml)."
check = "cargo test --manifest-path 0-ai-gatekeeper-protocol/repo-guardian-fs/tests-offline/Cargo.toml"
effects = "If these regress, any FFI/native consumer (e.g. Zig bindings, future editor plugins) linking against this logic would silently mis-enforce or fail to enforce invariants."

[[must]]
Expand Down
14 changes: 8 additions & 6 deletions .machine_readable/scorecards/a2ml-templates.scorecard.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ assessor = "estate-audit"
[[must]]
id = "M1"
text = "Each *.a2ml.template file MUST carry an SPDX-License-Identifier header."
system = "none"
status = "pass"
evidence = "All 7 files in /home/user/standards/a2ml-templates/ (META.a2ml.template, AGENTIC.a2ml.template, ECOSYSTEM.a2ml.template, NEUROSYM.a2ml.template, PLAYBOOK.a2ml.template, STATE.a2ml.template, STATE.a2ml.v2.template) and both scripts carry an SPDX-License-Identifier as line 1/2 (manually verified by reading each file); however no automated check enforces this for this directory - hooks/validate-spdx.sh only scans .github/workflows/*.yml, not a2ml-templates/."
system = "Manual license audit (Manual-Only policy: SPDX/licence rows never carry an automated check)."
status = "manual-only"
evidence = "Manually verified (and spot-checked via grep) that all 7 template files, the spec.adoc, and both migration scripts carry an SPDX-License-Identifier on line 1 or 2; per estate Manual-Only policy this remains a manual/licence-audit item, not an automated check."
effects = "Downstream repos copying these templates inherit correct licensing metadata by convention, but a future edit could silently drop the header with nothing to catch it."

[[must]]
Expand All @@ -41,9 +41,10 @@ effects = "Consuming repos (or the migration scripts themselves) can emit malfor
[[must]]
id = "M5"
text = "The spec MUST be tracked in the estate compliance dashboard with a scorecard once templates stabilize."
system = "COMPLIANCE-DASHBOARD.md rollup table"
status = "fail"
evidence = "COMPLIANCE-DASHBOARD.md line 50 lists `a2ml-templates | no scorecard | - | - | - | - | -` and line 58 includes a2ml-templates in the 27 specs still needing a scorecard (1/28 specs scored)."
system = "COMPLIANCE-DASHBOARD.md rollup table (line 52) plus .machine_readable/scorecards/a2ml-templates.scorecard.a2ml"
status = "pass"
evidence = "COMPLIANCE-DASHBOARD.md line 52 lists `a2ml-templates` with real must/should/could scores (1/5, 1/3, 0/2) rather than the 'no scorecard' placeholder, and this file (.machine_readable/scorecards/a2ml-templates.scorecard.a2ml) is the tracked scorecard; rollup states 'Specs with a scorecard: 30 / 30'."
check = "grep -n \"^| \\`a2ml-templates\\`\" COMPLIANCE-DASHBOARD.md | grep -qv \"no scorecard\" && test -f .machine_readable/scorecards/a2ml-templates.scorecard.a2ml"
effects = "The estate-wide rollup (1/28 specs scored, 50% system coverage) cannot include this spec's real compliance state, so any regression here is invisible at the estate level until this scorecard is produced and merged."

[[should]]
Expand All @@ -67,6 +68,7 @@ text = "The migration scripts SHOULD emit non-zero exit codes and clear diagnost
system = "none"
status = "pass"
evidence = "state-scm-to-v2.jl documents and implements distinct exit codes (0 ok, 2 parse/usage error, 3 not a (state ...) form) per its header comment and main()/convert() logic; state-migrate-v1-to-v2.sh uses `set -eu` and exits 1 with a message when the v1 file is missing (line 16)."
check = "cd /home/user/standards && sh a2ml-templates/state-migrate-v1-to-v2.sh /nonexistent-repo-path >/dev/null 2>&1; test $? -eq 1 && grep -q \"exit(2)\" a2ml-templates/state-scm-to-v2.jl && grep -q \"exit(3)\" a2ml-templates/state-scm-to-v2.jl"
effects = "Callers (CI or a future k9-init tool) can branch on exit code to decide whether to retry, prompt a human, or abort; without this, migration failures could pass silently and produce corrupt STATE.a2ml files downstream."

[[could]]
Expand Down
Loading
Loading