Platform changelog
核心导读与要点提炼
What has shipped on the Zeso platform, and when.
此页面尚未提供你的语言版本,以下为英文原文。
2026-10-24 · The checkout was not charging what the site says
Two prices, two wrong numbers, and nothing was looking. The only path on the site that takes money is the credit pack — the studio's "buy credits" button — and it reached the billing provider with planId: "free", because a pack is not a plan and a pack purchase has to name one. The provider priced the line from that plan, so the $15.00 pack was invoiced at $0.00, with $10.00 of inference behind it, and the quantity was dropped on the same floor. The provider's own metadata was dropped as well, which is the half that matters afterwards: without it a webhook cannot tell a pack purchase from a subscription.
The provider contract could not say what it was charging. A checkout carried a plan and a cycle and nothing else, so the only thing a gateway could price was a subscription. It now carries lines — a description, a quantity, a unit price — and a checkout with lines is a one-off payment. The pack path passes the catalogue's line, so the price on the invoice is the catalogue's price, and the caller's metadata travels with the session.
An annual term was charged one month of it. The adapter used the plan's monthly-equivalent annual rate as the annual amount, so a Pro subscription on an annual term was created for $15 a year instead of $180 — a twelfth of the published price, on every annual customer, silently. The rule now lives in one place: yearly is the monthly-equivalent, and the year is twelve of them.
And the dashboard quoted a price the site does not print. The plan table the dashboard reads said Pro was $14/mo on an annual term, where the pricing page publishes $15/mo and $180 for the year. One of two published numbers for one product is a bug wherever it sits, and the receipt has to match the promise.
And the webhook accepted a body nobody signed. The signing secret was checked only when one was configured — with none set, an unsigned body was parsed and applied, so a paid plan was something anyone could have by POSTing to a public route. It fails closed now, a signature older than five minutes is refused as a replay, and the two refusals are told apart: a forgery is a 400 and is not retried, a missing secret is a 503 and is retried once it is fixed.
What is still not here: the order and the payment attempt are not written yet, the event ledger does not record what the gateway said, and the credit pack's grant is still not wired to the webhook. And nothing is buyable until the deployment carries STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET — that part is a secret, not a change.
2026-10-24 · The local-SEO guide now answers the profile half properly
A guide was aimed at one phrase while a bigger phrase with the same intent sat unclaimed. The guide at /learn/how-to-get-found-on-google was titled "SEO for local business: how to get my website on Google", and its first section was three paragraphs about claiming and verifying a profile — the setup of a profile, not the optimization of one. The corpus had measured google business profile optimization at 5,400/mo, competition index 6, with a page one of reference and guide pages (read 2026-10-20), and nothing here was aimed at it.
The cluster is bigger than the row, and the difference matters. Google Business Profile is 723,000/mo across five rows — and 715,000 of that is Google's own two head terms, where Google owns seven of nine results. The addressable part is 8,000/mo across three rows, and 5,400 of it is the word "optimization".
So section 1 is now the section that query asks for: the fields and the order to fill them, the three moves — fill in every field, make the profile agree with the site, keep the name a name — the verification gate that comes before all three, and the half this platform does not do. The title carries the measured row and gives up the row it was already answering in the other four sections: 1,880/mo → 6,400/mo, net +4,520/mo, at half the competition index.
The claims gate caught the first draft of the section, and it was right to. The opening sentence said "what ranks first is Google's own help documentation" — which is true, because that is what the read found, and it is also a position promise, which is the one thing this repository does not publish. The observation moved to the research corpus, where it is evidence, and the guide says the field list and the rules belong to Google without saying who ranks where.
2026-10-23 · Every page that promised a download now says what we actually ship
Eighty-seven of our own comparison cells told a reader they could export a clean static HTML/CSS/JS bundle at any time — a promise we have never shipped. The export guide has said the opposite since it was written — "No one-click static bundle. You cannot download a pre-rendered HTML/CSS/JS archive of your site, because we do not build one" — and there is no bundle builder in this repository and no export command in package.json. The pages a reader uses to decide whether to leave were promising the one thing we do not ship.
Measured, not guessed. A gate now reads every published surface — the comparison pages, the guides, the twenty-four solution pages, the home page's copy, the plan tables, and both llms.txt manifests — and asks one question of each cell: does this say the site can be taken away as code? The answer was eighty-seven times, in English and in Chinese, on pages whose titles carry the phrase a reader types.
The same pass found three more things in the same class.
A Chinese answer that said something else. On the personal-branding page, the English half of one FAQ answer said the document is yours to read and to compile for any host you like; the Chinese half said "完全可以" and then promised a downloadable HTML/CSS/JS package deployable to Cloudflare Pages, to Vercel, or to any private server. Two halves of one answer, and only one of them was true.
A claim about competitors we had never read. The freelancers-and-creators page said the old way's export "produces a zip you can never host again". Our own capture of carrd says the opposite — "the export is real and genuinely portable" — and our own capture of base44 says two-way GitHub sync exports the full source to your own repo with nothing locked to the platform. Both captures were in the corpus the whole time.
A page with a broken character in it. The electricians page published one damaged byte in Chinese, where a "你" had been mangled into a replacement character. The page rendered, the build was green, and every audit was green, because a character is the smallest unit of copy and nothing was looking at it.
What ships now: one position on every surface — an open JSON SiteSpec, live content readable over a public API without a key, no export fee and no export tier, and leaving as a build you run rather than a download you wait for.
And the market prices went with it. Several pages stated what a lead marketplace or a directory charges — "$50–$150 per shared lead", "15%–30% booking commissions" — and our corpus holds no capture of Thumbtack, Angi, HomeAdvisor or a booking marketplace, so no number on the site could stand behind them. They are gone; the shape of the cost is what the pages say now. The two languages of a page also stopped disagreeing: where the English half said "$50–$150", the Chinese half said "several hundred", and a Chinese reader was getting a vaguer page than an English reader on the lines that carry the most load.
Four gates hold all of it, each with a negative control that breaks the corpus on purpose and checks that the gate goes red and names the cell: the export claim on our own pages, the export claim the guides make about a platform, the integrity of every published character, and the rule that the two languages of a page state the same figures.
And four trade pages now answer the question their shape can take. The corpus's own rule — read on 2026-10-20 — says a trade page can take local seo for [trade] and not website for [trade], because the first returns agency pages that answer for one trade and the second returns galleries and directories. Real-estate, landscaping, fitness and cleaning-services were still carrying the gallery-shaped row, and their targets were a competition index of 43, 55, 21 and 65. They are now local seo for real estate agents (110/mo, index 1), local seo for landscapers (50/mo, index 6), local seo for gyms (30/mo, index 13) and local seo for cleaning services (10/mo, index 5). The measured volume went down, and the rows that were released were the ones whose reader is not looking for a builder: agent directories, gym homepages, a landscaper's own site, a cleaner's own page.
2026-10-22 · The cost of a website, on both sides of the invoice
The design half of the cost question was missing from the cost guide. The market's cost pages answer "what does a website cost" with a builder's first year, and no page in the corpus puts a design quote next to a renewal rate. /learn/how-much-should-a-website-cost now prints the market's designer quotes, read on 2026-10-22 — $199, £299, AU$299, $399, $1,200, $1,500 to $3,000, $1,500 and up, $500 to $5,000, $5,000 to $30,000+ — and says the one thing that is true of all of them: a design quote covers the design and stops there. The bills that repeat underneath it are the same on both sides of that page, and the difference is that one side publishes them with the date they were read.
And the Chinese copy stopped typing its own numbers. The English body of that page prints the renewal range from the compare registry; the Chinese body printed "1.0 倍" and "39 倍" as literal text, so the pair could drift apart the moment a vendor with a larger step was added — the English page would move and the Chinese one would not, and no gate would have said so. It was the only place in the corpus where one language derived a range and the other typed it. The rendered page is unchanged today, and now says it because the registry says it.
And a code span inside a bold span stopped printing its own punctuation. Fifty-one places in the seed bodies write a path or a command inside a bold span, and every one of them showed the reader a pair of literal backticks — the parser's own comment claimed that case worked, and it did not. The inline parser now hands a captured bold or italic span back to itself, so the code span is a code chip again. On the changelog page alone, twelve bold spans were printing their backticks.
And a builder's number was in another builder's row. The price-posture table typed all fifteen of its rows by hand, and two of them were wrong the way a hand-kept copy of a price always is: a builder that publishes no renewal rate was given a two-year total anyway, and Squarespace's row carried GoDaddy's $323.76. Nothing caught it — the price gate reads the marketing pages, and these were document bodies whose numbers were typed into a markdown table. The table now prints the gap where the gap is, and a new gate joins those rows to the ledger: where a row names a builder in the audited registry, every price in that row has to be one of that builder's own published rates.
And the AI builder's page took a second phrasing. build a website with ai (880/mo) was read on 2026-10-22 and returns the same page one as ai website builder, with the same vendors on it — Figma Make, Base44, Replit, Squarespace, Hostinger, Kimi Build, Readdy, Relume, Emergent and Wix. /docs/ai-builder is now "AI website builder: build a website with AI, and edit it forever", and the two phrasings are one intent: the page one is a set of vendors' own pages about their own builders, and this is this site's own page about its own builder. The entry below writes that both pages of that family were "full at the two-phrasing cap" and then names one row for this one — the map agreed with the one row, so the sentence was wrong when it was written. The cap is full now, and the reason the rest of the cluster stays unclaimed is the shape of the cluster rather than a free slot.
2026-10-22 · The price of an AI-built site, and the gate each free tier hides
Three price audits, and only one of them turned out to be a comparison. Base44 was the first result on the ai website builder pricing page one and the ledger had never held it — so it is in it now, with a research capture, a full comparison detail module and a data entry. The ledger holds fifty-one vendors. Replit and Kimi are not in it, and the reasons are their own published statements rather than ours: Kimi's help centre rules out "business sites that require long-term stable hosting with a custom domain" and "complex websites with payment systems", and Replit's free tier's published app expires after 30 days behind a badge only a paying tier may remove.
So the page one's three "$0"s mean three different things, and every one of them publishes the difference: Base44's free tier cannot connect a custom domain; Replit's published deployment expires in 30 days; Kimi's free tier sits inside a membership that does not want your business site. The cost of an AI-built site is the plan price plus the gate you discover in month two — and the gate is the part no roundup prints.
There is a page now: /docs/ai-website-builder-pricing, in English and Chinese. It carries two rows for one intent — ai website builder pricing (30/mo, comp 6) and ai website builder cost (10/mo, comp 67) — because they return the same AI Overview and the same site-type bands, so one page answers both. It prints the market's bands, the three tools' real prices read from their own pricing pages, the four questions in the box beside the query, and ends on the two questions to ask before picking anything: what does month two cost, and what does the work cost when it is metered.
And the vendor count left the prose. The cost page said "fifty builders" in thirteen places across two seed modules, and said "thirty-six publish both rates" where the registry says thirty-eight and "five of the fifty publish no price at all" where it says two. The prose-counts audit cannot catch a spelled- out number, so the counts are now read from the registry — the ledger's size, the two rate counts and the renewal-multiple range — and the pages interpolate them. A count written as a word is a count nobody re-counted.
The inventory moves with it: 153 rows with a live page-one read, 43 without. And the Wix price question, which was two rows of one intent. Row 62 (how much is wix per month, 480/mo, comp 26) and row 56 (wix subscription, 480/mo, comp 10) return the same page one — Wix's own pricing pages, its plan explainer, Forbes' pricing guide, every third party repeating "$17 to $159 per month" — so one page carries both, and the title says both. The live table read today reproduced the September capture's consent-state condition (the regular prices, unstruck: Light $17, Core $29, Business $39, Business Elite $159), so the capture's numbers hold and its mechanism reproduces.
There is a page now: /docs/wix-pricing, in English and Chinese. It prints the price list, the two facts under it (the displayed prices are a yearly subscription paid in full up front, and the free domain is a voucher that cannot renew a domain you already own), the step every promoted tier takes at renewal, and the finding a cheapest-first list sorts away — Light costs $17 with no promotion at all while Core, a tier above it, is advertised at $14.50, so the cheapest-looking plan is the one that doubles.
The churn family is recorded, not claimed. wix price increase and wix too expensive return complaint threads, and wix renewal returns Wix's own account-management help pages. The fact all three want is answered on the price page — the step is 2.0x and it is disclosed, because Wix prints the regular price beside the promotional one — but a page shaped like theirs would be a page of complaints about a competitor.
And three spellings of one query. Rows 168 (ai site builder), 169 (website builder ai) and 170 (ai website builder) all carry the same CPC $28.11 and the same competition index 54, and the first two return the same vendors in the same order. Three rows of 33,100/mo are one query worth 33,100/mo, not 99,300/mo — the same lesson the corpus has learned before, that a group which looks like a cluster of opportunities may be one brand term. And the review family, which has no best — only four jobs. Row 174 (best ai website builder, 3,600/mo, comp 58) and row 192 (ai website builder review, 10/mo, comp 0) return one page one: the market's answer is a list of winners per job — "Wix for overall ecosystem power, Hostinger Website Builder for budget value, Framer for design-led control, and Squarespace for out-of-the-box templates" — with the reviewer's impression of a session attached to each (4.5/5, a 4.9, a video report card running "Replit 66/100 … Base44 95/100").
Audited, the market's own four picks read differently: the budget pick steps up 3.68× on the smallest sticker price, the ecosystem pick doubles, and two of the four publish no second rate at all — so their year-two cost is not a number anyone can quote, and the market still calls them the best. That gap is the page.
There is a page now: /docs/ai-website-builder-review, in English and Chinese. The long tail sets the topic and the head term rides along — the review is the shape and the title carries both words. The rates in its table are read from the ledger, not typed into the page, so a vendor with no second rate prints not published rather than a guess. And it answers the complaint the forums actually make — "Most AI website builders hit a wall fast or force your project into a generic template layout" — which is not a pricing problem, and not one you can fix later either.And the maintenance page gained the row it was missing. website care plan (70/mo, comp 26) is the same cluster as monthly website maintenance — agencies and WordPress shops selling tiered care plans, from Maple Creative's Essential $55/mo to FatLab's "typically range from $50 to $500+ per month" — with the same four line items on every plan: software updates, backups and recovery, security and monitoring, performance and speed. One page now carries both phrasings, and the title says both.
What the sellers' pages add is the second spread. The first spread (host price bands, four orders of magnitude) says the price measures what the site is. The second — the same four items between $50 and $500 a month — says the price measures how much of the work is done for you, and how many sites the plan covers. That is now the second question to put to whoever quotes, and it is the one nobody prints next to the price.And the free-tier page took the biggest row in its family. free ai website builder (4,400/mo, comp 56) returns the vendors' own free product pages — the same shape as the row the page was built for (website builder free trial, 390/mo) — with the AI builders' free tiers named in the summary. The page's title now carries both, and the two AI builders the page one puts first are in its table: Base44, whose free tier cannot connect a custom domain, and Replit, whose published deployment goes down after 30 days behind a badge only a paying tier may remove. One will not give you your address; the other will not give you the month.
And the count left the excerpt. It said "Eleven builders" — a number in a word, in a table that just grew. It now says "Every builder we have audited", in both languages.
The family is five buckets, not one query. Rows 171, 173, 177, 183 and 191 have different competition indices (56, 60, 50, 50, 65) and different CPCs, so unlike rows 168–170 they are five distinct queries in one family — which is why only one of them joins the title.And the third spelling of the AI-builder query is read, which closes it. Row 169 (website builder ai, 33,100/mo) returns the same page one as rows 168 and 170 — the AI Overview naming "Wix, Hostinger AI Website Builder, Framer, and Base44", with Wix "Plans start around $17/month" and Hostinger "roughly $3 to $4 per month". So the family is three rows, one query: 99,300/mo of apparent volume is 33,100/mo of real volume, and the page that owns it is /docs/ai-builder.
The lesson, learned twice in opposite directions. The free family looked like the same kind of group and was not one query (five distinct buckets, different competition indices and CPCs). This family looked like six or seven separate opportunities and was one. A group that looks like a cluster of opportunities may be one query, and a group that looks like one may be five — which is why the corpus reads the page one instead of inferring it from the planner's numbers.
And the narrowest free row, recorded rather than claimed. ai website builder with custom domain (10/mo, comp 34) returns the vendors' own free pages advertising the custom domain, beside Kleap's "Free AI Website Builder With a Domain: Real Costs" — "Which free AI website builders let you use a custom domain, and what domain and hosting really cost". The free-tier page answers it, but that title already carries two phrasings of the same intent and this is the narrowest of the three, so it is recorded, not claimed. The answer it wants is already here: Kleap has its own audited comparison page, the domain prices are derived from the registry, and the free-tier page prints exactly which free plans withhold the address. And a withdrawn product was in our own copy. Three page ones read today name Wix Aria as its AI builder — "Uses an AI agent named Aria to build business-ready sites with conversational prompts, plus manual drag-and-drop editing" — and Wix's own pricing page carries "AI website builder: Create a site from a single prompt and flow between AI generation and drag and drop to refine any detail". Wix ADI was retired on 2024-11-10, and /docs/ai-website-builder-no-code was still saying "Base44, Wix ADI, Hostinger AI, Replit, Kimi" in the sentence that says these tools all work the same way. Both languages now say Aria, and the sentence is more accurate for it.
The lane is not reclassified, and that is the deliberate part. LANES.md rule 1 says the lane comes from the flow, not the marketing, and defines chat-assist as "iterative chatbot inside a manual editor — no generation". A pricing page that markets a single prompt that generates is evidence against chat-assist — but it is marketing, and the corpus has already recorded that resolving Wix's lane needs the flow observed step by step. So the lane stays as the corpus has it, and the product name in our copy is what changed. The vendor capture's open question is unchanged, and now carries a dated re-check.
The lesson is one this corpus keeps re-learning. A comparative claim about a rival ages faster than the capture that supports it, because the rival keeps shipping — and a withdrawn name is the cheapest kind of claim to go stale, because nothing on the rival's site will ever contradict it. And our free-tier table had a paid plan's benefit on the free tier. Row 167 (wix ai website builder, 27,100/mo, comp 28) was the biggest unread row, and its page one names Wix's AI product: "The Wix AI Website Builder (powered by the Aria AI agent and part of Wix Harmony) generates complete, business-ready websites from a conversational prompt … which you can then refine using the standard Wix Editor", with a three-step flow (Chat & Prompt, Draft Generation, Hybrid Control), the built-in agent set (Aria for design, Kleo for marketing and SEO, Juno for support, Omni for inventory), and the line "free publishing on a Wix subdomain, while annual paid plans remove ads and unlock custom domains".
Wix's own pricing-page FAQ, read the same day: "Replace your free Wix URL (username.wixsite.com/sitename) with a custom domain you purchased from Wix, or one you already own", and "With a Premium plan you can connect your own domain". So the free tier gives a subdomain, and your own domain needs a Premium plan — and the free-domain voucher is a paid-plan item ("redeemable within 60 days following your purchase", "only valid towards the purchase of a new domain from Wix").
Our free-tier page said otherwise. Its Wix row read "A site, and a free domain | The domain is a 60-day voucher" — crediting the free tier with a domain a Premium plan carries, and quoting the 60-day voucher as if it were the free plan's. The row now says what Wix says, which also makes Wix the fourth builder in that table withholding the address — and the page's own claim that every row has the same shape gets stronger. The compare page had it right all along ("Free 1-year domain voucher with annual paid plans"), so the error was localized to one table rather than inherited.
And the lane is still not reclassified, and the reason is sharper. The published flow generates a full site draft — structure, colour themes, fonts, page copy — before the editor takes over, and LANES.md defines chat-assist as "iterative chatbot inside a manual editor — no generation". So the published flow contradicts chat-assist. But the lane comes from the flow, not from a description of the flow, so the lane stays as the corpus has it and the evidence is recorded. Settling it means watching one build from the first prompt to the published site — a pack-tier job.
The general shape of the mistake. A paid plan's benefit had drifted onto the free tier, in a table whose subject is exactly what the free tier does not give. A free-tier table is where a benefit lands on the wrong tier more easily than anywhere else, because the free tier is the one nobody re-reads. And the planner's numbers were overruled by a page one. Row 173 (ai website builder free, 4,400/mo) was read today, and it returns the same page one as row 171 — the same summary ("You can build a full website for free using the Base44 AI Website Builder"), the same "Top Free AI Website Builders" list. Rows 171 and 173 have different CPCs and different competition indices, and they are the same intent. §2.53 argued from those planner numbers that the free family is "five distinct buckets" — that reasoning was wrong, and §2.57 says so.
Which makes this corpus's two "one query" findings one finding. Rows 168, 169 and 170 shared the CPC, the competition index and the page one. Rows 171 and 173 share the page one and nothing else. What decides whether two rows are one intent is the page one — the planner's numbers are a hint, and sometimes a wrong one.
Row 173 is recorded, not claimed: the title already carries a long tail (website builder free trial, 390/mo) and a head term (free ai website builder, 4,400/mo), and a second spelling of the head term would replace the long tail rather than add to it.
And the read earns a paragraph on the page. Base44's own page says "Create a website with AI for free — hosting, security, and analytics included", and the summary above the query says you can build a full website for free with it. Both are true, and both are about a site on somebody else's address — what the free tier does not include is the third thing, your own name on it. The free-tier page now says so: the honest version of the claim is "a website for free", not "your website for free", and the difference is the row above.
And the general AI-builder cluster is one intent, counted seven times. Rows 172 (ai website generator, 2,900/mo) and 175 (ai website design, 1,600/mo) were read today, and both return the same genre: the vendors' own AI product pages, a "10 best" roundup, forums asking which is best, and a PAA or "Things to know" module. With rows 168, 169 and 170, the cluster's apparent 104,000/mo is one query family.
Two pages already own that family, and they own its two halves: /docs/ai-builder (what the engine is, and why the result stays editable) and /docs/ai-website-builder-review (which one, scored on the year-two price). Both are full at the two-phrasing cap, so the rest of the general cluster is recorded, not claimed, with the reason being the cap on a family we own twice over — not a shape difference, which is what the corpus records when a page is genuinely out of scope.
And the sub-intents are the real pages. The cluster's members that carry their own sub-intent each have one: the free family on the free-tier page, the price family on the pricing page, for business and no code on their own, with custom domain recorded against the free-tier page that answers it, for ecommerce closed with a reason. A family of one intent is not seven pages; it is two pages and five sub-intents.
The general form, which now covers every cluster in this corpus. Rows 168/169/170 shared the CPC, the competition index and the page one; rows 171/173 shared the page one and nothing else; rows 172/175 shared the page one while every number in the table said "different" — CPCs $21.29 and $22.07 against row 170's $28.11, competition indices 35 and 56 against 54. No number in the table decides this. The read does.
And a page that answered a measured query was not connected to it. /learn/free-domain-traps is titled "Is a free domain for the first year actually free?", and it says what the summary says and more — that the offer is "usually conditional — a hosting plan, a multi-year term, an email bundle" — and that it disappears if you buy the domain alone. Its title is the question row 163 asks, and the expectations map had no entry for it, so a measured page and a measured row sat next to each other with nothing joining them. The row is now claimed (free domain for a year, 20/mo, comp 51), and the title says the phrase the row is measured on.
Two facts the page did not have, and now does. GoDaddy's own page prints the small print next to the offer: "Get a free domain with purchase of any annual plan. Plus an ICANN fee of $0.20 per domain name per year." — the name is free, the registry's charge is not, and it is charged every year you keep it. And the "free for life" registrars (Northwest, iFreeDomains, FreeDomains.cc, DNSExit) are not a third option: their free renewals are conditional on keeping the rest of the service, so the free renewal is a property of the account, not of the domain. And the forums have already ruled on it — the top answer on the largest Quora thread, 308 votes: "Usually? Under false pretenses."
And the next page the corpus is asking for. cheap domain with hosting (390/mo, comp 46) is the two-bill shape: the registrars' own pages plus the forums asking for the cheapest combination, whose top answer is "Cheapest is to get a domain via CloudFlare, they sell the domains at cost" — this site's own model. It is recorded rather than claimed, because none of the three price pages answers it: the free-domain page answers the voucher's terms, the domain price page answers the name, the hosting price page answers the host. What is missing is a page that answers "what does it cost to have both, and what does the bundle really charge me in year two" — and its material is already derived: both price tables come out of the registry, the voucher rule is on the free-domain page, and the Verisign escalation is dated.
And the page the corpus was asking for. /docs/domain-and-hosting-cost — "Cheap domain with hosting: the two bills, and what the bundle really costs" — in English and Chinese, in the domains book. It claims cheap domain with hosting (390/mo, comp 46) and prints the two bills apart and then summed — the name's five-year total, the hosting's five-year total, and the two together, all derived from the registry, so the figures on this page cannot disagree with the figures on the two price pages beside it.
The argument is the one the forums' top answer misses. The top answer on r/webhosting is "Cheapest is to get a domain via CloudFlare, they sell the domains at cost" — which is this site's own model, and which is right, and which is beside the point: the name is not where the money is. A bundle's free domain is roughly $15 against a hosting bill of $179 to $900 over five years. What decides the bill is the hosting's renewal — our audit records Hostinger's entry at $2.99/mo on a 48-month prepay renewing at $10.99/mo, a 3.68× step — and whether the name survives when the hosting stops.
And it says the one thing a bundle page does not: GoDaddy's own domain page prints the small print beside the offer — "Plus an ICANN fee of $0.20 per domain name per year" — and the "free for life" registrars tie the free renewal to keeping the rest of the service.
And the two largest unread rows in the cluster are both families we already own. ai generated website (1,000/mo) returns the general cluster again — the vendors' pages, the forums ("Hostinger AI Website Builder is your best bet, perfect for beginners and non-technical users"), the videos, and a box that asks "How can I tell if a website is AI-generated?" And best free ai website builder (880/mo) is the free family with the ranking layer on top — the vendors' free pages beside Website Planet's "6 Best Free AI Website Builders", All About Cookies' "We Tested 20+ Web Builders", and the forums ("Neo Sites … because it provides free domain + site").
Both are recorded, not claimed, and the reason is the cap on families we own between them — the engine page and the review page for the general cluster, the free-tier page for the free family, all full at two phrasings. And the honest reason the free-tier page keeps its long tail: swapping website builder free trial (390/mo) for best free ai website builder (880/mo) would buy 490/mo and cost a title that reads like a keyword list, on a page whose job is to answer rather than to list its own synonyms. The two-phrasing cap is not a number to be maximised; it is a promise that a title is written for the reader.
What is left to read is the tail of every family — the smaller spellings, the domain cluster's other rows, the hire-a-designer cluster, the vertical rows. The bigger rows in each family are now read, which is the part that changes decisions: the families are one intent each, and the pages that own them are full.
And the bundle the corpus pointed at finally has a place. The maintenance page now prints the other bundle — the agencies that sell hosting and maintenance together (Ironistic, Gravitate Design, CommonPlaces, TechArk, whose own line is "Unlike hosting, website maintenance is the service related to keeping your specific website up to date and functioning properly") — beside the two questions the box asks about it: "How much does it cost to pay someone to maintain a website?" and "How much should I pay someone to host my website?" Two bills, priced separately on that page — the host's in "What the market charges", the maintainer's in "What the sellers charge" — and the bundle's own price is the one number on the page that tells you nothing about either.
And a stale note from §2.23 is corrected rather than left standing. It said the question was "the one the corpus has no measured row for: the hosting family was never probed." Both halves are now false: the sixth probe added web hosting price and web hosting cost at 1,900/mo each, and the hosting price page prints the host's five-year bill.
Row 106 stays recorded, not claimed — the family is full, and the page's title carries the family's long tail (monthly website maintenance, 30/mo at competition 7, the most winnable row in the cluster) and its head term (website care plan, 70/mo). Swapping the long tail for it would buy 60/mo and cost the page the identity the long tail gives it, for a query whose page one is a different set of documents: agency service pages, not the price guides and the care-plan sellers this page is built from.
And the transfer guide finally has a price and a measured row. domain transfer cost (110/mo, comp 36) was read today, and its page one is the registrars' transfer price pages, a comparison table, and the forum — where the top answer on r/Domains is the rule everything else follows from: "You pay transfer fees to the 'receiving' registrar. It also adds 1 extra year to your…" The summary's band is "$8 to $15 per year" for .com, .net and .org.
The guide already said the right thing about the year — "that year is part of the transfer rather than an extra charge" — and it named the blockers, the 60-day rules, the EPP code and the redemption ladder. What it did not have was a price. It now prints the published .com prices (Namecheap $11.48, Spaceship $9.48, NameSilo $10.80, GoDaddy $0.01 for the first year) and the one thing the market's headline hides: GoDaddy's $0.01 is the first year of a three-year purchase at $22.99 a year after it, so a transfer fee that looks free is usually a commitment priced somewhere else. The title now carries the row, and the page is measured for the first time.
And domain registration cost (260/mo) is recorded, not claimed — the price page already carries the two largest rows of that family (2,400/mo each) and prints the catalogue that answers it exactly: eighteen TLDs with their first year, their renewal and their five-year total. A third phrasing of one intent would buy 260/mo at the cost of a title that lists its own keywords. The band each vendor publishes is recorded instead, because the useful finding is that they do not agree — $6 to $15 from one, $10 to $45 from another, "a few dollars" from a third — and the price page's answer is the one that shows a number for each TLD rather than a band.
2026-10-21 · The machine-readable surfaces stopped describing a site we do not serve
Four surfaces exist to be read by something that never opens a page: /llms.txt, /llms-full.txt, /.well-known/ai-catalog.json and the OpenAPI contract. Measured against the sitemap and the two registries, all four were incomplete, and one of them pointed at documents that do not exist on this host.
The measurements, before any of it was changed:
/llms.txtlisted 7 of the 50 comparison pages. They were hand-written,
with no rule behind them, and Squarespace, GoDaddy, Webflow and Shopify were among the forty-three the index left out.
/llms.txtalso left out five pages the sitemap publishes:/pods,
/use-cases, /about, /contact and /terms. The contact page — where abuse reports, copyright notices and legal questions go — was one of them.
/llms-full.txt, the unabridged digest, carried the competitor ledger in
full and none of the twenty-four solution pages: no cohort page, not one of the seventeen trade pages, which is where the schema block, the per-trade catalogue and the answer nodes live.
/.well-known/ai-catalog.jsonadvertised an OpenAPI contract at
/api/openapi.json, and pointed the deployment capability at /api/docs/content-api.md. Both are the tenant plane's paths: on a customer's host /api/* rewrites to /tenant-api/*, and on the platform host it does not. Followed for real, both returned 404.
What ships now:
- The manifest's comparison section is derived from the registry, so all fifty
are listed, each with the renewal fact its own page is audited on — renews at 3.68x the intro rate; two-year total $143.52.
- The full digest gained a solutions ledger: one block per page, with the
audience, the Schema.org type the renderer emits for that trade, the catalogue, the credentials, the amenities, the cuisine, and the page's own questions and answers.
- The platform publishes its own OpenAPI 3.1 contract, at
/.well-known/openapi.json, describing the one public API operation and the machine-readable documents an agent can read.
- The catalog's solutions capability lists all twenty-four categories with
their kind, address and description, instead of a count and four examples.
And the second half of the day, which is the reason the first half mattered:
The site taught a command that has never existed. The manifest advertised "native CLI deployment (zeso deploy)". The export guide's procedure was npx zeso export --project your-project-id --out ./dist. A comparison page used the CLI to differentiate against Runable, a solution pillar promised a clean static export to any host, and the homepage's terminal ran it in front of every visitor. There is no zeso command: package.json is private, there is no bin, nothing is published under the @zeso scope on npm, and no spec ever promised one.
The copy now says what the platform actually ships — an open JSON SiteSpec, live content readable over a public API without a key, no export fee and no export tier — and says plainly what it does not: no CLI, no one-click static bundle, nothing to unlock. The competitor corpus already argues that this is the stronger position rather than the weaker one: the purest "toll on the exit" in that corpus is carrd's $49 HTML download and tilda's code export fenced behind six licence clauses, and PLAN-GATING.md records the point — the files are already the customer's.
The guard is the part that matters next. A command in a guide is a promise that the command exists, and nothing in this repo checked it. audit:claims now holds the published copy to the commands this project ships: a first-party package or command may be named only in a runnable position, only in lower case, and only if the repository implements it — the registry is derived, and each entry points at its implementation, so an entry cannot outlive the code it exempts. Six negative controls, including one that proves the exemption for an honest denial is load-bearing, and one that proves the lower-case brand in the terms of service is not a command.
Then the corpus, which had been quietly miscounting itself. The SERP provider's daily allowance was spent, so the reads went through the in-app browser — the same page one, a different instrument, recorded as such. Eight new rows were read and six rows that had been read twice in other tables were finally carried into the inventory, and the numbers came out 89 rows with a live read and 47 without. They had been written as 83 and 53. Fourteen rows also held their reading in the price column, where a price belongs, which is why three of them were still marked not checked while their page one was described three cells along. The audit now reads all four places the corpus keeps a reading, so a reading recorded in any of them has to reach the inventory.
Two pages the corpus had already told us about. The largest measured cluster with no page behind it was the cost of a website — its head term 1,900/mo at a competition index of 45 — and the page that answers it now exists in both languages, with its table drawn from the audited ledger rather than from the marketing version: year one is the number every quote leads with, and year two is the bill. And the definition page for AI SEO now titles itself GEO vs SEO vs AEO: the same practice under three names, because the two largest rows in that cluster are questions the page already answered with evidence and the title was the only thing not carrying them. The guide that answers "how do I get found on Google" was carrying neither of its cluster's rows and now carries both — including a row of a thousand searches a month at a competition index of three that the corpus had filed as "reference intent" and left unclaimed, when reference intent is the guide shape and the guide was already one.
And the gates that keep it. Every row a page targets must have a live SERP read, and a guide must title itself for the query it was measured to own — the trade pages have always been held to the second rule, and a guide is a page too. The corpus's own third table, the one nothing read, is now checked against the build; and the dynamic routes in the sitemap have to enumerate every registry record, which is the playbook's dev item 8 and was unwritten until this week.
The GEO/AEO cluster was four families wearing one label. Nine more rows were read through the browser, and they split a cluster the corpus had carried as one thing since the first pass. Four of the nine are a single shape: a market of software products ranking each other — SE Visible, Yotpo, Writesonic and Profound all publishing a "best GEO tools" list, with the tools' own product pages beside them. A page cannot take a leaderboard by answering it well; it can only take it by being on the list. One more is a button: six third-party llms.txt generators, a GitHub repository and a Reddit thread, and the searcher wants a button. Two are ours, and one of them was a row nothing had claimed: answer engine optimization services, 590/mo at a competition index of 10, whose page one is agency service pages — the same shape as the bigger twin the ai-search page already owned. That page now carries both rows and its title carries both phrasings, because a title that names one of them and leaves the other to a competitor is worth less than the elegance of naming one.
And the table of the titles was being read for the wrong thing. The corpus's §2.5 table records what each solution page is titled and which row the title carries. The rows were checked against the build; the title strings were checked against nothing, so a title could move and the research document would go on quoting the old one — describing a site that no longer exists. The audit compares them now, and the comparison carries its own negative control: the same corpus with one title changed by one character has to go red and name the page.
And a guide for the one row that asked for a page of its own. The corpus's reading of website as a service (260/mo) said the page one is the business model — the model's advocates, the tools built to run it, and the guides on selling websites on a subscription — and that it needed a page rather than a title change. It has one now: "What is a website as a service — and what it costs in year two". It defines the term, compares the four ways of getting a website and what each one leaves behind, prints the audited renewal rates beside it, and ends with the exit prices nobody quotes before signing: Carrd's $49 code export, Tilda's Business plan and six licence restrictions, and a store that goes offline when the subscription ends.
It is also the first document in the Choosing a builder book, which had a name, a blurb and a place on the docs index and nothing in it.
And the second one answers the row that asked for it next. The free-trial row's page one is the vendors' own funnels — GoDaddy's fifty AI credits, Squarespace's trial, Wix, Canva, Weebly, Website.com's thirty days, Google Sites — plus a listicle of trial lengths and a forum thread asking which free tier is actually free. The answer is that the audited free tiers differ in what they withhold: Weblium's is de-indexed with mandatory noindex tags, four builders hand you a subdomain, Site123 prohibits custom domains on the Free tier, Relume's free plan cannot publish, and three first-year domains have no published second-year price. The guide is a table of eleven of them, and the platform's own row is a one-page static site, free forever, with a domain registered at cost.
And the third one answers the row the corpus said wanted a page. The cheapest-builder lists are sorted by the price that stops mattering after month one. The new guide sorts fifteen audited builders by the two-year total instead, and the sort is the argument: Shopify's first three months cost $1.00 and its two years cost $528.00, Hostinger's $2.99 renews at $10.99, and the builder that looks most expensive in year one — ten dollars a year — is the cheapest in year two because its rate does not move. Nine of the fifteen renew at the rate they sell at, four are an intro followed by the real price, and two publish no renewal rate at all. It is the third document in the book, and the cheapest one to compete for: a competition index of 15.
And the local-SEO cost node picked up the second row of its family. The corpus had recorded local seo pricing (260/mo, comp 5) as "the same shape, with a bigger audience" — an agency rate guide, then forums — and the answer node's head now says both phrasings: What does local SEO cost? Local SEO pricing, and the three bills. A pricing question and a cost question are the same question: what recurs.
And the price-posture guide took the biggest row of the new family. cheap web hosting (6,600/mo) is the same intent as the row it was written for, with twenty times the volume, and its page one sorts by the promotional price — which is the thing the guide exists to sort against. The guide is now titled "Cheap web hosting: what it costs in year two".
And the hosting book got its first definition. The sixth probe's second-lowest competition index belonged to managed website hosting (1,000/mo, comp 11), whose page one is four definitions and a listicle of managed hosts. A definition is the shape this site publishes best, and the hosting book had six documents and no page that defines the term. There is one now, and it separates what a host takes on from what an agency takes on, then answers the question underneath it: the second year, where the audited renewal step runs from 1.0× to 33×.
And the corpus asked a family it had never asked about. The five original calls probed the zero-volume claim, local-service verticals, GEO / AEO, hire-a-designer and renewal language — not one of them asked about hosting or domains, and the site has a hosting book with six documents, a domains book with eight, an audited renewal ledger for fifty builders and an at-cost domain pass-through. A sixth call (40 keywords, $0.09) found 36,160/mo, comparable to the whole GEO / AEO cluster, with the two lowest competition indices in the corpus outside the local-SEO rows: how to choose a web host (comp 4) and managed website hosting (comp 11). The method checks itself: the probe reproduced an existing row's volume, competition index and CPC to the cent, and the AI Overview for cheap web hosting lists IONOS at a $14.00 renewal — the figure the audited ledger already carried.
And the brand-pricing family is closed — by the brand. wix subscription (480/mo) returns six of ten results that are Wix's own pages: the pricing page, the help centre's "Managing your subscriptions", "Overview of Wix Plans", "How much is a Wix website?", "Which Plan to Pick" and "Purchasing a Monthly Plan", then three videos, Forbes' pricing guide, and a Reddit block of price-hike complaints. A vendor owns both the price question and the support question about its own subscription, which is why those rows are graded E.
Two more maintenance rows confirmed the family from the other side. managed website service (40/mo) returns the same agencies §2.16 read for website management service — Eversite, Alliance Interactive, Pronto Marketing, DreamHost, Webstix, Red Evolution — so two phrasings of one intent, and the page keeps its larger row. And website hosting and maintenance (90/mo) is the two-bill split sold by the people who sell both: hosting and maintenance are two invoices, and the "People also ask" asks for each of them separately. That is the one question this site's hosting and maintenance pages answer between them, and the corpus has no measured row for it, because the hosting family was never probed.
And the same inheritance bug was in three more places. The Open Graph fix covered the title, the description and the URL; reading the rendered page showed the Twitter card still carrying the site's tagline, and the four noindex pages still publishing the homepage's canonical — a page saying "I am the homepage". The layout now declares no per-page field in either block and no canonical at all: every indexable route declares its own, and a noindex page declares none, which is what the four of them wanted. Three more checks, three more negative controls.
By the end of the day the inventory holds 168 rows with a live page-one read and 28 without, measured over the table's own cells rather than carried forward. The count in this entry was itself a row behind for a while — it said 121 and 45 while the table already held 122 and 44 — and it is corrected here rather than left to look exact. And the last five rows read corrected a number the corpus had been using as if it were two: a competition index of 1 can mean nobody advertises here rather than this field is open. website financing has the lowest index in the corpus outside local seo consultant, and its page one is Affirm and ChargeAfter — a closed market. Its neighbour in the same cluster, website payment plan, carries an index of 46 and an organic page made of the IRS and four state tax agencies. The index is advertiser competition, and it can point the opposite way from the page one; nothing in the table can tell the two apart.
Two pages the corpus said owned a measured row, and no check was looking at either. The local-SEO cost answer node (2026-10-20) and the cost answer node (2026-10-21) were both built with the phrase a searcher typed in the title — and the map of which page owns which row had never listed them, so the two checks that would have caught a title drifting off its row were pointed at a list that had not been updated since the pages were written. A page outside the map cannot fail the rule. Both are in it now.
And the cost answer node carries a second row: website design cost (1,300/mo) is the head term's page one, result for result, so the head now says both phrasings — Website design cost: how much should a website cost in year one and year two? The body needed nothing: its third section already answers the design-fee reading, because a title problem is a title problem.
And the pages stopped describing the homepage to everything that shares them. Twenty-one routes — every learn page, every doc, pricing, about, contact, terms — published the homepage's Open Graph: the site's tagline as their og:title, the homepage's description as their og:description, and the homepage's URL as their og:url, on pages whose own canonical pointed somewhere else.
The cause was a merge rule rather than a typo. Next merges a route's metadata with its layout's field by field, so a layout that sets openGraph.title hands that title to every child route that does not override it. The layout now declares only what is true of every page — the site name, the type, the locale, the one card — and the per-page fields are absent rather than empty, because with them absent the resolver falls back to the page's own title and description.
og:url is the exception: Next does not derive it, so a page has to say which URL it is. Every marketing route says so through one helper, and the Open Graph title is the page's own title without the layout's %s — zeso template — a social card that says "… — zeso" is a card about the brand, and a card that says the page's own title is a card about the page. The gate holds both halves: the layout may not declare a per-page Open Graph field, and a route that declares a canonical must declare an Open Graph block.
And the domains book got its price page. how much does a domain cost (2,400/mo) was read through the browser, and its page one is six learning pages — the registrars' own editorial on what a domain costs — each answering with a first-year band: $10–$20 (Squarespace, GoDaddy), $10–$45 (Wix, with most domains at $6.90–$45), $10–$50 (Network Solutions), $6–$15 for .net and .org (Namecheap), and "a few dollars a year to thousands or millions" (Cloudflare). The two threads in the trending block are the answer underneath the query: "Namecheap .com domains renewing at $18.50/year? Why so expensive", and "Hetzner .com Price Increases 2026 by 7%", answered with "Verisign raises the price every year by 7% until 2029."
Nobody on that page prints the five-year number. Six pages give a band, one table gives a price per extension, and the forums complain about year two. The domains book had eight documents and no price page, so there is one now: /docs/how-much-does-a-domain-cost — "How much does a domain cost? The price of popular TLDs over five years" — prints eighteen TLDs with the first year, the renewal and the five-year total, and then answers with the registry's own contract: $10.26 until 2026-11-01, $10.97 after it, about $13.45 by 2029.
And it does not repeat the marketing page. The corpus had already warned that a guide "would have to out-quote a page that already quotes Cloudflare at $10.44 and Porkbun at $11.08 against our $14.99". This guide quotes nobody: the comparison stays on /domains, where the rivals and their prices already are, and the guide prints the one table nobody else does. Ten of the eighteen TLDs land inside the market's own $10–$20-a-year band over five years, and eight do not — a .ai works out at $75.19 a year, nearly four times the top of the band.
And the family's two biggest rows were read at the same time. cheap domain names (4,400/mo) returns the registrars' own cheap-domain landing pages with TLD-List's 3,537-extension price table beside them — and the forum's top answer to "which registrar is cheapest" is that table, not a registrar. buy a domain name (4,400/mo) returns registrar homepages and a 240-comment thread whose top answer has 286 votes for Cloudflare. Google's own boxes put "how much should it cost to buy a domain name?" next to both, which splits the intent in two: where to buy, and what it costs. The second half has a page now.
And the first half said nothing at all. /domains — a page whose whole content is a price table for 400+ TLDs, with the renewal beside the first-year price, a five-year total on every row, and a dated comparison against twelve other registrars — shipped under the single-word <title> "Domains". It is now "Cheap domain names: 400+ TLDs, with the renewal shown", and the description says the other half out loud: we are not the cheapest .com and we say so.
And the marketing pages had no gate. The guide map and the solution map existed; the marketing map did not, so a marketing route's title could drift off its row and nothing would notice — which is what happened here. MARKETING_QUERY_EXPECTATIONS is keyed by the route, because a marketing page has no slug, and the check is the one the guides already use: the title has to contain the phrase a searcher typed. A route in the map whose title cannot be read is a failure rather than a skip. The gate bites: reverting the title to "Domains" turns it red and names the row.
And the price table was hand-typed, which is the one thing it must not be. The domain guide's eighteen rows were typed by hand into a document, and lib/domain-pricing.ts exists precisely so that a price is derived rather than typed — so the table was a second, hand-kept copy of the catalogue: correct on the day it was written, and silently wrong the first time a wholesale cost moved. It is derived now. lib/content/price-tables.ts builds the rows, the band counts and the per-year averages from the same functions that price the site, and the document interpolates them, so there is nothing left to keep in sync.
The Verisign escalation schedule was a comment in the pricing file and a second copy in the document. It is COM_ESCALATION now — data with one home — and the date the documents print is formatted per language from that one string, so "on 1 November 2026" and "2026 年 11 月 1 日" cannot drift apart. The table the build produces is byte-for-byte the table that was typed, and the next price change moves both.
And the pricing book got the market's answer. web hosting price (1,900/mo) and web hosting cost (1,900/mo) were read on 2026-10-21, and the page one is the hosts' own pricing pages beside a set of cost guides — every one of them answering with a first-year band. The summary above those results is headed "⚠️ The 'Introductory Rate' Trap" and names the mechanism in three claims: the advertised rate is promotional, the lowest rate needs a 24- to 48-month prepay, and the renewal regularly doubles or triples. Nobody on that page adds it up.
The pricing book had three documents — the renewal policy, how to read a hosting price honestly, how to read a renewal table — and no market answer. /docs/web-hosting-price is it: the market's own table by kind of hosting, the trap the market names, the second bill (the domain, the certificate, the mailbox), and then what a plan costs here over five years, with the published renewal step beside it.
And every number in it is derived. The plan rows, the five-year totals, the free year's five-year cost and the renewal-jump table all come from lib/data.ts through lib/content/price-tables.ts — the same rule the domain table now follows. A price that moves on the pricing page moves in the document on the same build.
And the title carries two rows of the family. web hosting price and web hosting cost are two phrasings of one question and one page one, so one title carries both: "Web hosting price: what web hosting costs over five years". The third phrasing — how much does web hosting cost (1,000/mo) — is the same page one and the same question, and a title cannot carry a third phrase, so it is recorded, not claimed.
And the same question asked twice gave the market two different bands. website hosting price (1,900/mo) is row 143's page one result for result — and its summary puts shared hosting's renewal at $10 to $35 a month where row 150's puts it at $10 to $20, on the same day, for the same question asked differently, with both summaries quoting a Forbes line that says $10 to $20. A band that moves with the wording of the question is not a number anybody can plan against — so that sentence is now in the guide, next to the argument it strengthens.
And the biggest unread row was a distinction nobody was drawing. domain with free email (2,900/mo, opp 974 — the largest opportunity left in the table) was read on 2026-10-21, and its page one is email providers: Zoho Mail's forever-free plan (up to five addresses, 5 GB each), Cloudflare Email Routing with Gmail, ImprovMX, mail.com's hundred shared extensions, the hosts that bundle one in (IONOS, Dynadot), and r/selfhosted's "Best way to get email@mydomain.com for free or cheap?" at 370+ comments.
And the page one never draws the line the query turns on. A forwarding rule passes mail on and keeps nothing; a mailbox stores it. The first is free because nobody stores anything, the second is not free because somebody does — and the results list them side by side as if they were one product.
This site ships both, so the distinction is ours to draw. /docs/domain-with-free-email draws it: what forwarding gives you, what a mailbox costs over five years, and — the part that matters — who the free answer actually is. If the question is "a free inbox on my own domain", the honest answer is Zoho's free plan, and the guide says so rather than taking the row on a promise this site cannot keep.
And every number in it is derived too — the email plan rows and the five-year totals come from lib/data.ts through lib/content/price-tables.ts, like the domain and hosting tables.
And the domain guide now carries both ways of asking the question. how much is a domain name (1,600/mo) is row 141's page one result for result — the same six learning pages, the same TLD-List table, the same first result — and its title is now "How much is a domain name: how much does a domain cost over five years". 4,000 searches a month on one title, and the gate holds both phrasings, so dropping either one turns the build red.
The read also handed back our own rate card, in someone else's words. The trending block under that query is a thread called "NameCheap no longer cheap domains. Need alternatives.", and its top comment says the increase is "not just Namecheap but the industry in general", that Verisign raised the wholesale .com price "by around 70 cents", that it "goes into effect on November 1st", that "the wholesale price is now $10.97 a year", and therefore that "this will be true with ALL domain registrars" — which is also why "most offer deals with hosting/email services as that is the only way they can make any real money."
The same $10.97, the same November 1st, the same pass-through argument — in a thread about one registrar, restating the contract this site's prices are derived from. The guide now prints it beside our own numbers, because a reader who arrives from the search has just read the forum's version of the same fact and deserves to see that it is the same fact.
And the static tier's own page finally answers the question the static hosts do not. static website hosting (880/mo) returns Static.app, Vercel, Netlify, Firebase, Wasmer, the AWS and Azure how-tos, a "10 Best Static Website Hosting Providers in 2026" listicle, and three r/webdev threads — and the summary above them defines the mechanism while not one result on the page says how the bill is computed. The "People also ask" box asks "What does static website hosting mean?" and "How much does it cost to host a static website?".
/docs/static-hosting was "Static hosting and page limits" — accurate, and saying nothing to a searcher. It is now "Static website hosting: metered by pages, one free forever", and its opening states the mechanism and then the thing no result on that page says: this tier is metered by page count rather than by traffic, so a page that goes viral costs nothing, and the one-page tier is free for as long as the domain stays registered here.
And the map that holds it is now a map of pages, not of guides. The expectation table was renamed PAGE_QUERY_EXPECTATIONS, because the row it now holds belongs to a reference document — a table called "the guides" that quietly holds a reference page is a table whose name lies about its contents. And one row was read, and deliberately not taken. best web hosting for small business (1,600/mo) returns a wall of roundups — TechnologyAdvice, WebHostMost's numbered list, Hostingstep's "23 Tested, 5 Recommended", Forbes' "10 Best", CNET, Website Planet — over "which one should I pick" threads whose top answer is "it depends what your business is". The price-posture guide already answers that intent, and its title carries the family's biggest row: cheap web hosting (6,600/mo). Putting "best" in that title would trade 6,600 searches a month for 1,600, and a second page for the same question would make two pages answer one question. So the row is recorded, not claimed — with the reason, which is the part that matters: it is not closed, it is held, and the price of holding it is knowing which row was left on the table.
And three rows of the "hire a designer" family turned out to be one question. custom website design (1,000/mo) returns the builders' own pages beside design agencies and freelancers — the summary prices the work at $500 to $5,000 for freelancers and $5,000 to $30,000+ for agencies — plus a five-step process and a run of how-to videos. affordable web design (320/mo, competition index 10 — the lowest left in the table) returns the most local shape in the whole corpus: a map pack of web designers, agencies quoting $199 and $399, and cheap-builder listicles. And row 70 (affordable website design for small business) was read on 2026-10-21 with the same three shapes.
The family splits three ways and the site owns one of them. The local-designer pack and the agencies are a services marketplace — a shape this site will never serve and should not try to, because the searcher wants a person who builds sites for money and we are a product. What is left is the cheap-builder listicle and the how-to, and two pages already answer both: the price-posture guide and the cost answer node, which is the answer to "How much should a full website design cost?" — one of the two questions in that row's own "People also ask" box. All three rows are recorded, not claimed, and the reason is the one the corpus can name: their remaining volume is smaller than the row the guide already gave up when it moved to cheap web hosting (6,600/mo).
And one of the four questions in that box is a question this site answers better than anything on that page: "Can ChatGPT build me a website?" The answer is not a price band but a fact about what an engine does and does not do. But the corpus has no row for it — its two ChatGPT rows are both about being cited — and the whole "have a machine build my site" intent is unmeasured. The builder rows the corpus holds are about other people's pricing and other people's verticals, and the site's own product has no row in the table at all. That is a gap in the corpus rather than a title to change, and the corpus is what can close it: one probe of the AI-builder family would put a number on the intent this product exists for.
And so the probe ran, and it is the largest thing the corpus has ever measured. The seventh call asked thirty questions of the AI-builder family, one call, $0.09, the same location, the same language and the same search-partner setting as every call before it. 77,260/mo once Google's close-variant groups are merged — 147,860/mo raw, and the difference is three rows that are the same query at 33,100 each, plus two more pairs.
ai website builder alone is 33,100/mo, and it is the largest single row in the table — the corpus's previous biggest was web design near me at 14,800/mo. The CPC is $28.11, which is what a term costs when the advertiser is selling software rather than a service.
And the page one is this site's own shape: Wix, Base44, Replit, Squarespace, QuillBot, Kimi Build, Design.com, Hostinger and caffeine.ai's own pages, beside a "10 Best AI Website Builders in 2026" roundup and three forums asking which one is best. The summary's own questions are "What are the limitations of AI website builders?" and "How much does an AI website builder cost?" — both of which this site has pages for and none of the nine does.
So the AI builder's page now carries the row. /docs/ai-builder was "The AI builder — from a prompt to a site you can edit forever"; it became "AI website builder: from a prompt to a site you can edit forever" — the promise unchanged, the phrase the corpus measured now in the title, and the gate holding it there. The title has carried a second phrasing since 2026-10-22, and the entry above says which one it is today.
The table is 196 rows now, and 62 of them have no SERP check. The probe added thirty rows of the intent this product exists for; one of them has been read through the browser and the rest carry the neutral 0.8 until they are read, which is what the column says it means.
And the method the criteria lists never wrote down. how to choose a web host (110/mo, competition index 4 — the lowest outside the churn cluster) returns a set of criteria lists: Dealify's twelve factors, PCMag's eleven key considerations, HostPapa's three (uptime, page load time, support), LightWave's performance/security/support/scalability/backups/control, Business.com's ten tips, Hostingstep's "23 Tested, 5 Recommended", two Reddit threads, two Quora threads and five videos whose chapter lists are criteria lists in themselves. And not one of them is executable — every list is "what to look for", none is "how to check it", because uptime cannot be checked against a price page. The method and the list have been confused for a decade.
The site already held the method in pieces — the six cells a price has, the renewal step, the static/app split, the export, the domain's own clock — and no page put them in an order. There is one now: /docs/how-to-choose-a-web-host, in English and Chinese, with the questions in the order that disqualifies the most hosts first. The last one is the question none of the lists asks: can you leave, and what does leaving cost.
And two long tails, and a summary that contradicts its own page. website hosting with email (590/mo) is two thirds forums — "Is there a webhosting service that also does emailing?" at 30+ comments, whose top answer is "Most hosts will provide email as part of their offering" — beside email-hosting explainers and the hosts that bundle one, GoDaddy's own page reading "Web Hosting as low as $5.99/mo. Free email". The "People also ask" box asks "How much should email hosting cost?", which is the one line every list skips.
So the email guide carries that row too. Its title is now "Website hosting with email: a domain with free email, and what it costs" — holding website hosting with email (590/mo) and domain with free email (2,900/mo) at once, 3,490/mo on one title, with the gate holding both.
And do I need web hosting (40/mo) is a beginner's question whose summary answers "Yes, web hosting is necessary for any website to be visible and functional online" — while the section underneath that summary is headed "Do You Always Have to Buy a Separate Host?" and answers that you do not always need to, because an all-in-one builder includes hosting with the plan. The first result is a 60-comment thread titled "Do I need a server for my website?". The honest answer is the one the thread gives and the summary does not, and it is small and recorded rather than claimed, because the page that would answer it properly is one to write.
And two rows at competition index zero, and two title changes. web hosting renewal price (10/mo, comp 0) returns the hosts' own renewal-rate tables — Forbes' "Renewal Price (Shared Hosting)" column, HostGator's hosting price chart, HostPapa's renewal-pricing page, Hostinger's "$49/mo when you renew", Wix's intro|renewal bands — beside a forum thread asking which hosts renew at the same rate they sign up at. So the page one is the question our own policy answers, and the renewal policy page is now titled "Web hosting renewal price: how year two is priced here".
domain with free whois privacy (10/mo, comp 0) returns the registrars' own privacy pages (Porkbun, Namecheap, Spaceship, Openprovider, Hover) beside Cloudflare's "What is domain privacy?" and two forums — one of which corrects the premise: "this doesn't 'protect your domain'", which is exactly the question our WHOIS document was written to answer. It is now titled "Domain with free WHOIS privacy: what it hides, and what it does not", and every domain registered here does include free WHOIS privacy.
Two titles, two rows, zero new pages. Both documents already existed and already answered the question; what was missing was that they named it, and that a gate could hold them to it.
And two more service marketplaces, and one list that never asks the question. web design packages (140/mo) returns agencies selling fixed-scope packages — the summary's own tier list ("Starter / Basic Package ($1,500 – $5,000): Scope: 3 to 5 pages") beside Succeeding Small's "$2,500 for 5-page SEO template" and a "$1050/$400" starter package, inside a $1,500 to $50,000+ band. That is §2.37's shape in a different row: a fixed-scope design engagement sold by a studio.
website hosting contract (90/mo, comp 5) returns legal templates — PandaDoc, Juro, LegalZoom, Practical Law's pro-customer UK agreement, an SEC filing, Level365's PDF — beside r/freelance's "do I need to make a contract?". The buyer on that page is a host serving other people's clients, and we are not in that business.
ai website builder no code (30/mo, comp 11) is ours, because the page one is seven roundups out of ten (topai.review's "Top 4" with Base44 first, aiprofitmode, opportunitybrowser's Best Tools, aiwebsitedetector's 10 Best) beside an AIpedia glossary entry and two how-to guides. The lists rank, and they never ask what the output is — and that is the question this site has a right answer to: the site is a JSON document you can edit, and its live content is readable over a public API without a key. What the lists do not carry is the answer about the others, and that answer belongs to the comparison pages, which record what each platform publishes and say "not established" where our capture did not reach it.
So there is a page now: /docs/ai-website-builder-no-code, drawing the line the phrase hides, printing the plan table with the five-year column, and ending on the four questions worth asking before picking one. The first is the one no roundup asks: can you export, and in what?
And the question the roundups skip, and the answer the forums give. ai website builder for business (40/mo, comp 9) returns the vendors' own pages — Wix's "just describe your business", Base44, Replit, Durable, Squarespace — beside a "10 Best AI Website Builders in 2026" roundup, an "8 Best ... for Small Business Owners" listicle, three videos, and a 60-comment thread on r/vibecoding from someone whose training business has had a bad website for years.
And the thread's most-upvoted answer is not a builder: "Use Claude to write you the code for the site, use Netlify to deploy and host it" — skip the builder and do it yourself.
So the page puts that answer first: /docs/ai-website-builder-for-business, "when you need one, and when you don't". A builder replaces hours, and the hours are the cheap part. If someone on your team can write and maintain HTML and CSS, a static host and an AI coding assistant is cheaper and the output is yours by definition; if the site is one page it is free forever; if it is a brochure that changes twice a year, a builder is a way of buying a CMS you do not need. Then the three cases where one is right, the price with its five-year column, and the list of what you keep — ending on the export, because if you cannot get the files out, you have not built a website, you have entered a tenancy.
And the page one gave the page its shape: every vendor's page opens with "describe your business" and every roundup ranks by feature and price. Nobody on that page tells a business owner when not to buy one — which is the first thing the searcher has to decide.
And the renewal tables, and the page that already had the answer. domain renewal cost (260/mo, comp 25) returns the renewal price tables — Network Solutions' per-TLD list (".ac $79.99 first year $86.99 per year"), Namecheap's, GoDaddy's "check my domain renewal price" help page, TLD-List's "lowest known renewal price" column, WebHostMost's "Domain Renewal Cost 2026: Why Prices Jump 300%" — beside r/selfhosted's "Cheapest place to renew a domain name" at 70+ comments, where one person wrote "renewals fee is super high, like 30$-50$ for a year" and another "$6.50 to renew my domain this year".
And the page one holds the answer and the anxiety in the same place. The summary puts a standard .com at $10 to $22 a year and splits the registrars into at-cost (Cloudflare, Porkbun — "around $9 to $11 per year with no hidden markup or price-hike traps") and standard (Namecheap, Spaceship — "around $13 to $17 per year for .com renewals"), while the "People also ask" box asks "Why is domain renewal so expensive?".
So the domain pricing policy page takes the row, because it already answers all three: the renewal is printed next to the first-year price on every TLD before you pay, the price is derived from a cost rather than set by hand, and the one thing that changes a renewal is the registry's own cost — which is the Verisign escalation the trending thread on that same page one is arguing about, and which this site's copy already states with a date on it. Its title is now "Domain renewal cost: the price, and the one thing that changes it".
And the cost breakdown by site type, and the three tools our ledger does not have. ai website builder pricing (30/mo, comp 6) is not a list of tools but a list of site types: "AI website builders cost anywhere from $0 to $160+ per month", split into "Portfolio or Brochure Site: $0 to $30 per month" and "Site with Booking & Payments: $30 to $150 per month", beside the vendors' own explainers — Base44's "How much does it cost to create a website with AI" first — and a video.
The material is mostly already here, except for the three tools that matter most. The audited ledger holds fifty vendors with their entry rate, renewal rate, multiple and two-year total, and sixteen of them are AI-capable (Wix, Squarespace, Hostinger, 10Web, Webflow, Shopify, Framer, Durable, Relume, Softr, Mixo, Zarla, Jimdo, SITE123, WordPress.com, Design.com). Base44, Replit and Kimi are not in it — and those three are the first three results on the page one.
So the row is recorded, and the next step is three price audits rather than a page. Until those three carry the same fields the other forty-seven carry, the page would be answering a comparison the site has not finished making.
And the ecommerce family, closed for a reason that has a cause. ai website builder for ecommerce (20/mo, comp 7) returns the builders' own ecommerce product pages — Replit's AI Ecommerce Builder ("Generates B2B, B2C, D2C, and Subscription sites in minutes"), Wix's Aria adding eCommerce pages from one prompt, Lovable, Shopify, Base44, Yeetcommerce — beside Manus's "9 Best AI Ecommerce Website Builders" and three how-to videos.
The shape is a store that takes money, and that is the one thing this platform does not do. The commerce modules exist, but the deployment has no payment provider wired, and the site's own copy says so: "this deployment is not connected to a payment provider, so there is no button that takes money." We build the site and the domain; we do not take a customer's money for it.
Recorded, not claimed — and the reason is a fact about the product, not about the search. Which means the family is re-openable the day a payment provider is connected, and it is written down here so the next reader knows the door is closed for a reason with a cause, rather than because nobody looked.
And four orders of magnitude for the same word. monthly website maintenance (30/mo, comp 7) returns maintenance price bands — Network Solutions' "$5–25/month for a personal blog" and "$200–1,000 for small business sites", GoDaddy's "$5 a month for basic, small websites" to "$25,000 a month for custom enterprise-level websites", WebFX's "$20 to $5,000 per month", Rocket.net's "$20 to $5,000", GruffyGoat's "$150 to $350 a month" — beside two r/Wordpress rate threads (80+ comments: "$30 for probono sites. Up to $250 for larger sites. Or $100+/hr") and a maintenance checklist.
And the "People also ask" box opens with the question the bands cannot answer: "Does a website need monthly maintenance?" A blog and an enterprise site are both "monthly maintenance", and the quotes differ by four orders of magnitude — so the price is not a measure of the work. It is a measure of what the site is, and of whether somebody picks up the phone at eleven at night.
So there is a page now: /docs/monthly-website-maintenance, printing the bands, naming what the monthly actually buys (the same checklist everywhere, so a retainer is a promise that somebody will look), drawing the line where the honest answer is that you do not need one, and ending on the two questions to ask whoever quotes you: what is in the monthly, and what happens if you stop.
2026-10-20 · The informational engine got the schema the strategy promised, and the gate that holds it
The five-pillar strategy named a schema type per pillar and an audit to hold them. Neither existed. The routes emitted a BreadcrumbList and a TechArticle and nothing else, so the four what-is-* definitions declared no DefinedTerm and the three answer nodes declared no FAQPage — and the strategy's own audit could not have been written against that state, because it would have described a different site.
Three defects fell out of writing it properly:
- Every informational page had two
<h1>elements. A body opens with its
own title; the page above it already renders a heading for the same document. The two were not even the same string — the page heading carries the reason-to-click clause, the body carries the term.
- Every learn page ended in a 301 loop. The cross-pillar banner linked
/docs/{own-slug}, which permanently redirects back to /learn/{slug}.
- A link inside a Chinese page dropped the reader into English. Body
links are written once and read in every locale, so they now resolve in the reader's language.
The audit is the other half, and it is the part that matters next: every document must declare a kind, every kind must earn the schema it claims, every link must resolve, every informational page must point at a guide and a product surface, and every decision document must appear on the Learning Center. The bilingual corpus is a ratchet rather than a rule — the count may not fall — because a rule that could never be green is a rule people switch off.
And the audit would have caught none of this by itself: it was written after the corpus was fixed, against the corpus that was already wrong.
Two more things shipped the same day, and the second one is the reason to read this entry twice.
The link graph was a diagram. The strategy promises that informational pages "form a closed-loop internal link graph" and "must not exist as orphan silos". The measurement was that twenty of the twenty English reference documents declared no related link at all — no panel, no prose link, nothing — and five of the seven how-to guides pointed at no solution page. A reader who followed one of the thirty-nine curated solution-to-guide edges landed on a dead end.
The related panel is now composed rather than declared: the writer's own links, then the definitions the body teaches, then the solutions that claim the document as a guide. Reciprocity is a property of the curated guide lists, not a second judgement. Two gates hold it — every document points out of itself, every guide points at a solution — and both were verified to fail, and to name the document, when the thing they watch is taken away.
And then the corpus checked what Google's own documentation says. This site emits FAQPage and HowTo, and two of the questions those schema types are supposed to earn are measured rows: faq schema (720/mo) and local business schema (320/mo). Neither was answered anywhere.
What the documentation says now is not what it said. Google's search documentation for the FAQ rich result redirects to a changelog entry reading "Removing documentation for the FAQ rich result feature … no longer shown in Google Search results", dated 2026-06-15. The How-to documentation was removed on 2023-09-14, as a rich result that "is no longer shown in search results, on both desktop and mobile devices". The QAPage documentation is still published.
So the pages now say it. Four claims the check made false went with it: a "100% crawl success rate" that was a median in a costume, "satisfying every technical ranking signal Google looks for", a LocalBusiness block that "directly populates Google's high-converting Local 3-Pack" — the map result comes from the Business Profile, not from markup — and the price an agency supposedly charges for a schema block, which is a competitor number we never measured.
And the corpus answered a question it had been leaving open: faq schema is now a definition of its own — the format, the two dates Google withdrew the rich result, and what the markup is still worth. The page exists because this site's own pages emit FAQPage, and had never said what that is worth.
And then the guides that told a reader to type something had nothing to show them. Pillar C asks for "complete configuration code snippets (DNS records, JSON-LD blocks, CLI commands)" and for terminal output examples, and the corpus had one code block in seven guides and no output in any of them. A reader could run dig and see a value, or run it and see nothing, and the guide had to be the thing that told them which. Five guides now show the answer: the domain guide answering with the CNAME target, the email guide reading the published records back out of the zone, the found-on-google guide showing a status line and a whole redirect chain, the llms.txt guide showing the manifest fetched, and the export guide showing the directory it leaves behind. Every value in them is derived from the code rather than typed next to it.
And then the answer bank was the one part of the corpus with no citations in it. Pillar B asks for "Direct, authoritative answers to high-friction industry questions with factual citations", formatted as supporting evidence, comparison tables and reference links. Six answer nodes, no comparison table on four of them, and not one reference link in the body of any of them — every claim on those pages stood alone with nothing to check it against.
The worst of them was the renewal-prices answer. It stated the churn figure as a known quantity, and that figure is one the research corpus names and refuses to cite. It gave Hostinger's renewal prices as $11.99 and $17.99, where our own audited pages say $10.99 and $16.99. It gave a "$22 to $35" domain renewal range, where one end is GoDaddy's published $21.99 and the other end has no source — and most of the industry prints no renewal price at all. And the English said "3x to 4x" where the Chinese said "2 倍至 4 倍 以上", on the same page, about the same mechanism.
All four now say what our own comparison pages say, the table behind them is built from those pages, and the two languages agree. The other five answer nodes gained the table and the references the pillar asks for, and a gate now holds them to it.
And the local-pack sweep had only ever read English. One Chinese page said a site with good structured data can be "直接被谷歌解析并推入地图与摘要 卡位" — pushed by Google straight into a map and a snippet placement. The English version of the same page says no such thing. That is the claim this repo has spent a day sweeping out, and the sweep missed it because it read one language.
So there is a gate for it now, and it is the first gate in this repo that reads prose rather than numbers. A sentence may not put an attainment verb next to a placement noun unless it is also negating — because the corpus states the boundary plainly, and those sentences are the most careful writing on the page. The gate carries a floor as well: the boundary statements have to keep being published, in both languages, or the promise rule is a rule with nothing behind it.
And then the comparison pages were guessing. Fourteen of the fifty were telling a reader that a vendor which publishes no renewal multiple has "1.0× or unstated" — a guess, where the playbook's absent-number rule says the page prints not published. The sibling component already did it that way; the detail page had its own wording and the two surfaces disagreed. The wording was also English on the Chinese page, and four different fallbacks were hardcoded strings in JSX, two of which did not even agree with each other. They all come from the dictionary now, and the dictionary keeps one phrase for it.
B12's data was wrong in the same direction: a 1× multiple travelling without a second rate behind it, because the registry's three fields were holding two different rates — the plan's, which is flat and published, and the free first-year domain's, which is not. And a new section in the compare registry audit now holds both halves: a ratio may only travel when both rates were published, and the compare pages print no literal of their own.
And the second pillar's link graph was missing two of its three directions. Template B names three links on a trade page: up to the parent cohort, sideways to two sibling trades, and across to the rival a reader most often arrives from. Two were there. The sideways one was not — a trade page linked up and across and to nothing else, while thirteen trades sat inside one cohort with none of them a link. And the cohort page named all thirteen of them and linked to none, so a reader who wanted the vertical had no way in.
The sideways set is curated, for the same reason the guide list is: a trade is not adjacent to another trade by a rule, it is adjacent because the two businesses have the same service model and the same buyer. The pairs are reciprocal, because two pages that point at each other are a recommendation and one that points away is a dead end.
And then the research itself was the last place the work was hiding. The keyword universe had carried two SERP checks as unusable — "returned off-topic results on first call and again on retry" — and its own gap list named the done for you and maintenance clusters as sized but not qualified. All three were re-read on 2026-10-20, and all three answered.
The two degraded rows were not unreadable queries; the read had degraded, which is what the method note said at the time: a degraded SERP is evidence of nothing. small business local seo returns ten agency guides and no builder, which cross-checks the row beside it that was checked the first time round. website for plumbers returns showcases, templates and one list of builders — no builder's own trade page.
And the done for you cluster is now qualified: the searcher is a business owner, and the whole page one is done-for-you services sitting on top of the builders — one of them says outright that it builds on Wix, Hostinger and Squarespace, and charges $99.95 to $3,200 for it.
That gave the corpus something to check itself against, and it did not come out clean. Ten of the twenty-three solution titles carried a measured keyword. Four carried the wrong one, and one of those four was website for restaurants, whose own SERP reads "yes — Wix, Squarespace, Canva, GoDaddy" — a row a builder cannot take. The five titles that carried nothing measured now carry the query they were measured to own, and a gate holds them there.
And the trade pages were claiming a schema block they did not print. Every one of them made the claim twice — a pillar titled "Schema.org Dentist structured data", and a FAQ that explains the type is a field you set rather than one the platform infers — and neither showed the markup. The playbook calls that block the differentiator, so a page claiming the markup without printing it is claiming the thing it is selling.
All fifteen now print it: the type the page already names, the fields the tenant renderer actually emits, and the offer catalogue the playbook asks for. The values are the reader's own, because the FAQ's own answer is that these are fields they set. The catalogue is the part that cannot be derived, so every trade declares its own four services — a plumber's catalogue is not a salon's — and a new check validates every block in CI against the Schema.org properties it is allowed to use, which is what the playbook asks for: a page that prints invalid JSON-LD fails the exact test the searcher is running.
And the lexicon had no pictures in it. The strategy asks the definitions for "architectural diagrams for core web concepts", and the eight entries had none — they named a format, a routing scheme, a policy sequence, a schema and a file structure without once showing any of them. All eight now carry the thing they are about, and the form follows the claim rather than a house style: a timeline for the phases of a request, a tree for the edges that announce one address, a vertical timeline for an expiry policy, a diagram for the one document three readers share, the specification itself for the schema page, the moment the three pillars are about for GEO — and, for llms.txt, not a diagram at all, because that page's claim is four dated measurements and a table is the honest carrier for those.
And then the guide that tells a customer what to type was sending them somewhere that cannot serve them. The domain-connection guide is the highest-intent page in the corpus — someone with a domain in hand and a registrar open. It asked them to point their CNAME at sites.zeso.net, a host in the platform zone, where customer sites are never served. The target they needed was sites.zeso.cc — the one the platform serves, and the one the guide now names. The same two paragraphs also asked for "Zeso's global Anycast edge IP address", which is not a value that exists: a custom domain resolves by pointing at a hostname, and the page had no hostname to give.
The right value was already in the runtime configuration, and nothing compared the two. So the value moved into a leaf module that the runtime and the published page both read, and a gate now compares what the guide says against what the deploy binds — the guide, the whole corpus, and both deploy files.
The other three guides that tell a reader to type something had the same problem in a different shape. The schema guide listed every field of the JSON-LD and never showed the block. The email guide described the records the platform publishes and then told the reader to look for a DKIM result it does not publish — the pipeline writes SPF, MX and DMARC, and deliberately no DKIM, because the keypair belongs to the mail service. The llms.txt guide listed the sections of the manifest and showed none of them. All three show the artifact now, and every value in them is derived from the code rather than typed next to it.
And two guides were teaching the type rule backwards. The renderer is orgOverrides?.type ?? (isLocal ? "LocalBusiness" : "Organization"), so a business type does not produce LocalBusiness — it produces that type. Dentist is what comes out when you set Dentist. Both guides said otherwise, and one of them listed "no explicit type" as a cause of not getting LocalBusiness, which is exactly backwards. That was the same finding the playbook's F7 had to be corrected for, applied to the two pages that teach the rule to the people who read them.
The tenant's own structured data was losing four of its fields. The renderer reads the business type, the coordinates, the hours and the price band from the organization's configuration, and the parser — the one that turns a stored spec back into a site — read seven of the eleven fields and threw the rest away. A tenant who set Dentist got LocalBusiness, because the type never survived the trip. The type is the field a machine filters on, so this was not a cosmetic loss: it was the difference between a site that declares what it is and a site that has an address.
The guide had been telling readers to set that type since the day it was written, and the stored spec kept proving it was not settable. The four fields are back. The test that should have caught it had been failing for a different reason since the F7 correction — it looked for an Organization on a site the renderer had been emitting as LocalBusiness, and it sat outside the audit suite, so nothing saw it.
A5 was the gate the strategy named and never got. "Nothing in CI holds either the renderer or the copy to the truth" was true of the tenant schema, and it is now false in three directions: a configured site emits every field it declares, an unconfigured one claims nothing, and every printed trade block is a shape the renderer can actually produce.
The block was the reason the gate had to be written. It printed areaServed and a service catalogue, and the platform could emit neither — so a page was printing markup the product could not produce. Both are organization fields now, and with them the three a local buyer filters on: the credential you hold, the amenities of the place, the cuisine you serve. Each trade declares its own, because a plumber's catalogue is not a salon's and a dentist's licence is not a stylist's.
Then the copy had to be rewritten, because it had been promising fields no block had ever carried. Eleven pillars named "24/7 opening hours", "accepted insurance", "parking access", "ASE certification", "bay capacity", "warranty terms" and "holiday hours" — real facts, and facts the markup could not declare. They now name what the block says, in the trade's own words, and a fourth section of the gate reads the copy the way a reader does: every field a pillar names must be a field that trade's own block carries, and the claims the platform can never make are refused outright.
Three of the promises were worse than the sentences. A badge saying "Local Maps Rank" and a badge saying "Gym Schema Ranking" promise a position the markup cannot win — the Business Profile decides that — and the rule that refuses such promises needed an attainment verb next to a placement noun, which a two-word label does not have. Badges have their own rule now.
The Chinese pages carried the same defect in a form the rule could not reach. "全面满足谷歌本地排名的严苛指标" — "fully satisfies Google's strict local ranking criteria" — names a placement and promises it; the noun was in the list and the verb was not. 满足, 符合 and 直通 are in the verb list now, and the two answers that promised a ranking say what their English twins say.
Six answers also contradicted the platform as it stands. They said the services were "the copy, not the markup" — and the markup carries a catalogue. They said the ASE certifications were not the markup — and the markup carries a credential. The guide and the definition carry the new fields with them, and so does the block the pages print.
Forty of the keyword universe's 136 rows had never been read. The playbook asks for four fields on every brief — volume, competition index, SERP owner, winnability — and says that a brief citing a volume without a SERP read is not evidence but a number. Forty rows were read live on 2026-10-20, and the reads produced a finding the numbers alone could not: the queries fall into families, and each family is owned by a kind of site. local seo for [trade] is owned by agency service pages, which is our own shape. [trade] website design is owned by galleries of examples, and website for [trade] by galleries, the businesses' own sites, or agent directories. A pitch cannot take a gallery.
Eight of the twelve queries the trade pages target were the wrong family, and the opportunity score could not see it, because it scores volume against competition and had never had a page one to read. Two titles moved without costing volume — lawyers and contractors now name their local-SEO row, which reads as agency service pages, and both pages already carried local-search substance in the schema block and the Google Maps FAQ. The other six keep their row, because the servable alternative is twelve to thirty-nine times smaller or does not exist, and the fix there is a page shape rather than a title.
Two headlines promised what the platform cannot deliver. The cohort page that carries the corpus's flagship query — local seo services, 6,600/mo at a competition index of 5 — opened with "Be the first result when someone nearby needs you now", on a page whose own FAQ says the markup does not rank. The lawyer page promised to "establish authority", which the corpus says comes from reviews, external citations and history. The first now reads "Be the business they call when someone nearby needs you now" — the call is the outcome the page's own description says it can win — and the second names the practice areas and the confidential intake, which is what the page actually does.
The rule that keeps them honest is new, and it is a position rule rather than a placement one. The claims audit already refused "map result" and "rich result"; it had no vocabulary for holding position one, because "the first result" is an ordinary organic position rather than a SERP feature. It has one now, and it reads headlines line by line — a headline carries no terminal punctuation, so a sentence-sized window swallows it and whatever negation happens to follow it in the file, which exempts the promise by accident.
The corpus's biggest row was on nobody's title. local seo services — 6,600/mo, a competition index of 8, and the highest opportunity score in the whole 136-row table — is the query the playbook's §4.2.1 assigns to the local-SEO cohort page, and no page carried it. The cohort page named the smaller row beside it, local seo for small business at 1,300/mo. Its title now reads "Local SEO services, without the retainer", which is what the page's own description already said it was about: "What a local SEO service actually does, what a small business needs, and which parts of the work a platform can make permanent."
Its SERP, read on 2026-10-20, is nine pages and every one of them is an agency — logicalposition, coalitiontechnologies, localseova, brightlocal, americaneagle, thriveagency, webfx — with a Semrush listicle and a YouTube video at #5 and #8. No builder ranks there, which is the opening the corpus had recorded on 2026-10-17 and nobody had taken.
A guide for the query with the lowest competition index in the corpus. how to get cited by chatgpt is 170/mo at a competition index of 1, and its page one is guides — marketersmedia, purposelaunch, a Reddit thread, a Quora thread — with no product page on it. It was the cheapest measured guide query the site did not own, and the learn library did not have it.
The guide is written against the site's own evidence, which is what makes it different from the pages that already rank for it. llms.txt is not the lever — four measurements say so, and the site's own definition page has them. The markup is: the block the platform prints, in a file a crawler can fetch without parsing a page. The fetch is: a live robots.txt that names the AI crawlers. And the content signal is: the search=yes, ai-input=yes, ai-train=no the platform already sends. It ships in both languages, is featured on the Learning Center, and the AI-search page points at it.
The copy that contradicted it is fixed too. The AI-search page said answer engines "read machine-readable llms.txt manifests" — the claim the site's own definition page spends four sources refuting. It now says what an engine actually does: fetch under a timeout budget, parse, and attribute. Its headline promised to be "found, cited, and recommended" by three named products, and its audience promised to "dominate AI-driven answer engine results"; it now promises the citation. Two learn documents claimed absolutes no site can keep — "guarantees 100% crawl success" and "ensuring zero crawler timeouts" — and two carried unsourced specifics: a daily page count and a "2 to 5 seconds" timeout range.
The one ranked trade without a page now has one. The playbook's Phase 2 names three trades — contractors, restaurants, electricians — and the first two were built while the third was skipped. It is also the sixth trade in the corpus's own ranking, and the only ranked trade with no page.
Both of its rows were read on 2026-10-20. local seo for electricians (210/mo, comp 18) reads as agency service pages, which is our shape, and electrician website design (260/mo, comp 18) reads as example galleries — "20 Best Electrician Websites of 2026" and "8 Electrician Web Design Agencies: Pricing & Lock-In Risks" — so the page names the local-SEO row, the way the dentists and plumbers pages do. That is the new rule in the query-target gate earning its keep on the day it was written: the row with the higher opportunity score is a gallery, and a pitch cannot take a gallery.
The page declares a Schema.org Electrician entity with the four services it actually sells, the licence it holds and the liability insurance it carries, and it links sideways to the two trades that share its buyer and across to the three builders a reader compares it against.
One more playbook gate now exists in the build. §5.6 lists "Hub-delta — every page answers at least three questions its hub does not" among the anti-thin gates, and it was in the document and not in the build: sixteen trade pages each carry a cohort as their parent, and nothing stopped a page from answering the same four questions its parent already answers — which is what a doorway is, and what the other five gates all try to prevent.
The gate compares the questions, normalised, because a page that asks the same thing in different words has still asked the same thing, and it compares the pillars too: a trade page whose three features are its cohort's three features has nothing of its own to say. All sixteen pass today with four or five unique questions each; the gate is there for the next one that does not.
Ten absolutes, and one claim the evidence had already refuted. The flagship cohort page — the one that carries local seo services, 6,600/mo at a competition index of 8 — still said answer engines "cite natively" the manifest and entity feeds it publishes. The corpus's own measurements say the opposite: across roughly 300,000 domains, then 37,894 AI-cited domains, then the server logs themselves, the file does not move citations. The same page said "ensures your site loads instantly", "never lose a mobile search", "guarantees permanent stability" and "your business is accurately cited and recommended" — absolutes about results that belong to a search engine, a crawler or a reader.
Ten of them are rewritten, in both languages, and the promise is now the mechanism: the page loads from the edge nearest the reader, the facts on it are legible and quotable, and whether an engine quotes you is its decision.
And the rule that keeps them out. The claims audit already refused "map result" and "rich result", and refused the first position. It now also refuses an absolute paired with a third party's outcome. An absolute about our own work — "instant rollbacks", "guarantees layout stability", "you keep 100% of the payments you take" — names no third party's result and passes; "ensures your business is accurately cited and recommended" does not. A vendor promising a ranking in their own FAQ is the vendor's promise, so a sentence that attributes the claim to them is exempt too.
An answer node for the cheapest question in the local-SEO family. local seo cost (140/mo, a competition index of 1) and local seo pricing (260/mo, comp 5) were read on 2026-10-20, and the page one is agency pricing pages and Reddit: the shape is a page that answers the cost question with prices. The answer bank had nothing there.
"What does local SEO cost?" now exists, in both languages. It splits the phrase into three bills — the free profile, the site you can buy once, and the upkeep that repeats every month — and says which of the three is the subscription. It also says why the phrase reads as a monthly line at all: the audited renewal steps run from 3.68x to 4.26x on the two cheapest Hostinger tiers, so a builder whose second year costs four times its first has not changed the work, only the invoice. The node is featured on the Learning Center, links the renewal procedure, the two-surface guide and the exportability test, and points at the platform surface it describes.
The corpus's table of the pages' target queries is now checked against the build. KEYWORD-UNIVERSE §2.6 records which page owns which measured row, who owns the page one for it, and whether the shape of that page one is one the page can take — and it went stale twice in one afternoon: once when two pages moved to a different row, and once when a page was added.
A corpus that records a mapping the build no longer holds records nothing, so the query-target gate now reads that table and fails when it disagrees with the map, naming the page and both rows. It found the two stale rows the moment it was written, and it will find the third one.
The corpus's two accountings of the same decision are now checked against the build. KEYWORD-UNIVERSE §2.5 keeps a table of the pages that carry a measured row, the title it rides in, and the row; §2.6 keeps a table of which page owns which row and whether the shape of that page one is one the page can take.
Both are hand-kept, and both were stale. §2.5 was missing three pages that do carry a measured row and had its totals wrong — "ten of 23 titles carry a measured keyword" — when it is sixteen of twenty-four. §2.6 had two pages recorded against rows they had moved off, and was missing a third page entirely.
The query-target gate now reads both and fails when either disagrees with the map, naming the page and the two rows. The gate found the discrepancy in §2.5 the moment it was extended to it, which is what a gate is for.
The manifest was missing the pages that carry the facts. /llms.txt is the site's machine-readable summary — the file the publish guide tells a reader to fetch, and the one an answer engine that reads it will use. It listed sixty-three pages and none of the twenty-four solution pages: not a cohort page, not a single trade page, which is where the schema block, the per-trade facts and the answer nodes live.
The publish guide says the manifest carries every published page, and the corpus's own check said every document was in it. Both were true and the site's substance was still missing, so the manifest now has a Solutions section and the audit checks it — the same way it checks the documents and the paths.
Each line is derived from the page it points at: its own headline and the first sentence of its own description. So the manifest cannot drift from the pages it summarises, and a page added without a manifest entry now fails the build.
The name-swap test now runs in the build. The playbook lists it among the ten anti-thin gates — "take the rendered page, swap the subject vendor for another vendor in the same band, count the sentences that become false" — and it was in the document and not in the build.
For a programmatic set it is the gate that matters most: sixteen trade pages share a shape by design, so nothing but a subject-specific count tells you whether any of them is more than that shape. The measure is conservative and mechanical: a sentence becomes false on a swap when it says something the other trades in the band cannot say — a word that appears in no other trade's copy. Sixteen pages, sixteen passes.
The cohort pages are not in the band: a cohort is the parent of the trades, not a rival of them, and swapping one for another would be a different test.
Negative control: a page whose copy is generic fails it with zero, and fails the query-target gate with it.
2026-10-17 · The five-pillar informational strategy, and the corpus it asked for
A strategy document is not a page. This one named five pillars, sixteen specific articles, a link graph and five audits, and it shipped with the corpus behind it: fifty competitor profiles measured against a registry, a lexicon of technical definitions, an answer bank of buyer questions, and procedural guides with their own schema.
The /learn and /docs split is the part worth stating, because it is the kind of decision that looks like tidiness and is actually about authority: a definition belongs at /learn/{slug}, a procedure belongs at /docs/{slug}, and a document that is given both URLs has two identities and therefore no identity at all.
The competitor work is behind it, and it is the reason the articles can make claims. Fifty rivals were profiled on their own terms — renewal multiples, five-year totals, who does the maintenance — and the comparison pages are generated from that registry rather than written by hand, so a new rival cannot quietly disagree with the ledger.
2026-10-11 · Two surfaces were live, and the sitemap never mentioned them
/pods and /use-cases were linked from the header on every page, were indexable, and were absent from the sitemap. Not badly listed — absent. The kind of defect that survives every content review and every "the site is healthy" check, because nothing is broken: the pages work, the links work, and the crawler simply never learns they exist.
The fix is a gate rather than a line in the sitemap. The sitemap audit now walks every route under app/[locale]/, reads each route's own robots directive, and fails the build when an indexable route is missing. Edit the array and the audit tells you; forget it and it tells you first.
The same week brought a set of contrast fixes that are worth one line because the pattern is the point: a chartreuse that reads as text had never been measured, and a de-emphasis style that failed AA in dark mode had been shipped on the assumption that it did not.
2026-10-10 · Machine-readable surfaces, and a ledger of fifty rivals
Three things landed on the same day, and together they are the difference between a site that is crawlable and a site that is readable.
- Per-bot crawler rules and machine-readable surfaces. The pages an answer
engine needs are not the pages a browser needs, and a site that serves one to both serves neither well.
- A comparison ledger of fifty platforms, generated from a registry with
one detail module per rival, and audited for parity — a rival in the registry with no detail module, or a detail module with no rival, fails the build.
- Solutions defined by audience rather than by feature, because "local
business" and "website builder" are not the same question, and a page that answers both answers neither.
2026-10-07 · Two product surfaces, and the last of the arbitrary geometry
/pods and /use-cases were rebuilt as real product pages rather than marketing surfaces, which is the more visible half of that day. The less visible half was arithmetic: a geometry ratchet existed to keep arbitrary pixel values from accumulating, and the last twenty-five were drained into role names. A value that has a name is a value someone can reason about; a value that is a number is a value the next person has to guess about.
2026-10-03 · Alchemy took the only deploy path, and the footer got real destinations
The deploy path used to be ambiguous, which is the same as saying two paths existed and the last one to run won. Alchemy was given sole ownership of routing, wrangler.jsonc was demoted to a development input, and the Worker stopped declaring its own secrets so a deploy cannot erase them. Turnstile was bound through the same layer for the same reason.
The other half of the day was smaller and more visible: the footer's link column pointed five labels — About, Blog, Careers, Contact, System Status — at the home page. A footer whose links go home teaches the visitor that none of the claims on it are load-bearing. Blog and Careers were removed rather than stubbed, and the pages that do not exist are now absent on purpose instead of present and lying.
2026-10-01 · One contract, one transport, and a wallet that pools
The API surface was rebuilt on one contract: the server defines it, the client is derived from it, and the dashboard calls the same thing any other client would. A typed client that cannot drift from its server is worth more than a hand-written one, because the drift is the thing that costs.
The credits system moved to a pool model in the same week — monthly grants, rollover pools, packs, FIFO spending — because per-turn accounting is easy to implement and wrong to depend on. A wallet that spends the oldest credit first is a wallet whose balance means something.
2026-09-29 · The free-domain floor was wrong, and the copy that carried it
The free-domain threshold was $7.49. It is $7.99. It was also wrong in a second direction, in six strings, and the live pricing copy was still naming tiers that no longer existed. Three separate defects, all of them the same defect: a number that was correct once, copied into the places that publish it, and never checked again.
What fixed it was not a careful read. It was an audit that computes the threshold from the catalogue and compares it against every string that publishes it, so the next change to the catalogue fails the build instead of failing quietly in six places.
2026-09-28 · Twelve specifications landed in a day, and the code came after them
The specs went down first, the code after: accounts and projects, registrar connections, the infrastructure plane, provisioning runs, pricing and orders, the provider contract, the site builder, mini programs, multilingual content, zip-drop static hosting, the merged hosting model, the database split, edge-injected apps, and the marketing surface.
The order is the point. Each specification records a decision and its reasons, and the implementation that follows cannot quietly diverge from the decision without a review noticing — because the review is reading the decision, not the diff. The specs that are still drafts are drafts because nobody has decided them yet, which is a different state from "not written".
2026-09-27 · Mini programs, and making published sites indexable
Two changes with one shape between them. Mini-program rendering landed in phase one: the same published content, served as a JSON document and rendered natively inside WeChat, with a Douyin renderer following on the same terms. The point was never the second renderer — it was that the content has exactly one source, and a second surface is a reader of it rather than a copy.
Published customer sites became indexable, with every canonical pointed at the real host. Before this, a tenant site could be live, correct and invisible, because the canonical still named the platform it was published from.
Also that day: hosts were classified by the Host header alone, and the edge cache was told not to serve one tenant's page to another. A shared cache without a key that includes the host is a cache that serves the wrong site to the wrong reader, and it does so silently.
2026-09-25 · A knowledge base, fifty compare pages, and one language withdrawn
The knowledge base shipped with the comparison corpus, and the compare pages shipped as generated surfaces rather than written pages — fifty rivals, each with a renewal multiple and a five-year total computed the same way, so the comparison is a measurement instead of an opinion.
Arabic was withdrawn from the site. The reason is worth recording, because it is the kind of decision that looks like a loss and is not one: a locale that resolves but renders English chrome serves a fallback while looking routable, and hreflang would claim a translation that does not exist. The language comes back when its copy ships, authored and reviewed.
2026-09-24 · Accounts, onboarding, and sites that provision themselves
Accounts and onboarding landed, and a starter site provisions itself. The interesting part is the ordering: registration is a domain registration, and everything after it — the zone, the certificate, the site, the mail records — is the same pipeline with more steps. A customer who registers a domain gets a working site before they have decided what to put on it, and the provisioning runs are resumable and idempotent, so a stalled step is picked up rather than repeated.
2026-09-23 · The platform's first public release
The twelve entries below were already in place when the repository went public on this date, and the public history does not record when each of them happened. They are grouped here under the release rather than given dates that were never recorded.
The renewal sweep now runs itself — and knows when it hasn't run.
Everything below this entry about renewals shared a quiet flaw: the database could refuse a charge we had not warned you about, and the renewal planner could produce a correct plan — and nothing ran it on a schedule. A renewal system that runs when a human remembers is not a renewal system.
So it runs daily now. The interesting part is what we had to build to notice when it doesn't.
Every safeguard we already had asks a question about records that exist — a charge with no warning, a domain that expired while still resolving. A sweep that never runs writes no records at all, so it passes all of them, and it looks exactly like a quiet week with nothing due. The failure is not a wrong record; it is the absence of a trace.
So every run leaves a heartbeat: it signs in when it starts and signs out when it finishes, and a check compares that against what was supposed to happen. That separates five things we could not previously tell apart — the job was never scheduled, it runs and always fails, it stopped firing, it died halfway through, or it is healthy — and each one needs a different fix.
Two more pieces came with it:
- The schedule is set so a missed day cannot cost you a warning. It runs
daily and tolerates two missed days, because our tightest obligation is ICANN's five-day post-expiry window. A test fails the build if either number grows past what that window can absorb: a sweep that runs too rarely does not send late warnings, it sends none for the windows it steps over.
- Old warnings are now actually deleted when their time is up. We said we keep
them seven years and that deleting them was permitted — and nothing was doing it. The same daily run now clears the queue, only ever what is already past its retention, and safely if it happens to run twice.
We tested the failure itself rather than trusting the happy path: the simulation drops the sweep for two days, then confirms the silence is detected, cleared by the run that catches up, and — the part that matters — that the two lost days cost no warning. A missed sweep delays a warning. It does not lose one.
We published the fees ICANN requires. Doing it corrected a citation we had wrong.
Closing the last open compliance item turned up a more interesting problem than the missing page.
The obligation had been written down as ERRP §3.3 — which actually says "registrars must permit the RAE to redeem a deleted registration". That is a behaviour, and we honour it. It is not a disclosure. The disclosure is §4.1.1, and it names three fees, not one: the renewal fee, the post-expiration renewal fee (if different), and the redemption/restore fee — all three to be clearly displayed on the site, with a link to them in the registration agreement.
The wrong paragraph was the real defect. A citation that points at a permission while the obligation is a publication makes an empty schedule read as a complete one — which is precisely what had happened: an audit row printed green over nothing, for as long as the citation went unchecked.
All three fees are now published at /pricing#fees, rendered from the same constant the audit reads so the page and the check cannot drift apart, and carried by the registration response so the agreement links to them. The registry's restore fee is a pass-through at zero markup — around $41.40 on a .com, quoted live for the specific name and never auto-charged. And because it is a sale rather than our revenue, it sits inside the tax base while adding nothing to margin: the two facts that sound like a contradiction until you separate "what is taxable" from "what we earn".
We also attack the guard rather than only running it. The audit hands it six deliberately broken schedules — a dropped fee, a marked-up pass-through, a restore fee booked as our own revenue, one chargeable without asking, one published as a fixed price, and an agreement linked to a page that does not exist — and each one must be refused.
The renewal system finally ran. Running it found six more bugs.
The two entries below this one end with a sentence that had started to be uncomfortable: the schema could prove a charge had been noticed, and refused one that had not, but nothing had ever tried to charge. Every guarantee was a guarantee about a system that had not run.
So the sweep exists, and it was played out over 900 days against the real database — a simulated gateway answering every presentment, a simulated registrar answering the expiry question, and a list of invariants checked on every one of those days. Not one of them may be violated, and the run exits non-zero if any is.
It found six defects, and they were all the same defect in different clothes: a rule that is true of hosting applied to a domain registration.
- A domain's renewal was presented on its expiry date. So the very first
declined card is already past expiry, ICANN's rules then require DNS to be interrupted, and the customer's site goes dark because their card expired. That was the routine path, not an edge case.
- Domains had no recovery path at all. A failed charge left the name active
forever: no retry, no grace window, and the sweep re-planned the same charge every single day. A customer's lapsed card was never retried — the most expensive ordinary failure we have, because the customer loses the name.
- Retries recorded nothing. A retry moved a counter and wrote no payment
record, so the ladder's own effectiveness could never be measured, which is the entire reason that table exists.
- Eligibility never asked whether we had already presented for that period.
- The sweep's look-ahead was borrowed from the domain policy, which was
invisible while both products happened to need the same number of days — and silently wrong the moment either moved.
- A charge could share a day with the notice that authorises it. The database
accepts a notice and a charge in the same second, and that is not notice: it is a receipt.
The last one is the one that justifies the whole exercise, because it was found by running the thing rather than reading it — on the simulation's first successful run. So the invariants were then deliberately broken, four different ways, to check that each is actually capable of failing. Reintroducing the re-planning bug produces 58 daily refusals, which is what it should do.
Three of the fixes changed the database, not just the code. A renewal order is per period and every attempt against it shares it, because the index that guarantees "at most one successful payment" keys off the order — giving each attempt its own order would have retired that guarantee the moment retries became real. The uniqueness backstop is now per retry, not just per opening attempt, closing the same double-charge hole one rung further down where it is much harder to see. And domains gained the ladder's state, including a grace column the schema had provisioned and nothing had ever written — dead schema is the tell that a state machine was described and never built.
One asymmetry is now stated in the code rather than left implicit, because all six bugs lived in the gap: a subscription's period end is a billing date we chose, while a domain's is a deadline the registry enforces and ICANN attaches obligations to that nobody can opt out of. So a hosting lapse ends in expired — our service stops — while a domain's ladder ends in nothing at all: the expiry comes from the registrar, and the software refuses to mark a domain expired from our own billing state, because doing that while we have in fact renewed the name would take a paying customer's site down.
What is still open is the money question underneath it, and it is now the largest one in this area: do we renew a domain at the registry before collecting, or collect first and let the name lapse if the card never clears? We currently collect first, which means a card that never clears costs the customer the name — with the post-expiry notice and the 30-day redemption window as the recovery path. Most registrars do the opposite and renew first, which protects the customer's name and costs us a wholesale renewal for every auto-renewing name that never pays. That is a business decision with a number attached, not a technical one, and it is written down rather than guessed at.
Also still true, and worth repeating because it is easy to read the above as "done": nothing schedules the sweep yet. It runs when it is called. The absence of a notice looks exactly like a period with nothing due, which is why the alarm for "this never ran" is part of the same job rather than an afterthought.
The renewal system was reviewed against ICANN and against the database. Both found bugs.
Three defects, all in code that had already passed its own audit — and none visible by inspection. Each one appeared the moment something tried to violate it, which is the argument for checking a promise by attacking it rather than by reading it.
The append-only notice log made every customer undeletable. Blocking deletes on the notice log was meant to make "we told you before we charged you" provable. It did that, and it also broke the three ON DELETE CASCADE relationships pointing into that table: deleting a customer cascaded into the log, the log refused, and the delete aborted. So three declared cascades could never fire, and GDPR erasure was impossible — a schema advertising behaviour it could not deliver, which is the same class of defect as copy that over-promises.
The fix says what is actually true instead of weakening the promise. A notice log holds no direct personal data — an opaque customer id, an amount, a period, a template key — so keeping it is not a privacy problem, and erasing the customer does not require deleting it. Retention is now explicit and the append-only rule is scoped to it: you cannot make the evidence disappear while it is still evidence, and past retention the row is a liability that must be purgeable. "Append-only forever" is not a policy, it is a hoard, and it was the thing that made erasure impossible.
Erasure is now redaction of the customer record, and the database refuses a partial one: every personal field cleared, the email pseudonymised to a non-routable address, and no live domain or subscription left behind — the registrar needs a full registrant contact for every registration.
The domain notice schedule did not meet ICANN's rules. The Expired Registration Recovery Policy requires two notices before expiry (roughly a month, then a week) and one within five days after it, telling the customer how to renew, in the registration agreement's language, delivered without requiring a click. Only the first two existed. Worse, they were fixed to days 30 and 7 rather than to ERRP's acceptable ranges, so a job firing a day late would have been out of compliance while looking perfectly healthy.
Notices are now windows with a signed offset, because a model that can only express "before expiry" cannot represent a compliant domain schedule at all. A build guard fails if those ranges drift, if the post-expiry notice loses its renewal instructions, or if a window could ever land on the charge day — a notice that arrives with the charge is a receipt.
And we had promised something we cannot deliver. "Your site stays up while we sort out your card" is true of hosting and false of a domain: ERRP requires DNS resolution to be interrupted from the moment a gTLD registration expires. A customer whose name has actually lapsed cannot reach their site, however generous our grace window is.
The state that rescues the promise is one the schema did not have. auto_renew_pending means we have already renewed at the registry and are collecting afterwards, so the name never lapsed, DNS is intact, and the site genuinely does stay up. That is the ordinary commercial practice, and it is the only state in which the promise holds. So what we may tell a customer is now scoped per product, and a guard fails the build if the domain version claims the service stays up or quietly drops its DNS caveat — because the failure mode here is a sentence creeping back into site copy, not a line of code.
Two things we are not doing, written down rather than left implied. We neither charge nor disclose a redemption fee, which ERRP and the RRA require us to publish and to state at registration — a disclosure duty, not a feature, and the audit prints it as an open gap rather than failing the build, because a known gap should be visible and not block every deploy. And retention is not yet a behaviour: the schema permits the purge and the queue exists, and nothing drains it. (The notice, retry, dunning and DNS-interruption jobs do now run — see the entry above.)
Corrections, added later rather than written back into the paragraph above. The fee disclosure is closed, and closing it fixed a citation: the duty had been filed under ERRP §3.3, which is a permission, not a publication — the disclosure is §4.1.1, and it names three fees rather than one. See the entry at the top of this log. The purge gap in the second sentence still stands, and so does the point about the purge being a document rather than a behaviour.
One limitation is worth stating plainly. The enforcement keys off a flag the caller supplies, so it protects against forgetting to mark a renewal — the realistic failure at this size — and not against lying about it. Deciding whether a charge is a renewal needs to know whether the subject's period had already begun, which is application state. So it is detected by a monitoring query instead of enforced, and detection is a weaker guarantee. Saying so is part of the guarantee.
Auto-renewal, and the promises behind it
A renewed paid year contributes +$162.00 on Pro — identical to any later paid year — but needs no free year and no invitation. It needs a notice and a working card. That makes it the cheapest revenue event in the business, and it is the number that ties renewal back to the free tier: $13.98 / $162.00 = 0.0863, which is exactly the 8.63% month-13 conversion threshold the free year has to clear. They are the same quantity at two scales, so a failed renewal is not a retention problem sitting beside the acquisition budget — it is the acquisition budget failing to clear.
Renewal is therefore pushed hard, and the line between aggressive and predatory is now written down as RENEWAL_POLICY in lib/renewals.ts: auto-renew on by default; notices at 30d and 7d (plus 1d for domains) that must state the amount, the date, and what happens if you do nothing; retries at +1/+3/+7/+14 days; a 30-day grace window; no late fee; no reactivation fee; no contact required to cancel; and no silent plan change on renewal.
Reviewing the schema against those promises found they were not merely unwritten — they were unwritable. 0001_init.sql had auto_renew and current_period_end and nothing else: nowhere to record that a notice was sent, nowhere to record a failed payment, and no grace window. "You are told before you are charged" was unverifiable by construction, and in a dispute the customer's account beats our absent row.
migrations/0002_renewals.sql makes three of them impossible to violate rather than merely recorded. A renewal charge cannot be inserted without a notice already on record for that period, stamped at or before the charge — a notice created alongside the charge is refused, because that is a receipt, not a notice. A renewal charge cannot be inserted on a subscription or domain with auto_renew = 0. And renewal_notices is append-only on both UPDATE and DELETE, because a log you can edit proves nothing, and the specific abuse is back-dating a notice to before a charge that already happened.
These are triggers rather than application rules for a narrow reason: each one is a rule a growth-minded edit removes, none are visible in any screenshot, and all three fail in a way that cannot be corrected afterwards. Application code refuses them too; the trigger is the floor that holds when the application is replaced.
pnpm audit:renewals does not read the migration and agree with it. It executes both migrations against a real SQLite engine and then attacks the promises — 22 attempts that must each be refused or allowed exactly as specified, printing the database's own error message, and exiting non-zero if a charge that should be refused is allowed. The assumed recovery figures (25% of lapses are a failed card, 60% of those recovered) are labelled as estimates so that payment_attempts can replace them with our own numbers once it is collecting data.
Also settled: when a domain and a plan are bought together they renew on one date. The two default renewal sweeps would otherwise produce two debits in one month for one customer, which reads as a double charge — and is the most effective way there is to make an honest renewal feel like a trap.
The free tier split in two, and one half became invite-only
"The free tier" turned out to be two products with opposite economics behind one word, and treating them the same would have been wrong in both directions.
The free App year costs us $28.97 to serve ($10.97 domain, $18.00 hosting) against $14.99 collected — year one is −$13.98, and it only pays for itself above 8.63% conversion. That one is now invited: not sold on the pricing page, not self-serve, reached by invitation, and disclosed in the pricing FAQ in plain words. Gated rather than hidden — the offer is a fact anyone can read about, just not a tier anyone can open.
The single free page on static hosting is the opposite: funded by the $4.02/yr domain renewal margin against $3.00/yr of static serving, so it earns +$1.02/yr while the domain stays. That one is included — provisioned with every domain registration, exactly as the pipeline documentation already described, with no invitation and no change in behaviour.
Collapsing both into one "hidden free tier" would have forced the free page behind an invitation and contradicted shipped behaviour. Plan.availability therefore has three states rather than a boolean, and the guard fails if a plan is reachable by no route, or by the wrong one.
Why gate the App year at all. Every figure above scales with SERVING_COST_USD, which is still an estimate. At $3/mo instead of $1.50/mo the break-even conversion moves from 8.63% to 22.21% — a different strategy. Publishing an unbounded offer priced against a number we have not measured is not aggression, it is an unhedged position. Gating converts it into figures: 500 redemptions across four channels, −$6,990 worst case and +$25,410 over the cohort at target conversion, printed by pnpm audit:invites alongside the same numbers at 1.5×, 2× and 3× the serving estimate.
It also buys what a public tier cannot: every invitation carries the channel that issued it, so "which campaign paid for itself" becomes a query instead of a guess.
Three rules are enforced in code rather than agreed in a document. An invitation never requires a card — that is a prepaid trial, not a gift. It never discounts the domain, because the domain is the paid gate and discounting it pays twice for one acquisition. And the price it converts into must be on the public pricing page, so the invitation page shows exactly what year two costs before the claim rather than on the first invoice. A fourth falls out of the split: an invitation may never grant something that is already free to everyone, because that is theatre.
The included page is a churn bet, not a conversion bet. It has no conversion event to amortise against, so it pays only while at least 42.7% of registrations keep the domain registered here. Past 57.3% churn it becomes a net cost that scales with registrations — and unlike the invited program, it has no cap at all. Nothing currently reconciles a domain leaving against a live free page.
Also corrected: two places on the site claimed the domain's first-year markup funds the free year. It does not. The markup is $4.02 against $28.97 of cost, and the gap is acquisition spend we carry deliberately. Saying otherwise would have hidden the exact number the program has to be managed against.
Our .com price was measured against the market
We priced our .com at $14.99 and had never checked whether that was competitive. It is not: against a dated snapshot of twelve registrars we rank 11th of 13 on first-year price and 9th of 13 on five-year cost of ownership. Cloudflare sells the same domain at cost, $10.44, flat; Porkbun at $11.08, flat.
The more useful finding is why it cannot be fixed. Our margin policy refuses to sell below cost + $2.50, so the cheapest price we are ever permitted to publish is $13.99 — already $3.55 above Cloudflare's shelf price. No discount available inside our own rules reaches an at-cost seller, and matching one would mean selling at a loss to lose anyway. So the domain is a component of the bundle, not a stand-alone product, and the acquisition spend stays where the year-one arithmetic is positive.
That measurement also killed a claim we had started making. A flat renewal is table stakes, not a differentiator: seven of the twelve registrars surveyed already hold year two at year one. The promotional-then-hike pattern belongs to hosts that bundle a domain as a loss leader — which is why the hosting renewal table is honest, and why a domain renewal table would not have been.
The site now states this in the unflattering direction, with the figures generated from the same snapshot the build audits. assertPositioningClaimsHold() fails the build if the market stops undercutting us, if our floor ever falls below an at-cost rival, or if the hosting comparison loses its cheapest competitor — so the copy cannot outlive the facts behind it.
Also fixed: the flagship category (.com, .net, .org) was missing from the Domains page grid. The cheap promotional TLDs were rendering and .com, the one everybody price-checks, was not.
Pricing restructured around renewal honesty
Domain markups are now set per category rather than by one global rate, and .com is verified against Verisign's published wholesale price — $10.97 from 2026-11-01. The previous snapshot carried $9.15, which means the margin audit was guarding a cost we had stopped paying; an audit cannot catch a wrong input. Every verified cost now records its source and date inline.
A second build-time invariant, assertNoBaitAndSwitch(), proves our renewal price only moves when the registry's cost moves — and holds exactly where the registry holds. .com now renews at $14.99 against a first year of $14.99: a 0% uplift. The pricing page carries the published entry-tier rates for the major hosts, dated and attributed, with the cheapest competitor left in on purpose — these are hosting companies bundling a domain as a loss leader, and their renewal jumps run to 17×. Registrars are a different market with a different answer; see the entry above.
The Domains page now shows a five-year total on every TLD, because first-year prices are the wrong column for comparison.
Domain pricing derived from cost
Retail prices are now generated from a wholesale snapshot with a per-category markup and a $2.50/year margin floor. A margin audit runs over the catalogue and fails the build if any TLD would sell below the floor. This caught a renewal price that was losing $20.01 per year.
Free-domain rules made explicit
A domain is free for year one only on qualifying annual hosting plans. The rule lives in one function, is enforced server-side, and cannot be requested by the client.
Provisioning pipeline
Registration now triggers a resumable, idempotent eight-step pipeline covering zones, delegation, certificates, sites and email. A stalled run is picked up by the sweep rather than requiring a human.
Onboarding checklist
A customer-facing checklist, separate from the internal pipeline, so internal retries never make the progress bar flicker.
在你的独立域名上体验边缘极速
全球 330+ 边缘节点、中位数低于 50ms 的 TTFB、Anycast 任播路由与全自动免费 SSL 证书。
相关指南与关联页面
- 技术百科
什么是 llms.txt——这份提案、它的格式,以及证据对它说了什么
The machine-readable surface this log keeps shipping, and what it is measured to do.
- 技术文档
如何为 AI 搜索发布 llms.txt 清单
The steps behind one of the entries above, if you want the same thing on your own site.
- 技术百科
AI SEO、GEO 与 AEO:同一件事的三个名字
The practice the informational engine exists to serve.
- 技术文档
小企业的便宜网络托管:第二年真正要付多少钱
这个市场里所有「最便宜」的榜单,都是按那个过了第一个月就不再作数的价排的。十四家经审计的建站工具,按同一个方案在第二年的花费排序,以及背后的三种价格姿态。
- 技术百科
什么是 Anycast DNS——全球边缘任播路由如何消除访问延迟
Anycast 任播技术允许多个分布在全球的物理服务器共享同一个 IP 地址,自动将来访用户引流至物理距离最近的边缘节点。
- 技术文档
我需要买主机吗?——三个场景,只有一个答案是「需要」
每个网站都需要一个地方把文件发出去。是否要为此单独付一笔,取决于你的站点要不要存状态、要不要按请求跑代码、有没有定时任务——诚实的答案只有一段话。
- 技术百科
什么是 ICANN 的 ERRP——域名到期后由谁按什么规则处理
《过期注册恢复政策》是注册商在名称失效时必须遵守的规则手册:通知、宽限期、删除,以及在注册之前就必须公示的三笔费用。
- 技术百科
什么是 FAQ Schema——以及它的富结果为何被撤下
FAQPage 把一个问题和它的答案配成一对,让机器能直接读出这一对。这里讲清格式、改变它价值的两个日期,以及这段标记今天还值什么。
- 技术文档
「免费建站工具」到底给了你什么
免费套餐不是折扣 本站审计过的每一家建站工具、各自免费套餐给了什么,以及它扣下了哪三件东西——你的域名、你的搜索结果,或者第二年的价格。
- 技术百科
什么是 LocalBusiness 结构化数据——它该包含哪些内容,以及它换不回什么
Schema.org LocalBusiness 结构化数据把实体地址、经纬度坐标、每周营业时间与执业资质写成机器能直接取走的形状,而且写自页面已经在显示的那批信息。
- 技术百科
什么是 SiteSpec——网站真正的存储形态
SiteSpec 是站点编译所依据的声明式 JSON 文档:页面、主题、区块、内容集合与语言版本。一份文档、多个渲染器,可移植因此只是一次编译,而不是一次抢救。
- 技术文档
什么是「网站即服务」——以及它在第二年要花多少钱
WaaS 是一种代理机构的商业模式,不是一件产品。这里讲清获得网站的四种方式、各自留下什么、审计过的续费价在第二年是什么样子,以及离开时要付出什么。