Skip to content

fix(mindmap): #636 §2 — wire Virtues mindmap i18n for En/Ru/Pt/Es (defer Ar/Fa/Zh) - #665

Merged
jsboige merged 1 commit into
masterfrom
fix/636-virtues-mindmap-i18n
Jul 3, 2026
Merged

fix(mindmap): #636 §2 — wire Virtues mindmap i18n for En/Ru/Pt/Es (defer Ar/Fa/Zh)#665
jsboige merged 1 commit into
masterfrom
fix/636-virtues-mindmap-i18n

Conversation

@jsboige

@jsboige jsboige commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

#636 §2 — Wire Virtues mindmap i18n for En/Ru/Pt/Es

Closes the mechanism gap behind #636 §2: Virtues mindmaps en/pt/ru shipped as byte-identical clones of the French (.content.svg/.links.svg share the FR SHA256 — the "EN" contained « Honnêteté intellectuelle » ×27, the "RU" had 0 Cyrillic). Same root cause family as #216 / #664 §1.

Decision (jsboige, interactive): wire the localization for En/Ru/Pt/Es (config-only, additive); defer Ar/Fa/Zh (they require entity extension — Virtue has no TitleAr/Fa/Zh props/ClassMap yet).

Root cause

  • Layer A (entity/expression): VirtueMindMapDocumentConfig default expressions referenced computed getters ({item.Title} → hardcoded TitleFr), which MindMapLocalization.StaticConversions could not target → every language rendered FR.
  • Layer B (config): the MindMapLocalization Virtue entry was a stale stub only rewriting the root literal "Vertus", not the node text.

Fix (mirrors the Fallacies wiring)

  1. VirtueMindMapDocumentConfig.cs — 5 default expressions now reference raw FR-suffixed props ({item.TitleFr}, {item.FamilyFr}, {item.SubfamilyFr}, {item.SubsubfamilyFr}, HtmlEncode(item.DescriptionFr)) so per-language StaticConversions can rewrite them.
  2. AssetConverterConfig.cs — two MindMapLocalization Virtue blocks: title+description, and the family hierarchy (most-specific-first: SubsubfamilyFr→ then SubfamilyFr→ then FamilyFr→). Conversions only for en/ru/pt/es (Ar/Fa/Zh absent → they fall back to FR = pre-existing deferred behavior, no regression). Stale "Vertus" stub removed.

Validation (end-to-end on fresh .mm, GUI-independent)

Localization is applied at .mm generation (node text), before SVG conversion, so fresh .mm prove the fix:

Lang .mm size Node text check
fr 161 623 B baseline
en 162 301 B "Valid argument", "Honest presentation", "Respectful language" — 0 French markers
ru 190 717 B 223 Cyrillic TEXT nodes ("Обоснованный аргумент", "Уместный аргумент"…)
pt 164 652 B "Rigor matemático", "Honestidade intelectual", "Respeito pela pessoa"
es 165 339 B "Exactitud numérica", "Honestidad intelectual", "Respeto de la persona"

Before the fix all four were 161 623 B (identical FR clones). Now each has distinct size + localized node text.

Tests

VirtueMindMapLocalizationTests (5 methods) replaces the superseded VirtueMindMapFRFrozenCharacterizationTests (per that file's own docstring instruction — the FR-frozen gap is now closed, so the characterization flips to the localized expectation rather than being silently dropped). Asserts: en/ru/pt/es expressions localize; ar/fa/zh stay FR; entries mirror the Fallacy tables (no "Vertus" stub); entity wires En/Ru/Pt/Es and defers Ar/Fa/Zh. 129 mindmap+localization tests pass, 0 fail.

Scope / follow-up

  • This PR = mechanism fix + tests only. The committed Virtue SVG assets (Cards/Fallacies/Mindmaps/{en,pt,ru}/) are not touched here — regenerating them as Batik SVGs requires a GUI-interactive FreeMind session (ai-01 desktop; XSLT fallback is proscribed per PR feat(mindmap): replace XSLT SVGs with FreeMind Batik SVGs + docs update #184). Asset regen tracked as the §2 follow-up.
  • Ar/Fa/Zh deferral tracked for a later entity-extension pass.

Relates #636, #216, #664, #134.

🤖 Generated with Claude Code

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Root cause (analogous to #216, documented in #601): the Virtues mind map
rendered French node text for every language because of a 2-layer gap —
Layer B, the MindMapLocalization Virtue entry was a stale stub only
rewriting the tree-root literal "Vertus"; Layer A, the document config
expressions referenced computed FR-only getters ({item.Text},
{item.Family}…) that StaticConversions could not target.

Fix (jsboige arbitration: wire the 4 languages whose data + entity
binding already exist; defer the 3 that need an entity extension):
- VirtueMindMapDocumentConfig: 5 expression defaults now reference the
  raw FR-suffixed props ({item.TitleFr}, {item.FamilyFr},
  {item.SubfamilyFr}, {item.SubsubfamilyFr}, item.DescriptionFr) so the
  StaticConversions can rewrite them per language. FR stays a no-op
  (Text => TitleFr).
- AssetConverterConfig.MindMapLocalization: replaced the "Vertus" stub
  with two per-field tables mirroring Fallacies (title/description +
  family hierarchy, most-specific-first), covering en/ru/pt/es only.
- Ar/Fa/Zh deferred: the Virtue entity has no Title/Family Ar/Fa/Zh
  property yet, so those three keep rendering FR (follow-up chantier).

Tests: replaced the #601 FR-frozen characterization guardrail (per its
own instruction to "flip these assertions to the localized expectation")
with VirtueMindMapLocalizationTests — pins localized en/ru/pt/es,
FR-frozen ar/fa/zh, the config-table shape, and the entity boundary.
129 mindmap+localization tests pass, 0 fail.

Code only; regenerated SVG assets follow in the same PR.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NanoClaw]

LGTM — fix(mindmap) #636 §2 — wire Virtues mindmap i18n for En/Ru/Pt/Es (defer Ar/Fa/Zh) (head ea3e670f, +258/-201, 4 fichiers). Firsthand au head :

Root cause confirmé et corrigé proprement : les mindmaps Virtues en/pt/ru étaient des clones byte-identiques du FR (« EN » contenait « Honnêteté intellectuelle » ×27, « RU » avait 0 cyrillique) parce que les expressions cibaient des accesseurs génériques ({item.Text}, {item.Family}) que la couche MindMapLocalization ne pouvait pas intercepter → toutes langues résolvaient en FR. Même famille racine que #216/#664 §1.

Mécanisme de fix sound (vérifié) :

  • VirtueMindMapDocumentConfig.cs : les expressions par défaut passent des accesseurs génériques aux propriétés source suffixées FR — {item.TitleFr}, {item.FamilyFr}, {item.SubfamilyFr}, {item.SubsubfamilyFr}. C'est le levier clé : en référençant la propriété TitleFr brute, les StaticConversions peuvent maintenant la réécrire par langue (TitleFr→TitleEn/Ru/Pt/Es). Commentaire honnête : « FR is a no-op (item.Text => TitleFr) ».
  • AssetConverterConfig.cs : étend le DocumentLocalization Virtue pour mapper TitleFrTitleEn/Ru/Pt/Es + DescriptionFrDescriptionEn/Ru/Pt/Es via nameof() (type-safe, refactor-safe). Ajoute un bloc pour la hiérarchie famille (Family/Subfamily/Subsubfamily) avec le même mapping, ordonné most-specific-first (sound — évite les partial-match sur noms courts comme substrings).
  • Conversion racine « Vertus »→« Virtues/Dobrodeteli/Virtudes/Virtudes » préservée.

Deferral Ar/Fa/Zh propre : ces langues ne sont pas dans les conversions Virtue (le bloc Fallacy juste au-dessus les inclut, mais Virtue non — car l'entité Virtue n'a pas de props TitleAr/Fa/Zh/ClassMap encore). Commentaire explicite : « Ar/Fa/Zh not yet mapped on the Virtue entity → deferred, render FR ». Pas de demi-wiring cassé — ils retombent sur FR proprement. Cela adresse directement mon concern #640 (passe native RU/AR avant merge) : AR est deferred ici, donc pas de contenu AR à vérifier ce cycle.

Test structuré : remplace VirtueMindMapFRFrozenCharacterizationTests.cs (-193, FR-only frozen) par VirtueMindMapLocalizationTests.cs (+231) — le bon move structurel (tester la localisation distincte, pas le freeze FR).

△ Caveat honnête (même discipline que #640) : la qualité des chaînes cyrilliques RU reste du ressort native-reader — je ne peux pas juger la justesse sémantique du russe. Mais le mécanisme de wiring (mapping TitleFr→TitleRu) est vérifié sound, et c'est le scope de ce PR (i18n mechanism gap, pas qualité de traduction). Si une passe native RU est requise, c'est sur les données CSV + le rendu généré, pas sur ce diff de wiring.

— NanoClaw (myia-ai-01) — LGTM (wiring mechanism sound, AR deferred cleanly, family partial-match ordering handled)

@jsboige
jsboige merged commit 27442ad into master Jul 3, 2026
3 checks passed
@jsboige
jsboige deleted the fix/636-virtues-mindmap-i18n branch July 3, 2026 17:10
jsboige added a commit that referenced this pull request Jul 5, 2026
…§2) (#686)

Regenerate Virtues mindmap SVGs via FreeMind GUI export (native Batik, not XSLT).

Root cause of the prior intermittent XSLT-fallback identified and confirmed live:
a window flashing / stealing foreground during the ~15-20s SendKeys menu navigation
makes the keystrokes land on the map canvas instead of the File -> Export -> SVG menu
(map title goes to "*", SVG never appears, code falls back to the proscribed XSLT path).
Run with a stable interactive foreground (RDP kept quiet) -> 8/8 languages exported as
real Batik, 0 XSLT fallback, EXIT=0.

Committed (verified genuinely localized: distinct SHA256, ru Cyrillic + es Spanish confirmed):
- fr/en/ru/pt content.svg + links.svg - refreshed (content changed vs the April 2026
  generation, picks up post-#665 taxonomy/i18n edits)
- es content.svg + links.svg - new (es Virtues mindmap was previously absent from the repo)

Held (NOT committed): ar/fa/zh - regeneration produced FR-clone content (content.svg
byte-identical to fr, SHA256 a640731217061be2) because the Virtues mindmap i18n is not
wired for those 3 languages (deferred #665 entity extension). Shipping them would
mislabel French content as ar/fa/zh.

HTML wrappers intentionally out of scope (lang-neutral generic shell; localization
mechanism to be reviewed separately). SVG header format (UTF-8 BOM + utf-16 decl) is the
established pipeline output, identical to the committed April SVGs - not a regression.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jul 5, 2026
… rendering French) (#715)

The Virtues mind map rendered French node text for ar/fa/zh because the
localization was only half-wired. #636 §2 wired en/ru/pt/es and deferred the
ar/fa/zh trio pending a Virtue entity extension. #686's PR body claimed the
ar/fa/zh wiring (commit c2e51192) but it never landed on master: HEAD:Virtue.cs
had 0 ar/fa/zh properties, the MindMapLocalization Virtue blocks listed only
en/ru/pt/es, and the code comment still read "Ar/Fa/Zh not yet mapped ... render FR".

This completes the two-layer wiring, mirroring the working Fallacy pattern:
- Layer A (entity): Virtue.cs gains Title/Description/Remark/Link/Family/
  Subfamily/Subsubfamily x Ar/Fa/Zh properties + ClassMap .Optional() bindings
  to the CSV *_ar/_fa/_zh columns (already fully translated, 223/223 native script).
- Layer B (config): the two Virtue MindMapLocalization tables now carry ar/fa/zh
  entries, so {item.TitleFr} -> {item.TitleAr/Fa/Zh} etc. for all 8 languages.

Tests:
- Flipped the #636 §2 deferral guardrail (VirtueMindMapLocalizationTests) in place
  to the completed wired-all-8 contract, per its own explicit instruction.
- Added VirtueMindMap_GeneratesNativeScript_ForArFaZh: generates a real .mm from the
  taxonomy CSV (headless, FreeMind GUI disabled) and asserts the Arabic/Persian/CJK
  Unicode block is present in node text - the regression that would have caught
  "Virtues mind maps in French instead of the target languages".

Full suite: 587 pass / 1 known-fail (#133 OWL round-trip, pre-existing) / 5 skip.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jul 6, 2026
… CS8603 in MmGeneratorTests) (#726)

Re-verification of the #710 nullable-cleanup baseline on master 9f52446 (dispatch h2utyb idle-de-
secours: "CS warnings beyond #710's 96"). Found +2 raw warnings = 1 new DISTINCT nullable-flow
warning introduced by PR #715 (fix #665 Virtue ar/fa/zh localization, commit 699580a).

Drift: MmGeneratorTests.cs:281 CS8603 (possible-null return). #715 added a CSV path-finder helper
(walks 12 parent dirs for Argumentum Virtues - Taxonomy.csv, returns null at line 281 if not found);
method returns non-nullable string → CS8603. Confirmed by git blame (lines 274-282 all = 699580a)
and diff vs 34c7702 (helper absent at #710 base — those lines held a FamilleExpression assertion).

MmGeneratorTests.cs: was 6 warnings (#710 top-8), now 7 raw (3 pre-existing CS8602 + 1 new CS8603).
Main converter project stays 0 CS (zero-warning, #587). Distinct-warnings on 9f52446 = 49; raw/echo
factor consistent across both measurements (96→98 = apples-to-apples raw-line count).

Impact on the plan: negligible — new warning is in Slice C scope (CS86xx nullable-flow),
MmGeneratorTests.cs already in §1 top-8. Post-tag Slice C file-by-file pass picks it up; no slice
re-scoping. Fix is low-risk: helper legitimately returns null → string? return type is the honest
annotation.

Read-only: 0 code change, 0 Cards/ write, 0 build mutation. Reproducible via dotnet build Tests.csproj
--no-incremental on 9f52446. Keeps the #710 baseline current so the post-tag lane runs against an
accurate inventory (96→98, +1 distinct).

Dispatch h2utyb (idle-de-secours). Base 9f52446.

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude-Code <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jul 6, 2026
…s + #715 CS8603 (4 warnings) (#730)

Second sub-lot of Slice C (CS86xx nullable-flow) of the #710 nullable-cleanup plan
(dispatch x0ykyn PRIMARY; follows Slice A #727, Slice B #728, Slice C-1 #729).

This sub-lot closes the dispatch's explicit ask — "corrige le CS8603 de #715" — by fixing all
4 CS86xx in MmGeneratorTests.cs (the mindmap-generation test fixture), including the CS8603 that
#715 (commit 699580a, #665 Virtue ar/fa/zh loc) introduced at L281 (documented in the #726 drift
note as the 96→98 regression). The file is test-only and exercises the real mindmap-generation
code path (FallacyMindMapDocumentConfig / VirtueMindMapDocumentConfig via FreeMindPath="" headless).

Fixes (4 warnings, all low-risk post-assert suppression or honest nullable return):

- L86  CS8602 `xmlDoc.Root!.Name.LocalName` — XDocument.Parse of the test's well-formed .mm yields
       a non-null Root; the `!` documents that invariant. (No prior Root assert, hence the `!`.)
- L138 CS8602 `xmlDoc.Root!.Element("node")!.Elements("node")` — both derefs are guarded by the
       two FluentAssertions `NotBeNull` on the immediately preceding lines (L136 Root, L137 node).
- L176 CS8602 `xmlDoc.Root!.Element("node")!.Elements("node")` — same pattern, guarded by L174+L175.
- L273/281 CS8603 `private static string? FindRepoVirtuesCsv()` returning `null` — the #715 path-finder
       helper legitimately returns null when the Virtues taxonomy CSV is not found walking up from
       the bin dir. `string?` is the honest return type. The sole caller (L299) asserts
       `csvPath.Should().NotBeNull(...)` on L300 before passing it to LoadVirtuesFromPathAsync on L302;
       `csvPath!` there acknowledges that assertion (the compiler can't track FluentAssertions).

#715 CS8603 root cause (code=truth): git blame L274-282 = 699580a (#715); the helper was added to
locate the committed Virtues CSV for the new native-script ar/fa/zh test, declared `string` (non-null)
with a `return null;` fallback — a classic CS8618/CS8630-class mismatch the #710 sweep now catches.

DoD (measured on this branch, base master 240511c):
- dotnet build Tests.csproj --no-incremental: MmGeneratorTests emits 0 CS86xx (4→0). 0 errors.
- dotnet test --filter MmGeneratorTests: 11/11 pass (incl. the 3 ar/fa/zh InlineData #715 cases).
- dotnet test (full): 587 pass / 1 fail (OWL #133 permanent) / 5 skip (#719). 0 regression.

CsvHelper safety (#710 §3): NOT IN SCOPE — MmGeneratorTests exercises the mindmap-generation path
(.mm XML via XDocument), not the CsvHelper CSV load path. The mapping-risk suites are untouched.

Slice C remaining: 15 distinct CS86xx across ~11 files (CsvGridConversion, SvgConversion×2,
SvgDisambiguation, SvgPostProcessing, OwlE2E, FallacyLinkFallback×3, LoggerMarkup,
UtilityExtensions, PKHierarchical, ImageFileGenerator×2, SimpleImageGenerator). Follow in
subsequent sub-lots.

Base 240511c. 0 Cards/ write, 0 rendering code change.

Dispatch x0ykyn (PRIMARY, Slice C-2 — closes the #715 CS8603 call-out). Base 240511c.

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude-Code <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jul 7, 2026
…e-file diagnosis (#738)

Issue #725 reported Argumentation_Virtues_{lang}.html wrappers inlining the FR
mind-map SVG in every language. Investigation on master 6ce91ef proves this is
a STALE-FILE artifact, not a code bug:

- GenerateHtmlSvgWrappers inlines the post-localization content.svg (the
  svgLoader produced after UpdateSvgWithItems), never the raw FreeMind render.
  #725's "inlines the raw FR svg" hypothesis is wrong on the mechanism.
- The committed wrappers date 2026-05-24 (df3c769, #312), BEFORE the Virtues
  i18n wiring (27442ad, #665). They were generated FR because content.svg was
  FR-frozen at the time; they were never regenerated since.
- content.svg is now localized for all 8 langs (204adc4, #686 post #665/#715/
  #724): Cyrillic=40066 (ru), CJK=10189 (zh), Arabic=23980 (ar), =25576 (fa),
  "Intellectual honesty" x28 (en). The wrapper just wasn't regenerated with it.
- Fallacies uses the identical assembly path and its wrapper IS localized
  (EN-hits=188) -> the assembly code is correct.
- Operational root cause: OverwriteExistingHtmlMaps defaults to false while
  OverwriteExistingDocs=true, so SVG regens clobber content.svg but skip the
  existing .html wrappers.

Fix = post-tag wrapper regen with OverwriteExistingHtmlMaps=true (po-2023 lane,
RDP/FreeMind-gated). This tick's gated, regen-free deliverable:

- CI regression test VirtuesMindmapWrapperLocalizationTests (headless, no
  Playwright) mirroring VisualTests/MindmapWrapperTests for Fallacies. Theory
  over fr/en/ru/zh/ar/fa asserts the wrapper assembled from the committed
  localized content.svg matches the target language (native script / EN label
  present, "Honnêteté intellectuelle" FR-frozen marker absent for non-FR).
- Investigation doc documenting the 4-source proof + post-tag action.

0 write Cards/, 0 regen, 0 CSV/DB/OWL. Empirical dotnet test: 594/1/5 (+7 vs
587/1/5 baseline, 0 regression; the 1 fail is the permanent OWL #133 known-fail).

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude-Code <noreply@anthropic.com>
jsboige added a commit that referenced this pull request Jul 28, 2026
…follow-up) (#962)

The release-gate dossier carried six facts measured stale against master
3094d42. All are mechanical/premise drift from July merges — no verdict,
no release scope changed. This pass corrects the dossier body that #959
(header/§0) deliberately left untouched.

1. §3.2 Virtues .content.svg were marked FR-figé ("gap structural"). FALSE:
   Argumentum_Virtues_MindMap_{lang}.content.svg are native-script 8/8,
   committed via #665/#715/#724/#686 (9f52446). Distinct-size proof
   (git cat-file -s): fr 431931 / en 418954 / ru 485254 / pt 446948 /
   es 432142 / ar 461859 / fa 461654 / zh 1148677 — a FR clone would be
   ~431931 everywhere. Twin premise of #636 (CLOSED 2026-07-06), false for
   the same reason. Marked RÉSOLU.

2. §3.2 es/ar/fa/zh mindmap SVG count 3 → 5 each (git ls-files | wc -l).
   fr 6 / en 5 / ru 5 / pt 5 / es 5 / ar 5 / fa 5 / zh 5.

3. §4 tests 596/601 → 643/638/0/5 (CI run 30280070312, both matrix legs),
   aligning with §0/#959. The 596/601 was pre-#911 (Test step was a no-op).

4. §4 Magick.NET 14.14.0 → 14.15.0 (#871 6f1a6e1a, 5 advisories patched).
   Also adds AutoMapper 14.0.0 (#588) and PdfPig 0.1.14 official (#908).

5. §3.6 + §5.8 + §7 + §8.2(c) "PT titre English Channel — open finding,
   appel à décision" → RÉSOLU. git grep "English Channel" -- Cards/ = 0.
   Per ai-01 precision: the string lived in an EMBEDDED csv key that is
   IGNORED at runtime (HarvestManager.cs overwrites it with the real CSV),
   so the defect never reached a card — NOT "resolved by #803". The
   observed mistranslation was stale-harvest, not a live prod defect.
   Separated from PT row-1 cover contamination (#306, distinct, also closed).

6. §5.4(a) + §8.2(a) #636 "arbitrage ouvert" → CLOSED 2026-07-06 (twin
   premise of #1).

Every value above is re-read at source (git ls-files / cat-file -s / grep /
gh issue view), not taken from an intermediate report. 3 audit-probe
imperfections (Fallacies/Scenarii counts grabbed Archive/2022; skos:prefLabel
grep namespace-split) are documented honestly in the audit report, not masked.

Scope: 1 docs file, docs-only, 0 prod write, 0 OWL, 0 CSV. Correction PR,
decision to merge = ai-01 (pre-tag sensitive zone, #134 gate).

Audit report: docs/investigations/2026-07-28-release-validation-v0.9.0-audit.md
(landed in #961). This PR is the body-correction follow-up ai-01 gave GO on
(arbitrage qgsvq4, 2 precisions applied: "n'a jamais atteint une carte"
phrasing + PT vs EN distinct #306).

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude-Code <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants