Skip to content

test(virtue): #499 VirtueClassMap regression via LoadFromContent (5 tests) - #559

Merged
jsboige merged 2 commits into
masterfrom
test/virtue-classmap-regression
Jun 20, 2026
Merged

test(virtue): #499 VirtueClassMap regression via LoadFromContent (5 tests)#559
jsboige merged 2 commits into
masterfrom
test/virtue-classmap-regression

Conversation

@jsboige

@jsboige jsboige commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

What

Add VirtueClassMapRegressionTests5 contract tests for the remaining uncovered production entity ClassMap (Virtue, the #499 scale-up taxonomy entity, 223 nodes / 194 leaves). Companion to FallacyClassMapRegressionTests and EntityClassMapRegressionTests. Additive only, no production code change. Full suite 422/0/5.

This is the ai-01 "couverture tests" runway (continued after #558).

Why

The CsvHelper ClassMap regression is a documented recurring silent-failure source (CLAUDE.md "CsvHelper Mapping" + the #216/#477 localization-mapping regression). 7 production ClassMaps exist; before this PR, Virtue had zero coverage (alongside TestFallacyCard, which is visual-test-only and lower-stakes). Virtue is the entity for the active #499 scale-up lane — a ClassMap drift here = silent data loss on Virtue generation, with no signal until a card renders empty.

VirtueClassMap declares 16 required FR columns (non-Optional) + 28 localized columns (en/ru/pt/es × 7) all .Optional(). The contract that must hold:

  1. Required FR columns resolve — else silent null properties.
  2. Optional columns may be absent without throwing — else HeaderValidated throws when a FR-only header set loads (breaks the multilingual harvest).
  3. The double map pkId AND PkGetId() returns Id; if either binding drops, GetId() returns null and any keyed generation pass breaks.

The 5 tests (VirtueClassMapRegressionTests)

Test What it pins
MapsRequiredColumns All 16 required FR columns map to their properties (incl. Depth int parse)
PkPopulatesBothIdAndPk pk column → Id + Pk; GetId() resolves (the silent-failure guard)
OptionalLocalizedColumnsAbsent_DoesNotThrow 28 optional columns absent → loads clean, properties null
OptionalLocalizedColumnsPresent_MapsThem Optional = "may be absent", not "ignored when present"
RequiredColumnAbsent_Throws A required FR column drift fails LOUD (HeaderValidationException), not silent

All via the real load path CsvBase<T,TMap>.LoadFromContent, inline CSV (no external fixture files), self-contained.

Verification

  • New tests: 5/5 pass.
  • Full suite: 422 passed / 0 failed / 5 skipped — no regression (baseline 417 + 5 new).
  • Build: 0 errors.
  • No production code touched — pure additive coverage.

Related

🤖 Generated with Claude Code

Your and others added 2 commits June 20, 2026 09:30
…scovery

Pin the 8 per-language LinkXxFallback cascades on Fallacy (Fr/En = 2-deep,
Ru/Pt/Es/Ar/Fa/Zh = 3-deep: target → En → Fr), the mind-map link resolution that
feeds FallacyMindMapDocumentConfig.LinkExpression ({item.LinkFrFallback}) and is
referenced — but NOT behavior-pinned — by MmGeneratorTests and
MindMapLocalizationRegressionTests.

29 contract tests (3 Fr + 2 En + 6×4 Theory for non-source languages) via reflection
helpers so one Theory covers all 6 languages uniformly.

Discovery surfaced by the tests: the cascade floor is NULL, not string.Empty — when
all three link sources are null, the expression returns null (not ""), which propagates
into the Mustache template as empty text but is null to any C# consumer. A silent-
wrong-output hazard documented explicitly (7 of the initial assertions had to flip from
BeEmpty to BeNull — the test now pins the REAL contract).

This is the ai-01 "couverture tests" runway. No production code change — additive tests
only. Full suite green (417/0/5, baseline 388 + 29 new).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ests)

Add VirtueClassMapRegressionTests — the remaining uncovered production entity
ClassMap (Virtue, the #499 scale-up taxonomy entity, 223 nodes / 194 leaves).
Companion to FallacyClassMapRegressionTests and EntityClassMapRegressionTests.

5 contract tests via the real load path CsvBase<T,TMap>.LoadFromContent:
- MapsRequiredColumns: 16 required FR columns (pk, path, depth, decimal_path_padded,
  family_fr, subfamily_fr, subsubfamily_fr, title_fr, description_fr, remark_fr,
  link_fr, family_fr_camelcase, depth_max4, card, update, locked) all resolve.
- PkPopulatesBothIdAndPk: the double map pk → Id AND Pk, so GetId() resolves
  (silent-failure source if either binding drops).
- OptionalLocalizedColumnsAbsent_DoesNotThrow: 28 optional en/ru/pt/es columns
  may be absent without HeaderValidated throwing (FR-only header set loads clean).
- OptionalLocalizedColumnsPresent_MapsThem: Optional = "may be absent", not "ignored".
- RequiredColumnAbsent_Throws: a required FR column drift fails LOUD
  (HeaderValidationException), not silent null — the contract that prevents data loss.

This is the ai-01 "couverture tests" runway. Additive only, no production code
change. Full suite green (422/0/5, baseline 417 + 5 new).

Co-Authored-By: Claude Opus 4.6 <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]#559 (test(virtue): #499 VirtueClassMap regression via LoadFromContent, 5 tests)

Verdict: clean additive contract suite, mergeable. Verified the 5 tests against the production VirtueClassMap — every column the tests pin is real, and the fragilities they guard are genuine.

ClassMap cross-check (read Virtue.cs at PR head) — the test's VirtueRequiredHeader constant matches production exactly:

  • 17 non-Optional Map() calls → 16 distinct required column names (because both Id and Pk map to "pk"): pk, path, depth, decimal_path_padded, family_fr, subfamily_fr, subsubfamily_fr, title_fr, description_fr, remark_fr, link_fr, family_fr_camelcase, depth_max4, card, update, locked. Identical to the constant.
  • 28 optional localized columns (en/ru/pt/es × 7: family/subfamily/subsubfamily/title/description/remark/link), all .Optional(). Matches the "28 localized" claim.

5 real assertions (not stubs) — all FluentAssertions on actual Virtue.LoadFromContent(csv) resolution:

  1. MapsRequiredColumns — asserts every required FR property (Pk/Path/Depth=1 int/DecimalPathPadded/FamilyFr/SubfamilyFr/SubsubfamilyFr="" empty-cell/TitleFr/DescriptionFr/RemarkFr/LinkFr/FamilyFrCamelcase/DepthMax4/Card/Update/Locked) against an inline CSV. Depth as int parsed from "depth" column is the non-trivial check.
  2. PkPopulatesBothIdAndPk — pins the real double-map: Map(Id).Name("pk") + Map(Pk).Name("pk") both bind to the pk column, so Id/Pk/GetId() all resolve to "1.1". Genuine silent-failure source (dropping either binding → GetId() returns null → broken keyed generation).
  3. OptionalLocalizedColumnsAbsent_DoesNotThrow — FR-only header loads without throwing; absent optional cols → null (TitleEn/TitlePt/FamilyEs). Correct .Optional() contract.
  4. OptionalLocalizedColumnsPresent_MapsThem — when present, title_en/title_pt/family_es map to their properties. Optional ≠ ignored.
  5. RequiredColumnAbsent_Throws — dropping title_fr (non-Optional) from header → HeaderValidationException. Correct CsvHelper default (strict header validation for non-optional maps = loud failure, prevents silent data loss). The extra-row / MissingFieldFound nuance is correctly reasoned in the comment.

Additive-only: 2 new test files, +330/-0, zero production .cs modified. Self-contained inline CSV (no external fixtures). Security scan clean — all data synthetic.

One non-blocking note: this PR also adds FallacyLinkFallbackTests.cs (+167/-0), identical to the file in #558#559's branch was cut from a state including #558. If #558 merges first, #559's diff auto-shrinks to just VirtueClassMapRegressionTests.cs (the actual subject). Worth knowing for merge ordering, not a defect.

Comment-only (self-review cap).

@jsboige
jsboige merged commit 25d0783 into master Jun 20, 2026
3 checks passed
@jsboige
jsboige deleted the test/virtue-classmap-regression branch June 20, 2026 09:41
jsboige added a commit that referenced this pull request Jun 20, 2026
…sts) (#561)

Add TestFallacyCardClassMapRegressionTests — the LAST entity ClassMap without a
dedicated regression suite. This closes the ClassMap matrix at 100%: Fallacy (#485),
Rule/ArgumentVirtue/Scenario (#476), Virtue (#559), DnnUiString, and now TestFallacyCard.

TestFallacyCard is the simplified fallacy entity for visual-test card generation. Its
ClassMap declares 5 columns ALL required (non-Optional): Id, Title, Type,
IllustrationPath, Description.

5 contract tests via the real load path CsvBase<T,TMap>.LoadFromContent:
- MapsAllColumns: all 5 required columns map to their properties.
- GetIdReturnsId: GetId() returns Id (the image-generator output-dictionary key).
- RequiredColumnAbsent_Throws: a required column drift fails LOUD
  (HeaderValidationException), not silent null — the data-loss-prevention contract.
- ShortRow_DoesNotThrow: a ragged row yields string.Empty for missing fields
  (MissingFieldFound is a log callback, not throw) — mirrors CsvBaseStrictContractTests.
- MultipleRows_LoadInOrder.

This is the ai-01 SECONDAIRE dispatch ("TestFallacyCard ClassMap — ferme la matrice").
Additive only, no production code change. Full suite green (434/0/5, baseline 429 + 5).

Co-authored-by: Your <your.email@example.com>
Co-authored-by: Claude Opus 4.6 <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