fix(docs): restore pt-br diacritics and enforce locale content integrity - #523
Conversation
GEN-002 has always required correct diacritics ("DO use correct
diacritical marks in Portuguese -- `não` not `nao`"), but nothing
enforced it: the companion rules checked only structure (page parity,
translation drift, link prefixes). Six pt-br pages sat in main with
their diacritics stripped, and a seventh had a corrupted frontmatter
description.
The nb locale hit the identical failure in #384, where ~500 occurrences
across 35 files needed two manual passes -- the second pass caught four
cases the first missed. Manual review is not a reliable detector here.
Content fixes:
- restore diacritics across 6 pt-br/examples pages (prose, headings and
frontmatter descriptions; code blocks and identifiers untouched)
- fix the stripped frontmatter description in max-file-length.mdx
New GEN-002 rules:
- i18n-encoding-corruption: rejects accented characters written as HTML
entities and double-encoded UTF-8. Detection requires a 0xC2/0xC3 lead
byte followed by a 0x80-0xBF continuation byte, so legitimate uppercase
Portuguese (where U+00C3 precedes an ASCII letter) is not flagged.
- i18n-diacritic-density: measures accented characters per 1000 prose
letters per locale, ignoring fenced and inline code, and fails a page
below the locale minimum.
Thresholds come from the corpus: healthy minimums are nb 5.9 and pt-br
15.2 per 1000; stripped pages measured 0.0-1.1. Limits are nb 2 and
pt-br 5, sitting between the bands.
A whole-file "has at least one diacritic" check was rejected as too weak
-- measured against the corrupt files it caught 1 of 6, because a single
accented character anywhere, including inside a code sample, defeats it.
Accented characters in the rules file are expressed as numeric code
points, never literals, so the check cannot be broken by the corruption
it detects.
The density rule is a bulk-stripping detector, not a spell checker: it
does not catch isolated stripped words in otherwise-correct prose, and
skips pages under 200 prose letters. Both limits are documented in the
ADR as review responsibilities.
Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Both are agent working process, so no mechanism can carry them. Every other learning from this branch already has a home: the code-point idiom lives in a comment in the rules file, and the density-over-word-list choice with its limits is documented in GEN-002's Compliance section. - A review agent's verdict on non-English prose is worthless and it fabricates the supporting detail. The orthography pass over the pt-br docs returned PASS while asserting accents the words do not contain. The existing "grep the quoted string" remedy does not apply to a claim about meaning, so the entry names the mechanical substitutes instead. - Reproduce a described failure before scheduling work from it, and prove a zero result is a real zero. Two of three audit-derived issues collapsed to no work once tested, and a `\b` inside a JS template literal is a backspace, which hid 69 real occurrences behind a confident zero. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
|
Warning Review limit reached
Next review available in: 41 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying archgate-cli with
|
| Latest commit: |
1c6b34e
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://2a4042fe.archgate-cli.pages.dev |
| Branch Preview URL: | https://fix-ptbr-diacritics-i18n-con.archgate-cli.pages.dev |
Code Coverage
Full HTML report available in workflow artifacts. Per-directory breakdown
|
rhuanbarreto
left a comment
There was a problem hiding this comment.
Review summary
(Posted as COMMENT because GitHub forbids REQUEST_CHANGES on one's own PR — treat this as a request-changes review.)
The approach is right: measured thresholds instead of guessed ones, corruption-proof numeric code points in the rules file, and an honest "Limits of Automated Enforcement" section. Content restoration spot-checks clean — diacritics are correct, including both crasis cases (leva à divergência, acesso direto à API) and the correct non-crasis before bare plurals (sensibilidade a maiúsculas).
One confirmed bug blocks merge: ENTITY_PATTERN misses á, é, ó — the entities for á/é/ó, the three most common Portuguese acute vowels. Verified empirically (stateless .match, same flags as the rule). Details and a committable fix on the inline thread.
The other three threads are optional: a comment documenting the cp1252 gap in the mojibake heuristic, a scope note about the corruption rule scanning fenced code, and a native-speaker orthography call on não-produção.
Everything else — density rule, mojibake detection, ADR updates, memory entries — is sound and verified. Approve once the entity pattern is fixed and fire-tested with é.
ENTITY_PATTERN factored the vowel out of each entity name, so a branch spelled `cute` could never match `á`: after `(?:a|A)` consumed the vowel, the remainder was `acute;`. That silently dropped seven entities, including the three most common Portuguese acute vowels, plus `Æ`, whose canonical capital E the `(?:a|A)elig` branch cannot produce. Replaced with one branch per entity name, so every name is independently greppable and the mis-factoring cannot recur. Verified by extracting the pattern from the source: 29/29 accented entities matched, and none of `< > & " ´ ©`. The standalone `´` stays excluded -- U+00B4 is a bare mark, not an accented letter, and the numeric 192-255 range excludes it too. The original fire-test passed because it injected `å`, which lands on a working branch. Both directions were covered but not every branch. Also from review: - document why the mojibake bound stops at 0xBF instead of covering Windows-1252, which remaps 0x80-0x9F and would need a wider range that false-positives on 0xC3 followed by NBSP or an ordinal indicator - document that i18n-encoding-corruption scans fenced code while i18n-diacritic-density strips it, so a page demonstrating entity escapes would be flagged - document that neither rule judges whether an accent is the correct one - reword `código de não-produção` to `o código que não é de produção`, sidestepping post-1990 hyphenation ambiguity rather than guessing The Windows-1252 rationale went into the ADR rather than the comment block: inlining it pushed the block to 10 prose lines against GEN-004's limit of 5, which the check caught. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
# archgate ## [0.51.0](v0.50.0...v0.51.0) (2026-07-26) ### Features * **adrs:** enforce concise, forward-only code comments (GEN-004) ([#496](#496)) ([9a114b3](9a114b3)), references [#2123](https://github.com/archgate/cli/issues/2123) * **adrs:** flag stray files at the repository root (GEN-005) ([#535](#535)) ([6a6e765](6a6e765)), closes [#514](#514), references [#500](#500) * **engine:** add ctx.readYAML and ctx.checkCase rule helpers ([#497](#497)) ([c5d82c5](c5d82c5)), closes [#490](#490), references [#490](#490) [#491](#491) [#499](#499) [#499](#499) [#499](#499) [#499](#499) * report truncated ADR briefings, trim the ADR corpus 15.6%, add GEN-005 briefing budget ([#501](#501)) ([a9dab40](a9dab40)) ### Bug Fixes * **docs:** relocate ADR content to clear briefing-budget warnings ([#531](#531)) ([c7419b3](c7419b3)) * **docs:** restore pt-br diacritics and enforce locale content integrity ([#523](#523)) ([db39104](db39104)), closes [#516](#516), references [#231](#231) * **engine:** allow symlinks that resolve inside the project root ([#500](#500)) ([387bf15](387bf15)) * **engine:** reject rule-file reads through a symlinked ancestor directory ([#499](#499)) ([a555f9d](a555f9d)), references [#497](#497) [#491](#491) [#497](#497) [#497](#497) [#497](#497) [#497](#497) * **engine:** scan top-level export declarations with a null source ([#493](#493)) ([d07db03](d07db03)), closes [#491](#491) * **engine:** stop dropping AST nodes with exotic literal values ([#494](#494)) ([0015542](0015542)), closes [#493](#493) [#493](#493) * **lint:** resolve no-bare-env-restore by captured key and lexical scope ([#524](#524)) ([7094a3a](7094a3a)), closes [#498](#498) * **rules:** make ARCH-020 and ARCH-023 match ctx.ast() instead of raw text ([#533](#533)) ([ad5529b](ad5529b)), closes [#513](#513), references [#486](#486) * **tests:** replace bun:test anti-patterns with idiomatic patterns ([#512](#512)) ([bcb086f](bcb086f)) --- This PR was generated with [simple-release](https://github.com/TrigenSoftware/simple-release). <details> <summary>📄 Cheatsheet</summary> <br> You can configure the bot's behavior through a pull request comment using the `!simple-release/set-options` command. ### Command Format ````md !simple-release/set-options ```json { "bump": {}, "publish": {} } ``` ```` ### Useful Parameters #### Bump | Parameter | Type | Description | |-----------|------|-------------| | `version` | `string` | Force set specific version | | `as` | `'major' \| 'minor' \| 'patch' \| 'prerelease'` | Release type | | `prerelease` | `string` | Pre-release identifier (e.g., "alpha", "beta") | | `firstRelease` | `boolean` | Whether this is the first release | | `skip` | `boolean` | Skip version bump | | `byProject` | `Record<string, object>` | Per-project bump options for monorepos | #### Publish | Parameter | Type | Description | |-----------|------|-------------| | `skip` | `boolean` | Skip publishing | | `access` | `'public' \| 'restricted'` | Package access level | | `tag` | `string` | Tag for npm publication | ### Usage Examples #### Force specific version ````md !simple-release/set-options ```json { "bump": { "version": "2.0.0" } } ``` ```` #### Force major bump ````md !simple-release/set-options ```json { "bump": { "as": "major" } } ``` ```` #### Create alpha pre-release ````md !simple-release/set-options ```json { "bump": { "prerelease": "alpha" } } ``` ```` #### Publish with specific access and tag ````md !simple-release/set-options ```json { "bump": { "prerelease": "beta" }, "publish": { "access": "public", "tag": "beta" } } ``` ```` ### Custom Changelog Preamble You can add custom markdown to the top of the changelog (right after the version header) using the `!simple-release/set-preamble` command. The markdown after the command line becomes the preamble. ```md !simple-release/set-preamble ## What's new? - The website was completely redesigned - The new API gives you awesome possibilities ``` In a monorepo, pass the full package name after the command to target a single package's changelog. Wrap the name in backticks so GitHub keeps it as text instead of a mention: ```md !simple-release/set-preamble `@your-org/core` ## Core changes - New plugin system ``` Use one comment per package, plus one without a name for the whole release. ### Access Restrictions The commands can only be used by users with permissions: - repository owner - organization member - collaborator ### Notes - The last comment with `!simple-release/set-options` command takes priority - The last `!simple-release/set-preamble` comment per package takes priority - JSON must be valid, otherwise the `set-options` command will be ignored - Parameters apply only to the current release execution - The commands can be updated by editing the comment or adding a new one </details> <!-- Please do not edit this comment. simple-release-pull-request: true simple-release-branch-from: release simple-release-branch-to: main --> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Closes #516.
The gap was live, not hypothetical
GEN-002 has always required correct diacritics — "DO use correct diacritical marks in Portuguese —
nãonotnao,códigonotcodigo" — but nothing enforced it. The companion rules checked only structure: page parity, translation drift, link prefixes. So sixpt-brpages sat inmainwith their diacritics stripped, plus a seventh with a corrupted frontmatterdescription.nbhit the identical failure in #384: ~500 occurrences across 35 files, fixed in two manual passes, where the second pass caught four cases the first missed. Manual review is not a reliable detector for this.Content
Diacritics restored across seven
pt-br/examplespages — prose, headings, and frontmatter descriptions. Verified mechanically: 0 stripped forms remain, and fenced code blocks are byte-identical tomainin all seven files, so no identifier, command, or path was touched.Rules
Two additions to
GEN-002-docs-i18n.rules.ts, botherror:i18n-encoding-corruption— accented characters written as HTML entities (å,ç) or as double-encoded UTF-8. Detection requires a0xC2/0xC3lead byte followed by a0x80–0xBFcontinuation byte. A bare lead-byte scan would flag legitimate uppercase Portuguese, whereÃprecedes an ASCII letter —ÃOalready occurs twice in this tree.i18n-diacritic-density— accented characters per 1000 prose letters per locale, ignoring fenced and inline code.Thresholds come from measuring the corpus, not from taste:
nbpt-brA whole-file "has at least one diacritic" check was tried and rejected. Measured against the six corrupt files it caught one:
wrapper-enforcement.mdxwas fully stripped in prose but containedNãoinside a code sample, which defeats it. Density caught five of six, with a 14× gap between the bands.Accented characters in the rules file are numeric code-point sets, never literals, so the check cannot be broken by the corruption it detects.
Documented limits
i18n-diacritic-densityis a bulk-stripping detector, not a spell checker. It does not catch isolated stripped words in otherwise-correct prose —max-file-length.mdxscored a healthy 26.6 while its frontmatter was stripped, and only a word-level scan found it — and it skips pages under 200 prose letters. Both limits are written into GEN-002's Compliance section as review responsibilities rather than left implicit.Verification
bun run validategreen: 1675 tests, 49/49 rules, build clean. Fire-tested both directions:mainåinjectedøinjectedVALIDAÇÃO COMPLETAinpt-brReview request
Please read the Portuguese as a native speaker. The automated checks count accents; they cannot tell a correct accent from a confidently wrong one.
àversusa(crasis) andéversuseare the places to look — I added several of each. An orthography review agent returned PASS here, but its per-word annotations were fabricated, so its verdict carries no weight.