From ee312fa28e2851aaaf2342dad9f4836530120ef7 Mon Sep 17 00:00:00 2001 From: Ben Buttigieg <70525+BenBtg@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:23:44 +0100 Subject: [PATCH 1/2] fix: correct specify step numbering Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e20ed25-f49e-41a6-b3d9-ac8f32e4ad17 --- templates/commands/specify.md | 4 +-- tests/test_specify_template_numbering.py | 44 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/test_specify_template_numbering.py diff --git a/templates/commands/specify.md b/templates/commands/specify.md index e32fd48971..54151e8b42 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -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: diff --git a/tests/test_specify_template_numbering.py b/tests/test_specify_template_numbering.py new file mode 100644 index 0000000000..201f596c96 --- /dev/null +++ b/tests/test_specify_template_numbering.py @@ -0,0 +1,44 @@ +"""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" + + +def _main_execution_ordinals(text: str) -> list[int]: + """Extract ordinals from the first top-level numbered list.""" + ordinals: list[int] = [] + + for line in text.splitlines(): + match = re.match(r"^(\d+)\. ", line) + if not match: + continue + + ordinal = int(match.group(1)) + if not ordinals: + if ordinal == 1: + ordinals.append(ordinal) + elif ordinal == 1: + break + else: + ordinals.append(ordinal) + + return ordinals + + +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, len(ordinals) + 1)) From 28134710062b220a05d9a81cc1f3f744c77281ee Mon Sep 17 00:00:00 2001 From: Ben Buttigieg <70525+BenBtg@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:26:54 +0100 Subject: [PATCH 2/2] test: harden specify numbering regression Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e20ed25-f49e-41a6-b3d9-ac8f32e4ad17 --- tests/test_specify_template_numbering.py | 31 ++++++++++-------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/tests/test_specify_template_numbering.py b/tests/test_specify_template_numbering.py index 201f596c96..cce8991d90 100644 --- a/tests/test_specify_template_numbering.py +++ b/tests/test_specify_template_numbering.py @@ -5,27 +5,22 @@ 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 ordinals from the first top-level numbered list.""" - ordinals: 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 [] - for line in text.splitlines(): - match = re.match(r"^(\d+)\. ", line) - if not match: - continue - - ordinal = int(match.group(1)) - if not ordinals: - if ordinal == 1: - ordinals.append(ordinal) - elif ordinal == 1: - break - else: - ordinals.append(ordinal) - - return ordinals + 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(): @@ -41,4 +36,4 @@ def test_main_execution_list_is_sequential(): 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, len(ordinals) + 1)) + assert ordinals == list(range(1, 9))