name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read

jobs:
  lint:
    name: Lint (${{ matrix.service }})
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - service: auth
            workspace: claw-auth-service
            prisma: true
          - service: chat
            workspace: claw-chat-service
            prisma: true
          - service: connector
            workspace: claw-connector-service
            prisma: true
          - service: routing
            workspace: claw-routing-service
            prisma: true
          - service: memory
            workspace: claw-memory-service
            prisma: true
          - service: file
            workspace: claw-file-service
            prisma: true
          - service: ollama
            workspace: claw-ollama-service
            prisma: true
          - service: audit
            workspace: claw-audit-service
            prisma: false
          - service: image
            workspace: claw-image-service
            prisma: true
          - service: file-generation
            workspace: claw-file-generation-service
            prisma: true
          - service: workspace
            workspace: claw-workspace-service
            prisma: true
          - service: agent
            workspace: claw-agent-service
            prisma: true
          - service: research
            workspace: claw-research-service
            prisma: true
          - service: llamacpp
            workspace: claw-llamacpp-service
            prisma: true
          - service: client-logs
            workspace: claw-client-logs-service
            prisma: false
          - service: server-logs
            workspace: claw-server-logs-service
            prisma: false
          - service: health
            workspace: claw-health-service
            prisma: false
          - service: frontend
            workspace: claw-frontend
            prisma: false
          - service: shared-types
            workspace: '@claw/shared-types'
            prisma: false
          - service: shared-constants
            workspace: '@claw/shared-constants'
            prisma: false
          - service: shared-rabbitmq
            workspace: '@claw/shared-rabbitmq'
            prisma: false
          - service: shared-auth
            workspace: '@claw/shared-auth'
            prisma: false
          - service: shared-utilities
            workspace: '@claw/shared-utilities'
            prisma: false
          - service: shared-entitlements
            workspace: '@claw/shared-entitlements'
            prisma: false
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci --ignore-scripts

      - name: Link tsgo binary (@typescript/native-preview)
        run: npm rebuild @typescript/native-preview

      - name: Build shared packages
        run: |
          cd packages/shared-types && npx tsgo -p tsconfig.build.json
          cd ../shared-constants && npx tsgo -p tsconfig.build.json
          cd ../shared-rabbitmq && npx tsgo -p tsconfig.build.json
          cd ../shared-auth && npx tsgo -p tsconfig.build.json
          cd ../shared-utilities && npx tsgo -p tsconfig.build.json
          cd ../shared-entitlements && npx tsgo -p tsconfig.build.json

      - name: Generate Prisma client
        if: matrix.prisma == true
        run: cd apps/claw-${{ matrix.service }}-service && npx prisma generate

      - name: Lint
        run: npm run lint --workspace=${{ matrix.workspace }}

  typecheck:
    name: Typecheck (${{ matrix.service }})
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - service: auth
            workspace: claw-auth-service
            prisma: true
          - service: chat
            workspace: claw-chat-service
            prisma: true
          - service: connector
            workspace: claw-connector-service
            prisma: true
          - service: routing
            workspace: claw-routing-service
            prisma: true
          - service: memory
            workspace: claw-memory-service
            prisma: true
          - service: file
            workspace: claw-file-service
            prisma: true
          - service: ollama
            workspace: claw-ollama-service
            prisma: true
          - service: audit
            workspace: claw-audit-service
            prisma: false
          - service: image
            workspace: claw-image-service
            prisma: true
          - service: file-generation
            workspace: claw-file-generation-service
            prisma: true
          - service: workspace
            workspace: claw-workspace-service
            prisma: true
          - service: agent
            workspace: claw-agent-service
            prisma: true
          - service: research
            workspace: claw-research-service
            prisma: true
          - service: llamacpp
            workspace: claw-llamacpp-service
            prisma: true
          - service: client-logs
            workspace: claw-client-logs-service
            prisma: false
          - service: server-logs
            workspace: claw-server-logs-service
            prisma: false
          - service: health
            workspace: claw-health-service
            prisma: false
          - service: frontend
            workspace: claw-frontend
            prisma: false
          - service: shared-types
            workspace: '@claw/shared-types'
            prisma: false
          - service: shared-constants
            workspace: '@claw/shared-constants'
            prisma: false
          - service: shared-rabbitmq
            workspace: '@claw/shared-rabbitmq'
            prisma: false
          - service: shared-auth
            workspace: '@claw/shared-auth'
            prisma: false
          - service: shared-utilities
            workspace: '@claw/shared-utilities'
            prisma: false
          - service: shared-entitlements
            workspace: '@claw/shared-entitlements'
            prisma: false
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci --ignore-scripts

      - name: Link tsgo binary (@typescript/native-preview)
        run: npm rebuild @typescript/native-preview

      - name: Build shared packages
        run: |
          cd packages/shared-types && npx tsgo -p tsconfig.build.json
          cd ../shared-constants && npx tsgo -p tsconfig.build.json
          cd ../shared-rabbitmq && npx tsgo -p tsconfig.build.json
          cd ../shared-auth && npx tsgo -p tsconfig.build.json
          cd ../shared-utilities && npx tsgo -p tsconfig.build.json
          cd ../shared-entitlements && npx tsgo -p tsconfig.build.json

      - name: Generate Prisma client
        if: matrix.prisma == true
        run: cd apps/claw-${{ matrix.service }}-service && npx prisma generate

      - name: Typecheck
        run: npm run typecheck --workspace=${{ matrix.workspace }}

  test:
    name: Test (${{ matrix.service }})
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - service: auth
            workspace: claw-auth-service
            prisma: true
          - service: chat
            workspace: claw-chat-service
            prisma: true
          - service: connector
            workspace: claw-connector-service
            prisma: true
          - service: routing
            workspace: claw-routing-service
            prisma: true
          - service: memory
            workspace: claw-memory-service
            prisma: true
          - service: file
            workspace: claw-file-service
            prisma: true
          - service: ollama
            workspace: claw-ollama-service
            prisma: true
          - service: audit
            workspace: claw-audit-service
            prisma: false
          - service: image
            workspace: claw-image-service
            prisma: true
          - service: file-generation
            workspace: claw-file-generation-service
            prisma: true
          - service: workspace
            workspace: claw-workspace-service
            prisma: true
          - service: agent
            workspace: claw-agent-service
            prisma: true
          - service: research
            workspace: claw-research-service
            prisma: true
          - service: llamacpp
            workspace: claw-llamacpp-service
            prisma: true
          - service: client-logs
            workspace: claw-client-logs-service
            prisma: false
          - service: server-logs
            workspace: claw-server-logs-service
            prisma: false
          - service: health
            workspace: claw-health-service
            prisma: false
          - service: frontend
            workspace: claw-frontend
            prisma: false
          - service: shared-types
            workspace: '@claw/shared-types'
            prisma: false
          - service: shared-constants
            workspace: '@claw/shared-constants'
            prisma: false
          - service: shared-rabbitmq
            workspace: '@claw/shared-rabbitmq'
            prisma: false
          - service: shared-auth
            workspace: '@claw/shared-auth'
            prisma: false
          - service: shared-utilities
            workspace: '@claw/shared-utilities'
            prisma: false
          - service: shared-entitlements
            workspace: '@claw/shared-entitlements'
            prisma: false
    env:
      # vitest (claw-frontend) on Node v24 + tinypool 1.x exhausts the
      # default ~4GB v8 heap during worker-pool teardown. All tests pass,
      # but the post-run cleanup OOMs and the npm script exits 1. Bump
      # the heap to 8GB for every test job — backend services unchanged
      # (jest is well under 1GB) and only the frontend job actually
      # benefits, but keeping it global avoids per-matrix divergence.
      NODE_OPTIONS: --max-old-space-size=8192
      # Auth
      JWT_SECRET: this_is_a_test_secret_that_is_32chars_long
      ENCRYPTION_KEY: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
      # Infrastructure (fake — unit tests mock all connections)
      REDIS_URL: redis://localhost:6379
      RABBITMQ_URL: amqp://guest:guest@localhost:5672
      OLLAMA_BASE_URL: http://localhost:11434
      # Inter-service URLs
      FILE_SERVICE_URL: http://localhost:4006
      CONNECTOR_SERVICE_URL: http://localhost:4003
      # PostgreSQL — each service reads only its own var
      AUTH_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      CHAT_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      CONNECTOR_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      ROUTING_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      MEMORY_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      FILES_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      OLLAMA_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      IMAGE_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      FILE_GENERATION_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      WORKSPACE_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      AGENT_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      RESEARCH_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      LLAMACPP_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
      LLAMACPP_SERVICE_URL: http://localhost:4017
      LLAMACPP_DATA_PATH: /tmp/llamacpp-test
      # MongoDB
      AUDIT_MONGODB_URI: mongodb://localhost:27017/test
      CLIENT_LOGS_MONGODB_URI: mongodb://localhost:27017/test
      SERVER_LOGS_MONGODB_URI: mongodb://localhost:27017/test
      # Workspace runtime gates (Phase E close-out, 2026-05-02)
      # These all have Zod defaults; the explicit values here mirror prod and
      # ensure the spec env-fixture types match without relying on defaults.
      WORKSPACE_SUGGESTION_FACTORY_RATE_PER_HOUR: '100'
      WEBHOOK_CONNECTOR_REQUESTS_PER_MINUTE: '60'
      AUTO_SUGGEST_INBOX_REPLY_CRON: '0 */15 * * * *'
      AUTO_SUGGEST_INBOX_REPLY_LOOKBACK_HOURS: '48'
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci --ignore-scripts

      - name: Link tsgo binary (@typescript/native-preview)
        run: npm rebuild @typescript/native-preview

      - name: Build shared packages
        run: |
          cd packages/shared-types && npx tsgo -p tsconfig.build.json
          cd ../shared-constants && npx tsgo -p tsconfig.build.json
          cd ../shared-rabbitmq && npx tsgo -p tsconfig.build.json
          cd ../shared-auth && npx tsgo -p tsconfig.build.json
          cd ../shared-utilities && npx tsgo -p tsconfig.build.json
          cd ../shared-entitlements && npx tsgo -p tsconfig.build.json

      - name: Generate Prisma client
        if: matrix.prisma == true
        run: cd apps/claw-${{ matrix.service }}-service && npx prisma generate

      - name: Hoist vite to root (frontend hoisting fix)
        if: matrix.service == 'frontend'
        run: npm install --no-save vite

      - name: Run tests
        run: npm run test --workspace=${{ matrix.workspace }}

  build:
    name: Build (${{ matrix.service }})
    runs-on: ubuntu-latest
    needs: [lint, typecheck, test]
    strategy:
      fail-fast: false
      matrix:
        include:
          - service: auth
            workspace: claw-auth-service
            prisma: true
          - service: chat
            workspace: claw-chat-service
            prisma: true
          - service: connector
            workspace: claw-connector-service
            prisma: true
          - service: routing
            workspace: claw-routing-service
            prisma: true
          - service: memory
            workspace: claw-memory-service
            prisma: true
          - service: file
            workspace: claw-file-service
            prisma: true
          - service: ollama
            workspace: claw-ollama-service
            prisma: true
          - service: audit
            workspace: claw-audit-service
            prisma: false
          - service: image
            workspace: claw-image-service
            prisma: true
          - service: file-generation
            workspace: claw-file-generation-service
            prisma: true
          - service: workspace
            workspace: claw-workspace-service
            prisma: true
          - service: agent
            workspace: claw-agent-service
            prisma: true
          - service: research
            workspace: claw-research-service
            prisma: true
          - service: llamacpp
            workspace: claw-llamacpp-service
            prisma: true
          - service: client-logs
            workspace: claw-client-logs-service
            prisma: false
          - service: server-logs
            workspace: claw-server-logs-service
            prisma: false
          - service: health
            workspace: claw-health-service
            prisma: false
          - service: frontend
            workspace: claw-frontend
            prisma: false
          - service: shared-types
            workspace: '@claw/shared-types'
            prisma: false
          - service: shared-constants
            workspace: '@claw/shared-constants'
            prisma: false
          - service: shared-rabbitmq
            workspace: '@claw/shared-rabbitmq'
            prisma: false
          - service: shared-auth
            workspace: '@claw/shared-auth'
            prisma: false
          - service: shared-utilities
            workspace: '@claw/shared-utilities'
            prisma: false
          - service: shared-entitlements
            workspace: '@claw/shared-entitlements'
            prisma: false
    env:
      # next build (claw-frontend) hits the same v8-heap ceiling that
      # the test job documents. Apply globally for parity — backend
      # builds are small and don't notice.
      NODE_OPTIONS: --max-old-space-size=8192
    steps:
      - uses: actions/checkout@v6

      - uses: actions/setup-node@v6
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci --ignore-scripts

      - name: Link tsgo binary (@typescript/native-preview)
        run: npm rebuild @typescript/native-preview

      - name: Build shared packages
        run: |
          cd packages/shared-types && npx tsgo -p tsconfig.build.json
          cd ../shared-constants && npx tsgo -p tsconfig.build.json
          cd ../shared-rabbitmq && npx tsgo -p tsconfig.build.json
          cd ../shared-auth && npx tsgo -p tsconfig.build.json
          cd ../shared-utilities && npx tsgo -p tsconfig.build.json
          cd ../shared-entitlements && npx tsgo -p tsconfig.build.json

      - name: Generate Prisma client
        if: matrix.prisma == true
        run: cd apps/claw-${{ matrix.service }}-service && npx prisma generate

      - name: Build
        run: npm run build --workspace=${{ matrix.workspace }}
