8ebc1da9e4
- Astro statique, EN par defaut + /fr/ + /nl/, detection langue navigateur - i18n par fichiers JSON, ajouter une langue = ajouter des traductions - Contenu original porte a l'identique (diff d'inventaire par langue) - Chronologie legislative corrigee sur sources primaires (PE, Conseil, votes) - Timeline 23 precedents + observatoire 35 items + annuaire 66 outils FOSS, chaque affirmation verifiee et sourcee - Zero requete tierce (teste), lisible JS coupe, axe WCAG AA x2 themes - Version offline monofichier par langue a chaque build - Docker multi-stage vers nginx + CSP stricte auto-generee - CI GitHub Actions (SHA-pinnees) + verification hebdo des liens - CONTRIBUTING : divulgation d'affiliation obligatoire, allowlist de domaines testee en CI
159 lines
8.0 KiB
Markdown
159 lines
8.0 KiB
Markdown
# Content-migration diff report
|
||
|
||
Legacy monolith `index.html` (591 tri-lingual span lines / 659 `data-l` spans per
|
||
language) → per-locale MDX under `src/content/sections/{en,fr,nl}/` + `src/data/tools.json`.
|
||
|
||
## How the inventories were produced
|
||
|
||
- `legacy-<lang>.txt` — the FULL legacy document reduced to one language
|
||
(every `data-l` run resolved), one line of whitespace-collapsed text per
|
||
block-level element. Chrome (topbar, hero, status banner, TOC, footer) is
|
||
included so nothing is hidden from this audit.
|
||
- `built-<lang>.txt` — same dump algorithm over `dist/index.html`,
|
||
`dist/fr/index.html`, `dist/nl/index.html` after `pnpm build`.
|
||
One deviation: `<noscript>` is skipped because parse5 exposes its children
|
||
as raw text (it is new chrome, absent from the legacy page anyway).
|
||
- `<b class="lbl">` / `<b class="tool-label">` elements are flushed to their
|
||
own line on both sides so tool-card prose lines stay comparable.
|
||
- Non-breaking spaces are folded into plain spaces on both sides.
|
||
- `node migration/compare.mjs` then segments each file into
|
||
head-chrome / narrative window / tail-chrome (narrative = first `PART 00 ·`
|
||
line through the manifesto paragraph) and walks the two narrative windows
|
||
**in order, line by line**. Every line must either match exactly or fall in
|
||
one of the categories below; anything else exits non-zero.
|
||
|
||
## Result
|
||
|
||
| lang | legacy narrative lines | built narrative lines | unexplained differences |
|
||
| ---- | ---------------------- | --------------------- | ----------------------- |
|
||
| en | 789 | 991 | **0** |
|
||
| fr | 789 | 991 | **0** |
|
||
| nl | 789 | 991 | **0** |
|
||
|
||
`991 = 789 − 6 (deferred legislative rows) + 208 (tool-card labels)` in every
|
||
language. Full machine output: `compare-report.json`.
|
||
|
||
## Explained differences, exhaustively
|
||
|
||
### 1. Tool-card labels are now real text (+208 lines per language)
|
||
|
||
In the legacy page the field labels ("What it's for / Why it matters /
|
||
For whom & when", `À quoi ça sert / Pourquoi / Pour qui & quand`,
|
||
`Waarvoor dient het / …`) and the `Install & use` summary were **CSS
|
||
`::before`/`::after` generated content**, so they never appeared in the DOM
|
||
text. `ToolCard.astro` renders them as real, accessible text:
|
||
54 cards × 3 field labels + 46 install summaries = 208 new lines per language.
|
||
The label strings are byte-identical to the legacy CSS `content` values.
|
||
|
||
### 2. Deferred legislative-status claims (−6 lines per language)
|
||
|
||
Per the migration plan, adopted/extended claims are being rewritten from
|
||
verified sources separately. Dropped from the `#menace` comparison table
|
||
(rows 4 and 5), verbatim:
|
||
|
||
- EN: `Duration` / `Temporary, extended to 3 April 2028` / `Permanent` /
|
||
`Status (Jul 2026)` / `Adopted 9 July 2026` / `Under negotiation, 5th trilogue failed 29 June`
|
||
- FR: `Durée` / `Temporaire, prolongé jusqu'au 3 avril 2028` / `Permanent` /
|
||
`Statut (juil. 2026)` / `Adopté le 9 juillet 2026` / `En négociation, 5e trilogue échoué le 29 juin`
|
||
- NL: `Looptijd` / `Tijdelijk, verlengd tot 3 april 2028` / `Permanent` /
|
||
`Status (juli 2026)` / `Aangenomen op 9 juli 2026` / `In onderhandeling, 5e trialoog mislukt op 29 juni`
|
||
|
||
The status banner ("Dernière minute : 9 juillet 2026" block) was excluded
|
||
wholesale with the chrome (see §4); it is replaced by `StatusBanner.astro`
|
||
fed from verified sources in the parallel workstream.
|
||
|
||
Two borderline in-prose date claims were **kept** (judgment call — they are
|
||
narrative argument, not adopted/extended status): the 19 March 2026 joint
|
||
appeal, and the "kept scanning after the legal basis lapsed on 4 April 2026"
|
||
sentence, both in `#menace`.
|
||
|
||
### 3. Typographic quotes (smartypants)
|
||
|
||
Astro's default markdown pipeline (`markdown.smartypants`, ON by default)
|
||
typesets `"` as `“ ”` and `'` as `’` in the rendered pages
|
||
(en: 138 lines affected, fr: 225, nl: 70). No other smartypants rule fires:
|
||
the legacy prose contains no ASCII `...` or `--` (its 3 `…` are literal and
|
||
pass through unchanged). This is the **only character-level transformation**
|
||
in the entire narrative.
|
||
|
||
It could not be disabled from inside this migration's ownership
|
||
(`astro.config.mjs` is off-limits). If byte-identical glyphs are required,
|
||
the config owner can add `markdown: { smartypants: false }` — one line — and
|
||
the compare gate can then drop its quote normalization.
|
||
|
||
### 4. Chrome not migrated (rebuilt separately)
|
||
|
||
Legacy head-chrome (36 lines/language) and tail-chrome (8 lines/language)
|
||
deliberately not migrated to MDX:
|
||
|
||
- topbar: brand `◆ EXIT CHAT CONTROL`, FR/NL/EN buttons, theme toggle;
|
||
- hero: stamp (`Mass surveillance · EU · 2026`), eyebrow, `Exit Chat Control_`
|
||
h1, lede paragraph, three profile meta tags;
|
||
- status banner: `Breaking: 9 July 2026` + the vote paragraph
|
||
(superseded content, see §2);
|
||
- TOC (24 lines) — duplicates the section titles that ARE migrated;
|
||
- footer: Resources / Sources / Act link lists, GitHub link, disclaimer
|
||
(`Facts last updated: 9 July 2026`).
|
||
|
||
The built pages already contain replacement chrome from the parallel
|
||
rebuild workstream (TopBar/Footer/StatusBanner components, new hero h1 +
|
||
description, skip-link, noscript note, rewritten source lists citing
|
||
official roll-call results). That text intentionally differs from the
|
||
legacy chrome and is **not** part of this migration's fidelity claim; it
|
||
sits outside the compared narrative window (built head-chrome: 6 lines,
|
||
tail-chrome: 9 lines).
|
||
|
||
- The legacy inline JS (lang/theme toggles, simpleicons CDN loader) was not
|
||
migrated by design. Icon rendering will be rebuilt offline later; the
|
||
legacy CDN slugs are preserved in `tools.json.iconSlug` (validated, §6).
|
||
|
||
### 5. NL gaps
|
||
|
||
None. Every one of the 649 `data-l` runs carries all three languages
|
||
(en/fr/nl counts are equal in every run), so the EN-fallback path never
|
||
fired. `extract-log.json → nlGaps: []`.
|
||
|
||
### 6. tools.json notes (language-neutral facts)
|
||
|
||
- 54 entries; every entry has `url` (first neutral footer link), full `links`
|
||
array (21 cards have 2–3 links), `monogram`, `color`, `profiles`
|
||
(the 🟢🟡🔴 footer note), `level` where the legacy card carried a level tag
|
||
(34 cards; the other 20 never had one).
|
||
- `iconSlug` was validated against the installed `simple-icons` package.
|
||
Renamed upstream and mapped: `tutanota → tuta`, `aegis → aegisauthenticator`.
|
||
Removed upstream and therefore set to null (6): `briar`, `molly`, `ivpn`,
|
||
`protonpass`, `nostr`, `standardnotes`. 5 cards never had an icon in the
|
||
legacy map (`t-bitchat`, `t-databrokers`, `t-mailbox`, `t-website`,
|
||
`t-yunohost`).
|
||
- 7 cards have localized display names (e.g. `Firefox (durci/hardened/gehard)`,
|
||
`Sauvegardes chiffrées / Encrypted backups / Versleutelde back-ups`).
|
||
`tools.json.name` stores the EN plain text; the localized display name is
|
||
rendered through the ToolCard `name` slot from each locale's MDX.
|
||
- One presentational attribute dropped: `style="margin:.6rem 0 .4rem"` on the
|
||
warning box inside `t-bitchat` (styling is rebuilt later; text intact).
|
||
|
||
### 7. Anchors
|
||
|
||
`anchors.json` lists all 82 `id=` values of the legacy file. 78 exist in
|
||
every built page: 23 section ids on `<section>` wrappers, 54 tool ids on
|
||
ToolCard `<article>` roots, `top` on the hero h1. The 4 missing are the
|
||
legacy control-widget ids `lang-fr`, `lang-nl`, `lang-en`, `theme`
|
||
(toggle buttons, never used as link targets — chrome rebuilt separately).
|
||
|
||
### 8. External domains for the allowlist review
|
||
|
||
The migrated content links to 75 unique external hostnames
|
||
(`external-domains.txt`). The parallel workstream's
|
||
`tests/unit/dist-links.test.ts` fails until these are reviewed and added to
|
||
`src/data/domains-allowlist.json` — that file requires review and is outside
|
||
this migration's ownership, so it was left untouched.
|
||
|
||
## Reproduce
|
||
|
||
```
|
||
node migration/extract.mjs # MDX + tools.json + anchors + legacy dumps
|
||
pnpm build
|
||
node migration/extract.mjs --built # built-page dumps
|
||
node migration/compare.mjs # exits non-zero on any unexplained diff
|
||
```
|