C-42: blocked workplan with no wait task (CUST-WP-0074-T06)
Blocked-with-nothing-waiting is a stale status; warn until a qualified wait task exists or the workplan is re-statused. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 237582@bnt-lap001 Assistant-Session: f2b3d9f1-8fb9-4b9c-bc2b-837ec5dfc826
This commit is contained in:
parent
49fa3ebcdf
commit
7d04c05484
2 changed files with 46 additions and 0 deletions
|
|
@ -45,6 +45,7 @@ Checks:
|
|||
C-39 task-wait-unqualified WARN No wait task has none of task-block depends_on, needs_human: true, blocked_on: message-from:<agent>, wait_until: YYYY-MM-DD (CUST-WP-0074 rules 1/6)
|
||||
C-40 task-wait-blocker-satisfied WARN No wait task whose depends_on targets are all terminal, whose decision_id is resolved, or whose wait_until has passed (CUST-WP-0074 rules 3/4)
|
||||
C-41 task-wait-qualifier-drift WARN Yes needs_human/blocking_reason/decision_id/blocked_on/wait_until differ between file and DB (file wins)
|
||||
C-42 workplan-blocked-no-wait WARN No blocked workplan has no task in status wait (CUST-WP-0074-T06)
|
||||
(C-20 also indexes task-block depends_on as workplan_dependencies rows with from_task_id set)
|
||||
(finished¬DoD-Ok is listed by `statehub quality-debt`, not per-file C-warn — avoids historical flood)
|
||||
|
||||
|
|
@ -1742,6 +1743,26 @@ def check_repo(
|
|||
},
|
||||
)
|
||||
|
||||
# C-42: a blocked workplan must say what it waits for — at least one
|
||||
# task in `wait` (which C-39 then requires to be qualified). Blocked
|
||||
# with no wait task is a stale status, not a block (CUST-WP-0074-T06).
|
||||
if file_status == "blocked" and not any(
|
||||
normalise_task_status(s) == "wait" for s in file_task_statuses
|
||||
):
|
||||
report.add(
|
||||
severity="WARN",
|
||||
check_id="C-42",
|
||||
message=(
|
||||
f"Blocked workplan '{ws.get('slug')}' has no task in status "
|
||||
f"wait — nothing states what it waits for; qualify a wait "
|
||||
f"task or re-status the workplan"
|
||||
),
|
||||
file_path=fname,
|
||||
db_id=ws_id,
|
||||
file_value=file_status,
|
||||
fixable=False,
|
||||
)
|
||||
|
||||
# C-04: status drift — normalise file value before comparing so that
|
||||
# legacy file/API aliases are not treated as drift. Lifecycle repairs
|
||||
# take precedence so a stale planning file cannot regress active work.
|
||||
|
|
|
|||
|
|
@ -2442,6 +2442,31 @@ class TestTaskWaitQualifiers:
|
|||
assert len(self._issues(report, "C-39")) == 1
|
||||
assert self._issues(report, "C-40") == []
|
||||
|
||||
def test_c42_blocked_workplan_without_wait_task(self, tmp_path, monkeypatch):
|
||||
# A blocked workplan whose only task is todo states nothing about what
|
||||
# it waits for (CUST-WP-0074-T06). The head fixture is `blocked`.
|
||||
repo = self._make_repo(
|
||||
tmp_path,
|
||||
"id: STATE-WP-0001-T01\nstatus: todo\npriority: high\n"
|
||||
"state_hub_task_id: \"task-1\"",
|
||||
)
|
||||
self._install(monkeypatch, self._fake_get(repo))
|
||||
report = check_repo("http://unused", "demo-repo")
|
||||
c42 = self._issues(report, "C-42")
|
||||
assert len(c42) == 1 and c42[0].fixable is False
|
||||
assert "has no task in status wait" in c42[0].message
|
||||
|
||||
# A qualified wait task satisfies it.
|
||||
repo = self._make_repo(
|
||||
tmp_path / "ok",
|
||||
"id: STATE-WP-0001-T01\nstatus: wait\npriority: high\n"
|
||||
"state_hub_task_id: \"task-1\"\nneeds_human: true\n"
|
||||
"blocking_reason: \"operator decision\"",
|
||||
)
|
||||
self._install(monkeypatch, self._fake_get(repo))
|
||||
report = check_repo("http://unused", "demo-repo")
|
||||
assert self._issues(report, "C-42") == []
|
||||
|
||||
def test_c41_ignores_blocks_that_do_not_carry_the_keys(self, tmp_path, monkeypatch):
|
||||
repo = self._make_repo(
|
||||
tmp_path,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue