ADR 008: Bilingual Structural Invariant — The Symmetry Guardrail
Status: Active Decider: Architecture Lead Date: 2026-04-20 (D045 — Diátaxis Migration)
Context
Zenzic.dev is a bilingual documentation site. English (docs/) is the
authoritative source; Italian (i18n/it/docusaurus-plugin-content-docs/current/)
is the translation mirror. Docusaurus's language switcher resolves Italian pages
by mirroring the English filesystem path: a user on
/docs/reference/finding-codes switches to /it/docs/reference/finding-codes —
and Docusaurus serves the file at the corresponding path in the i18n/it/ tree.
During the Diátaxis migration, 29 English files were renamed and moved to align with the four-quadrant structure. Several Italian files were not moved atomically in the same commit. The result: the language switcher produced 404 errors on pages where the English file had been moved but the Italian mirror had not.
This class of bug is particularly insidious because:
-
No build-time error is produced.
onBrokenLinks: 'throw'only detectsinternal
[text](link)references — it does not validate language switcher paths. -
The bug is invisible in development mode.
npm run startserves a singlelocale. The switcher is inactive. The 404 only appears in
just buildoutput when both locales are built simultaneously. -
The time-to-detection window is long. A missing IT file discovered three
commits after the EN rename requires a forensic git blame to trace — the coupling between the two moves is no longer visible in the history.
Decision
Every structural change to
docs/must be applied atomically toi18n/it/docusaurus-plugin-content-docs/current/in the same commit.
This is not a recommendation — it is a hard invariant. Three specific rules follow from it:
Rule 1 — Atomic Moves
Any file move or rename applied to a file in docs/ must be accompanied by a corresponding move or rename in the Italian mirror in the same commit.
Rule 2 — Slug Parity
If a slug: value is changed in an English file, it must be changed identically in the corresponding Italian file. A diverged slug: causes the language switcher to produce a 404.
Rule 3 — Symmetry Validation
Before committing any change that touches the filesystem structure, structural symmetry must be verified.
For step-by-step CLI commands and workflow details on how to perform the symmetry check, see the Bilingual Parity contribution checklist in the Release Protocol.
Rationale
1. Italian is a First-Class Citizen
The Italian documentation is not a secondary asset or a "nice to have". It is part of the Privacy Gate contract. A link that works in English but 404s in Italian is a structural failure of the documentation system — equivalent to a broken internal link in the English tree.
2. The Language Switcher Has No Safety Net
Docusaurus's onBrokenLinks: 'throw' does not cover language switcher paths.
This means the only safeguard is the contributor discipline enforced by this ADR.
There is no build-time backstop.
3. Git History Coherence
An atomic commit that moves both EN and IT files creates a coherent history unit: the rename is a single, reversible step. Split commits create history noise and make bisect unreliable when investigating regressions.
Invariants (Non-Negotiable)
-
The symmetry
diffcommand must exit 0 before any commit that modifies thefilesystem structure of
docs/ori18n/it/. -
New files added to
docs/must have a corresponding stub added toi18n/it/in the same commit — even if the Italian content is a copy of the English until a translation is provided.
-
The pre-commit hook (
pre-commit-config.yaml) enforces symmetry at the gate.Bypassing it with
--no-verifyon a structural commit is a Class 1 violation (Technical Debt).
Consequences
-
Every contributor who renames or moves a documentation file must be aware of
the Italian mirror — this is a non-optional part of the contribution workflow documented in
CONTRIBUTING.md. -
The
just lint-allrecipe (uvx pre-commit run --all-files) enforces thischeck in CI. A PR that breaks structural symmetry will fail at the gate.
-
The symmetry invariant applies to directory structure only. Italian
content may lag behind English during active development cycles, as long as the file is present (even as a stub). A 404 is worse than a stale translation.