Skip to content

[finding] llms-full.txt page order is not reproducible either — same root cause as #194, second surface #196

Description

@hotlong

Found while implementing #178, which needed a before/after comparison of the served llms-full.txt and could not get one until this was ruled out. Pre-existing on main; #178's change does not cause it and does not fix it.

#194 records this for sitemap.xml. This card records the second surface it reaches, because #194's suggested fix — sort the entries in sitemap.ts — leaves this one untouched.

What was measured

Three production builds of apps/docs, each served with next start and fetched over HTTP:

build tree page order
A main @ 6653744 Architecture, Extend Existing Systems, ObjectOS, Quickstart, Why ObjectOS, Agents, AI Builder, IDE Skills …
B #178 branch, first build Architecture, Extend Existing Systems, ObjectOS, Quickstart, Why ObjectOS, Air-gapped Deployment, Docker, Deployment …
C #178 branch, --force rebuild, tree untouched identical order to A

B and C are the same commit, same tree, two consecutive builds, and their llms-full.txt bodies are not byte-identical. All three agree exactly on the multiset: 79 page blocks, the same 93 #-prefixed lines, the same 798 heading lines, the same 646 link targets.

So the file's content is stable across builds; the order the pages are concatenated in is not.

Where it comes from

apps/docs/app/llms-full.txt/route.ts emits source.getPages(i18n.defaultLanguage).map(...) in whatever order that call returns, and joins the result unsorted. Same call, same enumeration, same shape as #194: the pages move in contiguous section-sized chunks — the whole build/ group swaps places with the whole deploy/ group — which is what an enumeration ordered by async file-read completion looks like, not a sort.

Note llms.txt is not affected and was byte-identical across all three builds: it walks source.getPageTree(lang), whose order comes from meta.json.

Why it is worth filing now

#175 is writing a gate that asserts the composition of these two bodies. For llms.txt any positional assertion is safe. For llms-full.txt it is not: a golden file, an ordered list of titles, or a diff against a recorded body will flake green or red depending on which build it happened to observe, on a tree nobody touched. The pin has to normalise — sort the page blocks, or assert on a set.

The measurement hands #175 the normalisation for free: comparing the page-title multiset, rather than the sequence, made all three builds agree.

Secondary, and the same as #194: deploy-docs.yml publishes on every push to main, so the served llms-full.txt changes bytes on deploys that changed no content.

Nothing user-visible is wrong today — a reader of the file gets every page either way. The cost is that anything asserting on, diffing, or caching these bytes is asserting on something that is not a function of the repository.

Suggested shape

Whatever #194 settles on for sitemap.ts, apply to this route too — or better, fix it once at the enumeration rather than twice at the call sites, since source.getPages() is what is unordered and there are now two proven consumers of it. Sorting the pages here changes which order pages appear in, which is a composition change, so it wants its own pass rather than a rider.

#194 remains open and is not addressed here.

Reproduce

cd apps/docs
pnpm run build && sha256sum .next/server/app/llms-full.txt.body
pnpm run build --force && sha256sum .next/server/app/llms-full.txt.body   # differs; tree untouched

Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions