ADR 008: Bilingual Structural Invariant — The Symmetry Guardrail
Status: Active Decider: Architecture Lead Date: 2026-04-20 (v0.7.0 sprint, 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 v0.7.0 Diátaxis migration (D045), 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 git mv applied to a file in docs/ must be accompanied by a corresponding
git mv in the Italian mirror in the same commit. A rename in English is a
rename in Italian.
# Correct — both moves in one commit
git mv docs/guides/intro.mdx docs/tutorials/intro.mdx
git mv i18n/it/docusaurus-plugin-content-docs/current/guides/intro.mdx \
i18n/it/docusaurus-plugin-content-docs/current/tutorials/intro.mdx
git commit -m "refactor(docs): move intro to tutorials quadrant (EN + IT)"
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, with no build-time warning.
Rule 3 — Symmetry Validation Before Every Commit
Before committing any change that touches the filesystem structure (renames, additions, deletions), the following command must exit 0:
diff \
<(find docs -name "*.mdx" | sed 's|^docs/||' | sort) \
<(find i18n/it/docusaurus-plugin-content-docs/current \
-name "*.mdx" | \
sed 's|^i18n/it/docusaurus-plugin-content-docs/current/||' | sort)
Any output from this command represents a structural asymmetry that will produce a 404 on the Italian language switcher.
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 Safe Harbor 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 operation. 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 preflightrecipe (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 sprints, as long as the file is present (even as a stub). A 404 is worse than a stale translation.