fix(accounts): declare unpriceable positions instead of dropping them… #300
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
| name: Sync contract artifacts | |
| # Catches contract drift that NO per-PR check can see: the kind that only | |
| # exists once two PRs are both on main. | |
| # | |
| # The incident this exists for (2026-07-30, #8774). #8768 refreshed | |
| # github-signals.json, which the subnet profile/detail OpenAPI *examples* are | |
| # generated from. Its own pre-merge build showed a clean public/ because that | |
| # branch was cut before #8758 landed the 76 network-addressed route variants | |
| # that duplicate those examples. Separately, #8761 added networks.json to | |
| # R2_ONLY_PATTERNS, flipping its storage_tier in contracts.json and | |
| # api-index.json. Each PR was self-consistent and green. The combination left | |
| # main's committed artifacts stale, and validate:contract-drift then failed on | |
| # EVERY open PR regardless of its contents until #8775 regenerated them. | |
| # | |
| # A per-PR freshness check is structurally blind to this: it compares a build | |
| # of THAT PR's tree against THAT PR's committed files. Only a build of main | |
| # itself, after the merge, can see it. So this runs on push to main -- the | |
| # moment the drift can first exist -- with a daily schedule as a backstop for | |
| # anything that lands while a run is skipped or fails. | |
| # | |
| # Same auto-PR shape as sync-client-version.yml / sync-mcp-version.yml: | |
| # regenerate, open a PR only when something actually differs, stay silent | |
| # otherwise. (The machine-DATA lanes that used to share this shape -- | |
| # sync-operational-surfaces, sync-schema-snapshots, sync-surface-verification, | |
| # sync-github-signals -- are retired: their files are now written directly by | |
| # Worker crons into R2 stores, see #9096. This lane stays a PR because its | |
| # output is COMMITTED CONTRACT -- openapi.json, generated types -- which must | |
| # be reviewed and versioned in git, not swapped underneath a deploy.) | |
| on: | |
| push: | |
| branches: | |
| - main | |
| schedule: | |
| - cron: "40 5 * * *" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| # Not cancel-in-progress: a run started by an earlier merge is still checking | |
| # a real state, and cancelling it could drop the only observation of a drift | |
| # that the next push happens not to reintroduce. | |
| group: sync-contract-artifacts | |
| cancel-in-progress: false | |
| jobs: | |
| sync: | |
| name: Regenerate contract artifacts if stale | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 # runs the full build | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: 22.23.2 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| # The real build, exactly as a contributor or CI runs it. It does not | |
| # re-capture github-signals (the Worker cron owns that lane now -- see | |
| # src/github-signals-sync.ts -- and without Cloudflare credentials in | |
| # this job's env the build reads the committed seed, never the store), | |
| # so this run compares generated output against the SAME committed | |
| # inputs main already has -- a diff here means the committed artifacts | |
| # are genuinely stale, not that upstream data moved underneath them. | |
| - name: Build | |
| run: npm run build | |
| # Scoped to the contract artifacts on purpose. build.ts already | |
| # auto-reverts the deploy-owned pair (r2-manifest.json, | |
| # schemas/index.json, see DEPLOY_OWNED_ARTIFACTS in scripts/lib.ts), and | |
| # anything else the build touches belongs to whichever sync workflow owns | |
| # it -- this one must not quietly adopt their files. | |
| - name: Check whether the contract artifacts changed | |
| id: diff | |
| run: | | |
| paths=( | |
| public/metagraph/openapi.json | |
| public/metagraph/contracts.json | |
| public/metagraph/api-index.json | |
| public/metagraph/types.d.ts | |
| packages/contract/index.d.ts | |
| ) | |
| if git diff --quiet -- "${paths[@]}"; then | |
| echo "contract artifacts match a fresh build of main" | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "contract artifacts on main are stale:" | |
| git diff --stat -- "${paths[@]}" | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Summarize which artifacts drifted | |
| if: steps.diff.outputs.changed == 'true' | |
| id: summary | |
| run: | | |
| files=$(git diff --name-only -- \ | |
| public/metagraph/openapi.json \ | |
| public/metagraph/contracts.json \ | |
| public/metagraph/api-index.json \ | |
| public/metagraph/types.d.ts \ | |
| packages/contract/index.d.ts \ | |
| | xargs -n1 basename | paste -sd ", " -) | |
| echo "files=$files" >> "$GITHUB_OUTPUT" | |
| - name: Open sync PR (no-op if unchanged) | |
| if: steps.diff.outputs.changed == 'true' | |
| uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11 | |
| id: pr | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| branch: chore/sync-contract-artifacts | |
| delete-branch: true | |
| add-paths: | | |
| public/metagraph/openapi.json | |
| public/metagraph/contracts.json | |
| public/metagraph/api-index.json | |
| public/metagraph/types.d.ts | |
| packages/contract/index.d.ts | |
| title: "chore(build): sync contract artifacts (${{ steps.summary.outputs.files }})" | |
| commit-message: "chore(build): sync contract artifacts (${{ steps.summary.outputs.files }})" | |
| body: | | |
| A fresh `npm run build` of `main` no longer matches the committed contract artifacts. Drifted: `${{ steps.summary.outputs.files }}`. | |
| **Merge this promptly.** While `main` is in this state, `validate:contract-drift` fails on every open PR regardless of its contents — that is what #8774 was. | |
| This usually means two PRs were individually green and mutually inconsistent: each was built against a tree that did not yet contain the other. No per-PR check can see that, which is why this workflow builds `main` itself after every merge. | |
| If the diff looks like more than a regeneration, check what merged just before it rather than merging this on trust. | |
| labels: | | |
| automation | |
| # #233 interim: merge the bot PR itself once its own checks are green, | |
| # replacing the daily manual merge. Deliberately the RELEASE_PLEASE_TOKEN | |
| # (a real PAT) rather than GITHUB_TOKEN: a GITHUB_TOKEN merge would not | |
| # trigger push-to-main workflows (the merge-triggered fast registry sync, | |
| # the version-bump lanes), silently detaching everything that reacts to | |
| # these merges. A failed or missing check leaves the PR open for a human | |
| # and turns this run red, which is the alert. | |
| - name: Auto-merge when checks are green | |
| if: steps.pr.outputs.pull-request-number | |
| timeout-minutes: 30 | |
| env: | |
| GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| pr="${{ steps.pr.outputs.pull-request-number }}" | |
| # Checks register within moments of the branch push; give them a | |
| # beat so --watch sees the run instead of "no checks reported". | |
| sleep 60 | |
| gh pr checks "$pr" --watch --fail-fast | |
| gh pr merge "$pr" --squash |