Skip to content

fix(sim): keep a region switch routing when its numbers are not numbers - #63

Merged
xevrion merged 1 commit into
xevrion:mainfrom
kevin9327:fix/region-nan
Sep 7, 2026
Merged

fix(sim): keep a region switch routing when its numbers are not numbers#63
xevrion merged 1 commit into
xevrion:mainfrom
kevin9327:fix/region-nan

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

What

Two numbers on the region node are read with Math.floor and then compared, and NaN fails every
comparison, so it survives both readings intact. One of them takes the switch off the air; the other
makes the panel contradict the routing it is derived from.

const declared = Math.floor(state.config.regions ?? state.out.length);
return Math.max(1, Math.min(declared, state.out.length));   // NaN in, NaN out

const configured = Math.floor(cfg.activeRegion ?? 0);
const wanted = configured < 0 ? 0 : configured >= count ? count - 1 : configured;   // NaN

Measured

One client, one region node, two regions behind it. 200 ticks:

config                  activeRegion  regionsTotal  regionsHealthy   east   west   failed
(baseline)                         0             2               2    208      0        0
regions: NaN                       0           NaN               0    208      0        0
activeRegion: NaN                NaN             2               2      0      0      170

activeRegion: NaN is an outage. NaN is adopted as the live region, state.out[NaN] is nothing,
so regionHealthy is false forever and the switch serves neither region. Every request fails.

regions: NaN is quieter and, I think, the more interesting one. regionsTotal reaches the panel
as NaN and regionsHealthy reads 0, because the census is a loop and i < NaN is false on the
first test. Routing is unaffected — 208 requests are served — so the node reports "0 of NaN regions
healthy" while it is healthily serving one. decorateStats says of that census:

from the same predicate pickEdge routes with, so the readout and the routing can never disagree
about reachability

which is exactly the property NaN removes.

Where it comes from

Not the inspector: regions is a number input bounded 1..8 and activeRegion 0..7. isTopology
checks the nine core config numbers — capacity, serviceMs, serviceCv, queueLimit, hitRate,
errorRate, timeoutMs, retries, rps — and neither of these, so a shared link, a .breakscale
file and a restored session carry them through untouched.

Fix

regionCount falls back to the edge count for anything that is not a finite number, which is the
same thing an absent regions already means.

The two places that clamp activeRegion were the same four lines written twice; they are now one
configuredRegion helper, which rejects a non-finite value as the first region. Deduplicating them
is not incidental — the second copy is in liveRegionIndex, whose whole job is to answer exactly
what pickEdge would do, so the two must not be able to drift.

Tests

src/sim/behaviour-control.region.test.ts, new:

  • an activeRegion of NaN still routes, publishes a real region index and fails nothing
  • a regions of NaN publishes a real total and counts both regions healthy
  • the readout and the routing agree: a node serving traffic cannot report zero healthy regions
  • an unset design and an explicit { regions: 2, activeRegion: 0 } produce identical completions,
    which is the check that nothing a reader can build moved
  • activeRegion: 1 still sends everything to the second region

Against main, three of the five fail:

× still routes when the active region is not a number
× counts its regions when the declared count is not a number
× keeps the readout and the routing agreeing
AssertionError: expected true to be false
AssertionError: expected 0 to be greater than 0

How I tested

Windows 11, Bun 1.3.14. bun run test is 934 passed across 40 files, up from 929 by the five new
tests, with nothing else moving. bun run typecheck and bun run format:check are clean, and
bun run lint reports the same pre-existing warnings in useVendor.ts, Examples.tsx and
Tooltip.tsx as main does.

Same family as #58, #60, #61 and #62, but this one is not about allocation: the region node's numbers
are small, and what NaN costs here is the routing and the readout rather than the process.

@kevin9327
kevin9327 requested a review from xevrion as a code owner September 6, 2026 11:51
@vercel

vercel Bot commented Sep 6, 2026

Copy link
Copy Markdown

@kevin9327 is attempting to deploy a commit to the whoarrryou's projects Team on Vercel.

A member of the Team first needs to authorize it.

@xevrion

xevrion commented Sep 7, 2026

Copy link
Copy Markdown
Owner

LGTM, thanks!

@xevrion
xevrion merged commit 1f4c63b into xevrion:main Sep 7, 2026
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants