# =============================================================================
# Polyglot CI - Izanagi AI (npm legado + Rust workspace + Go + Python + packages TS)
#
# Jobs 100% paralelos (nenhum "needs"): qualquer job vermelho falha o run
# inteiro => fail-fast global. Pipeline apenas de integracao; sem deploy.
#
# Supply chain: TODAS as actions de terceiros fixadas por SHA de commit
# completo (imutavel), resolvidos ao vivo na GitHub API em 2026-08-23.
# A tag major fica no comentario acima de cada "uses". Nunca referenciar
# tags mutaveis (@v4/@main/@latest) diretamente.
#
# Permissoes: somente leitura (least privilege). Nenhum job acessa secrets.
# =============================================================================

name: Polyglot CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  # Em PRs, o novo run cancela o run obsoleto anterior da mesma branch.
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
  # ---------------------------------------------------------------------------
  # 1) Framework npm legado na raiz (tsc + generate-manifest + 262 testes)
  #    Comandos validados localmente: npm ci / build / test => verde.
  #    ADR-006: "npm run verify" (= verify-build.js sandbox install + testes)
  #    foi ABSORVIDO do extinto trigger push/PR do publish.yml, que virou CD
  #    exclusivo de tag/release. Push/PR mantém paridade total de verificação.
  # ---------------------------------------------------------------------------
  legacy-npm:
    name: legacy npm (root)
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      # actions/checkout@v7
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      # actions/setup-node@v6 - Node 24 por paridade com dev local (v24.18.0);
      # engines: raiz declara >=18, pacotes poliglotas (sdk/cli) declaram >=22.
      - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f
        with:
          node-version: '24'
          cache: npm # usa o package-lock.json commitado na raiz
      - name: Install (npm ci without lifecycle scripts)
        run: npm ci --ignore-scripts
      - name: Build
        run: npm run build
      - name: Test
        run: npm test
      # Requer dist/ do step Build anterior (verify não builda; consome).
      - name: Verify (sandbox install)
        run: npm run verify

  # ---------------------------------------------------------------------------
  # 2) Rust workspace (crates/izanagi_core + crates/izanagi_mcp)
  #
  # HISTORICO DAS DECISOES (medidas localmente, agora RESOLVIDAS):
  #
  # a) "cargo fmt --check" estava desativado porque o codigo falhava o check
  #    com ~44 pontos de diff. A frente de endurecimento Rust rodou
  #    `cargo fmt` nos dois crates => gate ATIVADO abaixo e bloqueante.
  #
  # b) Clippy estava NAO-bloqueante por 4 warnings pre-existentes
  #    (manual_contains, needless_range_loop, collapsible_if, needless_borrow).
  #    Todos corrigidos semanticamente (zero #[allow]) => -D warnings ATIVADO.
  # ---------------------------------------------------------------------------
  rust:
    name: rust (fmt-check / clippy-D-warnings / test / wasm-check)
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      # actions/checkout@v7
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      # dtolnay/rust-toolchain@stable (branch mutavel por design do autor;
      # o SHA congela o CODIGO da action, nao a versao do Rust instalada)
      - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c
        with:
          toolchain: stable
          components: clippy, rustfmt
      # Swatinem/rust-cache@v2 - a workspace Cargo E a raiz do repo.
      # NOTA: input "workspaces: true" foi REJEITADO de proposito: lendo o
      # source oficial v2 (src/config.ts), o valor seria tratado como path e
      # resolvido para "<repo>/true" (inexistente), degradando o cache
      # silenciosamente. O default ("." = raiz) e o correto aqui.
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6
      - name: 'Format check (blocking)'
        run: cargo fmt --check
      - name: 'Clippy (blocking: -D warnings)'
        run: cargo clippy --workspace --all-targets -- -D warnings
      - name: Test
        run: cargo test --workspace
      # IMPORTANTE: a forma "cargo check --features wasm" NA RAIZ de workspace
      # virtual eh SILENCIOSAMENTE IGNORADA pelo cargo (verificado via
      # "cargo metadata": features=[] e cargo tree sem wasm-bindgen) => passaria
      # verde sem testar nada. A forma correta exige -p no membro dono da
      # feature (ADR-003); com -p, "cargo tree" mostra as 8 deps wasm-bindgen.
      - name: Check wasm feature (ADR-003)
        run: cargo check -p izanagi_core --features wasm

  # ---------------------------------------------------------------------------
  # 3) wasm-build - prova end-to-end do ADR-003 (bindings wasm-bindgen)
  #
  # EXPECTATIVA / MOTIVO DO COMENTARIO: este ambiente de desenvolvimento NAO
  # tem rustup instalado (verificado: "which rustup" vazio), portanto NENHUM
  # comando deste job pôde ser executado localmente. O job foi mantido porque
  # o ADR-003 declara exatamente este fluxo e o crate ja esta preparado:
  #   - crates/izanagi_core/Cargo.toml: crate-type = ["lib", "cdylib"] com
  #     comentario dizendo que o cdylib gera o .wasm consumido pelo
  #     wasm-bindgen-cli;
  #   - Cargo.lock fixa wasm-bindgen 0.2.127 (grep confirmado) => a CLI DEVE
  #     ser a mesma versao exata, senao a geracao falha.
  # Riscos assumidos ate o primeiro run no CI: disponibilidade do target
  # wasm32-unknown-unknown via rustup (padrao da action dtolnay), existencia
  # do artefato izanagi_core.wasm no path padrao do cargo e aceitacao do
  # binario musl estatico no runner ubuntu-latest (x86_64).
  # ---------------------------------------------------------------------------
  wasm-build:
    name: wasm32 build + bindgen (ADR-003)
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      # actions/checkout@v7
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      # dtolnay/rust-toolchain@stable - "targets" instala o target cross junto
      - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c
        with:
          toolchain: stable
          targets: wasm32-unknown-unknown
      - uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6
      # Binario pre-compilado oficial (release 0.2.127 publica asset musl
      # x86_64; hash sha256 conferido contra o .sha256sum publicado).
      # Alternativa seria "cargo install wasm-bindgen-cli --version 0.2.127",
      # porem compila na hora (~minutos). Versao TEM que bater com Cargo.lock.
      - name: Install wasm-bindgen-cli 0.2.127 (match Cargo.lock)
        run: |
          curl -fsSL -o /tmp/wbg.tar.gz \
            https://github.com/wasm-bindgen/wasm-bindgen/releases/download/0.2.127/wasm-bindgen-0.2.127-x86_64-unknown-linux-musl.tar.gz
          echo "61d4a7dc85acfa0d2354ccc0b8361928c7e52a746d17f28ebaa795ed3dc1614a  /tmp/wbg.tar.gz" | sha256sum -c -
          tar -xzf /tmp/wbg.tar.gz -C /tmp
          sudo mv /tmp/wasm-bindgen-0.2.127-x86_64-unknown-linux-musl/wasm-bindgen /usr/local/bin/
          wasm-bindgen --version | grep -qx 'wasm-bindgen 0.2.127'
      - name: Build cdylib for wasm32
        run: cargo build -p izanagi_core --features wasm --target wasm32-unknown-unknown
      # Flags minimas de proposito (nenhuma flag inventada): apenas --out-dir.
      # Diretorio de saida neutro (target/wasm-bindgen); nao existe convencao
      # de output documentada no repo (greps em *.md/*.toml/*.rs confirmaram),
      # entao o job apenas PROVA que a geracao funciona ponta a ponta.
      - name: Generate JS bindings
        run: wasm-bindgen target/wasm32-unknown-unknown/debug/izanagi_core.wasm --out-dir target/wasm-bindgen

  # ---------------------------------------------------------------------------
  # 4) Go - swarm orchestrator (go-services/swarm_orchestrator)
  #    go.mod declara "go 1.26.1"; setup-go le a versao DIRETO do arquivo,
  #    eliminando drift entre workflow e modulo. build/vet/test validados
  #    localmente com go1.26.1: todos verdes.
  # ---------------------------------------------------------------------------
  go:
    name: go swarm orchestrator
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      # actions/checkout@v7
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      # actions/setup-go@v5
      - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff
        with:
          go-version-file: go-services/swarm_orchestrator/go.mod
          cache-dependency-path: go-services/swarm_orchestrator/go.sum
      - name: Build
        working-directory: go-services/swarm_orchestrator
        run: go build ./...
      - name: Vet
        working-directory: go-services/swarm_orchestrator
        run: go vet ./...
      - name: Test
        working-directory: go-services/swarm_orchestrator
        run: go test ./...

  # ---------------------------------------------------------------------------
  # 5) Python - python-engine/ast_analyzer (pytest)
  #
  # DECISAO DE VERSAO (3.14, nao 3.12): o venv local roda CPython 3.14.3 com
  # os pins exatos de requirements-dev.txt e os 70 testes passam. Risco de
  # wheel foi descartado consultando o PyPI: tree-sitter 0.25.2 publica wheel
  # cp314 manylinux; tree-sitter-{python,go,typescript} publicam wheels abi3
  # (cp310/cp39) que sao forward-compatible com 3.14 => instalacao binaria,
  # zero compilacao de extensao no runner. Nao havia duvida real: 3.12 seria
  # conservadorismo sem evidencia.
  # ---------------------------------------------------------------------------
  python:
    name: python ast analyzer (3.14)
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      # actions/checkout@v7
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      # actions/setup-python@v5
      - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
        with:
          python-version: '3.14'
      # Venv explicito = paridade com o ambiente local provado (.venv).
      - name: Create venv
        working-directory: python-engine
        run: python -m venv .venv
      # Deps EXATAS confirmadas por pip freeze do venv local.
      - name: Install pinned dev dependencies
        working-directory: python-engine
        run: .venv/bin/python -m pip install -r requirements-dev.txt
      # O pacote em si: pyproject.toml declara dependencies=[] (tree-sitter e
      # extra opcional ja coberto acima), entao "pip install -e ." nao puxa
      # nada alem do build backend. Espelha o venv local (instalacao editable).
      - name: Install package (editable)
        working-directory: python-engine
        run: .venv/bin/python -m pip install -e .
      - name: Test
        working-directory: python-engine
        run: .venv/bin/python -m pytest tests/ -q

  # ---------------------------------------------------------------------------
  # 6) ts-packages - packages/sdk (test) e packages/cli (build)
  #    Matriz paralela; fail-fast default (true) cancela o irmao se um falhar.
  #    Ambos tem package-lock.json COMMITADO => npm ci (deterministico e
  #    falha rapido se lock/package.json divergirem). Validado localmente:
  #    sdk => 41 testes verdes; cli => dist/cli/src/index.js gerado.
  # ---------------------------------------------------------------------------
  ts-packages:
    name: ts ${{ matrix.package }}
    runs-on: ubuntu-latest
    timeout-minutes: 15
    strategy:
      fail-fast: true
      matrix:
        include:
          - package: sdk
            script: test # npm test = tsc + node --test dist/tests/*
          - package: cli
            script: build # npm run build = tsc -p tsconfig.json
    steps:
      # actions/checkout@v7
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      # actions/setup-node@v6 - cache por lockfile do pacote da matriz
      - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f
        with:
          node-version: '24'
          cache: npm
          cache-dependency-path: packages/${{ matrix.package }}/package-lock.json
      - name: Install (npm ci)
        working-directory: packages/${{ matrix.package }}
        run: npm ci
      - name: Verify (${{ matrix.script }})
        working-directory: packages/${{ matrix.package }}
        run: npm run ${{ matrix.script }}
