# &node_image is the pre-baked CI base built by .woodpecker/ci-image.yml:
# node:24-alpine + python3/make/g++/postgresql-client + pnpm + a warm pnpm
# store. The install step resolves from the baked store (--prefer-offline)
# instead of paying a ~731s cold fetch + native compile every run.
variables:
  - &node_image 'git.mosaicstack.dev/mosaicstack/stack/ci-base:latest'
  - &enable_pnpm 'corepack enable'

when:
  # PR + manual CI run on any branch — the pull_request pipeline is the merge gate.
  # push CI is restricted to protected branches (main) so a feature-branch push no
  # longer fires a redundant SECOND pipeline alongside its PR pipeline. This ~halves
  # CI load on the storage-constrained runner with zero loss of gating (branch
  # protection requires no push/ci status context; main still gets full push CI).
  - event: [pull_request, manual]
  - event: push
    branch: main

# Turbo remote cache (turbo.mosaicstack.dev) is configured via Woodpecker
# repository-level environment variables (TURBO_API, TURBO_TEAM, TURBO_TOKEN).
# This avoids from_secret which is blocked on pull_request events.
# If the env vars aren't set, turbo falls back to local cache only.

steps:
  install:
    image: *node_image
    commands:
      - corepack enable
      # python3/make/g++ are baked into ci-base; --prefer-offline resolves from
      # the baked pnpm store.
      - pnpm install --frozen-lockfile --prefer-offline

  # Blocking gate: public framework package must contain no operator-specific
  # personal data or private $HOME defaults. Runs early (no node_modules needed).
  sanitization:
    image: *node_image
    commands:
      - apk add --no-cache bash
      - bash packages/mosaic/framework/tools/quality/scripts/verify-sanitized.sh
      # Resident line-count ceiling over framework-owned resident files
      # (Constitution + dispatcher + each RUNTIME.md slice). See DESIGN §7 / R9.
      - bash packages/mosaic/framework/tools/quality/scripts/check-resident-budget.sh --self-test
      - bash packages/mosaic/framework/tools/quality/scripts/check-resident-budget.sh

  # Blocking gate (#791): a framework upgrade must never write or delete an
  # operator-owned path. The HARD GATE proves an unanticipated operator sentinel
  # survives a keep-mode reseed byte-identical (with rsync present AND absent —
  # keep mode is a single cp-based path that must not depend on rsync), and that a
  # corrupt/empty/missing manifest aborts fail-closed leaving operator files
  # untouched (B2/B3). The rollback gate proves a mid-sync failure is rolled back
  # from the pre-update snapshot (B1). The durable-snapshot gate (#791 PR2) proves
  # the retained, operator-scoped pre-update backup is taken before any mutation
  # (0700/0600, secret never logged, retention-pruned) and that the post-sync
  # verify net restores any operator file a manifest bug lets the sync touch. The
  # migration matrix pins the v2→v3 contract-file semantics. Pure bash, no
  # node_modules — runs early alongside sanitization.
  upgrade-guard:
    image: *node_image
    commands:
      - apk add --no-cache bash rsync
      - bash packages/mosaic/framework/tools/quality/scripts/test-upgrade-manifest-guard.sh
      - bash packages/mosaic/framework/tools/quality/scripts/test-upgrade-rollback.sh
      - bash packages/mosaic/framework/tools/quality/scripts/test-upgrade-durable-snapshot.sh
      - bash packages/mosaic/framework/tools/quality/scripts/test-install-migration.sh

  typecheck:
    image: *node_image
    commands:
      - *enable_pnpm
      - pnpm typecheck
    depends_on:
      - install
      - sanitization
      - upgrade-guard

  # lint, format, and test are independent — run in parallel after typecheck
  lint:
    image: *node_image
    commands:
      - *enable_pnpm
      - pnpm lint
    depends_on:
      - typecheck

  format:
    image: *node_image
    commands:
      - *enable_pnpm
      - pnpm format:check
    depends_on:
      - typecheck

  test:
    image: *node_image
    environment:
      # Avoid the namespace-level Woodpecker DB service named "postgres".
      # The Kubernetes backend exposes service containers by step name.
      DATABASE_URL: postgresql://mosaic:mosaic@ci-postgres:5432/mosaic
    commands:
      - *enable_pnpm
      # postgresql-client (pg_isready) is baked into ci-base.
      # Wait up to 60s for CI postgres to be ready; fail fast if it never comes up.
      - |
        ready=0
        for i in $(seq 1 60); do
          if pg_isready -h ci-postgres -p 5432 -U mosaic; then
            ready=1
            break
          fi
          echo "Waiting for ci-postgres ($i/60)..."
          sleep 1
        done
        if [ "$ready" -ne 1 ]; then
          echo "ci-postgres did not become ready" >&2
          exit 1
        fi
      # Run migrations (DATABASE_URL is set in environment above)
      - pnpm --filter @mosaicstack/db run db:migrate
      # Run all tests
      - pnpm test
    depends_on:
      - typecheck

services:
  ci-postgres:
    image: pgvector/pgvector:pg17
    environment:
      POSTGRES_USER: mosaic
      POSTGRES_PASSWORD: mosaic
      POSTGRES_DB: mosaic
