fix: enforce bounded task planning policy

This commit is contained in:
2026-09-02 14:46:50 +00:00
parent ef7bdf015b
commit e324610416
2 changed files with 53 additions and 46 deletions
+44 -41
View File
@@ -1,54 +1,57 @@
from pathlib import Path
import re
import unittest
COMMENT = re.compile(r"<!--.*?-->", re.DOTALL)
def task_section(skill: str) -> str:
operative = COMMENT.sub("", skill)
return operative.split("## Task and Dependency Breakdown", 1)[1].split("## Version Allocation", 1)[0]
def policy_failures(section: str, approval_rule: str) -> list[str]:
section = COMMENT.sub("", section)
patterns = {
"ownership": r"(?m)^Architecture owns complete Task decomposition for every Feature allocated to the release\.$",
"lifecycle": r"(?m)^1\. Architecture creates missing Tasks, reviews existing Tasks, and retains, revises, supersedes, or removes them .+ may freely revise or remove only draft Tasks .+;$",
"cardinality": r"(?m)^2\. define between two and six independently executable Tasks per Feature; permit one Task only when a recorded Architecture rationale proves it is the smallest atomic, independently verifiable boundary;$",
"mapping": r"(?m)^3\. map the Feature's Tasks collectively, exactly, and reciprocally to every acceptance-outcome ID and every applicable active `FR-\*` and `NFR-\*` record;$",
"dependencies": r"(?m)^4\. encode acyclic within-Feature sequencing and require every entry Task to depend on all terminal Tasks of every prerequisite Feature;$",
"contract": r"(?m)^5\. give each Task one specific outcome, repository/component owner, canonical/display identity, task-specific implementation artifacts, concrete inputs and outputs, failure boundaries, exclusions, verification steps, and future acceptance-evidence requirements;$",
"separate-gates": r"(?m)^6\. keep draft Tasks separate from implementation approval and Kanban Focus admission\.$",
"protected-history": r"(?m)^Approved, Kanban-admitted, in-progress, or completed Tasks must not be deleted or silently rewritten\. Retain an obsolete Task with a terminal Superseded or Cancelled status, its prior evidence and history, and explicit replacement links\.$",
"approval-invalidation": approval_rule,
}
return [name for name, pattern in patterns.items() if re.search(pattern, section) is None]
class TaskBreakdownPolicyTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.skill = Path(__file__).parents[1].joinpath("SKILL.md").read_text()
cls.task_section = cls.skill.split("## Task and Dependency Breakdown", 1)[1].split("## Version Allocation", 1)[0]
cls.task_section = task_section(cls.skill)
cls.approval_rule = (
r"(?m)^A material change to Task scope, outcome, dependency, repository, or component invalidates the Task's existing implementation approval, returns the Task to its pre-approval state, and always requires renewed human `Approved for Implementation` before implementation can resume\. After renewed approval, execution still requires a separate exact-task Kanban Focus admission\.$"
)
def test_architecture_owns_complete_release_task_breakdown(self):
required = [
"Architecture owns complete Task decomposition",
"every Feature allocated to the release",
"reviews existing Tasks",
"at least two independently executable Tasks",
"every acceptance outcome",
"every applicable requirement",
"must not report planning readiness",
]
for marker in required:
self.assertIn(marker, self.task_section)
def test_task_lifecycle_and_readiness_rules_are_fail_closed(self):
required = [
"repository/component owner",
"acceptance-evidence requirements",
"implementation artifacts",
"inputs and outputs",
"failure boundaries",
"exclusions",
"verification steps",
"within-Feature sequencing",
"cross-Feature prerequisite",
"acyclic Task dependencies",
"creates missing Tasks",
"freely revise or remove only draft Tasks",
"must not be deleted or silently rewritten",
"Superseded or Cancelled",
"replacement links",
"invalidate prior readiness evidence",
"pre-approval state",
"renewed human `Approved for Implementation`",
"separate exact-task Kanban Focus admission",
"Approved, Kanban-admitted, in-progress, or completed Tasks must not be deleted or silently rewritten.",
"Retain an obsolete Task with a terminal Superseded or Cancelled status, its prior evidence and history, and explicit replacement links.",
"A material change to Task scope, outcome, dependency, repository, or component must invalidate prior readiness evidence",
]
def test_operational_policy_is_complete_and_structured(self):
self.assertIn("version: 1.7.0", self.skill)
for marker in required:
self.assertIn(marker, self.task_section)
self.assertEqual(policy_failures(self.task_section, self.approval_rule), [])
def test_comments_and_weakened_rules_cannot_satisfy_policy(self):
self.assertTrue(policy_failures(f"<!--{self.task_section}-->", self.approval_rule))
mutations = {
"cardinality": ("between two and six", "at least two"),
"mapping": ("exactly, and reciprocally", "loosely"),
"dependencies": ("all terminal Tasks", "some Tasks"),
"approval": ("invalidates the Task's existing implementation approval", "invalidates prior readiness evidence"),
"renewal": ("always requires renewed human", "may require renewed human"),
}
for name, (old, new) in mutations.items():
with self.subTest(name=name):
self.assertTrue(policy_failures(self.task_section.replace(old, new), self.approval_rule))
if __name__ == "__main__":