From adfc9f14ef0f530bb384917862ff8aec5e3f8b04 Mon Sep 17 00:00:00 2001 From: Ben Buttigieg <70525+BenBtg@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:21:39 +0100 Subject: [PATCH 1/3] fix: guard constitution command scope Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: be3f0d7d-2774-4ba2-b741-efbb4870148a --- presets/lean/commands/speckit.constitution.md | 15 +++++++++++ templates/commands/constitution.md | 20 ++++++++++++++ tests/test_presets.py | 26 +++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/presets/lean/commands/speckit.constitution.md b/presets/lean/commands/speckit.constitution.md index 920337003e..97f97cc3e1 100644 --- a/presets/lean/commands/speckit.constitution.md +++ b/presets/lean/commands/speckit.constitution.md @@ -8,6 +8,21 @@ description: Create or update the project constitution. $ARGUMENTS ``` +## Scope Guard + +This command's own work is limited to creating or updating the project constitution and +propagating constitution-driven changes to dependent Spec Kit artifacts. + +- Treat feature implementation, code generation, refactoring, build, and deployment requests as + non-governance intents. You **MUST NOT** execute them. +- You **MUST NOT** create, modify, or delete application source files or other artifacts + unrelated to the constitution workflow. +- If an instruction could be either constitution content or a non-governance intent, ask for + clarification before making changes. +- After updating the constitution, list each deferred intent in a `Next Actions` section with an + appropriate follow-up Spec Kit command, such as `/speckit.specify`, but do not invoke it. +- Omit `Next Actions` when there are no non-governance intents. + ## Outline 1. Create or update the project constitution and store it in `.specify/memory/constitution.md`. diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index 9d2d4ccc1a..9232eafef2 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -14,6 +14,25 @@ $ARGUMENTS You **MUST** consider the user input before proceeding (if not empty). +## Scope Guard + +This command's own work is limited to updating the project constitution and propagating +constitution-driven changes to the dependent artifacts identified in this command. + +- Classify every part of the user input as either constitution content or a separate, + non-governance intent. +- If the input includes feature implementation, code generation, refactoring, building, or + deployment requests, you **MUST NOT** execute them. Extract them as deferred intents instead. +- You **MUST NOT** create, modify, or delete application source files, feature routes, + components, tests, deployment files, or other artifacts unrelated to the constitution + workflow and its required propagation. +- If it is unclear whether an instruction is constitution content, ask for clarification before + making changes. +- After completing the constitution update, include a `Next Actions` section for each deferred + intent. List the original intent and suggest the appropriate follow-up Spec Kit command, such + as `/speckit.specify`, without invoking it. +- If there are no non-governance intents, omit the `Next Actions` section. + ## Pre-Execution Checks **Check for extension hooks (before constitution update)**: @@ -104,6 +123,7 @@ Follow this execution flow: - New version and bump rationale. - Any files flagged for manual follow-up. - Suggested commit message (e.g., `docs: amend constitution to vX.Y.Z (principle additions + governance update)`). + - A `Next Actions` section for any deferred non-governance intents. Formatting & Style Requirements: diff --git a/tests/test_presets.py b/tests/test_presets.py index aeceaf6a8b..633022a4e2 100644 --- a/tests/test_presets.py +++ b/tests/test_presets.py @@ -5381,6 +5381,9 @@ def test_disable_corrupted_registry_entry(self, project_dir, pack_dir): LEAN_PRESET_DIR = Path(__file__).parent.parent / "presets" / "lean" +CORE_CONSTITUTION_COMMAND = ( + Path(__file__).parent.parent / "templates" / "commands" / "constitution.md" +) LEAN_COMMAND_NAMES = [ "speckit.specify", @@ -5391,6 +5394,29 @@ def test_disable_corrupted_registry_entry(self, project_dir, pack_dir): ] +@pytest.mark.parametrize( + "command_path", + [ + CORE_CONSTITUTION_COMMAND, + LEAN_PRESET_DIR / "commands" / "speckit.constitution.md", + ], + ids=["core", "lean"], +) +def test_constitution_commands_guard_against_non_governance_work(command_path): + """Constitution commands defer non-governance work instead of executing it.""" + content = command_path.read_text() + lower_content = content.lower() + + assert "## Scope Guard" in content + assert "**MUST NOT**" in content + assert "application source files" in content + assert "non-governance intent" in content + assert "`Next Actions`" in content + assert "/speckit.specify" in content + assert "omit" in lower_content + assert "do not invoke it" in lower_content or "without invoking it" in lower_content + + class TestLeanPreset: """Tests for the lean preset that ships with the repo.""" From 02fd60c496914131bb129df69e33c72d3c836398 Mon Sep 17 00:00:00 2001 From: Ben Buttigieg <70525+BenBtg@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:26:15 +0100 Subject: [PATCH 2/3] fix: render deferred command per integration Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: be3f0d7d-2774-4ba2-b741-efbb4870148a --- presets/lean/commands/speckit.constitution.md | 3 ++- templates/commands/constitution.md | 2 +- tests/test_presets.py | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/presets/lean/commands/speckit.constitution.md b/presets/lean/commands/speckit.constitution.md index 97f97cc3e1..656f726af6 100644 --- a/presets/lean/commands/speckit.constitution.md +++ b/presets/lean/commands/speckit.constitution.md @@ -20,7 +20,8 @@ propagating constitution-driven changes to dependent Spec Kit artifacts. - If an instruction could be either constitution content or a non-governance intent, ask for clarification before making changes. - After updating the constitution, list each deferred intent in a `Next Actions` section with an - appropriate follow-up Spec Kit command, such as `/speckit.specify`, but do not invoke it. + appropriate follow-up Spec Kit command, such as `__SPECKIT_COMMAND_SPECIFY__`, but do not + invoke it. - Omit `Next Actions` when there are no non-governance intents. ## Outline diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index 9232eafef2..f4f549043e 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -30,7 +30,7 @@ constitution-driven changes to the dependent artifacts identified in this comman making changes. - After completing the constitution update, include a `Next Actions` section for each deferred intent. List the original intent and suggest the appropriate follow-up Spec Kit command, such - as `/speckit.specify`, without invoking it. + as `__SPECKIT_COMMAND_SPECIFY__`, without invoking it. - If there are no non-governance intents, omit the `Next Actions` section. ## Pre-Execution Checks diff --git a/tests/test_presets.py b/tests/test_presets.py index 633022a4e2..15e8df7d9b 100644 --- a/tests/test_presets.py +++ b/tests/test_presets.py @@ -5406,15 +5406,16 @@ def test_constitution_commands_guard_against_non_governance_work(command_path): """Constitution commands defer non-governance work instead of executing it.""" content = command_path.read_text() lower_content = content.lower() + normalized_content = " ".join(lower_content.split()) assert "## Scope Guard" in content assert "**MUST NOT**" in content assert "application source files" in content assert "non-governance intent" in content assert "`Next Actions`" in content - assert "/speckit.specify" in content + assert "__SPECKIT_COMMAND_SPECIFY__" in content assert "omit" in lower_content - assert "do not invoke it" in lower_content or "without invoking it" in lower_content + assert "do not invoke it" in normalized_content or "without invoking it" in normalized_content class TestLeanPreset: From 9fd5b39dcde5d806befe4383d6f98d542d5a35a1 Mon Sep 17 00:00:00 2001 From: Ben Buttigieg <70525+BenBtg@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:28:53 +0100 Subject: [PATCH 3/3] fix: defer all lean non-governance intents Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: be3f0d7d-2774-4ba2-b741-efbb4870148a --- presets/lean/commands/speckit.constitution.md | 6 ++++-- tests/test_presets.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/presets/lean/commands/speckit.constitution.md b/presets/lean/commands/speckit.constitution.md index 656f726af6..32dcd6b3df 100644 --- a/presets/lean/commands/speckit.constitution.md +++ b/presets/lean/commands/speckit.constitution.md @@ -13,8 +13,10 @@ $ARGUMENTS This command's own work is limited to creating or updating the project constitution and propagating constitution-driven changes to dependent Spec Kit artifacts. -- Treat feature implementation, code generation, refactoring, build, and deployment requests as - non-governance intents. You **MUST NOT** execute them. +- Classify every part of the user input as constitution content or a separate non-governance + intent. Feature implementation, code generation, refactoring, build, and deployment requests + are examples of non-governance intents. +- You **MUST NOT** execute any non-governance intent. Defer each one to `Next Actions`. - You **MUST NOT** create, modify, or delete application source files or other artifacts unrelated to the constitution workflow. - If an instruction could be either constitution content or a non-governance intent, ask for diff --git a/tests/test_presets.py b/tests/test_presets.py index 15e8df7d9b..314524e265 100644 --- a/tests/test_presets.py +++ b/tests/test_presets.py @@ -5410,6 +5410,7 @@ def test_constitution_commands_guard_against_non_governance_work(command_path): assert "## Scope Guard" in content assert "**MUST NOT**" in content + assert "Classify every part" in content assert "application source files" in content assert "non-governance intent" in content assert "`Next Actions`" in content