name: Skills Index Freshness Check

# Belt-and-suspenders for the twice-daily build_skills_index pipeline.
# If the live /docs/api/skills-index.json ever goes more than 26 hours
# stale OR the file disappears entirely OR a major source has collapsed,
# this workflow opens a GitHub issue so we hear about it before users do.
#
# Triggered every 4 hours so we catch a stuck cron within one tick.

on:
  schedule:
    - cron: '0 */4 * * *'
  workflow_dispatch:

permissions:
  contents: read
  issues: write

jobs:
  check-freshness:
    if: github.repository == 'NousResearch/hermes-agent'
    runs-on: ubuntu-latest
    timeout-minutes: 10
    environment: trusted-automation
    steps:
      - name: Probe live index
        id: probe
        run: |
          set -e
          URL="https://hermes-agent.nousresearch.com/docs/api/skills-index.json"
          echo "Probing $URL"
          # -L follows redirects; -f fails on HTTP errors; -s suppresses progress
          if ! curl -fsSL --retry 3 --retry-delay 10 -o /tmp/skills-index.json "$URL"; then
            echo "status=fetch-failed" >> "$GITHUB_OUTPUT"
            echo "detail=Could not download $URL" >> "$GITHUB_OUTPUT"
            exit 0
          fi
          # Validate + extract generated_at and per-source counts
          python3 <<'PY' >> "$GITHUB_OUTPUT"
          import json, sys
          from datetime import datetime, timezone

          try:
              with open("/tmp/skills-index.json") as f:
                  data = json.load(f)
          except Exception as e:
              print(f"status=parse-failed")
              print(f"detail=JSON decode error: {e}")
              sys.exit(0)

          generated_at = data.get("generated_at", "")
          total = data.get("skill_count", 0)
          skills = data.get("skills", [])
          if not isinstance(skills, list):
              print("status=invalid-shape")
              print(f"detail=skills field is not a list (got {type(skills).__name__})")
              sys.exit(0)

          # Per-source counts
          from collections import Counter
          by_src = Counter(s.get("source", "") for s in skills)

          # Freshness
          age_hours = None
          try:
              ts = datetime.fromisoformat(generated_at.replace("Z", "+00:00"))
              age_hours = (datetime.now(timezone.utc) - ts).total_seconds() / 3600
          except Exception:
              pass

          # Floors — same as build_skills_index.py EXPECTED_FLOORS.
          floors = {
              "skills.sh": 100,
              "lobehub": 100,
              "clawhub": 50,
              "official": 50,
              "github": 30,
              "browse-sh": 50,
          }
          issues = []
          if age_hours is not None and age_hours > 26:
              issues.append(f"Index is {age_hours:.1f}h old (limit 26h)")
          for src, floor in floors.items():
              count = by_src.get(src, 0)
              if src == "skills.sh":
                  count = by_src.get("skills.sh", 0) + by_src.get("skills-sh", 0)
              if count < floor:
                  issues.append(f"{src}: {count} < {floor}")
          if total < 1500:
              issues.append(f"total skills: {total} < 1500")

          if issues:
              detail = "; ".join(issues)
              print("status=degraded")
              # GITHUB_OUTPUT doesn't allow newlines without explicit delimiter
              print(f"detail={detail}")
          else:
              print("status=ok")
              print(f"detail=Index OK — {total} skills, generated {generated_at}")
              by_summary = ", ".join(f"{k}={v}" for k, v in by_src.most_common(8))
              print(f"summary={by_summary}")
          PY

      - name: Report status
        run: |
          echo "Probe status: ${{ steps.probe.outputs.status }}"
          echo "Detail:       ${{ steps.probe.outputs.detail }}"
          if [ -n "${{ steps.probe.outputs.summary }}" ]; then
            echo "Summary:      ${{ steps.probe.outputs.summary }}"
          fi

      - name: Get GitHub App token
        if: steps.probe.outputs.status != 'ok'
        id: app-token
        uses: ./.github/actions/get-app-token
        with:
          client-id: ${{ vars.APP_CLIENT_ID }}
          private-key: ${{ secrets.APP_PRIVATE_KEY }}

      - name: Open issue on degraded / failed probe
        if: steps.probe.outputs.status != 'ok'
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}
          STATUS: ${{ steps.probe.outputs.status }}
          DETAIL: ${{ steps.probe.outputs.detail }}
        run: |
          # Find existing open issue by title prefix so we don't spam — we
          # append a comment instead of opening a new one each tick.
          TITLE_PREFIX="[skills-index-watchdog]"
          existing=$(gh issue list \
            --repo "${{ github.repository }}" \
            --state open \
            --search "in:title \"$TITLE_PREFIX\"" \
            --json number,title \
            --jq '.[] | select(.title | startswith("'"$TITLE_PREFIX"'")) | .number' \
            | head -1)
          BODY="Automated freshness probe failed.

          **Status:** \`$STATUS\`
          **Detail:** $DETAIL

          The Skills Hub at /docs/skills depends on \`/docs/api/skills-index.json\`.
          The unified index is rebuilt by \`.github/workflows/skills-index.yml\` (cron 6/18 UTC)
          and \`.github/workflows/deploy-site.yml\` (on every push affecting website/skills).
          If this issue keeps reopening, check the latest runs:

          - https://github.com/${{ github.repository }}/actions/workflows/skills-index.yml
          - https://github.com/${{ github.repository }}/actions/workflows/deploy-site.yml

          This issue was opened by \`.github/workflows/skills-index-freshness.yml\`. Close it once the underlying problem is fixed; the next probe will reopen if it's still broken."
          if [ -n "$existing" ]; then
            echo "Appending to existing issue #$existing"
            gh issue comment "$existing" --repo "${{ github.repository }}" --body "Probe still failing at $(date -u +%FT%TZ): \`$STATUS\` — $DETAIL"
          else
            echo "Opening new watchdog issue"
            gh issue create --repo "${{ github.repository }}" \
              --title "$TITLE_PREFIX Skills index is stale or degraded ($STATUS)" \
              --body "$BODY"
          fi
