# Pre-Release Quality Gates

> Mandatory checks before build, archive, or deploy. Every release workflow must pass a quality gate before irreversible steps.

## When to Use

- Before any release (TestFlight, App Store, npm publish, Docker push)
- Before any deployment (staging, production)
- In CI/CD pipelines
- In manual release workflows

## The Pattern

```
[Quality Gate] → [Build/Archive] → [Deploy/Upload]
     ↓ FAIL                             ↓ SUCCESS
   STOP & FIX                        [Post-Deploy Verify]
```

**The gate must be mandatory and non-bypassable.** A TestFlight build that skips compilation verification shipped a crash-on-launch bug (real incident — a Swift file was missing from the Xcode target).

## Quality Gate Checklist

### Universal (all platforms)

```markdown
0a. Git working directory is clean
git status --porcelain # Must be empty

0b. All tests pass
npm test / pytest / xcodebuild test

0c. Type checking passes
tsc --noEmit / mypy / swift build

0d. Linter passes
eslint / ruff / swiftlint

0e. No secrets in tracked files
bash scripts/secret-scan-repo.sh
```

### Web (Next.js / React)

```markdown
1. npm test — all tests pass
2. npm run typecheck — tsc --noEmit clean
3. npm run lint — ESLint clean
4. npm run build — production build succeeds
5. Bundle size check — within budget
6. Lighthouse score — above thresholds (if configured)
```

### iOS (SwiftUI / Xcode)

```markdown
1. Compile ALL targets (not just the main app):
   xcodebuild -workspace App.xcworkspace -scheme MainApp build
   xcodebuild -workspace App.xcworkspace -scheme KeyboardExt build
   xcodebuild -workspace App.xcworkspace -scheme WidgetExt build

2. pbxproj ↔ filesystem consistency:
   Compare Swift files on disk vs Xcode project references
   (Catches files that exist but aren't in the build target)

3. No print() statements in production code:
   grep -rn 'print(' Sources/ --include='\*.swift'

4. No force-unwraps in critical paths:
   grep -rn '![^=]' Sources/ --include='\*.swift'

5. Info.plist keys present (privacy descriptions, etc.)

6. Entitlements match capabilities
```

### Android (Kotlin / Gradle)

```markdown
1. ./gradlew :app:compileDebugKotlin
2. ./gradlew :app:lintDebug
3. ./gradlew :app:testDebugUnitTest
4. Check for BuildConfig leaks (no secrets in BuildConfig)
```

### Docker

```markdown
1. docker build passes (all stages)
2. docker run health check passes
3. No secrets in Dockerfile (use build args or runtime env)
4. Image runs as non-root user
5. .dockerignore excludes node_modules, .env, .git
```

### Microservices (Fastify / Express)

```markdown
1. pnpm build — TypeScript compiles clean
2. pnpm test — all tests pass
3. pnpm typecheck — no type errors
4. Health endpoint responds: GET /health → { status: "ok" }
5. Secret scan passes
```

## Implementing in Workflows

### Windsurf workflow example

```markdown
---
description: Build and upload iOS app to TestFlight
---

## Pre-Flight Quality Gate (MANDATORY — do NOT skip)

0a. Check git is clean:
git status --porcelain

0b. Compile all targets:
xcodebuild -workspace LysnrAI.xcworkspace -scheme LysnrAI -destination 'generic/platform=iOS' build
xcodebuild -workspace LysnrAI.xcworkspace -scheme LysnrKeyboard -destination 'generic/platform=iOS' build

0c. Run pbxproj consistency check

0d. Run secret scan:
bash scripts/secret-scan-repo.sh

IF ANY STEP FAILS → STOP. Fix the issue before proceeding.

## Build & Archive (only after gate passes)

...
```

### CI pipeline example

```yaml
jobs:
  quality-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: bash scripts/secret-scan-repo.sh
      - run: npm ci
      - run: npm run typecheck
      - run: npm test
      - run: npm run lint

  build:
    needs: quality-gate # Only runs if gate passes
    runs-on: ubuntu-latest
    steps:
      - run: npm run build
      - run: docker build .
```

## The Quick-Check Script

A single script that runs all quality checks:

```bash
#!/bin/bash
# quick-check.sh — Run all quality checks
set -e

echo "=== Secret Scan ==="
bash scripts/secret-scan-repo.sh

echo "=== Typecheck ==="
npm run typecheck

echo "=== Tests ==="
npm test

echo "=== Lint ==="
npm run lint

echo "=== Build ==="
npm run build

echo ""
echo "All checks passed."
```

## Anti-Patterns

- **No quality gate** — Going straight from code to deploy
- **Optional gate** — "Run tests if you have time" defeats the purpose
- **Partial compilation** — Compiling only the main target, not extensions/widgets
- **Tests in CI only** — Run locally too; CI feedback is slow
- **Ignoring warnings** — Warnings become errors eventually; fix them early

## Real-World Incident

**What happened:** A TestFlight build crashed on launch because `LysnrTelemetry.swift` was missing from the keyboard extension's build phase. The file existed on disk and compiled fine in the main app target.

**Root cause:** The `/release-testflight` workflow had no pre-flight compile check. It went straight to Archive.

**Fix:** Added mandatory quality gate with:

1. Compile ALL targets (main app + keyboard + widgets)
2. pbxproj ↔ filesystem consistency check
3. Created `/mobile-code-quality` workflow for ongoing verification

**Result:** This class of bug can never ship again.

## Related Skills

- [07 — Systematic Debugging](./07-systematic-debugging.md)
- [08 — Test-Driven Bug Fixing](./08-test-driven-fixing.md)
- [04 — Workflow Definitions](./04-workflow-definitions.md)
