Version: plugin 2.9.4 · Skill: /understand · File: skills/understand/merge-batch-graphs.py
Summary
_TEST_NAME_PATTERNS (line 113) has no .swift entry, and is_test_path returns False when the extension is unknown:
_TEST_NAME_PATTERNS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
".go": ((), ("_test",)),
".py": (("test_",), ("_test",)),
".java": ((), ("Test", "Tests", "IT")),
".kt": ((), ("Test", "Tests")),
".scala": ((), ("Spec", "Suite", "Test", "Tests")),
".cs": ((), ("Test", "Tests")),
".c" / ".cpp" / ".cc": …
} # no .swift, .rs, .rb, .php, .m
# is_test_path (~line 342)
patterns = _TEST_NAME_PATTERNS.get(ext)
if patterns is None:
return False
So every Swift file classifies as production. The tested_by linker then sees production → production for each iOS pair and drops it as semantically broken — 100% of iOS test coverage is deleted at merge time, with no error and only an aggregate line in the report.
Impact
On a repo with Windows/Android/iOS ports, the merge printed:
Fixed (33 corrections):
33 × tested_by edges dropped (orphan endpoint or test↔test / prod↔prod pair)
Android and C# passed clean because .kt and .cs are in the table. Of those 33, six were genuine iOS pairs (PdfEngine+Search.swift → SearchTests.swift, etc.) that the analyzers had correctly emitted production → test. They were only recovered because the assemble-reviewer sampled the batch files and noticed; a normal run would ship a graph asserting the iOS layer has no tests at all. Any dashboard filter on the tested tag under-reports in the same way — the linker's tagging pass never fires for those nodes either.
The failure is silent and asymmetric, which is what makes it dangerous: a polyglot repo looks fine in aggregate while one language's coverage vanishes.
Repro
- Any project with
Foo.swift and FooTests.swift where an analyzer emits tested_by: file:Foo.swift → file:FooTests.swift.
- Run
/understand.
- The edge is dropped as a
prod↔prod pair; assembled-graph.json has no iOS tested_by edges.
Fix
One line, edge-preserving:
".swift": ((), ("Tests", "Test", "Spec")),
Worth adding the other missing ecosystems at the same time — .rs (test_ / _test), .rb (_spec, _test, test_), .php (Test), .m/.mm (Tests) — since generate-ignore.mjs already ships suggested test-file patterns for Swift, Rust and Ruby, so the pipeline clearly intends to support them.
A defensive follow-up: when is_test_path gets an extension it has no patterns for, that is worth counting and printing (e.g. note: 21 .swift files had no test-name patterns), so the next missing language surfaces as a line in the report rather than as vanished edges.
Version: plugin 2.9.4 · Skill:
/understand· File:skills/understand/merge-batch-graphs.pySummary
_TEST_NAME_PATTERNS(line 113) has no.swiftentry, andis_test_pathreturnsFalsewhen the extension is unknown:So every Swift file classifies as production. The
tested_bylinker then seesproduction → productionfor each iOS pair and drops it as semantically broken — 100% of iOS test coverage is deleted at merge time, with no error and only an aggregate line in the report.Impact
On a repo with Windows/Android/iOS ports, the merge printed:
Android and C# passed clean because
.ktand.csare in the table. Of those 33, six were genuine iOS pairs (PdfEngine+Search.swift→SearchTests.swift, etc.) that the analyzers had correctly emitted production → test. They were only recovered because theassemble-reviewersampled the batch files and noticed; a normal run would ship a graph asserting the iOS layer has no tests at all. Any dashboard filter on thetestedtag under-reports in the same way — the linker's tagging pass never fires for those nodes either.The failure is silent and asymmetric, which is what makes it dangerous: a polyglot repo looks fine in aggregate while one language's coverage vanishes.
Repro
Foo.swiftandFooTests.swiftwhere an analyzer emitstested_by: file:Foo.swift → file:FooTests.swift./understand.prod↔prodpair;assembled-graph.jsonhas no iOStested_byedges.Fix
One line, edge-preserving:
Worth adding the other missing ecosystems at the same time —
.rs(test_/_test),.rb(_spec,_test,test_),.php(Test),.m/.mm(Tests) — sincegenerate-ignore.mjsalready ships suggested test-file patterns for Swift, Rust and Ruby, so the pipeline clearly intends to support them.A defensive follow-up: when
is_test_pathgets an extension it has no patterns for, that is worth counting and printing (e.g.note: 21 .swift files had no test-name patterns), so the next missing language surfaces as a line in the report rather than as vanished edges.