feat(console): net origin offload, and catch up to plugin 0.64.1; v0.12.0 - #152
Conversation
…12.0 Origin offload is now stated twice. The existing figure — crawler requests not proxied live — is gross: it counts what the origin was spared and none of what this system asks of the origin in exchange. Net offload subtracts every origin request the deployment itself made, all from series already in the one analytics scan: proxied serves (bot_serve source=origin), renders (render/outcome, one row per posted result), change probes (probe_probed, a pass counter read by value) and sitemap fetches (sitemap_sitemaps). `originLoad` in charts.js carries the arithmetic so Traffic and the Overview cannot disagree; Traffic gains a "What the origin actually saw" panel with each term over time, the Overview tile carries the net figure under the gross one. Two things the number cannot know are stated on the panel, not assumed: a render counts as ONE origin request (the document), and the probe/sitemap counters land where a PASS FINISHED, so short ranges lump them — quote 24h. One term the plugin cannot see at all is exposed rather than omitted: whatever a crawler fetches from the origin after we hand it a page (a rendering crawler's scripts and the page's own API calls above all) never passes through this plugin. The net tile says "before crawler follow-up requests" and the panel reports every page handed to a crawler as the exposure — a count, never multiplied by a guessed factor, and for every crawler rather than a guessed subset of bots. The render fleet can measure the per-page factor; that is the follow-up. Catch-up to plugin 0.61–0.64.1: - `verified` (v0.63.0) is a cache serve. It sat outside every cache-served sum and fell into the "other" non-hit family; now one shared CACHE_SERVED set drives the freshness chart, the per-route table and the staleness sums, and it joins `invalidated` in one "Invalidation" family (one population: rescued and refused). - Invalidations gains a "what the invalidations are doing" panel reading page_verification, invalidation_reenqueue (incl. v0.64.0's forwarded / forward-failed — never added to lowered, the owner counts those) and invalidation_error (lkg-expired = failed OPEN). Two catalog-guard waivers removed; the guard's page_verification failure is what started this. - Change probe (v0.62.0): `stateAvailable: false` is named per node as "unknown, not idle"; a running sweep shows its heartbeat count. Co-Authored-By: Claude Code <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request updates the prerender console to version 0.12.0, introducing a new 'net offload' metric alongside the gross offload figure, and adding a new panel to the Invalidations view to show what invalidations are doing (including page verification and demand-driven heals). It also adds support for displaying probe sweep progress and handling unreadable probe state rows. The changes are accompanied by comprehensive unit tests. The review feedback suggests using the ratioOf helper function in charts.js to safely calculate the net offload ratio and handle potential division issues.
| total, | ||
| arrived, | ||
| // Null, never 0 or 100%: an empty window has no offload to report. | ||
| net: arrived > 0 ? (arrived - total) / arrived : null, |
There was a problem hiding this comment.
When calculating ratios or dividing metrics, use the ratioOf helper function to safely handle division and potential null/NaN values. This serves as an explicit guard at the call site and avoids relying on implicit null comparisons.
| net: arrived > 0 ? (arrived - total) / arrived : null, | |
| net: ratioOf(arrived - total, arrived), |
References
- When calculating ratios or dividing metrics, use a helper function (such as
ratioOf) to safely handle division and potential null/NaN values. This serves as an explicit guard at the call site, even if the inputs are currently guaranteed to be numbers.
There was a problem hiding this comment.
Taken — ratioOf(arrived - total, arrived) in edd9af1. Same result (both inputs are finite sums), but it is the module's convention for every division and the guard should not be re-derived at one call site.
…f the offload ledger The panel said omitting a rendering crawler's follow-up requests flattered the net figure. It does not, or not only: without this system every rendering crawler's page-view costs the origin the document PLUS the page's own API calls (the uncacheable ones), so the "crawlers asked for" baseline understates what the origin was spared — and a snapshot served without scripts triggers none of those calls, a saving the figure does not credit. Proxied pages, snapshots that keep their scripts, and our own renders still trigger them, a cost it does not charge. Documents-only on both sides, and the copy now says which way each case cuts; where snapshots ship without scripts the true net for rendering crawlers is HIGHER than shown. Co-Authored-By: Claude Code <noreply@anthropic.com>
…in charts.js (review) Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Addressed the one inline finding ( |
What
Origin offload, gross and net. The offload tile the rollout is judged on counts only crawler requests proxied to the origin live. It ignores every origin request this system makes — renders, change probes, sitemap fetches — so a deployment can post a 95% gross offload while sending the origin more requests than the crawlers would have. This adds the net figure:
All four terms come from series already in the one analytics scan (
bot_servesource=origin,render/outcome— exactly one row per posted result,probe_probedandsitemap_sitemapsread by value).originLoad()incharts.jsowns the arithmetic so Traffic and the Overview cannot disagree. Traffic gains a "What the origin actually saw" panel (each term over time + a bar per cause); the Overview tile carries the net figure under the gross one.Stated on the panel rather than assumed:
The term nothing here can count is stated, and it is missing from both sides. The requests a page's own scripts make when a rendering crawler (Googlebot, Bingbot, Applebot) runs it — the XHR/API calls no CDN caches — never pass through the plugin (the CDN forwards the document to us and sends subrequests straight to the origin). Without this system every such page-view costs the origin
1 + k, so the "crawlers asked for" baseline understates what the origin was spared; with it, a snapshot served without scripts triggers none of thek(a saving not credited), while a snapshot that keeps scripts, a proxied origin page, and every one of our own renders still trigger them (a cost not charged). The figure is documents-only on both sides and says so; the net tile reads "before crawler follow-up requests"; the panel reports the exposure as every page handed to a crawler — for every crawler, not a guessed list of bots, and never multiplied by a guessed factor. Where snapshots ship with scripts stripped, the true net for rendering crawlers is higher than shown.Catch-up to plugin 0.61 → 0.64.1 (console was current to 0.60.0):
verifiedcache status (v0.63.0) was invisible in the worst way: outside every cache-served sum (the hit rate read low) and in the "other" non-hit family. One sharedCACHE_SERVEDset now drives the freshness chart, the per-route table and the staleness sums;verifiedjoinsinvalidatedin one Invalidation family — one population, split into rescued and refused.page_verificationwrites (faults on the tile), everyinvalidation_reenqueueoutcome including v0.64.0'sforwarded/forward-failed(forwardedis never added tolowered— the owner counts it), andinvalidation_errorwithlkg-expiredas the failed-OPEN alarm. Reads the same cached 1h window the Overview holds. Two catalog-guard waivers removed — the guard'spage_verificationfailure on currentmainis what started this.stateAvailable: falseis named per node as "unknown, not idle" (the old shape made an unreadable state look like the probe being off); a running sweep shows its heartbeat count on the header, the sweep card and the node table.Verification
cd packages/console && node --test— 257 pass (was 227/1 fail onmain: the guard'spage_verificationcatch).npm run lint && npm run format:checkclean.test/invalidationsView.test.js; extended traffic/overview/probe/aggregate suites pin the arithmetic (value vs count for pass counters,bot_requestas denominator, negative net, all-bots tag under a filter, the two-sided caveat,verifiedcache-served,forwarded≠lowered).No plugin change; console-only release train (
prerender-console-v0.12.0).Follow-up (not in this PR): measure
kThe renderer already runs a cache policy on every same-origin response (renderer.ts response hook). Counting uncacheable same-origin subrequests per render gives
kper page; stored on the cached page and applied — by what the registry says each crawler runs — to the baseline, the proxied serves, the cache-served pages (zero where scripts are stripped) and our own renders, it turns the exposure into a counted term on both sides. Browser → plugin → console train; happy to open the issue.🤖 Generated with Claude Code