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
|
@@ -20,7 +20,6 @@ from prompt_framework import (
|
|
|
20
20
|
generate_checkpoint_from_sections,
|
|
21
21
|
load_section,
|
|
22
22
|
merge_checkpoint_state,
|
|
23
|
-
normalize_mode,
|
|
24
23
|
pipeline_checkpoint_metadata,
|
|
25
24
|
read_text_file,
|
|
26
25
|
render_from_sections,
|
|
@@ -81,11 +80,17 @@ REFACTOR_SECTION_TO_SKILL = {
|
|
|
81
80
|
),
|
|
82
81
|
"phase-browser": checkpoint_step("browser-verification", "Browser Verification", []),
|
|
83
82
|
"refactor-phase-commit-report": checkpoint_group([
|
|
84
|
-
("prizmkit-retrospective", "Retrospective", []),
|
|
85
|
-
("prizmkit-committer", "Commit", []),
|
|
86
83
|
("refactor-report", "Generate Refactor Report", [".prizmkit/refactor/{slug}/refactor-report.md"]),
|
|
87
84
|
("completion-summary", "Completion Summary", [".prizmkit/refactor/{slug}/completion-summary.json"]),
|
|
88
85
|
]),
|
|
86
|
+
"retrospective": checkpoint_step(
|
|
87
|
+
"prizmkit-retrospective", "Retrospective",
|
|
88
|
+
[".prizmkit/refactor/{slug}/retrospective-result.json"],
|
|
89
|
+
),
|
|
90
|
+
"runtime-commit-handoff": checkpoint_step(
|
|
91
|
+
"prizmkit-committer", "Runtime Commit Handoff",
|
|
92
|
+
[".prizmkit/refactor/{slug}/runtime-commit-request.json"],
|
|
93
|
+
),
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
REFACTOR_SPLIT_STEPS = {}
|
|
@@ -107,8 +112,12 @@ def parse_args():
|
|
|
107
112
|
parser.add_argument("--state-dir", default=None, help="State directory (default: .prizmkit/state/refactor)")
|
|
108
113
|
parser.add_argument("--output", required=True, help="Output path for the rendered prompt")
|
|
109
114
|
parser.add_argument("--project-root", default=None, help="AI-visible project root used for rendered prompt paths")
|
|
115
|
+
parser.add_argument(
|
|
116
|
+
"--no-checkpoint-write",
|
|
117
|
+
action="store_true",
|
|
118
|
+
help="Render and validate a preview without creating or updating checkpoint state",
|
|
119
|
+
)
|
|
110
120
|
parser.add_argument("--template", default=None, help="Custom legacy template path. Defaults to section assembly.")
|
|
111
|
-
parser.add_argument("--mode", choices=["lite", "standard", "full"], default=None, help="Pipeline execution mode override")
|
|
112
121
|
add_continuation_args(parser, "refactor")
|
|
113
122
|
return parser.parse_args()
|
|
114
123
|
|
|
@@ -189,15 +198,39 @@ def format_scope_modules(scope):
|
|
|
189
198
|
return _format_scope_list(scope, "modules")
|
|
190
199
|
|
|
191
200
|
|
|
201
|
+
def _test_path_list(value):
|
|
202
|
+
if not isinstance(value, list):
|
|
203
|
+
return []
|
|
204
|
+
return [str(item) for item in value if str(item).strip()]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def format_existing_tests(value):
|
|
208
|
+
if isinstance(value, bool):
|
|
209
|
+
coverage = "yes" if value else "no"
|
|
210
|
+
return "- Coverage declared: {} (specific test paths not supplied)".format(coverage)
|
|
211
|
+
tests = _test_path_list(value)
|
|
212
|
+
if tests:
|
|
213
|
+
return "\n".join("- `{}`".format(test) for test in tests)
|
|
214
|
+
return "- (none specified)"
|
|
215
|
+
|
|
216
|
+
|
|
192
217
|
def format_behavior_preservation(bp):
|
|
193
218
|
if not bp or not isinstance(bp, dict):
|
|
194
219
|
return "- (no behavior preservation details)"
|
|
195
220
|
lines = ["- **Strategy**: {}".format(bp.get("strategy", "unknown"))]
|
|
196
|
-
existing_tests = bp.get("existing_tests"
|
|
197
|
-
if existing_tests:
|
|
198
|
-
lines.append(
|
|
199
|
-
|
|
200
|
-
|
|
221
|
+
existing_tests = bp.get("existing_tests")
|
|
222
|
+
if isinstance(existing_tests, bool):
|
|
223
|
+
lines.append(
|
|
224
|
+
"- **Existing Tests Cover Scope**: {}".format(
|
|
225
|
+
"yes" if existing_tests else "no"
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
else:
|
|
229
|
+
tests = _test_path_list(existing_tests)
|
|
230
|
+
if tests:
|
|
231
|
+
lines.append("- **Existing Tests**:")
|
|
232
|
+
lines.extend(" - `{}`".format(test) for test in tests)
|
|
233
|
+
new_tests_needed = _test_path_list(bp.get("new_tests_needed"))
|
|
201
234
|
if new_tests_needed:
|
|
202
235
|
lines.append("- **New Tests Needed**:")
|
|
203
236
|
lines.extend(" - {}".format(test) for test in new_tests_needed)
|
|
@@ -289,46 +322,24 @@ def _args_project_root(args, script_dir):
|
|
|
289
322
|
return resolve_project_root(script_dir)
|
|
290
323
|
|
|
291
324
|
|
|
292
|
-
def determine_refactor_mode(args, refactor):
|
|
293
|
-
if args.mode:
|
|
294
|
-
return args.mode
|
|
295
|
-
priority = str(refactor.get("priority", "medium")).lower()
|
|
296
|
-
complexity = str(refactor.get("complexity", "medium")).lower()
|
|
297
|
-
if priority == "critical" and complexity in ("high", "critical"):
|
|
298
|
-
return "full"
|
|
299
|
-
if complexity in ("high", "critical"):
|
|
300
|
-
return "standard"
|
|
301
|
-
return normalize_mode({"low": "lite", "medium": "lite"}.get(complexity, "lite"))
|
|
302
|
-
|
|
303
|
-
|
|
304
325
|
def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
305
326
|
project_root = _args_project_root(args, script_dir)
|
|
306
327
|
resolve_prompt_platform(project_root)
|
|
307
328
|
|
|
308
|
-
state_dir = (
|
|
309
|
-
os.path.abspath(args.state_dir)
|
|
310
|
-
if args.state_dir
|
|
311
|
-
else os.path.join(project_root, ".prizmkit", "state", "refactor")
|
|
312
|
-
)
|
|
313
|
-
session_status_path = os.path.join(state_dir, args.refactor_id, "sessions", args.session_id, "session-status.json")
|
|
314
|
-
|
|
315
329
|
scope = refactor.get("scope", {})
|
|
316
330
|
bp = refactor.get("behavior_preservation", {})
|
|
317
331
|
behavior_strategy = bp.get("strategy", "test-gate") if isinstance(bp, dict) else "test-gate"
|
|
318
|
-
existing_tests = bp.get("existing_tests"
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
new_tests_needed = []
|
|
324
|
-
existing_tests_str = "\n".join("- `{}`".format(test) for test in existing_tests) if existing_tests else "- (none specified)"
|
|
332
|
+
existing_tests = bp.get("existing_tests") if isinstance(bp, dict) else None
|
|
333
|
+
new_tests_needed = _test_path_list(
|
|
334
|
+
bp.get("new_tests_needed") if isinstance(bp, dict) else None
|
|
335
|
+
)
|
|
336
|
+
existing_tests_str = format_existing_tests(existing_tests)
|
|
325
337
|
new_tests_str = "\n".join("- {}".format(test) for test in new_tests_needed) if new_tests_needed else "- (none specified)"
|
|
326
338
|
|
|
327
339
|
browser_enabled, browser_tool, browser_verify_steps, browser_blocking = browser_enabled_from_item(refactor)
|
|
328
340
|
dev_port = detect_dev_server_port(project_root)
|
|
329
341
|
dev_url = "http://localhost:{}".format(dev_port) if dev_port.isdigit() else "<UNKNOWN_DETECT_FROM_PROJECT_CONFIG>"
|
|
330
342
|
|
|
331
|
-
pipeline_mode = determine_refactor_mode(args, refactor)
|
|
332
343
|
replacements = {
|
|
333
344
|
"{{SESSION_LOG_PATH}}": os.path.join(".prizmkit", "state", "refactor", args.refactor_id, "sessions", args.session_id, "logs", "session.log"),
|
|
334
345
|
"{{RUN_ID}}": args.run_id,
|
|
@@ -346,16 +357,15 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
|
346
357
|
"{{NEW_TESTS_NEEDED}}": new_tests_str,
|
|
347
358
|
"{{PRIORITY}}": refactor.get("priority", "medium"),
|
|
348
359
|
"{{COMPLEXITY}}": refactor.get("complexity", "medium"),
|
|
349
|
-
"{{PIPELINE_MODE}}": pipeline_mode,
|
|
350
360
|
"{{REFACTOR_DESCRIPTION}}": refactor.get("description", ""),
|
|
351
361
|
"{{USER_CONTEXT}}": format_user_context(refactor.get("user_context", [])),
|
|
352
362
|
"{{ACCEPTANCE_CRITERIA}}": format_acceptance_criteria(refactor.get("acceptance_criteria", [])),
|
|
353
363
|
"{{AC_CHECKLIST}}": format_ac_checklist(refactor.get("acceptance_criteria", [])),
|
|
354
364
|
"{{DEPENDENCIES}}": format_dependencies(refactor.get("dependencies", []), refactors),
|
|
355
365
|
"{{GLOBAL_CONTEXT}}": format_global_context(global_context, project_root),
|
|
356
|
-
"{{SESSION_STATUS_PATH}}": session_status_path,
|
|
357
366
|
"{{PROJECT_ROOT}}": project_root,
|
|
358
367
|
"{{ARTIFACT_DIR}}": ".prizmkit/refactor/{}".format(args.refactor_id),
|
|
368
|
+
"{{FAMILY_ARTIFACTS}}": "├── refactor-report.md\n├── completion-summary.json",
|
|
359
369
|
"{{CHECKPOINT_PATH}}": os.path.join(".prizmkit", "refactor", args.refactor_id, "workflow-checkpoint.json"),
|
|
360
370
|
"{{CHECKPOINT_SYSTEM}}": read_checkpoint_system_section(script_dir),
|
|
361
371
|
"{{TIMESTAMP}}": "",
|
|
@@ -404,24 +414,22 @@ def render_template(template_content, replacements, resume_phase, refactor):
|
|
|
404
414
|
return replace_placeholders(process_conditional_blocks(template_content, resume_phase, refactor), replacements)
|
|
405
415
|
|
|
406
416
|
|
|
407
|
-
def _refactor_header(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
"
|
|
411
|
-
"
|
|
412
|
-
|
|
413
|
-
}.get(pipeline_mode, "**Refactor pipeline**")
|
|
414
|
-
return title + "\n" + desc + "\n"
|
|
417
|
+
def _refactor_header():
|
|
418
|
+
return (
|
|
419
|
+
"# Dev-Pipeline Refactor Session Bootstrap — Canonical Guidance\n\n"
|
|
420
|
+
"Use the active skills and runtime contracts for planning, implementation, "
|
|
421
|
+
"review, behavior verification, retrospective, and runtime-owned commit execution.\n"
|
|
422
|
+
)
|
|
415
423
|
|
|
416
424
|
|
|
417
|
-
def assemble_refactor_sections(
|
|
425
|
+
def assemble_refactor_sections(sections_dir, browser_enabled, browser_tool="auto"):
|
|
418
426
|
sections = [
|
|
419
|
-
("header", _refactor_header(
|
|
427
|
+
("header", _refactor_header()),
|
|
420
428
|
("refactor-session-context", load_section(sections_dir, "refactor-session-context.md")),
|
|
421
429
|
("mission", load_section(sections_dir, "refactor-mission.md")),
|
|
422
430
|
("refactor-task-contract", load_section(sections_dir, "refactor-task-contract.md")),
|
|
423
431
|
("context-budget-rules", load_section(sections_dir, "context-budget-rules.md")),
|
|
424
|
-
("
|
|
432
|
+
("artifact-manifest", load_section(sections_dir, "artifact-manifest.md")),
|
|
425
433
|
("checkpoint-system", load_section(sections_dir, "checkpoint-system.md")),
|
|
426
434
|
("execution-header", "---\n\n## Execution\n"),
|
|
427
435
|
("refactor-phase-init", load_section(sections_dir, "refactor-phase-init.md")),
|
|
@@ -430,7 +438,6 @@ def assemble_refactor_sections(pipeline_mode, sections_dir, browser_enabled, bro
|
|
|
430
438
|
sections.extend([
|
|
431
439
|
("refactor-phase-implement", load_section(sections_dir, "refactor-phase-implement.md")),
|
|
432
440
|
("refactor-phase-review", load_section(sections_dir, "refactor-phase-review.md")),
|
|
433
|
-
("refactor-phase-test", load_section(sections_dir, "refactor-phase-test.md")),
|
|
434
441
|
])
|
|
435
442
|
if browser_enabled:
|
|
436
443
|
browser_section_file = {
|
|
@@ -439,9 +446,10 @@ def assemble_refactor_sections(pipeline_mode, sections_dir, browser_enabled, bro
|
|
|
439
446
|
}.get(browser_tool, "phase-browser-verification-auto.md")
|
|
440
447
|
sections.append(("phase-browser", load_section(sections_dir, browser_section_file)))
|
|
441
448
|
sections.extend([
|
|
442
|
-
("
|
|
449
|
+
("refactor-phase-test", load_section(sections_dir, "refactor-phase-test.md")),
|
|
443
450
|
("refactor-phase-commit-report", load_section(sections_dir, "refactor-phase-commit-report.md")),
|
|
444
|
-
("
|
|
451
|
+
("retrospective", load_section(sections_dir, "retrospective.md")),
|
|
452
|
+
("runtime-commit-handoff", load_section(sections_dir, "runtime-commit-handoff.md")),
|
|
445
453
|
("refactor-critical-paths", load_section(sections_dir, "refactor-critical-paths.md")),
|
|
446
454
|
("failure-capture", load_section(sections_dir, "failure-capture.md")),
|
|
447
455
|
("refactor-reminders", load_section(sections_dir, "refactor-reminders.md")),
|
|
@@ -449,20 +457,27 @@ def assemble_refactor_sections(pipeline_mode, sections_dir, browser_enabled, bro
|
|
|
449
457
|
return sections
|
|
450
458
|
|
|
451
459
|
|
|
452
|
-
def generate_refactor_checkpoint(
|
|
460
|
+
def generate_refactor_checkpoint(
|
|
461
|
+
refactor_id, session_id, sections=None, *, browser_enabled=False,
|
|
462
|
+
):
|
|
453
463
|
if sections is None:
|
|
454
464
|
sections = [
|
|
455
465
|
("refactor-phase-init", ""),
|
|
456
466
|
("refactor-phase-plan", ""),
|
|
457
467
|
("refactor-phase-implement", ""),
|
|
458
468
|
("refactor-phase-review", ""),
|
|
469
|
+
]
|
|
470
|
+
if browser_enabled:
|
|
471
|
+
sections.append(("phase-browser", ""))
|
|
472
|
+
sections.extend([
|
|
459
473
|
("refactor-phase-test", ""),
|
|
460
474
|
("refactor-phase-commit-report", ""),
|
|
461
|
-
|
|
475
|
+
("retrospective", ""),
|
|
476
|
+
("runtime-commit-handoff", ""),
|
|
477
|
+
])
|
|
462
478
|
return generate_checkpoint_from_sections(
|
|
463
479
|
sections,
|
|
464
480
|
REFACTOR_SECTION_TO_SKILL,
|
|
465
|
-
pipeline_mode,
|
|
466
481
|
"refactor-pipeline",
|
|
467
482
|
refactor_id,
|
|
468
483
|
refactor_id,
|
|
@@ -504,7 +519,6 @@ def main():
|
|
|
504
519
|
global_context = {}
|
|
505
520
|
|
|
506
521
|
replacements = build_replacements(args, refactor, refactors, global_context, script_dir)
|
|
507
|
-
pipeline_mode = replacements["{{PIPELINE_MODE}}"]
|
|
508
522
|
browser_enabled = replacements["{{BROWSER_ENABLED}}"] == "true"
|
|
509
523
|
|
|
510
524
|
use_sections = os.path.isdir(sections_dir) and not args.template
|
|
@@ -512,16 +526,17 @@ def main():
|
|
|
512
526
|
if use_sections:
|
|
513
527
|
try:
|
|
514
528
|
sections = assemble_refactor_sections(
|
|
515
|
-
|
|
529
|
+
sections_dir, browser_enabled,
|
|
516
530
|
browser_tool=replacements["{{BROWSER_TOOL}}"],
|
|
517
531
|
)
|
|
518
532
|
rendered = render_from_sections(sections, replacements)
|
|
519
533
|
except FileNotFoundError as exc:
|
|
520
|
-
|
|
521
|
-
use_sections = False
|
|
534
|
+
emit_failure("Refactor section assembly failed: {}".format(exc))
|
|
522
535
|
|
|
523
536
|
if not use_sections:
|
|
524
|
-
|
|
537
|
+
if not args.template:
|
|
538
|
+
emit_failure("Canonical Refactor prompt sections are unavailable")
|
|
539
|
+
template_path = args.template
|
|
525
540
|
template_content, err = read_text_file(template_path)
|
|
526
541
|
if err:
|
|
527
542
|
emit_failure("Template error: {}".format(err))
|
|
@@ -537,7 +552,7 @@ def main():
|
|
|
537
552
|
logger=LOGGER,
|
|
538
553
|
)
|
|
539
554
|
if not is_valid:
|
|
540
|
-
|
|
555
|
+
emit_failure("Rendered refactor prompt failed validation: {}".format("; ".join(errors)))
|
|
541
556
|
|
|
542
557
|
err = write_output(args.output, rendered)
|
|
543
558
|
if err:
|
|
@@ -545,9 +560,13 @@ def main():
|
|
|
545
560
|
|
|
546
561
|
project_root = _args_project_root(args, script_dir)
|
|
547
562
|
checkpoint_path = os.path.join(project_root, replacements["{{CHECKPOINT_PATH}}"])
|
|
548
|
-
|
|
563
|
+
if not args.no_checkpoint_write:
|
|
564
|
+
os.makedirs(os.path.dirname(checkpoint_path), exist_ok=True)
|
|
549
565
|
checkpoint = generate_refactor_checkpoint(
|
|
550
|
-
args.refactor_id,
|
|
566
|
+
args.refactor_id,
|
|
567
|
+
args.session_id,
|
|
568
|
+
sections if use_sections else None,
|
|
569
|
+
browser_enabled=browser_enabled,
|
|
551
570
|
)
|
|
552
571
|
if not any(step.get("skill") == "prizmkit-test" for step in checkpoint["steps"]):
|
|
553
572
|
emit_failure("Refactor checkpoint is missing the mandatory prizmkit-test stage")
|
|
@@ -562,7 +581,7 @@ def main():
|
|
|
562
581
|
resume_from="prizmkit-implement",
|
|
563
582
|
)
|
|
564
583
|
|
|
565
|
-
if (args.resume_phase != "null" or is_continuation(args)) and os.path.exists(checkpoint_path):
|
|
584
|
+
if not args.no_checkpoint_write and (args.resume_phase != "null" or is_continuation(args)) and os.path.exists(checkpoint_path):
|
|
566
585
|
try:
|
|
567
586
|
with open(checkpoint_path, "r", encoding="utf-8") as f:
|
|
568
587
|
existing = json.load(f)
|
|
@@ -571,14 +590,32 @@ def main():
|
|
|
571
590
|
except (json.JSONDecodeError, KeyError) as exc:
|
|
572
591
|
LOGGER.warning("Existing refactor checkpoint corrupted (%s) — generating fresh", exc)
|
|
573
592
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
593
|
+
if not args.no_checkpoint_write:
|
|
594
|
+
with open(checkpoint_path, "w", encoding="utf-8") as f:
|
|
595
|
+
json.dump(checkpoint, f, indent=2, ensure_ascii=False)
|
|
596
|
+
LOGGER.info("Wrote refactor checkpoint to %s", checkpoint_path)
|
|
577
597
|
|
|
578
598
|
if is_continuation(args):
|
|
579
599
|
rendered = append_continuation_handoff(
|
|
580
600
|
rendered, args, project_root, args.task_type, args.refactor_id, args.refactor_id, checkpoint,
|
|
581
601
|
)
|
|
602
|
+
final_valid, final_warnings, final_errors = validate_rendered(
|
|
603
|
+
rendered,
|
|
604
|
+
required_markers=[
|
|
605
|
+
("## Your Mission", "Mission section"),
|
|
606
|
+
("## Execution", "Execution section"),
|
|
607
|
+
("## Failure Capture", "Failure Capture Protocol"),
|
|
608
|
+
],
|
|
609
|
+
logger=LOGGER,
|
|
610
|
+
)
|
|
611
|
+
if not final_valid:
|
|
612
|
+
emit_failure(
|
|
613
|
+
"Rendered refactor continuation prompt failed validation: {}".format(
|
|
614
|
+
"; ".join(final_errors)
|
|
615
|
+
)
|
|
616
|
+
)
|
|
617
|
+
warnings.extend(final_warnings)
|
|
618
|
+
errors.extend(final_errors)
|
|
582
619
|
err = write_output(args.output, rendered)
|
|
583
620
|
if err:
|
|
584
621
|
emit_failure(err)
|
|
@@ -586,9 +623,8 @@ def main():
|
|
|
586
623
|
output = {
|
|
587
624
|
"success": True,
|
|
588
625
|
"output_path": os.path.abspath(args.output),
|
|
589
|
-
"checkpoint_path": checkpoint_path,
|
|
626
|
+
"checkpoint_path": "" if args.no_checkpoint_write else checkpoint_path,
|
|
590
627
|
"model": refactor.get("model", ""),
|
|
591
|
-
"pipeline_mode": pipeline_mode,
|
|
592
628
|
"render_mode": "sections" if use_sections else "legacy",
|
|
593
629
|
"validation_warnings": len(warnings),
|
|
594
630
|
"validation_errors": len(errors),
|
|
@@ -16,6 +16,7 @@ if _PIPELINE_ROOT not in sys.path:
|
|
|
16
16
|
|
|
17
17
|
from prizmkit_runtime.checkpoint_state import ( # noqa: E402
|
|
18
18
|
VALID_CHECKPOINT_STATUSES,
|
|
19
|
+
VALID_REPAIR_SCOPES,
|
|
19
20
|
expected_status_for_stage_result,
|
|
20
21
|
)
|
|
21
22
|
from prizmkit_runtime.test_result import valid_test_artifact_pair # noqa: E402
|
|
@@ -48,9 +49,11 @@ def route_pipeline_repair(stage_result, repair_scope=None, repair_round=0):
|
|
|
48
49
|
}
|
|
49
50
|
if stage_result == "TEST_PASS":
|
|
50
51
|
result.update(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
resumable=True,
|
|
53
|
+
next_stage="family-report",
|
|
54
|
+
resume_from="family-report",
|
|
55
|
+
route=["family-report", "prizmkit-retrospective"],
|
|
56
|
+
reason="project-native tests passed; family reports precede retrospective",
|
|
54
57
|
)
|
|
55
58
|
return result
|
|
56
59
|
if stage_result == "TEST_BLOCKED":
|
|
@@ -62,16 +65,7 @@ def route_pipeline_repair(stage_result, repair_scope=None, repair_round=0):
|
|
|
62
65
|
terminal_status="WORKFLOW_BLOCKED",
|
|
63
66
|
)
|
|
64
67
|
return result
|
|
65
|
-
if stage_result
|
|
66
|
-
result.update(
|
|
67
|
-
blocked=True,
|
|
68
|
-
resumable=False,
|
|
69
|
-
reason="prizmkit-test stopped with a known remaining correction",
|
|
70
|
-
blocked_reason="test_needs_fixes",
|
|
71
|
-
terminal_status="WORKFLOW_BLOCKED",
|
|
72
|
-
)
|
|
73
|
-
return result
|
|
74
|
-
if stage_result != "REVIEW_NEEDS_FIXES":
|
|
68
|
+
if stage_result not in {"REVIEW_NEEDS_FIXES", "TEST_NEEDS_FIXES"}:
|
|
75
69
|
result.update(
|
|
76
70
|
blocked=True,
|
|
77
71
|
reason="unknown stage result is unsafe",
|
|
@@ -87,13 +81,27 @@ def route_pipeline_repair(stage_result, repair_scope=None, repair_round=0):
|
|
|
87
81
|
terminal_status="WORKFLOW_BLOCKED",
|
|
88
82
|
)
|
|
89
83
|
return result
|
|
84
|
+
if repair_scope not in VALID_REPAIR_SCOPES:
|
|
85
|
+
result.update(
|
|
86
|
+
blocked=True,
|
|
87
|
+
reason="repair scope is missing or unsafe",
|
|
88
|
+
blocked_reason="unsafe_repair_scope",
|
|
89
|
+
terminal_status="WORKFLOW_BLOCKED",
|
|
90
|
+
)
|
|
91
|
+
return result
|
|
90
92
|
|
|
91
93
|
result["repair_round"] = current_round + 1
|
|
94
|
+
reason = (
|
|
95
|
+
"test findings require implementation, fresh review, and fresh testing"
|
|
96
|
+
if stage_result == "TEST_NEEDS_FIXES"
|
|
97
|
+
else "review findings require implementation and fresh review"
|
|
98
|
+
)
|
|
92
99
|
result.update(
|
|
100
|
+
resumable=True,
|
|
93
101
|
next_stage="prizmkit-implement",
|
|
94
102
|
resume_from="prizmkit-implement",
|
|
95
103
|
route=["prizmkit-implement", "prizmkit-code-review", "prizmkit-test"],
|
|
96
|
-
reason=
|
|
104
|
+
reason=reason,
|
|
97
105
|
)
|
|
98
106
|
return result
|
|
99
107
|
|
|
@@ -117,7 +125,7 @@ def pipeline_checkpoint_metadata(artifact_dir, stage="plan",
|
|
|
117
125
|
return {
|
|
118
126
|
"schema_version": 1,
|
|
119
127
|
"artifact_dir": artifact_dir,
|
|
120
|
-
"orchestrator": "
|
|
128
|
+
"orchestrator": "pipeline-runtime",
|
|
121
129
|
"stage": stage,
|
|
122
130
|
"current_stage": current_stage,
|
|
123
131
|
"status": status,
|
|
@@ -176,7 +184,7 @@ def validate_rendered(content, required_markers=None, logger=None):
|
|
|
176
184
|
|
|
177
185
|
unreplaced = re.findall(r"\{\{[A-Z][A-Z_0-9]+\}\}", content)
|
|
178
186
|
if unreplaced:
|
|
179
|
-
|
|
187
|
+
errors.append(
|
|
180
188
|
"Unreplaced placeholders: {}".format(", ".join(sorted(set(unreplaced))))
|
|
181
189
|
)
|
|
182
190
|
|
|
@@ -309,7 +317,6 @@ def _contract_steps(contract):
|
|
|
309
317
|
def generate_checkpoint_from_sections(
|
|
310
318
|
sections,
|
|
311
319
|
step_mapping,
|
|
312
|
-
pipeline_mode,
|
|
313
320
|
workflow_type,
|
|
314
321
|
item_id,
|
|
315
322
|
item_slug,
|
|
@@ -359,7 +366,6 @@ def generate_checkpoint_from_sections(
|
|
|
359
366
|
return {
|
|
360
367
|
"version": 1,
|
|
361
368
|
"workflow_type": workflow_type,
|
|
362
|
-
"pipeline_mode": pipeline_mode,
|
|
363
369
|
"item_id": item_id,
|
|
364
370
|
"item_slug": item_slug,
|
|
365
371
|
"session_id": session_id,
|
|
@@ -409,10 +415,18 @@ def merge_checkpoint_state(existing, fresh, project_root, validator=None, logger
|
|
|
409
415
|
artifacts = step.get("required_artifacts", [])
|
|
410
416
|
skill = step.get("skill", "")
|
|
411
417
|
stage_result = previous.get("stage_result") if isinstance(previous, dict) else None
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
418
|
+
expected_results = {
|
|
419
|
+
"context-snapshot-and-plan": "PLAN_READY",
|
|
420
|
+
"bug-diagnosis-and-plan": "PLAN_READY",
|
|
421
|
+
"prizmkit-plan": "PLAN_READY",
|
|
422
|
+
"prizmkit-implement": "IMPLEMENTED",
|
|
423
|
+
"prizmkit-code-review": "REVIEW_PASS",
|
|
424
|
+
"prizmkit-test": "TEST_PASS",
|
|
425
|
+
"prizmkit-retrospective": "RETRO_COMPLETE",
|
|
426
|
+
"prizmkit-committer": "COMMITTED",
|
|
427
|
+
}
|
|
428
|
+
expected_result = expected_results.get(skill)
|
|
429
|
+
verdict_valid = expected_result is None or stage_result == expected_result
|
|
416
430
|
if verdict_valid and validator(skill, artifacts):
|
|
417
431
|
step["status"] = "completed"
|
|
418
432
|
if stage_result:
|
|
@@ -441,25 +455,6 @@ def merge_checkpoint_state(existing, fresh, project_root, validator=None, logger
|
|
|
441
455
|
return fresh
|
|
442
456
|
|
|
443
457
|
|
|
444
|
-
def determine_mode_from_complexity(value):
|
|
445
|
-
"""Map a coarse complexity/severity value to lite/standard/full."""
|
|
446
|
-
mapping = {
|
|
447
|
-
"low": "lite",
|
|
448
|
-
"medium": "lite",
|
|
449
|
-
"minor": "lite",
|
|
450
|
-
"high": "standard",
|
|
451
|
-
"major": "standard",
|
|
452
|
-
"critical": "full",
|
|
453
|
-
}
|
|
454
|
-
return mapping.get(str(value or "").lower(), "lite")
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
def normalize_mode(value, default="lite"):
|
|
458
|
-
"""Normalize a mode string to lite/standard/full."""
|
|
459
|
-
value = str(value or "").lower()
|
|
460
|
-
return value if value in {"lite", "standard", "full"} else default
|
|
461
|
-
|
|
462
|
-
|
|
463
458
|
def detect_dev_server_port(project_root):
|
|
464
459
|
"""Return a detected dev-server port string, or an unknown placeholder."""
|
|
465
460
|
unknown = "<UNKNOWN_DETECT_FROM_PROJECT_CONFIG>"
|
|
@@ -1003,11 +1003,8 @@ def action_status(bug_list_data, state_dir, project_root=None):
|
|
|
1003
1003
|
bs = load_bug_status(state_dir, bid)
|
|
1004
1004
|
retry_count = bs.get("retry_count", 0)
|
|
1005
1005
|
max_retries_val = bs.get("max_retries", 3)
|
|
1006
|
-
# Read
|
|
1006
|
+
# Read the authoritative checkpoint cursor without mutating cached runtime state.
|
|
1007
1007
|
resume_phase = _checkpoint_phase_or_cached(project_root, bid, bs)
|
|
1008
|
-
if resume_phase != bs.get("resume_from_phase"):
|
|
1009
|
-
bs["resume_from_phase"] = resume_phase
|
|
1010
|
-
save_bug_status(state_dir, bid, bs)
|
|
1011
1008
|
|
|
1012
1009
|
if bstatus in counts:
|
|
1013
1010
|
counts[bstatus] += 1
|
|
@@ -14,6 +14,7 @@ if _PIPELINE_ROOT not in sys.path:
|
|
|
14
14
|
|
|
15
15
|
from prizmkit_runtime.checkpoint_state import ( # noqa: E402
|
|
16
16
|
MAX_OUTER_REPAIR_ROUNDS,
|
|
17
|
+
PLAN_RESULTS,
|
|
17
18
|
REVIEW_RESULTS,
|
|
18
19
|
SKILL_WORKFLOW_STAGES,
|
|
19
20
|
STEP_ID_PATTERN,
|
|
@@ -110,9 +111,16 @@ def _mandatory_predecessor_verdict_error(steps, index, workflow_type):
|
|
|
110
111
|
preceding = steps[:index]
|
|
111
112
|
review = next((item for item in preceding if item.get("skill") == "prizmkit-code-review"), None)
|
|
112
113
|
test = next((item for item in preceding if item.get("skill") == "prizmkit-test"), None)
|
|
114
|
+
skill = steps[index].get("skill")
|
|
115
|
+
if skill == "prizmkit-implement":
|
|
116
|
+
planning = [
|
|
117
|
+
item for item in preceding
|
|
118
|
+
if item.get("stage_result") in PLAN_RESULTS
|
|
119
|
+
]
|
|
120
|
+
if len(planning) != 1 or planning[0].get("status") != "completed" or planning[0].get("stage_result") != "PLAN_READY":
|
|
121
|
+
return "Implementation requires a completed PLAN_READY predecessor"
|
|
113
122
|
if review is None and test is None:
|
|
114
123
|
return None
|
|
115
|
-
skill = steps[index].get("skill")
|
|
116
124
|
if skill == "prizmkit-test":
|
|
117
125
|
if not review or review.get("status") != "completed" or review.get("stage_result") != "REVIEW_PASS":
|
|
118
126
|
return "Test stage requires a completed REVIEW_PASS predecessor"
|
|
@@ -170,23 +178,27 @@ def _validate_semantic_update(step, semantic_update):
|
|
|
170
178
|
|
|
171
179
|
|
|
172
180
|
def _apply_repair_policy(l4_state, stage_result, repair_scope):
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
181
|
+
terminal_blockers = {
|
|
182
|
+
"PLAN_BLOCKED": "plan_blocked",
|
|
183
|
+
"IMPLEMENT_REPAIR": "implementation_repair",
|
|
184
|
+
"IMPLEMENT_BLOCKED": "implementation_blocked",
|
|
185
|
+
"TEST_BLOCKED": "test_blocked",
|
|
186
|
+
"RETRO_BLOCKED": "retrospective_blocked",
|
|
187
|
+
"COMMIT_BLOCKED": "commit_blocked",
|
|
188
|
+
}
|
|
189
|
+
if stage_result in terminal_blockers:
|
|
179
190
|
l4_state.update(
|
|
180
191
|
terminal_status="WORKFLOW_BLOCKED",
|
|
181
|
-
blocked_reason=
|
|
182
|
-
"test_needs_fixes"
|
|
183
|
-
if stage_result == "TEST_NEEDS_FIXES"
|
|
184
|
-
else "test_blocked"
|
|
185
|
-
),
|
|
192
|
+
blocked_reason=terminal_blockers[stage_result],
|
|
186
193
|
current_stage=None,
|
|
187
194
|
next_stage=None,
|
|
188
195
|
)
|
|
189
196
|
return False
|
|
197
|
+
if stage_result not in {"REVIEW_NEEDS_FIXES", "TEST_NEEDS_FIXES"}:
|
|
198
|
+
return False
|
|
199
|
+
current_round = l4_state.get("repair_round", 0)
|
|
200
|
+
if not isinstance(current_round, int) or isinstance(current_round, bool):
|
|
201
|
+
current_round = MAX_OUTER_REPAIR_ROUNDS
|
|
190
202
|
if current_round >= MAX_OUTER_REPAIR_ROUNDS:
|
|
191
203
|
l4_state.update(
|
|
192
204
|
repair_round=MAX_OUTER_REPAIR_ROUNDS,
|
|
@@ -205,12 +217,36 @@ def _apply_repair_policy(l4_state, stage_result, repair_scope):
|
|
|
205
217
|
)
|
|
206
218
|
return False
|
|
207
219
|
l4_state["repair_round"] = current_round + 1
|
|
220
|
+
l4_state["repair_scope"] = repair_scope
|
|
208
221
|
l4_state["terminal_status"] = None
|
|
209
222
|
l4_state["blocked_reason"] = None
|
|
210
223
|
l4_state["next_stage"] = "prizmkit-implement"
|
|
211
224
|
return True
|
|
212
225
|
|
|
213
226
|
|
|
227
|
+
def _prepare_repair_reentry(data, index):
|
|
228
|
+
"""Rewind downstream gates when a routed repair re-enters implementation."""
|
|
229
|
+
step = data["steps"][index]
|
|
230
|
+
if step.get("skill") != "prizmkit-implement":
|
|
231
|
+
return
|
|
232
|
+
state_key = semantic_state_key(str(data.get("workflow_type") or ""))
|
|
233
|
+
l4_state = data.get(state_key)
|
|
234
|
+
if not isinstance(l4_state, dict):
|
|
235
|
+
return
|
|
236
|
+
if (
|
|
237
|
+
l4_state.get("next_stage") != "prizmkit-implement"
|
|
238
|
+
or l4_state.get("stage_result")
|
|
239
|
+
not in {"REVIEW_NEEDS_FIXES", "TEST_NEEDS_FIXES"}
|
|
240
|
+
):
|
|
241
|
+
return
|
|
242
|
+
for later in data["steps"][index + 1:]:
|
|
243
|
+
later["status"] = "pending"
|
|
244
|
+
later.pop("stage_result", None)
|
|
245
|
+
later.pop("note", None)
|
|
246
|
+
l4_state["terminal_status"] = None
|
|
247
|
+
l4_state["blocked_reason"] = None
|
|
248
|
+
|
|
249
|
+
|
|
214
250
|
def _sync_cursor(data, l4_state, preserve_next_stage=False):
|
|
215
251
|
active = next(
|
|
216
252
|
(step for step in data["steps"] if step.get("status") not in TERMINAL_STEP_STATUSES),
|
|
@@ -291,6 +327,9 @@ def update_checkpoint(
|
|
|
291
327
|
suffix = " Available: {}".format(", ".join(available)) if available else ""
|
|
292
328
|
return {"ok": False, "error": "{}{}".format(find_error or "Step not found.", suffix)}
|
|
293
329
|
|
|
330
|
+
if new_status == "in_progress":
|
|
331
|
+
_prepare_repair_reentry(data, index)
|
|
332
|
+
|
|
294
333
|
if new_status in {"in_progress", "completed", "skipped"} and not _predecessors_terminal(data["steps"], index):
|
|
295
334
|
return {
|
|
296
335
|
"ok": False,
|
|
@@ -306,6 +345,11 @@ def update_checkpoint(
|
|
|
306
345
|
return {"ok": False, "error": verdict_error}
|
|
307
346
|
|
|
308
347
|
semantic_update = _normalize_semantic_update(semantic_update)
|
|
348
|
+
if semantic_update.get("stage_result") == "COMMITTED":
|
|
349
|
+
return {
|
|
350
|
+
"ok": False,
|
|
351
|
+
"error": "COMMITTED is Runtime-owned and cannot be written by the Prompt checkpoint helper",
|
|
352
|
+
}
|
|
309
353
|
semantic_error = _validate_semantic_update(step, semantic_update)
|
|
310
354
|
if semantic_error:
|
|
311
355
|
return {"ok": False, "error": semantic_error}
|
|
@@ -319,6 +363,10 @@ def update_checkpoint(
|
|
|
319
363
|
stage_result = stage_result or step.get("stage_result")
|
|
320
364
|
if stage_result != "TEST_PASS":
|
|
321
365
|
return {"ok": False, "error": "Test completion requires TEST_PASS"}
|
|
366
|
+
if new_status == "completed" and step.get("skill") == "prizmkit-committer":
|
|
367
|
+
stage_result = stage_result or step.get("stage_result")
|
|
368
|
+
if stage_result != "COMMITTED":
|
|
369
|
+
return {"ok": False, "error": "Committer completion requires Runtime-owned COMMITTED"}
|
|
322
370
|
expected_status = expected_status_for_stage_result(stage_result)
|
|
323
371
|
if expected_status is not None and new_status != expected_status:
|
|
324
372
|
return {
|
|
@@ -350,7 +398,7 @@ def update_checkpoint(
|
|
|
350
398
|
if key in semantic_update:
|
|
351
399
|
l4_state[key] = semantic_update[key]
|
|
352
400
|
l4_state["schema_version"] = 1
|
|
353
|
-
l4_state["orchestrator"] = "
|
|
401
|
+
l4_state["orchestrator"] = "pipeline-runtime"
|
|
354
402
|
skill = step.get("skill")
|
|
355
403
|
l4_state["stage"] = SKILL_WORKFLOW_STAGES.get(skill, skill)
|
|
356
404
|
l4_state["status"] = new_status
|