From 5eafbff6cb4b31a5047029f412bdf17ab2d81690 Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 1 Jul 2026 22:49:07 +0200 Subject: [PATCH 1/3] ci: dogfood codebase-intelligence gate --- .github/workflows/ci.yml | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24a58d0..14f69ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,8 @@ jobs: node-version: [18, 22] steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: pnpm/action-setup@v4 @@ -38,6 +40,72 @@ jobs: - name: Build run: pnpm build + - name: Codebase Intelligence CI + if: matrix.node-version == 22 + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + BASE_REF="origin/${{ github.base_ref }}" + else + BASE_REF="${{ github.event.before }}" + if [ -z "$BASE_REF" ] || [ "$BASE_REF" = "0000000000000000000000000000000000000000" ]; then + BASE_REF="HEAD~1" + fi + fi + + set +e + + node dist/cli.js ci . \ + --base "$BASE_REF" \ + --new-only \ + --changed-workspaces \ + --format annotations \ + --summary \ + --force + CBI_STATUS=$? + + node dist/cli.js ci . \ + --base "$BASE_REF" \ + --new-only \ + --changed-workspaces \ + --format sarif \ + --output codebase-intelligence.sarif \ + --summary \ + --force + CBI_SARIF_STATUS=$? + + node dist/cli.js ci . \ + --base "$BASE_REF" \ + --new-only \ + --changed-workspaces \ + --comment markdown \ + --output codebase-intelligence-pr-comment.md \ + --summary \ + --force + CBI_COMMENT_STATUS=$? + + if [ -f codebase-intelligence-pr-comment.md ]; then + cat codebase-intelligence-pr-comment.md >> "$GITHUB_STEP_SUMMARY" + fi + + if [ "$CBI_STATUS" -ne 0 ]; then + exit "$CBI_STATUS" + fi + if [ "$CBI_SARIF_STATUS" -ne 0 ]; then + exit "$CBI_SARIF_STATUS" + fi + exit "$CBI_COMMENT_STATUS" + + - name: Upload Codebase Intelligence reports + if: matrix.node-version == 22 && always() + uses: actions/upload-artifact@v4 + with: + name: codebase-intelligence-reports + path: | + codebase-intelligence.sarif + codebase-intelligence-pr-comment.md + retention-days: 14 + if-no-files-found: warn + - name: Test run: pnpm test From 634db4f7872ef7f09342edae5e56b55e5b5710bc Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 1 Jul 2026 22:53:59 +0200 Subject: [PATCH 2/3] ci: run dogfood gate from canary --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14f69ec..308f8b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: set +e - node dist/cli.js ci . \ + npx -y codebase-intelligence@canary ci . \ --base "$BASE_REF" \ --new-only \ --changed-workspaces \ @@ -63,7 +63,7 @@ jobs: --force CBI_STATUS=$? - node dist/cli.js ci . \ + npx -y codebase-intelligence@canary ci . \ --base "$BASE_REF" \ --new-only \ --changed-workspaces \ @@ -73,7 +73,7 @@ jobs: --force CBI_SARIF_STATUS=$? - node dist/cli.js ci . \ + npx -y codebase-intelligence@canary ci . \ --base "$BASE_REF" \ --new-only \ --changed-workspaces \ From 1ac5de89f31b4fd42a044d59e264caab34f83c7f Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Thu, 2 Jul 2026 02:36:11 +0200 Subject: [PATCH 3/3] ci: post reports and shard tests --- .github/workflows/ci.yml | 97 ++++++++++++++++++++++++---- package.json | 4 +- tests/boundaries.e2e.test.ts | 2 +- tests/cli-mcp-stdio.e2e.test.ts | 2 +- tests/drift.e2e.test.ts | 2 +- tests/health.e2e.test.ts | 2 +- tests/highways.e2e.test.ts | 2 +- tests/map.e2e.test.ts | 3 +- tests/operation-registry.e2e.test.ts | 2 +- tests/roadmap-2-5-e2e.test.ts | 2 +- 10 files changed, 97 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 308f8b6..b75a54b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,11 @@ on: pull_request: branches: [main] +permissions: + contents: read + issues: write + pull-requests: write + concurrency: group: ci-${{ github.head_ref || github.ref_name }} cancel-in-progress: true @@ -14,9 +19,6 @@ jobs: quality: name: Quality Gates runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18, 22] steps: - uses: actions/checkout@v4 with: @@ -26,7 +28,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 22 cache: pnpm - run: pnpm install --frozen-lockfile @@ -41,7 +43,6 @@ jobs: run: pnpm build - name: Codebase Intelligence CI - if: matrix.node-version == 22 run: | if [ "${{ github.event_name }}" = "pull_request" ]; then BASE_REF="origin/${{ github.base_ref }}" @@ -95,8 +96,58 @@ jobs: fi exit "$CBI_COMMENT_STATUS" + - name: Post Codebase Intelligence PR comment + if: ${{ always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }} + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const marker = ''; + const reportPath = 'codebase-intelligence-pr-comment.md'; + + if (!fs.existsSync(reportPath)) { + core.info('No Codebase Intelligence PR comment report found.'); + return; + } + + const report = fs.readFileSync(reportPath, 'utf8').trim(); + if (!report) { + core.info('Codebase Intelligence PR comment report is empty.'); + return; + } + + const body = `${marker}\n${report}`; + const { owner, repo } = context.repo; + const issue_number = context.issue.number; + const comments = await github.paginate(github.rest.issues.listComments, { + owner, + repo, + issue_number, + per_page: 100, + }); + const existing = comments.find((comment) => + comment.user?.type === 'Bot' && comment.body?.includes(marker) + ); + + if (existing) { + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existing.id, + body, + }); + return; + } + + await github.rest.issues.createComment({ + owner, + repo, + issue_number, + body, + }); + - name: Upload Codebase Intelligence reports - if: matrix.node-version == 22 && always() + if: always() uses: actions/upload-artifact@v4 with: name: codebase-intelligence-reports @@ -106,23 +157,45 @@ jobs: retention-days: 14 if-no-files-found: warn - - name: Test - run: pnpm test - # Coverage is best-effort: vitest v3 + v8 provider can hang after tests - # pass on CI runners. The blocking Test step above proves correctness; + # pass on CI runners. The blocking test matrix proves correctness; # this step is bounded so coverage cannot block the release gate. - name: Coverage - if: matrix.node-version == 22 continue-on-error: true timeout-minutes: 4 run: timeout 180s pnpm vitest run --coverage --pool forks --no-file-parallelism || true - name: Upload coverage - if: matrix.node-version == 22 && always() + if: always() uses: actions/upload-artifact@v4 with: name: coverage-report path: coverage/ retention-days: 14 if-no-files-found: ignore + + test: + name: Tests (${{ matrix.node-version }}, shard ${{ matrix.shard }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [18, 22] + shard: ["1/4", "2/4", "3/4", "4/4"] + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + - name: Test shard + run: pnpm test:shard --shard=${{ matrix.shard }} diff --git a/package.json b/package.json index f5da5e6..9ff0cef 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "build": "tsc -p tsconfig.build.json", "dev": "tsx src/cli.ts", "start": "node dist/cli.js", - "test": "pnpm build && vitest run --no-cache --pool threads --no-file-parallelism --maxWorkers=1", + "test": "pnpm build && pnpm test:run", + "test:run": "vitest run --no-cache --pool threads --maxWorkers=50%", + "test:shard": "vitest run --no-cache --pool threads --maxWorkers=2", "test:coverage": "pnpm build && vitest run --coverage --pool threads --no-file-parallelism --exclude 'tests/*.e2e.test.ts'", "verify:cli-real": "pnpm build && node tools/verify-cli-real-codebases.mjs", "verify:cli-real:heavy": "pnpm build && CBI_REAL_PROFILE=heavy node tools/verify-cli-real-codebases.mjs", diff --git a/tests/boundaries.e2e.test.ts b/tests/boundaries.e2e.test.ts index b5ae990..2c03182 100644 --- a/tests/boundaries.e2e.test.ts +++ b/tests/boundaries.e2e.test.ts @@ -23,7 +23,7 @@ interface RunResult { type BoundaryPayload = BoundariesResult & { cache?: unknown; nextSteps?: unknown }; beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); function isRecord(value: unknown): value is Record { diff --git a/tests/cli-mcp-stdio.e2e.test.ts b/tests/cli-mcp-stdio.e2e.test.ts index 5a16210..abed1fe 100644 --- a/tests/cli-mcp-stdio.e2e.test.ts +++ b/tests/cli-mcp-stdio.e2e.test.ts @@ -22,7 +22,7 @@ const GIT_ENV = { }; beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); function isRecord(value: unknown): value is Record { diff --git a/tests/drift.e2e.test.ts b/tests/drift.e2e.test.ts index caa80f0..18a720e 100644 --- a/tests/drift.e2e.test.ts +++ b/tests/drift.e2e.test.ts @@ -47,7 +47,7 @@ interface DriftPayload { } beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); function isRecord(value: unknown): value is Record { diff --git a/tests/health.e2e.test.ts b/tests/health.e2e.test.ts index c044737..754d1a1 100644 --- a/tests/health.e2e.test.ts +++ b/tests/health.e2e.test.ts @@ -51,7 +51,7 @@ interface HealthPayload { } beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); function isRecord(value: unknown): value is Record { diff --git a/tests/highways.e2e.test.ts b/tests/highways.e2e.test.ts index 7c9617e..80be161 100644 --- a/tests/highways.e2e.test.ts +++ b/tests/highways.e2e.test.ts @@ -83,7 +83,7 @@ interface HighwaysPayload { const created: string[] = []; beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); afterEach(() => { diff --git a/tests/map.e2e.test.ts b/tests/map.e2e.test.ts index 3f2c760..45ca802 100644 --- a/tests/map.e2e.test.ts +++ b/tests/map.e2e.test.ts @@ -1,4 +1,5 @@ import { execFile, execSync } from "node:child_process"; +import fs from "node:fs"; import path from "node:path"; import { promisify } from "node:util"; import { fileURLToPath } from "node:url"; @@ -66,7 +67,7 @@ interface CodebaseMapPayload { } beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); function isRecord(value: unknown): value is Record { diff --git a/tests/operation-registry.e2e.test.ts b/tests/operation-registry.e2e.test.ts index 35435c0..91d1053 100644 --- a/tests/operation-registry.e2e.test.ts +++ b/tests/operation-registry.e2e.test.ts @@ -193,7 +193,7 @@ function expectCliTextMatchesFormatter( } beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); describe("operation registry chained parity", () => { diff --git a/tests/roadmap-2-5-e2e.test.ts b/tests/roadmap-2-5-e2e.test.ts index 6b5def8..b168a27 100644 --- a/tests/roadmap-2-5-e2e.test.ts +++ b/tests/roadmap-2-5-e2e.test.ts @@ -21,7 +21,7 @@ interface RunResult { const created: string[] = []; beforeAll(() => { - execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); + if (!fs.existsSync(cli)) execSync("pnpm build", { cwd: repoRoot, stdio: "inherit" }); }, 120_000); afterEach(() => {