Skip to content

feat(agent): add gated durable learning workflows #1149

feat(agent): add gated durable learning workflows

feat(agent): add gated durable learning workflows #1149

Workflow file for this run

# 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