What Building a Thousand Pages Taught Us
10 min read · updated August 4, 2026
A plan for a thousand pages, four of them written. Two working sessions later, 940 existed and shortly after that all 1,000 did. Most of what decided whether that was worth doing had nothing to do with writing, and the single most useful thing built in the first session was not a page at all.
What actually happened
The plan was two documents: 1,000 rows, each with a slug, one primary keyword, an intent, a decay class and an angle. Row one was written on day one. By the end of the second working session the library held 800 editorial pages and 200 interactive tools, split across 39 clusters, written by roughly 40 agents working in parallel on files that never touched each other.
The honest summary of the outcome is that the production problem was solved and the demand problem is untested. The site is days old. We do not know whether any of it ranks, and the section at the bottom of this page says what would have to be true for it to.
What follows is the part that transfers: four structural decisions, each of which paid for itself within a day, and the things that broke anyway.
Build the machine before the content
The instinct at four pages written and 996 to go is to write. The first session wrote four pages and spent everything else on infrastructure:
- A typed page model with the rules encoded in it. Every page is a TypeScript object with required fields — one primary keyword, a cluster id, two or three sibling slugs — rather than a markdown file with front-matter that may or may not be filled in.
- A test suite over the data, not the rendered output. Rendering tests are slow and test the wrong layer. Every rule worth enforcing at this scale is a property of the objects.
- A release schedule held outside the repository. See the next section; this is the one that matters most.
- A tracker derived from the code. A generated count of what exists on disk, rather than a checklist somebody ticks. It was correct every time it was asked, which a hand-kept one would not have been by page 200.
The test suite earned its place immediately by catching a keyword collision between two agents that had never seen each other’s work. The four pages mattered too, but as a reference file: the thing every later agent was told to read before writing. One good example beats a style guide, and it is cheaper to produce.
Merging is publishing, and they must be separated
In a repository, a page exists the moment it is merged. So writing 400 pages and publishing 400 pages are the same action unless you make them different ones — and a bulk dump of hundreds of URLs onto a young domain is a textbook scaled-content-abuse signal. That mistake is one push away and it is not recoverable by reverting, because the crawl already happened.
The mechanism is a release date per page, a generated schedule file holding the dates, and routes that evaluate the date per request rather than at build time. A page can be written, reviewed, committed and deployed and still return 404 until its morning. Two properties made it safe rather than merely clever.
The default fails closed. No date anywhere means not published. It was the opposite when four pages existed and a human typed each date; the moment pages arrive twenty at a time that default is a loaded gun. The two failure modes are “forget a date and one page is invisible” and “forget a date and the backlog publishes itself”. Pick the first, and make a test fail loudly on it.
The scheduler is append-only. A slug that has a date keeps it forever. Re-running can extend the queue and can never move, re-order or un-publish anything already out, which is what makes it safe to run against live indexed URLs.
The full argument, including what happened when the owner chose to publish everything at once anyway, is in what we learned publishing on a schedule.
Disjoint files, not disjoint instructions
Twenty agents editing one directory works fine if each owns exactly one file and nothing shared. Across 40 agents and two waves there were zero merge conflicts. Four things made that true:
- One file per agent, named in the prompt. “Create exactly this file. Create, edit or delete nothing else.”
- The index is wired afterwards, by the orchestrator. Agents that edit a shared registry collide. Let them write content; do the plumbing yourself.
- Warn them about each other. “Other agents are writing sibling files right now — if a typecheck reports an error in a file that is not yours, ignore it.” Without that line they try to repair a half-written neighbour.
- Uniqueness comes from the source document. Every agent copied its keyword verbatim from the plan’s Keyword column. Eight hundred pages, zero duplicate keywords, from writers who could not see each other’s output. That only works if you state that the column is authoritative and must be copied exactly.
The one rule that decided quality
The plan’s Angle column says measured, tested or benchmarked on well over a hundred rows. Nobody had run any of it. An agent told to write those pages will produce plausible numbers, and a plausible number is the failure that destroys the whole library: one fabricated benchmark found by one reader discredits every other page on the domain.
The instruction given to every agent, verbatim, was that they may never write “we measured” or “our results show”, and that each such row had exactly three honest options: report published work by name and date it, ship the harness so the reader measures their own, or derive the arithmetic with every assumption labelled. Then rewrite the angle to what the page actually delivers, and record the rewrite — row number and reason — in the file’s header.
Roughly 120 angles were rewritten. Deriving turned out to be the strongest option: KV-cache bytes per token, LoRA parameter counts, a cascade break-even, HNSW graph memory are all calculable from first principles, and a derivation done in front of the reader cannot go stale. Shipping the harness turned out to be the most linkable.
Requiring the rewrites be recorded is what made it real. An agent that must write down which promise it broke and why does not quietly fabricate instead. Several declined outright — one refused to build a live-litigation tracker, one stated on the page that it would give no current GPU-supply status because any status it gave would be wrong within months, one quoted no water-usage figure at all because every published one is a division of two estimates. That judgement only appears if you ask for it explicitly.
What broke
| Failure | Description |
|---|---|
| A silently skipped file | One 40-row cluster was split across two agents, producing a file named c24b. The test suite matched cluster files with the pattern c\d\d-, which does not match c24b, so it silently skipped 20 pages. An agent reading the test found it, not the orchestrator. |
| A fragile progress count | Counting slug declarations at exactly four spaces of indentation reported a finished file as one page written, because that agent indented at two. Two status updates were wrong. Match loosely when measuring, strictly only when asserting. |
| Late shared primitives | The tools library shipped without a select control or a slider, and three agents each wrote their own within minutes. Two independent reinventions is the signal; the third means you were slow. |
| A bundle nobody had costed | One eager registry importing 140 client components put 441 kB of first-load JavaScript on every tool page, against 111 kB for an editorial page — on precisely the pages whose purpose is to rank. Fixing it took two wrong turns before the right one. |
| A session limit mid-flight | Twelve of twenty agents were cut off part-way through a wave. The recovery that worked: typecheck to find which files are actually broken (only one was), delete the genuinely empty ones rather than committing scaffolding somebody would mistake for a starting point, keep the ones holding definitions others depend on, and say plainly in the commit which rows never got written. |
Four defects in shipped interactive tools were found by running the code rather than reading it: an approximate-nearest-neighbour demo whose insertion loop started at the wrong graph level, so recall sat at 27% no matter what the search parameter did; a PDF reader that failed on every compressed file because the specification’s newline before a stream terminator is not stream data; a schema emitter that wrote nested classes after the class referencing them; and a markdown parser that treated a heading inside a fenced code block as a new document. The first of those is the frightening one — 27% recall is a plausible number that would have read as a lesson about approximate search rather than as a bug.
What we do not know yet
This is the section every account like this leaves out. The production problem is solved and the demand problem is completely untested.
- No page here has ranked for anything yet. The library went fully live days ago. Any claim about outcomes at this point would be invented.
- The cadence argument was overridden. The staggered queue existed precisely to avoid a bulk-release signal, and the owner chose immediate publication with the cost stated. Whether that was expensive is not yet knowable either.
- Volume is not the variable we can defend. What can be defended is that no page claims a measurement that did not happen. If the library earns links, that will be why; if it does not, the failure will not have been dishonesty.