fix(mindmap): #636 §2 — wire Virtues mindmap i18n for En/Ru/Pt/Es (defer Ar/Fa/Zh) - #665
Conversation
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
left a comment
There was a problem hiding this comment.
[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éTitleFrbrute, lesStaticConversionspeuvent 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 leDocumentLocalizationVirtue pour mapperTitleFr→TitleEn/Ru/Pt/Es+DescriptionFr→DescriptionEn/Ru/Pt/Esvianameof()(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)
…§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>
… 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>
… 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>
…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>
…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>
…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>
#636 §2 — Wire Virtues mindmap i18n for En/Ru/Pt/Es
Closes the mechanism gap behind #636 §2: Virtues mindmaps
en/pt/rushipped as byte-identical clones of the French (.content.svg/.links.svgshare 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 —
Virtuehas noTitleAr/Fa/Zhprops/ClassMap yet).Root cause
VirtueMindMapDocumentConfigdefault expressions referenced computed getters ({item.Title}→ hardcodedTitleFr), whichMindMapLocalization.StaticConversionscould not target → every language rendered FR.MindMapLocalizationVirtue entry was a stale stub only rewriting the root literal "Vertus", not the node text.Fix (mirrors the Fallacies wiring)
VirtueMindMapDocumentConfig.cs— 5 default expressions now reference raw FR-suffixed props ({item.TitleFr},{item.FamilyFr},{item.SubfamilyFr},{item.SubsubfamilyFr},HtmlEncode(item.DescriptionFr)) so per-languageStaticConversionscan rewrite them.AssetConverterConfig.cs— twoMindMapLocalizationVirtue blocks: title+description, and the family hierarchy (most-specific-first:SubsubfamilyFr→ thenSubfamilyFr→ thenFamilyFr→). Conversions only foren/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
.mmgeneration (node text), before SVG conversion, so fresh.mmprove the fix:.mmsizeBefore 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 supersededVirtueMindMapFRFrozenCharacterizationTests(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
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.Relates #636, #216, #664, #134.
🤖 Generated with Claude Code
Co-Authored-By: Claude Fable 5 noreply@anthropic.com