from pathlib import Path from typing import Any import scripts.decisions_lib as dl import scripts.decisions_validate as dv def _rec(**kw: Any) -> dl.Record: base: dict[str, Any] = dict(heading="H", source=Path("x"), lineno=1, status="active") base.update(kw) return dl.Record(**base) def _v(recs: list[dl.Record], **kw: Any) -> list[str]: args: dict[str, Any] = dict(archive_keys=set(), catalog_ok=True, budget_ok=True, removed=[], rewritten=[]) args.update(kw) return dv.validate(recs, **args) def test_two_active_same_key_fails(): assert any("more than one active" in e for e in _v([_rec(key="a.b"), _rec(key="a.b")])) def test_bad_key_format_fails(): assert any("key format" in e for e in _v([_rec(key="BadKey")])) def test_dangling_superseded_by_fails(): recs = [_rec(key="a.b", status="superseded", superseded_by="a.c@2026-07-01")] assert any("superseded-by" in e and "a.c" in e for e in _v(recs)) def test_superseded_by_resolves_to_archive_key_passes(): # successor lives in archive → known via archive_keys, no dangling error recs = [_rec(key="a.b", status="superseded", superseded_by="a.c@2026-07-01")] assert not any("superseded-by" in e for e in _v(recs, archive_keys={"a.c"})) def test_removed_active_not_in_archive_fails(): assert any("removed from the active set" in e for e in _v([], removed=["2026-01-01 — Gone (#9)"])) def test_rewritten_rationale_without_token_fails(): assert any( "rationale" in e and "decisions-edit" in e for e in _v([_rec(key="a.b")], rewritten=["2026-01-01 — Reworded (#9)"]) ) def test_clean_corpus_passes(): assert _v([_rec(key="a.b"), _rec(key="c.d")]) == []