CI #97
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: {} | |
| jobs: | |
| build-test: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| # 20 is the dev-toolchain floor (vitest needs ≥20); 24 is current. The | |
| # published bundle's Node 18 floor is covered by runtime-node-floor. | |
| node-version: [20, 24] | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Typecheck | |
| run: pnpm run typecheck | |
| - name: Lint | |
| run: pnpm run lint | |
| - name: Build is reproducible | |
| run: pnpm run check:build | |
| - name: Test (with coverage) | |
| run: pnpm run test:coverage | |
| - name: Smoke-run the committed bundle (offline render + check) | |
| run: pnpm run demo | |
| - name: Assert the SRD was produced and is structurally complete | |
| run: | | |
| test -f /tmp/construct-demo/SRD.json | |
| test -f /tmp/construct-demo/requirements/FUNCTIONAL.md | |
| test -f /tmp/construct-demo/SRD.md | |
| # The gate has to work in BOTH directions, so prove both. | |
| - name: The gate REFUSES an un-authored complex scaffold | |
| run: | | |
| rm -rf /tmp/construct-scaffold | |
| mkdir -p /tmp/construct-scaffold/evidence | |
| cp tests/fixtures/sample-brief.json /tmp/construct-scaffold/brief.json | |
| cp tests/fixtures/sample-evidence.json /tmp/construct-scaffold/evidence/evidence.json | |
| node scripts/construct.mjs render --out /tmp/construct-scaffold --level complex | |
| if node scripts/construct.mjs check --out /tmp/construct-scaffold; then | |
| echo "::error::check accepted a complex scaffold whose acceptance criteria are still the renderer's" | |
| exit 1 | |
| fi | |
| - name: The shipped example SRD is in sync with its manifest and passes the gate | |
| run: | | |
| node scripts/construct.mjs render --out assets/example-srd --from-srd | |
| git diff --exit-code -- assets/example-srd | |
| node scripts/construct.mjs check --out assets/example-srd --min-grounding 66 | |
| install-bundle: | |
| runs-on: ubuntu-latest | |
| name: install-bundle (skill installs whole, not just SKILL.md) | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: pnpm/action-setup@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build the embedded bundle | |
| run: pnpm run build | |
| - name: Verify the install-bundle shape (no root SKILL.md, engine in sync) | |
| run: pnpm run verify:bundle | |
| - name: End-to-end — `skills add` bundles the engine + references, not SKILL.md alone | |
| run: | | |
| WORK="$(mktemp -d)" | |
| cd "$WORK" | |
| npx --yes skills add "$GITHUB_WORKSPACE" --skill construct --agent claude-code --copy -y | |
| DIR=.claude/skills/construct | |
| test -f "$DIR/SKILL.md" || { echo "::error::SKILL.md not installed"; exit 1; } | |
| test -f "$DIR/scripts/construct.mjs" || { echo "::error::engine not bundled — skills add dropped scripts/"; exit 1; } | |
| test -d "$DIR/references" || { echo "::error::references/ not bundled"; exit 1; } | |
| # The stack is the engine's. A copy here would be a second source of | |
| # truth that goes stale silently, so its ABSENCE is the assertion — | |
| # and the replacement is proving the engine writes one out instead. | |
| test ! -e "$DIR/docker-compose.yml" || { echo "::error::stale docker-compose.yml in the installed skill — the stack lives in the engine"; exit 1; } | |
| test ! -e "$DIR/docker" || { echo "::error::stale docker/ in the installed skill — the stack lives in the engine"; exit 1; } | |
| node "$DIR/scripts/construct.mjs" --help > /dev/null || { echo "::error::installed engine does not run"; exit 1; } | |
| export CONSTRUCT_CACHE_DIR="$WORK/cache" | |
| node "$DIR/scripts/construct.mjs" firecrawl status > /dev/null 2>&1 || true | |
| test -f "$CONSTRUCT_CACHE_DIR/compose/docker-compose.yml" \ | |
| || { echo "::error::the installed skill could not materialise the compose file — the stack is inoperable as-installed"; exit 1; } | |
| test -f "$CONSTRUCT_CACHE_DIR/compose/docker/searxng/settings.yml" \ | |
| || { echo "::error::searxng settings not materialised — the SearXNG mount would fail"; exit 1; } | |
| test -f "$CONSTRUCT_CACHE_DIR/compose/docker/firecrawl/firecrawl.env" \ | |
| || { echo "::error::firecrawl env not materialised — env_file: would fail before docker is reached"; exit 1; } | |
| grep -q "construct semantic up" "$CONSTRUCT_CACHE_DIR/compose/docker-compose.yml" \ | |
| || { echo "::error::the materialised compose names another tool's command"; exit 1; } | |
| echo "install-bundle: skill installed whole, the engine runs, and it writes its own stack out." | |
| runtime-node-floor: | |
| runs-on: ubuntu-latest | |
| name: runtime (Node 18 floor, zero-dep bundle) | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 18 | |
| # This job exists to prove the zero-dep bundle RUNS on the Node floor — not | |
| # to assert an SRD is gate-clean. It renders at --level light for the same | |
| # reason `pnpm demo` does: a raw `complex` scaffold is deliberately NOT | |
| # gate-clean (its acceptance criteria are still the renderer's). Both | |
| # directions of that gate are proved in build-test, against the authored | |
| # example and against a bare scaffold. | |
| - name: The committed bundle renders + checks an SRD on Node 18 (no install) | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/run18/evidence" | |
| cp tests/fixtures/sample-brief.json "$RUNNER_TEMP/run18/brief.json" | |
| cp tests/fixtures/sample-evidence.json "$RUNNER_TEMP/run18/evidence/evidence.json" | |
| node scripts/construct.mjs render --out "$RUNNER_TEMP/run18" --level light --merge | |
| node scripts/construct.mjs check --out "$RUNNER_TEMP/run18" | |
| test -f "$RUNNER_TEMP/run18/SRD.json" | |
| test -f "$RUNNER_TEMP/run18/TRACEABILITY.md" | |
| - name: The example SRD also passes on the Node 18 floor | |
| run: node scripts/construct.mjs check --out assets/example-srd --min-grounding 66 |