Skip to content

fix(accounts): declare unpriceable positions instead of dropping them… #300

fix(accounts): declare unpriceable positions instead of dropping them…

fix(accounts): declare unpriceable positions instead of dropping them… #300

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