status: a cancelled task is a closed one
Some checks failed
ci / check (push) Has been cancelled

CB-WP-0005 read 5/8 and CB-WP-0007 read 2/6 in every status run since
they closed, because only 'done' counted and their remaining tasks are
'cancel'. Two permanently-wrong numbers teach the reader to skip the
column. Both now collapse into 'closed and complete' -- 18 of them --
while an open workplan with cancellations still shows the count
separately, so a cancellation is visible rather than laundered into
completion.

The workplan block is extracted as render_workplans so the control is
stated over what the tool PRINTS rather than over a literal the test
wrote: a done+cancelled fixture must collapse, and one with a real todo
must not. The first version of that control asserted arithmetic on its
own input, which is the tautological shape ADR-0010 D2 demoted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-03 18:55:11 +02:00
parent cc8917a6fb
commit 5c00c72d3b

View file

@ -266,18 +266,37 @@ def report():
# length limit it is meant to keep. Collapse the fully-closed ones to
# a single line rather than raising the limit — the precedent is
# LOOP-LINT's four loadability breaches, each fixed structurally.
render_workplans(plans)
report_tail(plans)
def render_workplans(plans):
"""The workplan block. Extracted so its behaviour can be asserted on
rather than re-derived in a test (ADR-0010 D2: controls are stated
over what the tool does, not over a literal the test wrote)."""
print("\n workplans")
closed = []
for wid, title, status, tasks, _kind in plans:
# `cancel` is a CLOSED outcome, not an open one. Counting only
# `done` left CB-WP-0005 reading "5/8" and CB-WP-0007 "2/6" in
# every status run since they closed — permanently wrong numbers,
# which teach the reader to skip the column. The two figures are
# kept separate so a cancellation is still visible rather than
# laundered into completion.
done = sum(1 for _, s, _ in tasks if s == "done")
if status == "done" and done == len(tasks):
cancelled = sum(1 for _, s, _ in tasks if s == "cancel")
if status == "done" and done + cancelled == len(tasks):
closed.append(wid.replace("CB-WP-", ""))
continue
short = (title or "")[:44]
print(f" {wid} {status:<12} {done}/{len(tasks)} done {short}")
note = f", {cancelled} cancelled" if cancelled else ""
print(f" {wid} {status:<12} {done}/{len(tasks)} done{note} {short}")
if closed:
print(f" {len(closed)} closed and complete: " + " ".join(closed))
def report_tail(plans):
"""Next task, spend, budgets, fast gates — the rest of the report."""
nxt = next_task(plans)
if nxt:
wid, tid, prio = nxt
@ -351,6 +370,25 @@ def self_test():
abs(META_SOFT_PCT - 100 / TRAILING_PASSES) < 1e-9,
f"{META_SOFT_PCT}% over {TRAILING_PASSES} passes; one meta pass at "
f"parity reads {100 / TRAILING_PASSES:.0f}%")
# A workplan whose tasks are done-or-cancelled is CLOSED. Counting
# only `done` left two real workplans reading 5/8 and 2/6 forever.
def rendered(tasks):
out = io.StringIO()
saved, sys.stdout = sys.stdout, out
try:
render_workplans([("CB-WP-0000", "fixture", "done", tasks, "meta")])
finally:
sys.stdout = saved
return out.getvalue()
both = rendered([("T01", "done", "high"), ("T02", "cancel", "low")])
check("a done+cancelled workplan collapses to closed",
"closed and complete" in both and "1/2" not in both,
both.strip().splitlines()[-1].strip())
open_one = rendered([("T01", "done", "high"), ("T02", "todo", "low")])
check("a workplan with a real todo does NOT collapse",
"1/2 done" in open_one, open_one.strip().splitlines()[-1].strip())
check("the budget states what it is for",
bool(META_PURPOSE) and "task at hand" in META_PURPOSE)