diff --git a/.github/workflows/dispatch-on-push.yml b/.github/workflows/dispatch-on-push.yml deleted file mode 100644 index 910d97e2..00000000 --- a/.github/workflows/dispatch-on-push.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Dispatch on Push - -on: - push: - branches: [main] - paths: - - "openapi/**" - - "*/guides/**" - - "*/mcp/**" - -permissions: - contents: read - -jobs: - detect: - runs-on: ubuntu-latest - outputs: - changed_services: ${{ steps.detect.outputs.changed_services }} - commit_sha: ${{ steps.detect.outputs.commit_sha }} - skip: ${{ steps.detect.outputs.skip }} - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - - name: Detect changed services - id: detect - run: | - changed_files=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "") - echo "Changed files:" - echo "$changed_files" - - changed_services=$(echo "$changed_files" | grep -oP '^(?:openapi/|[^/]+/guides/|[^/]+/mcp/)\K[^/.]+' | sort -u | tr '\n' ',' | sed 's/,$//') - echo "changed_services=$changed_services" >> "$GITHUB_OUTPUT" - echo "commit_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - - if [ -z "$changed_services" ]; then - echo "skip=true" >> "$GITHUB_OUTPUT" - else - echo "skip=false" >> "$GITHUB_OUTPUT" - fi - - dispatch: - needs: detect - if: needs.detect.outputs.skip != 'true' - runs-on: ubuntu-latest - timeout-minutes: 5 - strategy: - fail-fast: false - matrix: - # Code consumers receive canonical contracts directly from PlatformBackend. - # Docs only dispatches published-content updates to these consumers. - include: - - repo: AceDataCloud/APIs - services: all - - repo: AceDataCloud/Skills - services: all - steps: - - name: Check if service is relevant - id: check - run: | - changed="${{ needs.detect.outputs.changed_services }}" - target="${{ matrix.services }}" - if [ "$target" = "all" ]; then - echo "relevant=true" >> "$GITHUB_OUTPUT" - elif echo ",$changed," | grep -q ",$target,"; then - echo "relevant=true" >> "$GITHUB_OUTPUT" - else - echo "relevant=false" >> "$GITHUB_OUTPUT" - echo "Skipping ${{ matrix.repo }} — '$target' not in '$changed'" - fi - - - name: Dispatch to downstream repo - if: steps.check.outputs.relevant == 'true' - uses: peter-evans/repository-dispatch@v3 - with: - token: ${{ secrets.BOT_GITHUB_TOKEN }} - repository: ${{ matrix.repo }} - event-type: docs-updated - client-payload: | - { - "commit_sha": "${{ needs.detect.outputs.commit_sha }}", - "changed_services": "${{ needs.detect.outputs.changed_services }}", - "source": "Docs-push" - } diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml deleted file mode 100644 index 6cd67c9c..00000000 --- a/.github/workflows/sync.yml +++ /dev/null @@ -1,167 +0,0 @@ -name: Sync Docs from PlatformBackend - -on: - push: - branches: [main] - paths: - - 'scripts/**' - - '.github/workflows/sync.yml' - repository_dispatch: - types: [platform-contracts-updated] - workflow_dispatch: - schedule: - - cron: "37 * * * *" - -concurrency: - group: docs-publication-main - cancel-in-progress: false - -permissions: - contents: write - -env: - PYTHONUNBUFFERED: "1" - -jobs: - sync: - runs-on: ubuntu-latest - timeout-minutes: 30 - outputs: - changed: ${{ steps.changes.outputs.changed }} - changed_services: ${{ steps.changes.outputs.changed_services }} - commit_sha: ${{ steps.commit.outputs.commit_sha }} - steps: - - name: Checkout Docs repo - uses: actions/checkout@v4 - with: - path: Docs - ref: main - token: ${{ secrets.BOT_GITHUB_TOKEN }} - - - name: Checkout current PlatformBackend source - uses: actions/checkout@v4 - with: - repository: AceDataCloud/PlatformBackend - ref: main - fetch-depth: 0 - path: PlatformBackend - token: ${{ secrets.BOT_GITHUB_TOKEN }} - - - name: Verify source event and current contract - id: backend - env: - EVENT_NAME: ${{ github.event_name }} - SOURCE_SHA: ${{ github.event.client_payload.source_sha }} - run: | - actual=$(git -C PlatformBackend rev-parse HEAD) - if [ "$EVENT_NAME" = "repository_dispatch" ]; then - if ! printf '%s' "$SOURCE_SHA" | grep -Eq '^[0-9a-f]{40}$'; then - echo "::error::Contract events require a full source_sha." - exit 1 - fi - # An old queued event is a reconciliation signal, never permission - # to replay an older snapshot over newer published content. - git -C PlatformBackend merge-base --is-ancestor "$SOURCE_SHA" "$actual" - fi - echo "sha=$actual" >> "$GITHUB_OUTPUT" - bundle=$(mktemp -d) - python PlatformBackend/scripts/ecosystem_contracts.py \ - --backend-dir PlatformBackend compile --output-dir "$bundle" --source-sha "$actual" - python PlatformBackend/scripts/ecosystem_contracts.py verify \ - --bundle-dir "$bundle" --source-sha "$actual" - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Reconcile public documents - id: publication - working-directory: Docs - env: - PUBLIC_EXAMPLE_DENYLIST: ${{ secrets.PUBLIC_EXAMPLE_DENYLIST }} - run: | - set +e - python -u scripts/sync_from_platformbackend.py \ - --backend-dir ../PlatformBackend \ - --output-dir . \ - --report "$RUNNER_TEMP/docs-sync-report.json" - result=$? - set -e - if [ "$result" -ne 0 ] && [ "$result" -ne 2 ]; then - exit "$result" - fi - echo "incomplete=$([ "$result" -eq 2 ] && echo true || echo false)" >> "$GITHUB_OUTPUT" - python - "$RUNNER_TEMP/docs-sync-report.json" >> "$GITHUB_STEP_SUMMARY" <<'PY' - import json, sys - report = json.load(open(sys.argv[1])) - print(f"Current document versions: {report['ready']}/{report['total']}") - for item in report['pending'][:100]: - print(f"- {item['language']}/{item['source_key']}: {item['status']}") - PY - - - name: Preserve publication completeness report - if: always() - uses: actions/upload-artifact@v4 - with: - name: docs-sync-report - path: ${{ runner.temp }}/docs-sync-report.json - if-no-files-found: warn - retention-days: 14 - - - uses: actions/setup-node@v4 - with: - node-version: '24' - cache: npm - cache-dependency-path: Docs/package-lock.json - - - name: Validate MDX and local links before pushing - working-directory: Docs - run: | - npm ci --ignore-scripts - node scripts/validate_mdx.mjs . - - - name: Check for changes - id: changes - working-directory: Docs - run: | - git add -A - if git diff --cached --quiet; then - echo "changed=false" >> "$GITHUB_OUTPUT" - echo "changed_services=" >> "$GITHUB_OUTPUT" - exit 0 - fi - - echo "changed=true" >> "$GITHUB_OUTPUT" - changed_files=$(git diff --cached --name-only) - git diff --cached --stat - - changed_services=$(echo "$changed_files" \ - | grep -oP '^(?:openapi/|[^/]+/guides/|[^/]+/mcp/)\K[^/.]+' \ - | sort -u \ - | tr '\n' ',' \ - | sed 's/,$//' || true) - echo "changed_services=$changed_services" >> "$GITHUB_OUTPUT" - - - name: Commit and push - id: commit - if: steps.changes.outputs.changed == 'true' - working-directory: Docs - run: | - git config user.name "Ace Data Cloud Dev" - git config user.email "dev@acedata.cloud" - latest=$(git -C ../PlatformBackend ls-remote origin refs/heads/main | cut -f1) - test "$latest" = "${{ steps.backend.outputs.sha }}" || { - echo "::error::PlatformBackend advanced during publication; retry from current main." - exit 1 - } - git commit -m "docs: sync from PlatformBackend [automated]" \ - -m "Source: ${{ steps.backend.outputs.sha }}" - git push - echo "commit_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - - - name: Require complete publication - if: steps.publication.outputs.incomplete == 'true' - run: | - echo "::error::Publication is incomplete. Current pages were refreshed; retained or missing translations are listed in docs-sync-report." - exit 1 diff --git a/README.md b/README.md index 52d99c10..2524bded 100644 --- a/README.md +++ b/README.md @@ -31,17 +31,12 @@ links with `mint broken-links`. Navigation and site settings live in `docs.json` ## Synchronization contract -`Sync Ecosystem Contracts` is the only source-change trigger. The Docs workflow -serializes all writers, checks out current `main` after acquiring the queue, and -validates that an event SHA belongs to the current backend history. Old events -cannot republish old source snapshots. A final source check rejects a backend -revision that advanced during generation; normal Git push rejects concurrent -editorial changes without overwriting them. - -Hourly reconciliation picks up asynchronous source deployment and translation -completion even when no new Git event occurs. Before switching this consumer on, -deploy the additive metadata on the existing document list. Missing metadata or -malformed/incomplete pages fail instead of being treated as a successful sync. +PlatformBackend's daily ecosystem CronJob is the only publication coordinator. +It checks out a pinned current Backend source, runs this repository's existing +generator, validates MDX, and opens or updates a PR. Mintlify publishes after +normal review and merge. No cross-repository dispatch or hourly GitHub writer +remains. Every daily pass also checks translation completion without requiring +a new source commit. For every generated page, the database source hash must match the checked-out Markdown and the target translation must be current. Catalog identity must also @@ -50,11 +45,11 @@ and never counts that fallback as a current translation. When a translation is pending, an existing page is retained for availability but is explicitly reported as incomplete; a missing page is not fabricated. Ready pages and public withdrawals can still publish. Exit status **2** means partial -publication and fails the workflow's final completeness gate. Other nonzero +publication and prevents the daily controller from advancing its checkpoint. Other nonzero statuses abort publication; **0** means every expected page is current. -The workflow retains `docs-sync-report` for 14 days and puts pending page keys, -locales, and reasons in the job summary. Generated output is staged and validated +The generator writes a completeness report for the controller; incomplete +publication is retried on the next daily run. Generated output is staged and validated before an atomic publish; interruption recovery includes navigation and all MCP locales. A separate MDX and local-link gate checks every site page before Git push, including editorial entry points. Plain Markdown braces are escaped outside code rather than interpreted as @@ -88,3 +83,11 @@ containing complete responses from the same document list for reproducible, offline verification. Reports belong outside the generated output tree. No sync command writes the backend DB or generates translations. + +## Daily capability updates + +PlatformBackend `ecosystem.py` is the only scheduled coordinator. +One daily Kubernetes Job reviews Backend docs and API changes with Claude Code, +updates existing files, and creates or updates one reviewable PR per repository. +It never merges PRs or duplicates the Backend guide tree. Normal CI and review +remain required; publication and sub-repository mirroring run after merge.