Repository navigation
feat(agent): add gated durable learning workflows #1149
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # CI orchestrator (structured like a pipeline graph, not a monolith): | |
| # | |
| # changes ─┬─ security (_security.yml) always on | |
| # ├─ backend (_backend.yml) gated by path filter | |
| # ├─ frontend (_frontend.yml) gated by path filter | |
| # ├─ contract (_contract.yml) gated by path filter | |
| # └─ docker (_docker.yml) gated by path filter | |
| # └────── ci-ok ── single stable required context | |
| # | |
| # Extension rules: | |
| # - A new gate is a new `_name.yml` reusable workflow plus one calling job | |
| # here and one entry in `ci-ok.needs`. Branch protection never changes: | |
| # it only ever requires `ci-ok`. | |
| # - Path filters live only in this file; reusable workflows stay unconditioned. | |
| # - Skipped stages count as green in `ci-ok` (docs/CI-only PRs must not wedge | |
| # merges), but the `changes` job itself must succeed outright. | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| jobs: | |
| # --- Which areas changed? Each heavier gate keys off these outputs. --- | |
| changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| backend: ${{ steps.filter.outputs.backend }} | |
| console: ${{ steps.filter.outputs.console }} | |
| management: ${{ steps.filter.outputs.management }} | |
| docker: ${{ steps.filter.outputs.docker }} | |
| contract: ${{ steps.filter.outputs.contract }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Detect changed paths | |
| id: filter | |
| uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4 | |
| with: | |
| filters: | | |
| backend: | |
| - 'services/**' | |
| - 'init-db/**' | |
| - 'scripts/**' | |
| - 'docker/redis/**' | |
| # Docker topology and observability changes must also exercise | |
| # the backend workflow's dynamic infrastructure contracts. | |
| - 'docker/docker-compose*.yml' | |
| - 'infrastructure/observability/**' | |
| - 'infrastructure/nginx/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/_backend.yml' | |
| - '.github/services-matrix.json' | |
| console: | |
| - 'apps/console/**' | |
| - 'packages/**' | |
| - 'shared/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/_frontend.yml' | |
| management: | |
| - 'apps/management/**' | |
| - 'packages/**' | |
| - 'shared/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/_frontend.yml' | |
| contract: | |
| - 'services/api/**' | |
| - 'services/pom.xml' | |
| - 'services/docs/CONTRACT_COMPAT_GATE.md' | |
| - 'scripts/test/api-contract-boundary-contract.sh' | |
| - 'scripts/test/dubbo-provider-reference-contract.sh' | |
| - 'scripts/test/submission-compatibility-retirement-contract.sh' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/_contract.yml' | |
| docker: | |
| - 'services/**' | |
| - 'apps/console/Dockerfile' | |
| - 'apps/management/Dockerfile' | |
| - 'docker/docker-compose*.yml' | |
| - 'infrastructure/observability/**' | |
| - 'docker/prometheus/**' | |
| - 'services/docs/OBSERVABILITY_RUNBOOK.md' | |
| - '.github/actions/**' | |
| - '.github/workflows/docker-publish.yml' | |
| - '.github/workflows/cd-deploy.yml' | |
| - '.github/workflows/cd-rollback.yml' | |
| - 'scripts/runbooks/image-reference-policy.sh' | |
| - 'scripts/test/supply-chain-contract.sh' | |
| - 'scripts/runbooks/deployment-integrity.sh' | |
| - 'scripts/test/deployment-integrity-contract.sh' | |
| - '.dockerignore' | |
| - 'apps/console/nginx.conf' | |
| - 'apps/management/nginx.conf' | |
| - 'infrastructure/nginx/**' | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/_docker.yml' | |
| - '.github/services-matrix.json' | |
| # --- Security: runs on every change set, independent of area gates. --- | |
| security: | |
| name: Security Gate | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.result == 'success' }} | |
| uses: ./.github/workflows/_security.yml | |
| secrets: inherit | |
| # --- Backend gates --- | |
| backend: | |
| name: Backend | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.backend == 'true' }} | |
| uses: ./.github/workflows/_backend.yml | |
| secrets: inherit | |
| # --- Frontend gates (either app or shared packages) --- | |
| frontend: | |
| name: Frontend | |
| needs: changes | |
| if: ${{ !cancelled() && (needs.changes.outputs.console == 'true' || needs.changes.outputs.management == 'true') }} | |
| uses: ./.github/workflows/_frontend.yml | |
| with: | |
| console_changed: ${{ needs.changes.outputs.console == 'true' }} | |
| management_changed: ${{ needs.changes.outputs.management == 'true' }} | |
| secrets: inherit | |
| # --- Contract compatibility gate --- | |
| contract: | |
| name: Contract Compatibility | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.contract == 'true' }} | |
| uses: ./.github/workflows/_contract.yml | |
| secrets: inherit | |
| # --- Docker build verification --- | |
| docker: | |
| name: Docker Verify | |
| needs: changes | |
| if: ${{ !cancelled() && needs.changes.outputs.docker == 'true' }} | |
| uses: ./.github/workflows/_docker.yml | |
| secrets: inherit | |
| # --- The one summary context for branch protection. Fails unless every | |
| # stage succeeded; `skipped` is fine because stages are path-gated. --- | |
| ci-ok: | |
| name: ci-ok | |
| needs: [changes, security, backend, frontend, contract, docker] | |
| if: ${{ always() }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: All CI stages must have succeeded (or been skipped) | |
| env: | |
| RESULTS: ${{ toJSON(needs) }} | |
| run: | | |
| echo "$RESULTS" | jq . | |
| jq -e ' | |
| .changes.result == "success" | |
| and ([to_entries[] | select(.key != "changes") | .value.result] | |
| | all(. == "success" or . == "skipped")) | |
| ' <<< "$RESULTS" > /dev/null |