# ci-arm64-advisory — Mac arm64 self-hosted ADVISORY fast-check lane.
#
# === WHY ===
#
# The amd64 Gitea runner pool (molecule-runner-1..20) is queue-contended
# (internal#418). This lane offloads the *genuinely container-independent*
# fast checks (Go build/vet/lint, shellcheck, Python lint) onto the Mac
# arm64 self-hosted runner so developers get a fast arm64 signal WITHOUT
# adding load to the starved amd64 pool — capability-honestly, as an
# additive pilot. Pilot ② of the Mac-CI strategy (CTO-delegated 2026-05-17).
#
# === NON-NEGOTIABLE SAFETY CONTRACT (the prime directive) ===
#
# This lane is **ADVISORY ONLY**. It is provably incapable of hanging a
# merge. Concretely:
#
#   1. It is a SEPARATE workflow file. `ci.yml` is byte-for-byte
#      untouched by this PR. The `CI / all-required` aggregator sentinel
#      and the five contexts it polls
#      (`CI / Detect changes|Platform (Go)|Canvas (Next.js)|
#      Shellcheck (E2E scripts)|Python Lint & Test (pull_request)`)
#      are unchanged. The canonical required gate stays 100% on the
#      existing amd64 pool.
#
#   2. The context this workflow emits is
#      `ci-arm64-advisory / fast-checks (pull_request)`. That string is
#      DELIBERATELY NOT present in, and this PR does NOT add it to:
#        - branch_protections/{main,staging}.status_check_contexts
#          (DB-verified pb 86/75 = exactly
#           ["CI / all-required (pull_request)",
#            "sop-checklist / all-items-acked (pull_request)"])
#        - audit-force-merge.yml REQUIRED_CHECKS env
#        - ci.yml `all-required` sentinel's hardcoded `required[]` list
#      Branch protection therefore never waits on this context. If the
#      Mac runner is absent / offline / removed, this workflow's status
#      simply never appears — and because nothing requires it, every
#      merge proceeds exactly as it does today. There is no path by
#      which a missing/red arm64 status blocks a merge.
#
#   3. `continue-on-error: true` on the job — even a genuine arm64-only
#      failure (toolchain drift, arch-specific test flake) is surfaced
#      as information, never as a merge blocker, for the duration of
#      the pilot.
#
#   4. The job carries a `github.event_name` `if:` gate. Beyond its
#      functional purpose this also keeps the job OUT of
#      `ci-required-drift.py:ci_job_names()` (which excludes
#      `github.event_name`/`github.ref`-gated jobs), so the hourly
#      ci-required-drift sentinel's F1 ("job not under sentinel needs")
#      cannot ever flag this advisory job. F2/F3 are untouched because
#      this context is absent from BP and from REQUIRED_CHECKS.
#      `lint-bp-context-emit-match` only fails on BP→emitter gaps; an
#      emitter without a BP context is explicitly informational there.
#
# === RUNNER TARGETING ===
#
# The Mac runner is `hongming-pc-runner-1`. The bare `self-hosted`
# label is POLLUTED in this Gitea instance: molecule-runner-1..20
# (the contended amd64 pool) also advertise `self-hosted`. Targeting
# bare `self-hosted` would route back onto the very pool we are trying
# to relieve — and onto amd64 hardware. We therefore require an
# AND-set of labels that ONLY the Mac satisfies. `macos-self-hosted`
# is Mac-exclusive (the amd64 pool does not carry it). Until the
# label-install burst (a10862b2) lands `self-hosted`+`macos-self-hosted`
# on the Mac, the runner's current unique label `hongming-pc-laptop`
# is also listed; AND-semantics over the labels a runner advertises
# means a job requiring [self-hosted, macos-self-hosted] can ONLY be
# claimed once the Mac advertises both. If neither label set is yet
# present on the Mac, the workflow stays queued harmlessly and is
# garbage-collected by the normal stale-run reaper — it blocks nothing
# (see safety contract point 2).
#
# === ROLLBACK ===
#
# Delete this single file (`git rm .gitea/workflows/ci-arm64-advisory.yml`)
# and merge. No branch-protection edit, no ci.yml edit, no
# REQUIRED_CHECKS edit is required to roll back, because none were made
# to roll forward. Zero blast radius either direction.

name: ci-arm64-advisory

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

# Per-ref cancel: a newer commit on the same ref supersedes the older
# advisory run. Distinct from ci.yml's `ci-${ref}` group so this lane
# never cancels (or is cancelled by) the canonical required CI.
concurrency:
  group: ci-arm64-advisory-${{ github.ref }}
  cancel-in-progress: true

env:
  GITHUB_SERVER_URL: https://git.moleculesai.app

jobs:
  fast-checks:
    name: fast-checks
    # AND-set: only the Mac arm64 runner advertises macos-self-hosted.
    # See "RUNNER TARGETING" header note for why bare self-hosted is unsafe.
    runs-on: [self-hosted, macos-self-hosted]
    # ADVISORY: never blocks. See safety contract point 3. mc#774
    # internal#418 — tracked: arm64 advisory pilot, non-gating by design.
    continue-on-error: true
    # event_name gate: functional (only meaningful on push/PR) AND keeps
    # this job out of ci-required-drift.py:ci_job_names() so F1 can never
    # flag it. See safety contract point 4.
    if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }}
    timeout-minutes: 20
    steps:
      - name: Provenance — advisory lane, non-gating
        run: |
          echo "This is the arm64 ADVISORY fast-check lane."
          echo "It does NOT gate merges. Canonical required CI is ci.yml"
          echo "on the amd64 pool. Arch: $(uname -m) on $(uname -s)."

      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      # ---- Go: build + vet + lint (container-independent: needs only the
      # Go toolchain; no amd64 ECR image, no docker-in-job). Race-detector
      # unit-test + coverage gates are deliberately NOT duplicated here —
      # those stay authoritative on amd64 ci.yml `Platform (Go)`. This lane
      # is fast-feedback for the compile/vet/lint surface only. ----
      - name: Setup Go
        uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
        with:
          go-version: 'stable'
      - name: Go build + vet (workspace-server)
        working-directory: workspace-server
        run: |
          go mod download
          go build ./cmd/server
          go vet ./...
      - name: golangci-lint (workspace-server)
        working-directory: workspace-server
        run: |
          go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2
          "$(go env GOPATH)/bin/golangci-lint" run --timeout 3m ./...

      # ---- Shellcheck (container-independent: shellcheck binary only).
      # Mirrors ci.yml `Shellcheck (E2E scripts)` bulk pass scope. ----
      - name: Install shellcheck (arm64)
        run: |
          if ! command -v shellcheck >/dev/null 2>&1; then
            echo "shellcheck not preinstalled on this self-hosted runner."
            echo "Attempting Homebrew install (Mac arm64)."
            brew install shellcheck || {
              echo "::warning::shellcheck unavailable on runner; advisory shellcheck skipped."
              exit 0
            }
          fi
          shellcheck --version
      - name: Shellcheck tests/e2e + infra/scripts
        run: |
          command -v shellcheck >/dev/null 2>&1 || { echo "skip"; exit 0; }
          find tests/e2e infra/scripts -type f -name '*.sh' -print0 \
            | xargs -0 shellcheck --severity=warning

      # ---- Python lint/compile (container-independent: CPython only).
      # Lint + import-compile surface; the authoritative pytest + coverage
      # floors stay on amd64 ci.yml `Python Lint & Test`. ----
      - name: Setup Python
        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: '3.11'
      - name: Python byte-compile (workspace)
        working-directory: workspace
        run: |
          python -m pip install --quiet ruff || true
          python -m compileall -q .
          if command -v ruff >/dev/null 2>&1; then
            ruff check . || echo "::warning::ruff findings (advisory only)"
          fi

      - name: Advisory summary
        if: always()
        run: |
          {
            echo "## arm64 advisory fast-checks complete"
            echo ""
            echo "This lane is **advisory** — it does not gate merges."
            echo "Authoritative required CI remains \`CI / all-required\`"
            echo "on the amd64 pool (\`ci.yml\`, unchanged by this PR)."
          } >> "$GITHUB_STEP_SUMMARY"
