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
@@ -1,7 +1,6 @@
1
1
  """Tests for generate-bootstrap-prompt.py core functions."""
2
2
 
3
3
  import json
4
- import importlib.util
5
4
  import os
6
5
  import re
7
6
  from argparse import Namespace
@@ -16,10 +15,8 @@ from generate_bootstrap_prompt import (
16
15
  format_ac_checklist,
17
16
  format_global_context,
18
17
  get_completed_dependencies,
19
- determine_pipeline_mode,
20
- determine_legacy_template_mode,
21
18
  process_conditional_blocks,
22
- process_mode_blocks,
19
+ process_template_blocks,
23
20
  assemble_sections,
24
21
  build_replacements,
25
22
  generate_checkpoint_definition,
@@ -87,14 +84,6 @@ def assert_complete_prompt_rendering(prompt):
87
84
  assert re.findall(r"\{\{[A-Z][A-Z_0-9]+\}\}", prompt) == []
88
85
 
89
86
 
90
- def _load_recovery_prompt_module():
91
- path = Path("dev-pipeline/scripts/generate-recovery-prompt.py")
92
- spec = importlib.util.spec_from_file_location("generate_recovery_prompt", path)
93
- module = importlib.util.module_from_spec(spec)
94
- spec.loader.exec_module(module)
95
- return module
96
-
97
-
98
87
  def test_rendered_prompt_validation_rejects_unresolved_control_placeholders():
99
88
  content = (
100
89
  "## Your Mission\n"
@@ -218,7 +207,6 @@ class TestExplicitProjectRoot:
218
207
  state_dir=str(main_checkout / ".prizmkit" / "state" / "features"),
219
208
  output=str(main_checkout / ".prizmkit" / "state" / "features" / "F-001" / "sessions" / "session-1" / "bootstrap-prompt.md"),
220
209
  template=None,
221
- mode=None,
222
210
  extract_baselines=False,
223
211
  project_root=str(execution_root),
224
212
  )
@@ -328,23 +316,6 @@ class TestGetCompletedDependencies:
328
316
  assert "no completed dependencies" in result
329
317
 
330
318
 
331
- # ---------------------------------------------------------------------------
332
- # determine_pipeline_mode
333
- # ---------------------------------------------------------------------------
334
-
335
- class TestDeterminePipelineMode:
336
- def test_all_complexities_use_unified_full_guidance(self):
337
- for complexity in ("low", "medium", "high", "critical", "banana", None):
338
- assert determine_pipeline_mode(complexity) == "full"
339
-
340
- def test_legacy_template_mode_mapping_remains_available_for_custom_templates(self):
341
- assert determine_legacy_template_mode("low") == "lite"
342
- assert determine_legacy_template_mode("medium") == "lite"
343
- assert determine_legacy_template_mode("high") == "standard"
344
- assert determine_legacy_template_mode("critical") == "full"
345
- assert determine_legacy_template_mode("banana") == "lite"
346
-
347
-
348
319
  # ---------------------------------------------------------------------------
349
320
  # process_conditional_blocks
350
321
  # ---------------------------------------------------------------------------
@@ -374,29 +345,18 @@ class TestProcessConditionalBlocks:
374
345
 
375
346
 
376
347
  # ---------------------------------------------------------------------------
377
- # process_mode_blocks
348
+ # explicit custom-template conditionals
378
349
  # ---------------------------------------------------------------------------
379
350
 
380
- class TestProcessModeBlocks:
381
- def test_lite_mode_keeps_lite(self):
382
- tpl = "{{IF_MODE_LITE}}lite content{{END_IF_MODE_LITE}}"
383
- result = process_mode_blocks(tpl, "lite", init_done=True)
384
- assert "lite content" in result
385
- assert "IF_MODE" not in result
386
-
387
- def test_lite_mode_removes_full(self):
388
- tpl = "{{IF_MODE_FULL}}full content{{END_IF_MODE_FULL}}"
389
- result = process_mode_blocks(tpl, "lite", init_done=True)
390
- assert "full content" not in result
391
-
351
+ class TestProcessTemplateBlocks:
392
352
  def test_init_done_keeps_init_done_block(self):
393
353
  tpl = "{{IF_INIT_DONE}}\ninit done\n{{END_IF_INIT_DONE}}"
394
- result = process_mode_blocks(tpl, "standard", init_done=True)
354
+ result = process_template_blocks(tpl, init_done=True)
395
355
  assert "init done" in result
396
356
 
397
357
  def test_init_needed_when_not_done(self):
398
358
  tpl = "{{IF_INIT_NEEDED}}\nneed init\n{{END_IF_INIT_NEEDED}}"
399
- result = process_mode_blocks(tpl, "standard", init_done=False)
359
+ result = process_template_blocks(tpl, init_done=False)
400
360
  assert "need init" in result
401
361
 
402
362
 
@@ -415,8 +375,7 @@ class TestScopedFeatureTestGate:
415
375
  ]
416
376
 
417
377
  @staticmethod
418
- def _write_result(root, result="TEST_PASS", *, unresolved=None,
419
- review_required=False, review_scope=None):
378
+ def _write_result(root, result="TEST_PASS", *, unresolved=None):
420
379
  artifact = root / ".prizmkit" / "specs" / "123-scope-test"
421
380
  artifact.mkdir(parents=True, exist_ok=True)
422
381
  (artifact / "test-report.md").write_text(
@@ -436,19 +395,16 @@ class TestScopedFeatureTestGate:
436
395
  },
437
396
  "repair_rounds": 0,
438
397
  "production_changed": False,
439
- "review_required": review_required,
440
- "review_scope": review_scope,
441
398
  "unresolved_items": unresolved or [],
442
399
  }
443
400
  (artifact / "test-result.json").write_text(
444
401
  json.dumps(payload), encoding="utf-8",
445
402
  )
446
403
 
447
- def test_standard_sections_insert_prizmkit_test_after_review(self):
404
+ def test_canonical_sections_insert_prizmkit_test_after_review(self):
448
405
  sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
449
406
  sections = assemble_sections(
450
- "standard", str(sections_dir), init_done=True,
451
- is_resume=False, browser_enabled=False,
407
+ str(sections_dir), init_done=True, browser_enabled=False,
452
408
  )
453
409
  names = [name for name, _ in sections]
454
410
  rendered = "\n".join(content for _, content in sections)
@@ -461,11 +417,10 @@ class TestScopedFeatureTestGate:
461
417
  assert ".prizmkit/test/evidence" not in rendered
462
418
  assert "TEST_FAIL" not in rendered
463
419
 
464
- def test_standard_sections_include_central_checkpoint_helper(self):
420
+ def test_canonical_sections_include_central_checkpoint_helper(self):
465
421
  sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
466
422
  sections = assemble_sections(
467
- "standard", str(sections_dir), init_done=True,
468
- is_resume=False, browser_enabled=False,
423
+ str(sections_dir), init_done=True, browser_enabled=False,
469
424
  )
470
425
  rendered = "\n".join(content for _, content in sections)
471
426
 
@@ -479,27 +434,82 @@ class TestScopedFeatureTestGate:
479
434
  assert "--status completed --stage-result TEST_PASS" in rendered
480
435
  assert "--status completed --stage-result RETRO_COMPLETE" in rendered
481
436
  assert "--status in_progress --stage-result COMMIT_PENDING" in rendered
482
- assert "--status completed --stage-result COMMITTED" in rendered
437
+ assert "Python runtime" in rendered
438
+ assert "alone advances this step to `completed/COMMITTED`" in rendered
483
439
  assert "Do not hand-edit `workflow-checkpoint.json` directly." in rendered
484
440
  assert "authoritative_evidence_paths" not in rendered
485
441
 
486
442
  def test_checkpoint_orders_test_after_review_with_terminal_artifacts(self):
487
443
  sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
488
444
  sections = assemble_sections(
489
- "standard", str(sections_dir), init_done=True,
490
- is_resume=False, browser_enabled=False,
445
+ str(sections_dir), init_done=True, browser_enabled=False,
491
446
  )
492
447
  checkpoint = generate_checkpoint_definition(
493
- sections, pipeline_mode="standard", workflow_type="feature-pipeline",
448
+ sections, workflow_type="feature-pipeline",
494
449
  item_id="F-123", item_slug="123-scope-test",
495
450
  session_id="F-123-session", init_done=True,
496
451
  )
497
452
  skills = [step["skill"] for step in checkpoint["steps"]]
453
+ plan_step = next(
454
+ step for step in checkpoint["steps"]
455
+ if step["skill"] == "context-snapshot-and-plan"
456
+ )
457
+ review_step = next(
458
+ step for step in checkpoint["steps"]
459
+ if step["skill"] == "prizmkit-code-review"
460
+ )
498
461
  test_step = next(step for step in checkpoint["steps"] if step["skill"] == "prizmkit-test")
499
462
 
500
463
  assert skills.index("prizmkit-code-review") < skills.index("prizmkit-test")
464
+ assert plan_step["required_artifacts"] == [
465
+ ".prizmkit/specs/123-scope-test/context-snapshot.md",
466
+ ".prizmkit/specs/123-scope-test/spec.md",
467
+ ".prizmkit/specs/123-scope-test/plan.md",
468
+ ]
469
+ assert review_step["required_artifacts"] == [
470
+ ".prizmkit/specs/123-scope-test/review-report.md"
471
+ ]
501
472
  assert test_step["required_artifacts"] == self._artifacts()
502
473
 
474
+ def test_merge_rewinds_completed_atomic_stage_without_domain_result(self, tmp_path):
475
+ existing = {
476
+ "steps": [
477
+ {
478
+ "id": "S01",
479
+ "skill": "context-snapshot-and-plan",
480
+ "status": "completed",
481
+ "required_artifacts": [],
482
+ },
483
+ {
484
+ "id": "S02",
485
+ "skill": "prizmkit-implement",
486
+ "status": "completed",
487
+ "stage_result": "IMPLEMENTED",
488
+ "required_artifacts": [],
489
+ },
490
+ ]
491
+ }
492
+ fresh = {
493
+ "steps": [
494
+ {
495
+ "id": "S01",
496
+ "skill": "context-snapshot-and-plan",
497
+ "status": "pending",
498
+ "required_artifacts": [],
499
+ },
500
+ {
501
+ "id": "S02",
502
+ "skill": "prizmkit-implement",
503
+ "status": "pending",
504
+ "required_artifacts": [],
505
+ },
506
+ ]
507
+ }
508
+
509
+ merged = merge_checkpoint_state(existing, fresh, str(tmp_path))
510
+
511
+ assert [step["status"] for step in merged["steps"]] == ["pending", "pending"]
512
+
503
513
  def test_merge_keeps_only_consistent_test_pass_artifacts(self, tmp_path):
504
514
  self._write_result(tmp_path)
505
515
  existing = {"steps": [{
@@ -536,8 +546,7 @@ class TestScopedFeatureTestGate:
536
546
  self._write_result(tmp_path)
537
547
  result_path = tmp_path / ".prizmkit/specs/123-scope-test/test-result.json"
538
548
  payload = json.loads(result_path.read_text(encoding="utf-8"))
539
- payload["review_required"] = True
540
- payload["review_scope"] = None
549
+ payload["caller_route"] = "prizmkit-code-review"
541
550
  result_path.write_text(json.dumps(payload), encoding="utf-8")
542
551
  existing = {"steps": [{
543
552
  "id": "S01", "skill": "prizmkit-test", "status": "completed",
@@ -552,21 +561,32 @@ class TestScopedFeatureTestGate:
552
561
 
553
562
  assert merged["steps"][0]["status"] == "pending"
554
563
 
555
- def test_feature_result_routing_stops_test_non_pass_without_outer_repair(self):
556
- review = route_feature_repair("REVIEW_NEEDS_FIXES", repair_round=0)
557
- needs_fixes = route_feature_repair("TEST_NEEDS_FIXES", repair_round=1)
564
+ def test_feature_result_routing_owns_bounded_outer_repair(self):
565
+ review = route_feature_repair(
566
+ "REVIEW_NEEDS_FIXES", repair_scope="production", repair_round=0,
567
+ )
568
+ needs_fixes = route_feature_repair(
569
+ "TEST_NEEDS_FIXES", repair_scope="production", repair_round=1,
570
+ )
558
571
  blocked = route_feature_repair("TEST_BLOCKED", repair_round=1)
572
+ passed = route_feature_repair("TEST_PASS", repair_round=1)
559
573
 
560
574
  assert review["route"] == [
561
575
  "prizmkit-implement", "prizmkit-code-review", "prizmkit-test",
562
576
  ]
563
577
  assert review["repair_round"] == 1
564
- assert needs_fixes["blocked"] is True
565
- assert needs_fixes["route"] == []
566
- assert needs_fixes["blocked_reason"] == "test_needs_fixes"
578
+ assert needs_fixes["blocked"] is False
579
+ assert needs_fixes["route"] == [
580
+ "prizmkit-implement", "prizmkit-code-review", "prizmkit-test",
581
+ ]
582
+ assert needs_fixes["repair_round"] == 2
567
583
  assert blocked["blocked"] is True
568
584
  assert blocked["blocked_reason"] == "test_blocked"
569
585
  assert blocked["terminal_status"] == "WORKFLOW_BLOCKED"
586
+ assert passed["route"] == ["family-report", "prizmkit-retrospective"]
587
+ assert passed["next_stage"] == "family-report"
588
+ unsafe = route_feature_repair("TEST_NEEDS_FIXES", repair_round=0)
589
+ assert unsafe["blocked_reason"] == "unsafe_repair_scope"
570
590
 
571
591
  def test_pipeline_checkpoint_metadata_rejects_legacy_or_mismatched_status(self):
572
592
  invalid = [
@@ -627,26 +647,24 @@ class TestHeadlessRecoveryReframing:
627
647
  deleted_title = "Session " + "Checkpoint Awareness"
628
648
  placeholder = "{{LOG_" + "SIZE_AWARENESS}}"
629
649
 
630
- for mode in ("lite", "standard", "full"):
631
- rendered = "\n".join(
632
- section for _name, section in assemble_sections(
633
- mode, str(sections_dir), init_done=True, is_resume=False,
634
- browser_enabled=False,
635
- )
650
+ rendered = "\n".join(
651
+ section for _name, section in assemble_sections(
652
+ str(sections_dir), init_done=True, browser_enabled=False,
636
653
  )
637
- assert deleted_title not in rendered
638
- assert placeholder not in rendered
639
- assert REMOVED_MAX_LOG_ENV not in rendered
640
- assert REMOVED_MAX_LOG_HUMAN not in rendered
641
- assert ("209" + "7152") not in rendered
642
- assert ("2" + "MB") not in rendered
643
- assert "monitor-log" not in rendered
644
- assert "COMPACT_NEEDED" not in rendered
645
- assert "log-size monitor" not in rendered
646
- assert "The log-size monitor is the only allowed" not in rendered
647
- assert "Run this command and keep it running" not in rendered
648
- assert "Execute `/compact`" not in rendered
649
- assert "run `/compact` after" not in rendered
654
+ )
655
+ assert deleted_title not in rendered
656
+ assert placeholder not in rendered
657
+ assert REMOVED_MAX_LOG_ENV not in rendered
658
+ assert REMOVED_MAX_LOG_HUMAN not in rendered
659
+ assert ("209" + "7152") not in rendered
660
+ assert ("2" + "MB") not in rendered
661
+ assert "monitor-log" not in rendered
662
+ assert "COMPACT_NEEDED" not in rendered
663
+ assert "log-size monitor" not in rendered
664
+ assert "The log-size monitor is the only allowed" not in rendered
665
+ assert "Run this command and keep it running" not in rendered
666
+ assert "Execute `/compact`" not in rendered
667
+ assert "run `/compact` after" not in rendered
650
668
 
651
669
 
652
670
  class TestDirectOrchestratorImplementationPrompts:
@@ -668,57 +686,44 @@ class TestDirectOrchestratorImplementationPrompts:
668
686
  assert (templates_dir / "agent-prompts" / FORBIDDEN_DEV_FIX_PROMPT).exists() is False
669
687
  assert (templates_dir / "agent-prompts" / FORBIDDEN_DEV_RESUME_PROMPT).exists() is False
670
688
 
671
- def test_sections_all_modes_use_direct_orchestrator_implementation(self):
689
+ def test_canonical_sections_use_direct_orchestrator_implementation(self):
672
690
  sections_dir = Path("dev-pipeline/templates/sections").resolve()
673
691
 
674
- for mode in ("lite", "standard", "full"):
675
- rendered = "\n".join(
676
- section for _name, section in assemble_sections(
677
- mode, str(sections_dir), init_done=True, is_resume=False,
678
- browser_enabled=False,
679
- )
692
+ rendered = "\n".join(
693
+ section for _name, section in assemble_sections(
694
+ str(sections_dir), init_done=True, browser_enabled=False,
680
695
  )
696
+ )
681
697
 
682
- assert "/prizmkit-implement" in rendered
683
- assert "orchestrator) execute" in rendered or "Run `/prizmkit-implement`" in rendered
684
- assert "Spawn Dev subagent" not in rendered
685
- assert "Spawn Dev agent" not in rendered
686
- assert "Implement — Dev" not in rendered
687
- assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
688
- assert "dev-implement.md" not in rendered
689
- assert FORBIDDEN_REVIEW_DEV_FIX not in rendered
690
- assert FORBIDDEN_REVIEWER_DEV_SPAWN not in rendered
691
- assert FORBIDDEN_EXPLORE_SUBAGENT not in rendered
692
- assert FORBIDDEN_TEST_CMD_PLACEHOLDER not in rendered
693
- assert FORBIDDEN_THREE_STRIKE not in rendered
694
- assert FORBIDDEN_TWENTY_STEP not in rendered
695
- assert "review-report.md" in rendered
696
- assert "Final Result" in rendered
697
- assert "low=0" not in rendered
698
- assert "Reviewer 3" not in rendered
698
+ assert "/prizmkit-implement" in rendered
699
+ assert "orchestrator) execute" in rendered or "Run `/prizmkit-implement`" in rendered
700
+ assert "Spawn Dev subagent" not in rendered
701
+ assert "Spawn Dev agent" not in rendered
702
+ assert "Implement — Dev" not in rendered
703
+ assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
704
+ assert "dev-implement.md" not in rendered
705
+ assert FORBIDDEN_REVIEW_DEV_FIX not in rendered
706
+ assert FORBIDDEN_REVIEWER_DEV_SPAWN not in rendered
707
+ assert FORBIDDEN_EXPLORE_SUBAGENT not in rendered
708
+ assert FORBIDDEN_TEST_CMD_PLACEHOLDER not in rendered
709
+ assert FORBIDDEN_THREE_STRIKE not in rendered
710
+ assert FORBIDDEN_TWENTY_STEP not in rendered
711
+ assert "review-report.md" in rendered
712
+ assert "Final Result" in rendered
713
+ assert "low=0" not in rendered
714
+ assert "Reviewer 3" not in rendered
699
715
 
700
716
  def test_all_rendered_pipeline_prompts_have_one_main_agent_review_model(self, tmp_path):
701
- recovery = _load_recovery_prompt_module()
702
717
  prompts = [
703
- _render_feature_prompt(tmp_path / "feature-lite", mode="lite"),
704
- _render_feature_prompt(tmp_path / "feature-standard", mode="standard"),
705
- _render_feature_prompt(tmp_path / "feature-full", mode="full"),
718
+ _render_feature_prompt(tmp_path / "feature-low", complexity="low"),
719
+ _render_feature_prompt(tmp_path / "feature-medium", complexity="medium"),
720
+ _render_feature_prompt(tmp_path / "feature-high", complexity="high"),
706
721
  _render_feature_prompt(
707
- tmp_path / "feature-tier3",
708
- mode="full",
722
+ tmp_path / "feature-compatibility-template",
709
723
  template="bootstrap-tier3.md",
710
724
  ),
711
725
  _render_bugfix_prompt(tmp_path / "bugfix"),
712
726
  _render_refactor_prompt(tmp_path / "refactor"),
713
- recovery.build_bugfix_prompt(
714
- {
715
- "workflow_type": "bug-fix-workflow",
716
- "phase": 5,
717
- "phase_name": "Review",
718
- "workflow_data": {"bug_id": "B-001"},
719
- },
720
- str(tmp_path),
721
- ),
722
727
  ]
723
728
 
724
729
  for prompt in prompts:
@@ -824,7 +829,6 @@ class TestContinuationHandoff:
824
829
  def test_modular_feature_prompt_renders_user_context(tmp_path):
825
830
  prompt = _render_feature_prompt(
826
831
  tmp_path / "user-context",
827
- mode="standard",
828
832
  user_context=["Use the existing event envelope", "Keep the public API backward compatible"],
829
833
  )
830
834
 
@@ -854,7 +858,7 @@ def _write_feature_list(path, feature):
854
858
  path.write_text(json.dumps({"features": [feature], "global_context": {"language": "Python"}}), encoding="utf-8")
855
859
 
856
860
 
857
- def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="claude", browser_interaction=None, complexity=None, user_context=None):
861
+ def _render_feature_prompt(tmp_path, template=None, platform="claude", browser_interaction=None, complexity=None, user_context=None, continuation_mode=None):
858
862
  project = tmp_path / "project"
859
863
  project.mkdir(parents=True)
860
864
  (project / ".prizmkit" / "plans").mkdir(parents=True)
@@ -865,7 +869,7 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
865
869
  "id": "F-123",
866
870
  "title": "Prompt Cleanup",
867
871
  "description": "Clean prompt text",
868
- "estimated_complexity": complexity or {"lite": "low", "standard": "medium", "full": "high"}[mode],
872
+ "estimated_complexity": complexity or "medium",
869
873
  "acceptance_criteria": ["Prompts are clean"],
870
874
  }
871
875
  if user_context is not None:
@@ -886,8 +890,9 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
886
890
  "--state-dir", str(project / ".prizmkit" / "state" / "features"),
887
891
  "--project-root", str(project),
888
892
  "--output", str(output),
889
- "--mode", mode,
890
893
  ]
894
+ if continuation_mode:
895
+ args.extend(["--continuation-mode", continuation_mode])
891
896
  if template:
892
897
  template_path = Path(template)
893
898
  if not template_path.is_absolute():
@@ -1045,12 +1050,11 @@ def _render_refactor_prompt(tmp_path, platform="claude", explicit_platform=None,
1045
1050
  return output.read_text(encoding="utf-8")
1046
1051
 
1047
1052
 
1048
- class TestFeaturePromptUnifiedFullGuidance:
1049
- def test_default_sections_prompt_uses_full_guidance_for_all_complexities(self, tmp_path):
1053
+ class TestFeaturePromptCanonicalGuidance:
1054
+ def test_default_sections_prompt_uses_same_guidance_for_all_complexities(self, tmp_path):
1050
1055
  prompts = {
1051
1056
  complexity: _render_feature_prompt(
1052
1057
  tmp_path / f"complexity-{complexity}",
1053
- mode="lite",
1054
1058
  complexity=complexity,
1055
1059
  )
1056
1060
  for complexity in ("low", "medium", "high", "critical")
@@ -1061,83 +1065,96 @@ class TestFeaturePromptUnifiedFullGuidance:
1061
1065
  assert "## Task Contract" in prompt
1062
1066
  assert "## Workflow Checkpoint System" in prompt
1063
1067
  assert "### Specify + Plan (Full Workflow)" in prompt
1064
- assert "### Plan Self-Check Orchestrator Direct" in prompt
1068
+ assert "The injected session validates artifact presence but does not perform a second planning review" in prompt
1065
1069
  assert "### Scoped Feature Test Gate — PrizmKit Test" in prompt
1066
- assert "## Test Failure Recovery Protocol" in prompt
1070
+ assert "## Test Failure Recovery Protocol" not in prompt
1067
1071
  assert "test-report.md" in prompt
1068
1072
  assert "test-result.json" in prompt
1069
1073
  assert "### Browser Verification — MANDATORY" not in prompt
1070
- assert "### TERMINAL STOP — Commit Completed" in prompt
1074
+ assert "### Feature Completion Summary" in prompt
1075
+ assert "### Runtime Commit Handoff" in prompt
1071
1076
  assert "# Dev-Pipeline Session Bootstrap — Tier 1" not in prompt
1072
1077
  assert "# Dev-Pipeline Session Bootstrap — Tier 2" not in prompt
1073
1078
  assert "### Phase 0: SKIP (already initialized)" not in prompt
1074
1079
 
1075
- # The complexity value remains planning metadata, but guidance markers are
1076
- # the same full/tier3-equivalent composition for every complexity.
1077
- def test_cli_mode_override_does_not_downgrade_default_sections_guidance(self, tmp_path):
1078
- prompt = _render_feature_prompt(tmp_path / "mode-lite", mode="lite", complexity="low")
1080
+ # Complexity remains planning metadata; every task gets the same guidance.
1081
+ def test_canonical_guidance_has_no_pipeline_mode_context(self, tmp_path):
1082
+ prompt = _render_feature_prompt(tmp_path / "canonical", complexity="low")
1079
1083
 
1080
1084
  assert "{{PIPELINE_MODE}}" not in prompt
1085
+ assert "compatibility mode" not in prompt
1081
1086
  assert "### Specify + Plan (Full Workflow)" in prompt
1082
- assert "### Plan Self-Check — Orchestrator Direct" in prompt
1087
+ assert "### Plan Self-Check — Orchestrator Direct" not in prompt
1088
+ assert "does not perform a second planning review" in prompt
1083
1089
  assert "### Phase 0: SKIP (already initialized)" not in prompt
1084
1090
 
1085
1091
  def test_explicit_custom_template_override_still_renders(self, tmp_path):
1086
1092
  custom = tmp_path / "custom-template.md"
1087
1093
  custom.write_text(
1088
- "CUSTOM {{FEATURE_ID}} {{FEATURE_TITLE}} {{COMPLEXITY}} {{IF_FRESH_START}}fresh{{END_IF_FRESH_START}}",
1094
+ "## Your Mission\nCUSTOM {{FEATURE_ID}} {{FEATURE_TITLE}} {{COMPLEXITY}} "
1095
+ "{{IF_FRESH_START}}fresh{{END_IF_FRESH_START}}\n\n## Execution\ncustom\n\n"
1096
+ "## Failure Capture\ncustom",
1089
1097
  encoding="utf-8",
1090
1098
  )
1091
1099
 
1092
1100
  prompt = _render_feature_prompt(
1093
1101
  tmp_path / "custom-template-project",
1094
- mode="lite",
1095
1102
  complexity="low",
1096
1103
  template=custom,
1097
1104
  )
1098
1105
 
1099
- assert prompt == "CUSTOM F-123 Prompt Cleanup low fresh"
1106
+ assert "CUSTOM F-123 Prompt Cleanup low fresh" in prompt
1107
+ checkpoint_path = (
1108
+ tmp_path / "custom-template-project" / "project" / ".prizmkit"
1109
+ / "specs" / "123-prompt-cleanup" / "workflow-checkpoint.json"
1110
+ )
1111
+ checkpoint = json.loads(checkpoint_path.read_text(encoding="utf-8"))
1112
+ assert [step["skill"] for step in checkpoint["steps"]] == [
1113
+ "prizmkit-init",
1114
+ "context-snapshot-and-plan",
1115
+ "prizmkit-implement",
1116
+ "prizmkit-code-review",
1117
+ "prizmkit-test",
1118
+ "completion-summary",
1119
+ "prizmkit-retrospective",
1120
+ "prizmkit-committer",
1121
+ ]
1100
1122
 
1101
- def test_fallback_without_sections_prefers_tier3_then_bootstrap_prompt(self, tmp_path, monkeypatch):
1123
+ def test_malformed_continuation_addendum_fails_closed(self, tmp_path, monkeypatch):
1124
+ import generate_bootstrap_prompt as gbp
1125
+
1126
+ monkeypatch.setattr(
1127
+ gbp,
1128
+ "append_continuation_handoff",
1129
+ lambda rendered, *_args, **_kwargs: rendered + "\n{{BROKEN_CONTINUATION}}",
1130
+ )
1131
+ try:
1132
+ _render_feature_prompt(
1133
+ tmp_path / "malformed-continuation",
1134
+ continuation_mode="ai_error",
1135
+ )
1136
+ except SystemExit as exc:
1137
+ assert exc.code == 1
1138
+ else:
1139
+ raise AssertionError("malformed continuation Prompt did not fail closed")
1140
+
1141
+ def test_missing_canonical_sections_fails_closed(self, tmp_path, monkeypatch):
1102
1142
  import generate_bootstrap_prompt as gbp
1103
1143
 
1104
1144
  original_isdir = os.path.isdir
1105
- original_isfile = os.path.isfile
1106
- requested = []
1107
1145
 
1108
1146
  def fake_isdir(path):
1109
1147
  if str(path).endswith(os.path.join("templates", "sections")):
1110
1148
  return False
1111
1149
  return original_isdir(path)
1112
1150
 
1113
- def fake_isfile(path):
1114
- requested.append(Path(path).name)
1115
- return original_isfile(path)
1116
-
1117
1151
  monkeypatch.setattr(gbp.os.path, "isdir", fake_isdir)
1118
- monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile)
1119
- prompt = _render_feature_prompt(tmp_path / "fallback-tier3", mode="lite", complexity="low")
1120
-
1121
- assert requested.index("bootstrap-tier3.md") < requested.index("bootstrap-prompt.md") if "bootstrap-prompt.md" in requested else True
1122
- assert "# Dev-Pipeline Session Bootstrap — Full Guidance" in prompt
1123
- assert "bootstrap-tier1.md" not in requested
1124
- assert "bootstrap-tier2.md" not in requested
1125
-
1126
- requested.clear()
1127
-
1128
- def fake_isfile_without_tier3(path):
1129
- requested.append(Path(path).name)
1130
- if Path(path).name == "bootstrap-tier3.md":
1131
- return False
1132
- return original_isfile(path)
1133
-
1134
- monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile_without_tier3)
1135
- prompt = _render_feature_prompt(tmp_path / "fallback-bootstrap-prompt", mode="lite", complexity="low")
1136
-
1137
- assert "bootstrap-tier3.md" in requested
1138
- assert "bootstrap-tier1.md" not in requested
1139
- assert "bootstrap-tier2.md" not in requested
1140
- assert "# Dev-Pipeline Fallback Bootstrap Prompt" in prompt
1152
+ try:
1153
+ _render_feature_prompt(tmp_path / "missing-sections", complexity="low")
1154
+ except SystemExit as exc:
1155
+ assert exc.code == 1
1156
+ else:
1157
+ raise AssertionError("missing canonical sections did not fail closed")
1141
1158
 
1142
1159
 
1143
1160
  class TestBrowserBlockingPromptPolicy:
@@ -1153,10 +1170,16 @@ class TestBrowserBlockingPromptPolicy:
1153
1170
  _render_refactor_prompt(tmp_path / "refactor-browser-blocking", refactor_overrides={"browser_interaction": browser_interaction}),
1154
1171
  ]
1155
1172
 
1156
- for prompt in prompts:
1173
+ test_markers = (
1174
+ "### Scoped Feature Test Gate — PrizmKit Test",
1175
+ "### Bugfix Test Gate — PrizmKit Test",
1176
+ "### Refactor Test Gate — PrizmKit Test",
1177
+ )
1178
+ for prompt, test_marker in zip(prompts, test_markers, strict=True):
1157
1179
  assert "Browser blocking policy: `true`" in prompt
1158
1180
  assert "stop before commit" in prompt
1159
1181
  assert "Failures do NOT block the commit" not in prompt
1182
+ assert prompt.index("### Browser Verification — MANDATORY") < prompt.index(test_marker)
1160
1183
 
1161
1184
  def test_feature_bugfix_refactor_nonblocking_browser_policy_continues(self, tmp_path):
1162
1185
  browser_interaction = {
@@ -1278,7 +1301,8 @@ class TestBrowserOptInPromptPolicy:
1278
1301
  assert "Manual / Hybrid Verification Gate" in prompt
1279
1302
  assert "must complete manual/hybrid verification automatically" in prompt
1280
1303
  assert "Stop before `/prizmkit-retrospective` and `/prizmkit-committer`" not in prompt
1281
- assert "### Headless Commit Authorization" in prompt
1304
+ assert "### Runtime Commit Handoff" in prompt
1305
+ assert prompt.index("Manual / Hybrid Verification Gate") < prompt.index("### Bugfix Test Gate")
1282
1306
  assert "status=\"partial\"" not in prompt
1283
1307
 
1284
1308
  def test_recovery_manual_bugfix_uses_same_automatic_policy(self, tmp_path):
@@ -1291,14 +1315,16 @@ class TestBrowserOptInPromptPolicy:
1291
1315
  assert "Manual / Hybrid Verification Gate" in prompt
1292
1316
  assert "must complete manual/hybrid verification automatically" in prompt
1293
1317
  assert "Recovery-class session: automated verification may substitute" not in prompt
1294
- assert "### Headless Commit Authorization" in prompt
1318
+ assert "### Runtime Commit Handoff" in prompt
1295
1319
 
1296
1320
 
1297
1321
  class TestHeadlessPromptCleanupF033:
1298
1322
  def test_rendered_feature_bugfix_refactor_prompts_are_clean(self, tmp_path):
1299
- prompts = []
1300
- for mode in ("lite", "standard", "full"):
1301
- prompts.append(_render_feature_prompt(tmp_path / mode, mode=mode))
1323
+ prompts = [
1324
+ _render_feature_prompt(tmp_path / "low", complexity="low"),
1325
+ _render_feature_prompt(tmp_path / "medium", complexity="medium"),
1326
+ _render_feature_prompt(tmp_path / "high", complexity="high"),
1327
+ ]
1302
1328
  prompts.append(_render_bugfix_prompt(tmp_path))
1303
1329
  prompts.append(_render_refactor_prompt(tmp_path))
1304
1330
 
@@ -1326,8 +1352,47 @@ class TestHeadlessPromptCleanupF033:
1326
1352
  assert "which " not in prompt # no which-command shell glue
1327
1353
  assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
1328
1354
 
1355
+ def test_all_families_render_shared_manifest_and_precommit_order(self, tmp_path):
1356
+ prompts = {
1357
+ "feature": _render_feature_prompt(tmp_path / "manifest-feature"),
1358
+ "bugfix": _render_bugfix_prompt(tmp_path / "manifest-bugfix"),
1359
+ "refactor": _render_refactor_prompt(tmp_path / "manifest-refactor"),
1360
+ }
1361
+ common_artifacts = (
1362
+ "spec.md",
1363
+ "plan.md",
1364
+ "context-snapshot.md",
1365
+ "review-report.md",
1366
+ "test-report.md",
1367
+ "test-result.json",
1368
+ "retrospective-result.json",
1369
+ "failure-log.md",
1370
+ "workflow-checkpoint.json",
1371
+ "runtime-commit-request.json",
1372
+ )
1373
+ test_markers = {
1374
+ "feature": "### Scoped Feature Test Gate — PrizmKit Test",
1375
+ "bugfix": "### Bugfix Test Gate — PrizmKit Test",
1376
+ "refactor": "### Refactor Test Gate — PrizmKit Test",
1377
+ }
1378
+ for family, prompt in prompts.items():
1379
+ assert "## Requirement Artifact Manifest" in prompt
1380
+ for artifact in common_artifacts:
1381
+ assert artifact in prompt
1382
+ assert "Atomic Skills write only their stage-owned artifacts and domain results" in prompt
1383
+ assert "COMMIT_REQUEST_READY" in prompt
1384
+ assert "workflow_state_path" not in prompt
1385
+ assert "outcome=RETRO_COMPLETE" in prompt
1386
+ assert "Never recreate the testing-local repair loop" in prompt
1387
+ assert prompt.index(test_markers[family]) < prompt.index("### Retrospective")
1388
+ assert prompt.index("### Retrospective") < prompt.index("### Runtime Commit Handoff")
1389
+
1390
+ assert prompts["feature"].index("### Feature Completion Summary") < prompts["feature"].index("### Retrospective")
1391
+ assert prompts["bugfix"].index("### Bug Fix Report") < prompts["bugfix"].index("### Retrospective")
1392
+ assert prompts["refactor"].index("### Refactor Report") < prompts["refactor"].index("### Retrospective")
1393
+
1329
1394
  def test_retained_tier3_template_is_clean_when_rendered(self, tmp_path):
1330
- prompt = _render_feature_prompt(tmp_path / "bootstrap-tier3.md", mode="full", template="bootstrap-tier3.md")
1395
+ prompt = _render_feature_prompt(tmp_path / "bootstrap-tier3.md", template="bootstrap-tier3.md")
1331
1396
  for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
1332
1397
  assert forbidden not in prompt
1333
1398
  assert "prizmkit-test-gate.py" not in prompt
@@ -1357,7 +1422,6 @@ class TestHeadlessPromptCleanupF033:
1357
1422
  ]
1358
1423
  prompt = _render_feature_prompt(
1359
1424
  tmp_path / "browser-bootstrap-tier3.md",
1360
- mode="full",
1361
1425
  template="bootstrap-tier3.md",
1362
1426
  browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
1363
1427
  )
@@ -1380,7 +1444,6 @@ class TestHeadlessPromptCleanupF033:
1380
1444
  bug_id="B-001", session_id="session-1", run_id="run-1",
1381
1445
  retry_count="0", resume_phase="null", state_dir=None,
1382
1446
  output="out.md", project_root=str(bug_project), template=None,
1383
- mode=None,
1384
1447
  )
1385
1448
  replacements = bugfix_build_replacements(
1386
1449
  args, {"id": "B-001", "title": "Broken"}, {}, str(Path("dev-pipeline/scripts").resolve())
@@ -1403,7 +1466,6 @@ class TestHeadlessPromptCleanupF033:
1403
1466
  bug_id="B-001", session_id="session-1", run_id="run-1",
1404
1467
  retry_count="0", resume_phase="null", state_dir=None,
1405
1468
  output="out.md", project_root=str(bug_project), template=None,
1406
- mode=None,
1407
1469
  )
1408
1470
  replacements = bugfix_build_replacements(
1409
1471
  args, {"id": "B-001", "title": "Broken"}, {}, str(Path("dev-pipeline/scripts").resolve())
@@ -1455,11 +1517,11 @@ class TestFeatureBootstrapShellExtraction:
1455
1517
  assert "text final-verdict .prizmkit/specs/123-prompt-cleanup/review-report.md" in prompt
1456
1518
 
1457
1519
  def test_rendered_section_feature_prompts_use_runtime_helper_not_extracted_bash(self, tmp_path):
1458
- for mode in ("lite", "standard", "full"):
1520
+ for complexity in ("low", "medium", "high"):
1459
1521
  prompt = _render_feature_prompt(
1460
- tmp_path / f"section-{mode}",
1461
- mode=mode,
1462
- browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
1522
+ tmp_path / f"section-{complexity}",
1523
+ complexity=complexity,
1524
+ browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
1463
1525
  )
1464
1526
 
1465
1527
  self.assert_shell_extracted_operations_removed(prompt)
@@ -1474,7 +1536,6 @@ class TestFeatureBootstrapShellExtraction:
1474
1536
  def test_rendered_retained_tier3_feature_prompt_uses_runtime_helper_not_extracted_bash(self, tmp_path):
1475
1537
  prompt = _render_feature_prompt(
1476
1538
  tmp_path / "legacy-bootstrap-tier3.md",
1477
- mode="full",
1478
1539
  template="bootstrap-tier3.md",
1479
1540
  browser_interaction={"tool": "playwright-cli", "verify_steps": ["Open the page"]},
1480
1541
  )
@@ -1488,12 +1549,18 @@ class TestFeatureBootstrapShellExtraction:
1488
1549
  def test_retained_tier3_specific_extracted_operations_map_to_helper_commands(self, tmp_path):
1489
1550
  tier3 = _render_feature_prompt(
1490
1551
  tmp_path / "legacy-tier3-helper-map",
1491
- mode="full",
1492
1552
  template="bootstrap-tier3.md",
1493
1553
  )
1494
1554
  assert "text search . --pattern \"123-prompt-cleanup\" --json" in tier3
1495
1555
  assert "text count .prizmkit/specs/123-prompt-cleanup/plan.md --pattern \"- [ ]\"" in tier3
1496
- assert "Check if feature already committed by inspecting recent git history" in tier3
1556
+ assert "/prizmkit-committer operation=prepare-runtime-commit" in tier3
1557
+ assert "Require `COMMIT_REQUEST_READY`; this session records `COMMIT_PENDING`" in tier3
1558
+ assert "The Python runtime validates the request" in tier3
1559
+ assert "all `.prizmkit/**` paths are PrizmKit-internal" in tier3
1560
+ assert "project-specific transient data must already be covered by git ignore rules" in tier3.lower()
1561
+ assert "Unknown Git-visible paths are not silently ignored" in tier3
1562
+ assert "git add" not in tier3
1563
+ assert "git commit" not in tier3
1497
1564
 
1498
1565
 
1499
1566
  # ---------------------------------------------------------------------------
@@ -1587,16 +1654,17 @@ class TestDetectTestCommands:
1587
1654
 
1588
1655
 
1589
1656
 
1590
- def test_feature_checkpoint_generation_skips_noop_and_expands_only_finalization_group():
1657
+ def test_feature_checkpoint_generation_skips_noop_and_preserves_finalization_order():
1591
1658
  from generate_bootstrap_prompt import generate_checkpoint_definition
1592
1659
 
1593
1660
  checkpoint = generate_checkpoint_definition(
1594
1661
  [
1595
1662
  ("phase0-test-baseline", "noop"),
1596
1663
  ("phase-context-snapshot", "context"),
1597
- ("phase-commit", "finalize"),
1664
+ ("feature-completion-summary", "summary"),
1665
+ ("phase-commit", "retrospective"),
1666
+ ("runtime-commit-handoff", "commit"),
1598
1667
  ],
1599
- "standard",
1600
1668
  "feature-pipeline",
1601
1669
  "F-123",
1602
1670
  "123-prompt-cleanup",
@@ -1605,9 +1673,9 @@ def test_feature_checkpoint_generation_skips_noop_and_expands_only_finalization_
1605
1673
 
1606
1674
  assert [step["skill"] for step in checkpoint["steps"]] == [
1607
1675
  "context-snapshot",
1676
+ "completion-summary",
1608
1677
  "prizmkit-retrospective",
1609
1678
  "prizmkit-committer",
1610
- "completion-summary",
1611
1679
  ]
1612
1680
  assert checkpoint["steps"][0]["depends_on"] is None
1613
1681
  assert checkpoint["steps"][1]["depends_on"] == "S01"