feat(site): add a curated /pricing.md markdown twin for agents - #4069
feat(site): add a curated /pricing.md markdown twin for agents#4069revmag wants to merge 1 commit into
Conversation
/pricing.md was produced by the generic HTML-to-markdown pipeline, which
turns the pricing page's sliders, tabs, and calculator into UI fragments
("0GB100TB", repeated icon URLs) rather than a price list. Agents could
not reliably read plan tiers, rates, or limits from it.
Serve a hand-authored markdown twin instead:
- constants/pricing.ts holds the canonical rate data (per-GB logs/traces
and per-million-sample metrics prices for every retention tier, the
retention minimums, and plan-level amounts). The pricing calculator now
re-exports from it, so the page and the markdown cannot drift.
- utils/pricingMarkdown.ts renders plans at a glance, per-signal rates,
retention price tables generated from those constants, what the Teams
minimum includes, a bill formula with worked examples, Enterprise
options, the startup program, licensing, a plan feature breakdown, and
billing/cost-control pointers.
- app/(site)/pricing.md/route.ts serves it with the shared agent headers.
- Routing gains a "curated markdown twin" concept: /pricing.md is a real
route excluded from the page pipeline, and Accept: text/markdown on
/pricing rewrites to it. Vary: Accept on /pricing is preserved.
- llms.txt lists it under a new Pricing section.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Claude finished @revmag's task in 2m 49s —— View job PR Review — curated
|
| | Monthly ingestion | Usage cost | Bill | | ||
| | --- | --- | --- | | ||
| | 50 GB logs, 20 GB traces, 100 mn metric samples | $31 | ${teamsMinimum} (within included usage) | | ||
| | 300 GB logs, 200 GB traces, 500 mn metric samples | $200 | $200 | | ||
| | 2,000 GB logs, 1,000 GB traces, 5,000 mn metric samples | $1,400 | $1,400 | |
There was a problem hiding this comment.
Worked-example figures are hardcoded — drift risk · Medium
The ingestion volumes and usage costs in this table ($31, $200, $1,400) are literal strings, whereas the retention tables above are generated from constants/pricing.ts. If the base rates change there, the summary line and retention tables update but these three rows silently go stale — the exact "page and markdown can't drift" failure mode this PR set out to eliminate. The new pricing-md.test.js asserts the retention tiers but not these numbers, so a rate change wouldn't fail CI here.
Since every example uses minimum-retention rates, the usage costs can be derived from the same constants, e.g.:
const example = (logsGb: number, tracesGb: number, metricMillions: number) => {
const usage =
logsGb * BASE_TRACES_AND_LOGS_PRICE_PER_GB +
tracesGb * BASE_TRACES_AND_LOGS_PRICE_PER_GB +
metricMillions * BASE_METRICS_PRICE_PER_MILLION_SAMPLES
const bill = Math.max(PLAN_PRICING.TEAMS_MONTHLY_MINIMUM, usage)
const note = usage < PLAN_PRICING.TEAMS_MONTHLY_MINIMUM ? ' (within included usage)' : ''
return `| ${logsGb.toLocaleString()} GB logs, ${tracesGb.toLocaleString()} GB traces, ${metricMillions.toLocaleString()} mn metric samples | ${money(usage)} | ${money(bill)}${note} |`
}That keeps the examples locked to the same source and lets you assert them in the test.
| * plan/rate/feature document instead. | ||
| */ | ||
| export async function GET() { | ||
| return agentResponse(buildPricingMarkdown(), { varyAccept: true }) |
There was a problem hiding this comment.
varyAccept: true on a route that never negotiates · Low
agentResponse documents varyAccept as "Set on negotiated URLs that also serve HTML." /pricing.md always returns markdown regardless of Accept, so Vary: Accept here just fragments the CDN cache by request Accept without buying anything. The URL that actually negotiates is /pricing, and the proxy already appends Vary: Accept there (servesMarkdownAlternate). The route this mirrors — /skill.md — calls agentResponse(SKILL_MD) with no varyAccept. Consider dropping it (and the corresponding assertion in pricing-md.test.js). Harmless either way, just inconsistent.
Staging preview
📄 Summary
An agent-experience audit flagged
/pricing.mdas thin: it existed, but only because the generic HTML-to-markdown pipeline converts the pricing page. That page is highly interactive (retention sliders, tabs, a bill calculator), so the conversion emits UI fragments instead of a price list — slider ranges render as0GB100TB, icon URLs repeat, the plan cards fragment into loose headings, and nothing states the rates for retention tiers other than the default. An agent can't reliably answer "what does 500 GB of logs at 90-day retention cost, and which plan do I need?" from it.This PR serves a hand-authored markdown twin at
/pricing.mdinstead.constants/pricing.tsPricingCalculator/constants.ts) now re-exports from it, so the page and the markdown can't drift.utils/pricingMarkdown.tsapp/(site)/pricing.md/route.tsagentResponseheaders, mirroring/skill.md.proxy.ts,utils/agentMarkdownRouting.tsapp/(site)/llms.txt/route.ts## Pricingsection.Curated markdown twins. A small map (
CURATED_MARKDOWN_TWINS, currently just/pricing) marks pages whose HTML converts poorly and that ship a hand-authored twin./pricing.mdis excluded from the generic page pipeline, andAccept: text/markdownon/pricingrewrites to the twin instead of/api/page-markdown/pricing, so both entry points return the same document.Vary: Accepton/pricingis preserved.Content provenance. Plan tiers, feature matrix, startup terms, and Enterprise offerings come from the live pricing page components. The retention→price tables, retention minimums, what counts as ingested volume vs. a metric sample, included-usage/overage mechanics, AWS Marketplace activation, trial/cancellation behavior, and dual-licensing are drawn from the Billing docs in #3642. Retention prices were cross-checked against
PricingCalculator/constants.tsin this repo and match — which also resolves the "please confirm the retention pairing" reviewer note on #3642.✅ Change Type
🧪 Testing Strategy
tests/pricing-md.test.js(6 tests): response shape andVary: Accept, all three plan tiers with their prices, every retention tier asserted againstconstants/pricing.ts(so a rate change that isn't reflected in the doc fails), what usage is billed on, the feature breakdown, and that every link is absolute.tests/agent-markdown-routing.test.js— newcurated markdown twins bypass the generic page pipelinecase; existing generic-pipeline assertions repointed from/pricingto/alerts-management.tests/proxy.test.js— newserves the curated markdown twin for /pricingcase; generic-pipeline assertions repointed likewise.tests/llms-txt.test.jsfor the new section.node --teston pricing-md / agent-markdown-routing / proxy: 61 pass, 0 fail.yarn check:stale-urls: pass.yarn lint: 0 errors.npx tsc --noEmit: no errors in changed files.yarn build: succeeds with/pricing.mdregistered as a route.Known pre-existing failure, not from this PR:
tests/llms-txt.test.js→ "llms.txt follows the llms.txt structure: H1 then summary blockquote" fails on cleanmaintoo (verified by stashing this branch's changes). The summary line lacks its>prefix. The fix is queued in a separate in-flight branch covering/api-reference.mdand the MCP discovery surfaces, so it's left alone here to avoid a conflict./pricingHTML page is unchanged — the calculator now imports the same numbers fromconstants/pricing.tsrather than declaring them locally./pricing— covered by the new proxy test, which also asserts it no longer reaches/api/page-markdown/pricing./pricing.mdfalls back to the generic pipeline output it serves today.📝 Changelog
/pricing.mdnow serves a structured, hand-authored pricing document — plan tiers, per-signal rates at every retention tier, worked bill examples, and a plan feature breakdown — instead of a conversion of the interactive pricing page.📋 Checklist
/pricing.mdalready resolved; the response body changes, the URL does not)👀 Notes for Reviewers
Two things worth a product read before merge:
$199reference. The page shows Teams as$199struck through$49. The doc phrases this as "a $49/month minimum (listed on the pricing page as a discount from $199/month)". Say the word if that framing should be dropped entirely.Coming soon/Beta/Enterprise self-managedmarkers, which were transcribed fromExploreAllFeatures.tsx.Also flagging follow-up debt: the same rate tables are still duplicated in
SigNozCloudPricingOverview.tsx,MetricsCostEstimation.tsx, andcomponents/Monthly-estimate/*. That's pre-existing and out of scope here, but they should all fold intoconstants/pricing.ts.🤖 Generated with Claude Code