diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000..3885e2b --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: MPL-2.0 +# Enforces the MUST.contractile invariants on every PR — the +# "quality.yml runs must-check on every PR" promise in MUST.contractile +# [enforcement] — via the portable must-check enforcer, plus an advisory +# EditorConfig pass. No path filters, so it is always created as a stable check. +name: Code Quality + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + must-check: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: MUST.contractile invariants (must-check) + run: bash .machine_readable/contractiles/k9/must-check.sh + + - name: EditorConfig (advisory) + uses: editorconfig-checker/action-editorconfig-checker@4b6cd6190d435e7e084fb35e36a096e98506f7b9 # v2.1.0 + continue-on-error: true diff --git a/.machine_readable/MUST.contractile b/.machine_readable/MUST.contractile index a1a075c..0e390df 100644 --- a/.machine_readable/MUST.contractile +++ b/.machine_readable/MUST.contractile @@ -85,7 +85,12 @@ ; (must "# Add project-specific invariants here") (enforcement + ; Declarative form (estate standard; run by the Nickel k9 `contractile` + ; runner once its _base.ncl / template-hunt.k9.ncl bases are wired here): (k9-validator "contractiles/k9/must-check.k9.ncl") + ; Portable enforcer active today (bash + coreutils, no k9 runner needed) — + ; checks the mechanically-verifiable MUST invariants: + (runnable-validator ".machine_readable/contractiles/k9/must-check.sh") (ci "quality.yml runs must-check on every PR") ) ) diff --git a/.machine_readable/contractiles/k9/must-check.sh b/.machine_readable/contractiles/k9/must-check.sh new file mode 100755 index 0000000..c3ca874 --- /dev/null +++ b/.machine_readable/contractiles/k9/must-check.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# must-check — portable, runnable enforcer for MUST.contractile invariants. +# +# MUST.contractile [enforcement] promises "quality.yml runs must-check on every +# PR". The estate's declarative form is a Nickel k9 validator +# (contractiles/k9/must-check.k9.ncl) executed by the k9 `contractile` runner; +# that runner (and its _base.ncl / template-hunt.k9.ncl bases) is not yet wired +# into this repo, so this script is the portable enforcer that runs today with +# nothing but bash + coreutils. It checks the mechanically-verifiable MUST +# invariants; it never mutates. +set -uo pipefail +cd "$(dirname "$0")/../../.." || exit 2 + +fail=0 +err() { echo "::error::MUST violation: $*"; fail=1; } + +# --- License / structure --- +[ -f LICENSE ] || err "LICENSE file missing" +grep -q 'Mozilla Public License\|MPL-2.0' LICENSE || err "LICENSE is not MPL-2.0" +[ -f 0-AI-MANIFEST.a2ml ] || err "0-AI-MANIFEST.a2ml missing" +[ -d .machine_readable ] || err ".machine_readable/ directory missing" + +# --- No SCM state files loose in repo root --- +for f in STATE.a2ml META.a2ml ECOSYSTEM.a2ml AGENTIC.a2ml NEUROSYM.a2ml PLAYBOOK.a2ml; do + [ -f "$f" ] && err "SCM file $f in repo root (must live under .machine_readable/)" +done + +# --- All GitHub Actions SHA-pinned (no @vN / @branch) --- +if grep -rnE "uses:[[:space:]]*[^#]*@v[0-9]" .github/workflows/*.yml 2>/dev/null | grep -vE "^\s*#" ; then + err "unpinned GitHub Action(s) — pin to a full 40-char commit SHA" +fi + +# --- No proof escape hatches in proof/source trees --- +if grep -rnE "\b(believe_me|assert_total|unsafeCoerce|Obj\.magic)\b|^[[:space:]]*(sorry|Admitted)\b" \ + --include=*.idr --include=*.idr2 --include=*.lean --include=*.v \ + --include=*.hs --include=*.ml proofs crates 2>/dev/null ; then + err "proof escape hatch present (believe_me/assert_total/sorry/Admitted/unsafeCoerce/Obj.magic)" +fi + +# --- No new banned-language source (TypeScript / Python / Go) --- +banned=$(find . -path ./target -prune -o \ + \( -name "*.ts" -o -name "*.py" -o -name "*.go" \) -print 2>/dev/null \ + | grep -vE "\.d\.ts$|/target/|/node_modules/") +if [ -n "$banned" ]; then + echo "$banned" + err "banned-language source present (TypeScript/Python/Go)" +fi + +# --- No hardcoded absolute home/mnt paths in source --- +if grep -rnE "(/home/[a-z]|/mnt/|/var/mnt/)" \ + --include=*.rs --include=*.sh --include=*.toml crates .github 2>/dev/null ; then + err "hardcoded absolute path (/home|/mnt|/var/mnt) in source" +fi + +# --- SPDX header on every Rust source file --- +missing_spdx="" +while IFS= read -r f; do + head -3 "$f" | grep -q "SPDX-License-Identifier" || missing_spdx="$missing_spdx $f" +done < <(find crates -name "*.rs" -not -path "*/target/*" 2>/dev/null) +[ -n "$missing_spdx" ] && err "Rust source missing SPDX header:$missing_spdx" + +if [ "$fail" = "0" ]; then + echo "must-check: all mechanically-verifiable MUST invariants satisfied." +fi +exit $fail diff --git a/crates/claude-client/src/lib.rs b/crates/claude-client/src/lib.rs index 1622361..5beedac 100644 --- a/crates/claude-client/src/lib.rs +++ b/crates/claude-client/src/lib.rs @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MPL-2.0 //! Claude API Client - Cloud Connection //! //! Connects to Claude (Anthropic's AI) for advanced reasoning diff --git a/crates/lsm/src/lib.rs b/crates/lsm/src/lib.rs index ba3ec35..967b90b 100644 --- a/crates/lsm/src/lib.rs +++ b/crates/lsm/src/lib.rs @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MPL-2.0 //! Liquid State Machine (LSM) - Spiking Neural Network Reservoir //! //! Implements a biologically-inspired spiking neural network using