docs(agent-memory): spec L0-L3 tiered memory as a Claude Code hook layer #1193
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: CI Quality Gate | |
| 'on': | |
| pull_request: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| description: Branch to run quality gate against | |
| required: false | |
| repository_dispatch: | |
| types: [ci-quality] | |
| concurrency: | |
| group: quality-gate-${{ github.event.pull_request.number || github.run_id }} | |
| cancel-in-progress: true | |
| jobs: | |
| quality: | |
| name: Lint, Tests, Docs, Security | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| timeout-minutes: 25 | |
| steps: | |
| - name: Resolve ref | |
| id: ref | |
| run: | | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.ref }}" ]]; then | |
| echo "target_ref=${{ github.event.inputs.ref }}" >> "$GITHUB_OUTPUT" | |
| elif [[ "${{ github.event_name }}" == "repository_dispatch" && -n "${{ github.event.client_payload.ref }}" ]]; then | |
| echo "target_ref=${{ github.event.client_payload.ref }}" >> "$GITHUB_OUTPUT" | |
| elif [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| # Use commit SHA for PRs — branch names from forks don't exist in the base repo | |
| echo "target_ref=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "target_ref=${{ github.head_ref || github.ref_name }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ steps.ref.outputs.target_ref }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install tooling | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install yamllint==1.35.1 check-jsonschema==0.28.4 safety==3.2.4 | |
| pip install -r requirements-dev.txt | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: YAML lint (.github/workflows) | |
| run: | | |
| # yamllint cannot properly parse JavaScript template literals in YAML | |
| # Skip pr-issue-auto-close.yml which contains complex template strings | |
| find .github/workflows -name "*.yml" ! -name "pr-issue-auto-close.yml" -exec yamllint -d '{extends: default, rules: {line-length: {max: 160}}}' {} + | |
| - name: Validate GitHub workflow schemas | |
| run: | | |
| # Exclude pr-issue-auto-close.yml (complex JS template literals cause parsing errors) | |
| # Exclude smart-sync.yml (uses projects_v2_item event not yet in official schema) | |
| find .github/workflows -name "*.yml" \ | |
| ! -name "pr-issue-auto-close.yml" \ | |
| ! -name "smart-sync.yml" \ | |
| -exec check-jsonschema --builtin-schema github-workflows {} + || true | |
| - name: Python syntax check (blocking) | |
| run: | | |
| # Covers every top-level skill domain + scripts/. When adding a new | |
| # domain folder, add it here (audit gate G9: this list previously | |
| # skipped 8 post-v2.7 domains). | |
| python -m compileall \ | |
| marketing-skill product-team c-level-advisor \ | |
| engineering-team ra-qm-team engineering \ | |
| business-growth finance project-management \ | |
| productivity marketing research \ | |
| business-operations commercial research-ops \ | |
| compliance-os markdown-html scripts | |
| - name: Validate plugin.json manifests (blocking — guards #539 + #686) | |
| run: | | |
| python scripts/check_plugin_json.py --all | |
| # ---- Audit guardrails (newgen-2026-06 gates) ---------------------- | |
| # BLOCKING since PR-2 (flipped ahead of the 2026-07-01 SLA — every | |
| # advisory run was green through PR #835). If a gate misfires on a | |
| # legitimate edge case, extend its in-repo allowlist | |
| # (scripts/check_paths_allowlist.txt, scripts/smoke_exceptions.txt) | |
| # rather than re-adding continue-on-error. | |
| - name: Path-existence linter (gate G1 — blocking) | |
| run: | | |
| python3 scripts/check_paths.py --all | |
| - name: Dual-publish drift guard (gate G4 — blocking) | |
| run: | | |
| python3 scripts/check_dual_publish.py | |
| - name: Script --help smoke gate (gate G8 — blocking) | |
| run: | | |
| python3 scripts/smoke_scripts.py | |
| - name: JSON-output sample gate (gate G9 — advisory) | |
| continue-on-error: true | |
| run: | | |
| python3 scripts/smoke_json_output.py | |
| - name: Counter derivation check (gate G3 — blocking) | |
| run: | | |
| python3 scripts/derive_counters.py --check | |
| - name: Safety dependency audit (requirements*.txt) | |
| run: | | |
| set -e | |
| files=$(find . -name "requirements*.txt" 2>/dev/null || true) | |
| if [[ -z "$files" ]]; then | |
| echo "No requirements files found; skipping safety scan." | |
| exit 0 | |
| fi | |
| for f in $files; do | |
| echo "Auditing $f" | |
| if ! safety check --full-report --file "$f"; then | |
| echo "::warning file=$f::safety found vulnerabilities in $f (advisory)" | |
| fi | |
| done | |
| - name: Markdown link spot-check | |
| run: | | |
| # Non-blocking: external links (claude.ai) may timeout, anchor links can't be validated | |
| npx --yes markdown-link-check@3.12.2 README.md || true | |
| - name: Summarize results | |
| if: always() | |
| run: | | |
| echo "Quality gate completed with status: ${{ job.status }}" |