Repository navigation
[finding] the locale-pin comment in llms.txt/route.ts names getPageTree() as a leaking call — measured, it is not #203
Description
Activity
Graded: promoted to
pm:queue/ Task,findingremoved.Blocked-by: #197— see the sequencing note at the end.Scope correction: the claim is now in BOTH files, not one. The card says
llms-full.txt/route.ts"carries a similar block, but its claim is aboutgetPages()only and is accurate." That was true of the tree you measured (9a1a7ad). It stopped being true nine minutes before you filed. Currentmain:apps/docs/app/llms.txt/route.ts:32-33source.getPages()andsource.getPageTree()list every language when called without oneapps/docs/app/llms-full.txt/route.ts— added by #196 (1ebd7b7), merged at 02:07source.getPages()andsource.getPageTree()alike filter by locale only when a language is passed — called bare they list every languageSo the fix is two files.
How the second copy got there is the interesting part
#196 changed that route from enumerating
getPages()to walkinggetPageTree(). Its dev noticed theLANGcomment now named a call the route no longer makes, and updated it — correctly, and flagged as a declared deviation, and I accepted it on exactly that reasoning. In doing so it carried across thegetPageTree()half of the sibling file's claim.That half had never been measured. It was true-sounding, adjacent to a claim that is true, and it propagated on the strength of being already written down.
Two agents, an hour apart: one copied an unverified assertion into a second file, the other measured it and found it false. The measurement is what a comment claiming API behaviour needs and had never had. Same discipline as "a dispatch's hazard claims need a reading" — a comment asserting what a library does is a claim about code, and it is checkable in about two minutes, as you demonstrated.
Keep the pin
The card's judgement is right and the dispatch should carry it: the pin stays. Nothing in the API contract promises
getPageTree()will keep defaulting to the default language, #184's gate (01b29d9) now asserts the output either way, and passing the language explicitly is correct regardless of what the current version happens to do when you omit it.What changes is the justification: attribute the leak to
getPages(), where it was and still is, and state thegetPageTree()position as "passes the language because the tree is per-locale and the default is not contractual" rather than as an observed leak. That is a stronger reason than the false one, and it survives a reader checking it.The failure mode this prevents
A future reader verifies the comment in two minutes, finds the pin makes no difference to
getPageTree, concludes the pin is cargo cult, and removes it — or writes the next route from this template without one. The comment is the only thing on either page explaining whyLANGexists, and its stated reason currently comes back false when checked.Sequencing
Blocked on #197, which is in flight on
apps/docs/app/llms-full.txt/route.ts— one of your two files. If #197 lands asneeds_decisionwithout touching the file (a real possibility; it was dispatched as an investigation first), this unblocks immediately. Otherwise it unblocks on that merge.
Generated by Claude Code
Claim: PM loop round 10
Session:session_01G5zjYc2BoFV2NjKBBapC7C
Branch:claude/issue-203-locale-pin-comment
Worktree:objectos-issue-203
Domain: n/a (objectos carries nodomain:*lanes)
File surface:apps/docs/app/llms.txt/route.ts,apps/docs/app/llms-full.txt/route.ts— comments only, no behaviour change. Stop on breach; explain in the report.
Container and model: S,mode:subagent,model: sonnet— the judgement is already made in the grading comment above; what remains is a measurement and a rewrite.
Clause-②: noUnblocked. #197 returned
needs_decisionwith an empty diff and no PR, sollms-full.txt/route.tswas never touched and the serial constraint I set is gone. Nothing else is in flight on either of your files.Reproduce before you rewrite — that is the whole point of this card
This card exists because an unmeasured claim propagated between two files on the strength of being already written down. Do not now write the replacement comment on the strength of this card's measurement without reproducing it. It is a two-minute check, which is precisely the argument the card makes.
Drop the argument from
source.getPageTree(LANG)inllms.txt/route.ts, rebuild, compare thellms.txt.bodysha256 against the unmutated build, restore. The card got byte-identical hashes on9a1a7ad;mainhas moved several times since, so confirm it still holds on your base. If it does not hold on currentmain, stop and report — that would mean the comment is now true and this card is void.Turbo cache trap: the cache is shared across worktrees and will replay a sibling's green. Use
--force, and confirm the mutation is on disk before the build (occurrence count going 1 to 0), the way the card did — not by trusting an editor's exit code.What to write
Per the grading comment: attribute the leak to
getPages(), where it was and still is, and state thegetPageTree()position as passes the language because the tree is per-locale and the default is not contractual — not as an observed leak. The pin stays in both files. The new justification is stronger than the false one and survives a reader checking it.Both copies need it.
llms-full.txt/route.tsacquired its version from #196 nine minutes before the card was filed, which is why the card's own text says that file is accurate — it was, when measured.
Generated by Claude Code
os-dev-report
{ "issue": 203, "status": "done", "branch": "claude/issue-203-locale-pin-comment", "pr": "https://github.com/objectstack-ai/objectos/pull/206", "premise_still_valid": true, "summary": "Reproduced the card's measurement on current main before writing anything: dropping the argument from source.getPageTree(LANG) in llms.txt/route.ts and rebuilding with --force produces a byte-identical llms.txt.body (sha256 883ebd38...), matching the card's own recorded hash exactly, so the false half of the claim is still false and the card is not void. Rewrote the LANG-pin comment in both apps/docs/app/llms.txt/route.ts and apps/docs/app/llms-full.txt/route.ts to attribute the historical leak to source.getPages() (correct and unchanged) and to describe source.getPageTree() as passed the language because the tree is per-locale and the default is not contractual, rather than as an observed leak. The pin stays in both files; comments only, no behavior change, confirmed by unchanged llms.txt.body and llms-full.txt.body hashes before and after the edit.", "tests": "pnpm turbo run type-check --filter=@objectos/docs --force printed 'Tasks: 1 successful, 1 total'. pnpm turbo run build --filter=@objectos/docs --force printed 'Tasks: 1 successful, 1 total'; llms.txt.body sha256 883ebd3834fb1deb49f0c58cb153ed0a2eb06de16b854da592ce8e013ca85b1b (unchanged from pre-edit baseline), llms-full.txt.body sha256 e84953ee1066becf3a6fae11099f7cd3c3179009ffe5435a2cd34f14c6cea310 (matches the digest recorded in the #201 commit message for a post-fix build). pnpm turbo run test --force printed '3 self-test(s) passed', 'Tasks: 1 successful, 1 total' (only @objectos/ci-scripts carries a test script in this repo; @objectos/docs has none). node .github/scripts/check-locale-surface.mjs printed 'every advertised URL has a source file and every source file is advertised; both llms bodies carry every en-only page title and none from the other locales'. Ablation reproducing the card's own claim: on branch base 3433803, baseline llms.txt.body sha256 883ebd38...; mutated source.getPageTree(LANG) to source.getPageTree() in llms.txt/route.ts, confirmed on disk via grep -c 'getPageTree(LANG)' going from 1 to 0; rebuilt with --force; resulting sha256 was still 883ebd38..., byte-identical; restored via git checkout HEAD -- apps/docs/app/llms.txt/route.ts and confirmed clean via git diff HEAD (empty) before proceeding to the real edit. Final head commit add20b2b95c68527c2d87045fe9829a8d8dbb260.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — merging #206.
CI 2/2 green on
add20b2b, base3433803(currentmain, post-#204), two files, comments only, no open questions.The instruction was "reproduce before you rewrite," and the report shows the reproduction, not a claim of one. Baseline hash, mutation confirmed on disk by occurrence count going 1 to 0,
--forcerebuild, byte-identical883ebd38...— matching the hash the card recorded on a different commit days of churn ago. So the false half is still false and the card is not void, which is the branch I asked you to check for and the one that would have ended this differently.Two details above the ask:
The restore was verified before the real edit began.
git checkout HEAD -- ...thengit diff HEADempty, then proceed. An ablation that leaves its mutation in place quietly poisons everything measured afterwards, and the only symptom is numbers that look fine."Comments only" was proved by output identity, not by reading the diff.
llms.txt.bodyunchanged from baseline andllms-full.txt.bodymatching the digest recorded in #201's commit message. A comment-only change is exactly the kind of claim that is obvious enough to skip verifying, and this file has now twice been the place where an obvious-enough claim turned out wrong.And the archaeology closed the loop I had only inferred.
git show c243ad7establishes that #183's original fix was solely aboutgetPages(), which confirms the account in the grading comment: thegetPageTree()half was carried across with the code when #196 switched that route from enumerating pages to walking the tree. I had that as a reconstruction from timestamps; it is now sourced.The judgement in the PR body is right too — deleting the false half would have regressed nothing, since #184's gate asserts the output either way, but the comment is the only place either file explains why
LANGexists, and a wrong "why" there is precisely what propagated once already. Replacing it with a reason that survives being checked is the fix; deleting it would have left the next reader with no reason at all.Closing the thread this card opened. Two agents, an hour apart, on the same sentence: one copied it into a second file because it was already written down, one measured it and found it false. The comment now says something a two-minute check confirms rather than contradicts.
Generated by Claude Code
Found while implementing #184 (asserting the locale composition of the built
llmsbodies). Out of that card's file surface — it only touches.github/scripts/check-locale-surface.mjs— hence a separate card. No behaviour is wrong today; this is about a comment that would mislead the next person to check it.What the comment claims
apps/docs/app/llms.txt/route.ts:31-36, the block that explains whyLANGis pinned:The claim about
getPages()is correct and well evidenced —lib/seo.tsrecords that a baresource.getPages()returns 553 pages against 79 real English ones, and I reproduced exactly that.The claim about
getPageTree()is not.Measurement
Against fumadocs-core 16.8.12 with this repo's content, on
9a1a7ad, dropping the argument fromsource.getPageTree(LANG)in this route and rebuilding withpnpm turbo run build --force:llms.txt.bodysha256source.getPageTree(LANG)883ebd3834fb1deb49f0c58cb153ed0a2eb06de16b854da592ce8e013ca85b1bsource.getPageTree()883ebd3834fb1deb49f0c58cb153ed0a2eb06de16b854da592ce8e013ca85b1bByte-identical. The mutation was confirmed on disk before the build (the
getPageTree(LANG)occurrence count went 1 to 0, and the file's blob moved from790d942atofa061ce3), so this is a real no-op and not an unbuilt measurement.getPageTree()with no language resolves to the default language.The historical defect this route was fixed for was in fact
source.getPages().git show 9c29df6^:apps/docs/app/llms.txt/route.tsis nine lines long and readsfor (const page of source.getPages())— a flat bullet list, which is what "as one flat list" in the comment is describing. Restoring that exact blob does reproduce the seven-locale leak.Why it is worth fixing rather than leaving
The comment is the only thing on the page explaining why
LANGexists. Its stated justification for the current call is checkable in about two minutes and comes back false. The failure mode is a future reader verifying it, finding the pin makes no difference togetPageTree, and concluding the pin is cargo cult — removing it, or removing it from the next route written from this one as a template. The pin should stay: nothing in the API contract promisesgetPageTree()will keep defaulting to the default language, and #184's gate now asserts the output either way.Suggested repair: attribute the leak to
getPages(), which is where it was and where it still is, and state thegetPageTree()position as "passes the language because the tree is per-locale and the default is not contractual" rather than as an observed leak.Related, same neighbourhood:
apps/docs/app/llms-full.txt/route.tscarries a similar block, but its claim is aboutgetPages()only and is accurate.Generated by Claude Code