Skip to content

ci(ag-ui): verify the deployed runtime mounts every topic after deploy - #925

Merged
blove merged 1 commit into
mainfrom
blove/ag-ui-post-deploy-verify
Sep 1, 2026
Merged

ci(ag-ui): verify the deployed runtime mounts every topic after deploy#925
blove merged 1 commit into
mainfrom
blove/ag-ui-post-deploy-verify

Conversation

@blove

@blove blove commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Closes the gap that hid the subagents outage for two and a half months.

The boot gate from #899 proves the aggregated server imports with the pinned deps. It can't prove the rollout took:

  • railway up --detach returns at upload time, before the image builds or starts.
  • When a new image fails to start, Railway keeps serving the last good one.
  • /ok is no help — a stale image answers it happily.

So from CI, a broken deploy is indistinguishable from a healthy one. /agent/subagents was 404 in production from 2026-06-16 to 2026-08-31 while every deploy reported success, and today's runtime topics couldn't appear either.

The check

Poll the endpoints the SPAs actually call until each topic answers; fail the deploy if any doesn't.

An empty POST is a token-free canary — the FastAPI request model rejects it before any graph or LLM call runs:

Status Meaning
422 mounted and healthy
404 missing from the deployed image, or no proxy route
401 AG_UI_INTERNAL_TOKEN mismatch

Probing goes through the public Vercel proxy because the middleware requires X-Internal-Token, which is deliberately not a CI secret.

The topic list mirrors collectTopics() in the deployment generator, so it asserts exactly what the deployment was generated to mount — a new topic is covered with no edit here. URLs are product-aware: ag-ui and runtimes share the runtime, but the examples route table has a separate rule per product, so probing a runtime under /ag-ui would pass through the wrong rule and stop reflecting what the SPA calls.

Verification

Against production right now — 9/9 mounted, exit 0:

✅ aws-strands: mounted at /runtimes/aws-strands/agent (HTTP 422)
✅ subagents:   mounted at /ag-ui/subagents/agent (HTTP 422)
… 7 more
9 healthy, 0 failing

Against the outage it was written for, it named the failing topic and pointed at the Railway build log rather than reporting green.

Unit spec: 11 pass, pinning the status semantics (a well-meaning "simplify to status < 500" would silently reintroduce the blind spot) and the per-product URL mapping.

eslint reports one @nx/enforce-module-boundaries error for the relative registry import — identical to the existing scripts/generate-ag-ui-deployment-config.ts, and root scripts/ isn't in any lint target.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
threadplane Ready Ready Preview Sep 1, 2026 6:19am UTC

Request Review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

The boot gate added in #899 proves the aggregated server imports with the
pinned deps. It cannot prove the rollout took: `railway up --detach` returns
at upload time, and when a new image fails to start Railway keeps serving the
last good one. From CI a broken deploy is indistinguishable from a healthy
one, and /ok is no help — a stale image answers it happily.

That combination hid a dead capability for two and a half months:
/agent/subagents was 404 in production from 2026-06-16 until 2026-08-31
while every deploy reported success.

Poll the endpoints the SPAs actually call until each topic answers, and fail
the deploy if any does not. An empty POST is a token-free canary — the
request model rejects it before any graph or LLM call runs, so 422 means
mounted, 404 means missing, 401 means internal-token mismatch. Probing goes
through the public Vercel proxy because the FastAPI middleware requires
X-Internal-Token, which is deliberately not a CI secret.

The topic list mirrors collectTopics() in the deployment generator, so it
asserts exactly what the deployment was generated to mount and a new topic is
covered with no edit here. URLs are product-aware: 'ag-ui' and 'runtimes'
capabilities share the runtime but the examples route table has a separate
rule per product.

Verified against production: 9/9 topics mounted, exit 0. Against the outage
it was written for, it named the failing topic and pointed at the Railway
build log.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@blove
blove force-pushed the blove/ag-ui-post-deploy-verify branch from 2ca4711 to 0cd8914 Compare September 1, 2026 06:11
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit 1732623 into main Sep 1, 2026
65 checks passed
@blove
blove deleted the blove/ag-ui-post-deploy-verify branch September 1, 2026 06:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant