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
@@ -38,8 +38,11 @@ class ResetOptions:
38
38
  item_id: str = ""
39
39
  item_range: tuple[str, str] | None = None
40
40
  filter_mode: str = ""
41
+ state_only: bool = False
42
+ fresh_checkout: bool = False
41
43
  clean: bool = False
42
44
  preserve_runtime: bool = False
45
+ all_items: bool = False
43
46
  help_requested: bool = False
44
47
  unknown_args: tuple[str, ...] = ()
45
48
 
@@ -112,7 +115,7 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
112
115
  list_path = _resolve_list_path(options.list_path, paths.project_root)
113
116
  if not list_path.is_file():
114
117
  return CommandResult(1, f"Python {kind} reset", f"{kind} list not found: {list_path}")
115
- if not options.preserve_runtime and not (family.state_dir / "pipeline.json").is_file():
118
+ if (options.fresh_checkout or options.clean) and not (family.state_dir / "pipeline.json").is_file():
116
119
  return CommandResult(1, f"Python {kind} reset", f"No pipeline state found. Run the {kind} pipeline first to initialize.")
117
120
 
118
121
  options = ResetOptions(
@@ -120,8 +123,11 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
120
123
  item_id=options.item_id,
121
124
  item_range=options.item_range,
122
125
  filter_mode=options.filter_mode,
126
+ state_only=options.state_only,
127
+ fresh_checkout=options.fresh_checkout,
123
128
  clean=options.clean,
124
129
  preserve_runtime=options.preserve_runtime,
130
+ all_items=options.all_items,
125
131
  help_requested=options.help_requested,
126
132
  unknown_args=options.unknown_args,
127
133
  )
@@ -140,6 +146,16 @@ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> Command
140
146
  text,
141
147
  stdout=text,
142
148
  )
149
+ if options.state_only:
150
+ state_result = _run_state_only_updater(family, options, paths.project_root)
151
+ text = state_result.stdout.strip() or state_result.stderr.strip() or "State-only reset failed"
152
+ ok = state_result.returncode == 0 and _json_without_error(state_result.stdout)
153
+ return CommandResult(
154
+ 0 if ok else 1,
155
+ f"Python {kind} reset --state-only",
156
+ text,
157
+ stdout=text,
158
+ )
143
159
 
144
160
  try:
145
161
  items = _resolve_items(family, options)
@@ -174,8 +190,11 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
174
190
  item_id = ""
175
191
  item_range: tuple[str, str] | None = None
176
192
  filter_mode = ""
193
+ state_only = False
194
+ fresh_checkout = False
177
195
  clean = False
178
196
  preserve_runtime = False
197
+ all_items = False
179
198
  help_requested = False
180
199
  unknown: list[str] = []
181
200
  positional: list[str] = []
@@ -183,16 +202,22 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
183
202
  index = 0
184
203
  while index < len(args):
185
204
  arg = args[index]
186
- if arg in {"--help", "-h", "help"}:
205
+ if arg in {"--help", "-h"}:
187
206
  help_requested = True
207
+ elif arg == "--state-only":
208
+ state_only = True
209
+ elif arg == "--fresh-checkout":
210
+ fresh_checkout = True
188
211
  elif arg == "--clean":
189
212
  clean = True
190
213
  elif arg == "--preserve-runtime":
191
214
  preserve_runtime = True
215
+ elif arg == "--all":
216
+ all_items = True
192
217
  elif arg == "--run":
193
218
  raise ValueError(
194
219
  "Reset no longer accepts --run. Run reset first, then execute "
195
- f"`{family.kind} run` as a separate command."
220
+ f"`run {family.kind}` as a separate command."
196
221
  )
197
222
  elif arg in FILTER_FLAGS:
198
223
  next_filter = FILTER_FLAGS[arg]
@@ -208,9 +233,15 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
208
233
 
209
234
  for value in positional:
210
235
  if _looks_like_range(value, family.id_prefix):
211
- item_range = _normalize_range(value, family.id_prefix)
212
- elif _looks_like_item_id(value, family.id_prefix) and not item_id:
213
- item_id = _normalize_item_id(value, family.id_prefix)
236
+ if item_range is None and not item_id:
237
+ item_range = _normalize_range(value, family.id_prefix)
238
+ else:
239
+ unknown.append(value)
240
+ elif _looks_like_item_id(value, family.id_prefix):
241
+ if not item_id and item_range is None:
242
+ item_id = _normalize_item_id(value, family.id_prefix)
243
+ else:
244
+ unknown.append(value)
214
245
  elif list_path == family.plan_path:
215
246
  list_path = Path(value).expanduser()
216
247
  else:
@@ -221,8 +252,11 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
221
252
  item_id=item_id,
222
253
  item_range=item_range,
223
254
  filter_mode=filter_mode,
255
+ state_only=state_only,
256
+ fresh_checkout=fresh_checkout,
224
257
  clean=clean,
225
258
  preserve_runtime=preserve_runtime,
259
+ all_items=all_items,
226
260
  help_requested=help_requested,
227
261
  unknown_args=tuple(unknown),
228
262
  )
@@ -231,14 +265,51 @@ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> Reset
231
265
  def _reset_option_error(family: RunnerFamily, options: ResetOptions) -> str:
232
266
  if options.unknown_args:
233
267
  return "Unsupported reset arguments: " + " ".join(options.unknown_args)
234
- if not options.preserve_runtime:
268
+
269
+ selected_modes = [
270
+ name
271
+ for name, enabled in (
272
+ ("--state-only", options.state_only),
273
+ ("--fresh-checkout", options.fresh_checkout),
274
+ ("--clean", options.clean),
275
+ ("--preserve-runtime", options.preserve_runtime),
276
+ )
277
+ if enabled
278
+ ]
279
+ if len(selected_modes) != 1:
280
+ return (
281
+ "Exactly one reset mode is required: --state-only, --fresh-checkout, "
282
+ "--clean, or --preserve-runtime.\n" + _help_text(family)
283
+ )
284
+
285
+ selectors = sum(
286
+ bool(value)
287
+ for value in (
288
+ options.item_id,
289
+ options.item_range,
290
+ options.filter_mode,
291
+ options.all_items,
292
+ )
293
+ )
294
+ if options.state_only:
295
+ if options.item_range or options.filter_mode:
296
+ return "--state-only accepts only one item ID or explicit --all; ranges and status filters are unsupported."
297
+ if selectors != 1 or not (options.item_id or options.all_items):
298
+ return "--state-only requires exactly one item ID or explicit --all."
299
+ return ""
300
+
301
+ if options.fresh_checkout or options.clean:
302
+ if options.all_items:
303
+ return "--all is supported only with --state-only."
304
+ if selectors != 1:
305
+ mode = "--clean" if options.clean else "--fresh-checkout"
306
+ return f"{mode} requires exactly one item ID, range, or supported status filter."
235
307
  return ""
308
+
236
309
  if options.filter_mode != "failed":
237
310
  return "--preserve-runtime requires --failed and cannot be used with another reset filter."
238
- if options.clean:
239
- return "--preserve-runtime and --clean are mutually exclusive."
240
- if options.item_id or options.item_range:
241
- return "--preserve-runtime is a whole-list failed-chain reset and cannot target an ID or range."
311
+ if options.item_id or options.item_range or options.all_items:
312
+ return "--preserve-runtime is a whole-list failed-chain reset and cannot target an ID, range, or --all."
242
313
  return ""
243
314
 
244
315
 
@@ -282,6 +353,8 @@ def _resolve_items(family: RunnerFamily, options: ResetOptions) -> tuple[ResetIt
282
353
  for item_id in ids:
283
354
  item = by_id.get(item_id)
284
355
  if not isinstance(item, dict):
356
+ if options.item_id:
357
+ raise ValueError(f"{FAMILY_LABELS[family.kind].title()} '{item_id}' not found in {options.list_path}")
285
358
  continue
286
359
  title = str(item.get(TITLE_FIELD_BY_KIND[family.kind]) or "")
287
360
  resolved.append(ResetItem(item_id=item_id, title=title, slug=_slug_for_item(family, item_id, title), status=str(item.get("status") or "unknown")))
@@ -339,6 +412,8 @@ def _reset_one(family: RunnerFamily, item: ResetItem, options: ResetOptions, pro
339
412
  except RuntimeError as exc:
340
413
  lines.append(f"ERROR: Reset {item.item_id} checkout identity failed: {exc}")
341
414
  return False
415
+ if options.fresh_checkout:
416
+ lines.append(f"Fresh-checkout boundary published for {item.item_id}")
342
417
  lines.append(f"{item.item_id} {action} complete: status -> pending, retry count -> 0")
343
418
  return True
344
419
  error = _error_text(result.stdout) or result.stderr.strip() or "unknown"
@@ -346,6 +421,33 @@ def _reset_one(family: RunnerFamily, item: ResetItem, options: ResetOptions, pro
346
421
  return False
347
422
 
348
423
 
424
+ def _run_state_only_updater(
425
+ family: RunnerFamily,
426
+ options: ResetOptions,
427
+ project_root: Path,
428
+ ) -> subprocess.CompletedProcess[str]:
429
+ command = [
430
+ sys.executable,
431
+ str(family.updater_script),
432
+ family.list_arg,
433
+ str(options.list_path),
434
+ "--state-dir",
435
+ str(family.state_dir),
436
+ "--action",
437
+ "reset_state",
438
+ ]
439
+ if options.item_id:
440
+ command.extend([family.item_id_arg, options.item_id])
441
+ return subprocess.run(
442
+ command,
443
+ cwd=str(project_root),
444
+ stdout=subprocess.PIPE,
445
+ stderr=subprocess.PIPE,
446
+ text=True,
447
+ check=False,
448
+ )
449
+
450
+
349
451
  def _run_updater(family: RunnerFamily, action: str, options: ResetOptions, item: ResetItem, project_root: Path) -> subprocess.CompletedProcess[str]:
350
452
  command = [
351
453
  sys.executable,
@@ -455,9 +557,14 @@ def _numeric_suffix(value: str, prefix: str) -> int:
455
557
  def _help_text(family: RunnerFamily) -> str:
456
558
  label = FAMILY_LABELS[family.kind]
457
559
  return (
458
- f"Usage: prizmkit-runtime reset {family.kind} <{label}-id|range> [--clean] "
459
- "[--auto-skipped|--failed|--stalled] [list-path]\n"
560
+ f"Usage: prizmkit-runtime reset {family.kind} <{label}-id> --state-only [list-path]\n"
561
+ f" prizmkit-runtime reset {family.kind} --state-only --all [list-path]\n"
562
+ f" prizmkit-runtime reset {family.kind} <{label}-id|range> --fresh-checkout [list-path]\n"
563
+ f" prizmkit-runtime reset {family.kind} <--auto-skipped|--failed|--stalled> --fresh-checkout [list-path]\n"
564
+ f" prizmkit-runtime reset {family.kind} <{label}-id|range> --clean [list-path]\n"
565
+ f" prizmkit-runtime reset {family.kind} <--auto-skipped|--failed|--stalled> --clean [list-path]\n"
460
566
  f" prizmkit-runtime reset {family.kind} --failed --preserve-runtime [list-path]\n"
461
- "Reset changes state only and never accepts --run; execute the matching family run command separately.\n"
462
- "Standard/clean reset abandons the active checkout boundary. Preserve-runtime reset keeps task runtime and work."
567
+ "Exactly one reset mode is required. State-only preserves checkout, Git, checkpoints, and artifacts; "
568
+ "fresh-checkout publishes a new checkout boundary; clean is destructive; preserve-runtime is whole-list failed recovery.\n"
569
+ "Reset never accepts --run; execute the matching run <family> command separately."
463
570
  )
@@ -126,7 +126,7 @@ class PreserveRuntimeResetResult:
126
126
  "Existing sessions, checkpoints, artifacts, branches, worktrees, and task work were not deleted.",
127
127
  "Reset did not start a runner. Run separately:",
128
128
  "python3 ./.prizmkit/dev-pipeline/cli.py "
129
- f"{family.kind} run {shlex.quote(str(list_path))}",
129
+ f"run {family.kind} {shlex.quote(str(list_path))}",
130
130
  )
131
131
  )
132
132
  return tuple(lines)
@@ -65,6 +65,17 @@ def classify_session(
65
65
  progress_fingerprint=fingerprint,
66
66
  checkpoint_state=checkpoint.semantic_snapshot,
67
67
  )
68
+ if (
69
+ checkpoint is not None
70
+ and checkpoint.semantic_complete
71
+ and not _runtime_commit_receipt_matches(project_root, checkpoint)
72
+ ):
73
+ return SessionClassification(
74
+ "commit_missing",
75
+ reason="runtime_commit_receipt_mismatch",
76
+ progress_fingerprint=fingerprint,
77
+ checkpoint_state=checkpoint.semantic_snapshot,
78
+ )
68
79
  if _is_terminal_success(result) and checkpoint is not None and checkpoint.semantic_complete:
69
80
  return SessionClassification(
70
81
  "success",
@@ -172,6 +183,25 @@ def _is_terminal_success(result: AISessionResult) -> bool:
172
183
  )
173
184
 
174
185
 
186
+ def _runtime_commit_receipt_matches(
187
+ project_root: Path,
188
+ checkpoint: CheckpointState,
189
+ ) -> bool:
190
+ """Verify canonical Runtime receipt identity against the current Git HEAD."""
191
+ commit_hash = checkpoint.semantic.runtime_commit_hash
192
+ base_head = checkpoint.semantic.runtime_base_head
193
+ if not commit_hash and not base_head:
194
+ return True
195
+ head = run_git_command(project_root, ("rev-parse", "HEAD"))
196
+ parent = run_git_command(project_root, ("rev-parse", f"{commit_hash}^"))
197
+ return bool(
198
+ head.return_code == 0
199
+ and parent.return_code == 0
200
+ and head.stdout.strip().lower() == commit_hash.lower()
201
+ and parent.stdout.strip().lower() == base_head.lower()
202
+ )
203
+
204
+
175
205
  def _has_late_runtime_error_after_completion(
176
206
  result: AISessionResult,
177
207
  checkpoint: CheckpointState | None,
@@ -201,9 +231,27 @@ def has_branch_completion_evidence(
201
231
  working_branch: str,
202
232
  artifact_path: Path | None,
203
233
  ) -> bool:
204
- """Return true only when a task branch is ahead and semantically complete."""
205
- if not base_branch or not working_branch or not has_completed_artifact_path(artifact_path, project_root):
234
+ """Require semantic completion and matching Runtime receipt on the task branch."""
235
+ if not base_branch or not working_branch or artifact_path is None:
236
+ return False
237
+ checkpoint_path = artifact_path / "workflow-checkpoint.json"
238
+ if not checkpoint_path.is_file():
239
+ return False
240
+ checkpoint = load_checkpoint_state(checkpoint_path, project_root=project_root)
241
+ if not checkpoint.semantic_complete:
206
242
  return False
243
+ commit_hash = checkpoint.semantic.runtime_commit_hash
244
+ base_head = checkpoint.semantic.runtime_base_head
245
+ if commit_hash or base_head:
246
+ branch_head = run_git_command(project_root, ("rev-parse", working_branch))
247
+ parent = run_git_command(project_root, ("rev-parse", f"{commit_hash}^"))
248
+ if not (
249
+ branch_head.return_code == 0
250
+ and parent.return_code == 0
251
+ and branch_head.stdout.strip().lower() == commit_hash.lower()
252
+ and parent.stdout.strip().lower() == base_head.lower()
253
+ ):
254
+ return False
207
255
  return _has_commit_range(project_root, base_branch, working_branch)
208
256
 
209
257
 
@@ -79,7 +79,6 @@ class RunnerInvocation:
79
79
  item_filter: str = ""
80
80
  max_retries: int | None = None
81
81
  max_infra_retries: int = 3
82
- mode: str | None = None
83
82
  dry_run: bool = False
84
83
  clean: bool = False
85
84
  no_reset: bool = False
@@ -95,7 +94,6 @@ class PromptGenerationResult:
95
94
 
96
95
  output_path: Path
97
96
  model: str = ""
98
- pipeline_mode: str = ""
99
97
  checkpoint_path: Path | None = None
100
98
  artifact_path: Path | None = None
101
99
  raw: Mapping[str, object] = field(default_factory=dict)
@@ -273,7 +271,6 @@ def parse_invocation(
273
271
  item_filter = ""
274
272
  max_retries: int | None = None
275
273
  max_infra_retries = 3
276
- mode: str | None = None
277
274
  dry_run = False
278
275
  clean = False
279
276
  no_reset = False
@@ -285,7 +282,7 @@ def parse_invocation(
285
282
  index = 0
286
283
  while index < len(args):
287
284
  arg = args[index]
288
- if arg in {"--help", "-h", "help"}:
285
+ if arg in {"--help", "-h"}:
289
286
  help_requested = True
290
287
  elif arg == "--dry-run":
291
288
  dry_run = True
@@ -308,11 +305,6 @@ def parse_invocation(
308
305
  max_infra_retries = _safe_int(args[index], 3)
309
306
  elif arg.startswith("--max-infra-retries="):
310
307
  max_infra_retries = _safe_int(arg.split("=", 1)[1], 3)
311
- elif arg == "--mode" and index + 1 < len(args):
312
- index += 1
313
- mode = args[index]
314
- elif arg.startswith("--mode="):
315
- mode = arg.split("=", 1)[1]
316
308
  elif arg == "--resume-phase" and index + 1 < len(args):
317
309
  index += 1
318
310
  resume_phase = args[index]
@@ -339,7 +331,6 @@ def parse_invocation(
339
331
  item_filter=item_filter,
340
332
  max_retries=max_retries,
341
333
  max_infra_retries=max_infra_retries,
342
- mode=mode,
343
334
  dry_run=dry_run,
344
335
  clean=clean,
345
336
  no_reset=no_reset,
@@ -22,6 +22,7 @@ def generate_prompt(
22
22
  project_root: Path,
23
23
  execution_root: Path | None = None,
24
24
  continuation: dict[str, object] | None = None,
25
+ preview: bool = False,
25
26
  ) -> PromptGenerationResult:
26
27
  """Run the existing prompt generator and return its structured JSON result."""
27
28
  visible_root = execution_root or project_root
@@ -47,8 +48,8 @@ def generate_prompt(
47
48
  "--output",
48
49
  str(session_paths.prompt_path),
49
50
  ]
50
- if invocation.mode:
51
- command.extend(["--mode", invocation.mode])
51
+ if preview:
52
+ command.append("--no-checkpoint-write")
52
53
  if continuation:
53
54
  command.extend(["--continuation-mode", "ai_error"])
54
55
  for flag, key in (
@@ -95,7 +96,6 @@ def generate_prompt(
95
96
  return PromptGenerationResult(
96
97
  output_path=output_path,
97
98
  model=str(data.get("model") or ""),
98
- pipeline_mode=str(data.get("pipeline_mode") or ""),
99
99
  checkpoint_path=Path(str(checkpoint)) if checkpoint else None,
100
100
  artifact_path=_artifact_path(family, visible_root, item_id, data),
101
101
  raw=data,