prizmkit 1.1.154 → 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 (157) 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 +21 -27
  6. package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +341 -15
  7. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +0 -3
  8. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +1 -15
  9. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
  10. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
  11. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +0 -9
  12. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
  13. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +120 -22
  14. package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
  15. package/bundled/dev-pipeline/prizmkit_runtime/test_result.py +64 -11
  16. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +145 -367
  17. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +91 -62
  18. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +105 -69
  19. package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
  20. package/bundled/dev-pipeline/scripts/update-bug-status.py +1 -4
  21. package/bundled/dev-pipeline/scripts/update-checkpoint.py +61 -13
  22. package/bundled/dev-pipeline/scripts/update-feature-status.py +1 -4
  23. package/bundled/dev-pipeline/scripts/update-refactor-status.py +1 -4
  24. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +22 -27
  25. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +71 -104
  26. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +59 -111
  27. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +37 -72
  28. package/bundled/dev-pipeline/templates/sections/artifact-manifest.md +39 -0
  29. package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +3 -1
  30. package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +8 -25
  31. package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +3 -3
  32. package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +2 -2
  33. package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +3 -3
  34. package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +2 -2
  35. package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +4 -4
  36. package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +0 -1
  37. package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +7 -4
  38. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +14 -27
  39. package/bundled/dev-pipeline/templates/sections/feature-completion-summary.md +20 -0
  40. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -71
  41. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
  42. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +3 -3
  43. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -4
  44. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +5 -17
  45. package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +3 -1
  46. package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +10 -23
  47. package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +2 -2
  48. package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +2 -2
  49. package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +3 -3
  50. package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +2 -2
  51. package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +7 -7
  52. package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +0 -1
  53. package/bundled/dev-pipeline/templates/sections/retrospective.md +12 -0
  54. package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +35 -0
  55. package/bundled/dev-pipeline/templates/session-status-schema.json +45 -62
  56. package/bundled/dev-pipeline/tests/test_checkpoint_state.py +469 -18
  57. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -175
  58. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +62 -23
  59. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +76 -28
  60. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +168 -18
  61. package/bundled/dev-pipeline/tests/test_recovery_workflow.py +111 -0
  62. package/bundled/dev-pipeline/tests/test_reset_preserve.py +0 -2
  63. package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
  64. package/bundled/dev-pipeline/tests/test_unified_cli.py +167 -25
  65. package/bundled/skills/_metadata.json +9 -9
  66. package/bundled/skills/app-planner/SKILL.md +3 -3
  67. package/bundled/skills/app-planner/references/generated-plan-review.md +2 -1
  68. package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +56 -64
  69. package/bundled/skills/app-planner/references/rules/backend/fixed-rules.md +85 -240
  70. package/bundled/skills/app-planner/references/rules/backend/question-bank.md +25 -25
  71. package/bundled/skills/app-planner/references/rules/backend/question-manifest.json +16 -7
  72. package/bundled/skills/app-planner/references/rules/backend/template.md +74 -92
  73. package/bundled/skills/app-planner/references/rules/database/derivation-rules.md +93 -93
  74. package/bundled/skills/app-planner/references/rules/database/fixed-rules.md +66 -173
  75. package/bundled/skills/app-planner/references/rules/database/question-bank.md +31 -26
  76. package/bundled/skills/app-planner/references/rules/database/question-manifest.json +13 -4
  77. package/bundled/skills/app-planner/references/rules/database/template.md +76 -98
  78. package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +68 -95
  79. package/bundled/skills/app-planner/references/rules/frontend/fixed-rules.md +93 -166
  80. package/bundled/skills/app-planner/references/rules/frontend/question-bank.md +46 -36
  81. package/bundled/skills/app-planner/references/rules/frontend/question-manifest.json +11 -2
  82. package/bundled/skills/app-planner/references/rules/frontend/template.md +79 -257
  83. package/bundled/skills/app-planner/references/rules/mobile/derivation-rules.md +91 -99
  84. package/bundled/skills/app-planner/references/rules/mobile/fixed-rules.md +73 -246
  85. package/bundled/skills/app-planner/references/rules/mobile/question-bank.md +17 -17
  86. package/bundled/skills/app-planner/references/rules/mobile/question-manifest.json +17 -2
  87. package/bundled/skills/app-planner/references/rules/mobile/template.md +73 -85
  88. package/bundled/skills/app-planner/references/rules-configuration.md +133 -65
  89. package/bundled/skills/app-planner/scripts/validate-rules-configuration.py +291 -0
  90. package/bundled/skills/prizmkit/SKILL.md +17 -18
  91. package/bundled/skills/prizmkit/references/workflow-state-protocol.md +22 -18
  92. package/bundled/skills/prizmkit-code-review/SKILL.md +22 -58
  93. package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +6 -6
  94. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +2 -2
  95. package/bundled/skills/prizmkit-committer/SKILL.md +82 -132
  96. package/bundled/skills/prizmkit-deploy/SKILL.md +27 -11
  97. package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +89 -0
  98. package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +44 -14
  99. package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +19 -3
  100. package/bundled/skills/prizmkit-deploy/references/database-setup.md +22 -12
  101. package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +3 -1
  102. package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +22 -6
  103. package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +49 -0
  104. package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +1 -1
  105. package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +164 -0
  106. package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +9 -8
  107. package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +6 -6
  108. package/bundled/skills/prizmkit-implement/SKILL.md +30 -66
  109. package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +4 -4
  110. package/bundled/skills/prizmkit-init/SKILL.md +4 -0
  111. package/bundled/skills/prizmkit-plan/SKILL.md +21 -64
  112. package/bundled/skills/prizmkit-plan/references/artifact-identity.md +38 -0
  113. package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +4 -4
  114. package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +5 -5
  115. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +11 -1
  116. package/bundled/skills/prizmkit-retrospective/SKILL.md +63 -77
  117. package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -3
  118. package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
  119. package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +17 -23
  120. package/bundled/skills/prizmkit-test/SKILL.md +64 -51
  121. package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +206 -0
  122. package/bundled/skills/prizmkit-test/references/independent-test-review.md +17 -9
  123. package/bundled/skills/prizmkit-test/references/test-coverage-model.md +45 -21
  124. package/bundled/skills/prizmkit-test/references/test-report-template.md +20 -13
  125. package/bundled/skills/prizmkit-workflow/SKILL.md +35 -37
  126. package/bundled/skills/prizmkit-workflow/references/artifact-identity.md +34 -0
  127. package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +22 -18
  128. package/bundled/skills/recovery-workflow/SKILL.md +2 -1
  129. package/bundled/skills/recovery-workflow/references/detection.md +4 -3
  130. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +15 -5
  131. package/package.json +1 -1
  132. package/src/scaffold.js +33 -22
  133. package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +0 -16
  134. package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +0 -31
  135. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -7
  136. package/bundled/dev-pipeline/templates/sections/critical-paths-lite.md +0 -7
  137. package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +0 -9
  138. package/bundled/dev-pipeline/templates/sections/directory-convention-lite.md +0 -6
  139. package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +0 -15
  140. package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -61
  141. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -24
  142. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -12
  143. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -44
  144. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -25
  145. package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +0 -20
  146. package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +0 -20
  147. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -20
  148. package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +0 -17
  149. package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +0 -28
  150. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +0 -52
  151. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +0 -52
  152. package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +0 -174
  153. package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +0 -174
  154. package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +0 -174
  155. package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +0 -174
  156. package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +0 -174
  157. package/bundled/skills/prizmkit-test/references/external-contract-mock-guidance.md +0 -119
@@ -15,10 +15,8 @@ from generate_bootstrap_prompt import (
15
15
  format_ac_checklist,
16
16
  format_global_context,
17
17
  get_completed_dependencies,
18
- determine_pipeline_mode,
19
- determine_legacy_template_mode,
20
18
  process_conditional_blocks,
21
- process_mode_blocks,
19
+ process_template_blocks,
22
20
  assemble_sections,
23
21
  build_replacements,
24
22
  generate_checkpoint_definition,
@@ -209,7 +207,6 @@ class TestExplicitProjectRoot:
209
207
  state_dir=str(main_checkout / ".prizmkit" / "state" / "features"),
210
208
  output=str(main_checkout / ".prizmkit" / "state" / "features" / "F-001" / "sessions" / "session-1" / "bootstrap-prompt.md"),
211
209
  template=None,
212
- mode=None,
213
210
  extract_baselines=False,
214
211
  project_root=str(execution_root),
215
212
  )
@@ -319,23 +316,6 @@ class TestGetCompletedDependencies:
319
316
  assert "no completed dependencies" in result
320
317
 
321
318
 
322
- # ---------------------------------------------------------------------------
323
- # determine_pipeline_mode
324
- # ---------------------------------------------------------------------------
325
-
326
- class TestDeterminePipelineMode:
327
- def test_all_complexities_use_unified_full_guidance(self):
328
- for complexity in ("low", "medium", "high", "critical", "banana", None):
329
- assert determine_pipeline_mode(complexity) == "full"
330
-
331
- def test_legacy_template_mode_mapping_remains_available_for_custom_templates(self):
332
- assert determine_legacy_template_mode("low") == "lite"
333
- assert determine_legacy_template_mode("medium") == "lite"
334
- assert determine_legacy_template_mode("high") == "standard"
335
- assert determine_legacy_template_mode("critical") == "full"
336
- assert determine_legacy_template_mode("banana") == "lite"
337
-
338
-
339
319
  # ---------------------------------------------------------------------------
340
320
  # process_conditional_blocks
341
321
  # ---------------------------------------------------------------------------
@@ -365,29 +345,18 @@ class TestProcessConditionalBlocks:
365
345
 
366
346
 
367
347
  # ---------------------------------------------------------------------------
368
- # process_mode_blocks
348
+ # explicit custom-template conditionals
369
349
  # ---------------------------------------------------------------------------
370
350
 
371
- class TestProcessModeBlocks:
372
- def test_lite_mode_keeps_lite(self):
373
- tpl = "{{IF_MODE_LITE}}lite content{{END_IF_MODE_LITE}}"
374
- result = process_mode_blocks(tpl, "lite", init_done=True)
375
- assert "lite content" in result
376
- assert "IF_MODE" not in result
377
-
378
- def test_lite_mode_removes_full(self):
379
- tpl = "{{IF_MODE_FULL}}full content{{END_IF_MODE_FULL}}"
380
- result = process_mode_blocks(tpl, "lite", init_done=True)
381
- assert "full content" not in result
382
-
351
+ class TestProcessTemplateBlocks:
383
352
  def test_init_done_keeps_init_done_block(self):
384
353
  tpl = "{{IF_INIT_DONE}}\ninit done\n{{END_IF_INIT_DONE}}"
385
- result = process_mode_blocks(tpl, "standard", init_done=True)
354
+ result = process_template_blocks(tpl, init_done=True)
386
355
  assert "init done" in result
387
356
 
388
357
  def test_init_needed_when_not_done(self):
389
358
  tpl = "{{IF_INIT_NEEDED}}\nneed init\n{{END_IF_INIT_NEEDED}}"
390
- result = process_mode_blocks(tpl, "standard", init_done=False)
359
+ result = process_template_blocks(tpl, init_done=False)
391
360
  assert "need init" in result
392
361
 
393
362
 
@@ -406,8 +375,7 @@ class TestScopedFeatureTestGate:
406
375
  ]
407
376
 
408
377
  @staticmethod
409
- def _write_result(root, result="TEST_PASS", *, unresolved=None,
410
- review_required=False, review_scope=None):
378
+ def _write_result(root, result="TEST_PASS", *, unresolved=None):
411
379
  artifact = root / ".prizmkit" / "specs" / "123-scope-test"
412
380
  artifact.mkdir(parents=True, exist_ok=True)
413
381
  (artifact / "test-report.md").write_text(
@@ -427,19 +395,16 @@ class TestScopedFeatureTestGate:
427
395
  },
428
396
  "repair_rounds": 0,
429
397
  "production_changed": False,
430
- "review_required": review_required,
431
- "review_scope": review_scope,
432
398
  "unresolved_items": unresolved or [],
433
399
  }
434
400
  (artifact / "test-result.json").write_text(
435
401
  json.dumps(payload), encoding="utf-8",
436
402
  )
437
403
 
438
- def test_standard_sections_insert_prizmkit_test_after_review(self):
404
+ def test_canonical_sections_insert_prizmkit_test_after_review(self):
439
405
  sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
440
406
  sections = assemble_sections(
441
- "standard", str(sections_dir), init_done=True,
442
- is_resume=False, browser_enabled=False,
407
+ str(sections_dir), init_done=True, browser_enabled=False,
443
408
  )
444
409
  names = [name for name, _ in sections]
445
410
  rendered = "\n".join(content for _, content in sections)
@@ -452,11 +417,10 @@ class TestScopedFeatureTestGate:
452
417
  assert ".prizmkit/test/evidence" not in rendered
453
418
  assert "TEST_FAIL" not in rendered
454
419
 
455
- def test_standard_sections_include_central_checkpoint_helper(self):
420
+ def test_canonical_sections_include_central_checkpoint_helper(self):
456
421
  sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
457
422
  sections = assemble_sections(
458
- "standard", str(sections_dir), init_done=True,
459
- is_resume=False, browser_enabled=False,
423
+ str(sections_dir), init_done=True, browser_enabled=False,
460
424
  )
461
425
  rendered = "\n".join(content for _, content in sections)
462
426
 
@@ -470,27 +434,82 @@ class TestScopedFeatureTestGate:
470
434
  assert "--status completed --stage-result TEST_PASS" in rendered
471
435
  assert "--status completed --stage-result RETRO_COMPLETE" in rendered
472
436
  assert "--status in_progress --stage-result COMMIT_PENDING" in rendered
473
- 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
474
439
  assert "Do not hand-edit `workflow-checkpoint.json` directly." in rendered
475
440
  assert "authoritative_evidence_paths" not in rendered
476
441
 
477
442
  def test_checkpoint_orders_test_after_review_with_terminal_artifacts(self):
478
443
  sections_dir = Path(__file__).resolve().parents[1] / "templates" / "sections"
479
444
  sections = assemble_sections(
480
- "standard", str(sections_dir), init_done=True,
481
- is_resume=False, browser_enabled=False,
445
+ str(sections_dir), init_done=True, browser_enabled=False,
482
446
  )
483
447
  checkpoint = generate_checkpoint_definition(
484
- sections, pipeline_mode="standard", workflow_type="feature-pipeline",
448
+ sections, workflow_type="feature-pipeline",
485
449
  item_id="F-123", item_slug="123-scope-test",
486
450
  session_id="F-123-session", init_done=True,
487
451
  )
488
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
+ )
489
461
  test_step = next(step for step in checkpoint["steps"] if step["skill"] == "prizmkit-test")
490
462
 
491
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
+ ]
492
472
  assert test_step["required_artifacts"] == self._artifacts()
493
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
+
494
513
  def test_merge_keeps_only_consistent_test_pass_artifacts(self, tmp_path):
495
514
  self._write_result(tmp_path)
496
515
  existing = {"steps": [{
@@ -527,8 +546,7 @@ class TestScopedFeatureTestGate:
527
546
  self._write_result(tmp_path)
528
547
  result_path = tmp_path / ".prizmkit/specs/123-scope-test/test-result.json"
529
548
  payload = json.loads(result_path.read_text(encoding="utf-8"))
530
- payload["review_required"] = True
531
- payload["review_scope"] = None
549
+ payload["caller_route"] = "prizmkit-code-review"
532
550
  result_path.write_text(json.dumps(payload), encoding="utf-8")
533
551
  existing = {"steps": [{
534
552
  "id": "S01", "skill": "prizmkit-test", "status": "completed",
@@ -543,21 +561,32 @@ class TestScopedFeatureTestGate:
543
561
 
544
562
  assert merged["steps"][0]["status"] == "pending"
545
563
 
546
- def test_feature_result_routing_stops_test_non_pass_without_outer_repair(self):
547
- review = route_feature_repair("REVIEW_NEEDS_FIXES", repair_round=0)
548
- 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
+ )
549
571
  blocked = route_feature_repair("TEST_BLOCKED", repair_round=1)
572
+ passed = route_feature_repair("TEST_PASS", repair_round=1)
550
573
 
551
574
  assert review["route"] == [
552
575
  "prizmkit-implement", "prizmkit-code-review", "prizmkit-test",
553
576
  ]
554
577
  assert review["repair_round"] == 1
555
- assert needs_fixes["blocked"] is True
556
- assert needs_fixes["route"] == []
557
- 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
558
583
  assert blocked["blocked"] is True
559
584
  assert blocked["blocked_reason"] == "test_blocked"
560
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"
561
590
 
562
591
  def test_pipeline_checkpoint_metadata_rejects_legacy_or_mismatched_status(self):
563
592
  invalid = [
@@ -618,26 +647,24 @@ class TestHeadlessRecoveryReframing:
618
647
  deleted_title = "Session " + "Checkpoint Awareness"
619
648
  placeholder = "{{LOG_" + "SIZE_AWARENESS}}"
620
649
 
621
- for mode in ("lite", "standard", "full"):
622
- rendered = "\n".join(
623
- section for _name, section in assemble_sections(
624
- mode, str(sections_dir), init_done=True, is_resume=False,
625
- browser_enabled=False,
626
- )
650
+ rendered = "\n".join(
651
+ section for _name, section in assemble_sections(
652
+ str(sections_dir), init_done=True, browser_enabled=False,
627
653
  )
628
- assert deleted_title not in rendered
629
- assert placeholder not in rendered
630
- assert REMOVED_MAX_LOG_ENV not in rendered
631
- assert REMOVED_MAX_LOG_HUMAN not in rendered
632
- assert ("209" + "7152") not in rendered
633
- assert ("2" + "MB") not in rendered
634
- assert "monitor-log" not in rendered
635
- assert "COMPACT_NEEDED" not in rendered
636
- assert "log-size monitor" not in rendered
637
- assert "The log-size monitor is the only allowed" not in rendered
638
- assert "Run this command and keep it running" not in rendered
639
- assert "Execute `/compact`" not in rendered
640
- 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
641
668
 
642
669
 
643
670
  class TestDirectOrchestratorImplementationPrompts:
@@ -659,43 +686,40 @@ class TestDirectOrchestratorImplementationPrompts:
659
686
  assert (templates_dir / "agent-prompts" / FORBIDDEN_DEV_FIX_PROMPT).exists() is False
660
687
  assert (templates_dir / "agent-prompts" / FORBIDDEN_DEV_RESUME_PROMPT).exists() is False
661
688
 
662
- def test_sections_all_modes_use_direct_orchestrator_implementation(self):
689
+ def test_canonical_sections_use_direct_orchestrator_implementation(self):
663
690
  sections_dir = Path("dev-pipeline/templates/sections").resolve()
664
691
 
665
- for mode in ("lite", "standard", "full"):
666
- rendered = "\n".join(
667
- section for _name, section in assemble_sections(
668
- mode, str(sections_dir), init_done=True, is_resume=False,
669
- browser_enabled=False,
670
- )
692
+ rendered = "\n".join(
693
+ section for _name, section in assemble_sections(
694
+ str(sections_dir), init_done=True, browser_enabled=False,
671
695
  )
696
+ )
672
697
 
673
- assert "/prizmkit-implement" in rendered
674
- assert "orchestrator) execute" in rendered or "Run `/prizmkit-implement`" in rendered
675
- assert "Spawn Dev subagent" not in rendered
676
- assert "Spawn Dev agent" not in rendered
677
- assert "Implement — Dev" not in rendered
678
- assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
679
- assert "dev-implement.md" not in rendered
680
- assert FORBIDDEN_REVIEW_DEV_FIX not in rendered
681
- assert FORBIDDEN_REVIEWER_DEV_SPAWN not in rendered
682
- assert FORBIDDEN_EXPLORE_SUBAGENT not in rendered
683
- assert FORBIDDEN_TEST_CMD_PLACEHOLDER not in rendered
684
- assert FORBIDDEN_THREE_STRIKE not in rendered
685
- assert FORBIDDEN_TWENTY_STEP not in rendered
686
- assert "review-report.md" in rendered
687
- assert "Final Result" in rendered
688
- assert "low=0" not in rendered
689
- 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
690
715
 
691
716
  def test_all_rendered_pipeline_prompts_have_one_main_agent_review_model(self, tmp_path):
692
717
  prompts = [
693
- _render_feature_prompt(tmp_path / "feature-lite", mode="lite"),
694
- _render_feature_prompt(tmp_path / "feature-standard", mode="standard"),
695
- _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"),
696
721
  _render_feature_prompt(
697
- tmp_path / "feature-tier3",
698
- mode="full",
722
+ tmp_path / "feature-compatibility-template",
699
723
  template="bootstrap-tier3.md",
700
724
  ),
701
725
  _render_bugfix_prompt(tmp_path / "bugfix"),
@@ -805,7 +829,6 @@ class TestContinuationHandoff:
805
829
  def test_modular_feature_prompt_renders_user_context(tmp_path):
806
830
  prompt = _render_feature_prompt(
807
831
  tmp_path / "user-context",
808
- mode="standard",
809
832
  user_context=["Use the existing event envelope", "Keep the public API backward compatible"],
810
833
  )
811
834
 
@@ -835,7 +858,7 @@ def _write_feature_list(path, feature):
835
858
  path.write_text(json.dumps({"features": [feature], "global_context": {"language": "Python"}}), encoding="utf-8")
836
859
 
837
860
 
838
- 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):
839
862
  project = tmp_path / "project"
840
863
  project.mkdir(parents=True)
841
864
  (project / ".prizmkit" / "plans").mkdir(parents=True)
@@ -846,7 +869,7 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
846
869
  "id": "F-123",
847
870
  "title": "Prompt Cleanup",
848
871
  "description": "Clean prompt text",
849
- "estimated_complexity": complexity or {"lite": "low", "standard": "medium", "full": "high"}[mode],
872
+ "estimated_complexity": complexity or "medium",
850
873
  "acceptance_criteria": ["Prompts are clean"],
851
874
  }
852
875
  if user_context is not None:
@@ -867,8 +890,9 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
867
890
  "--state-dir", str(project / ".prizmkit" / "state" / "features"),
868
891
  "--project-root", str(project),
869
892
  "--output", str(output),
870
- "--mode", mode,
871
893
  ]
894
+ if continuation_mode:
895
+ args.extend(["--continuation-mode", continuation_mode])
872
896
  if template:
873
897
  template_path = Path(template)
874
898
  if not template_path.is_absolute():
@@ -1026,12 +1050,11 @@ def _render_refactor_prompt(tmp_path, platform="claude", explicit_platform=None,
1026
1050
  return output.read_text(encoding="utf-8")
1027
1051
 
1028
1052
 
1029
- class TestFeaturePromptUnifiedFullGuidance:
1030
- 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):
1031
1055
  prompts = {
1032
1056
  complexity: _render_feature_prompt(
1033
1057
  tmp_path / f"complexity-{complexity}",
1034
- mode="lite",
1035
1058
  complexity=complexity,
1036
1059
  )
1037
1060
  for complexity in ("low", "medium", "high", "critical")
@@ -1042,83 +1065,96 @@ class TestFeaturePromptUnifiedFullGuidance:
1042
1065
  assert "## Task Contract" in prompt
1043
1066
  assert "## Workflow Checkpoint System" in prompt
1044
1067
  assert "### Specify + Plan (Full Workflow)" in prompt
1045
- 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
1046
1069
  assert "### Scoped Feature Test Gate — PrizmKit Test" in prompt
1047
- assert "## Test Failure Recovery Protocol" in prompt
1070
+ assert "## Test Failure Recovery Protocol" not in prompt
1048
1071
  assert "test-report.md" in prompt
1049
1072
  assert "test-result.json" in prompt
1050
1073
  assert "### Browser Verification — MANDATORY" not in prompt
1051
- assert "### TERMINAL STOP — Commit Completed" in prompt
1074
+ assert "### Feature Completion Summary" in prompt
1075
+ assert "### Runtime Commit Handoff" in prompt
1052
1076
  assert "# Dev-Pipeline Session Bootstrap — Tier 1" not in prompt
1053
1077
  assert "# Dev-Pipeline Session Bootstrap — Tier 2" not in prompt
1054
1078
  assert "### Phase 0: SKIP (already initialized)" not in prompt
1055
1079
 
1056
- # The complexity value remains planning metadata, but guidance markers are
1057
- # the same full/tier3-equivalent composition for every complexity.
1058
- def test_cli_mode_override_does_not_downgrade_default_sections_guidance(self, tmp_path):
1059
- 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")
1060
1083
 
1061
1084
  assert "{{PIPELINE_MODE}}" not in prompt
1085
+ assert "compatibility mode" not in prompt
1062
1086
  assert "### Specify + Plan (Full Workflow)" in prompt
1063
- 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
1064
1089
  assert "### Phase 0: SKIP (already initialized)" not in prompt
1065
1090
 
1066
1091
  def test_explicit_custom_template_override_still_renders(self, tmp_path):
1067
1092
  custom = tmp_path / "custom-template.md"
1068
1093
  custom.write_text(
1069
- "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",
1070
1097
  encoding="utf-8",
1071
1098
  )
1072
1099
 
1073
1100
  prompt = _render_feature_prompt(
1074
1101
  tmp_path / "custom-template-project",
1075
- mode="lite",
1076
1102
  complexity="low",
1077
1103
  template=custom,
1078
1104
  )
1079
1105
 
1080
- 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
+ ]
1122
+
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")
1081
1140
 
1082
- def test_fallback_without_sections_prefers_tier3_then_bootstrap_prompt(self, tmp_path, monkeypatch):
1141
+ def test_missing_canonical_sections_fails_closed(self, tmp_path, monkeypatch):
1083
1142
  import generate_bootstrap_prompt as gbp
1084
1143
 
1085
1144
  original_isdir = os.path.isdir
1086
- original_isfile = os.path.isfile
1087
- requested = []
1088
1145
 
1089
1146
  def fake_isdir(path):
1090
1147
  if str(path).endswith(os.path.join("templates", "sections")):
1091
1148
  return False
1092
1149
  return original_isdir(path)
1093
1150
 
1094
- def fake_isfile(path):
1095
- requested.append(Path(path).name)
1096
- return original_isfile(path)
1097
-
1098
1151
  monkeypatch.setattr(gbp.os.path, "isdir", fake_isdir)
1099
- monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile)
1100
- prompt = _render_feature_prompt(tmp_path / "fallback-tier3", mode="lite", complexity="low")
1101
-
1102
- assert requested.index("bootstrap-tier3.md") < requested.index("bootstrap-prompt.md") if "bootstrap-prompt.md" in requested else True
1103
- assert "# Dev-Pipeline Session Bootstrap — Full Guidance" in prompt
1104
- assert "bootstrap-tier1.md" not in requested
1105
- assert "bootstrap-tier2.md" not in requested
1106
-
1107
- requested.clear()
1108
-
1109
- def fake_isfile_without_tier3(path):
1110
- requested.append(Path(path).name)
1111
- if Path(path).name == "bootstrap-tier3.md":
1112
- return False
1113
- return original_isfile(path)
1114
-
1115
- monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile_without_tier3)
1116
- prompt = _render_feature_prompt(tmp_path / "fallback-bootstrap-prompt", mode="lite", complexity="low")
1117
-
1118
- assert "bootstrap-tier3.md" in requested
1119
- assert "bootstrap-tier1.md" not in requested
1120
- assert "bootstrap-tier2.md" not in requested
1121
- 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")
1122
1158
 
1123
1159
 
1124
1160
  class TestBrowserBlockingPromptPolicy:
@@ -1134,10 +1170,16 @@ class TestBrowserBlockingPromptPolicy:
1134
1170
  _render_refactor_prompt(tmp_path / "refactor-browser-blocking", refactor_overrides={"browser_interaction": browser_interaction}),
1135
1171
  ]
1136
1172
 
1137
- 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):
1138
1179
  assert "Browser blocking policy: `true`" in prompt
1139
1180
  assert "stop before commit" in prompt
1140
1181
  assert "Failures do NOT block the commit" not in prompt
1182
+ assert prompt.index("### Browser Verification — MANDATORY") < prompt.index(test_marker)
1141
1183
 
1142
1184
  def test_feature_bugfix_refactor_nonblocking_browser_policy_continues(self, tmp_path):
1143
1185
  browser_interaction = {
@@ -1259,7 +1301,8 @@ class TestBrowserOptInPromptPolicy:
1259
1301
  assert "Manual / Hybrid Verification Gate" in prompt
1260
1302
  assert "must complete manual/hybrid verification automatically" in prompt
1261
1303
  assert "Stop before `/prizmkit-retrospective` and `/prizmkit-committer`" not in prompt
1262
- 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")
1263
1306
  assert "status=\"partial\"" not in prompt
1264
1307
 
1265
1308
  def test_recovery_manual_bugfix_uses_same_automatic_policy(self, tmp_path):
@@ -1272,14 +1315,16 @@ class TestBrowserOptInPromptPolicy:
1272
1315
  assert "Manual / Hybrid Verification Gate" in prompt
1273
1316
  assert "must complete manual/hybrid verification automatically" in prompt
1274
1317
  assert "Recovery-class session: automated verification may substitute" not in prompt
1275
- assert "### Headless Commit Authorization" in prompt
1318
+ assert "### Runtime Commit Handoff" in prompt
1276
1319
 
1277
1320
 
1278
1321
  class TestHeadlessPromptCleanupF033:
1279
1322
  def test_rendered_feature_bugfix_refactor_prompts_are_clean(self, tmp_path):
1280
- prompts = []
1281
- for mode in ("lite", "standard", "full"):
1282
- 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
+ ]
1283
1328
  prompts.append(_render_bugfix_prompt(tmp_path))
1284
1329
  prompts.append(_render_refactor_prompt(tmp_path))
1285
1330
 
@@ -1307,8 +1352,47 @@ class TestHeadlessPromptCleanupF033:
1307
1352
  assert "which " not in prompt # no which-command shell glue
1308
1353
  assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
1309
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
+
1310
1394
  def test_retained_tier3_template_is_clean_when_rendered(self, tmp_path):
1311
- 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")
1312
1396
  for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
1313
1397
  assert forbidden not in prompt
1314
1398
  assert "prizmkit-test-gate.py" not in prompt
@@ -1338,7 +1422,6 @@ class TestHeadlessPromptCleanupF033:
1338
1422
  ]
1339
1423
  prompt = _render_feature_prompt(
1340
1424
  tmp_path / "browser-bootstrap-tier3.md",
1341
- mode="full",
1342
1425
  template="bootstrap-tier3.md",
1343
1426
  browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
1344
1427
  )
@@ -1361,7 +1444,6 @@ class TestHeadlessPromptCleanupF033:
1361
1444
  bug_id="B-001", session_id="session-1", run_id="run-1",
1362
1445
  retry_count="0", resume_phase="null", state_dir=None,
1363
1446
  output="out.md", project_root=str(bug_project), template=None,
1364
- mode=None,
1365
1447
  )
1366
1448
  replacements = bugfix_build_replacements(
1367
1449
  args, {"id": "B-001", "title": "Broken"}, {}, str(Path("dev-pipeline/scripts").resolve())
@@ -1384,7 +1466,6 @@ class TestHeadlessPromptCleanupF033:
1384
1466
  bug_id="B-001", session_id="session-1", run_id="run-1",
1385
1467
  retry_count="0", resume_phase="null", state_dir=None,
1386
1468
  output="out.md", project_root=str(bug_project), template=None,
1387
- mode=None,
1388
1469
  )
1389
1470
  replacements = bugfix_build_replacements(
1390
1471
  args, {"id": "B-001", "title": "Broken"}, {}, str(Path("dev-pipeline/scripts").resolve())
@@ -1436,11 +1517,11 @@ class TestFeatureBootstrapShellExtraction:
1436
1517
  assert "text final-verdict .prizmkit/specs/123-prompt-cleanup/review-report.md" in prompt
1437
1518
 
1438
1519
  def test_rendered_section_feature_prompts_use_runtime_helper_not_extracted_bash(self, tmp_path):
1439
- for mode in ("lite", "standard", "full"):
1520
+ for complexity in ("low", "medium", "high"):
1440
1521
  prompt = _render_feature_prompt(
1441
- tmp_path / f"section-{mode}",
1442
- mode=mode,
1443
- 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"]},
1444
1525
  )
1445
1526
 
1446
1527
  self.assert_shell_extracted_operations_removed(prompt)
@@ -1455,7 +1536,6 @@ class TestFeatureBootstrapShellExtraction:
1455
1536
  def test_rendered_retained_tier3_feature_prompt_uses_runtime_helper_not_extracted_bash(self, tmp_path):
1456
1537
  prompt = _render_feature_prompt(
1457
1538
  tmp_path / "legacy-bootstrap-tier3.md",
1458
- mode="full",
1459
1539
  template="bootstrap-tier3.md",
1460
1540
  browser_interaction={"tool": "playwright-cli", "verify_steps": ["Open the page"]},
1461
1541
  )
@@ -1469,12 +1549,18 @@ class TestFeatureBootstrapShellExtraction:
1469
1549
  def test_retained_tier3_specific_extracted_operations_map_to_helper_commands(self, tmp_path):
1470
1550
  tier3 = _render_feature_prompt(
1471
1551
  tmp_path / "legacy-tier3-helper-map",
1472
- mode="full",
1473
1552
  template="bootstrap-tier3.md",
1474
1553
  )
1475
1554
  assert "text search . --pattern \"123-prompt-cleanup\" --json" in tier3
1476
1555
  assert "text count .prizmkit/specs/123-prompt-cleanup/plan.md --pattern \"- [ ]\"" in tier3
1477
- 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
1478
1564
 
1479
1565
 
1480
1566
  # ---------------------------------------------------------------------------
@@ -1568,16 +1654,17 @@ class TestDetectTestCommands:
1568
1654
 
1569
1655
 
1570
1656
 
1571
- def test_feature_checkpoint_generation_skips_noop_and_expands_only_finalization_group():
1657
+ def test_feature_checkpoint_generation_skips_noop_and_preserves_finalization_order():
1572
1658
  from generate_bootstrap_prompt import generate_checkpoint_definition
1573
1659
 
1574
1660
  checkpoint = generate_checkpoint_definition(
1575
1661
  [
1576
1662
  ("phase0-test-baseline", "noop"),
1577
1663
  ("phase-context-snapshot", "context"),
1578
- ("phase-commit", "finalize"),
1664
+ ("feature-completion-summary", "summary"),
1665
+ ("phase-commit", "retrospective"),
1666
+ ("runtime-commit-handoff", "commit"),
1579
1667
  ],
1580
- "standard",
1581
1668
  "feature-pipeline",
1582
1669
  "F-123",
1583
1670
  "123-prompt-cleanup",
@@ -1586,9 +1673,9 @@ def test_feature_checkpoint_generation_skips_noop_and_expands_only_finalization_
1586
1673
 
1587
1674
  assert [step["skill"] for step in checkpoint["steps"]] == [
1588
1675
  "context-snapshot",
1676
+ "completion-summary",
1589
1677
  "prizmkit-retrospective",
1590
1678
  "prizmkit-committer",
1591
- "completion-summary",
1592
1679
  ]
1593
1680
  assert checkpoint["steps"][0]["depends_on"] is None
1594
1681
  assert checkpoint["steps"][1]["depends_on"] == "S01"