Enrich the task template for new cards (task 07)
Merge the highest-value slots from a fuller development-task template into bench's lean one: an optional Depends on header line, an Affected areas line in Context, Out of scope bullets in What to build, edge-case and Given/When/Then guidance in Acceptance, and a Risks slot in Notes. Each slot says who consumes it and is marked deletable — empty boilerplate is worse than absence. The load-bearing contracts are unchanged: exact Status values, the Open questions heading the NOT READY gate keys off, Acceptance as the review target, and the template staying off the board. Organisation process (staging, sign-offs, approvals, contacts) is deliberately absent; a new contract test pins both the gained slots and what must not grow back. CLAUDE.md's Task file format section documents the Depends on line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -413,5 +413,15 @@ Type is orthogonal to status. A discovery task — research, scoping, spiking an
|
||||
approach — moves through the same five stages as everything else; "discovery"
|
||||
describes the work, not where it sits on the board.
|
||||
|
||||
An optional **Depends on** line can name what must land first — task numbers
|
||||
or external preconditions — so sequencing lives in the header instead of
|
||||
prose asides:
|
||||
|
||||
```markdown
|
||||
**Depends on:** 03, 05
|
||||
```
|
||||
|
||||
The board does not enforce it; it informs whoever picks the next card.
|
||||
|
||||
The rest of the file is freeform — description, research findings, approach,
|
||||
open questions, whatever is relevant to the current stage.
|
||||
|
||||
+38
-4
@@ -3,6 +3,15 @@ Copy this file into backlog/ as NN-short-kebab-title.md — numbers are
|
||||
allocated in creation order and stay with the task for life. The board never
|
||||
lists this template (it only reads the stage directories). The **PR:** line
|
||||
is added by the board itself when the task reaches review/ with a branch.
|
||||
|
||||
Anything below marked *optional* is deletable, and deleting beats leaving
|
||||
it hollow — an empty boilerplate section reads as thinking that never
|
||||
happened. Board process (review, PR, CI, merge) and the project-wide
|
||||
definition of done stay off the card: the board does the former
|
||||
mechanically and the repo CLAUDE.md owns the latter.
|
||||
|
||||
This template lives in tasks/, which updates never touch — improvements to
|
||||
it ship only with fresh installs, so local edits are yours to keep.
|
||||
-->
|
||||
|
||||
# NN — Imperative title: what changes when this is done
|
||||
@@ -10,6 +19,8 @@ is added by the board itself when the task reaches review/ with a branch.
|
||||
**Status:** Backlog
|
||||
**Priority:** Medium — one clause on why it sits at this level
|
||||
**Type:** Feature
|
||||
**Depends on:** 03, 05 — task numbers or external preconditions that must
|
||||
land first, for whoever sequences the board; delete when nothing blocks this
|
||||
|
||||
One paragraph for someone — human or agent — who has the codebase but not
|
||||
the conversation: what this task changes, and why it is worth doing.
|
||||
@@ -18,7 +29,12 @@ the conversation: what this task changes, and why it is worth doing.
|
||||
|
||||
What exists today and why it falls short. Point at real places rather than
|
||||
describing from memory: packages and modules (`packages/domain/...`), prior
|
||||
tasks (`../done/...`), reference documents (`../../reference/...`).
|
||||
tasks (`../done/...`), plan files (`../../plans/...`) and reference
|
||||
documents (`../../reference/...`) — a link outlives a summary.
|
||||
|
||||
**Affected areas:** the modules or layers this touches, one line in the
|
||||
repo CLAUDE.md's module-map vocabulary — telling reviewers where to look
|
||||
and agents where to stop. Optional: delete when the title already says it.
|
||||
|
||||
## What to build
|
||||
|
||||
@@ -29,13 +45,24 @@ convenience.
|
||||
- First piece
|
||||
- Second piece
|
||||
|
||||
**Out of scope** — the adjacent changes this task deliberately does not
|
||||
make. This is what bounds the work agent's brief; scope creep is the
|
||||
classic headless failure. Optional, but cheap insurance on any task with
|
||||
tempting neighbours — delete rather than leave empty.
|
||||
|
||||
- Not this, even though it is nearby
|
||||
|
||||
## Acceptance
|
||||
|
||||
Observable outcomes, not implementation steps. The repo's definition of done
|
||||
(tests pass, `lint-imports` clean, new behaviour covered) applies on top.
|
||||
Observable outcomes, not implementation steps — review agents judge the
|
||||
diff against exactly this list. The repo's definition of done (tests pass,
|
||||
`lint-imports` clean, new behaviour covered) applies on top; don't restate
|
||||
it. Given/When/Then phrasing is welcome where it sharpens a criterion, and
|
||||
edge cases belong here too — boundaries, empty inputs, failure paths.
|
||||
|
||||
- [ ] Something a reviewer can check without reading the diff
|
||||
- [ ] Another one
|
||||
- [ ] Given <a state>, when <the action>, then <the observable result>
|
||||
- [ ] Edge case: the boundary that would embarrass this feature if missed
|
||||
|
||||
## Open questions
|
||||
|
||||
@@ -51,3 +78,10 @@ it) when the task is ready to action.
|
||||
Freeform: research findings, links, decisions taken along the way. The
|
||||
board's relevance checks and PR reviews append their reports below this
|
||||
line as the task moves.
|
||||
|
||||
**Risks** — known hazards and blockers: what could sink the approach, what
|
||||
the change might break, what must hold for it to work. For the author
|
||||
weighing the task and the reviewer double-checking it. Optional: delete
|
||||
when there is nothing real to name.
|
||||
|
||||
- None worth naming yet.
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
"""The task template's load-bearing contract. Its headings are machinery,
|
||||
not prose convention: the body becomes the work agent's brief verbatim,
|
||||
Acceptance is what review agents judge against, and the Open questions
|
||||
heading is what the NOT READY gate keys off — so the template must keep
|
||||
them, exactly, in order. Task 07 enriched the template; these tests pin
|
||||
both what it gained and what it must never grow.
|
||||
|
||||
python3 -m unittest discover -s tests -v
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
TEMPLATE = (Path(__file__).resolve().parents[1]
|
||||
/ "tasks" / "task-template.md")
|
||||
|
||||
LOAD_BEARING_HEADINGS = [
|
||||
"Context", "What to build", "Acceptance", "Open questions", "Notes",
|
||||
]
|
||||
|
||||
# Organisation process the board either does mechanically or doesn't own —
|
||||
# deliberately absent from the template, and it must not grow back.
|
||||
ORG_PROCESS_TERMS = (
|
||||
"staging", "sign-off", "signoff", "qa ", "product owner",
|
||||
"browser", "device matrix", "contact",
|
||||
)
|
||||
|
||||
# The slots task 07 added, each of which earns its keep on the card.
|
||||
ENRICHED_SLOTS = (
|
||||
"**Depends on:**",
|
||||
"**Affected areas:**",
|
||||
"**Out of scope**",
|
||||
"**Risks**",
|
||||
"Given <",
|
||||
"Edge case",
|
||||
)
|
||||
|
||||
|
||||
class TemplateContract(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.text = TEMPLATE.read_text()
|
||||
|
||||
def test_load_bearing_headings_survive_in_order(self):
|
||||
headings = re.findall(r"^## (.+)$", self.text, re.MULTILINE)
|
||||
self.assertEqual(headings, LOAD_BEARING_HEADINGS)
|
||||
|
||||
def test_status_is_an_exact_board_value(self):
|
||||
self.assertIn("**Status:** Backlog\n", self.text)
|
||||
|
||||
def test_open_questions_section_names_the_gate(self):
|
||||
section = self.text.split("## Open questions", 1)[1]
|
||||
section = section.split("## ", 1)[0]
|
||||
self.assertIn("`NOT READY`", section)
|
||||
|
||||
def test_enriched_slots_are_present(self):
|
||||
for slot in ENRICHED_SLOTS:
|
||||
with self.subTest(slot=slot):
|
||||
self.assertIn(slot, self.text)
|
||||
|
||||
def test_new_slots_say_they_are_deletable(self):
|
||||
# "delete" appears with each optional slot, so authors trim rather
|
||||
# than leave hollow sections behind.
|
||||
for slot in ("**Depends on:**", "**Affected areas:**",
|
||||
"**Out of scope**", "**Risks**"):
|
||||
with self.subTest(slot=slot):
|
||||
paragraph = self.text.split(slot, 1)[1].split("\n\n", 1)[0]
|
||||
self.assertIn("delete", paragraph.lower())
|
||||
|
||||
def test_no_organisation_process_creeps_in(self):
|
||||
lowered = self.text.lower()
|
||||
for term in ORG_PROCESS_TERMS:
|
||||
with self.subTest(term=term):
|
||||
self.assertNotIn(term, lowered)
|
||||
|
||||
def test_template_sits_outside_every_stage_directory(self):
|
||||
# The board lists stage directories only; the template must stay a
|
||||
# sibling of them, not a card.
|
||||
self.assertEqual(TEMPLATE.parent.name, "tasks")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user