Skip to content

chore(release): 0.9.1 - make the health module edge-safe by construction - #20

Merged
vreshch merged 1 commit into
masterfrom
fix/edge-safe
Aug 10, 2026
Merged

chore(release): 0.9.1 - make the health module edge-safe by construction#20
vreshch merged 1 commit into
masterfrom
fix/edge-safe

Conversation

@vreshch

@vreshch vreshch commented Aug 10, 2026

Copy link
Copy Markdown
Member

Fixes the production outage 0.9.0 caused, in the library rather than in each consumer.

What happened

0.9.0 added process.uptime() - the only Node API this module has ever contained. Every gated route on admin.agentage.io then 500’d, in an app that only ever wanted links from the shared barrel.

The chain: the @agentage/shared barrel re-exports @agentage/observability/healthmiddleware.ts imports the barrel → middleware runs in the Edge Runtime. Next detects Node APIs in edge bundles statically, so the typeof process?.uptime === "function" guard I wrote around the call was worthless - the check never runs. The module threw at evaluation and the gate failed before any page rendered.

Dropping the re-export fixes the symptom per repo (agentage/admin#46). This fixes the cause, so no future consumer can be poisoned by importing a barrel.

The fix

performance.timeOrigin is the same instant to the millisecond - verified 0ms delta against the uptime-based value - and is a Web API present in Node, the Edge Runtime and browsers alike.

dist/health.js now references exactly one process property: process.env, which Next supports in edge bundles and which the entire commit/buildTime provenance story rests on.

The guard

test/edge-safety.test.ts is a source-text test, deliberately. A behavioural test cannot catch this class of bug - the code works perfectly under Node. The only thing that fails is a bundler reading the source, so that is what the test reproduces.

It scans raw text including comments, because tsc emits comments into dist and not every analyzer that might read this package parses an AST rather than grepping. It also scans dist when a build exists, and pins the module’s no-imports property.

It fired on its first run - on the comment explaining the fix. I reworded the comment rather than exempting comments: a name that must not appear in the shipped artifact must not appear in prose either.

Verification

npm run verify green: 115 tests (15 in the new edge-safety suite), build, dist smoke. Post-build scan of dist/health.js shows process.env and nothing else.

Consumers should still prefer not re-exporting the kit from an edge-imported barrel - this makes that a hygiene preference rather than an outage.

0.9.0 introduced the one Node API this module has ever had, and it took down
admin.agentage.io: every gated route 500'd, in an app that only ever wanted
`links` from the shared barrel.

The barrel re-exports this module, middleware.ts imports the barrel, and
middleware runs in the Edge Runtime. Next detects Node APIs in edge bundles
STATICALLY, so the `typeof` guard I wrote around the call was worthless - the
check never runs. The module threw at evaluation and the gate failed before any
page rendered.

performance.timeOrigin gives the same instant to the millisecond (verified: 0ms
delta) and is a Web API present in Node, the Edge Runtime and browsers. The
module now has no Node APIs beyond process.env, which Next supports in edge
bundles and which the whole provenance story rests on.

test/edge-safety.test.ts keeps it that way. It is a source-text test on purpose:
a behavioural test cannot catch this, because the code works perfectly under
Node - the only thing that fails is a bundler reading the source. It scans raw
text INCLUDING comments, since tsc emits comments into dist and not every
analyzer parses an AST rather than grepping. It also scans dist when one exists,
and asserts this module keeps its no-imports property.

The guard fired on its first run, on the comment explaining the fix. Reworded
rather than exempted: a name that must not appear in the shipped artifact must
not appear in prose either.

Downstream repos can drop their barrel workarounds after bumping, though
dropping the re-export is still better hygiene than relying on this.
@vreshch
vreshch merged commit 7ce674a into master Aug 10, 2026
1 check passed
@vreshch
vreshch deleted the fix/edge-safe branch August 10, 2026 01:43
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