Some checks failed
Build and publish policy-nexus image / build-and-push (push) Failing after 39s
T03 writes a rulings overlay and a readable conflict list. T04 starts relevance: five superseded, five live conflicts, estate and activity-core ADRs marked publish-after-prefix. The Coulomb estate map is now a published architecture document.
169 lines
7.3 KiB
Python
169 lines
7.3 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
|
|
|
|
ROOT = Path(__file__).parents[1]
|
|
sys.path.insert(0, str(ROOT / "tools"))
|
|
from adr_review_ledger import build_ledger
|
|
|
|
|
|
class AdrReviewLedgerTest(unittest.TestCase):
|
|
def test_maps_inventory_and_flags_bare_adr_collisions(self) -> None:
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
root = Path(directory)
|
|
left = root / "alpha"
|
|
right = root / "beta"
|
|
(left / "docs/adr").mkdir(parents=True)
|
|
(right / "docs/adr").mkdir(parents=True)
|
|
(left / "docs/adr/ADR-0001-one.md").write_text(
|
|
"---\nid: ALPHA-ADR-0001\ntitle: One\nstatus: accepted\n"
|
|
"owner: alpha\nrevision: accepted-1\n"
|
|
"last_reviewed: \"2026-08-18\"\nreview_interval: 6m\n---\n# One\n",
|
|
encoding="utf-8",
|
|
)
|
|
(right / "docs/adr/ADR-0001-two.md").write_text("# Two\n", encoding="utf-8")
|
|
config = root / "source-inventory.config.json"
|
|
config.write_text(
|
|
json.dumps(
|
|
{
|
|
"schema_version": 1,
|
|
"repositories": {
|
|
"alpha": {"branch": "main", "remote": "https://example.invalid/a.git", "selectors": ["docs/adr/*.md"]},
|
|
"beta": {"branch": "main", "remote": "https://example.invalid/b.git", "selectors": ["docs/adr/*.md"]},
|
|
},
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
inventory = root / "source-inventory.json"
|
|
inventory.write_text(
|
|
json.dumps(
|
|
{
|
|
"schema_version": 1,
|
|
"sources": [
|
|
{
|
|
"source_repo": "alpha",
|
|
"source_path": "docs/adr/ADR-0001-one.md",
|
|
"disposition": "metadata-pending",
|
|
"reason": "pending",
|
|
},
|
|
{
|
|
"source_repo": "beta",
|
|
"source_path": "docs/adr/ADR-0001-two.md",
|
|
"disposition": "metadata-pending",
|
|
"reason": "pending",
|
|
},
|
|
],
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
ledger = build_ledger(
|
|
inventory, config, policy_root=root, source_root=root
|
|
)
|
|
rows = {f"{row['source_repo']}/{row['source_path']}": row for row in ledger["rows"]}
|
|
self.assertEqual(2, len(rows))
|
|
self.assertEqual([], rows["alpha/docs/adr/ADR-0001-one.md"]["missing_fields"])
|
|
self.assertIn("id", rows["beta/docs/adr/ADR-0001-two.md"]["missing_fields"])
|
|
self.assertEqual("ADR-0001", rows["alpha/docs/adr/ADR-0001-one.md"]["bare_adr"])
|
|
self.assertEqual(
|
|
["beta/docs/adr/ADR-0001-two.md"],
|
|
rows["alpha/docs/adr/ADR-0001-one.md"]["bare_adr_collisions"],
|
|
)
|
|
self.assertEqual("unreviewed", rows["alpha/docs/adr/ADR-0001-one.md"]["proposed_disposition"])
|
|
|
|
def test_rulings_overlay_and_shared_id_kind_one(self) -> None:
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
root = Path(directory)
|
|
(root / "alpha/docs/adr").mkdir(parents=True)
|
|
(root / "beta/docs/adr").mkdir(parents=True)
|
|
(root / "alpha/docs/adr/one.md").write_text(
|
|
"---\nid: ADR-001\ntitle: One\nstatus: accepted\nowner: alpha\n"
|
|
"revision: 1\nlast_reviewed: \"2026-08-18\"\nreview_interval: 6m\n---\n# One\n",
|
|
encoding="utf-8",
|
|
)
|
|
(root / "beta/docs/adr/two.md").write_text(
|
|
"---\nid: ADR-001\ntitle: Two\nstatus: accepted\nowner: beta\n"
|
|
"revision: 1\nlast_reviewed: \"2026-08-18\"\nreview_interval: 6m\n---\n# Two\n",
|
|
encoding="utf-8",
|
|
)
|
|
config = root / "source-inventory.config.json"
|
|
config.write_text(
|
|
json.dumps(
|
|
{
|
|
"schema_version": 1,
|
|
"repositories": {
|
|
"alpha": {
|
|
"branch": "main",
|
|
"remote": "https://example.invalid/a.git",
|
|
"selectors": ["docs/adr/*.md"],
|
|
},
|
|
"beta": {
|
|
"branch": "main",
|
|
"remote": "https://example.invalid/b.git",
|
|
"selectors": ["docs/adr/*.md"],
|
|
},
|
|
},
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
inventory = root / "source-inventory.json"
|
|
inventory.write_text(
|
|
json.dumps(
|
|
{
|
|
"schema_version": 1,
|
|
"sources": [
|
|
{
|
|
"source_repo": "alpha",
|
|
"source_path": "docs/adr/one.md",
|
|
"disposition": "metadata-pending",
|
|
"reason": "pending",
|
|
},
|
|
{
|
|
"source_repo": "beta",
|
|
"source_path": "docs/adr/two.md",
|
|
"disposition": "metadata-pending",
|
|
"reason": "pending",
|
|
},
|
|
],
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
rulings = root / "rulings.json"
|
|
rulings.write_text(
|
|
json.dumps(
|
|
{
|
|
"schema_version": 1,
|
|
"rulings": [
|
|
{
|
|
"source_repo": "beta",
|
|
"source_path": "docs/adr/two.md",
|
|
"proposed_disposition": "conflict",
|
|
"conflict_kinds": [6],
|
|
"successor": "",
|
|
"review_notes": "duplicate claim",
|
|
}
|
|
],
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
ledger = build_ledger(
|
|
inventory,
|
|
config,
|
|
policy_root=root,
|
|
source_root=root,
|
|
rulings_path=rulings,
|
|
)
|
|
rows = {f"{row['source_repo']}/{row['source_path']}": row for row in ledger["rows"]}
|
|
self.assertEqual("unreviewed", rows["alpha/docs/adr/one.md"]["proposed_disposition"])
|
|
self.assertIn(1, rows["alpha/docs/adr/one.md"]["conflict_kinds"])
|
|
self.assertEqual("conflict", rows["beta/docs/adr/two.md"]["proposed_disposition"])
|
|
self.assertEqual([6, 1], rows["beta/docs/adr/two.md"]["conflict_kinds"])
|