fix(merge): coerce malformed tags before adding "tested" (#113)

Codex flagged that prod_node.setdefault("tags", []) returns the existing
value when the key is present, so a raw LLM batch with tags=None or
tags="some string" would crash the whole merge on the next "tested" not
in tags membership check.

The TypeScript autoFixGraph normalizer that handles this case runs
downstream of merge-batch-graphs.py, not before it, so the Python side
has to defend itself. Coerce non-list tags to a fresh [] before the
membership/append.

Regression test exercises None / comma-string / single-string / int /
dict inputs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lum1104
2026-05-07 10:25:56 +08:00
Unverified
parent 6c257a55f0
commit fdfa331009
2 changed files with 30 additions and 1 deletions
@@ -479,7 +479,14 @@ def link_tests(
"description": "Path-based pairing (deterministic)",
})
added += 1
tags = prod_node.setdefault("tags", [])
# `tags` may be missing, None, or a malformed string from raw LLM
# batch JSON — the TypeScript autoFixGraph layer that normalizes it
# only runs downstream of this script. Coerce to a fresh list so a
# bad batch can't crash the whole merge.
tags = prod_node.get("tags")
if not isinstance(tags, list):
tags = []
prod_node["tags"] = tags
if "tested" not in tags:
tags.append("tested")
tagged += 1
@@ -443,6 +443,28 @@ class LinkTestsTests(unittest.TestCase):
self.assertEqual(edges[0]["target"], "file:src/foo.test.ts")
self.assertIn("tested", prod["tags"])
def test_malformed_tags_is_replaced_not_crashed(self) -> None:
# Raw LLM batch JSON can ship `tags` as None, a string, or other
# non-list values — the TypeScript autoFixGraph normalizer runs
# downstream of this script. The linker must coerce instead of crash.
for bad_tags in (None, "tested,foo", "single", 0, {"k": "v"}):
with self.subTest(bad_tags=bad_tags):
prod = {
"id": "file:src/foo.ts",
"type": "file",
"name": "foo.ts",
"filePath": "src/foo.ts",
"tags": bad_tags,
}
test = _file_node("src/foo.test.ts")
nodes_by_id = {prod["id"]: prod, test["id"]: test}
edges: list[dict[str, Any]] = []
added, dropped, tagged = mbg.link_tests(nodes_by_id, edges)
self.assertEqual((added, dropped, tagged), (1, 0, 1))
self.assertEqual(prod["tags"], ["tested"])
# ── merge_and_normalize integration ───────────────────────────────────────