Skip to content

the sitemap expiry guard never fired, because the rows have no status - #2789

Merged
Flotapponnier merged 1 commit into
devfrom
fix/sitemap-expiry-guard
Oct 2, 2026
Merged

Flotapponnier merged 1 commit into
devfrom
fix/sitemap-expiry-guard

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

Found by a blocked deploy

The production deploy of #2788 failed its sitemap smoke gate and attempted a rollback:

[smoke] FAILURES (deploy will be blocked):
  https://openchainbench.com/benchmarks/bridge-execution-latency → meta robots noindex
  https://openchainbench.com/benchmarks/bridge-realized-cost     → meta robots noindex
[smoke] 149/151 OK, 2 failed

Two pages that render noindex were listed in the sitemap. (The rollback then reported "No deployment rollback in progress" and did nothing, so the deploy is live — worth a separate look.)

The cause

isExpiredBench guards against exactly this. It read:

return b.status === "live" && dataAgeHours(b) > NOINDEX_AFTER_HOURS;

The only rows that reach it are the sitemap rows the worker publishes: slug, lastRunAt, category, perChainSlugs. No status. So the comparison was false for every row and the guard did nothing from the day it was written.

isExpiredRpcPage beside it has no status check, which is precisely why chain RPC pages expired correctly and nothing else did. Its own comment describes perp-asset-breadth sitting in the sitemap with index, follow and month-old data "because every expiry check downstream was RPC-shaped" — the fix for that was this function, and it was inert.

Why those two benches

Their lastRunAt is 1970-01-01T00:00:00.000Z. That is deliberate: materialize/load.ts writes the epoch when a bench declares a freshness_timestamp_metric and Prometheus reports no run at all, "so say so rather than pretending". The data is real (4 providers ranked, 27 samples) but no run was ever timestamped, so the page correctly renders noindex at an age of 497,487 hours.

The fix

An absent status counts as live. A draft bench has no business in the sitemap either, so the default loses nothing. The worker publishes the real status from here on, so rows carry the fact rather than relying on the default.

Seven tests pin it, including the case that was broken: a row with no status at all.

425 tests, 235 specs, tsc and eslint clean.

isExpiredBench exists to keep a page that renders noindex out of the
sitemap. It read `b.status === "live"`, and the only rows that ever reach
it are the sitemap rows the worker publishes: slug, lastRunAt, category,
perChainSlugs. No status. So the comparison was false for every row and
the guard did nothing from the day it was written.

The RPC variant beside it has no status check, which is exactly why chain
pages expired correctly and nothing else did. Its own comment describes
perp-asset-breadth sitting in the sitemap with index, follow and
month-old data "because every expiry check downstream was RPC-shaped":
the fix for that was this function, and it was inert.

Found because it blocked a deploy. bridge-execution-latency and
bridge-realized-cost render noindex, both were listed, and the sitemap
smoke gate failed the production deploy and tried to roll back. Their
lastRunAt is the Unix epoch, which materialize/load.ts writes
deliberately when a bench declares a freshness_timestamp_metric and
Prometheus reports no run at all, "so say so rather than pretending". A
56-year-old page must not be advertised to crawlers.

An absent status now counts as live. A draft bench has no business in the
sitemap either, so the default loses nothing, and the worker publishes
the real status from here on so the row carries the fact instead of
relying on a default.

Seven tests pin it, including the case that was broken: a row with no
status at all.
@Flotapponnier
Flotapponnier merged commit 73ef624 into dev Oct 2, 2026
2 checks passed
@Flotapponnier
Flotapponnier deleted the fix/sitemap-expiry-guard branch October 2, 2026 14:56
Flotapponnier added a commit that referenced this pull request Oct 2, 2026
…#2789) (#2790)

isExpiredBench exists to keep a page that renders noindex out of the
sitemap. It read `b.status === "live"`, and the only rows that ever reach
it are the sitemap rows the worker publishes: slug, lastRunAt, category,
perChainSlugs. No status. So the comparison was false for every row and
the guard did nothing from the day it was written.

The RPC variant beside it has no status check, which is exactly why chain
pages expired correctly and nothing else did. Its own comment describes
perp-asset-breadth sitting in the sitemap with index, follow and
month-old data "because every expiry check downstream was RPC-shaped":
the fix for that was this function, and it was inert.

Found because it blocked a deploy. bridge-execution-latency and
bridge-realized-cost render noindex, both were listed, and the sitemap
smoke gate failed the production deploy and tried to roll back. Their
lastRunAt is the Unix epoch, which materialize/load.ts writes
deliberately when a bench declares a freshness_timestamp_metric and
Prometheus reports no run at all, "so say so rather than pretending". A
56-year-old page must not be advertised to crawlers.

An absent status now counts as live. A draft bench has no business in the
sitemap either, so the default loses nothing, and the worker publishes
the real status from here on so the row carries the fact instead of
relying on a default.

Seven tests pin it, including the case that was broken: a row with no
status at all.
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