# Zindex - Multi-agent workflow diagram. Keeps a BPMN-style diagram of the
# agent orchestration policy in sync with the orchestration YAML on every PR
# that touches it (plus a daily safety-net run).
#
# Drop into .github/workflows/zindex-orchestration.yml.

name: Zindex - Multi-agent workflow

on:
  pull_request:
    paths:
      - "agents/triage.yaml"
      - "agents/**/*.yaml"
  schedule:
    - cron: "0 6 * * *"   # Daily 06:00 UTC safety net
  workflow_dispatch:

permissions:
  contents: read
  pull-requests: write

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

env:
  ZINDEX_API_BASE: https://api.zindex.ai

jobs:
  sync-orchestration-diagram:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 1. Parse the orchestration YAML. Each entry maps to a workflow
      #    element - author scripts/parse-orchestration.mjs against your
      #    project's YAML schema. The parser should emit
      #    { steps: [{ id, type, label, transitions }] } where `type` is one
      #    of classifier|agent|human-review|gateway|terminate.
      - name: Parse orchestration to steps.json
        run: |
          mkdir -p out
          node scripts/parse-orchestration.mjs > out/steps.json
          echo "::notice::Parsed $(jq '.steps | length' out/steps.json) steps"

      - name: Capture current revision
        id: prev_rev
        env:
          ZINDEX_API_KEY: ${{ secrets.ZINDEX_API_KEY }}
          ZINDEX_SCENE_ID: ${{ secrets.ZINDEX_SCENE_ID }}
        run: |
          echo "rev=$(curl -fsSL -H "Authorization: Bearer $ZINDEX_API_KEY" \
            "$ZINDEX_API_BASE/v1/scenes/$ZINDEX_SCENE_ID" | jq -r '.revision')" >> "$GITHUB_OUTPUT"

      # 2. Map each step to a Zindex workflow element. Use stable ids (the
      #    YAML key) so a renamed step produces updateNode rather than
      #    delete + create - the latter would break sequenceFlow edges.
      - name: Compute applyOps batch
        run: node scripts/orchestration-to-ops.mjs out/steps.json > out/ops.json

      - name: Apply ops
        id: apply
        env:
          ZINDEX_API_KEY: ${{ secrets.ZINDEX_API_KEY }}
          ZINDEX_SCENE_ID: ${{ secrets.ZINDEX_SCENE_ID }}
        run: |
          RESP=$(curl -fsSL -X POST \
            -H "Authorization: Bearer $ZINDEX_API_KEY" \
            -H "Content-Type: application/json" \
            --data-binary @out/ops.json \
            "$ZINDEX_API_BASE/v1/scenes/$ZINDEX_SCENE_ID/ops")
          echo "rev=$(echo "$RESP" | jq -r '.revision')" >> "$GITHUB_OUTPUT"
          echo "applied=$(echo "$RESP" | jq -r '.applied')" >> "$GITHUB_OUTPUT"

      - name: Validate workflow semantics
        env:
          ZINDEX_API_KEY: ${{ secrets.ZINDEX_API_KEY }}
          ZINDEX_SCENE_ID: ${{ secrets.ZINDEX_SCENE_ID }}
        run: |
          curl -fsSL -X POST \
            -H "Authorization: Bearer $ZINDEX_API_KEY" \
            -H "Content-Type: application/json" \
            --data-binary @<(curl -fsSL -H "Authorization: Bearer $ZINDEX_API_KEY" \
              "$ZINDEX_API_BASE/v1/scenes/$ZINDEX_SCENE_ID" | jq '{schemaVersion: "0.1", diagramFamily, scene, layoutStrategy, elements}') \
            "$ZINDEX_API_BASE/v1/scenes/validate" \
            > out/validation.json
          if [ "$(jq -r '.ok' out/validation.json)" != "true" ]; then
            echo "::error::Validation failed - workflow YAML may have invalid BPMN semantics. See out/validation.json."
            jq -r '.diagnostics[] | "::error::\(.code) at \(.path // "scene"): \(.message)"' out/validation.json
            exit 1
          fi

      - name: Render
        env:
          ZINDEX_API_KEY: ${{ secrets.ZINDEX_API_KEY }}
          ZINDEX_SCENE_ID: ${{ secrets.ZINDEX_SCENE_ID }}
        run: |
          curl -fsSL -X POST \
            -H "Authorization: Bearer $ZINDEX_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{"format":"svg","theme":"clean"}' \
            "$ZINDEX_API_BASE/v1/scenes/$ZINDEX_SCENE_ID/render" \
            | jq -r '.output.content' > out/diagram.svg

      - name: Diff revisions
        id: diff
        if: steps.apply.outputs.rev != steps.prev_rev.outputs.rev
        env:
          ZINDEX_API_KEY: ${{ secrets.ZINDEX_API_KEY }}
          ZINDEX_SCENE_ID: ${{ secrets.ZINDEX_SCENE_ID }}
          PREV: ${{ steps.prev_rev.outputs.rev }}
          NEW: ${{ steps.apply.outputs.rev }}
        run: |
          curl -fsSL -H "Authorization: Bearer $ZINDEX_API_KEY" \
            "$ZINDEX_API_BASE/v1/scenes/$ZINDEX_SCENE_ID/diff?from=$PREV&to=$NEW" \
            > out/diff.json
          echo "added=$(jq -r '.summary.added' out/diff.json)" >> "$GITHUB_OUTPUT"
          echo "removed=$(jq -r '.summary.removed' out/diff.json)" >> "$GITHUB_OUTPUT"
          echo "modified=$(jq -r '.summary.modified' out/diff.json)" >> "$GITHUB_OUTPUT"

      - uses: actions/upload-artifact@v4
        id: upload
        with:
          name: orchestration-diagram-svg
          path: out/diagram.svg
          retention-days: 30

      - uses: peter-evans/find-comment@v3
        if: github.event_name == 'pull_request'
        id: find_comment
        with:
          issue-number: ${{ github.event.pull_request.number }}
          comment-author: "github-actions[bot]"
          body-includes: "<!-- zindex-bot:multi-agent-workflow -->"

      - uses: peter-evans/create-or-update-comment@v4
        if: github.event_name == 'pull_request'
        with:
          comment-id: ${{ steps.find_comment.outputs.comment-id }}
          issue-number: ${{ github.event.pull_request.number }}
          edit-mode: replace
          body: |
            <!-- zindex-bot:multi-agent-workflow -->
            ### Orchestration diagram updated · revision ${{ steps.apply.outputs.rev }}

            | | |
            |---|---|
            | Workflow changes | +${{ steps.diff.outputs.added || '0' }} / -${{ steps.diff.outputs.removed || '0' }} / ~${{ steps.diff.outputs.modified || '0' }} |
            | Revision | ${{ steps.prev_rev.outputs.rev }} → ${{ steps.apply.outputs.rev }} |

            <details><summary>Download rendered SVG</summary>

            ${{ steps.upload.outputs.artifact-url }}

            </details>

            <sub>Rendered by Zindex · scene `${{ secrets.ZINDEX_SCENE_ID }}`</sub>
