Skip to content

Commit 581c3ac

Browse files
mnriemCopilot
andcommitted
test(presets): guard wrap argument-hint inheritance for unmapped command
The existing regression test for #3991 wraps `speckit.specify`, whose stem is in Claude's ARGUMENT_HINTS map. The string-injection fallback in post_process_skill_content re-adds argument-hint even when wrap composition drops it, so that test passes with or without the inheritance fix and does not actually guard the regression. Add a parallel test that wraps an extension-like command (`speckit.myfeature`) absent from ARGUMENT_HINTS, so the wrap-composition inheritance is the only path that can carry argument-hint into the SKILL.md. This test fails without the fix and passes with it. Refs #3991 Assisted-by: GitHub Copilot (model: claude-opus-4.8, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 970babe2-48cd-4c41-adae-0282d879a9ce
1 parent f19fec9 commit 581c3ac

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

tests/test_presets.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4803,6 +4803,87 @@ def test_wrap_preset_inherits_argument_hint_from_core(self, project_dir, temp_di
48034803
f"description was corrupted; parsed={parsed}"
48044804
)
48054805

4806+
def test_wrap_preset_inherits_argument_hint_for_unmapped_command(self, project_dir, temp_dir):
4807+
"""Wrap inheritance must carry argument-hint for a command NOT in ARGUMENT_HINTS.
4808+
4809+
Regression guard for issue #3991. The companion test above wraps
4810+
``speckit.specify``, whose stem is in Claude's ``ARGUMENT_HINTS`` map, so
4811+
the string-injection fallback in ``post_process_skill_content`` re-adds
4812+
``argument-hint`` even when wrap composition drops it — masking the bug.
4813+
This test wraps an extension-like command (``speckit.myfeature``) that is
4814+
absent from that map, so the *only* thing that can carry the hint into the
4815+
SKILL.md is the wrap-composition inheritance fix itself. Without the fix
4816+
the key is dropped and this test fails.
4817+
"""
4818+
core_arg_hint = "Custom hint that lives only on the core template"
4819+
preset_description = "Wrapped speckit.myfeature — extra project context added"
4820+
self._write_init_options(project_dir, ai="claude")
4821+
skills_dir = project_dir / ".claude" / "skills"
4822+
self._create_skill(skills_dir, "speckit-myfeature")
4823+
4824+
# Place a core template (extension-like command) that declares argument-hint
4825+
core_cmds = project_dir / ".specify" / "templates" / "commands"
4826+
core_cmds.mkdir(parents=True, exist_ok=True)
4827+
(core_cmds / "myfeature.md").write_text(
4828+
"---\n"
4829+
"description: Core myfeature description.\n"
4830+
f'argument-hint: "{core_arg_hint}"\n'
4831+
"---\n\n"
4832+
"Core myfeature body.\n",
4833+
encoding="utf-8",
4834+
)
4835+
4836+
# Wrap preset: only declares description (no argument-hint)
4837+
preset_dir = temp_dir / "wrap-hint-preset-unmapped"
4838+
preset_dir.mkdir()
4839+
(preset_dir / "commands").mkdir()
4840+
(preset_dir / "commands" / "speckit.myfeature.md").write_text(
4841+
"---\n"
4842+
f'description: "{preset_description}"\n'
4843+
"strategy: wrap\n"
4844+
"---\n\n"
4845+
"{CORE_TEMPLATE}\n",
4846+
encoding="utf-8",
4847+
)
4848+
manifest_data = {
4849+
"schema_version": "1.0",
4850+
"preset": {
4851+
"id": "wrap-hint-preset-unmapped",
4852+
"name": "Wrap Hint Preset Unmapped",
4853+
"version": "1.0.0",
4854+
"description": "Test wrap hint inheritance for an unmapped command",
4855+
},
4856+
"requires": {"speckit_version": ">=0.1.0"},
4857+
"provides": {
4858+
"templates": [
4859+
{
4860+
"type": "command",
4861+
"name": "speckit.myfeature",
4862+
"file": "commands/speckit.myfeature.md",
4863+
"strategy": "wrap",
4864+
}
4865+
]
4866+
},
4867+
}
4868+
import yaml as _yaml
4869+
with open(preset_dir / "preset.yml", "w") as f:
4870+
_yaml.dump(manifest_data, f)
4871+
4872+
manager = PresetManager(project_dir)
4873+
manager.install_from_directory(preset_dir, "1.0.0")
4874+
4875+
skill_file = skills_dir / "speckit-myfeature" / "SKILL.md"
4876+
assert skill_file.exists()
4877+
parsed = yaml.safe_load(skill_file.read_text(encoding="utf-8").split("---", 2)[1])
4878+
# argument-hint must be inherited from core, not dropped
4879+
assert parsed.get("argument-hint") == core_arg_hint, (
4880+
f"argument-hint was not inherited from core; parsed={parsed}"
4881+
)
4882+
# description must be exactly the preset's declared value, not concatenated
4883+
assert parsed["description"] == preset_description, (
4884+
f"description was corrupted; parsed={parsed}"
4885+
)
4886+
48064887
def test_register_skills_resolves_command_refs(self, project_dir, temp_dir):
48074888
"""Preset skill overrides must resolve __SPECKIT_COMMAND_*__ tokens (issue #2717).
48084889

0 commit comments

Comments
 (0)