name: Convoy metrics gate

# Forces convoy PRs to include role-event telemetry. Without this gate, the
# pipeline produces work but no signal — exactly what happened during the
# Jun 5-11 experiment window when 8 convoy PRs shipped without logging a
# single .metrics.jsonl row (see analytics/v0.4-beta1-results.md in
# agent-pipeline).
#
# Triggers: PR titled `convoy:` (case-insensitive prefix). If a convoy PR
# does NOT add at least one new role-event line to .convoys/.metrics.jsonl,
# this check fails. Bypass: add the `skip-metrics` label to the PR (rare,
# document the reason in the PR body).
#
# Other PRs are no-op (skip the gate).

on:
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened, edited, labeled, unlabeled]

permissions:
  contents: read
  pull-requests: read

jobs:
  gate:
    name: Require role-event telemetry on convoy PRs
    runs-on: [self-hosted, axiom]
    steps:
      - name: Inspect PR
        id: inspect
        uses: actions/github-script@v7
        with:
          script: |
            const pr = context.payload.pull_request;
            const title = pr.title || '';
            const labels = (pr.labels || []).map(l => l.name);
            const isConvoy = /^convoy:/i.test(title);
            const hasBypass = labels.includes('skip-metrics');
            core.setOutput('is_convoy', isConvoy ? 'true' : 'false');
            core.setOutput('has_bypass', hasBypass ? 'true' : 'false');
            core.info(`title="${title}" is_convoy=${isConvoy} has_bypass=${hasBypass}`);
            if (hasBypass) {
              core.warning(`skip-metrics label present on PR #${pr.number} — gate will exit early. Document the reason in the PR body.`);
            }

      - name: Skip — not a convoy PR
        if: steps.inspect.outputs.is_convoy != 'true'
        run: |
          echo "PR title is not 'convoy:' — gate is no-op for this PR."

      - name: Skip — bypass label present
        if: steps.inspect.outputs.is_convoy == 'true' && steps.inspect.outputs.has_bypass == 'true'
        run: |
          echo "::warning::skip-metrics label bypass. Metrics gate not enforced for this PR."

      - name: Checkout PR head
        if: steps.inspect.outputs.is_convoy == 'true' && steps.inspect.outputs.has_bypass != 'true'
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Verify metrics rows added
        if: steps.inspect.outputs.is_convoy == 'true' && steps.inspect.outputs.has_bypass != 'true'
        run: |
          set -euo pipefail

          BASE_SHA="${{ github.event.pull_request.base.sha }}"
          HEAD_SHA="${{ github.event.pull_request.head.sha }}"
          METRICS=".convoys/.metrics.jsonl"

          if [ ! -f "$METRICS" ]; then
            echo "::error::Convoy PR but $METRICS does not exist. The L2 roles must call scripts/log-convoy-event.sh after each hand-off — see .cursor/agents/role-*.md 'Metrics' sections."
            exit 1
          fi

          ADDED_LINES=$(git diff "$BASE_SHA"..."$HEAD_SHA" -- "$METRICS" | grep -c '^+{' || true)

          if [ "$ADDED_LINES" -eq 0 ]; then
            echo "::error::Convoy PR did not add any rows to $METRICS."
            echo "::error::Did the L2 roles call scripts/log-convoy-event.sh after their hand-off? See .cursor/agents/role-*.md 'Metrics' section."
            echo "::error::To bypass intentionally (rare), add 'skip-metrics' label to the PR and document why in the PR body."
            exit 1
          fi

          if ! git diff "$BASE_SHA"..."$HEAD_SHA" -- "$METRICS" | grep -q '"convoy"'; then
            echo "::warning::Added lines do not appear to be well-formed JSON with a 'convoy' field. Verify scripts/log-convoy-event.sh ran cleanly."
          fi

          echo "::notice::Convoy metrics gate passed: $ADDED_LINES new role-event row(s) added to $METRICS."
