"""Tests for union resolution (SHARD-WP-0007 T6).""" from shard_wiki.adapters import FolderAdapter from shard_wiki.coordination import DecisionLog, EventType from shard_wiki.policy import CanonicalSource, Policy from shard_wiki.union import ResolutionKind, UnionGraph def _shard(tmp_path, name, files): root = tmp_path / name for rel, text in files.items(): p = root / rel p.parent.mkdir(parents=True, exist_ok=True) p.write_text(text, encoding="utf-8") return FolderAdapter(name, root) def test_single_resolution(tmp_path): u = UnionGraph("space") u.attach(_shard(tmp_path, "shardA", {"Home.md": "A home"})) res = u.resolve("Home") assert res.kind is ResolutionKind.SINGLE assert res.single().body == "A home" def test_red_link_when_absent(tmp_path): u = UnionGraph("space") u.attach(_shard(tmp_path, "shardA", {"Home.md": "x"})) assert u.resolve("Nope").is_red_link def test_chorus_on_ambiguity_records_divergence(tmp_path): u = UnionGraph("space") u.attach(_shard(tmp_path, "shardA", {"Home.md": "A home"})) u.attach(_shard(tmp_path, "shardB", {"Home.md": "B home"})) res = u.resolve("Home") assert res.kind is ResolutionKind.CHORUS assert {p.body for p in res.pages} == {"A home", "B home"} # Each page names its divergent peer — union without erasure. a = next(p for p in res.pages if p.identity.shard == "shardA") assert a.envelope.divergence == ("shardB:Home",) def test_designated_canonical_orders_first(tmp_path): policy = Policy(canonical_source=CanonicalSource.DESIGNATED_CANONICAL, designated_shard="shardB") u = UnionGraph("space", policy=policy) u.attach(_shard(tmp_path, "shardA", {"Home.md": "A"})) u.attach(_shard(tmp_path, "shardB", {"Home.md": "B"})) res = u.resolve("Home") assert res.kind is ResolutionKind.CHORUS assert res.single().identity.shard == "shardB" # designated wins the canonical pick def test_alias_from_log_redirects(tmp_path): log = DecisionLog() log.append("space", EventType.ALIAS_SET, {"alias": "Start", "target": "shardA:Index"}) u = UnionGraph("space", log=log) u.attach(_shard(tmp_path, "shardA", {"Index.md": "the index"})) res = u.resolve("Start") assert res.kind is ResolutionKind.SINGLE assert res.single().body == "the index" def test_dangling_alias_falls_through_to_red_link(tmp_path): log = DecisionLog() log.append("space", EventType.ALIAS_SET, {"alias": "Start", "target": "shardA:Missing"}) u = UnionGraph("space", log=log) u.attach(_shard(tmp_path, "shardA", {"Index.md": "x"})) assert u.resolve("Start").is_red_link