synthetic-traffic: require evidence before paging on an all-failed tick - #151
Merged
Conversation
A tick with one real action and one transient on-chain failure read as 100% and paged as a total outage. The all-failed alert now needs a tick wide enough to stand on its own or a run of consecutive all-failed ticks, and counts aggregator payments in the denominator they already failed into.
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.
What broke
On 2026-08-03 19:44Z the engine paged Discord with
every action this tick failed (1/1) — platform down or config broken?while it was healthy: deposits and sends completed on the ticks either side. That tick planned exactly ONE action, a deposit tomeli-mercosur:BRwhose bundle FAILED on-chain, andfailures === batch.length && batch.length > 0has no floor on the denominator, so one transient failure reads identically to a total outage.Task:
theahaco-submodule-0024.What changed
Alert policy moves into
synthetic-traffic/alerts.tsas a pure fold over tick outcomes, unit-tested;main.tscounts the tick and hands the numbers to it.MIN_ALL_FAILED_ACTIONS = 4real actions. The planner samples Poisson arrivals per provider, so off-peak ticks routinely hold 1-2 actions; 4 independent actions failing back to back is not plausible transient noise, and it is still well under the 40-action cap so a genuine outage at any hour of the day clears the bar within a tick or two.ALL_FAILED_TICKS = 3consecutive ones (~15 min at the deployed 5-min cadence). A sustained outage during a quiet hour still pages promptly; an isolated transient never gets to a second tick, since any non-all-failed tick resets the streak.ALL_FAILED_REALERT_TICKS = 12(~hourly) while it holds, mirroring the stuck-tick alert.failuresbut were absent frombatch.length, so 2 clean batch actions next to 2 failed aggregator payments paged as "2/2" — a second false-positive path.attemptednow counts both loops, and only actions the engine actually ran (planned-but-skipped actions, missing actor/receiver, are excluded from both sides rather than padding the denominator).Unchanged on purpose: intentional seasoning failures (
actFail->injectFailingBundle) still never incrementfailures— they submit a bundle that FAILS on-chain and return normally, so the alert has never fired on on-purpose errors. The stuck-streak path (STUCK_ALERT_TICKS/REALERT_TICKS) is untouched. The two paths cannot double-page: a tick that throws never reaches the all-failed evaluation, and a tick that completes never counts toward the stuck streak.Verification
deno task test(newtesttask;@std/assertadded to imports) — 9 tests, all passing:The two cases that matter, end to end:
attempted=1, failures=1-> streak 1, below the floor, below the streak requirement -> silent. The next tick's deposit succeeds -> streak resets. No page, engine keeps running.7 >= 4-> pages on the first tick,every action this tick failed (7/7). If the outage starts during a quiet hour with 1-2 action ticks, the third consecutive all-failed tick pagesevery action failed for 3 consecutive ticks (latest 2/2)about 15 minutes in, then hourly until it clears.deno task check,deno lint(clean for the touched files; the pre-existingno-unused-varsinaggregators.tsis untouched) anddeno fmt --checkall pass.Notes
SYNTRAF_ONCE=truesmoke runs keep the broad-tick page while never accumulating a streak.alerts.ts.fly deploy -c synthetic-traffic/fly.testnet.toml --dockerfile synthetic-traffic/Dockerfilefrom the repo root. Nothing auto-deploys on merge.