Repository navigation
fix(relay-ops): recalibrate the pre-roll monitor gate to chronic production baselines - #21241
Conversation
The 15-minute pre-drain dry-run froze 39 times out of 39 on conditions that have nothing to do with the roll it gates: - A cell probe is one HTTP round trip from one runner. When the Asia cells' readiness SQL probe times out behind a saturated pool, the load balancer answers "no healthy upstream" for ~30 s and the gate froze on a single sample. Cell probe signals now need more than cellProbeToleranceSamples consecutive failing samples to freeze; absorbed blips are recorded in the state artifact. Director and auth probes keep zero tolerance. - directorErrors 3 -> 15. Measured non-503 5xx per rolling five minutes over the 24 h to 2026-09-17: p90 3 / p95 5 / p99 9 / max 52. The old bar sat on the p90 and froze 29% of gates. - cloudSqlBackends 250 -> 320. Measured latest-sum over the same 24 h: p95 212 / p99 262 / max 282. The old bar sat under the observed peak and froze 22% of gates. Failure codes are unchanged so downstream matchers keep working, and the trusted evidence scripts are untouched.
…flight Three review findings on the cell-probe tolerance: - The streak was keyed per signal, so a cell alternating between slow (latency over bar) and down (health/ready 0) held every individual streak at one and never reached the tolerance. A continuously unhealthy cell passed the gate. The streak is now keyed by cell id, so one cell's health, ready and latency readings share it. - The live preflight runs one sample before every mutating wave and retried only on freshness codes, so the same Asia blip could still fail a wave there. It now re-samples per-cell probe breaches on the same tolerance, spaced the existing interval. Director and auth probes still fail the wave on the first bad sample, as does any non-probe threshold. - docs/relay-incident-monitor.md still stated the old bars. Updated the threshold table, the 400-connection ceiling text, and the superseded 2026-08-26 and 2026-09-12 entries, and added a dated 2026-09-17 recalibration entry. Also pins the resumed-state case: a state file carrying a full streak now has a test proving it freezes on the next bad sample. Trusted evidence scripts remain untouched.
There was a problem hiding this comment.
ℹ️ No critical issues — minor suggestions inline. The threshold recalibration is well-evidenced and the monitor-side per-cell tolerance is sound; the two notes below are about the live preflight not quite matching the monitor's tolerance in practice.
Reviewed changes
- Cloud SQL backends 250 → 320 and director 5xx 3 → 15. Measured 24 h percentiles are recorded next to each constant and in
cloud/docs/relay-incident-monitor.md; the newcloudSqlBackendsbar also aligns with the pre-existingCLOUD_SQL_LIMIT = 320inrelay-asia-rollout-evidence.mjs. Bounds are exercised exactly (282 green / 321 freeze; 15 green / 16 freeze). - Per-cell active-probe tolerance in
incident-monitor.ts.cellProbeStreakKeykeys by cell sohealth/ready/latency_msshare one streak, director/auth probes returnnulland stay zero-tolerance, and absorbed breaches are sealed undertoleratedProbeEvents. I traced every write toprobeStreaks: a cell that fails on every fresh sample it is evaluated against cannot escape freezing on the third. - Live preflight re-sampling for cell-probe breaches with independent freshness/probe budgets, so a single pre-wave sample no longer hard-fails on a probe blip.
- State compatibility.
probeStreaks/toleratedProbeEventsare optional-with-defaults in the CLIStateSchema,schemaVersionstays 4, and the evidence validators check fields individually so the manifest hash chain is unaffected.
️ Nitpicks
cloud/infra/terraform/relay-observability.tf:622(out of diff, so not anchored) still documents the alert as firing before the "400-connection ceiling" / "modeled 385-connection operating maximum", while this PR rebases the shared model onmax_connections500 / 490 usable (relay-cloud-sql-connection-budget.test.mjsnow expectsoperatingMaximum403). Since the PR deliberately refreshed the stale ceiling text in the monitor doc, this sibling reference is now inconsistent with it.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
| // gate learned to ride it out. Hold the two to the same tolerance. Unlike the | ||
| // freshness retry this needs no flag, because a per-cell probe breach is never | ||
| // the operator's call to waive. | ||
| const cellProbeAttempts = 1 + INCIDENT_MONITOR_THRESHOLDS.cellProbeToleranceSamples |
There was a problem hiding this comment.
The preflight copies the monitor's sample count but not its cadence: attempts is 3 here, and retries are spaced by FRESHNESS_RETRY_INTERVAL_MS (15 s), while the monitor needs 3 samples 60 s apart. So the preflight tolerates ~30 s of continuous probe failure versus the monitor's ~120 s, and the cited ~30 s "no healthy upstream" window can still land in three 15 s samples and fail the wave — the outcome this change targets. If parity is the goal, scale the attempt count by the cadence ratio or bound the loop by a wall-clock deadline.
Technical details
# Preflight probe tolerance is ~4x stricter than the monitor's in wall-clock time
## Affected sites
- `cloud/apps/relay-ops/src/incident-live-preflight-cli.ts:178` — `cellProbeAttempts = 1 + cellProbeToleranceSamples` (= 3).
- `cloud/apps/relay-ops/src/incident-live-preflight-cli.ts:20` — `FRESHNESS_RETRY_INTERVAL_MS = 15_000`.
- `cloud/apps/relay-ops/src/incident-monitor.ts:142,904,907,988` — freeze needs `streak > 2` at `state.intervalMs` (60 s), i.e. 3 samples / ~120 s.
## Required outcome
- A ~30 s per-cell probe outage should not fail a mutating wave, matching the monitor gate's stated intent.
## Suggested approach
- Derive the retry count from the cadence ratio (`1 + tolerance * intervalMs / retryIntervalMs`), re-sample probe breaches on the monitor interval, or bound the loop by a wall-clock deadline tied to the tolerated outage length.| const cellProbeAttempts = 1 + INCIDENT_MONITOR_THRESHOLDS.cellProbeToleranceSamples | ||
| const attempts = Math.max(freshnessAttempts, cellProbeAttempts) | ||
| let freshnessRetries = freshnessAttempts - 1 | ||
| let cellProbeRetries = cellProbeAttempts - 1 |
There was a problem hiding this comment.
cellProbeRetries is a single counter shared across all cells, but the monitor's tolerance is a per-cell streak. Two different cells that each blink once on successive samples draw down both retries and throw on the third, even though the monitor would keep two independent streaks of 1 and tolerate both. Since the comment above claims to select per-cell breaches only, keying this budget by cellProbeStreakKey(failure) would match the monitor's behavior.
Technical details
# Preflight probe budget is global, not per cell
## Affected sites
- `cloud/apps/relay-ops/src/incident-live-preflight-cli.ts:181,196-198,215` — one flat `cellProbeFailures` list and one `cellProbeRetries` counter across all cells.
- `cloud/apps/relay-ops/src/incident-monitor.ts:892-905` — monitor streaks are keyed per `cellProbeStreakKey`.
## Required outcome
- Single-sample breaches from different cells must not combine into a tolerance breach for any one cell.
## Suggested approach
- Track a per-key consecutive-breach count in the preflight and throw only when a single key exceeds `cellProbeToleranceSamples`.…uction baselines (stablyai#21241) * fix(relay-ops): let the pre-roll gate ride out chronic production noise The 15-minute pre-drain dry-run froze 39 times out of 39 on conditions that have nothing to do with the roll it gates: - A cell probe is one HTTP round trip from one runner. When the Asia cells' readiness SQL probe times out behind a saturated pool, the load balancer answers "no healthy upstream" for ~30 s and the gate froze on a single sample. Cell probe signals now need more than cellProbeToleranceSamples consecutive failing samples to freeze; absorbed blips are recorded in the state artifact. Director and auth probes keep zero tolerance. - directorErrors 3 -> 15. Measured non-503 5xx per rolling five minutes over the 24 h to 2026-09-17: p90 3 / p95 5 / p99 9 / max 52. The old bar sat on the p90 and froze 29% of gates. - cloudSqlBackends 250 -> 320. Measured latest-sum over the same 24 h: p95 212 / p99 262 / max 282. The old bar sat under the observed peak and froze 22% of gates. Failure codes are unchanged so downstream matchers keep working, and the trusted evidence scripts are untouched. * fix(relay-ops): key probe tolerance by cell and extend it to live preflight Three review findings on the cell-probe tolerance: - The streak was keyed per signal, so a cell alternating between slow (latency over bar) and down (health/ready 0) held every individual streak at one and never reached the tolerance. A continuously unhealthy cell passed the gate. The streak is now keyed by cell id, so one cell's health, ready and latency readings share it. - The live preflight runs one sample before every mutating wave and retried only on freshness codes, so the same Asia blip could still fail a wave there. It now re-samples per-cell probe breaches on the same tolerance, spaced the existing interval. Director and auth probes still fail the wave on the first bad sample, as does any non-probe threshold. - docs/relay-incident-monitor.md still stated the old bars. Updated the threshold table, the 400-connection ceiling text, and the superseded 2026-08-26 and 2026-09-12 entries, and added a dated 2026-09-17 recalibration entry. Also pins the resumed-state case: a state file carrying a full streak now has a test proving it freezes on the next bad sample. Trusted evidence scripts remain untouched.

ELI5
Before we change anything in the relay fleet, a 15-minute safety check runs and
looks at a long list of production health signals. If any of them look wrong, it
stops the change.
That check has been stopping us for the wrong reason. It has run 39 times and
stopped 39 times, every single time on a problem that was already there before
the change and has nothing to do with it. So it has not been protecting anything
for the last 8.5 hours, it has just been saying "no" to everything.
This PR teaches the check to ignore three kinds of everyday background noise it
was mistaking for danger, while still stopping on the real thing.
What Changed
Before: the pre-drain dry-run froze on every run. Of the last 14 freezes, 7
were an Asia cell's health probe reading zero for one sample, 5 were the director
reporting 4-9 server errors against a bar of 3, and 2 were the auth database
holding 272-281 connections against a bar of 250.
After: the same run passes on those conditions and still freezes on the
failures it exists to catch.
Three changes, all in the monitor:
1. A cell health probe now has to fail repeatedly, not once. Each sample is a
single HTTP round trip from one GitHub runner to one cell. The Asia cells run
their readiness check as a
SELECT 1against Cloud SQL in us-central1, a 176 msround trip, behind a 2-second timeout. When the connection pool is busy that
check times out, the load balancer answers "no healthy upstream" for about 30
seconds, and the monitor recorded
health=0andready=0.The important detail is that "no healthy upstream" arrives as a real HTTP 503
response, not as a dropped connection. So the monitor cannot tell it apart from a
cell that is genuinely serving an unhealthy answer by looking at where the
answer came from. What does tell them apart is how long it lasts: the load
balancer case clears in about 30 seconds, and the sample interval is 60 seconds,
so it shows up in one sample and at worst two. A genuinely broken cell stays
broken.
So per-cell probe signals now need to fail more than
cellProbeToleranceSamples(2) consecutive samples before they freeze the run. The director and auth probes
are deliberately excluded and keep zero tolerance, because they are the single
points of failure this gate mainly exists to catch. A blip that gets absorbed is
written into the sealed state artifact under
toleratedProbeEvents, so a passingrun still shows exactly what the gate chose not to stop on.
The streak is keyed by cell, not by signal. A cell's health, ready and latency
readings all describe the same round trip, so they share one streak. Keyed per
signal instead, a cell that alternates between answering slowly and not answering
at all would hold every individual streak at one and never reach the tolerance,
which would let a continuously unhealthy cell through. There is a test for exactly
that shape.
The same tolerance applies to the live preflight. A separate check collects one
sample immediately before every mutating wave, and it previously retried only on
freshness codes. That left the identical hole: the same 30-second blip could pass
the 15-minute gate and then fail the wave seconds later. It now re-samples per-cell
probe breaches up to the same tolerance, spaced by the existing retry interval and
still capped by the same evidence-age budget. Director and auth probes, and every
non-probe threshold, still fail the wave on the first bad sample.
2.
directorErrors3 -> 15. This counts non-503 5xx answers from thedirector over a rolling five-minute window.
3.
cloudSqlBackends250 -> 320. This is the connection count on the authdatabase instance, summed across its seven databases.
Failure codes in the artifact are unchanged, so the tooling that matches on the
source/codeprefix keeps working. The trusted evidence scripts undercloud/dev/scripts/are not touched by this PR.cloud/docs/relay-incident-monitor.mdis updated to match: the threshold table,the stale 400-connection ceiling text, a note on the probe tolerance, and a dated
2026-09-17 entry in the recalibration log alongside the prior ones. The superseded
2026-08-26 backends entry and 2026-09-12 director-error note now say so.
Why
This loosens a safety gate. Here is why it is still safe.
A gate that has refused 39 of 39 runs is not adding safety, it is only adding
delay, and the pressure it creates is to bypass it by hand, which is strictly
worse than a calibrated gate. Each new bar below is set from measured production
data over the 24 hours to 2026-09-17, read through the Cloud Monitoring API with
the same aggregation the monitor itself uses.
director.errors, non-503 5xx per rolling 5 minutes:The old bar of 3 sat exactly on the p90, so 9.2% of individual windows and 29.0%
of 15-minute gates froze on ordinary load. 15 sits above the chronic p99 and
brings the baseline freeze rate to 1.5%. It is deliberately not set above the
20-52 bursts, so those remain detectable. For scale, the director answers roughly
50 requests a minute in 503s alone, so a director that is actually broken serves
5xx in the hundreds per window, an order of magnitude clear of this bar.
cloud_sql.backends, summed per minute:The old bar of 250 was below the observed maximum, which is why it could never
be reliably cleared: 1.95% of minutes and 21.8% of 15-minute gates tripped on it.
320 clears every measured healthy minute with 13% of headroom above the peak, and
still fires at 65% of the 490 connections the budget work (#21165 / orca-cloud
#487) treats as usable out of
max_connections500, leaving 170 connections inhand. Connection exhaustion is a runaway, not a plateau, so it crosses 320 on its
way to 490.
Alternatives considered.
Leave the bars and bypass the gate by hand. Rejected: it throws away the
evidence trail for every future roll, not just this one.
Make the thresholds dispatch-time inputs in the job YAML. Rejected, even though
the brief suggested keeping them configurable where they already are. They are
not currently configurable anywhere: they are code constants, and the whole set
is sealed into every checkpoint artifact as
thresholds. That is what makes arecorded green run auditable after the fact. Moving them to workflow inputs would
let an operator loosen the gate at dispatch time with no review and no stable
record of what bar was actually applied. Changing them in code, with the
measurement written next to the number, is the property worth keeping.
Discriminate the cell probe by provenance instead of persistence, that is, treat
a failed fetch differently from a served
health=0. Rejected after reading theprobe:
probePathalready retries a thrown fetch once and only then reportsok: false, and the actual production symptom arrives as an HTTP 503 from theload balancer, which is a real answer. Provenance cannot separate the two cases
here. Persistence can, which is also the discriminator the file already uses for
freshness failures.
Raise the cell latency bar again. Rejected: that was done on 2026-09-05 for this
same pair of cells and did not address
health/readyreading zero, which is thesignal actually freezing the gate now.
The design reuses the shape already in this file.
INCIDENT_FRESHNESS_TOLERANCE_SAMPLESalready tolerates N consecutive unreadable samples per signal key; the new probe
tolerance is the same per-key streak idea, with the difference that exceeding it
freezes the run rather than restarting the window.
Linked Issue
No GitHub issue. This came from the relay same-cap rollout being blocked for 8.5
hours on the pre-roll gate.
cloud/docs/relay-reconnect-2026-09-findings.mdrecords the same recommendation from an earlier session, where ten dry-runs
produced four freezes on
directorErrorsalone and recalibration was written upas follow-up work that was never done.
Visual Proof
N/A. This changes a CI safety gate's arithmetic and has no user-facing surface.
Testing
pnpm --filter @orca-cloud/relay-ops testandpnpm --filter @orca-cloud/relay-ops typecheck, both green at 12 files and 106 tests.Six new tests in
incident-monitor.test.tsdrive the probe tolerance end to endthrough
runIncidentMonitor:blip is still recorded in the artifact
per-signal keying would have let through
Four new tests in
incident-live-preflight-cli.test.tscover the preflight side:an outage within the tolerance lets the wave proceed after re-sampling, an outage
past it fails the wave, and neither a director probe failure nor a non-probe
threshold breach causes any re-sampling at all.
The two existing threshold tests were updated to the new bars and now assert the
measured healthy peak passes.
I verified the tests bite rather than passing vacuously, by mutating the source and
confirming the intended tests fail each time:
cloud/dev/scripts/relay-monitor-evidence.test.mjsandrelay-production-capacity-wave.test.mjsalso pass at 19 tests, confirming thestate artifact still satisfies the trusted evidence validators.
Not verified:
cloud/apps/pushfailstypecheckon this branch, onretryLockTimeoutnot existing inSchemaStartupOptions. That file is untouchedby this PR (
git diff origin/main -- cloud/apps/pushis empty), so it ispre-existing on main.
Platforms: this is Node code that runs on the CI Ubuntu runner only. Verified on
macOS locally.
AI Disclosure
Review
Note on evidence authority: editing the monitor's code invalidates any sealed
canary authority that depends on these paths. No canary evidence is sealed at the
time of writing, so nothing is invalidated by this PR. Any dry-run evidence sealed
before this merges was produced under the old bars and should not be reused to
justify a roll after it.
The state file gains two fields,
probeStreaksandtoleratedProbeEvents. Bothare optional with defaults in the CLI's zod schema, so
schemaVersionstays at 4and a state file written by the previous version still restores. This follows the
tolerated: z.boolean().default(false)precedent already in that schema. Bothevidence validators check fields individually rather than strictly, so the added
fields do not affect them.
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
Security: no change to identity, tokens, or admin call paths. The gate is
read-only. Backwards compatibility: covered above, state files restore across the
change. Performance: the streak bookkeeping is a per-sample map operation over at
most a handful of keys. SSH/mobile/cross-platform: not applicable, this runs only
in the production monitor workflow.
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)