plans/ held 58 documents and exactly one said whether it was open. The rest
mixed finished work, reviews of shipped work, parked specs and genuinely
pending ones, with nothing distinguishing them, so "how many plans are in
the queue" had no answer short of reading all 58.
Now `grep -H '^Status:' plans/*.md` is the answer:
50 done 3 in progress 2 planned 2 reference 1 parked
Statuses were derived rather than guessed: CLAUDE.md's own built list and
"What's NOT built yet" section, plus checking the subject exists in the
code. A review of work that shipped counts as done -- it records what was
found, it is not a request for anything. `reference` separates the two docs
that are conventions rather than work items (admin-design-standards,
admin-work-framework), which otherwise read as permanently-open plans.
The vocabulary is deliberately five words. A larger one invites "mostly
done" and "blocked-ish", which is how the directory became unreadable.
test_plans_declare_status.py keeps it from rotting: a new plan without a
marker fails, as does an unknown status, one buried below the eighth line,
or an open status with no reason -- "planned" alone is the state that rots,
since nobody can tell later whether it waits on a decision, a dependency,
or just nobody's turn.
Also updates the sweep plan with what landed and what did not, including
that #9 was not a defect.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
65 lines
2.5 KiB
Python
65 lines
2.5 KiB
Python
"""Every plan doc declares a status, so the queue is answerable.
|
|
|
|
Before this, `plans/` held 58 documents and exactly one said whether it was
|
|
open. The rest mixed finished work, reviews of shipped work, parked specs
|
|
and genuinely pending ones, with nothing distinguishing them -- so "how many
|
|
plans are in the queue" had no answer short of reading all 58.
|
|
|
|
The point of the marker is that `grep -H '^Status:' plans/*.md` is the
|
|
answer. This test keeps a new plan from arriving without one.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
PLANS = sorted((Path(__file__).resolve().parent.parent / "plans").glob("*.md"))
|
|
|
|
# Deliberately small. A larger vocabulary invites "mostly done" and
|
|
# "blocked-ish", which is how the directory got unreadable in the first place.
|
|
VALID = {"done", "planned", "in progress", "parked", "reference"}
|
|
|
|
STATUS_RE = re.compile(r"^Status: (?P<status>[a-z ]+?)(?: -- (?P<reason>.+))?$", re.M)
|
|
|
|
|
|
def test_there_are_plans_to_check():
|
|
assert len(PLANS) > 20, "plans/ did not resolve; the glob is probably wrong"
|
|
|
|
|
|
@pytest.mark.parametrize("path", PLANS, ids=lambda p: p.name)
|
|
def test_each_plan_declares_a_valid_status(path):
|
|
text = path.read_text(encoding="utf-8")
|
|
match = STATUS_RE.search(text)
|
|
assert match, (
|
|
f"{path.name} has no 'Status:' line. Add one of {sorted(VALID)} "
|
|
f"below the title, ideally with ' -- <one-line reason>'."
|
|
)
|
|
status = match.group("status").strip()
|
|
assert status in VALID, f"{path.name}: unknown status {status!r}, want one of {sorted(VALID)}"
|
|
|
|
|
|
@pytest.mark.parametrize("path", PLANS, ids=lambda p: p.name)
|
|
def test_the_status_is_near_the_top(path):
|
|
"""A marker buried on line 200 is not a marker anyone reads."""
|
|
head = "\n".join(path.read_text(encoding="utf-8").split("\n")[:8])
|
|
assert STATUS_RE.search(head), f"{path.name}: Status line is not in the first 8 lines"
|
|
|
|
|
|
@pytest.mark.parametrize("path", PLANS, ids=lambda p: p.name)
|
|
def test_open_plans_say_why_they_are_open(path):
|
|
"""`done` can stand alone; anything still live needs a reason.
|
|
|
|
"planned" with no reason is the state that rots -- nobody can tell later
|
|
whether it is waiting on a decision, a dependency, or just nobody's turn.
|
|
"""
|
|
match = STATUS_RE.search(path.read_text(encoding="utf-8"))
|
|
status = match.group("status").strip()
|
|
if status in {"planned", "in progress", "parked"}:
|
|
assert match.group("reason"), (
|
|
f"{path.name}: status {status!r} needs ' -- <why>' so the next "
|
|
f"reader knows what it is waiting on"
|
|
)
|