Skip to content

Commit 44fddad

Browse files
chore: add TDD RED test files for implementation-plan skill improvements
Add xfail RED-phase test files for dso-gp00 (AC library new categories) and dso-awsv (TDD enforcement language in SKILL.md). Also include ticket metadata updates from previous session. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 71e679a commit 44fddad

File tree

6 files changed

+282
-3
lines changed

6 files changed

+282
-3
lines changed

.tickets/dso-4f1i.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
id: dso-4f1i
3-
status: open
3+
status: in_progress
44
deps: []
55
links: []
66
created: 2026-03-18T21:11:22Z

.tickets/dso-gsqg.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
id: dso-gsqg
3-
status: open
3+
status: in_progress
44
deps: []
55
links: []
66
created: 2026-03-18T21:11:38Z

.tickets/dso-tk5c.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
id: dso-tk5c
3-
status: open
3+
status: in_progress
44
deps: []
55
links: []
66
created: 2026-03-18T21:11:00Z
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Tests for new categories in ACCEPTANCE-CRITERIA-LIBRARY.md.
2+
3+
These are RED-phase xfail tests. They assert the presence of two new
4+
categories that have not yet been added to the file. Once the GREEN task
5+
(dso-gp00) adds the content, these tests will pass and should be converted
6+
to normal assertions.
7+
"""
8+
9+
import os
10+
11+
import pytest
12+
13+
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
14+
AC_LIBRARY_PATH = os.path.join(
15+
REPO_ROOT,
16+
"plugins",
17+
"dso",
18+
"docs",
19+
"ACCEPTANCE-CRITERIA-LIBRARY.md",
20+
)
21+
22+
23+
def _read_ac_library() -> str:
24+
with open(AC_LIBRARY_PATH) as f:
25+
return f.read()
26+
27+
28+
@pytest.mark.xfail(strict=True, reason="Category not yet added (dso-gp00)")
29+
def test_red_test_task_category_present() -> None:
30+
"""'Category: RED Test Task' must be present in ACCEPTANCE-CRITERIA-LIBRARY.md."""
31+
content = _read_ac_library()
32+
assert "Category: RED Test Task" in content
33+
34+
35+
@pytest.mark.xfail(strict=True, reason="Category not yet added (dso-gp00)")
36+
def test_test_exempt_task_category_present() -> None:
37+
"""'Category: Test-Exempt Task' must be present in ACCEPTANCE-CRITERIA-LIBRARY.md."""
38+
content = _read_ac_library()
39+
assert "Category: Test-Exempt Task" in content
40+
41+
42+
@pytest.mark.xfail(
43+
strict=True, reason="Justification criterion not yet added (dso-gp00)"
44+
)
45+
def test_test_exempt_justification_criterion_present() -> None:
46+
"""The test-exempt category must include a justification criterion."""
47+
content = _read_ac_library()
48+
# Confirm the category exists and has justification text after it
49+
assert "Category: Test-Exempt Task" in content
50+
idx = content.index("Category: Test-Exempt Task")
51+
section = content[idx : idx + 500]
52+
assert "justification" in section.lower()
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"""Tests for TDD enforcement language in implementation-plan/SKILL.md.
2+
3+
TDD spec for task dso-awsv (GREEN task):
4+
- SKILL.md Step 3 must contain explicit TDD enforcement rules covering:
5+
1. 'no conditional logic' — ban on conditional/parametric logic in tests
6+
2. 'change-detector test' — escape hatch terminology
7+
3. 'infrastructure-boundary-only' — scope qualifier for escape hatch
8+
4. 'RED test task' — required naming for the failing-test task
9+
5. 'behavioral content' — definition distinguishing real tests from test stubs
10+
6. Integration test task rule language
11+
7. 'existing coverage' — prohibition on relying on pre-existing tests
12+
8. 'no test environment' — prohibition on writing tests needing special env
13+
9. Justification requirement for escape hatch use
14+
15+
All tests are marked xfail(strict=True) because SKILL.md has not yet been
16+
updated by dso-awsv. They will turn GREEN once dso-awsv lands its changes.
17+
"""
18+
19+
import pathlib
20+
21+
import pytest
22+
23+
REPO_ROOT = pathlib.Path(__file__).resolve().parents[2]
24+
SKILL_MD = REPO_ROOT / "plugins" / "dso" / "skills" / "implementation-plan" / "SKILL.md"
25+
26+
27+
def _read_skill() -> str:
28+
return SKILL_MD.read_text()
29+
30+
31+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
32+
def test_skill_md_contains_no_conditional_logic() -> None:
33+
"""SKILL.md must prohibit conditional/parametric logic in TDD test tasks."""
34+
content = _read_skill()
35+
assert "no conditional logic" in content, (
36+
"SKILL.md Step 3 must contain 'no conditional logic' to prohibit "
37+
"parametric test stubs that always pass."
38+
)
39+
40+
41+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
42+
def test_skill_md_contains_change_detector_test() -> None:
43+
"""SKILL.md must name the escape hatch anti-pattern as 'change-detector test'."""
44+
content = _read_skill()
45+
assert "change-detector test" in content, (
46+
"SKILL.md Step 3 must reference 'change-detector test' as the "
47+
"canonical name for the escape hatch anti-pattern."
48+
)
49+
50+
51+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
52+
def test_skill_md_contains_infrastructure_boundary_only() -> None:
53+
"""SKILL.md must restrict escape hatch to infrastructure-boundary-only cases."""
54+
content = _read_skill()
55+
assert "infrastructure-boundary-only" in content, (
56+
"SKILL.md Step 3 must contain 'infrastructure-boundary-only' to scope "
57+
"when the change-detector test escape hatch is permitted."
58+
)
59+
60+
61+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
62+
def test_skill_md_contains_red_test_task() -> None:
63+
"""SKILL.md must require a named 'RED test task' as a distinct task in the plan."""
64+
content = _read_skill()
65+
assert "RED test task" in content, (
66+
"SKILL.md Step 3 must require a 'RED test task' as a standalone task "
67+
"that writes the failing test before implementation."
68+
)
69+
70+
71+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
72+
def test_skill_md_contains_behavioral_content() -> None:
73+
"""SKILL.md must define 'behavioral content' to distinguish real tests."""
74+
content = _read_skill()
75+
assert "behavioral content" in content, (
76+
"SKILL.md Step 3 must use 'behavioral content' to distinguish tests "
77+
"with real assertions from empty stubs or pass-through fixtures."
78+
)
79+
80+
81+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
82+
def test_skill_md_contains_integration_test_task_rule() -> None:
83+
"""SKILL.md must include rule language governing integration test tasks."""
84+
content = _read_skill()
85+
assert "integration test task" in content, (
86+
"SKILL.md Step 3 must contain 'integration test task' rule language "
87+
"specifying how integration tests fit into the TDD task structure."
88+
)
89+
90+
91+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
92+
def test_skill_md_contains_existing_coverage() -> None:
93+
"""SKILL.md must prohibit relying on existing coverage to satisfy RED."""
94+
content = _read_skill()
95+
assert "existing coverage" in content, (
96+
"SKILL.md Step 3 must reference 'existing coverage' to clarify that "
97+
"pre-existing passing tests do not satisfy the RED requirement."
98+
)
99+
100+
101+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
102+
def test_skill_md_contains_no_test_environment() -> None:
103+
"""SKILL.md must prohibit tests that require a special test environment."""
104+
content = _read_skill()
105+
assert "no test environment" in content, (
106+
"SKILL.md Step 3 must contain 'no test environment' to prohibit "
107+
"writing tests that require special setup unavailable in CI."
108+
)
109+
110+
111+
@pytest.mark.xfail(strict=True, reason="RED: SKILL.md not yet updated by dso-awsv")
112+
def test_skill_md_contains_justification_requirement() -> None:
113+
"""SKILL.md must require a written justification when invoking the escape hatch."""
114+
content = _read_skill()
115+
assert "justification requirement" in content, (
116+
"SKILL.md Step 3 must contain 'justification requirement' to require "
117+
"agents to document why the change-detector test escape hatch was invoked."
118+
)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""Tests for new dimensions in the implementation-plan TDD reviewer (tdd.md).
2+
3+
All tests are xfail(strict=True) — they must fail until task dso-j700 adds the
4+
'red_test_dependency' and 'exemption_justification' dimensions to tdd.md and
5+
updates the review-criteria.md schema hash.
6+
"""
7+
8+
import pathlib
9+
10+
import pytest
11+
12+
REPO_ROOT = pathlib.Path(__file__).resolve().parents[2]
13+
TDD_REVIEWER = (
14+
REPO_ROOT
15+
/ "plugins"
16+
/ "dso"
17+
/ "skills"
18+
/ "implementation-plan"
19+
/ "docs"
20+
/ "reviewers"
21+
/ "plan"
22+
/ "tdd.md"
23+
)
24+
REVIEW_CRITERIA = (
25+
REPO_ROOT
26+
/ "plugins"
27+
/ "dso"
28+
/ "skills"
29+
/ "implementation-plan"
30+
/ "docs"
31+
/ "review-criteria.md"
32+
)
33+
34+
35+
@pytest.mark.xfail(
36+
strict=True, reason="dso-j700: red_test_dependency not yet added to tdd.md"
37+
)
38+
def test_tdd_reviewer_contains_red_test_dependency() -> None:
39+
"""tdd.md must define a 'red_test_dependency' dimension.
40+
41+
This dimension will flag plans where a task's specified failing test
42+
depends on another task's code being written first (i.e., the test
43+
cannot be run RED in isolation).
44+
"""
45+
content = TDD_REVIEWER.read_text()
46+
assert "red_test_dependency" in content, (
47+
"tdd.md is missing the 'red_test_dependency' dimension. "
48+
"Task dso-j700 must add it."
49+
)
50+
51+
52+
@pytest.mark.xfail(
53+
strict=True, reason="dso-j700: exemption_justification not yet added to tdd.md"
54+
)
55+
def test_tdd_reviewer_contains_exemption_justification() -> None:
56+
"""tdd.md must define an 'exemption_justification' dimension.
57+
58+
This dimension will require reviewers to flag tasks that claim a TDD
59+
exemption without providing a written justification.
60+
"""
61+
content = TDD_REVIEWER.read_text()
62+
assert "exemption_justification" in content, (
63+
"tdd.md is missing the 'exemption_justification' dimension. "
64+
"Task dso-j700 must add it."
65+
)
66+
67+
68+
@pytest.mark.xfail(
69+
strict=True,
70+
reason="dso-j700: exemption criteria description not yet added to tdd.md",
71+
)
72+
def test_tdd_reviewer_describes_exemption_criteria() -> None:
73+
"""tdd.md must describe when TDD exemptions are acceptable.
74+
75+
Acceptable exemption criteria include: the change contains 'no conditional
76+
logic' or is a 'change-detector' test (a test that would pass vacuously).
77+
At least one of these sentinel phrases must appear in tdd.md.
78+
"""
79+
content = TDD_REVIEWER.read_text()
80+
assert "no conditional logic" in content or "change-detector" in content, (
81+
"tdd.md does not describe valid TDD exemption criteria. "
82+
"Expected 'no conditional logic' or 'change-detector' to appear. "
83+
"Task dso-j700 must add exemption criteria language."
84+
)
85+
86+
87+
@pytest.mark.xfail(
88+
strict=True,
89+
reason="dso-j700: review-criteria.md still contains old hash ae8bfc7bd9a0d7e3",
90+
)
91+
def test_review_criteria_old_hash_absent() -> None:
92+
"""review-criteria.md must not contain the stale schema hash 'ae8bfc7bd9a0d7e3'.
93+
94+
Precondition: the file exists and is non-empty (guards against vacuous pass
95+
if the file is deleted).
96+
97+
# NOTE: This test passes vacuously if review-criteria.md is deleted.
98+
# Acceptable risk — file deletion would fail other tests.
99+
"""
100+
assert REVIEW_CRITERIA.exists(), (
101+
"review-criteria.md does not exist — cannot assert hash absence."
102+
)
103+
content = REVIEW_CRITERIA.read_text()
104+
assert len(content) > 0, "review-criteria.md is empty — cannot assert hash absence."
105+
106+
assert "ae8bfc7bd9a0d7e3" not in content, (
107+
"review-criteria.md still contains the old schema hash 'ae8bfc7bd9a0d7e3'. "
108+
"Task dso-j700 must update the hash after adding new TDD dimensions."
109+
)

0 commit comments

Comments
 (0)