CUST-WP-0075: reconcile owner waits and decision routing

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a10391-6355-7b41-b0fa-3e14e874f091
This commit is contained in:
tegwick 2026-10-04 00:48:22 +02:00
parent d61ba327fa
commit 831ae0e598
3 changed files with 233 additions and 3 deletions

View file

@ -2199,7 +2199,7 @@ class TestTaskWaitQualifiers:
repo = self._make_repo(
tmp_path,
"id: STATE-WP-0001-T01\nstatus: wait\npriority: high\n"
"state_hub_task_id: \"task-1\"\nneeds_human: true\n"
"state_hub_task_id: \"task-1\"\nneeds_human: true\ndecision_id: decision-1\n"
"blocking_reason: \"operator must provision creds\"",
)
self._install(monkeypatch, self._fake_get(repo))
@ -2314,7 +2314,7 @@ class TestTaskWaitQualifiers:
repo = self._make_repo(
tmp_path,
"id: STATE-WP-0001-T01\nstatus: wait\npriority: high\n"
"state_hub_task_id: \"task-1\"\nneeds_human: true\n"
"state_hub_task_id: \"task-1\"\nneeds_human: true\ndecision_id: decision-1\n"
"decision_id: CCR-2026-0004\n"
"blocking_reason: \"operator must provision creds\"",
extra_files={"docs/decisions.md": decision_doc},
@ -2532,3 +2532,56 @@ class TestTaskWaitQualifiers:
assert ("/tasks/task-1", wait_fields) in patches
assert any("C-20 fixed" in fix for fix in report.fixes_applied)
assert any("C-41 fixed" in fix for fix in report.fixes_applied)
class TestRoutedHumanGates:
WORKPLAN_HEAD = TestTaskWaitQualifiers.WORKPLAN_HEAD
_make_repo = TestTaskWaitQualifiers._make_repo
_fake_get = TestTaskWaitQualifiers._fake_get
_install = TestTaskWaitQualifiers._install
_issues = staticmethod(TestTaskWaitQualifiers._issues)
@pytest.mark.parametrize("status,flavor,decision,expected", [
("blocked", "implementation", "", 1),
("active", "implementation", "decision-1", 0),
("blocked", "residual", "", 0),
("finished", "implementation", "", 0),
("archived", "implementation", "", 0),
])
def test_human_gate_routing(self, tmp_path, monkeypatch, status, flavor, decision, expected):
repo = self._make_repo(tmp_path, "id: STATE-WP-0001-T01\nstatus: wait\nneeds_human: true\n"
+ (f"decision_id: {decision}\n" if decision else ""))
path = repo / "workplans/STATE-WP-0001-waiting.md"
path.write_text(path.read_text().replace("status: blocked", f"status: {status}\nflavor: {flavor}", 1))
self._install(monkeypatch, self._fake_get(repo))
issues = self._issues(check_repo("http://unused", "demo-repo"), "C-39")
assert len(issues) == expected
if issues:
assert "without decision_id" in issues[0].message
assert not issues[0].fixable
@pytest.mark.parametrize("read_at,date,flavor,status,description,expected", [
("2026-10-03T12:00:00Z", "2026-10-03T11:00:00Z", "implementation", "blocked", "2026-10-01: still waiting.", 1),
(None, "2026-10-01T11:00:00Z", "implementation", "active", "2026-10-02: reply reviewed; still waiting.", 0),
(None, "2026-10-03T11:00:00Z", "residual", "blocked", "2026-10-01: waiting.", 0),
(None, "2026-10-03T11:00:00Z", "implementation", "finished", "2026-10-01: waiting.", 0),
(None, "2026-10-03T11:00:00Z", "implementation", "ready", "Undated wait.", 1),
("2026-10-03T12:00:00Z", "2026-10-03T11:00:00Z", "implementation", "ready", "Undated wait.", 0),
])
def test_task_owner_return_sweep(tmp_path, monkeypatch, read_at, date, flavor, status, description, expected):
from consistency_check import _check_blocked_unblock_sweep
queries = []
def fake_get(_api_base, _path, params):
queries.append(params)
return [{"id": "reply-1", "from_agent": "provider", "created_at": date, "read_at": read_at},
{"id": "unrelated", "from_agent": "other", "created_at": date}]
monkeypatch.setattr("consistency_check._api_get", fake_get)
body = f"```task\nid: DEMO-WP-0001-T01\nstatus: wait\nblocked_on: message-from:provider\n```\n\n{description}"
report = ConsistencyReport(repo_slug="demo", repo_path=str(tmp_path))
_check_blocked_unblock_sweep("http://unused", "demo", tmp_path,
[(tmp_path / "plan.md", {"status": status, "flavor": flavor}, body)], report)
assert len(report.issues) == expected
if expected:
assert report.issues[0]._fix_context == {"task_record_id": "DEMO-WP-0001-T01", "message_ids": ["reply-1"]}
assert queries[0]["unread_only"] is False