@@ -743,6 +743,86 @@ def test_list_json_rows_include_stack(self, spec_kit_project: Path, monkeypatch:
743743 info = json .loads (info_result .stdout )
744744 assert row ["stack" ] == info ["stack" ]
745745
746+ def test_hidden_command_layer_source_path_is_own_pack_file (
747+ self , spec_kit_project : Path
748+ ):
749+ """A hidden (non-active) command row must not report the winner's
750+ shared materialized agent output as its ``sourcePath``.
751+
752+ Both presets below register the same command name and the same
753+ agent skill name, so the tracked materialized output is a single
754+ shared file. Only the active (winning) row may report that shared
755+ file; the hidden loser row must report its own installed pack file.
756+ """
757+ pack_low = install_preset (
758+ spec_kit_project ,
759+ "aaa-low-priority-preset" ,
760+ {
761+ "commands" : [
762+ {
763+ "name" : "speckit.compliance.plan" ,
764+ "file" : "commands/speckit.compliance.plan.md" ,
765+ "description" : "Loser" ,
766+ }
767+ ]
768+ },
769+ priority = 20 ,
770+ )
771+ (pack_low / "commands" ).mkdir ()
772+ (pack_low / "commands" / "speckit.compliance.plan.md" ).write_text (
773+ "---\n description: Loser\n ---\n loser body\n " , encoding = "utf-8"
774+ )
775+ PresetRegistry (spec_kit_project / ".specify" / "presets" ).update (
776+ "aaa-low-priority-preset" ,
777+ {"registered_skills" : {"copilot" : ["speckit-compliance-plan" ]}},
778+ )
779+
780+ pack_high = install_preset (
781+ spec_kit_project ,
782+ "zzz-high-priority-preset" ,
783+ {
784+ "commands" : [
785+ {
786+ "name" : "speckit.compliance.plan" ,
787+ "file" : "commands/speckit.compliance.plan.md" ,
788+ "description" : "Winner" ,
789+ }
790+ ]
791+ },
792+ priority = 5 ,
793+ )
794+ (pack_high / "commands" ).mkdir ()
795+ (pack_high / "commands" / "speckit.compliance.plan.md" ).write_text (
796+ "---\n description: Winner\n ---\n winner body\n " , encoding = "utf-8"
797+ )
798+ PresetRegistry (spec_kit_project / ".specify" / "presets" ).update (
799+ "zzz-high-priority-preset" ,
800+ {"registered_skills" : {"copilot" : ["speckit-compliance-plan" ]}},
801+ )
802+
803+ skill_file = (
804+ spec_kit_project
805+ / ".github"
806+ / "skills"
807+ / "speckit-compliance-plan"
808+ / "SKILL.md"
809+ )
810+ skill_file .parent .mkdir (parents = True )
811+ skill_file .write_text ("---\n name: speckit-compliance-plan\n ---\n " , encoding = "utf-8" )
812+
813+ info = ArtifactCatalog (spec_kit_project ).get_artifact_info ("speckit.compliance.plan" )
814+ stack = info ["stack" ]
815+ assert stack [0 ]["active" ] is True
816+ assert stack [0 ]["sourcePath" ] == ".github/skills/speckit-compliance-plan/SKILL.md"
817+
818+ hidden_rows = [layer for layer in stack if layer ["active" ] is False ]
819+ assert hidden_rows
820+ for row in hidden_rows :
821+ assert row ["sourcePath" ] != stack [0 ]["sourcePath" ]
822+ assert row ["sourcePath" ] == (
823+ ".specify/presets/aaa-low-priority-preset/commands/speckit.compliance.plan.md"
824+ )
825+
746826 def test_list_json_stack_source_path_contract (
747827 self , spec_kit_project : Path , monkeypatch : pytest .MonkeyPatch
748828 ):
0 commit comments