diff --git a/scripts/consistency_check.py b/scripts/consistency_check.py index 35826e6..01f2143 100644 --- a/scripts/consistency_check.py +++ b/scripts/consistency_check.py @@ -2547,10 +2547,10 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo return False repo_id: str = repo.get("id", "") - domain_slug: str = "" + domain_slug = str(repo.get("domain_slug") or "") - # Resolve domain slug: prefer active workstreams, fall back to any workstream - # so that a fully-finished repo doesn't degrade to "(unknown)". + # The repository projection owns domain identity. Retain the workplan/topic + # lookup only for compatibility with older API responses that omitted it. workstreams: list[dict] = [] for status in OPEN_WORKSTREAM_STATUSES: rows = _api_get(api_base, "/workplans", {"repo_id": repo_id, "status": status}) or [] @@ -2560,7 +2560,7 @@ def _write_custodian_brief(api_base: str, repo_slug: str, repo_path: str) -> boo if not _ws_for_domain: all_ws = _api_get(api_base, "/workplans", {"repo_id": repo_id}) or [] _ws_for_domain = all_ws if isinstance(all_ws, list) else [] - if _ws_for_domain: + if not domain_slug and _ws_for_domain: topic = _api_get(api_base, f"/topics/{_ws_for_domain[0].get('topic_id', '')}") if topic: domain_slug = topic.get("domain_slug", "") diff --git a/tests/test_consistency_check.py b/tests/test_consistency_check.py index d7c752e..a58f6f0 100644 --- a/tests/test_consistency_check.py +++ b/tests/test_consistency_check.py @@ -41,6 +41,7 @@ from consistency_check import ( _patch_frontmatter_field, _patch_task_status_in_file, _report_needs_action, + _write_custodian_brief, archive_closed_workplans, canonical_workplan_filename, check_repo, @@ -72,6 +73,63 @@ class TestResolveTopicDomainSlug: assert resolve_topic_domain_slug("custodian", repo_market_domain="infotech") == "infotech" +class TestCustodianBriefDomain: + @staticmethod + def _install_common_mocks(monkeypatch, calls, repo_payload, topic_payload=None): + def fake_get(_api_base, path, params=None): + calls.append((path, params)) + if path == "/repos/demo": + return repo_payload + if path == "/workplans": + return [{"id": "wp-1", "title": "Open", "topic_id": None}] + if path == "/tasks": + return [] + if path == "/repo-goals": + return [] + if path.startswith("/topics/"): + return topic_payload + if path == "/messages": + return [] + return None + + monkeypatch.setattr("consistency_check._api_get", fake_get) + monkeypatch.setattr( + "consistency_check._git_commit_writeback", lambda *args, **kwargs: True + ) + + def test_brief_prefers_repository_domain_when_workplan_topic_is_null( + self, tmp_path, monkeypatch + ): + calls = [] + self._install_common_mocks( + monkeypatch, + calls, + {"id": "repo-1", "domain_slug": "infotech"}, + ) + + assert _write_custodian_brief("http://unused", "demo", str(tmp_path)) is True + brief = (tmp_path / ".custodian-brief.md").read_text(encoding="utf-8") + assert "**Domain:** infotech" in brief + assert '`get_domain_summary("infotech")`' in brief + assert not any(path.startswith("/topics/") for path, _params in calls) + + def test_brief_retains_topic_fallback_for_legacy_repo_response( + self, tmp_path, monkeypatch + ): + calls = [] + self._install_common_mocks( + monkeypatch, + calls, + {"id": "repo-1"}, + {"domain_slug": "financials"}, + ) + + assert _write_custodian_brief("http://unused", "demo", str(tmp_path)) is True + brief = (tmp_path / ".custodian-brief.md").read_text(encoding="utf-8") + assert "**Domain:** financials" in brief + assert any(path.startswith("/topics/") for path, _params in calls) + + class TestRepoManagerConformanceAdapter: def test_surfaces_repo_manager_findings_without_reimplementing_rules(self, tmp_path, monkeypatch): rmgr = tmp_path / "rmgr" diff --git a/workplans/STATE-WP-0079-retirement-strangler.md b/workplans/STATE-WP-0079-retirement-strangler.md index 16dc194..760de4b 100644 --- a/workplans/STATE-WP-0079-retirement-strangler.md +++ b/workplans/STATE-WP-0079-retirement-strangler.md @@ -346,6 +346,16 @@ project repos are already routed to `rmgr scaffold`. Gate the deletion on `RMGR-WP-0004-T06` proving byte-identical durable output and idempotent re-scaffolding. +**Brief compatibility repair (2026-08-23):** the surviving consistency +generator degraded `the-custodian` to `Domain: (unknown)` and emitted +`get_domain_summary("")` even though `GET /repos/the-custodian` correctly +projected `domain_slug: infotech`. Active workplans can legitimately have no +topic, so topic inference is not authoritative. The generator now prefers the +repository projection and retains topic lookup only for legacy API responses +that omit `domain_slug`. Two regression tests cover both paths; all 131 +consistency-check tests pass. This is a compatibility fix until the generator +moves or retires, not new permanent State Hub authority. + ## Retire legacy surfaces ```task