# CI/CD Pipeline Guide ## Overview GSD 2 uses a three-stage promotion pipeline that automatically moves merged PRs through **Dev → Test → Prod** environments using npm dist-tags. ``` PR merged to main │ ▼ ┌─────────┐ ci.yml passes (build, test, typecheck) │ DEV │ → publishes gsd-pi@-dev. with @dev tag └────┬────┘ ▼ (automatic if green) ┌─────────┐ CLI smoke tests + LLM fixture replay │ TEST │ → promotes to @next tag └────┬────┘ → pushes Docker image as :next ▼ (manual approval required) ┌─────────┐ optional real-LLM integration tests │ PROD │ → promotes to @latest tag └─────────┘ → creates GitHub Release ``` ## For Contributors: Testing Your PR Before It Ships ### Install the Dev Build Every merged PR is immediately installable: ```bash # Latest dev build (bleeding edge, every merged PR) npx gsd-pi@dev # Test candidate (passed smoke + fixture tests) npx gsd-pi@next # Stable production release npx gsd-pi@latest # or just: npx gsd-pi ``` ### Using Docker ```bash # Test candidate docker run --rm -v $(pwd):/workspace ghcr.io/gsd-build/gsd-pi:next --version # Stable docker run --rm -v $(pwd):/workspace ghcr.io/gsd-build/gsd-pi:latest --version ``` ### Checking if a Fix Landed 1. Find the PR's merge commit SHA (first 7 chars) 2. Check if it's in `@dev`: `npm view gsd-pi@dev version` - If the version ends in `-dev.`, your PR is in dev 3. Check if it promoted to `@next`: `npm view gsd-pi@next version` 4. Check if it's in production: `npm view gsd-pi@latest version` ## For Maintainers ### Pipeline Workflows | Workflow | File | Trigger | Purpose | |----------|------|---------|---------| | CI | `ci.yml` | PR + push to main | Build, test, typecheck — **gate for all promotions** | | Release Pipeline | `pipeline.yml` | After CI succeeds on main | Three-stage promotion | | Native Binaries | `build-native.yml` | `v*` tags | Cross-compile platform binaries | | Dev Cleanup | `cleanup-dev-versions.yml` | Weekly (Monday 06:00 UTC) | Unpublish `-dev.` versions older than 30 days | | AI Triage | `triage.yml` | New issues + PRs | Automated classification via Claude Haiku (v2.36) | **CI optimization (v2.38):** GitHub Actions minutes were reduced ~60-70% (~10k → ~3-4k/month) through workflow consolidation and caching improvements. **Pipeline optimization (v2.41):** - **Shallow clones** — CI lint and build jobs use `fetch-depth: 1` or `fetch-depth: 2` instead of full history, saving ~30-60s per job - **npm cache in pipeline** — dev-publish, test-verify, and prod-release now use `cache: 'npm'` on setup-node, saving ~1-2 min per job on repeat runs - **Exponential backoff** — npm registry propagation waits in `build-native.yml` replaced hardcoded `sleep 30` + fixed 15s retries with exponential backoff (5s → 10s → 20s → 30s cap), typically finishing in <15s when the registry is fast - **Security hardening** — pipeline.yml moved `${{ }}` expressions from `run:` blocks to `env:` variables to prevent command injection vectors ### Build-Relevant Change Detection CI classifies changed files before the expensive jobs run. Changes that do not touch build, runtime, test, package, web, native, Docker, or TypeScript config paths skip the build/test matrix. - **Skipped:** `build`, `integration-tests`, `e2e`, `docker-e2e`, and `windows-portability` - **Still runs:** `lint` (secret scanning, `.gsd/` check), `docs-check` (prompt injection scan) This saves CI minutes on documentation and metadata-only PRs while still enforcing security checks. ### Prompt Injection Scan (v2.41) The `docs-check` job runs `scripts/docs-prompt-injection-scan.sh` on every PR that touches markdown files. It scans documentation prose (excluding fenced code blocks) for patterns that could manipulate LLM behavior when docs are ingested as context: - **System prompt markers** — ``, `<|im_start|>system`, `[SYSTEM]:` - **Role/instruction overrides** — `ignore previous instructions`, `you are now`, `new instructions:` - **Hidden HTML directives** — `