The locale list leaves the prose, and pt is logged as an open question - #401
Merged
Conversation
Build size
Updated: |
nyblnet
added a commit
that referenced
this pull request
Aug 29, 2026
The entry recorded what went wrong with the locale list and stopped there. The same failure had three instances in one day — AGENTS.md, CLAUDE.md and docs/PARALLEL-WORK.md each stating a locale count, each true when written, each stale in silence, one of them costing bento/type a language — and the entry left the reader to generalise from them. Now it says it: A count in prose is verified by nothing. Name the mechanism, never its current output. With the consequence for THIS file, which is where it bites hardest: an append-only entry cannot be corrected, so a number belongs in one only when it is frozen. The test is whether the number could change without the entry becoming wrong. "Eleven cases went untested" passes — a fact about something that already happened. "Eight catalogues" fails, because the next locale makes it a lie nobody can edit. Prompted by declining a live count (`RIGS.length`, offered as a concrete figure for the rig entry) on exactly this reasoning. Refusing it was the right call and the reasoning was worth more than the refusal, so it is recorded rather than left in a message. Deliberately NOT duplicated into the rig entry, which is the same lesson from the testing side. Two copies of one rule drift, which is the failure this branch exists to fix; the closing paragraph names the connection without a hard cross-reference, so neither entry depends on the other's PR landing. #401 is unmerged, so this extends the entry rather than superseding it.
nyblnet
added a commit
that referenced
this pull request
Aug 29, 2026
Found by running the test I had just written against the document I had written it in. The entry states that a number belongs in an append-only log only when frozen, and offers "eight catalogues" as the example of one that is not. It also contains a table saying 8 twice. Not actually a contradiction — the table is stamped `Measured on 2026-08-29` and says the number is growing, so it reads as a reading taken at a moment. But the rule as stated did not name that distinction, so the entry appeared to violate itself three paragraphs after stating it, and a rule caught contradicting itself is not believed again. The rule now says what actually does the work: a number is frozen by its FRAMING, not its value. The same figure is safe reported as a dated measurement and unsafe asserted as a standing fact. Date a measurement and it becomes evidence; leave it undated and it becomes a fact with an expiry nobody sees. Stated explicitly because the short form is unusable: "avoid numbers" is advice nobody can follow, and a rule people cannot follow is one they route around. The real instruction is narrower — never write a number that is still claiming to be current. #401 is unmerged; this sharpens the paragraph added in the previous commit rather than superseding it.
AGENTS.md rule 6 named seven catalogues; LOCALES has packed eight since Portuguese landed 2026-07-25. PR #394 followed the rule exactly and shipped type/ one language short, hard-coding the seven-locale list into its new build script on the way. The rule was the defect, so no document states the list any more — rule 6 names where it lives and why it is not written down here. Wider than first proposed, after two findings from bento-team-type that I verified against the tree: - The list is THREE copies per app, not one: catalogue file, LOCALES, and any rig holding its own. "Point at the build script" is true and incomplete — it leaves the rig's copy stale, which is what goes red. - Only build-i18n.mjs (slides) errors on a catalogue missing from LOCALES. build-spaces-i18n.mjs lacks it (verified: zero matches for the guard string) and #394's build-type-i18n.mjs lacks it too. On those, adding a catalogue without touching LOCALES exits 0 and silently never packs it — a translation that ships to nobody. Porting the guard is ops' and is NOT done here. - scripts/test-i18n-coverage.mjs:51 already derives the list by parsing PACKED_LOCALES out of the generated packed.ts. That is the pattern a rig should copy, and it makes #394's second hardcoded list a regression against an established shape rather than a new problem. Also logged as an OPEN QUESTION, not settled: `pt` is two languages. slides/src/i18n/pt.ts is Brazilian by declaration (arquivo 47, ficheiro 10) and spaces/src/i18n/pt.ts drifted European (ficheiro 58, arquivo 9), under one locale code, so no mechanical check can see it. Settling it means retranslating a catalogue — translation work and a maintainer's call, not a docs change. Slides also violates its own stated policy 10 times, so no app is clean. CLAUDE.md carries the same stale "7 locales" and is deliberately NOT touched here; the wording is in the PR for the maintainer to apply. Counts verified on 2026-08-29 against origin/main = 220f7e7. No app's i18n touched.
…stale 7 Two corrections after ops traced the i18n protection levels, both verified: - scripts/test-i18n-coverage.mjs is SLIDES-ONLY. Line 34 hardcodes `coreDir = join(root, 'slides/src/i18n')`. My rule-6 bullet named it as the pattern to copy without saying what it covers, which invites a spaces or type session to assume its catalogues are checked. They are not checked by anything. The three apps have three different levels of protection — slides: guard + rig; spaces: neither; type (#394): neither, plus a second hardcoded locale list. - docs/PARALLEL-WORK.md §3 said "All 7 catalogs in the same PR" — the same defect this branch exists to fix, one file further down, and in my own zone. Found while checking §3's changelog rule. The count is gone; the line names LOCALES and cites hard rule 6. Also in §3: the changelog bullet still described per-app changelogs as a future ("when apps multiply, each app gets its own"). spaces/ and dash/ have had theirs for weeks and type/ is getting one. It now states what is true — including that the ROOT file is bento/slides' and has NOT moved to slides/CHANGELOG.md — and gives the reason a cross-app entry is a real defect rather than a tidiness issue: notes ride inside the signed update manifest, so an app describing another app's changes tells a user about changes their document did not get. That reasoning is spaces/CHANGELOG.md's preamble; it was nowhere in PARALLEL-WORK, which is where someone looks before appending.
The entry recorded what went wrong with the locale list and stopped there. The same failure had three instances in one day — AGENTS.md, CLAUDE.md and docs/PARALLEL-WORK.md each stating a locale count, each true when written, each stale in silence, one of them costing bento/type a language — and the entry left the reader to generalise from them. Now it says it: A count in prose is verified by nothing. Name the mechanism, never its current output. With the consequence for THIS file, which is where it bites hardest: an append-only entry cannot be corrected, so a number belongs in one only when it is frozen. The test is whether the number could change without the entry becoming wrong. "Eleven cases went untested" passes — a fact about something that already happened. "Eight catalogues" fails, because the next locale makes it a lie nobody can edit. Prompted by declining a live count (`RIGS.length`, offered as a concrete figure for the rig entry) on exactly this reasoning. Refusing it was the right call and the reasoning was worth more than the refusal, so it is recorded rather than left in a message. Deliberately NOT duplicated into the rig entry, which is the same lesson from the testing side. Two copies of one rule drift, which is the failure this branch exists to fix; the closing paragraph names the connection without a hard cross-reference, so neither entry depends on the other's PR landing. #401 is unmerged, so this extends the entry rather than superseding it.
Found by running the test I had just written against the document I had written it in. The entry states that a number belongs in an append-only log only when frozen, and offers "eight catalogues" as the example of one that is not. It also contains a table saying 8 twice. Not actually a contradiction — the table is stamped `Measured on 2026-08-29` and says the number is growing, so it reads as a reading taken at a moment. But the rule as stated did not name that distinction, so the entry appeared to violate itself three paragraphs after stating it, and a rule caught contradicting itself is not believed again. The rule now says what actually does the work: a number is frozen by its FRAMING, not its value. The same figure is safe reported as a dated measurement and unsafe asserted as a standing fact. Date a measurement and it becomes evidence; leave it undated and it becomes a fact with an expiry nobody sees. Stated explicitly because the short form is unusable: "avoid numbers" is advice nobody can follow, and a rule people cannot follow is one they route around. The real instruction is narrower — never write a number that is still claiming to be current. #401 is unmerged; this sharpens the paragraph added in the previous commit rather than superseding it.
nyblnet
force-pushed
the
docs/i18n-locale-source-of-truth
branch
from
August 30, 2026 19:13
843c275 to
f08e93f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AGENTS.mdrule 6 named seven catalogues;LOCALEShas packed eight since Portuguese landed 2026-07-25. PR #394 followed the rule exactly and shippedtype/one language short, hard-coding the seven-locale list into its new build script on the way. The rule was the defect, so no document states the list any more.Documentation only —
AGENTS.mdanddocs/DECISIONS.md. No app's i18n touched. Verified againstorigin/main=220f7e7on 2026-08-29.Wider than I first proposed
Two findings from bento-team-type, both of which I verified against the tree, changed the wording:
1. The list is three copies per app, not one. Catalogue file,
LOCALES, and any rig holding its own. "Point at the build script" is true and incomplete — it leaves the rig's copy stale, which is what goes red.2. The extra-file guard is not where it was believed to be.
LOCALESLOCALESOnly
build-i18n.mjscarries the guard (grep -c 'not listed in LOCALES'→ 1 for slides, 0 for spaces). On the others, adding a catalogue without touchingLOCALESexits 0 and silently never packs it — a translation that ships to nobody, announced by nothing. That is worse than a red build. Porting the guard is ops' job and is deliberately not done here.3. The right pattern already exists in this repo.
scripts/test-i18n-coverage.mjs:51derives the list by parsingPACKED_LOCALESout of the generatedpacked.ts, so it cannot disagree with the build. That makes #394's second hardcoded list a regression against an established shape rather than a novel problem — and it is what rule 6 now tells rigs to copy.ptis logged as an OPEN QUESTION, not settledarquivoficheirotelaguardarslides/src/i18n/pt.tsspaces/src/i18n/pt.tsSlides is Brazilian by declaration, spaces drifted European, both files correctly named
pt.ts— so every mechanical check passes while two apps speak different Portuguese to the same user. Pointing the docs atLOCALEScannot catch this, which is exactly why it is prose.I did not settle it. Settling means retranslating a catalogue — translation work and a maintainer's call. Slides also violates its own stated policy 10 times, so no app is clean. The entry records the three questions and one interim rule: a new catalogue for a language with regional variants states its variant in its header.
Recorded per the scribe bar: if you cannot find the evidence, write the entry as an open question rather than an assertion.
CLAUDE.mdis deliberately NOT in this PRIt carries the same stale
7 localesat lines 236–237. My harness forbids me editingCLAUDE.mdat another session's request — that is a config file governing agent behaviour, and a peer cannot authorise it. Proposed replacement, for the maintainer to apply:Everything after that line is unchanged.