Conversation
Gateful merges the DAO APIs' OpenAPI specs into /docs/json on every request, so waiting for gateful's own commit said nothing about the schemas it would serve. On #2093 gateful reported the new commit at 14:33:54, the dashboard's codegen read the spec at 14:34:23, and ens-api only came up at 14:34:34 — the build typechecked against the previous contract and failed on scoresTotal. The DAO API now reports its running commit on /health, gateful surfaces it as upstreams.<dao>.commit, and wait-for-gateful waits for every upstream that reports one. That is enabled only when the push touches the paths Railway watches to rebuild those APIs, so releases that leave them alone are not blocked waiting for a rebuild that will never happen. Also stop caching @anticapture/client#codegen: its real input is the live gateful spec, which no hash can see, so the raced output was replayed on every retry of that commit and no re-run could ever fix it. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…ad compare Two review findings on the gate. A DAO API that reports no commit was being skipped, which is exactly the state of every API during this release's own rollout — the field ships with it. The gate would have passed the moment gateful updated, reproducing the race. DAO APIs now have to report the expected commit; gateful labels each upstream with a `kind` so relayers, address enrichment and authful stay exempt. A failing `gh api` inside an `if` was indistinguishable from "no API change", so a rate limit or outage would silently drop the gate on the releases that need it most. It now runs as its own command, where set -e fails the step. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
A third review finding: with `cancel-in-progress`, a non-API push landing while an API push is still deploying cancels the earlier waiter, and asking "did THIS push change the API" answers no — so the gate stood down while the APIs were still serving the pre-release spec. The workflow now resolves the last commit that touched the paths Railway watches for the DAO APIs, and passes that commit plus every commit after it. A superseding push resolves the same API commit and keeps waiting for it, and accepting "or newer" also covers Railway stamping a service with the head of a multi-commit push rather than the commit that changed it. This drops the REQUIRE_UPSTREAM_COMMIT flag and the compare API call along with it — git already knows, so there is no request left to fail. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…he DAO APIs A fourth review finding, and a factual correction to a comment I wrote: the relayer and address enrichment also contribute paths and schemas to /docs/json via mergeUpstreamDocs, so a release changing either of them could reproduce the same stale-spec race the DAO API gate was closing. Both now report their commit on /health, and the expected commits are resolved per upstream kind from that service's own Railway watch paths — a relayer release waits for the relayer, not for the APIs. Authful stays exempt: its spec is not merged, so it only has to be reachable. Requiring a commit cannot deadlock these two either: teaching a service to report its commit necessarily touches its own watched paths, so the release that adds the field is also the release that rebuilds it. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This PR's own preview build failed exactly the way production did: codegen ran at 16:10:45 while the preview relayer, redeployed at 16:07 because this branch touches apps/relayer, was still coming up. Gateful served a spec whose relay paths had no matching schemas, so the generated sdk.ts imported types models.ts never got and the SDK build failed on them. Re-running with no code change passed, which is the race admitting what it is. The preview waiter only ever checked gateful's own commit, so it had none of the protection deploy.yaml just gained. It now resolves the same per-upstream commit sets from the PR head. Untrusted PRs point at shared dev gateful and already leave the expected commit unset; the upstream check rides along with it and stays off for them. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Re-running codegen on a retry was pointless while `@anticapture/client#build` still hashed the same: `generated/**` is gitignored, so it never entered that task's input set, and turbo would restore the `dist` compiled from the stale spec over the freshly generated one. The dashboard build hashes the client build in turn, so it inherited the same blindness. Listing `generated/**` explicitly makes the spec visible to both hashes while keeping the cache useful when the spec really is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
78a5329 declared `generated/**` as an input to `@anticapture/client#build`, which does not work: turbo hashes inputs before the run, and the directory is gitignored, so on a fresh checkout the glob matches nothing at hash time. The retry hashed identically to the poisoned run and restored its `dist`. Reproduced in isolation with turbo 2.8.16 — a cache:false codegen writing a gitignored dir, a cached build consuming it, the same hash across both runs and the stale output replayed on top of fresh generated files. tsup runs with `dts: true`, so the spec fetched at runtime is compiled into `dist` and no hash can see it — the same reason codegen is uncached. The build is ~6s, so this is cheap. `@anticapture/dashboard#build` keeps its cache: turbo only caches successes, and it is the task that fails in this mode. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
fix(ci): gate the production deploy on the API release, not just gateful
pikonha
requested review from
LeonardoVieira1630,
PedroBinotto,
alextnetto and
brunod-e
as code owners
August 1, 2026 16:51
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
🚅 Deployed to the anticapture-pr-2100 environment in anticapture-infra
|
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Medium Risk
Changes CI/deploy blocking behavior and health API contracts; misconfigured
EXPECTED_UPSTREAM_SHASor git resolution could delay or fail deploys, but runtime app logic outside health/deploy is largely unchanged.Overview
Fixes dashboard/SDK builds racing gateful while DAO APIs, relayer, and address-enrichment still serve an older merged OpenAPI spec on
/docs/json.Upstream commit reporting: Those services expose
commitfromRAILWAY_GIT_COMMIT_SHAon/health. Gateful forwards each upstream’skindandcommitin its own/healthresponse.Deploy gate:
scripts/wait-for-gateful.mjsnow requires gateful’s commit and that spec-contributing upstreams report SHAs inEXPECTED_UPSTREAM_SHAS(resolved in deploy and PR workflows from git history over each service’s Railway watch paths — “that commit or newer”; missingcommitcounts as stale). Checkouts use full history so that resolution works.Turbo:
@anticapture/clientcodegen and build are no longer cached, because the live spec URL can’t be hashed and stale generated/distoutput could stick across retries.Reviewed by Cursor Bugbot for commit 059370d. Configure here.