Skip to content

test(svg): pin SVG disambiguation heuristics (fragile area #1) + latent bug - #560

Merged
jsboige merged 1 commit into
masterfrom
test/svg-disambiguation-contract
Jun 20, 2026
Merged

test(svg): pin SVG disambiguation heuristics (fragile area #1) + latent bug#560
jsboige merged 1 commit into
masterfrom
test/svg-disambiguation-contract

Conversation

@jsboige

@jsboige jsboige commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

What

Pin the SVG disambiguation heuristics (FallacyMindMapDocumentConfig.CollectPossibleSvgNodes + DisambiguateSvgNodes) — CLAUDE.md "Known Fragile Area #1" — with 7 contract tests via XElement fixtures. Additive only, no production code change. Full suite 429/0/5.

This is the ai-01 PRIMAIRE dispatch (msg-20260620T094434-yj9f75): "SVG disambiguation contract tests (fragile area #1)... Pin the behavior with XElement fixtures (pas d'extraction prod requise). Je confirme la valeur : risque silencieux #1 documenté."

Why

"SVG disambiguation in mind map generation" with "fragile heuristics dependent on Freeplane's output structure" is the #1 documented fragility (CLAUDE.md). A regression in the min-length grouping, the 3-char prefix fallback, or the parent-distance tie-break silently wires each fallacy to the WRONG mind-map node — caught only by visually inspecting every generated SVG.

These methods are PRIVATE instance methods bound to TitleFunc/Logger — audited and rejected for the #204 extraction lane (delegates + Logger + XElement coupling break the byte-identity-by-inspection bar). The coordinator's call: pin the BEHAVIOR with fixtures (no extraction), because the silent-wrong-output risk justifies the coverage regardless.

How — reflection + real Fallacy fixtures

The methods are invoked via reflection against real Fallacy instances (which implement IMindMapItem and expose TextFr, so TitleFunc's {item.TextFr} interpolation resolves cleanly). Minimal <g><text> XElement fixtures exercise each branch.

The 7 tests (SvgDisambiguationContractTests)

Test What it pins
Collect_SingleExactMatch_ReturnsThatNode happy path
Collect_MultipleMatches_DifferentLengths_KeepsShortest THE fragile bit — min-length group wins (title node, not a re-quoting descendant)
Collect_NoExactMatch_LeavesItemAbsentFromResult silent-drop contract (logged, never a null-value entry)
Collect_SubstringMatchAcrossTextElements_Resolves string.Join over split <text> children (Freeplane label+detail)
Collect_TitleShorterThan3CharsAndNoMatch_ThrowsOnPrefixFallback latent bug — guard-less Substring(0,3) on a <3-char title throws
Disambiguate_SingleCandidatePerItem_Passthrough common path doesn't mutate selection
Disambiguate_EmptyInput_ReturnsEmpty_NotThrows early-exit guard doesn't NRE on Descendants()

A latent bug documented (not fixed — output-neutral)

CollectPossibleSvgNodes line 1304 calls title.Substring(0, 3) unconditionally in the no-match branch. A title shorter than 3 chars with no exact match throws ArgumentOutOfRangeException. In practice fallacy titles are long enough, but the code has no guard — the test pins the throw so the hazard is documented (a future caller with a short label crashes loud here, not silently misbehaves). Fixing it would be a behavior change → separate PR.

Verification

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

Related

🤖 Generated with Claude Code

…nt bug

Pin the behavior of FallacyMindMapDocumentConfig.CollectPossibleSvgNodes and
DisambiguateSvgNodes — CLAUDE.md "Known Fragile Area #1": SVG disambiguation in mind
map generation, fragile heuristics dependent on Freeplane's output structure.

These private instance methods (bound to TitleFunc/Logger) were audited + rejected
for the #204 extraction lane (not cleanly separable). The coordinator dispatched
pinning their BEHAVIOR via XElement fixtures instead of extraction, because the
silent-wrong-output risk is the #1 documented fragility: a regression in the
min-length grouping, the 3-char prefix fallback, or the parent-distance tie-break
silently wires each fallacy to the WRONG mind-map node — caught only by visually
inspecting every generated SVG.

7 contract tests via reflection against real Fallacy instances (which implement
IMindMapItem and expose TextFr, so TitleFunc's {item.TextFr} resolves):
- Collect: single exact match returns that node.
- Collect: multiple matches with different lengths KEEPS SHORTEST (the title node,
  not a re-quoting descendant) — the fragile bit.
- Collect: no exact match leaves the item ABSENT from the result (silent-drop
  contract — never a null-value entry).
- Collect: substring match across split <text> elements resolves (string.Join).
- Collect: title shorter than 3 chars with no match THROWS on the guard-less
  Substring(0,3) prefix fallback — documents a latent bug.
- Disambiguate: single candidate per item = passthrough.
- Disambiguate: empty input returns empty, does not throw on Descendants().

Additive only, no production code change. Full suite green (429/0/5, baseline 422 + 7).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jsboige
jsboige merged commit de01e28 into master Jun 20, 2026
3 checks passed
@jsboige
jsboige deleted the test/svg-disambiguation-contract branch June 20, 2026 11:10
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.

1 participant