prizmkit 1.1.154 → 1.1.156
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.
- package/bundled/VERSION.json +3 -3
- package/bundled/adapters/codex/skill-adapter.js +1 -1
- package/bundled/adapters/pi/skill-adapter.js +2 -1
- package/bundled/dev-pipeline/.env.example +2 -6
- package/bundled/dev-pipeline/README.md +21 -27
- package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +341 -15
- package/bundled/dev-pipeline/prizmkit_runtime/cli.py +0 -3
- package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +1 -15
- package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +48 -14
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +50 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +0 -9
- package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +120 -22
- package/bundled/dev-pipeline/prizmkit_runtime/runtime_commit.py +482 -0
- package/bundled/dev-pipeline/prizmkit_runtime/test_result.py +64 -11
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +145 -367
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +91 -62
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +105 -69
- package/bundled/dev-pipeline/scripts/prompt_framework.py +36 -41
- package/bundled/dev-pipeline/scripts/update-bug-status.py +1 -4
- package/bundled/dev-pipeline/scripts/update-checkpoint.py +61 -13
- package/bundled/dev-pipeline/scripts/update-feature-status.py +1 -4
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +1 -4
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +22 -27
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +71 -104
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +59 -111
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +37 -72
- package/bundled/dev-pipeline/templates/sections/artifact-manifest.md +39 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +3 -1
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +8 -25
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +3 -3
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +2 -2
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +3 -3
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +2 -2
- package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +4 -4
- package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +0 -1
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +7 -4
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +14 -27
- package/bundled/dev-pipeline/templates/sections/feature-completion-summary.md +20 -0
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -71
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +3 -3
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -4
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +5 -17
- package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +3 -1
- package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +10 -23
- package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +3 -3
- package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +2 -2
- package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +7 -7
- package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +0 -1
- package/bundled/dev-pipeline/templates/sections/retrospective.md +12 -0
- package/bundled/dev-pipeline/templates/sections/runtime-commit-handoff.md +35 -0
- package/bundled/dev-pipeline/templates/session-status-schema.json +45 -62
- package/bundled/dev-pipeline/tests/test_checkpoint_state.py +469 -18
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +262 -175
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +62 -23
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +76 -28
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +168 -18
- package/bundled/dev-pipeline/tests/test_recovery_workflow.py +111 -0
- package/bundled/dev-pipeline/tests/test_reset_preserve.py +0 -2
- package/bundled/dev-pipeline/tests/test_runtime_commit.py +608 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +167 -25
- package/bundled/skills/_metadata.json +9 -9
- package/bundled/skills/app-planner/SKILL.md +3 -3
- package/bundled/skills/app-planner/references/generated-plan-review.md +2 -1
- package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +56 -64
- package/bundled/skills/app-planner/references/rules/backend/fixed-rules.md +85 -240
- package/bundled/skills/app-planner/references/rules/backend/question-bank.md +25 -25
- package/bundled/skills/app-planner/references/rules/backend/question-manifest.json +16 -7
- package/bundled/skills/app-planner/references/rules/backend/template.md +74 -92
- package/bundled/skills/app-planner/references/rules/database/derivation-rules.md +93 -93
- package/bundled/skills/app-planner/references/rules/database/fixed-rules.md +66 -173
- package/bundled/skills/app-planner/references/rules/database/question-bank.md +31 -26
- package/bundled/skills/app-planner/references/rules/database/question-manifest.json +13 -4
- package/bundled/skills/app-planner/references/rules/database/template.md +76 -98
- package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +68 -95
- package/bundled/skills/app-planner/references/rules/frontend/fixed-rules.md +93 -166
- package/bundled/skills/app-planner/references/rules/frontend/question-bank.md +46 -36
- package/bundled/skills/app-planner/references/rules/frontend/question-manifest.json +11 -2
- package/bundled/skills/app-planner/references/rules/frontend/template.md +79 -257
- package/bundled/skills/app-planner/references/rules/mobile/derivation-rules.md +91 -99
- package/bundled/skills/app-planner/references/rules/mobile/fixed-rules.md +73 -246
- package/bundled/skills/app-planner/references/rules/mobile/question-bank.md +17 -17
- package/bundled/skills/app-planner/references/rules/mobile/question-manifest.json +17 -2
- package/bundled/skills/app-planner/references/rules/mobile/template.md +73 -85
- package/bundled/skills/app-planner/references/rules-configuration.md +133 -65
- package/bundled/skills/app-planner/scripts/validate-rules-configuration.py +291 -0
- package/bundled/skills/prizmkit/SKILL.md +17 -18
- package/bundled/skills/prizmkit/references/workflow-state-protocol.md +22 -18
- package/bundled/skills/prizmkit-code-review/SKILL.md +22 -58
- package/bundled/skills/prizmkit-code-review/references/independent-code-review.md +6 -6
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +2 -2
- package/bundled/skills/prizmkit-committer/SKILL.md +82 -132
- package/bundled/skills/prizmkit-deploy/SKILL.md +27 -11
- package/bundled/skills/prizmkit-deploy/assets/deploy-document-template.md +89 -0
- package/bundled/skills/prizmkit-deploy/references/ci-cd-workflows.md +44 -14
- package/bundled/skills/prizmkit-deploy/references/cloud-platform-deploy.md +19 -3
- package/bundled/skills/prizmkit-deploy/references/database-setup.md +22 -12
- package/bundled/skills/prizmkit-deploy/references/deploy-config-schema.md +3 -1
- package/bundled/skills/prizmkit-deploy/references/deploy-history-schema.md +22 -6
- package/bundled/skills/prizmkit-deploy/references/deploy-metadata-schema.json +49 -0
- package/bundled/skills/prizmkit-deploy/references/live-validation-notes.md +1 -1
- package/bundled/skills/prizmkit-deploy/references/pending-input-schema.json +164 -0
- package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +9 -8
- package/bundled/skills/prizmkit-deploy/references/ssh-execution-flow.md +6 -6
- package/bundled/skills/prizmkit-implement/SKILL.md +30 -66
- package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +4 -4
- package/bundled/skills/prizmkit-init/SKILL.md +4 -0
- package/bundled/skills/prizmkit-plan/SKILL.md +21 -64
- package/bundled/skills/prizmkit-plan/references/artifact-identity.md +38 -0
- package/bundled/skills/prizmkit-plan/references/independent-plan-review.md +4 -4
- package/bundled/skills/prizmkit-plan/references/review-plan-spec-loop.md +5 -5
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +75 -11
- package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +191 -56
- package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +18 -18
- package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +14 -8
- package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +12 -5
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +23 -12
- package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +13 -9
- package/bundled/skills/prizmkit-retrospective/SKILL.md +94 -97
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +79 -37
- package/bundled/skills/prizmkit-retrospective/references/retrospective-result-schema.json +138 -0
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +111 -54
- package/bundled/skills/prizmkit-test/SKILL.md +64 -51
- package/bundled/skills/prizmkit-test/references/boundary-contract-and-test-double-guidance.md +206 -0
- package/bundled/skills/prizmkit-test/references/independent-test-review.md +17 -9
- package/bundled/skills/prizmkit-test/references/test-coverage-model.md +45 -21
- package/bundled/skills/prizmkit-test/references/test-report-template.md +20 -13
- package/bundled/skills/prizmkit-workflow/SKILL.md +35 -37
- package/bundled/skills/prizmkit-workflow/references/artifact-identity.md +34 -0
- package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +22 -18
- package/bundled/skills/recovery-workflow/SKILL.md +2 -1
- package/bundled/skills/recovery-workflow/references/detection.md +4 -3
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +15 -5
- package/bundled/templates/hooks/validate-prizm-docs.py +124 -12
- package/package.json +1 -1
- package/src/scaffold.js +33 -22
- package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +0 -16
- package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +0 -31
- package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -7
- package/bundled/dev-pipeline/templates/sections/critical-paths-lite.md +0 -7
- package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +0 -9
- package/bundled/dev-pipeline/templates/sections/directory-convention-lite.md +0 -6
- package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +0 -15
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -61
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -24
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -12
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +0 -44
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -25
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +0 -20
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +0 -20
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +0 -20
- package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +0 -17
- package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +0 -28
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +0 -52
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +0 -52
- package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +0 -174
- package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +0 -174
- 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
|
-
|
|
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
|
-
#
|
|
348
|
+
# explicit custom-template conditionals
|
|
369
349
|
# ---------------------------------------------------------------------------
|
|
370
350
|
|
|
371
|
-
class
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 "
|
|
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
|
-
|
|
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,
|
|
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["
|
|
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
|
|
547
|
-
review = route_feature_repair(
|
|
548
|
-
|
|
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
|
|
556
|
-
assert needs_fixes["route"] == [
|
|
557
|
-
|
|
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
|
-
|
|
622
|
-
|
|
623
|
-
|
|
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
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
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
|
|
689
|
+
def test_canonical_sections_use_direct_orchestrator_implementation(self):
|
|
663
690
|
sections_dir = Path("dev-pipeline/templates/sections").resolve()
|
|
664
691
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
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
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
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-
|
|
694
|
-
_render_feature_prompt(tmp_path / "feature-
|
|
695
|
-
_render_feature_prompt(tmp_path / "feature-
|
|
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-
|
|
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,
|
|
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
|
|
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
|
|
1030
|
-
def
|
|
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 "
|
|
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 "###
|
|
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
|
-
#
|
|
1057
|
-
|
|
1058
|
-
|
|
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
|
-
"
|
|
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
|
|
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
|
|
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
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
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
|
-
|
|
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 "###
|
|
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 "###
|
|
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
|
-
|
|
1282
|
-
|
|
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",
|
|
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
|
|
1520
|
+
for complexity in ("low", "medium", "high"):
|
|
1440
1521
|
prompt = _render_feature_prompt(
|
|
1441
|
-
tmp_path / f"section-{
|
|
1442
|
-
|
|
1443
|
-
|
|
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 "
|
|
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
|
|
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
|
-
("
|
|
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"
|