prizmkit 1.1.153 → 1.1.155

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/codex/skill-adapter.js +1 -1
  3. package/bundled/adapters/pi/skill-adapter.js +2 -1
  4. package/bundled/dev-pipeline/.env.example +2 -6
  5. package/bundled/dev-pipeline/README.md +120 -113
  6. package/bundled/dev-pipeline/assets/skill-subagent-integration.md +1 -1
  7. package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +355 -15
  8. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +189 -110
  9. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +146 -111
  10. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +4 -20
  11. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
  12. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +0 -1
  13. package/bundled/dev-pipeline/prizmkit_runtime/paths.py +0 -3
  14. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +122 -15
  15. package/bundled/dev-pipeline/prizmkit_runtime/reset_preserve.py +1 -1
  16. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
  17. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +1 -10
  18. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
  19. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +139 -74
  20. package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
  21. package/bundled/dev-pipeline/prizmkit_runtime/status.py +106 -1
  22. package/bundled/dev-pipeline/prizmkit_runtime/test_result.py +64 -11
  23. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +145 -367
  24. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +91 -62
  25. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +105 -69
  26. package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +2 -2
  27. package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
  28. package/bundled/dev-pipeline/scripts/update-bug-status.py +197 -71
  29. package/bundled/dev-pipeline/scripts/update-checkpoint.py +77 -16
  30. package/bundled/dev-pipeline/scripts/update-feature-status.py +46 -121
  31. package/bundled/dev-pipeline/scripts/update-refactor-status.py +46 -123
  32. package/bundled/dev-pipeline/scripts/utils.py +119 -0
  33. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +22 -27
  34. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +71 -104
  35. package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +3 -2
  36. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +59 -111
  37. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +37 -72
  38. package/bundled/dev-pipeline/templates/sections/artifact-manifest.md +39 -0
  39. package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +3 -1
  40. package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +8 -25
  41. package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +3 -3
  42. package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +2 -2
  43. package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +3 -3
  44. package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +2 -2
  45. package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +4 -4
  46. package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +0 -1
  47. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +7 -4
  48. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +14 -27
  49. package/bundled/dev-pipeline/templates/sections/feature-completion-summary.md +20 -0
  50. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -71
  51. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
  52. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +3 -3
  53. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -4
  54. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +5 -17
  55. package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +3 -1
  56. package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +10 -23
  57. package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +2 -2
  58. package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +2 -2
  59. package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +3 -3
  60. package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +2 -2
  61. package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +7 -7
  62. package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +0 -1
  63. package/bundled/dev-pipeline/templates/sections/retrospective.md +12 -0
  64. package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +35 -0
  65. package/bundled/dev-pipeline/templates/session-status-schema.json +45 -62
  66. package/bundled/dev-pipeline/tests/test_auto_skip.py +111 -32
  67. package/bundled/dev-pipeline/tests/test_checkpoint_state.py +617 -30
  68. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -194
  69. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +62 -23
  70. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +76 -28
  71. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +281 -206
  72. package/bundled/dev-pipeline/tests/test_recovery_workflow.py +322 -0
  73. package/bundled/dev-pipeline/tests/test_reset_modes.py +935 -0
  74. package/bundled/dev-pipeline/tests/test_reset_preserve.py +5 -7
  75. package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
  76. package/bundled/dev-pipeline/tests/test_unified_cli.py +617 -188
  77. package/bundled/skills/_metadata.json +9 -9
  78. package/bundled/skills/app-planner/SKILL.md +3 -3
  79. package/bundled/skills/app-planner/references/generated-plan-review.md +2 -1
  80. package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +56 -64
  81. package/bundled/skills/app-planner/references/rules/backend/fixed-rules.md +85 -240
  82. package/bundled/skills/app-planner/references/rules/backend/question-bank.md +25 -25
  83. package/bundled/skills/app-planner/references/rules/backend/question-manifest.json +16 -7
  84. package/bundled/skills/app-planner/references/rules/backend/template.md +74 -92
  85. package/bundled/skills/app-planner/references/rules/database/derivation-rules.md +93 -93
  86. package/bundled/skills/app-planner/references/rules/database/fixed-rules.md +66 -173
  87. package/bundled/skills/app-planner/references/rules/database/question-bank.md +31 -26
  88. package/bundled/skills/app-planner/references/rules/database/question-manifest.json +13 -4
  89. package/bundled/skills/app-planner/references/rules/database/template.md +76 -98
  90. package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +68 -95
  91. package/bundled/skills/app-planner/references/rules/frontend/fixed-rules.md +93 -166
  92. package/bundled/skills/app-planner/references/rules/frontend/question-bank.md +46 -36
  93. package/bundled/skills/app-planner/references/rules/frontend/question-manifest.json +11 -2
  94. package/bundled/skills/app-planner/references/rules/frontend/template.md +79 -257
  95. package/bundled/skills/app-planner/references/rules/mobile/derivation-rules.md +91 -99
  96. package/bundled/skills/app-planner/references/rules/mobile/fixed-rules.md +73 -246
  97. package/bundled/skills/app-planner/references/rules/mobile/question-bank.md +17 -17
  98. package/bundled/skills/app-planner/references/rules/mobile/question-manifest.json +17 -2
  99. package/bundled/skills/app-planner/references/rules/mobile/template.md +73 -85
  100. package/bundled/skills/app-planner/references/rules-configuration.md +133 -65
  101. package/bundled/skills/app-planner/scripts/validate-rules-configuration.py +291 -0
  102. package/bundled/skills/bug-planner/references/schema-validation.md +1 -1
  103. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +1 -1
  104. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +21 -13
  105. package/bundled/skills/feature-pipeline-launcher/SKILL.md +22 -14
  106. package/bundled/skills/prizmkit/SKILL.md +17 -18
  107. package/bundled/skills/prizmkit/references/workflow-state-protocol.md +22 -18
  108. package/bundled/skills/prizmkit-code-review/SKILL.md +22 -58
  109. package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +6 -6
  110. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +2 -2
  111. package/bundled/skills/prizmkit-committer/SKILL.md +82 -132
  112. package/bundled/skills/prizmkit-deploy/SKILL.md +27 -11
  113. package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +89 -0
  114. package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +44 -14
  115. package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +19 -3
  116. package/bundled/skills/prizmkit-deploy/references/database-setup.md +22 -12
  117. package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +3 -1
  118. package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +22 -6
  119. package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +49 -0
  120. package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +1 -1
  121. package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +164 -0
  122. package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +9 -8
  123. package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +6 -6
  124. package/bundled/skills/prizmkit-implement/SKILL.md +30 -66
  125. package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +4 -4
  126. package/bundled/skills/prizmkit-init/SKILL.md +4 -0
  127. package/bundled/skills/prizmkit-plan/SKILL.md +21 -64
  128. package/bundled/skills/prizmkit-plan/references/artifact-identity.md +38 -0
  129. package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +4 -4
  130. package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +5 -5
  131. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +11 -1
  132. package/bundled/skills/prizmkit-retrospective/SKILL.md +63 -77
  133. package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -3
  134. package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
  135. package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +17 -23
  136. package/bundled/skills/prizmkit-test/SKILL.md +64 -51
  137. package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +206 -0
  138. package/bundled/skills/prizmkit-test/references/independent-test-review.md +17 -9
  139. package/bundled/skills/prizmkit-test/references/test-coverage-model.md +45 -21
  140. package/bundled/skills/prizmkit-test/references/test-report-template.md +20 -13
  141. package/bundled/skills/prizmkit-workflow/SKILL.md +35 -37
  142. package/bundled/skills/prizmkit-workflow/references/artifact-identity.md +34 -0
  143. package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +22 -18
  144. package/bundled/skills/recovery-workflow/SKILL.md +9 -6
  145. package/bundled/skills/recovery-workflow/evals/evals.json +2 -2
  146. package/bundled/skills/recovery-workflow/references/detection.md +7 -6
  147. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +16 -6
  148. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +21 -13
  149. package/bundled/templates/project-memory-template.md +19 -11
  150. package/package.json +1 -1
  151. package/src/scaffold.js +33 -22
  152. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +0 -228
  153. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +0 -767
  154. package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +0 -16
  155. package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +0 -31
  156. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -7
  157. package/bundled/dev-pipeline/templates/sections/critical-paths-lite.md +0 -7
  158. package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +0 -9
  159. package/bundled/dev-pipeline/templates/sections/directory-convention-lite.md +0 -6
  160. package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +0 -15
  161. package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -61
  162. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -24
  163. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -12
  164. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -44
  165. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -25
  166. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +0 -20
  167. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +0 -20
  168. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -20
  169. package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +0 -17
  170. package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +0 -28
  171. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +0 -52
  172. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +0 -52
  173. package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +0 -174
  174. package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +0 -174
  175. package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +0 -174
  176. package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +0 -174
  177. package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +0 -174
  178. package/bundled/skills/prizmkit-test/references/external-contract-mock-guidance.md +0 -119
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env python3
2
+ """Validate app-planner Rules Configuration resources as one coherent contract."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import re
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ LAYERS = ("frontend", "backend", "database", "mobile")
13
+ SCHEMA_VERSION = "app-planner-question-manifest-v2"
14
+ REQUIRED_RENDER_CONTRACT = {
15
+ "fixed_rules_policy": "invariants_only",
16
+ "selected_decision_precedence": True,
17
+ "quick_mode_requires_explicit_authorization": True,
18
+ "unmapped_option_policy": "semantic_fallback",
19
+ "not_applicable_policy": "explicit_statement",
20
+ "conflict_policy": "fail_generation",
21
+ }
22
+ QUESTION_HEADING_RE = re.compile(r"^###\s+(Q[0-9]+[a-z]?)\.", re.MULTILINE)
23
+ PLACEHOLDER_RE = re.compile(r"\{\{\s*([A-Za-z0-9_]+)\s*\}\}")
24
+ CONDITION_RE = re.compile(
25
+ r"^(Q[0-9]+[a-z]?)\s*(?:==|!=)\s*[A-Z][A-Z0-9_-]*$"
26
+ r"|^(Q[0-9]+[a-z]?)\s+in\s+\[[A-Z][A-Z0-9_-]*(?:,\s*[A-Z][A-Z0-9_-]*)*\]$"
27
+ )
28
+ CONDITION_FIELDS = (
29
+ "required_if",
30
+ "auto_derived_when",
31
+ "dual_native_repeat_when",
32
+ "note_open_ended_when",
33
+ )
34
+ FIXED_RULE_FORBIDDEN_PATTERNS = (
35
+ "all user-facing text must use i18n keys",
36
+ "only add dependencies after explicit permission",
37
+ "all apis must follow rest conventions",
38
+ "jwt is the default authentication mechanism",
39
+ "every module must have unit tests",
40
+ "all deep links must use universal links",
41
+ )
42
+
43
+
44
+ def _load_json(path: Path) -> dict[str, Any]:
45
+ data = json.loads(path.read_text(encoding="utf-8"))
46
+ if not isinstance(data, dict):
47
+ raise ValueError("root must be a JSON object")
48
+ return data
49
+
50
+
51
+ def _as_string_list(value: object, label: str, errors: list[str]) -> list[str]:
52
+ if not isinstance(value, list) or not all(isinstance(item, str) for item in value):
53
+ errors.append(f"{label} must be an array of strings")
54
+ return []
55
+ return list(value)
56
+
57
+
58
+ def _validate_layer(rules_root: Path, layer: str, errors: list[str]) -> None:
59
+ layer_root = rules_root / layer
60
+ required_files = {
61
+ "manifest": layer_root / "question-manifest.json",
62
+ "bank": layer_root / "question-bank.md",
63
+ "fixed": layer_root / "fixed-rules.md",
64
+ "derivation": layer_root / "derivation-rules.md",
65
+ "template": layer_root / "template.md",
66
+ }
67
+ missing = [name for name, path in required_files.items() if not path.is_file()]
68
+ if missing:
69
+ errors.append(f"{layer}: missing resources: {', '.join(missing)}")
70
+ return
71
+
72
+ try:
73
+ manifest = _load_json(required_files["manifest"])
74
+ except (OSError, json.JSONDecodeError, ValueError) as exc:
75
+ errors.append(f"{layer}: invalid question-manifest.json: {exc}")
76
+ return
77
+
78
+ if manifest.get("schema_version") != SCHEMA_VERSION:
79
+ errors.append(
80
+ f"{layer}: schema_version must be {SCHEMA_VERSION!r}, "
81
+ f"got {manifest.get('schema_version')!r}"
82
+ )
83
+ if manifest.get("layer") != layer:
84
+ errors.append(f"{layer}: manifest layer must equal directory name")
85
+
86
+ render_contract = manifest.get("render_contract")
87
+ if not isinstance(render_contract, dict):
88
+ errors.append(f"{layer}: render_contract must be an object")
89
+ render_contract = {}
90
+ for key, expected in REQUIRED_RENDER_CONTRACT.items():
91
+ if render_contract.get(key) != expected:
92
+ errors.append(
93
+ f"{layer}: render_contract.{key} must be {expected!r}, "
94
+ f"got {render_contract.get(key)!r}"
95
+ )
96
+
97
+ questions = manifest.get("questions")
98
+ if not isinstance(questions, list) or not all(isinstance(item, dict) for item in questions):
99
+ errors.append(f"{layer}: questions must be an array of objects")
100
+ questions = []
101
+ question_ids = [str(item.get("id") or "") for item in questions]
102
+ if any(not question_id for question_id in question_ids):
103
+ errors.append(f"{layer}: every question must have a non-empty id")
104
+ if len(question_ids) != len(set(question_ids)):
105
+ errors.append(f"{layer}: duplicate question ids in manifest")
106
+ if manifest.get("total_questions") != len(question_ids):
107
+ errors.append(
108
+ f"{layer}: total_questions={manifest.get('total_questions')!r} "
109
+ f"does not match {len(question_ids)} manifest questions"
110
+ )
111
+
112
+ groups = manifest.get("groups")
113
+ if not isinstance(groups, list) or not all(isinstance(item, dict) for item in groups):
114
+ errors.append(f"{layer}: groups must be an array of objects")
115
+ groups = []
116
+ group_ids = {str(item.get("id") or "") for item in groups}
117
+ question_positions = {question_id: index for index, question_id in enumerate(question_ids)}
118
+ for index, question in enumerate(questions):
119
+ question_id = str(question.get("id") or "")
120
+ if question.get("group") not in group_ids:
121
+ errors.append(
122
+ f"{layer}: question {question_id!r} references unknown group "
123
+ f"{question.get('group')!r}"
124
+ )
125
+ varying_parent = question.get("options_vary_by")
126
+ if varying_parent is not None:
127
+ if not isinstance(varying_parent, str) or varying_parent not in question_positions:
128
+ errors.append(
129
+ f"{layer}: question {question_id} options_vary_by references "
130
+ f"unknown question {varying_parent!r}"
131
+ )
132
+ elif question_positions[varying_parent] >= index:
133
+ errors.append(
134
+ f"{layer}: question {question_id} options_vary_by must reference "
135
+ "an earlier question"
136
+ )
137
+ for field in CONDITION_FIELDS:
138
+ condition = question.get(field)
139
+ if condition is None:
140
+ continue
141
+ if not isinstance(condition, str):
142
+ errors.append(f"{layer}: question {question_id} {field} must be a string")
143
+ continue
144
+ match = CONDITION_RE.fullmatch(condition)
145
+ if match is None:
146
+ errors.append(
147
+ f"{layer}: question {question_id} {field} has invalid option-ID "
148
+ f"condition syntax: {condition!r}"
149
+ )
150
+ continue
151
+ referenced_question = match.group(1) or match.group(2)
152
+ if referenced_question not in question_positions:
153
+ errors.append(
154
+ f"{layer}: question {question_id} {field} references unknown "
155
+ f"question {referenced_question}"
156
+ )
157
+ elif question_positions[referenced_question] >= index:
158
+ errors.append(
159
+ f"{layer}: question {question_id} {field} must reference an earlier question"
160
+ )
161
+
162
+ bank_text = required_files["bank"].read_text(encoding="utf-8")
163
+ bank_question_ids = QUESTION_HEADING_RE.findall(bank_text)
164
+ if question_ids != bank_question_ids:
165
+ errors.append(
166
+ f"{layer}: question bank/manifest drift; manifest={question_ids}, "
167
+ f"question_bank={bank_question_ids}"
168
+ )
169
+
170
+ fallback_questions = _as_string_list(
171
+ render_contract.get("semantic_fallback_questions"),
172
+ f"{layer}: render_contract.semantic_fallback_questions",
173
+ errors,
174
+ )
175
+ if fallback_questions != question_ids:
176
+ errors.append(
177
+ f"{layer}: semantic_fallback_questions must match manifest question order; "
178
+ f"got {fallback_questions}"
179
+ )
180
+
181
+ placeholders = manifest.get("template_placeholders")
182
+ if not isinstance(placeholders, dict):
183
+ errors.append(f"{layer}: template_placeholders must be an object")
184
+ placeholders = {}
185
+ declared: set[str] = set()
186
+ for category in ("from_questions", "from_fixed_rules", "auto_generated", "metadata"):
187
+ values = _as_string_list(
188
+ placeholders.get(category),
189
+ f"{layer}: template_placeholders.{category}",
190
+ errors,
191
+ )
192
+ overlap = declared.intersection(values)
193
+ if overlap:
194
+ errors.append(
195
+ f"{layer}: placeholders declared in multiple categories: {sorted(overlap)}"
196
+ )
197
+ declared.update(values)
198
+
199
+ template_text = required_files["template"].read_text(encoding="utf-8")
200
+ actual = set(PLACEHOLDER_RE.findall(template_text))
201
+ undeclared = sorted(actual - declared)
202
+ unused = sorted(declared - actual)
203
+ if undeclared:
204
+ errors.append(f"{layer}: template has undeclared placeholders: {undeclared}")
205
+ if unused:
206
+ errors.append(f"{layer}: manifest declares unused placeholders: {unused}")
207
+ if "Generated by app-planner Rules Configuration" not in template_text:
208
+ errors.append(f"{layer}: template must identify app-planner Rules Configuration as owner")
209
+ if ".claude/skills/" in template_text:
210
+ errors.append(f"{layer}: template contains a platform-specific source pointer")
211
+ if re.search(r"generated by the `(?:frontend|backend|database|mobile)-rules` skill", template_text, re.I):
212
+ errors.append(f"{layer}: template references a retired independent layer-rules skill")
213
+
214
+ fixed_text = required_files["fixed"].read_text(encoding="utf-8")
215
+ if "POLICY_CLASS: invariant" not in fixed_text:
216
+ errors.append(f"{layer}: fixed-rules.md must declare POLICY_CLASS: invariant")
217
+ if "Selected-decision boundary" not in fixed_text:
218
+ errors.append(f"{layer}: fixed-rules.md must state the selected-decision boundary")
219
+ normalized_fixed_text = " ".join(fixed_text.lower().split())
220
+ for forbidden_pattern in FIXED_RULE_FORBIDDEN_PATTERNS:
221
+ if forbidden_pattern in normalized_fixed_text:
222
+ errors.append(
223
+ f"{layer}: fixed-rules.md contains decision-owned policy: "
224
+ f"{forbidden_pattern!r}"
225
+ )
226
+ for placeholder in placeholders.get("from_fixed_rules", []):
227
+ if f"{{{{ {placeholder} }}}}" not in fixed_text:
228
+ errors.append(
229
+ f"{layer}: fixed-rules.md has no injection mapping for {{{{ {placeholder} }}}}"
230
+ )
231
+
232
+ derivation_text = required_files["derivation"].read_text(encoding="utf-8")
233
+ if "SEMANTIC_FALLBACK_POLICY" not in derivation_text:
234
+ errors.append(f"{layer}: derivation-rules.md must define SEMANTIC_FALLBACK_POLICY")
235
+
236
+ multi_profile = manifest.get("multi_profile_contract")
237
+ if layer == "mobile":
238
+ expected_multi_profile = {
239
+ "when": "Q1 == E",
240
+ "dimensions": ["Q4", "Q6", "Q7", "Q8", "Q13", "Q14"],
241
+ "profiles": ["ios", "android"],
242
+ "output_placeholder": "platform_profiles",
243
+ }
244
+ if multi_profile != expected_multi_profile:
245
+ errors.append("mobile: multi_profile_contract does not match the dual-native contract")
246
+ if "platform_profiles" not in placeholders.get("auto_generated", []):
247
+ errors.append("mobile: platform_profiles must be an auto-generated placeholder")
248
+ elif multi_profile is not None:
249
+ errors.append(f"{layer}: multi_profile_contract is only valid for mobile")
250
+
251
+
252
+ def validate_rules_root(rules_root: Path) -> dict[str, object]:
253
+ errors: list[str] = []
254
+ if not rules_root.is_dir():
255
+ errors.append(f"rules root does not exist: {rules_root}")
256
+ else:
257
+ actual_layers = sorted(path.name for path in rules_root.iterdir() if path.is_dir())
258
+ unexpected = sorted(set(actual_layers) - set(LAYERS))
259
+ missing = sorted(set(LAYERS) - set(actual_layers))
260
+ if unexpected:
261
+ errors.append(f"unexpected rules layers: {unexpected}")
262
+ if missing:
263
+ errors.append(f"missing rules layers: {missing}")
264
+ for layer in LAYERS:
265
+ if (rules_root / layer).is_dir():
266
+ _validate_layer(rules_root, layer, errors)
267
+ return {
268
+ "valid": not errors,
269
+ "layers": list(LAYERS),
270
+ "errors": errors,
271
+ }
272
+
273
+
274
+ def main() -> int:
275
+ parser = argparse.ArgumentParser(
276
+ description="Validate app-planner Rules Configuration manifests and rendering resources."
277
+ )
278
+ parser.add_argument(
279
+ "--rules-root",
280
+ type=Path,
281
+ default=Path(__file__).resolve().parent.parent / "references" / "rules",
282
+ help="Path containing frontend/backend/database/mobile rules resources.",
283
+ )
284
+ args = parser.parse_args()
285
+ report = validate_rules_root(args.rules_root.expanduser().resolve())
286
+ print(json.dumps(report, indent=2, ensure_ascii=False))
287
+ return 0 if report["valid"] else 1
288
+
289
+
290
+ if __name__ == "__main__":
291
+ raise SystemExit(main())
@@ -17,7 +17,7 @@ Use this checklist for manual validation when `validate-bug-list.py` is not avai
17
17
  - [ ] `error_source.type`: one of `stack_trace`, `user_report`, `failed_test`, `log_pattern`, `monitoring_alert`
18
18
  - [ ] `verification_type`: one of `automated`, `manual`, `hybrid`
19
19
  - [ ] `acceptance_criteria`: non-empty array of strings
20
- - [ ] `status`: one of `pending`, `in_progress`, `completed`, `failed`, `skipped`, `needs_info`; new bugs should start as `pending`
20
+ - [ ] `status`: one of `pending`, `in_progress`, `completed`, `failed`, `skipped`, `needs_info`, `auto_skipped`; new bugs should start as `pending`, while `auto_skipped` is runtime-managed for blocked descendants
21
21
  - [ ] `dependencies` if present: array of existing `B-NNN` IDs; no self-dependencies
22
22
 
23
23
  ## Consistency Checks
@@ -29,7 +29,7 @@ from datetime import datetime, timezone
29
29
  VALID_SEVERITIES = {"critical", "high", "medium", "low"}
30
30
  VALID_SOURCE_TYPES = {"stack_trace", "user_report", "failed_test", "log_pattern", "monitoring_alert"}
31
31
  VALID_VERIFICATION_TYPES = {"automated", "manual", "hybrid"}
32
- VALID_STATUSES = {"pending", "in_progress", "completed", "failed", "skipped", "needs_info"}
32
+ VALID_STATUSES = {"pending", "in_progress", "completed", "failed", "skipped", "needs_info", "auto_skipped"}
33
33
  BUG_ID_PATTERN = re.compile(r"^B-\d{3}$")
34
34
  SCHEMA_VERSION = "dev-pipeline-bug-fix-list-v1"
35
35
 
@@ -67,7 +67,7 @@ Only the start intent uses the execution-mode and configuration rounds.
67
67
 
68
68
  Use one `AskUserQuestion` call with exactly one question:
69
69
 
70
- - **Foreground (Recommended)** — build `bugfix run`; output remains attached to the user's terminal.
70
+ - **Foreground (Recommended)** — build `run bugfix`; output remains attached to the user's terminal.
71
71
  - **Background daemon** — build `daemon bugfix start`; the runtime manages detached execution and logs.
72
72
 
73
73
  Wait for the response before asking configuration.
@@ -100,7 +100,7 @@ Foreground template:
100
100
 
101
101
  ```bash
102
102
  VERBOSE=1 MAX_RETRIES=3 \
103
- python3 ./.prizmkit/dev-pipeline/cli.py bugfix run .prizmkit/plans/bug-fix-list.json
103
+ python3 ./.prizmkit/dev-pipeline/cli.py run bugfix .prizmkit/plans/bug-fix-list.json
104
104
  ```
105
105
 
106
106
  Background template:
@@ -118,7 +118,7 @@ Return:
118
118
 
119
119
  ```bash
120
120
  python3 ./.prizmkit/dev-pipeline/cli.py daemon bugfix status
121
- python3 ./.prizmkit/dev-pipeline/cli.py bugfix status .prizmkit/plans/bug-fix-list.json
121
+ python3 ./.prizmkit/dev-pipeline/cli.py status bugfix .prizmkit/plans/bug-fix-list.json
122
122
  ```
123
123
 
124
124
  Do not infer completion from the plan file alone when runtime state may exist.
@@ -151,39 +151,47 @@ Optionally include the daemon status command for the user to run afterward. Do n
151
151
 
152
152
  ## Retry Command
153
153
 
154
- Reset changes state only; it never starts execution and rejects `--run`. Always return reset and run as separate commands.
154
+ Reset never starts execution and rejects `--run`. Every reset command must select exactly one mode: `--state-only`, `--fresh-checkout`, `--clean`, or `--preserve-runtime`. Always return reset and run as separate commands.
155
155
 
156
- A standard reset can discard uncommitted changes when the target task branch is currently checked out and records a fresh-checkout boundary. Clean reset additionally deletes the task branch and clears task history/artifacts. Preserve-runtime failed recovery instead scans the whole selected list, restores every failed root and its causal `auto_skipped` descendants, and retains valid checkout identity, sessions, checkpoints, artifacts, branches, worktrees, and WIP. If a recorded branch is missing, it creates a replacement from the recorded base, retains old artifacts for reference, and rewinds implementation-and-later checkpoint stages. Never hide these effects behind the word “retry.”
156
+ State-only recovery resets selected failed/skipped/needs-info roots and only causal `auto_skipped` descendants whose complete blocker set is recovered. It resets retry/session/continuation state but never changes checkout identity, branches, worktrees, source changes, checkpoints, or artifact files. Selecting an auto-skipped bug includes all of its transitive blocking roots; `--all` recovers all eligible chains. Fresh-checkout performs the former standard reset, can discard uncommitted changes on the active task branch, and records a new checkout boundary. Clean additionally deletes the task branch and clears task history/artifacts. Preserve-runtime scans the whole list for failed roots, retains runtime history and valid checkout/WIP, and alone may replace a missing branch from the recorded base and rewind implementation-and-later checkpoints. Never hide these effects behind the word “retry.”
157
157
 
158
158
  Use `AskUserQuestion` before constructing retry commands:
159
159
 
160
- - **Preserve failed runtime (Recommended for continuing failed work)** — recover all failed chains in the selected list without cleanup, then run the list; disclose that this is whole-list recovery rather than a single-ID reset.
161
- - **Standard fresh retry** — reset one bug, then run that bug separately; warn that the active task branch can lose uncommitted changes.
160
+ - **State-only causal recovery** — recover one bug closure, or all closures with `--all`, while preserving Git/checkouts/checkpoints/artifact files.
161
+ - **Preserve failed runtime (Recommended for continuing failed work)** — recover all failed chains without cleanup while retaining history and continuation evidence; disclose that this is whole-list failed-only recovery.
162
+ - **Fresh-checkout retry** — reset one bug, then run it separately; warn that the active task branch can lose uncommitted changes.
162
163
  - **Clean retry** — reset one bug, delete its task branch/history/artifacts, then run it separately.
163
164
  - **Cancel** — return no reset or run command.
164
165
 
166
+ State-only template:
167
+
168
+ ```bash
169
+ python3 ./.prizmkit/dev-pipeline/cli.py reset bugfix B-001 --state-only .prizmkit/plans/bug-fix-list.json
170
+ python3 ./.prizmkit/dev-pipeline/cli.py run bugfix B-001 .prizmkit/plans/bug-fix-list.json
171
+ ```
172
+
165
173
  Preserve-runtime template:
166
174
 
167
175
  ```bash
168
176
  python3 ./.prizmkit/dev-pipeline/cli.py reset bugfix --failed --preserve-runtime .prizmkit/plans/bug-fix-list.json
169
- python3 ./.prizmkit/dev-pipeline/cli.py bugfix run .prizmkit/plans/bug-fix-list.json
177
+ python3 ./.prizmkit/dev-pipeline/cli.py run bugfix .prizmkit/plans/bug-fix-list.json
170
178
  ```
171
179
 
172
- Standard template:
180
+ Fresh-checkout template:
173
181
 
174
182
  ```bash
175
- python3 ./.prizmkit/dev-pipeline/cli.py reset bugfix B-001 .prizmkit/plans/bug-fix-list.json
176
- python3 ./.prizmkit/dev-pipeline/cli.py bugfix run B-001 .prizmkit/plans/bug-fix-list.json
183
+ python3 ./.prizmkit/dev-pipeline/cli.py reset bugfix B-001 --fresh-checkout .prizmkit/plans/bug-fix-list.json
184
+ python3 ./.prizmkit/dev-pipeline/cli.py run bugfix B-001 .prizmkit/plans/bug-fix-list.json
177
185
  ```
178
186
 
179
187
  Clean template:
180
188
 
181
189
  ```bash
182
190
  python3 ./.prizmkit/dev-pipeline/cli.py reset bugfix B-001 --clean .prizmkit/plans/bug-fix-list.json
183
- python3 ./.prizmkit/dev-pipeline/cli.py bugfix run B-001 .prizmkit/plans/bug-fix-list.json
191
+ python3 ./.prizmkit/dev-pipeline/cli.py run bugfix B-001 .prizmkit/plans/bug-fix-list.json
184
192
  ```
185
193
 
186
- `--preserve-runtime` requires `--failed` and cannot be combined with `--clean`, an ID, a range, or another reset filter. Retry-budget flags such as `--max-retries` and `--max-infra-retries` belong on the run command, never reset. For clean retry, require explicit acknowledgement of branch deletion and possible uncommitted-change loss before displaying either command.
194
+ State-only requires exactly one ID or explicit `--all` and rejects ranges/status filters. Fresh-checkout and clean accept one ID, range, or supported status filter. Preserve-runtime requires `--failed`, scans the whole list, and rejects IDs, ranges, `--all`, clean, other modes, and other filters. Retry-budget flags belong on the run command, never reset. For fresh-checkout or clean retry, require explicit acknowledgement of possible uncommitted-change loss; clean additionally requires acknowledgement of branch/history/artifact deletion.
187
195
 
188
196
  ## Output Contract
189
197
 
@@ -71,7 +71,7 @@ Only the start intent uses the execution-mode and configuration rounds.
71
71
 
72
72
  Use one `AskUserQuestion` call with exactly one question:
73
73
 
74
- - **Foreground (Recommended)** — build `feature run`; output remains attached to the user's terminal.
74
+ - **Foreground (Recommended)** — build `run feature`; output remains attached to the user's terminal.
75
75
  - **Background daemon** — build `daemon feature start`; the runtime manages detached execution and logs.
76
76
 
77
77
  Wait for the response before asking configuration.
@@ -104,14 +104,14 @@ Foreground template:
104
104
 
105
105
  ```bash
106
106
  VERBOSE=1 MAX_RETRIES=3 \
107
- python3 ./.prizmkit/dev-pipeline/cli.py feature run .prizmkit/plans/feature-list.json
107
+ python3 ./.prizmkit/dev-pipeline/cli.py run feature .prizmkit/plans/feature-list.json
108
108
  ```
109
109
 
110
110
  Foreground subset template:
111
111
 
112
112
  ```bash
113
113
  VERBOSE=1 MAX_RETRIES=3 \
114
- python3 ./.prizmkit/dev-pipeline/cli.py feature run .prizmkit/plans/feature-list.json --features F-001:F-005
114
+ python3 ./.prizmkit/dev-pipeline/cli.py run feature .prizmkit/plans/feature-list.json --features F-001:F-005
115
115
  ```
116
116
 
117
117
  Background template:
@@ -136,7 +136,7 @@ Return both commands when the user asks for overall status:
136
136
 
137
137
  ```bash
138
138
  python3 ./.prizmkit/dev-pipeline/cli.py daemon feature status
139
- python3 ./.prizmkit/dev-pipeline/cli.py feature status .prizmkit/plans/feature-list.json
139
+ python3 ./.prizmkit/dev-pipeline/cli.py status feature .prizmkit/plans/feature-list.json
140
140
  ```
141
141
 
142
142
  Do not infer completion from the plan file alone when runtime state may exist.
@@ -169,39 +169,47 @@ Optionally include the daemon status command for the user to run afterward. Do n
169
169
 
170
170
  ## Retry Command
171
171
 
172
- Reset changes state only; it never starts execution and rejects `--run`. Always return reset and run as separate commands.
172
+ Reset never starts execution and rejects `--run`. Every reset command must select exactly one mode: `--state-only`, `--fresh-checkout`, `--clean`, or `--preserve-runtime`. Always return reset and run as separate commands.
173
173
 
174
- A standard reset can discard uncommitted changes when the target task branch is currently checked out and records a fresh-checkout boundary. Clean reset additionally deletes the task branch and clears task history/artifacts. Preserve-runtime failed recovery instead scans the whole selected list, restores every failed root and its causal `auto_skipped` descendants, and retains valid checkout identity, sessions, checkpoints, artifacts, branches, worktrees, and WIP. If a recorded branch is missing, it creates a replacement from the recorded base, retains old artifacts for reference, and rewinds implementation-and-later checkpoint stages. Never hide these effects behind the word “retry.”
174
+ State-only recovery resets selected failed/skipped roots and only causal `auto_skipped` descendants whose complete blocker set is recovered. It resets retry/session/continuation state but never changes checkout identity, branches, worktrees, source changes, checkpoints, or artifact files. Selecting an auto-skipped feature includes all of its transitive blocking roots; `--all` recovers all eligible chains. Fresh-checkout performs the former standard reset, can discard uncommitted changes on the active task branch, and records a new checkout boundary. Clean additionally deletes the task branch and clears task history/artifacts. Preserve-runtime scans the whole list for failed roots, retains runtime history and valid checkout/WIP, and alone may replace a missing branch from the recorded base and rewind implementation-and-later checkpoints. Never hide these effects behind the word “retry.”
175
175
 
176
176
  Use `AskUserQuestion` before constructing retry commands:
177
177
 
178
- - **Preserve failed runtime (Recommended for continuing failed work)** — recover all failed chains in the selected list without cleanup, then run the list; disclose that this is whole-list recovery rather than a single-ID reset.
179
- - **Standard fresh retry** — reset one feature, then run that feature separately; warn that the active task branch can lose uncommitted changes.
178
+ - **State-only causal recovery** — recover one feature closure, or all closures with `--all`, while preserving Git/checkouts/checkpoints/artifact files.
179
+ - **Preserve failed runtime (Recommended for continuing failed work)** — recover all failed chains without cleanup while retaining history and continuation evidence; disclose that this is whole-list failed-only recovery.
180
+ - **Fresh-checkout retry** — reset one feature, then run it separately; warn that the active task branch can lose uncommitted changes.
180
181
  - **Clean retry** — reset one feature, delete its task branch/history/artifacts, then run it separately.
181
182
  - **Cancel** — return no reset or run command.
182
183
 
184
+ State-only template:
185
+
186
+ ```bash
187
+ python3 ./.prizmkit/dev-pipeline/cli.py reset feature F-001 --state-only .prizmkit/plans/feature-list.json
188
+ python3 ./.prizmkit/dev-pipeline/cli.py run feature F-001 .prizmkit/plans/feature-list.json
189
+ ```
190
+
183
191
  Preserve-runtime template:
184
192
 
185
193
  ```bash
186
194
  python3 ./.prizmkit/dev-pipeline/cli.py reset feature --failed --preserve-runtime .prizmkit/plans/feature-list.json
187
- python3 ./.prizmkit/dev-pipeline/cli.py feature run .prizmkit/plans/feature-list.json
195
+ python3 ./.prizmkit/dev-pipeline/cli.py run feature .prizmkit/plans/feature-list.json
188
196
  ```
189
197
 
190
- Standard template:
198
+ Fresh-checkout template:
191
199
 
192
200
  ```bash
193
- python3 ./.prizmkit/dev-pipeline/cli.py reset feature F-001 .prizmkit/plans/feature-list.json
194
- python3 ./.prizmkit/dev-pipeline/cli.py feature run F-001 .prizmkit/plans/feature-list.json
201
+ python3 ./.prizmkit/dev-pipeline/cli.py reset feature F-001 --fresh-checkout .prizmkit/plans/feature-list.json
202
+ python3 ./.prizmkit/dev-pipeline/cli.py run feature F-001 .prizmkit/plans/feature-list.json
195
203
  ```
196
204
 
197
205
  Clean template:
198
206
 
199
207
  ```bash
200
208
  python3 ./.prizmkit/dev-pipeline/cli.py reset feature F-001 --clean .prizmkit/plans/feature-list.json
201
- python3 ./.prizmkit/dev-pipeline/cli.py feature run F-001 .prizmkit/plans/feature-list.json
209
+ python3 ./.prizmkit/dev-pipeline/cli.py run feature F-001 .prizmkit/plans/feature-list.json
202
210
  ```
203
211
 
204
- `--preserve-runtime` requires `--failed` and cannot be combined with `--clean`, an ID, a range, or another reset filter. Retry-budget flags such as `--max-retries` and `--max-infra-retries` belong on the run command, never reset. For clean retry, require explicit acknowledgement of branch deletion and possible uncommitted-change loss before displaying either command.
212
+ State-only requires exactly one ID or explicit `--all` and rejects ranges/status filters. Fresh-checkout and clean accept one ID, range, or supported status filter. Preserve-runtime requires `--failed`, scans the whole list, and rejects IDs, ranges, `--all`, clean, other modes, and other filters. Retry-budget flags belong on the run command, never reset. For fresh-checkout or clean retry, require explicit acknowledgement of possible uncommitted-change loss; clean additionally requires acknowledgement of branch/history/artifact deletion.
205
213
 
206
214
  ## Output Contract
207
215
 
@@ -57,7 +57,7 @@ prizmkit-plan
57
57
  → prizmkit-committer
58
58
  ```
59
59
 
60
- The lifecycle starts at `/prizmkit-plan`. For a one-entry experience, invoke `/prizmkit-workflow` with the requirement; it coordinates the same stages without replacing their responsibilities. When the host supports skill-to-skill handoff, the stages continue automatically. Otherwise, each stage writes the next semantic skill and the workflow state provides the deterministic resume context.
60
+ For a one-entry experience, invoke `/prizmkit-workflow`; it owns ordering, state, repair routing, and stage invocation without replacing stage responsibilities. Atomic Skills receive explicit stage-local input, return stage-local results, and never read or write the coordinator's state. External injected Prompts may provide the same orchestration around atomic Skills.
61
61
 
62
62
  All six stages are required for a formal requirement. A stage may choose a verification depth appropriate to the change, but it may not be silently skipped.
63
63
 
@@ -67,14 +67,14 @@ Typos, pure formatting, small documentation edits, and other explicitly low-risk
67
67
 
68
68
  ### Stage Responsibilities
69
69
 
70
- | Stage | Responsibility | Success handoff |
70
+ | Stage | Responsibility | Stage-local success |
71
71
  |---|---|---|
72
- | `prizmkit-plan` | Clarify the requirement and create/review `spec.md` and `plan.md`. | `status=completed`, `stage_result=PLAN_READY` → `prizmkit-implement` |
73
- | `prizmkit-implement` | Execute the plan tasks and record completion. | `status=completed`, `stage_result=IMPLEMENTED` → `prizmkit-code-review` |
74
- | `prizmkit-code-review` | Main Agent reviews, repairs, verifies, and loops until convergence. | `status=completed`, `stage_result=REVIEW_PASS` → `prizmkit-test` |
75
- | `prizmkit-test` | Validate the final reviewed workspace with project-native tests and a consistent terminal report/result pair. | `status=completed`, `stage_result=TEST_PASS` → `prizmkit-retrospective` |
76
- | `prizmkit-retrospective` | Synchronize durable project documentation or record no documentation change. | `status=completed`, `stage_result=RETRO_COMPLETE` → `prizmkit-committer` |
77
- | `prizmkit-committer` | Verify gates, request commit confirmation, and create the local commit. | `status=completed`, `stage_result=COMMITTED` |
72
+ | `prizmkit-plan` | Clarify the requirement and create/review `spec.md` and `plan.md`. | `PLAN_READY` |
73
+ | `prizmkit-implement` | Execute supplied plan tasks and record completion. | `IMPLEMENTED` |
74
+ | `prizmkit-code-review` | Review, repair, verify, and converge on the supplied change. | `PASS` |
75
+ | `prizmkit-test` | Test the supplied change with a consistent report/result pair. | `TEST_PASS` |
76
+ | `prizmkit-retrospective` | Synchronize durable documentation or record no change. | `RETRO_COMPLETE` |
77
+ | `prizmkit-committer` | Create a confirmed interactive commit or prepare an exact Runtime request. | `COMMITTED` or `COMMIT_REQUEST_READY` |
78
78
 
79
79
  ### `prizmkit-workflow`
80
80
 
@@ -86,9 +86,8 @@ Use for a one-entry formal requirement workflow. It coordinates all six lifecycl
86
86
 
87
87
  Initialization is a soft prerequisite, not a hard dependency:
88
88
 
89
- - If project initialization is missing, `/prizmkit-plan` recommends `/prizmkit-init`.
90
- - The user may continue without initialization.
91
- - Planning then reads the source tree, README, manifests, and available project rules as fallback context.
89
+ - If project initialization is missing, the user may still invoke `/prizmkit-init` separately or continue without it.
90
+ - Planning reads the source tree, README, manifests, and available project rules as fallback context.
92
91
  - Later documentation synchronization reports when the Prizm documentation system is not initialized instead of pretending that synchronization completed.
93
92
 
94
93
  ## Independent Skills
@@ -110,7 +109,7 @@ REVIEW_NEEDS_FIXES
110
109
 
111
110
  TEST_NEEDS_FIXES
112
111
  → preserve test-report.md and test-result.json
113
- → stop with the known correction or delta-review requirement
112
+ → stop with the known correction
114
113
  → caller owns any later review/retest route
115
114
 
116
115
  TEST_BLOCKED
@@ -122,7 +121,7 @@ Automatic outer repair is limited to three rounds. The workflow stops with a res
122
121
 
123
122
  ## Commit and Deployment Boundary
124
123
 
125
- `prizmkit-committer` must not create a commit until the preceding five formal stages have succeeded. Before creating the local commit, it presents the intended files, diff summary, and Conventional Commit message and waits for user confirmation.
124
+ The active coordinator validates all required evidence before invoking `prizmkit-committer` with exact `evidence_paths` and any caller-state `excluded_paths`. Interactive use confirms and creates a local commit. Preparation use returns `COMMIT_REQUEST_READY` without Git mutation; the injected Prompt records its pending state and Python Runtime executes the request.
126
125
 
127
126
  Pushing to a remote is a separate explicit action. Deployment is always a separate invocation of `/prizmkit-deploy`.
128
127
 
@@ -131,10 +130,10 @@ Pushing to a remote is a separate explicit action. Deployment is always a separa
131
130
  An active requirement may use:
132
131
 
133
132
  ```text
134
- .prizmkit/state/workflows/<requirement-slug>.json
133
+ .prizmkit/state/workflows/<requirement-identity>.json
135
134
  ```
136
135
 
137
- This runtime state records the current stage, terminal status, repair scope, repair round, and resume entry. The skill set does not prescribe whether the target project commits, ignores, or shares this file.
136
+ `<requirement-identity>` is the validated exact basename of the active artifact directory. An existing state file that records a different artifact directory is a blocking collision and is never silently overwritten or suffixed. This coordinator-owned state records current stage, terminal status, repair scope, repair round, and resume entry. Atomic Skills do not read or write it. The target project controls whether the file is committed, ignored, or shared.
138
137
 
139
138
  Read `${SKILL_DIR}/references/workflow-state-protocol.md` for the state protocol. If the state file is missing or stale, use `spec.md`, `plan.md`, the review report, `test-report.md`, and `test-result.json` to reconstruct the safest recoverable stage and report that reconstruction.
140
139
 
@@ -152,19 +151,19 @@ Then:
152
151
  1. Optionally run /prizmkit-init when entering a project for the first time.
153
152
  2. Start a formal requirement with /prizmkit-plan.
154
153
  3. Continue through implement → code-review → test → retrospective → committer.
155
- 4. Confirm the local commit when /prizmkit-committer presents it.
154
+ 4. For interactive use, confirm the local commit when `/prizmkit-committer operation=interactive-commit` presents it; pipeline runtimes use preparation mode and execute Git themselves.
156
155
  5. Invoke /prizmkit-deploy separately when deployment or operations work is needed.
157
156
  ```
158
157
 
159
158
  ## Scope Boundary
160
159
 
161
- This toolkit is self-contained: its skills describe only this toolkit's lifecycle and independent entry points. External systems may integrate through the published skill inputs, outputs, state, and authorization contracts, but their internal architecture and names are outside this toolkit's protocol.
160
+ This toolkit is self-contained. External coordinators integrate through atomic stage inputs, stage-owned artifacts, and domain results; coordinator state and routing remain outside atomic Skill contracts.
162
161
 
163
162
  The toolkit does not promise universal automatic handoff, universal deployment automation, automatic remote push, or access beyond the host platform's permissions and environment.
164
163
 
165
164
  If the user says only "ship it", ask whether they mean:
166
165
 
167
- 1. Commit the current changes with `/prizmkit-committer`.
166
+ 1. Use `/prizmkit-committer operation=interactive-commit` for a user-confirmed local commit, or preparation mode when a Python pipeline runtime owns Git execution.
168
167
  2. Deploy or operate the project with `/prizmkit-deploy`.
169
168
 
170
169
  Do not route an ambiguous "ship it" directly to either action.