Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions templates/commands/specify.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ Given that feature description, do this:
7. Identify Key Entities (if data involved)
8. Return: SUCCESS (spec ready for planning)

6. Write the specification to SPEC_FILE using the template structure, replacing placeholders with concrete details derived from the feature description (arguments) while preserving section order and headings.
7. Write the specification to SPEC_FILE using the template structure, replacing placeholders with concrete details derived from the feature description (arguments) while preserving section order and headings.

7. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria:
8. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria:

a. **Create Spec Quality Checklist**: Generate a checklist file at `SPECIFY_FEATURE_DIRECTORY/checklists/requirements.md` using the checklist template structure with these validation items:

Expand Down
39 changes: 39 additions & 0 deletions tests/test_specify_template_numbering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Regression tests for top-level step numbering in specify.md."""

import re
from pathlib import Path

REPO_ROOT = Path(__file__).parent.parent
SPECIFY_TEMPLATE = REPO_ROOT / "templates" / "commands" / "specify.md"
MAIN_LIST_START = "Given that feature description, do this:"
MAIN_LIST_END = "## Mandatory Post-Execution Hooks"


def _main_execution_ordinals(text: str) -> list[int]:
"""Extract top-level ordinals from the main execution flow."""
_, start, execution_flow = text.partition(MAIN_LIST_START)
execution_flow, end, _ = execution_flow.partition(MAIN_LIST_END)
if not start or not end:
return []

return [
int(match.group(1))
for line in execution_flow.splitlines()
if (match := re.match(r"^(\d+)\. ", line))
]


def test_main_execution_list_has_no_duplicate_ordinals():
"""The main execution list must not reuse a step number."""
ordinals = _main_execution_ordinals(SPECIFY_TEMPLATE.read_text(encoding="utf-8"))
duplicates = {ordinal for ordinal in ordinals if ordinals.count(ordinal) > 1}

assert not duplicates, f"Duplicate top-level ordinals found: {sorted(duplicates)}"


def test_main_execution_list_is_sequential():
"""The main execution list must run from 1 through N without gaps."""
ordinals = _main_execution_ordinals(SPECIFY_TEMPLATE.read_text(encoding="utf-8"))

assert ordinals, "Could not find the main execution list in specify.md"
assert ordinals == list(range(1, 9))