# Five AI-code CI checks
# Drop-in companion to the article. Add these as steps in your existing
# GitHub Actions workflow (or adapt to your CI of choice).
#
# Each block is independent. You can add them all at once or one at a time.

name: ai-code-verification

on:
  pull_request:
    branches: [main]

jobs:
  verification:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # =====================================================================
      # 1. Independent test rerun
      # Catches: agent self-reporting tests passed without actually running.
      # =====================================================================
      - name: Independent test container
        id: independent_test
        run: |
          docker run --rm -v $PWD:/app -w /app node:20 npm test
          echo "exit=$?" >> "$GITHUB_OUTPUT"

      - name: Compare to agent-reported status
        if: always()
        run: |
          if [ "${{ steps.independent_test.outputs.exit }}" != "0" ]; then
            echo "Independent run failed. Block merge."
            exit 1
          fi

      # =====================================================================
      # 2. Hallucinated dependency check
      # Catches: package names AI added that do not exist on the registry.
      # =====================================================================
      - name: Verify added dependencies exist
        run: |
          added=$(git diff origin/main -- package.json | \
                  grep '^+' | grep -oP '"\K[^"]+(?=":)' || true)
          for pkg in $added; do
            if [ -z "$pkg" ]; then continue; fi
            if ! npm view "$pkg" name >/dev/null 2>&1; then
              echo "Hallucinated or unregistered package: $pkg"
              exit 1
            fi
          done

      # Python equivalent:
      # for pkg in $added; do
      #   pip index versions "$pkg" >/dev/null 2>&1 || { echo "Missing: $pkg"; exit 1; }
      # done
      #
      # Rust equivalent:
      # for pkg in $added; do
      #   cargo search "$pkg" --limit 1 | grep -q "^$pkg " || { echo "Missing: $pkg"; exit 1; }
      # done

      # =====================================================================
      # 3. Duplication delta check
      # Catches: AI rewriting helpers that already exist in the codebase.
      # =====================================================================
      - name: Duplication delta
        run: |
          npx jscpd --silent --threshold 0 --min-lines 5 \
                    --reporters json --output ./jscpd-pr ./src
          git stash
          git checkout origin/main -- ./src
          npx jscpd --silent --threshold 0 --min-lines 5 \
                    --reporters json --output ./jscpd-main ./src
          git checkout HEAD -- ./src
          git stash pop || true
          pr=$(jq '.statistics.total.duplicatedLines' jscpd-pr/jscpd-report.json)
          base=$(jq '.statistics.total.duplicatedLines' jscpd-main/jscpd-report.json)
          delta=$((pr - base))
          echo "Duplication delta: $delta lines"
          if [ "$delta" -gt 30 ]; then
            echo "PR adds $delta duplicated lines (threshold 30)"
            exit 1
          fi

      # =====================================================================
      # 4. Env file consistency
      # Catches: .env.example updated without matching schema and deploy config.
      # Adapt the paths to your stack.
      # =====================================================================
      - name: Env file consistency
        run: |
          keys_example=$(grep -E '^[A-Z_]+=' .env.example | cut -d= -f1 | sort)
          keys_schema=$(grep -oE 'process\.env\.[A-Z_]+' src/env.ts 2>/dev/null \
                        | sort -u | sed 's/process\.env\.//')
          keys_deploy=$(grep -E '^\s*[A-Z_]+:' deploy/production.yaml 2>/dev/null \
                        | awk '{print $1}' | tr -d ':' | sort)
          missing_schema=$(comm -23 <(echo "$keys_example") <(echo "$keys_schema") || true)
          missing_deploy=$(comm -23 <(echo "$keys_example") <(echo "$keys_deploy") || true)
          if [ -n "$missing_schema" ]; then
            echo "Keys in .env.example missing from schema:"
            echo "$missing_schema"
            exit 1
          fi
          if [ -n "$missing_deploy" ]; then
            echo "Keys in .env.example missing from deploy config:"
            echo "$missing_deploy"
            exit 1
          fi

      # =====================================================================
      # 5. Awaited-DB-in-loop detector
      # Catches: N+1 query patterns AI writes by default.
      # =====================================================================
      - name: Detect awaited DB calls inside loops
        run: |
          matches=$(grep -rEn 'for \([^)]+\) \{[^}]*await (db|prisma|knex|orm)\.' src/ 2>/dev/null || true)
          if [ -n "$matches" ]; then
            echo "Awaited DB call inside loop. Use Promise.all, batch query, or DataLoader."
            echo "$matches"
            exit 1
          fi

# =====================================================================
# Notes
# =====================================================================
# - All five blocks run in under one minute combined on a typical pipeline.
# - The thresholds (30 duplicated lines, etc.) are illustrative.
#   Calibrate against your codebase baseline.
# - The grep patterns in #5 catch the most common syntactic shape.
#   Replace with an AST query (jscodeshift, tree-sitter) for stronger coverage.
# - Test independently before adding all five at once. The first PR
#   after enabling them will likely fail at least one check; that is
#   the system working as intended.
