Skip to content

release: 17.0.0 — a bound whose own NaN made its guard read false, in 129 places - #378

Merged
sebyx07 merged 1 commit into
mainfrom
release/17.0.0
Aug 26, 2026
Merged

release: 17.0.0 — a bound whose own NaN made its guard read false, in 129 places#378
sebyx07 merged 1 commit into
mainfrom
release/17.0.0

Conversation

@sebyx07

@sebyx07 sebyx07 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

One sweep, five slices, in tier order: #364 (tiers 0–1), #370 (2–3), #374 (4), #375 (5), #377 (the blind spots). This is the release commit.

bun run finite-bounds goes from 129 sites to 4, and both survivors are audited pins carrying the sentence saying why screening them would be worse — @ultimat3/ui's Textarea rows and @ultimat3/admin's logo.width, each with the one-line edit that overturns the decision. Not unexamined debt.

The defect class

?? guards nullish, and NaN is not nullish. So Number(process.env.X) on an unset variable, a parseInt of a typo and an untyped config value all walk past the default and land on the bound intact. Math.max, Math.min and Math.floor are not validators either — all three propagate NaN, and this repo was relying on all three as guards.

What it produced — each measured, not reasoned about

a NaN token estimate did not bypass the AI budget, it poisoned it — after one such call a 5,000,000-token request passed a 1,000-token ceiling
awaitActionable({ timeoutMs: NaN }) 835,462 polls in 3 seconds against a real browser, past ctx.signal, past the watchdog, past the job timeout
syncAuthenticator({ ttlMs: NaN }) held a revoked session across a full year of clock advance — sweepGrants answered {revoked: 0} and the book still held the socket
randomToken(NaN) returned "" — the framework's secret generator, producing no secret and reporting success
generateRecoveryCodes(Infinity) wedged the process on the enrolment path; NaN enrolled a user with zero recovery codes
configureLifecycle({ deadlineMs: NaN }) made a deploy drop in-flight requests and abandon close hooks on the first tick
an ISR entry with a non-finite TTL was never fresh, so the page regenerated on every request
chunk({ size }), embedBatched synchronous infinite loops, past every AbortSignal

Three breaking entries, all the same shape

A numeric option that used to accept NaN refuses it — at boot or at the call boundary, never mid-request, so one bun test or one x verify surfaces every one at once and each fix: carries the edit.

An app passing real numbers is unaffected. An app passing NaN was not working: the bound it declared was not being enforced, and nothing said so.

0 stays legal everywhere it means somethingport: 0 asks the OS for a free port, timeout: 0 is one look, seed: 0 is a seed, maxAgeSeconds: 0 is "revalidate every time", concurrency: 0 is one worker. Every floor is pinned by a mutation in both directions, and four floors were chosen by intuition and corrected by a grepkdf.maxConcurrent: 0 is a deliberate zero-width gate, retentionPlan(deploys, 0) and Skeleton lines: 0 are shipped tests.

wiki/Upgrading.md gains its 16.x → 17.0.0 walkthrough, one row per entry.

The ratchet shipped with the sweep, and was widened three times by defects that walked past it

An optional chain on the object; a default read out of a table of numbers; and bare parameter defaults. All three found the same way — by testing the guard rather than reading it, never by reading it.

Two more corrections in the same spirit:

  • A clause added to that regex measured inert — 59 sites with it and without — and was deleted rather than left reading as a rule holding a line it was not holding.
  • Its non-vacuity guard broke because the tree got better. It asserted total > 10, calibrated at 129 sites, so it failed as the count approached zero. A count is the wrong instrument once the count is meant to reach zero. It now asserts every pinned package still reports exactly its pinned count — those sites are deliberately unrepaired, so they are the one thing a working scanner is guaranteed to find. Blinding the scanner turns 9 tests red.

And one rule I proposed was measured and declined: a second matcher for the !== undefined assignment form would find ~1 site per two packages (24 occurrences across core+auth, exactly one numeric).

Docs made true, not restated

CLAUDE.md said @ultimat3/notify "has never been published" and owed step 1 of PUBLISHING.md before the next release run. That was true when written, and the 16.0.0 run published it — bun run scripts/registry-audit.ts --json answers 31/31 publishable packages are on npm at 16.0.0, every one attested. Following that paragraph would have produced E403 … cannot publish over the previously published versions. Corrected to point at the audit instead, which is what the whole table on that page exists for.

Verification

bun run verify14 of 20 passed, 6 skipped. bun run scripts/release.ts --check 17.0.031 packages stamped at 17.0.0. bun run scripts/reference-app-gate.tsevery pin holds. bun install --frozen-lockfile → no changes.

The first release-gate run was red on 2 steps, both post-bump bookkeeping with executable fixes: 232 stale workspace ranges in bun.lock and a v16.0.0 stamp in wiki/_Footer.md. Note bun install alone would not have fixed the lockfile — Bun refreshes a workspace block only when that workspace's own manifest changed, and --frozen-lockfile accepts every stale range, which is why this repo has a dedicated lockfile:fix.

After merge

Annotated tag (git tag -a — a lightweight tag is not a release trigger and --follow-tags will not push one), then the GitHub Release, which is what fires release.yml. The workflow then reaches waiting on the npm-publish environment gate — that reads as waiting, not a failure, and is the last point at which an irreversible publish can be stopped.

Filed during the sweep, not fixed by it

#376 — a third toMs, in packages/jobs/src/clock.ts:18, with no screen at all and a comment reading "Numbers pass through so callers may stay explicit". It is the one step.sleep's wake time, the retry curve's base/max and every job timeout go through, so step.sleep(Number(process.env.X)) is still a sleep that never ends.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

… 129 places

One sweep, five slices, in tier order: #364 (tiers 0–1), #370 (2–3), #374 (4),
#375 (5), #377 (the blind spots). `bun run finite-bounds` goes from 129 sites to
4, and both survivors are AUDITED pins carrying the sentence saying why
screening them would be worse, not unexamined debt.

THE DEFECT CLASS. `??` guards nullish and `NaN` is not nullish, so
`Number(process.env.X)` on an unset variable, a parseInt of a typo and an
untyped config value all walk past the default and land on the bound intact.
`Math.max`, `Math.min` and `Math.floor` are not validators either — all three
PROPAGATE NaN, and this repo was relying on all three as guards.

What that produced, each measured rather than reasoned about:

  a NaN token estimate did not bypass the AI budget, it POISONED it — after one
  such call a 5,000,000-token request passed a 1,000-token ceiling;
  `awaitActionable({ timeoutMs: NaN })` ran 835,462 polls in 3 seconds against a
  real browser, past ctx.signal, past the watchdog, past the job timeout;
  `syncAuthenticator({ ttlMs: NaN })` held a revoked session across a full year
  of clock advance;
  `randomToken(NaN)` returned "" — the framework's secret generator, producing
  no secret and reporting success;
  `generateRecoveryCodes(Infinity)` wedged the process on the enrolment path,
  and `NaN` enrolled a user with zero recovery codes;
  `configureLifecycle({ deadlineMs: NaN })` made a deploy drop in-flight
  requests and abandon close hooks on the first tick;
  an ISR page with a non-finite TTL was never fresh, so it regenerated on EVERY
  request;
  `chunk({ size })` and `embedBatched` were synchronous infinite loops.

THREE BREAKING ENTRIES, all the same shape: a numeric option that used to accept
NaN refuses it, at boot or at the call boundary rather than mid-request. An app
passing real numbers is unaffected. An app passing NaN was not working — the
bound it declared was not being enforced, and nothing said so. `0` stays legal
everywhere it means something: port 0 asks the OS for a free port, timeout 0 is
one look, seed 0 is a seed, maxAgeSeconds 0 is "revalidate every time".

THE RATCHET SHIPPED WITH THE SWEEP AND WAS WIDENED THREE TIMES BY DEFECTS THAT
WALKED PAST IT — an optional chain on the object, a default read out of a table
of numbers, and bare parameter defaults. All three were found the same way: by
TESTING the guard rather than reading it. One clause added along the way
measured inert and was deleted rather than left reading as a rule holding a line
it was not holding. Its non-vacuity guard also broke because the tree got
better: `total > 10` was calibrated at 129 sites, so it failed as the count
approached zero. It now asserts that every PINNED package still reports exactly
its pinned count.

Docs made true rather than restated: CLAUDE.md said `@ultimat3/notify` had never
been published and owed a hand publish before the next release run. True when
written; the 16.0.0 run published it, and the audit answers 31/31 attested — so
following that paragraph would have produced an E403.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Warning

Review limit reached

  • Run on-demand review

On-demand reviews are free for the next 25 days. After that, they cost $0.25 per reviewed file.

Or wait 2 minutes for your next included review.

View limit details

Limit details: You’ve used the included review currently available. Your 76 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bf018478-da9a-4416-ad19-00b108b19a7f

📥 Commits

Reviewing files that changed from the base of the PR and between e33e32e and 87920f6.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock, !**/bun.lock
📒 Files selected for processing (48)
  • CHANGELOG.md
  • CLAUDE.md
  • docker/helm/Chart.yaml
  • dummy/social-media-clone/package.json
  • dummy/social-media-clone/packages/i18n/package.json
  • examples/dummy/apps/admin/package.json
  • examples/dummy/apps/web/package.json
  • examples/dummy/package.json
  • examples/dummy/packages/core/package.json
  • examples/dummy/packages/db/package.json
  • examples/dummy/packages/domain/package.json
  • examples/dummy/packages/i18n/package.json
  • examples/dummy/packages/mcp/package.json
  • examples/dummy/packages/ui/package.json
  • framework.manifest.json
  • packages/action/package.json
  • packages/admin/package.json
  • packages/ai/package.json
  • packages/auth/package.json
  • packages/cache/package.json
  • packages/cli/package.json
  • packages/core/package.json
  • packages/create-ultimate/package.json
  • packages/db/package.json
  • packages/entity/package.json
  • packages/flags/package.json
  • packages/http/package.json
  • packages/i18n/package.json
  • packages/jobs/package.json
  • packages/mail/package.json
  • packages/manifest/package.json
  • packages/mcp/package.json
  • packages/money/package.json
  • packages/notify/package.json
  • packages/policy/package.json
  • packages/pwa/package.json
  • packages/query/package.json
  • packages/realtime/package.json
  • packages/render/package.json
  • packages/schema/package.json
  • packages/scraping/package.json
  • packages/seo/package.json
  • packages/storage/package.json
  • packages/testing/package.json
  • packages/time/package.json
  • packages/ui/package.json
  • wiki/Upgrading.md
  • wiki/_Footer.md

Comment @coderabbitai help to get the list of available commands.

@sebyx07
sebyx07 merged commit a4857f1 into main Aug 26, 2026
38 checks passed
@sebyx07
sebyx07 deleted the release/17.0.0 branch August 26, 2026 20:54
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.

1 participant