From 6a34130ae8c4fbf17578acc359501d00263a1f0f Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:09 -0400 Subject: [PATCH 01/41] ci: run ops/validate-starters.sh on every PR --- .github/workflows/validate-starters.yml | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/validate-starters.yml diff --git a/.github/workflows/validate-starters.yml b/.github/workflows/validate-starters.yml new file mode 100644 index 0000000..13dc0bb --- /dev/null +++ b/.github/workflows/validate-starters.yml @@ -0,0 +1,30 @@ +name: Validate starters and l9-ci-pack + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: validate-starters-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: validate-starters.sh + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Run ops/validate-starters.sh + run: | + chmod +x ops/validate-starters.sh + ops/validate-starters.sh From fdab7740101950f006529309c95ff368e8a3c915 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:10 -0400 Subject: [PATCH 02/41] feat(l9-ci-pack): agent-first instantiation README (v2) --- l9-ci-pack/README.md | 105 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 l9-ci-pack/README.md diff --git a/l9-ci-pack/README.md b/l9-ci-pack/README.md new file mode 100644 index 0000000..270f1cf --- /dev/null +++ b/l9-ci-pack/README.md @@ -0,0 +1,105 @@ +# L9 CI instantiation pack (v2) + +Everything a consumer repo — human or agent — needs to fully instantiate +`l9-ci-core` **v2**, without browsing the `l9-ci-core` repo itself. Source of +truth for these files is `Quantum-L9/l9-ci-core/docs/templates/`; this pack is +the synced org distribution copy (see `ops/sync-v2-starters.sh`). + +> **Canonical "how Core works / how to plug in" doc:** +> [`Quantum-L9/l9-ci-core/AGENTS.md`](https://github.com/Quantum-L9/l9-ci-core/blob/main/AGENTS.md). +> Read this README for the copy-paste path; read `AGENTS.md` when you need +> ownership rules, ordering guarantees, or pinning rationale. + +## 1. What "fully active Core" means + +- **Governance + analysis** (`governance/*.yaml` + `workflows/l9-analysis.yml`) + is the part that **publishes GitHub checks** — this is the L9 finding + pipeline (semgrep → SDK normalize/validate → publish). +- **Lint templates** (`workflows/l9-lint-test.yml` / + `workflows/l9-lint-test-node.yml`) are **optional hygiene** — generic + dev-tool CI (ruff/mypy/pytest or eslint/tsc/vitest). Core does not call or + gate on these; you own them outright. + +## 2. Prerequisites + +- Pin Core at **`f88116503430aa18992b70d8d31063e34ff97ef1`** (the current + verified candidate; will become `@v2.0.0` once released). **Never `@main`.** +- **Never** copy the legacy `@v1` kernel starters for new work — see §9. + +## 3. Universal steps (both languages) + +1. Copy `governance/*.yaml` (all six files) → your repo's + `.github/governance/`. + ⚠️ **Format gotcha:** these are JSON-in-`.yaml` — the resolver parses them + with `json.loads`. Double-quoted keys, no comments, no trailing commas. +2. Copy `workflows/l9-analysis.yml` → `.github/workflows/l9-analysis.yml`. +3. Set the semgrep `--config` ruleset for your language inside that file + (§4/§5 below). +4. Grant `checks: write` **only** on the job that calls Core's + `publish-analysis.yml` (already scoped that way in the template — do not + widen it). + +## 4. Python path + +1. Do §3 above with `--config p/python`. +2. Copy `workflows/l9-lint-test.yml` → `.github/workflows/l9-lint-test.yml`. +3. Tune the `env:` block: `PYTHON_VERSION`, `SOURCE_DIR`, `TEST_DIR`, + `COVERAGE_THRESHOLD`. + +## 5. Node / TypeScript path + +1. Do §3 above with `--config p/javascript --config p/typescript`. +2. Copy `workflows/l9-lint-test-node.yml` → + `.github/workflows/l9-lint-test-node.yml`. +3. Tune package manager / scripts — auto-detected from your lockfile + (npm / pnpm / yarn). Keep `tsconfig.json` / `.eslintrc*` / + `vitest.config.ts` as your source of truth; the template invokes your + tools, it does not replace your configs. + +## 6. Profile matrix + +| Profile | Event | sdk_profile | Default mode | semgrep required | +|---|---|---|---|---| +| `pr_fast` | `pull_request` | ci_fast | blocking | yes | +| `merge` | `push` | ci_fast | blocking | yes | +| `nightly` | `schedule` | ci_deep | advisory | no | +| `release` | `push` | ci_deep | blocking | yes | +| `supply_chain` | `schedule` | ci_deep | blocking | yes | + +## 7. Rollout: shadow → advisory → blocking + +Start a new provider or a stricter policy in `shadow` (runs, artifacts +retained as promotion evidence, **no** GitHub check), then promote per +`governance/promotion-policy.yaml`: `disabled → shadow → advisory → +blocking`. Change the mode in `governance/rule-modes.yaml` (`defaults` or a +`provider_overrides` entry). + +## 8. Verification checklist + +- [ ] `l9-analysis.yml` run resolves governance without error. +- [ ] Analysis artifact set uploaded (`raw/`, `l9/`, `metadata/`). +- [ ] GitHub check published for `blocking`/`advisory` modes, **or** shadow + evidence retained for `shadow` mode. +- [ ] Lint/test template green, if adopted. + +## 9. Do not use for new work + +The org's existing `@v1` kernel starters (`workflow-templates/l9-pr-pipeline.yml`, +`l9-security.yml`, `l9-scorecard.yml`, `l9-sbom.yml`, `l9-pre-commit.yml`, +`l9-nightly.yml`, `l9-release.yml`, `l9-governance.yml`, +`l9-node-ts-monorepo.yml`) are **Legacy (frozen `@v1`)** — kept only so +already-imported wrappers keep resolving against the historical `l9-ci-core` +kernels. New work always starts here, from `l9-ci-pack/`. + +Scorecard / SBOM / Gitleaks / pre-commit / a dedicated nightly-release kernel +have **no v2 `workflow_call` equivalent** — the v2 SDK does not implement +those providers yet. Do not re-add them as Core reusable workflows without an +explicit, authorized scope change (see `l9-ci-core/AGENTS.md` §1, "frozen +seven"). + +## 10. Dormant SDK capability (documented, not wired) + +`gate evaluate`, `providers list/detect`, and `semgrep detect` exist in the +pinned SDK but are **not** wired into Core's `invoke-sdk` allowlist yet — see +`l9-ci-core/AGENTS.md` §7 for the full list and rationale. Do not depend on +them from a consumer workflow. From b7844c44624136a2373dfe3e481ba8cea7493868 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:11 -0400 Subject: [PATCH 03/41] feat(l9-ci-pack): sync governance/execution-profiles.yaml from l9-ci-core docs/templates --- l9-ci-pack/governance/execution-profiles.yaml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 l9-ci-pack/governance/execution-profiles.yaml diff --git a/l9-ci-pack/governance/execution-profiles.yaml b/l9-ci-pack/governance/execution-profiles.yaml new file mode 100644 index 0000000..2d58873 --- /dev/null +++ b/l9-ci-pack/governance/execution-profiles.yaml @@ -0,0 +1,45 @@ +{ + "schema": "l9.execution-profiles/v1", + "profiles": { + "pr_fast": { + "sdk_profile": "ci_fast", + "strict": true, + "default_mode": "blocking", + "providers": ["semgrep"], + "policy": "", + "allowed_events": ["pull_request", "workflow_dispatch"] + }, + "merge": { + "sdk_profile": "ci_fast", + "strict": true, + "default_mode": "blocking", + "providers": ["semgrep"], + "policy": "", + "allowed_events": ["push", "workflow_dispatch"] + }, + "nightly": { + "sdk_profile": "ci_deep", + "strict": true, + "default_mode": "advisory", + "providers": ["semgrep"], + "policy": "", + "allowed_events": ["schedule", "workflow_dispatch"] + }, + "release": { + "sdk_profile": "ci_deep", + "strict": true, + "default_mode": "blocking", + "providers": ["semgrep"], + "policy": "", + "allowed_events": ["push", "workflow_dispatch"] + }, + "supply_chain": { + "sdk_profile": "ci_deep", + "strict": true, + "default_mode": "blocking", + "providers": ["semgrep"], + "policy": "", + "allowed_events": ["schedule", "workflow_dispatch"] + } + } +} From 4812f174954d87cee72ca9ea174d5a1b2781dafc Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:12 -0400 Subject: [PATCH 04/41] feat(l9-ci-pack): sync governance/provider-requiredness.yaml from l9-ci-core docs/templates --- .../governance/provider-requiredness.yaml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 l9-ci-pack/governance/provider-requiredness.yaml diff --git a/l9-ci-pack/governance/provider-requiredness.yaml b/l9-ci-pack/governance/provider-requiredness.yaml new file mode 100644 index 0000000..a8194e4 --- /dev/null +++ b/l9-ci-pack/governance/provider-requiredness.yaml @@ -0,0 +1,20 @@ +{ + "schema": "l9.provider-requiredness/v1", + "profiles": { + "pr_fast": { + "semgrep": true + }, + "merge": { + "semgrep": true + }, + "nightly": { + "semgrep": false + }, + "release": { + "semgrep": true + }, + "supply_chain": { + "semgrep": true + } + } +} From 9f24d9d016614ab97068d3abc7ddffa7ff0ededa Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:13 -0400 Subject: [PATCH 05/41] feat(l9-ci-pack): sync governance/rule-modes.yaml from l9-ci-core docs/templates --- l9-ci-pack/governance/rule-modes.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 l9-ci-pack/governance/rule-modes.yaml diff --git a/l9-ci-pack/governance/rule-modes.yaml b/l9-ci-pack/governance/rule-modes.yaml new file mode 100644 index 0000000..443e424 --- /dev/null +++ b/l9-ci-pack/governance/rule-modes.yaml @@ -0,0 +1,19 @@ +{ + "schema": "l9.rule-modes/v1", + "defaults": { + "pr_fast": "blocking", + "merge": "blocking", + "nightly": "advisory", + "release": "blocking", + "supply_chain": "blocking" + }, + "provider_overrides": { + "semgrep": {} + }, + "allowed_modes": [ + "blocking", + "advisory", + "shadow", + "disabled" + ] +} From 96da0587e5f92ff57d80f06f1ce04c5657350f27 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:14 -0400 Subject: [PATCH 06/41] feat(l9-ci-pack): sync governance/waivers.yaml from l9-ci-core docs/templates --- l9-ci-pack/governance/waivers.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 l9-ci-pack/governance/waivers.yaml diff --git a/l9-ci-pack/governance/waivers.yaml b/l9-ci-pack/governance/waivers.yaml new file mode 100644 index 0000000..dce98fa --- /dev/null +++ b/l9-ci-pack/governance/waivers.yaml @@ -0,0 +1,4 @@ +{ + "schema": "l9.waivers/v1", + "waivers": [] +} From 23afb6bf73d30e5fe0c5bbfc2226cc3c5dfa8445 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:15 -0400 Subject: [PATCH 07/41] feat(l9-ci-pack): sync governance/promotion-policy.yaml from l9-ci-core docs/templates --- l9-ci-pack/governance/promotion-policy.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 l9-ci-pack/governance/promotion-policy.yaml diff --git a/l9-ci-pack/governance/promotion-policy.yaml b/l9-ci-pack/governance/promotion-policy.yaml new file mode 100644 index 0000000..69b5470 --- /dev/null +++ b/l9-ci-pack/governance/promotion-policy.yaml @@ -0,0 +1,16 @@ +{ + "schema": "l9.promotion-policy/v1", + "transitions": { + "disabled": ["shadow"], + "shadow": ["advisory", "disabled"], + "advisory": ["blocking", "shadow"], + "blocking": ["advisory"] + }, + "requirements": { + "minimum_observation_runs": 20, + "minimum_observation_days": 7, + "maximum_contract_failures": 0, + "maximum_artifact_validation_failures": 0, + "approval_required": true + } +} From 2fd7feddc8a307b8cfbd95068aaeadca4b1cb1a5 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:16 -0400 Subject: [PATCH 08/41] feat(l9-ci-pack): sync governance/quality-thresholds.yaml from l9-ci-core docs/templates --- l9-ci-pack/governance/quality-thresholds.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 l9-ci-pack/governance/quality-thresholds.yaml diff --git a/l9-ci-pack/governance/quality-thresholds.yaml b/l9-ci-pack/governance/quality-thresholds.yaml new file mode 100644 index 0000000..d33cbd6 --- /dev/null +++ b/l9-ci-pack/governance/quality-thresholds.yaml @@ -0,0 +1,21 @@ +{ + "schema": "l9.quality-threshold-selection/v1", + "profiles": { + "pr_fast": { + "sdk_policy": "" + }, + "merge": { + "sdk_policy": "" + }, + "nightly": { + "sdk_policy": "" + }, + "release": { + "sdk_policy": "" + }, + "supply_chain": { + "sdk_policy": "" + } + }, + "note": "Core selects an SDK policy file but never evaluates finding thresholds itself. Point sdk_policy at a policy file the pinned SDK understands to raise/lower gates." +} From 53c70f2523ea609c4b31a4dd6954a5becf968daa Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:17 -0400 Subject: [PATCH 09/41] feat(l9-ci-pack): sync workflows/l9-analysis.yml from l9-ci-core docs/templates --- l9-ci-pack/workflows/l9-analysis.yml | 197 +++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 l9-ci-pack/workflows/l9-analysis.yml diff --git a/l9-ci-pack/workflows/l9-analysis.yml b/l9-ci-pack/workflows/l9-analysis.yml new file mode 100644 index 0000000..230ebf4 --- /dev/null +++ b/l9-ci-pack/workflows/l9-analysis.yml @@ -0,0 +1,197 @@ +# L9 analysis caller (TEMPLATE — copy into your repo at .github/workflows/l9-analysis.yml) +# +# Works for Python AND Node.js repos: semgrep is the single, language-agnostic +# provider the pinned SDK normalizes. The ONLY per-language difference is the +# semgrep --config rulesets in the "Run semgrep" step below. +# +# Topology (this is the wiring that actually works): +# job analyze -> generates the semgrep report and runs the SDK pipeline in ONE +# job so the freshly-generated report is on the same filesystem +# (the reusable normalize workflow re-checks-out github.sha and +# would NOT see an uncommitted report). +# job publish -> calls Core's publish-analysis.yml, which DOWNLOADS the +# uploaded artifact (no report-in-tree needed) and publishes the +# GitHub check per the resolved governance mode. +# +# Prerequisite: copy docs/templates/governance/*.yaml into THIS repo at +# .github/governance/ (that is the CI instantiation pack the resolver reads). + +name: L9 Analysis + +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: l9-analysis-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + # Pin Core to the immutable release commit (or replace with the v2 tag). + L9_CORE_REF: "f88116503430aa18992b70d8d31063e34ff97ef1" + # Match the event: pr_fast for pull_request, merge for push, nightly/release/ + # supply_chain as appropriate. Must be allowed_events in execution-profiles.yaml. + L9_PROFILE: "pr_fast" + L9_MATRIX_ID: "pr-semgrep" + +jobs: + analyze: + name: Analyze (semgrep -> SDK) + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + outputs: + mode: ${{ steps.gov.outputs.mode }} + enabled: ${{ steps.gov.outputs.enabled }} + artifact-name: ${{ steps.names.outputs.artifact-name }} + governance-digest: ${{ steps.gov.outputs.governance-digest }} + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + + - id: gov + name: Resolve governance (Core) + uses: Quantum-L9/l9-ci-core/.github/actions/resolve-governance@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + profile: ${{ env.L9_PROFILE }} + provider: semgrep + event-name: ${{ github.event_name }} + repository: ${{ github.repository }} + ref: ${{ github.ref }} + governance-root: .github/governance + + - id: names + name: Resolve artifact name + env: + MATRIX_ID: ${{ env.L9_MATRIX_ID }} + run: | + set -euo pipefail + echo "artifact-name=l9-semgrep-${MATRIX_ID}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_OUTPUT" + + - name: Run semgrep (produce raw report) + if: steps.gov.outputs.enabled == 'true' + run: | + set -euo pipefail + python -m pip install --upgrade pip semgrep + mkdir -p "artifacts/raw/semgrep/${L9_MATRIX_ID}" + # ── PER-LANGUAGE RULESETS ────────────────────────────────────────── + # Python repo: --config p/python + # Node.js repo: --config p/javascript --config p/typescript + # Polyglot / either: keep all three (semgrep skips rules that do not + # match any files) or use --config auto. + semgrep scan \ + --config p/python \ + --config p/javascript \ + --config p/typescript \ + --json \ + --output "artifacts/raw/semgrep/${L9_MATRIX_ID}/report.json" \ + --error --quiet || true + env: + L9_MATRIX_ID: ${{ env.L9_MATRIX_ID }} + + - id: sdk + name: Provision immutable SDK + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/provision-sdk@f88116503430aa18992b70d8d31063e34ff97ef1 + + - name: Normalize provider report + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/invoke-sdk@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + executable: ${{ steps.sdk.outputs.executable }} + operation: semgrep-normalize + input: artifacts/raw/semgrep/${{ env.L9_MATRIX_ID }}/report.json + output: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + root: . + snapshot-id: ${{ github.sha }} + revision: ${{ github.sha }} + strict: ${{ steps.gov.outputs.strict }} + required: ${{ steps.gov.outputs.required-provider }} + policy: ${{ steps.gov.outputs.sdk-policy }} + + - name: Validate canonical bundle + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/validate-bundle@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + executable: ${{ steps.sdk.outputs.executable }} + bundle: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + + - name: Project agent-review payload + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/invoke-sdk@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + executable: ${{ steps.sdk.outputs.executable }} + operation: bundle-project-agent-payload + input: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + output: .l9/runtime/${{ env.L9_MATRIX_ID }}/agent-review-payload.json + strict: ${{ steps.gov.outputs.strict }} + + - id: route + name: Route artifacts + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/route-artifacts@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + provider: semgrep + matrix-id: ${{ env.L9_MATRIX_ID }} + raw-report: artifacts/raw/semgrep/${{ env.L9_MATRIX_ID }}/report.json + bundle: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + agent-payload: .l9/runtime/${{ env.L9_MATRIX_ID }}/agent-review-payload.json + destination-root: artifacts + + - name: Build artifact manifest + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/build-artifact-manifest@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + provider: semgrep + matrix-id: ${{ env.L9_MATRIX_ID }} + sdk-revision: ${{ steps.sdk.outputs.sdk-revision }} + bundle: ${{ steps.route.outputs.bundle }} + agent-payload: ${{ steps.route.outputs.agent-payload }} + raw-directory: ${{ steps.route.outputs.raw-directory }} + output: artifacts/metadata/${{ env.L9_MATRIX_ID }}/artifact-manifest.json + + - name: Upload analysis artifact set + if: steps.gov.outputs.enabled == 'true' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: ${{ steps.names.outputs.artifact-name }} + path: | + artifacts/raw/semgrep/${{ env.L9_MATRIX_ID }}/ + artifacts/l9/${{ env.L9_MATRIX_ID }}/ + artifacts/metadata/${{ env.L9_MATRIX_ID }}/ + if-no-files-found: error + retention-days: 14 + + publish: + name: Publish analysis (Core) + needs: analyze + if: needs.analyze.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/workflows/publish-analysis.yml@f88116503430aa18992b70d8d31063e34ff97ef1 + permissions: + actions: read + checks: write + contents: read + with: + artifact-name: ${{ needs.analyze.outputs.artifact-name }} + profile: pr_fast + mode: ${{ needs.analyze.outputs.mode }} + provider: semgrep + matrix-id: pr-semgrep + governance-digest: ${{ needs.analyze.outputs.governance-digest }} + repository-revision: ${{ github.sha }} + workflow-result: ${{ needs.analyze.result }} From c22e64d771b37f8ba94a7956e7b61998a5360c1d Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:18 -0400 Subject: [PATCH 10/41] feat(l9-ci-pack): sync workflows/l9-lint-test.yml from l9-ci-core docs/templates --- l9-ci-pack/workflows/l9-lint-test.yml | 126 ++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 l9-ci-pack/workflows/l9-lint-test.yml diff --git a/l9-ci-pack/workflows/l9-lint-test.yml b/l9-ci-pack/workflows/l9-lint-test.yml new file mode 100644 index 0000000..912957a --- /dev/null +++ b/l9-ci-pack/workflows/l9-lint-test.yml @@ -0,0 +1,126 @@ +# L9 consumer lint + test workflow (TEMPLATE — copy into your repo) +# +# This file is NOT executed from l9-ci-core. Copy it into the CONSUMER +# repository at `.github/workflows/l9-lint-test.yml`. It replaces the +# lint / type-check / test half of the retired v1 `pr-pipeline.yml`. +# +# It deliberately lives consumer-side: l9-ci-core v2 is a thin control plane +# whose workflow set is fixed by `tests/workflows/test_phase_scope.py`. Generic +# ruff / mypy / pytest hygiene is owned by the consuming repository, not Core. +# +# v2 conventions preserved here: +# - immutable event-revision checkout (no floating action ref) +# - external actions pinned to full commit SHAs +# - explicit least-privilege permissions (contents: read, no write scopes) +name: L9 Lint and Test + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +# ── Consumer config: edit these values for your repo ─────────────────────────── +env: + PYTHON_VERSION: "3.12" + SOURCE_DIR: "." + TEST_DIR: "tests/" + # Fail the build below this line coverage percentage. 0 = advisory (no gate). + COVERAGE_THRESHOLD: "0" + +permissions: + contents: read + +concurrency: + group: l9-lint-test-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint and Type Check + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Set up Python + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install lint tools + run: | + set -euo pipefail + python -m pip install --upgrade pip + if [ -f requirements-ci.txt ]; then pip install -r requirements-ci.txt; fi + command -v ruff >/dev/null 2>&1 || pip install ruff + command -v mypy >/dev/null 2>&1 || pip install mypy + - name: ruff check + run: ruff check . --output-format=github + - name: ruff format --check + run: ruff format --check . + - name: mypy + run: | + mypy "${SOURCE_DIR}" \ + --show-error-codes --pretty \ + --install-types --non-interactive --ignore-missing-imports + + test: + name: Test Suite + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Set up Python + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install test tools + run: | + set -euo pipefail + python -m pip install --upgrade pip + if [ -f requirements-ci.txt ]; then pip install -r requirements-ci.txt; fi + pip install -e ".[dev]" || pip install -e . || \ + echo "::notice::no local editable package to install" + command -v pytest >/dev/null 2>&1 || pip install pytest + python -c "import pytest_cov" 2>/dev/null || pip install pytest-cov + python -c "import xdist" 2>/dev/null || pip install pytest-xdist + python -c "import pytest_timeout" 2>/dev/null || pip install pytest-timeout + - name: pytest with coverage + env: + TESTING: "true" + run: | + set -euo pipefail + PYTHONPATH=. pytest "${TEST_DIR}" \ + -n auto \ + --cov="${SOURCE_DIR}" \ + --cov-report=xml --cov-report=term-missing \ + --cov-fail-under="${COVERAGE_THRESHOLD}" \ + --timeout=300 --tb=short -v From be230f818b7cd15acb9fc9209b18b8f75a8345e1 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:19 -0400 Subject: [PATCH 11/41] feat(l9-ci-pack): sync workflows/l9-lint-test-node.yml from l9-ci-core docs/templates --- l9-ci-pack/workflows/l9-lint-test-node.yml | 156 +++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 l9-ci-pack/workflows/l9-lint-test-node.yml diff --git a/l9-ci-pack/workflows/l9-lint-test-node.yml b/l9-ci-pack/workflows/l9-lint-test-node.yml new file mode 100644 index 0000000..0bf4db2 --- /dev/null +++ b/l9-ci-pack/workflows/l9-lint-test-node.yml @@ -0,0 +1,156 @@ +# L9 consumer lint + test workflow for Node.js / TypeScript (TEMPLATE) +# +# Copy into the CONSUMER repo at `.github/workflows/l9-lint-test-node.yml`. +# Node counterpart to l9-lint-test.yml (Python). Provides the TypeScript/Node +# hygiene half that v1's pr-pipeline never covered. +# +# Three independent gates (each surfaces as its own required check): +# lint -> eslint . lint / style / correctness (your eslint config) +# typecheck -> tsc --noEmit type-check the whole tree against the type +# system (honors tsconfig, e.g. strict: true). +# NO compiled output; it proves the types are +# sound, it does not run the code. +# test -> vitest run one-shot, non-interactive run of *.test.ts. +# `run` is mandatory in CI — bare `vitest` is +# watch mode and would hang the job forever. +# +# v2 conventions: immutable event-revision checkout, contents: read only (no +# write scopes). Node comes preinstalled on ubuntu-latest; see the optional +# setup-node block to pin a specific version. Package manager auto-detected +# from the lockfile (npm / pnpm / yarn). +name: L9 Lint and Test (Node) + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: l9-lint-test-node-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# ── Reusable anchors kept inline per job (templates must stay copy-paste-able). +# Each job: immutable checkout -> install deps -> run one gate. + +jobs: + lint: + name: ESLint + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + # OPTIONAL — pin Node. ubuntu-latest ships Node 20+, used as-is. To pin, + # uncomment and set a full 40-char SHA you trust for actions/setup-node: + # - uses: actions/setup-node@ # v4.x + # with: + # node-version-file: package.json # or .nvmrc, or node-version: "20" + - name: Install dependencies + run: | + set -euo pipefail + corepack enable || true + if [ -f pnpm-lock.yaml ]; then + corepack prepare pnpm@latest --activate && pnpm install --frozen-lockfile + elif [ -f yarn.lock ]; then + corepack prepare yarn@stable --activate && yarn install --immutable + elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then + npm ci + else + npm install + fi + - name: ESLint + run: npx --no-install eslint . || npx eslint . + + typecheck: + name: tsc --noEmit + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Install dependencies + run: | + set -euo pipefail + corepack enable || true + if [ -f pnpm-lock.yaml ]; then + corepack prepare pnpm@latest --activate && pnpm install --frozen-lockfile + elif [ -f yarn.lock ]; then + corepack prepare yarn@stable --activate && yarn install --immutable + elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then + npm ci + else + npm install + fi + - name: Type-check (tsc --noEmit) + run: npx --no-install tsc --noEmit || npx tsc --noEmit + + test: + name: Vitest + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Install dependencies + run: | + set -euo pipefail + corepack enable || true + if [ -f pnpm-lock.yaml ]; then + corepack prepare pnpm@latest --activate && pnpm install --frozen-lockfile + elif [ -f yarn.lock ]; then + corepack prepare yarn@stable --activate && yarn install --immutable + elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then + npm ci + else + npm install + fi + - name: Vitest (one-shot, non-interactive) + env: + CI: "true" + run: npx --no-install vitest run || npx vitest run + # For coverage, install @vitest/coverage-v8 and use: + # npx vitest run --coverage From 1e6476a73b54fdbb9bc202e038e79a5bb54d1530 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:20 -0400 Subject: [PATCH 12/41] feat(ops): add sync-v2-starters.sh to sync l9-ci-pack from Core --- ops/sync-v2-starters.sh | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 ops/sync-v2-starters.sh diff --git a/ops/sync-v2-starters.sh b/ops/sync-v2-starters.sh new file mode 100644 index 0000000..6860321 --- /dev/null +++ b/ops/sync-v2-starters.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# ops/sync-v2-starters.sh +# Syncs the v2 CI instantiation surface from Quantum-L9/l9-ci-core's +# docs/templates/ into this repo's l9-ci-pack/, then rewrites every Core pin +# in l9-ci-pack/ + workflow-templates/l9-v2-*.yml to the given ref. +# +# Usage: +# ops/sync-v2-starters.sh +# +# Full 40-char commit SHA (pre-release candidate) or a Core +# release tag (e.g. v2.0.0) once cut. Never `main`. +# +# Run from the root of the Quantum-L9/.github repo, with a clean working tree. +set -euo pipefail + +CORE_REPO="Quantum-L9/l9-ci-core" +CORE_REF="${1:-}" +PACK_DIR="l9-ci-pack" + +if [[ -z "$CORE_REF" ]]; then + echo "❌ ERROR: usage: $0 " >&2 + echo " must be a full 40-char commit SHA or a release tag (e.g. v2.0.0)." >&2 + exit 1 +fi + +if [[ "$CORE_REF" == "main" ]]; then + echo "❌ ERROR: refusing to sync against a floating ref (main)." >&2 + exit 1 +fi + +if [[ -n "$(git status --porcelain)" ]]; then + echo "❌ ERROR: working tree is not clean. Commit or stash changes first." >&2 + git status --short + exit 1 +fi + +WORKDIR="$(mktemp -d)" +trap 'rm -rf "$WORKDIR"' EXIT + +echo "=== Syncing l9-ci-pack from ${CORE_REPO}@${CORE_REF} ===" + +echo "Fetching docs/templates/ from ${CORE_REPO}@${CORE_REF}..." +git clone --quiet --no-checkout "https://github.com/${CORE_REPO}.git" "$WORKDIR/core" +git -C "$WORKDIR/core" fetch --quiet --depth=1 origin "$CORE_REF" +git -C "$WORKDIR/core" checkout --quiet FETCH_HEAD -- docs/templates + +mkdir -p "$PACK_DIR/governance" "$PACK_DIR/workflows" + +for f in execution-profiles provider-requiredness rule-modes waivers promotion-policy quality-thresholds; do + cp "$WORKDIR/core/docs/templates/governance/${f}.yaml" "$PACK_DIR/governance/${f}.yaml" +done + +for f in l9-analysis l9-lint-test l9-lint-test-node; do + cp "$WORKDIR/core/docs/templates/${f}.yml" "$PACK_DIR/workflows/${f}.yml" +done + +echo "Rewriting Core pins to @${CORE_REF} in ${PACK_DIR}/ and workflow-templates/l9-v2-*.yml..." +# Matches full-40-char-SHA pins on Quantum-L9/l9-ci-core refs only — never +# touches @v1 legacy starter pins (different repo path pattern is not present +# in these files) and never introduces a floating ref. +FILES_TO_REPIN=("$PACK_DIR"/workflows/*.yml) +if compgen -G "workflow-templates/l9-v2-*.yml" >/dev/null; then + FILES_TO_REPIN+=(workflow-templates/l9-v2-*.yml) +fi +for f in "${FILES_TO_REPIN[@]}"; do + [[ -f "$f" ]] || continue + sed -i.bak -E "s#(Quantum-L9/l9-ci-core/[A-Za-z0-9._/-]+)@[0-9a-f]{40}#\\1@${CORE_REF}#g" "$f" + rm -f "${f}.bak" +done +sed -i.bak -E "s#(pin Core at \`)[0-9a-f]{40}(\`)#\\1${CORE_REF}\\2#gi" "$PACK_DIR/README.md" 2>/dev/null || true +rm -f "$PACK_DIR/README.md.bak" + +echo "" +echo "✅ Synced. Review the diff, then run ops/validate-starters.sh before committing:" +echo " git diff --stat" +echo " ops/validate-starters.sh" From 0b92bac31a8db13e94c8ee889eb9ac29f0abe0c7 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:21 -0400 Subject: [PATCH 13/41] feat(starters): add v2 starter l9-v2-analysis.yml aligned to l9-ci-pack --- workflow-templates/l9-v2-analysis.yml | 197 ++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 workflow-templates/l9-v2-analysis.yml diff --git a/workflow-templates/l9-v2-analysis.yml b/workflow-templates/l9-v2-analysis.yml new file mode 100644 index 0000000..230ebf4 --- /dev/null +++ b/workflow-templates/l9-v2-analysis.yml @@ -0,0 +1,197 @@ +# L9 analysis caller (TEMPLATE — copy into your repo at .github/workflows/l9-analysis.yml) +# +# Works for Python AND Node.js repos: semgrep is the single, language-agnostic +# provider the pinned SDK normalizes. The ONLY per-language difference is the +# semgrep --config rulesets in the "Run semgrep" step below. +# +# Topology (this is the wiring that actually works): +# job analyze -> generates the semgrep report and runs the SDK pipeline in ONE +# job so the freshly-generated report is on the same filesystem +# (the reusable normalize workflow re-checks-out github.sha and +# would NOT see an uncommitted report). +# job publish -> calls Core's publish-analysis.yml, which DOWNLOADS the +# uploaded artifact (no report-in-tree needed) and publishes the +# GitHub check per the resolved governance mode. +# +# Prerequisite: copy docs/templates/governance/*.yaml into THIS repo at +# .github/governance/ (that is the CI instantiation pack the resolver reads). + +name: L9 Analysis + +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: l9-analysis-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + # Pin Core to the immutable release commit (or replace with the v2 tag). + L9_CORE_REF: "f88116503430aa18992b70d8d31063e34ff97ef1" + # Match the event: pr_fast for pull_request, merge for push, nightly/release/ + # supply_chain as appropriate. Must be allowed_events in execution-profiles.yaml. + L9_PROFILE: "pr_fast" + L9_MATRIX_ID: "pr-semgrep" + +jobs: + analyze: + name: Analyze (semgrep -> SDK) + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + outputs: + mode: ${{ steps.gov.outputs.mode }} + enabled: ${{ steps.gov.outputs.enabled }} + artifact-name: ${{ steps.names.outputs.artifact-name }} + governance-digest: ${{ steps.gov.outputs.governance-digest }} + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + + - id: gov + name: Resolve governance (Core) + uses: Quantum-L9/l9-ci-core/.github/actions/resolve-governance@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + profile: ${{ env.L9_PROFILE }} + provider: semgrep + event-name: ${{ github.event_name }} + repository: ${{ github.repository }} + ref: ${{ github.ref }} + governance-root: .github/governance + + - id: names + name: Resolve artifact name + env: + MATRIX_ID: ${{ env.L9_MATRIX_ID }} + run: | + set -euo pipefail + echo "artifact-name=l9-semgrep-${MATRIX_ID}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_OUTPUT" + + - name: Run semgrep (produce raw report) + if: steps.gov.outputs.enabled == 'true' + run: | + set -euo pipefail + python -m pip install --upgrade pip semgrep + mkdir -p "artifacts/raw/semgrep/${L9_MATRIX_ID}" + # ── PER-LANGUAGE RULESETS ────────────────────────────────────────── + # Python repo: --config p/python + # Node.js repo: --config p/javascript --config p/typescript + # Polyglot / either: keep all three (semgrep skips rules that do not + # match any files) or use --config auto. + semgrep scan \ + --config p/python \ + --config p/javascript \ + --config p/typescript \ + --json \ + --output "artifacts/raw/semgrep/${L9_MATRIX_ID}/report.json" \ + --error --quiet || true + env: + L9_MATRIX_ID: ${{ env.L9_MATRIX_ID }} + + - id: sdk + name: Provision immutable SDK + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/provision-sdk@f88116503430aa18992b70d8d31063e34ff97ef1 + + - name: Normalize provider report + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/invoke-sdk@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + executable: ${{ steps.sdk.outputs.executable }} + operation: semgrep-normalize + input: artifacts/raw/semgrep/${{ env.L9_MATRIX_ID }}/report.json + output: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + root: . + snapshot-id: ${{ github.sha }} + revision: ${{ github.sha }} + strict: ${{ steps.gov.outputs.strict }} + required: ${{ steps.gov.outputs.required-provider }} + policy: ${{ steps.gov.outputs.sdk-policy }} + + - name: Validate canonical bundle + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/validate-bundle@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + executable: ${{ steps.sdk.outputs.executable }} + bundle: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + + - name: Project agent-review payload + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/invoke-sdk@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + executable: ${{ steps.sdk.outputs.executable }} + operation: bundle-project-agent-payload + input: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + output: .l9/runtime/${{ env.L9_MATRIX_ID }}/agent-review-payload.json + strict: ${{ steps.gov.outputs.strict }} + + - id: route + name: Route artifacts + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/route-artifacts@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + provider: semgrep + matrix-id: ${{ env.L9_MATRIX_ID }} + raw-report: artifacts/raw/semgrep/${{ env.L9_MATRIX_ID }}/report.json + bundle: .l9/runtime/${{ env.L9_MATRIX_ID }}/finding-bundle.json + agent-payload: .l9/runtime/${{ env.L9_MATRIX_ID }}/agent-review-payload.json + destination-root: artifacts + + - name: Build artifact manifest + if: steps.gov.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/actions/build-artifact-manifest@f88116503430aa18992b70d8d31063e34ff97ef1 + with: + provider: semgrep + matrix-id: ${{ env.L9_MATRIX_ID }} + sdk-revision: ${{ steps.sdk.outputs.sdk-revision }} + bundle: ${{ steps.route.outputs.bundle }} + agent-payload: ${{ steps.route.outputs.agent-payload }} + raw-directory: ${{ steps.route.outputs.raw-directory }} + output: artifacts/metadata/${{ env.L9_MATRIX_ID }}/artifact-manifest.json + + - name: Upload analysis artifact set + if: steps.gov.outputs.enabled == 'true' + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: ${{ steps.names.outputs.artifact-name }} + path: | + artifacts/raw/semgrep/${{ env.L9_MATRIX_ID }}/ + artifacts/l9/${{ env.L9_MATRIX_ID }}/ + artifacts/metadata/${{ env.L9_MATRIX_ID }}/ + if-no-files-found: error + retention-days: 14 + + publish: + name: Publish analysis (Core) + needs: analyze + if: needs.analyze.outputs.enabled == 'true' + uses: Quantum-L9/l9-ci-core/.github/workflows/publish-analysis.yml@f88116503430aa18992b70d8d31063e34ff97ef1 + permissions: + actions: read + checks: write + contents: read + with: + artifact-name: ${{ needs.analyze.outputs.artifact-name }} + profile: pr_fast + mode: ${{ needs.analyze.outputs.mode }} + provider: semgrep + matrix-id: pr-semgrep + governance-digest: ${{ needs.analyze.outputs.governance-digest }} + repository-revision: ${{ github.sha }} + workflow-result: ${{ needs.analyze.result }} From 6fc30ed2eefd3fb742531fcf09fc592c7994d569 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:22 -0400 Subject: [PATCH 14/41] feat(starters): add v2 starter l9-v2-analysis.properties.json --- .../l9-v2-analysis.properties.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 workflow-templates/l9-v2-analysis.properties.json diff --git a/workflow-templates/l9-v2-analysis.properties.json b/workflow-templates/l9-v2-analysis.properties.json new file mode 100644 index 0000000..c349f5a --- /dev/null +++ b/workflow-templates/l9-v2-analysis.properties.json @@ -0,0 +1,17 @@ +{ + "name": "L9 Analysis (v2)", + "description": "Semgrep -> l9-ci-core v2 SDK normalize/validate/publish. Requires the governance pack from l9-ci-pack/governance/ copied to .github/governance/ first. See l9-ci-pack/README.md.", + "iconName": "shield", + "categories": [ + "Python", + "JavaScript", + "TypeScript", + "Security", + "CI" + ], + "filePatterns": [ + "**/*.py", + "**/*.js", + "**/*.ts" + ] +} From f45657702d633ac82067683864ef3f64c531cd9f Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:23 -0400 Subject: [PATCH 15/41] feat(starters): add v2 starter l9-v2-lint-test.yml aligned to l9-ci-pack --- workflow-templates/l9-v2-lint-test.yml | 126 +++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 workflow-templates/l9-v2-lint-test.yml diff --git a/workflow-templates/l9-v2-lint-test.yml b/workflow-templates/l9-v2-lint-test.yml new file mode 100644 index 0000000..912957a --- /dev/null +++ b/workflow-templates/l9-v2-lint-test.yml @@ -0,0 +1,126 @@ +# L9 consumer lint + test workflow (TEMPLATE — copy into your repo) +# +# This file is NOT executed from l9-ci-core. Copy it into the CONSUMER +# repository at `.github/workflows/l9-lint-test.yml`. It replaces the +# lint / type-check / test half of the retired v1 `pr-pipeline.yml`. +# +# It deliberately lives consumer-side: l9-ci-core v2 is a thin control plane +# whose workflow set is fixed by `tests/workflows/test_phase_scope.py`. Generic +# ruff / mypy / pytest hygiene is owned by the consuming repository, not Core. +# +# v2 conventions preserved here: +# - immutable event-revision checkout (no floating action ref) +# - external actions pinned to full commit SHAs +# - explicit least-privilege permissions (contents: read, no write scopes) +name: L9 Lint and Test + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +# ── Consumer config: edit these values for your repo ─────────────────────────── +env: + PYTHON_VERSION: "3.12" + SOURCE_DIR: "." + TEST_DIR: "tests/" + # Fail the build below this line coverage percentage. 0 = advisory (no gate). + COVERAGE_THRESHOLD: "0" + +permissions: + contents: read + +concurrency: + group: l9-lint-test-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint and Type Check + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Set up Python + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install lint tools + run: | + set -euo pipefail + python -m pip install --upgrade pip + if [ -f requirements-ci.txt ]; then pip install -r requirements-ci.txt; fi + command -v ruff >/dev/null 2>&1 || pip install ruff + command -v mypy >/dev/null 2>&1 || pip install mypy + - name: ruff check + run: ruff check . --output-format=github + - name: ruff format --check + run: ruff format --check . + - name: mypy + run: | + mypy "${SOURCE_DIR}" \ + --show-error-codes --pretty \ + --install-types --non-interactive --ignore-missing-imports + + test: + name: Test Suite + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Set up Python + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install test tools + run: | + set -euo pipefail + python -m pip install --upgrade pip + if [ -f requirements-ci.txt ]; then pip install -r requirements-ci.txt; fi + pip install -e ".[dev]" || pip install -e . || \ + echo "::notice::no local editable package to install" + command -v pytest >/dev/null 2>&1 || pip install pytest + python -c "import pytest_cov" 2>/dev/null || pip install pytest-cov + python -c "import xdist" 2>/dev/null || pip install pytest-xdist + python -c "import pytest_timeout" 2>/dev/null || pip install pytest-timeout + - name: pytest with coverage + env: + TESTING: "true" + run: | + set -euo pipefail + PYTHONPATH=. pytest "${TEST_DIR}" \ + -n auto \ + --cov="${SOURCE_DIR}" \ + --cov-report=xml --cov-report=term-missing \ + --cov-fail-under="${COVERAGE_THRESHOLD}" \ + --timeout=300 --tb=short -v From 7bcfb524781abdc34250a4ef31e352a471721899 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:24 -0400 Subject: [PATCH 16/41] feat(starters): add v2 starter l9-v2-lint-test.properties.json --- workflow-templates/l9-v2-lint-test.properties.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 workflow-templates/l9-v2-lint-test.properties.json diff --git a/workflow-templates/l9-v2-lint-test.properties.json b/workflow-templates/l9-v2-lint-test.properties.json new file mode 100644 index 0000000..aab8fa2 --- /dev/null +++ b/workflow-templates/l9-v2-lint-test.properties.json @@ -0,0 +1,12 @@ +{ + "name": "L9 Lint and Test (v2, Python)", + "description": "Python hygiene: ruff, ruff format, mypy, pytest+coverage. Consumer-owned template, not called by l9-ci-core. Pairs with L9 Analysis (v2). See l9-ci-pack/README.md.", + "iconName": "beaker", + "categories": [ + "Python", + "CI" + ], + "filePatterns": [ + "**/*.py" + ] +} From e102025ae74792794ad064c3718e17b4c8ab5a71 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:25 -0400 Subject: [PATCH 17/41] feat(starters): add v2 starter l9-v2-lint-test-node.yml aligned to l9-ci-pack --- workflow-templates/l9-v2-lint-test-node.yml | 156 ++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 workflow-templates/l9-v2-lint-test-node.yml diff --git a/workflow-templates/l9-v2-lint-test-node.yml b/workflow-templates/l9-v2-lint-test-node.yml new file mode 100644 index 0000000..0bf4db2 --- /dev/null +++ b/workflow-templates/l9-v2-lint-test-node.yml @@ -0,0 +1,156 @@ +# L9 consumer lint + test workflow for Node.js / TypeScript (TEMPLATE) +# +# Copy into the CONSUMER repo at `.github/workflows/l9-lint-test-node.yml`. +# Node counterpart to l9-lint-test.yml (Python). Provides the TypeScript/Node +# hygiene half that v1's pr-pipeline never covered. +# +# Three independent gates (each surfaces as its own required check): +# lint -> eslint . lint / style / correctness (your eslint config) +# typecheck -> tsc --noEmit type-check the whole tree against the type +# system (honors tsconfig, e.g. strict: true). +# NO compiled output; it proves the types are +# sound, it does not run the code. +# test -> vitest run one-shot, non-interactive run of *.test.ts. +# `run` is mandatory in CI — bare `vitest` is +# watch mode and would hang the job forever. +# +# v2 conventions: immutable event-revision checkout, contents: read only (no +# write scopes). Node comes preinstalled on ubuntu-latest; see the optional +# setup-node block to pin a specific version. Package manager auto-detected +# from the lockfile (npm / pnpm / yarn). +name: L9 Lint and Test (Node) + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: l9-lint-test-node-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# ── Reusable anchors kept inline per job (templates must stay copy-paste-able). +# Each job: immutable checkout -> install deps -> run one gate. + +jobs: + lint: + name: ESLint + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + # OPTIONAL — pin Node. ubuntu-latest ships Node 20+, used as-is. To pin, + # uncomment and set a full 40-char SHA you trust for actions/setup-node: + # - uses: actions/setup-node@ # v4.x + # with: + # node-version-file: package.json # or .nvmrc, or node-version: "20" + - name: Install dependencies + run: | + set -euo pipefail + corepack enable || true + if [ -f pnpm-lock.yaml ]; then + corepack prepare pnpm@latest --activate && pnpm install --frozen-lockfile + elif [ -f yarn.lock ]; then + corepack prepare yarn@stable --activate && yarn install --immutable + elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then + npm ci + else + npm install + fi + - name: ESLint + run: npx --no-install eslint . || npx eslint . + + typecheck: + name: tsc --noEmit + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Install dependencies + run: | + set -euo pipefail + corepack enable || true + if [ -f pnpm-lock.yaml ]; then + corepack prepare pnpm@latest --activate && pnpm install --frozen-lockfile + elif [ -f yarn.lock ]; then + corepack prepare yarn@stable --activate && yarn install --immutable + elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then + npm ci + else + npm install + fi + - name: Type-check (tsc --noEmit) + run: npx --no-install tsc --noEmit || npx tsc --noEmit + + test: + name: Vitest + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + steps: + - name: Checkout immutable event revision + env: + REPOSITORY: ${{ github.repository }} + REVISION: ${{ github.sha }} + TOKEN: ${{ github.token }} + run: | + set -euo pipefail + git init . + git remote add origin \ + "https://x-access-token:${TOKEN}@github.com/${REPOSITORY}.git" + git -c protocol.version=2 fetch --depth=1 origin "${REVISION}" + git checkout --detach FETCH_HEAD + git remote set-url origin "https://github.com/${REPOSITORY}.git" + - name: Install dependencies + run: | + set -euo pipefail + corepack enable || true + if [ -f pnpm-lock.yaml ]; then + corepack prepare pnpm@latest --activate && pnpm install --frozen-lockfile + elif [ -f yarn.lock ]; then + corepack prepare yarn@stable --activate && yarn install --immutable + elif [ -f package-lock.json ] || [ -f npm-shrinkwrap.json ]; then + npm ci + else + npm install + fi + - name: Vitest (one-shot, non-interactive) + env: + CI: "true" + run: npx --no-install vitest run || npx vitest run + # For coverage, install @vitest/coverage-v8 and use: + # npx vitest run --coverage From edbfaa4ab304b0dfb63a4a5e6cc1ac06557f8cd2 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:26 -0400 Subject: [PATCH 18/41] feat(starters): add v2 starter l9-v2-lint-test-node.properties.json --- .../l9-v2-lint-test-node.properties.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 workflow-templates/l9-v2-lint-test-node.properties.json diff --git a/workflow-templates/l9-v2-lint-test-node.properties.json b/workflow-templates/l9-v2-lint-test-node.properties.json new file mode 100644 index 0000000..21e06ef --- /dev/null +++ b/workflow-templates/l9-v2-lint-test-node.properties.json @@ -0,0 +1,14 @@ +{ + "name": "L9 Lint and Test (v2, Node/TypeScript)", + "description": "Node/TypeScript hygiene: eslint, tsc --noEmit, vitest run. Consumer-owned template, not called by l9-ci-core. Pairs with L9 Analysis (v2). See l9-ci-pack/README.md.", + "iconName": "beaker", + "categories": [ + "JavaScript", + "TypeScript", + "CI" + ], + "filePatterns": [ + "**/*.ts", + "**/*.js" + ] +} From 31d7e064b1ceaf69fea8db53b3cccf41c0c24181 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:27 -0400 Subject: [PATCH 19/41] fix(ops): tag-v1.sh freezes historical SHA, no longer requires main==EXPECTED_SHA --- ops/tag-v1.sh | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/ops/tag-v1.sh b/ops/tag-v1.sh index 2724e83..4579091 100755 --- a/ops/tag-v1.sh +++ b/ops/tag-v1.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash # ops/tag-v1.sh -# Creates v1.0.0 annotated tag and moving v1 tag on Quantum-L9/l9-ci-core. +# Creates v1.0.0 annotated tag and moving v1 tag on Quantum-L9/l9-ci-core, +# pointing at the frozen historical kernel commit — NOT at whatever main +# currently is (main has since moved on to the v2 thin-control-plane rewrite). +# # PREREQUISITE: Run from inside the l9-ci-core repo root with a clean working tree. # PREREQUISITE: git remote 'origin' must point to Quantum-L9/l9-ci-core. set -euo pipefail @@ -27,25 +30,26 @@ if [[ -n "$(git status --porcelain)" ]]; then exit 1 fi -# 3. Fetch latest from origin/main -echo "Fetching origin/main..." -git fetch origin main +# 3. Fetch the exact historical commit this tag freezes. This is intentionally +# a `git fetch origin `, NOT `git fetch origin main` — v1 tags a fixed +# historical commit regardless of where main has advanced to since (v2 retired +# the 8 kernels this tag preserves). Do NOT change this to track main. +echo "Fetching pinned historical commit $EXPECTED_SHA..." +git fetch origin "$EXPECTED_SHA" -# 4. Assert HEAD matches expected SHA -HEAD_SHA=$(git rev-parse origin/main) -echo "HEAD SHA: $HEAD_SHA" -echo "Expected: $EXPECTED_SHA" - -if [[ "$HEAD_SHA" != "$EXPECTED_SHA" ]]; then - echo "❌ ERROR: HEAD SHA does not match expected SHA." - echo " This script is pinned to SHA $EXPECTED_SHA." - echo " If main has advanced legitimately, update EXPECTED_SHA in this script." +# 4. Confirm the pinned commit actually exists in this remote (fails loudly if +# EXPECTED_SHA was ever force-pushed away or the fetch above silently no-ops). +if ! git cat-file -e "${EXPECTED_SHA}^{commit}" 2>/dev/null; then + echo "❌ ERROR: $EXPECTED_SHA is not a valid commit reachable from origin." + echo " This script tags a fixed historical commit; it does not require" + echo " main to be at this SHA. If this commit is genuinely gone, stop and" + echo " ask a human — do not repoint v1 at a different commit silently." exit 1 fi +echo "✅ Pinned commit verified reachable." -echo "✅ SHA assertion passed." - -# 5. Checkout the exact SHA +# 5. Checkout the exact historical SHA (detached) — independent of main's +# current position. git checkout "$EXPECTED_SHA" # 6. Create annotated v1.0.0 tag (immutable) From 77d12f026b7144b856f1043f8c4de99c6ea6adaf Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:28 -0400 Subject: [PATCH 20/41] feat(ops): validate-starters.sh also checks l9-ci-pack completeness --- ops/validate-starters.sh | 57 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/ops/validate-starters.sh b/ops/validate-starters.sh index 700bff8..d4d04de 100755 --- a/ops/validate-starters.sh +++ b/ops/validate-starters.sh @@ -2,11 +2,16 @@ # ops/validate-starters.sh # Validates every workflow-templates/*.yml has a matching *.properties.json. # Validates each properties.json contains required fields: name, description, iconName, categories, filePatterns. +# Validates the l9-ci-pack/ (v2) required CI file set is present and pinned to +# a full commit SHA or a Core release tag — never @main. # Run from the root of the Quantum-L9/.github repo. set -euo pipefail TEMPLATES_DIR="workflow-templates" +PACK_DIR="l9-ci-pack" REQUIRED_FIELDS=("name" "description" "iconName" "categories" "filePatterns") +REQUIRED_PACK_GOVERNANCE=("execution-profiles.yaml" "provider-requiredness.yaml" "rule-modes.yaml" "waivers.yaml" "promotion-policy.yaml" "quality-thresholds.yaml") +REQUIRED_PACK_WORKFLOWS=("l9-analysis.yml" "l9-lint-test.yml" "l9-lint-test-node.yml") PASS=0 FAIL=0 @@ -51,9 +56,10 @@ for yml in "$TEMPLATES_DIR"/*.yml; do fi done - # Validate no @main references in the YAML (must use @v1) + # Validate no @main references in the YAML (must use @v1, a full SHA, or a + # Core release tag such as @v2.0.0/@v2) if grep -q "@main" "$yml"; then - echo "❌ @main REFERENCE found in $yml — must use @v1" + echo "❌ @main REFERENCE found in $yml — must use @v1, a full commit SHA, or a release tag" FAIL=$((FAIL+1)) FIELDS_OK=false fi @@ -64,6 +70,53 @@ for yml in "$TEMPLATES_DIR"/*.yml; do fi done +echo "" +echo "=== l9-ci-pack (v2) completeness ===" + +if [ ! -d "$PACK_DIR" ]; then + echo "❌ FATAL: $PACK_DIR directory not found." + FAIL=$((FAIL+1)) +else + for f in "${REQUIRED_PACK_GOVERNANCE[@]}"; do + path="$PACK_DIR/governance/$f" + if [ -f "$path" ]; then + echo "✅ $path present" + PASS=$((PASS+1)) + else + echo "❌ MISSING required governance file: $path" + FAIL=$((FAIL+1)) + fi + done + + for f in "${REQUIRED_PACK_WORKFLOWS[@]}"; do + path="$PACK_DIR/workflows/$f" + if [ ! -f "$path" ]; then + echo "❌ MISSING required workflow template: $path" + FAIL=$((FAIL+1)) + continue + fi + if grep -q "@main" "$path"; then + echo "❌ @main REFERENCE found in $path — must be a full commit SHA or a release tag" + FAIL=$((FAIL+1)) + continue + fi + echo "✅ $path present, no @main refs" + PASS=$((PASS+1)) + done + + if [ ! -f "$PACK_DIR/README.md" ]; then + echo "❌ MISSING $PACK_DIR/README.md" + FAIL=$((FAIL+1)) + else + echo "✅ $PACK_DIR/README.md present" + PASS=$((PASS+1)) + fi + + # Explicitly NOT required in the pack: issue/PR templates are owned solely + # by this repo's own community-health files (.github/ISSUE_TEMPLATE/, + # root PULL_REQUEST_TEMPLATE.md), never synced from l9-ci-core. +fi + echo "" echo "================================" echo "Results: $PASS passed, $FAIL failed" From 57285cd7a08e6383c2a6b67178ae80eb2fb00ea1 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:29 -0400 Subject: [PATCH 21/41] docs(registry): add v2 pack block; current_sha for CANDIDATE, mark v1 kernels frozen/historical --- workflow-interface-registry.yml | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/workflow-interface-registry.yml b/workflow-interface-registry.yml index 780f8f8..e2a928a 100644 --- a/workflow-interface-registry.yml +++ b/workflow-interface-registry.yml @@ -9,6 +9,67 @@ last_audited: "2026-07-05" # v1 — moving tag, force-updated by platform team on backward-compatible changes # v2 — cut for breaking changes (new required inputs, removed outputs, renamed jobs) # Never reference @main from thin callers. Always use @v1. +# +# v1 is FROZEN (historical): l9-ci-core `main` has since been rewritten as a +# thin control plane (v2) and no longer contains these 8 kernels at HEAD — +# they only exist at the pinned historical commit above. @v1 starters below +# keep resolving against that frozen commit; they are not maintained further. + +# v2 (CURRENT — start here for all new work): +# Full instantiation pack: l9-ci-pack/ (README.md + governance/ + workflows/) +# Pinned Core ref: see l9-ci-pack/README.md "Prerequisites" (full +# commit SHA pre-release; @v2.0.0 / @v2 after cut) +# Legacy v1 starters: workflow-templates/l9-{pr-pipeline,security, +# scorecard,sbom,pre-commit,nightly,release, +# governance,node-ts-monorepo}.yml — frozen @v1, +# kept only for already-imported wrappers. +v2: + schema_version: "1.0" + kernel_provider: "Quantum-L9/l9-ci-core" + current_sha: "f88116503430aa18992b70d8d31063e34ff97ef1" + status: "pre-release-candidate" # flips to "released" once v2.0.0 is tagged + pack_path: "l9-ci-pack/" + pack_readme: "l9-ci-pack/README.md" + reusable_workflows: + - name: profile-normalize-semgrep + file: "l9-ci-pack/workflows/l9-analysis.yml" + calls: "Quantum-L9/l9-ci-core/.github/workflows/profile-normalize-semgrep.yml" + classification: KERNEL + description: "Semgrep -> SDK normalize/validate/route, one job per caller repo." + - name: publish-analysis + file: "l9-ci-pack/workflows/l9-analysis.yml" + calls: "Quantum-L9/l9-ci-core/.github/workflows/publish-analysis.yml" + classification: KERNEL + description: "Publishes the resolved GitHub check + PR annotations from the SDK agent-review projection." + consumer_owned_templates: + - name: l9-lint-test + file: "l9-ci-pack/workflows/l9-lint-test.yml" + classification: CONSUMER_TEMPLATE + description: "Python hygiene (ruff, mypy, pytest+coverage). Not called by Core; copied and owned by the consumer." + - name: l9-lint-test-node + file: "l9-ci-pack/workflows/l9-lint-test-node.yml" + classification: CONSUMER_TEMPLATE + description: "Node/TypeScript hygiene (eslint, tsc --noEmit, vitest run). Not called by Core; copied and owned by the consumer." + governance_files: + - "l9-ci-pack/governance/execution-profiles.yaml" + - "l9-ci-pack/governance/provider-requiredness.yaml" + - "l9-ci-pack/governance/rule-modes.yaml" + - "l9-ci-pack/governance/waivers.yaml" + - "l9-ci-pack/governance/promotion-policy.yaml" + - "l9-ci-pack/governance/quality-thresholds.yaml" + excluded_from_pack: + # Owned solely by this repo's own community-health files; never synced + # from l9-ci-core docs/templates/. + - ".github/ISSUE_TEMPLATE/*" + - "PULL_REQUEST_TEMPLATE.md" + no_v2_equivalent: + # SDK does not implement these providers yet — do not re-add as Core + # reusable workflows without an explicit, authorized scope change. + - scorecard + - sbom + - gitleaks + - pre-commit + - dedicated-nightly-release-kernel kernels: - name: pr-pipeline From 2eea9e1c64f4112ca77fff9a3cf00e5c4746f9bc Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:30 -0400 Subject: [PATCH 22/41] docs(starters): mark l9-governance.yml Legacy (frozen @v1) --- workflow-templates/l9-governance.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-governance.yml b/workflow-templates/l9-governance.yml index 1c40c12..0007dea 100644 --- a/workflow-templates/l9-governance.yml +++ b/workflow-templates/l9-governance.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — Three-tier separation enforcement (model/service/interface). Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 Governance Trio" on: pull_request: From 59c7fe96b06b1319675d3a91db675482686d4983 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:31 -0400 Subject: [PATCH 23/41] docs(starters): mark l9-governance.properties.json Legacy (frozen @v1) --- workflow-templates/l9-governance.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-governance.properties.json b/workflow-templates/l9-governance.properties.json index 58743e1..bdf77b9 100644 --- a/workflow-templates/l9-governance.properties.json +++ b/workflow-templates/l9-governance.properties.json @@ -1,6 +1,6 @@ { "name": "L9 Governance Trio", - "description": "Three-tier separation enforcement (model/service/interface). Calls l9-ci-core kernel; do not add logic here.", + "description": "Three-tier separation enforcement (model/service/interface). Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "shield", "categories": [ "Python", @@ -9,4 +9,4 @@ "filePatterns": [ "**/*.py" ] -} \ No newline at end of file +} From 577bc23d0a0a0315b60999d9c9fa728c4f156fb7 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:32 -0400 Subject: [PATCH 24/41] docs(starters): mark l9-nightly.yml Legacy (frozen @v1) --- workflow-templates/l9-nightly.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-nightly.yml b/workflow-templates/l9-nightly.yml index cb70235..8745a0e 100644 --- a/workflow-templates/l9-nightly.yml +++ b/workflow-templates/l9-nightly.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — Nightly scheduled validation and dependency freshness check. Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 Nightly" on: schedule: From e78db0da6bb827507cecbc78dd59266f126312a7 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:33 -0400 Subject: [PATCH 25/41] docs(starters): mark l9-nightly.properties.json Legacy (frozen @v1) --- workflow-templates/l9-nightly.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-nightly.properties.json b/workflow-templates/l9-nightly.properties.json index 9937b5b..ad72f61 100644 --- a/workflow-templates/l9-nightly.properties.json +++ b/workflow-templates/l9-nightly.properties.json @@ -1,6 +1,6 @@ { "name": "L9 Nightly", - "description": "Nightly scheduled validation and dependency freshness check. Calls l9-ci-core kernel; do not add logic here.", + "description": "Nightly scheduled validation and dependency freshness check. Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "clock", "categories": [ "Python", @@ -9,4 +9,4 @@ "filePatterns": [ "**/*.py" ] -} \ No newline at end of file +} From f47942e38f1002c20c4b2f01cedf57e268927b44 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:34 -0400 Subject: [PATCH 26/41] docs(starters): mark l9-node-ts-monorepo.yml Legacy (frozen @v1) --- workflow-templates/l9-node-ts-monorepo.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-node-ts-monorepo.yml b/workflow-templates/l9-node-ts-monorepo.yml index 3da0575..12b413d 100644 --- a/workflow-templates/l9-node-ts-monorepo.yml +++ b/workflow-templates/l9-node-ts-monorepo.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — Node/TypeScript monorepo pipeline. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). # Inline jobs for install/typecheck/test/publish-dry-run. # Security and Scorecard delegate to l9-ci-core kernels; do not add logic to those jobs. name: "L9 Node/TS Monorepo Pipeline" From f4fe1979850ca22c07ab66ccef823af6f45941c9 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:35 -0400 Subject: [PATCH 27/41] docs(starters): mark l9-node-ts-monorepo.properties.json Legacy (frozen @v1) --- workflow-templates/l9-node-ts-monorepo.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-node-ts-monorepo.properties.json b/workflow-templates/l9-node-ts-monorepo.properties.json index b357135..b9837b2 100644 --- a/workflow-templates/l9-node-ts-monorepo.properties.json +++ b/workflow-templates/l9-node-ts-monorepo.properties.json @@ -1,6 +1,6 @@ { "name": "L9 Node/TS Monorepo Pipeline", - "description": "Full Node/TypeScript monorepo pipeline: install, typecheck, Jest tests, npm publish dry-run, security scan, Scorecard.", + "description": "Full Node/TypeScript monorepo pipeline: install, typecheck, Jest tests, npm publish dry-run, security scan, Scorecard. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "package", "categories": [ "Node", @@ -13,4 +13,4 @@ "tsconfig.json", "**/*.ts" ] -} \ No newline at end of file +} From 3028999fdfcf0c1315879bb1bd988ddee177cf80 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:36 -0400 Subject: [PATCH 28/41] docs(starters): mark l9-pr-pipeline.yml Legacy (frozen @v1) --- workflow-templates/l9-pr-pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-pr-pipeline.yml b/workflow-templates/l9-pr-pipeline.yml index c6ae847..923660b 100644 --- a/workflow-templates/l9-pr-pipeline.yml +++ b/workflow-templates/l9-pr-pipeline.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — Full PR validation pipeline (lint, type-check, tests, security). Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 PR Pipeline" on: pull_request: From df7f9e80ad0a6a17415829bce5de2526c1d46ca9 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:37 -0400 Subject: [PATCH 29/41] docs(starters): mark l9-pr-pipeline.properties.json Legacy (frozen @v1) --- workflow-templates/l9-pr-pipeline.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-pr-pipeline.properties.json b/workflow-templates/l9-pr-pipeline.properties.json index 4f3124e..8b4a3b0 100644 --- a/workflow-templates/l9-pr-pipeline.properties.json +++ b/workflow-templates/l9-pr-pipeline.properties.json @@ -1,6 +1,6 @@ { "name": "L9 PR Pipeline", - "description": "Full PR validation pipeline (lint, type-check, tests, security). Calls l9-ci-core kernel; do not add logic here.", + "description": "Full PR validation pipeline (lint, type-check, tests, security). Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "beaker", "categories": [ "Python", @@ -9,4 +9,4 @@ "filePatterns": [ "**/*.py" ] -} \ No newline at end of file +} From ae5b5bead16fec53d36731a6af39c7bfa39fb87a Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:38 -0400 Subject: [PATCH 30/41] docs(starters): mark l9-pre-commit.yml Legacy (frozen @v1) --- workflow-templates/l9-pre-commit.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-pre-commit.yml b/workflow-templates/l9-pre-commit.yml index 68aab51..edbe907 100644 --- a/workflow-templates/l9-pre-commit.yml +++ b/workflow-templates/l9-pre-commit.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — Pre-commit hook enforcement in CI (ruff, mypy, hooks). Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 Pre-Commit CI" on: pull_request: From d3c4fff17aaec7e9b1c9e54af5fce2e1690866df Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:39 -0400 Subject: [PATCH 31/41] docs(starters): mark l9-pre-commit.properties.json Legacy (frozen @v1) --- workflow-templates/l9-pre-commit.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-pre-commit.properties.json b/workflow-templates/l9-pre-commit.properties.json index 8537c62..c674828 100644 --- a/workflow-templates/l9-pre-commit.properties.json +++ b/workflow-templates/l9-pre-commit.properties.json @@ -1,6 +1,6 @@ { "name": "L9 Pre-Commit CI", - "description": "Pre-commit hook enforcement in CI (ruff, mypy, hooks). Calls l9-ci-core kernel; do not add logic here.", + "description": "Pre-commit hook enforcement in CI (ruff, mypy, hooks). Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "verified", "categories": [ "Python", @@ -9,4 +9,4 @@ "filePatterns": [ ".pre-commit-config.yaml" ] -} \ No newline at end of file +} From 2d4c3e4c97a52a1b4e1d8bdff354e87d38cc361c Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:40 -0400 Subject: [PATCH 32/41] docs(starters): mark l9-release.yml Legacy (frozen @v1) --- workflow-templates/l9-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-release.yml b/workflow-templates/l9-release.yml index 579d78d..bae15e6 100644 --- a/workflow-templates/l9-release.yml +++ b/workflow-templates/l9-release.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — Versioned release build and PyPI publish. Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 Release" on: push: From 17cda5cc954ca459b928fa8e647ac2766a2b43b0 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:40 -0400 Subject: [PATCH 33/41] docs(starters): mark l9-release.properties.json Legacy (frozen @v1) --- workflow-templates/l9-release.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-release.properties.json b/workflow-templates/l9-release.properties.json index 25aa880..9c220f0 100644 --- a/workflow-templates/l9-release.properties.json +++ b/workflow-templates/l9-release.properties.json @@ -1,6 +1,6 @@ { "name": "L9 Release", - "description": "Versioned release build and PyPI publish. Calls l9-ci-core kernel; do not add logic here.", + "description": "Versioned release build and PyPI publish. Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "tag", "categories": [ "Python", @@ -9,4 +9,4 @@ "filePatterns": [ "**/*.py" ] -} \ No newline at end of file +} From e4e2c05bfbfaa54bbe8d8365a7b88810427cb63b Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:41 -0400 Subject: [PATCH 34/41] docs(starters): mark l9-sbom.yml Legacy (frozen @v1) --- workflow-templates/l9-sbom.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-sbom.yml b/workflow-templates/l9-sbom.yml index d3742b8..e63245e 100644 --- a/workflow-templates/l9-sbom.yml +++ b/workflow-templates/l9-sbom.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — SBOM generation (SPDX-JSON via Syft). Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 SBOM Generator" on: push: From 68d6c5f04c16861c2e034eef54f093548543e881 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:42 -0400 Subject: [PATCH 35/41] docs(starters): mark l9-sbom.properties.json Legacy (frozen @v1) --- workflow-templates/l9-sbom.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-sbom.properties.json b/workflow-templates/l9-sbom.properties.json index 9752077..452fb77 100644 --- a/workflow-templates/l9-sbom.properties.json +++ b/workflow-templates/l9-sbom.properties.json @@ -1,10 +1,10 @@ { "name": "L9 SBOM Generator", - "description": "SBOM generation (SPDX-JSON via Syft). Calls l9-ci-core kernel; do not add logic here.", + "description": "SBOM generation (SPDX-JSON via Syft). Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "package", "categories": [ "Security", "Supply Chain" ], "filePatterns": [] -} \ No newline at end of file +} From fe30707001c6864b19351e87a5bc49ce90286d3f Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:43 -0400 Subject: [PATCH 36/41] docs(starters): mark l9-scorecard.yml Legacy (frozen @v1) --- workflow-templates/l9-scorecard.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-scorecard.yml b/workflow-templates/l9-scorecard.yml index b7c60bb..a1f9e93 100644 --- a/workflow-templates/l9-scorecard.yml +++ b/workflow-templates/l9-scorecard.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — OpenSSF Scorecard analysis. Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 OpenSSF Scorecard" on: schedule: From 6c0e894cd7ae036dbb95976195b30d2d48daf233 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:44 -0400 Subject: [PATCH 37/41] docs(starters): mark l9-scorecard.properties.json Legacy (frozen @v1) --- workflow-templates/l9-scorecard.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-scorecard.properties.json b/workflow-templates/l9-scorecard.properties.json index 6bb2638..d338c2a 100644 --- a/workflow-templates/l9-scorecard.properties.json +++ b/workflow-templates/l9-scorecard.properties.json @@ -1,10 +1,10 @@ { "name": "L9 OpenSSF Scorecard", - "description": "OpenSSF Scorecard analysis. Calls l9-ci-core kernel; do not add logic here.", + "description": "OpenSSF Scorecard analysis. Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "graph", "categories": [ "Security", "Supply Chain" ], "filePatterns": [] -} \ No newline at end of file +} From a4e870c09e189f584c65c3da292355973a4d5100 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:46 -0400 Subject: [PATCH 38/41] docs(starters): mark l9-security.yml Legacy (frozen @v1) --- workflow-templates/l9-security.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow-templates/l9-security.yml b/workflow-templates/l9-security.yml index f064a48..526a52e 100644 --- a/workflow-templates/l9-security.yml +++ b/workflow-templates/l9-security.yml @@ -1,4 +1,5 @@ # Quantum-L9 org starter — Security scan pipeline (gitleaks, Bandit, Semgrep, pip-audit). Calls l9-ci-core kernel; do not add logic here. +# LEGACY (frozen @v1) — historical kernel starter. New work starts from l9-ci-pack/README.md (v2). name: "L9 Security Scan" on: pull_request: From fe399df73eb8a83a77dfbb4550323e8b5cdb8b89 Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:47 -0400 Subject: [PATCH 39/41] docs(starters): mark l9-security.properties.json Legacy (frozen @v1) --- workflow-templates/l9-security.properties.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow-templates/l9-security.properties.json b/workflow-templates/l9-security.properties.json index 81c0831..0f489e8 100644 --- a/workflow-templates/l9-security.properties.json +++ b/workflow-templates/l9-security.properties.json @@ -1,6 +1,6 @@ { "name": "L9 Security Scan", - "description": "Security scan pipeline (gitleaks, Bandit, Semgrep, pip-audit). Calls l9-ci-core kernel; do not add logic here.", + "description": "Security scan pipeline (gitleaks, Bandit, Semgrep, pip-audit). Calls l9-ci-core kernel; do not add logic here. LEGACY (frozen @v1) \u2014 see l9-ci-pack/README.md for v2.", "iconName": "lock", "categories": [ "Security", @@ -11,4 +11,4 @@ "**/*.js", "**/*.ts" ] -} \ No newline at end of file +} From 28d279412116a5b5f5e2d5db03e79824b6be903a Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:48 -0400 Subject: [PATCH 40/41] docs: point new-repo CI instantiation at l9-ci-pack (v2); mark v1 table legacy --- CONTRIBUTING.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be1fd66..2bf2c8d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,9 +34,15 @@ the workspace root must have `.cursor/` symlinks resolving to `Cursor-Governance --- -## CI Gate Requirements +## CI Gate Requirements (Legacy `@v1`) -All pull requests must pass: +> **New repos: skip this table.** Instantiate `l9-ci-core` **v2** from +> [`l9-ci-pack/README.md`](https://github.com/Quantum-L9/.github/blob/main/l9-ci-pack/README.md) +> instead — governed semgrep analysis + optional per-language lint/test +> templates. The kernels below are frozen at the historical `@v1` commit and +> kept only so already-imported repos keep resolving. + +All pull requests on repos still using legacy `@v1` kernels must pass: | Gate | Tool | Kernel | |---|---|---| @@ -67,4 +73,20 @@ All pull requests must pass: - Kernels must use `on: workflow_call` only - `l9-self-ci.yml` must remain `on: pull_request/push` — **never convert to workflow_call** (circular dependency) - `@v1` moving tag discipline: force-update `v1` for backward-compatible changes; cut `v2` for breaking changes -- See [workflow-interface-registry.yml](https://github.com/Quantum-L9/.github/blob/main/workflow-interface-registry.yml) for the full kernel API contract +- See [workflow-interface-registry.yml](https://github.com/Quantum-L9/.github/blob/main/workflow-interface-registry.yml) for the full kernel API contract (see the `v2:` block for the current pack; the top-level `kernels:` list is the frozen `@v1` set) + +--- + +## Instantiating l9-ci-core v2 (current) + +For any new repo, start here — not the `@v1` table above: + +1. Copy the six governance files from + [`l9-ci-pack/governance/`](https://github.com/Quantum-L9/.github/tree/main/l9-ci-pack/governance) → `.github/governance/`. +2. Copy [`l9-ci-pack/workflows/l9-analysis.yml`](https://github.com/Quantum-L9/.github/blob/main/l9-ci-pack/workflows/l9-analysis.yml) → `.github/workflows/l9-analysis.yml`. +3. Optionally copy the matching lint/test template for your language. +4. Full steps, profile matrix, and rollout guidance: + [`l9-ci-pack/README.md`](https://github.com/Quantum-L9/.github/blob/main/l9-ci-pack/README.md). + +Ownership and pinning rules live in +[`l9-ci-core/AGENTS.md`](https://github.com/Quantum-L9/l9-ci-core/blob/main/AGENTS.md). From c27691dd17633ffae48a11d61d8c15cf72c8e6df Mon Sep 17 00:00:00 2001 From: Igor Beylin <31744795+cryptoxdog@users.noreply.github.com> Date: Mon, 20 Jul 2026 03:16:49 -0400 Subject: [PATCH 41/41] docs: point org profile README at l9-ci-pack (v2) for l9-ci-core instantiation --- profile/README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/profile/README.md b/profile/README.md index d8f7377..d66dabb 100644 --- a/profile/README.md +++ b/profile/README.md @@ -13,16 +13,24 @@ | Repository | Role | Entry Point | |---|---|---| | [`Cursor-Governance`](https://github.com/Quantum-L9/Cursor-Governance) | Policy SSOT — CANONICAL_LAW.md §1–§9, symlink wiring, GlobalCommands | `CANONICAL_LAW.md` | -| [`l9-ci-core`](https://github.com/Quantum-L9/l9-ci-core) | Reusable CI kernel library — 8 `workflow_call` kernels | `.github/workflows/pr-pipeline.yml@v1` | +| [`l9-ci-core`](https://github.com/Quantum-L9/l9-ci-core) | Thin GitHub Actions control plane (v2) — SDK-provisioning, governance resolution, publication | [`l9-ci-pack/README.md`](https://github.com/Quantum-L9/.github/blob/main/l9-ci-pack/README.md) (v2, current); `pr-pipeline.yml@v1` (legacy, frozen) | | [`l9-assurance`](https://github.com/Quantum-L9/l9-assurance) | 51-package TypeScript governance assurance monorepo | `packages/` | | [`.github`](https://github.com/Quantum-L9/.github) | Org backbone — health files, starter templates, workflow registry | `workflow-interface-registry.yml` | --- -## CI Kernel API +## CI instantiation -All repositories consume `l9-ci-core` kernels via thin caller workflows. -See [`workflow-interface-registry.yml`](https://github.com/Quantum-L9/.github/blob/main/workflow-interface-registry.yml) for the machine-readable CI API contract. +**v2 (current, start here):** [`l9-ci-pack/README.md`](https://github.com/Quantum-L9/.github/blob/main/l9-ci-pack/README.md) — +governed semgrep analysis (`l9-ci-pack/workflows/l9-analysis.yml`) publishing +GitHub checks via `l9-ci-core`'s `profile-normalize-semgrep.yml` + +`publish-analysis.yml`, plus optional per-language lint/test templates. + +**`@v1` (legacy, frozen):** All repositories still on legacy `@v1` consume +`l9-ci-core` kernels via thin caller workflows. See +[`workflow-interface-registry.yml`](https://github.com/Quantum-L9/.github/blob/main/workflow-interface-registry.yml) +for the machine-readable CI API contract (`v2:` block for the current pack, +top-level `kernels:` list for the frozen `@v1` set). | Kernel | Purpose | |---|---|