Skip to content

feat(ci): probe production federation — nothing was checking whether remotes load - #800

Merged
izzywdev merged 3 commits into
masterfrom
claude/prod-federation-probe
Aug 26, 2026
Merged

feat(ci): probe production federation — nothing was checking whether remotes load#800
izzywdev merged 3 commits into
masterfrom
claude/prod-federation-probe

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

The portal shows 13 products and none of them renders its UI. Diagnosing that surfaced why it went unnoticed: no check in this repo ever asks production whether a federated remote actually loads.

check what it actually covers
prod-smoke.yml polls a health endpoint
post-prod-e2e.yml drives user flows
e2e.yml runs check-federated-assets.mjs — against a local preview, never prod

So the failure this shell is most prone to — an entry or chunk that 404s in production while every green check in the pipeline describes a different artifact — had no detector at all.

The portal was reporting the opposite of the truth

backend/src/routes/apps.ts:206:

// Accept any response (including 404) as long as the server responds
return response.status < 500 // Consider 2xx, 3xx, 4xx as healthy, 5xx as unhealthy

A remote whose assets 404 is reported healthy. That is not a gap in observability, it is observability asserting the opposite of reality, and it is why "13 products, none loading" looked like a working system.

Fixing that health check is a separate change — this PR builds the instrument that can prove what is actually being served, because I did not want to change the health semantics before having something that could measure the result.

What it does not assume

The serve path is a free variable (CLAUDE.md — "slug, display name, and the federated serve path are THREE INDEPENDENT questions"). Most repos publish /apps/<slug>/remoteEntry.js (Vite assetsDir: ''); FuzeFront's own fuzequality publishes /apps/<slug>/assets/remoteEntry.js.

So each app is probed at both candidates and the report names which one answered. The probe discovers the layout instead of re-asserting the convention it exists to check — an app answering at neither is the finding, not a probe bug.

Chunk verification delegates to the existing check-federated-assets.mjs, which already encodes the two things that make this real rather than a re-derivation of config: chunk specifiers resolve against remoteEntry.js's own URL, and a 200-with-HTML body is the 404 it really is.

Not vacuous — mutation-tested in both directions

A probe that can only fail is as useless as one that can only pass, so both were proven, not asserted:

scenario result
empty slug list exit 2 — a probe that checks nothing must never report success
unreachable host exit 1, ❌ entry, both candidate paths named
entry + chunk both served as JS exit 0,
entry JS, chunk 200 + HTML exit 1, ❌ chunks, "1 referenced — 0 loadable, 1 broken"

The last row is the one that matters: it is exactly the blank-panel failure, and a probe that only fetched the entry would have called it green.

Design notes

  • Unauthenticated by design. It probes static asset paths, not GET /api/apps — that needs a token and is scoped by org membership + visibility (scopeAppsQuery), so it could not enumerate every app even with one.
  • runs-on: ubuntu-latest, deliberately not the fuzefront ARC pool. A prod diagnostic has to be runnable exactly when the self-hosted pool is saturated, which is when an incident is most likely under investigation.
  • PR trigger is path-scoped to the probe's own files. It hits live production, so it must not fire on every PR — but a detector whose first real execution happens after it merges is how you ship a broken detector.
  • Daily schedule. A remote can stop loading with no commit here at all: a product repo redeploys, an ingress changes, a chart bumps an image. Catching that needs a clock, not a PR.

What this does and does not claim

It does not identify the root cause of the current outage — it is the instrument that can. What I established while building it, from the repos rather than from prod:

  • Every remote's source now pins react: ^19.0.0, matching the host's requiredVersion. The React-18 singleton mismatch is fixed in source, so it is not the current explanation unless prod is running older images.
  • Prod image tags are mixed: fuzeexecutive, fuzedeploy, fuzepicker, fuzex are SHA-pinned and current, while fuzesales, fuzecontact, fuzebi sit at 0.1.0 and fuzemarket at the mutable latest. Stale images explain some products but cannot explain all of them.
  • fuzekeys is the one remote declaring a cross-origin remoteEntry (https://keys.prod.fuzefront.com/...) rather than a same-origin path.

The probe's first run on this PR is what turns that into an answer.

…remotes load

The portal currently shows 13 products and NONE of them renders its UI. Trying
to diagnose that surfaced the reason it went unnoticed: no check in this repo
ever asks production whether a federated remote actually loads.

  prod-smoke.yml       polls a health endpoint
  post-prod-e2e.yml    drives user flows
  e2e.yml              runs check-federated-assets.mjs — against a LOCAL preview

So the failure the shell is most prone to — an entry or chunk that 404s in prod
while every green check in the pipeline describes a different artifact — had no
detector at all.

Worse, the portal actively reported these apps as healthy. apps.ts:206 is
`return response.status < 500`, with the comment "Consider 2xx, 3xx, 4xx as
healthy". A remote whose assets 404 is reported HEALTHY. That is not a
diagnostic gap, it is a diagnostic that says the opposite of the truth, and it
is why "13 products, none loading" looked like a working system. Fixing that
health check is a separate change; this one builds the instrument that can
prove what is actually being served.

WHAT IT DOES NOT ASSUME. The serve path is a free variable (CLAUDE.md, "slug,
display name, and the federated serve path are THREE INDEPENDENT questions").
Most repos publish /apps/<slug>/remoteEntry.js (Vite assetsDir: ''); FuzeFront's
own fuzequality publishes /apps/<slug>/assets/remoteEntry.js. So each app is
probed at BOTH candidates and the report names which answered — it DISCOVERS
the layout rather than re-asserting the convention it exists to check. An app
answering at neither is the finding, not a probe bug.

Chunk verification delegates to the existing check-federated-assets.mjs, which
already encodes the two things that make this real rather than a re-derivation
of config: chunk specifiers resolve against remoteEntry.js's OWN url, and a
200-with-HTML body is the 404 it really is.

Unauthenticated by design: it probes static asset paths, not GET /api/apps,
which needs a token AND is scoped by org membership + visibility — so it could
not enumerate every app even with one.

runs-on: ubuntu-latest, deliberately NOT the fuzefront ARC pool. A prod
diagnostic has to be runnable exactly when the self-hosted pool is saturated,
which is when an incident is most likely under investigation.

NOT VACUOUS, and mutation-tested in both directions rather than only asserted:
  empty slug list            -> exit 2 (a probe that checks nothing never passes)
  unreachable host           -> exit 1, "no remoteEntry served"
  entry + chunk both JS      -> exit 0
  entry JS, chunk 200 + HTML -> exit 1, "BROKEN", 1 referenced / 0 loadable
The last case is the one that matters: it is precisely the blank-panel failure,
and a probe that only fetched the entry would have called it green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
@github-actions
github-actions Bot requested a review from izzywdev as a code owner August 24, 2026 23:07
@github-actions github-actions Bot added the auto-merge Enable squash auto-merge once CI passes label Aug 24, 2026
Path-scoped, not on every PR — it hits LIVE production. It fires when the
instrument changes, so a change to the detector is validated by using it
rather than first executing for real only after it merges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
@github-actions
github-actions Bot enabled auto-merge (squash) August 24, 2026 23:07
…cated a 404

The first run reported 16 of 16 apps broken. Fifteen of those are real. The
sixteenth, `keys`, was the probe's own bug.

The frozen contract allows an absolute http(s) `remoteEntry` for remotes hosted
outside the cluster, and fuzekeys uses one:
https://keys.prod.fuzefront.com/apps/fuzekeys/remoteEntry.js

The probe only ever tried /apps/<slug>/... on the host origin. For fuzekeys that
404 was CORRECT — nothing is supposed to be served there — and the probe turned
it into a failure report. A probe that manufactures a failure is as harmful as
one that hides a real failure: both make the whole report untrustworthy, and
this one would have sent someone to debug an ingress that is not meant to exist.

Each entry is now either `slug` (probe the two same-origin layouts) or
`slug=<absolute url>` (probe exactly what the manifest declares). The workflow
default carries fuzekeys in the second form.

Verified, not assumed — the absolute form is proven to actually bypass --base:
  --base https://app.example.invalid --slugs aliased=http://127.0.0.1:8791/...
  -> exit 0, entry reported as the absolute URL.
If the code had still resolved against --base, that case would have failed.
Same-origin form re-tested unchanged, and the four earlier non-vacuity cases
still hold.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv

@izzywdev izzywdev left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

All CI gates pass (gate-authz, gate-ds-conformance, gate-identifier, gate-frames-first, gate-test, gate-lint, gate-build, gate-sast, gate-toolchain, gate-version, gate-localup, etc.). Approving per governance policy.

@izzywdev
izzywdev merged commit 92845ba into master Aug 26, 2026
56 of 57 checks passed
@izzywdev
izzywdev deleted the claude/prod-federation-probe branch August 26, 2026 05:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-merge Enable squash auto-merge once CI passes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant