prizmkit 1.1.129 → 1.1.131
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/dev-pipeline/.env.example +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/checkpoint_state.py +445 -8
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +87 -66
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +53 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +55 -25
- package/bundled/dev-pipeline/prizmkit_runtime/runner_status.py +4 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +15 -1
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +398 -6
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +61 -3
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +64 -4
- package/bundled/dev-pipeline/scripts/prompt_framework.py +156 -7
- package/bundled/dev-pipeline/scripts/update-bug-status.py +53 -0
- package/bundled/dev-pipeline/scripts/update-checkpoint.py +294 -69
- package/bundled/dev-pipeline/scripts/update-feature-status.py +57 -0
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +53 -0
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +2 -2
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +20 -14
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +21 -4
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +18 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +1 -1
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +5 -15
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-test.md +21 -0
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +10 -10
- package/bundled/dev-pipeline/templates/sections/headless-commit-authorization.md +16 -0
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +26 -23
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +12 -8
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-phase-test.md +21 -0
- package/bundled/dev-pipeline/tests/test_checkpoint_state.py +362 -3
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +404 -24
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +132 -0
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +91 -0
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +411 -18
- package/bundled/dev-pipeline/tests/test_unified_cli.py +3 -3
- package/bundled/skills/_metadata.json +62 -25
- package/bundled/skills/app-planner/SKILL.md +4 -3
- package/bundled/skills/bug-fix-workflow/SKILL.md +89 -180
- package/bundled/skills/bug-planner/SKILL.md +12 -27
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +131 -220
- package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +36 -90
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +129 -271
- package/bundled/skills/feature-pipeline-launcher/references/configuration.md +35 -76
- package/bundled/skills/feature-planner/SKILL.md +27 -22
- package/bundled/skills/feature-planner/assets/planning-guide.md +4 -4
- package/bundled/skills/feature-workflow/SKILL.md +94 -121
- package/bundled/skills/prizmkit/SKILL.md +130 -94
- package/bundled/skills/prizmkit/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/prizmkit-code-review/SKILL.md +114 -84
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +1 -1
- package/bundled/skills/prizmkit-code-review/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/prizmkit-committer/SKILL.md +131 -47
- package/bundled/skills/prizmkit-committer/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/prizmkit-implement/SKILL.md +99 -73
- package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +1 -1
- package/bundled/skills/prizmkit-implement/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/prizmkit-init/SKILL.md +5 -5
- package/bundled/skills/prizmkit-plan/SKILL.md +132 -105
- package/bundled/skills/prizmkit-plan/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/prizmkit-retrospective/SKILL.md +111 -53
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +7 -6
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +5 -4
- package/bundled/skills/prizmkit-retrospective/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/prizmkit-test/SKILL.md +28 -6
- package/bundled/skills/prizmkit-test/references/examples.md +1 -1
- package/bundled/skills/prizmkit-test/references/test-report-template.md +1 -1
- package/bundled/skills/prizmkit-test/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/prizmkit-workflow/SKILL.md +266 -0
- package/bundled/skills/prizmkit-workflow/references/workflow-state-protocol.md +181 -0
- package/bundled/skills/recovery-workflow/SKILL.md +62 -241
- package/bundled/skills/recovery-workflow/evals/evals.json +17 -33
- package/bundled/skills/recovery-workflow/references/detection.md +28 -52
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +105 -439
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +136 -275
- package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +53 -88
- package/bundled/skills/refactor-planner/SKILL.md +12 -57
- package/bundled/skills/refactor-planner/references/behavior-preservation.md +111 -230
- package/bundled/skills/refactor-planner/references/error-recovery.md +37 -0
- package/bundled/skills/refactor-planner/references/planning-phases.md +11 -17
- package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +1 -1
- package/bundled/skills/refactor-workflow/SKILL.md +98 -139
- package/bundled/templates/project-memory-template.md +4 -4
- package/package.json +1 -1
- package/src/index.js +4 -0
- package/src/prompts.js +10 -3
- package/src/scaffold.js +1 -1
- package/bundled/dev-pipeline/tests/test-deploy-safety.sh +0 -223
- package/bundled/skills/feature-pipeline-launcher/scripts/preflight-check.py +0 -462
|
@@ -22,9 +22,11 @@ from prompt_framework import (
|
|
|
22
22
|
merge_checkpoint_state,
|
|
23
23
|
mode_agent_count,
|
|
24
24
|
normalize_mode,
|
|
25
|
+
pipeline_checkpoint_metadata,
|
|
25
26
|
read_text_file,
|
|
26
27
|
render_from_sections,
|
|
27
28
|
replace_placeholders,
|
|
29
|
+
route_pipeline_repair,
|
|
28
30
|
validate_rendered,
|
|
29
31
|
write_output,
|
|
30
32
|
)
|
|
@@ -34,6 +36,30 @@ from utils import enrich_global_context, helper_replacements, load_json_file, re
|
|
|
34
36
|
LOGGER = setup_logging("generate-refactor-prompt")
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
def route_refactor_repair(stage_result, repair_scope=None, repair_round=0):
|
|
40
|
+
"""Map Refactor review/test outcomes to the shared safe route contract."""
|
|
41
|
+
return route_pipeline_repair(stage_result, repair_scope, repair_round)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def refactor_checkpoint_metadata(artifact_dir, evidence=None, stage="plan",
|
|
45
|
+
status="PLAN_READY", stage_result=None,
|
|
46
|
+
repair_scope=None, repair_round=0,
|
|
47
|
+
next_stage="prizmkit-implement",
|
|
48
|
+
resume_from="prizmkit-implement"):
|
|
49
|
+
"""Build Refactor L4 handoff metadata while preserving Refactor L1 state."""
|
|
50
|
+
return pipeline_checkpoint_metadata(
|
|
51
|
+
artifact_dir,
|
|
52
|
+
evidence=evidence,
|
|
53
|
+
stage=stage,
|
|
54
|
+
status=status,
|
|
55
|
+
stage_result=stage_result,
|
|
56
|
+
repair_scope=repair_scope,
|
|
57
|
+
repair_round=repair_round,
|
|
58
|
+
next_stage=next_stage,
|
|
59
|
+
resume_from=resume_from,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
37
63
|
REFACTOR_SECTION_TO_SKILL = {
|
|
38
64
|
"refactor-phase-init": checkpoint_step("prizmkit-init", "Initialize", [".prizmkit/refactor/{slug}"]),
|
|
39
65
|
"refactor-phase-plan": checkpoint_step(
|
|
@@ -48,6 +74,14 @@ REFACTOR_SECTION_TO_SKILL = {
|
|
|
48
74
|
"prizmkit-code-review", "Review — Code Review & Behavior Verification",
|
|
49
75
|
[".prizmkit/refactor/{slug}/review-report.md"],
|
|
50
76
|
),
|
|
77
|
+
"refactor-phase-test": checkpoint_step(
|
|
78
|
+
"prizmkit-test", "Post-Review Test Gate",
|
|
79
|
+
[
|
|
80
|
+
".prizmkit/test/evidence/*/manifest.json",
|
|
81
|
+
".prizmkit/test/evidence/*/verdict.json",
|
|
82
|
+
".prizmkit/test/evidence/*/validation.json",
|
|
83
|
+
],
|
|
84
|
+
),
|
|
51
85
|
"phase-browser": checkpoint_step("browser-verification", "Browser Verification", []),
|
|
52
86
|
"refactor-phase-commit-report": checkpoint_group([
|
|
53
87
|
("prizmkit-retrospective", "Retrospective", []),
|
|
@@ -383,7 +417,7 @@ def _refactor_header(pipeline_mode):
|
|
|
383
417
|
return title + "\n" + desc + "\n"
|
|
384
418
|
|
|
385
419
|
|
|
386
|
-
def assemble_refactor_sections(pipeline_mode, sections_dir, browser_enabled):
|
|
420
|
+
def assemble_refactor_sections(pipeline_mode, sections_dir, browser_enabled, browser_tool="auto"):
|
|
387
421
|
sections = [
|
|
388
422
|
("header", _refactor_header(pipeline_mode)),
|
|
389
423
|
("refactor-session-context", load_section(sections_dir, "refactor-session-context.md")),
|
|
@@ -399,10 +433,16 @@ def assemble_refactor_sections(pipeline_mode, sections_dir, browser_enabled):
|
|
|
399
433
|
sections.extend([
|
|
400
434
|
("refactor-phase-implement", load_section(sections_dir, "refactor-phase-implement.md")),
|
|
401
435
|
("refactor-phase-review", load_section(sections_dir, "refactor-phase-review.md")),
|
|
436
|
+
("refactor-phase-test", load_section(sections_dir, "refactor-phase-test.md")),
|
|
402
437
|
])
|
|
403
438
|
if browser_enabled:
|
|
404
|
-
|
|
439
|
+
browser_section_file = {
|
|
440
|
+
"playwright-cli": "phase-browser-verification.md",
|
|
441
|
+
"opencli": "phase-browser-verification-opencli.md",
|
|
442
|
+
}.get(browser_tool, "phase-browser-verification-auto.md")
|
|
443
|
+
sections.append(("phase-browser", load_section(sections_dir, browser_section_file)))
|
|
405
444
|
sections.extend([
|
|
445
|
+
("headless-commit-authorization", load_section(sections_dir, "headless-commit-authorization.md")),
|
|
406
446
|
("refactor-phase-commit-report", load_section(sections_dir, "refactor-phase-commit-report.md")),
|
|
407
447
|
("refactor-session-status", load_section(sections_dir, "refactor-session-status.md")),
|
|
408
448
|
("refactor-critical-paths", load_section(sections_dir, "refactor-critical-paths.md")),
|
|
@@ -419,6 +459,7 @@ def generate_refactor_checkpoint(refactor_id, session_id, pipeline_mode="standar
|
|
|
419
459
|
("refactor-phase-plan", ""),
|
|
420
460
|
("refactor-phase-implement", ""),
|
|
421
461
|
("refactor-phase-review", ""),
|
|
462
|
+
("refactor-phase-test", ""),
|
|
422
463
|
("refactor-phase-commit-report", ""),
|
|
423
464
|
]
|
|
424
465
|
return generate_checkpoint_from_sections(
|
|
@@ -434,7 +475,11 @@ def generate_refactor_checkpoint(refactor_id, session_id, pipeline_mode="standar
|
|
|
434
475
|
|
|
435
476
|
|
|
436
477
|
def merge_refactor_checkpoint_state(existing, fresh, project_root):
|
|
437
|
-
|
|
478
|
+
merged = merge_checkpoint_state(existing, fresh, project_root, logger=LOGGER)
|
|
479
|
+
existing_state = existing.get("refactor_state")
|
|
480
|
+
if isinstance(existing_state, dict):
|
|
481
|
+
merged["refactor_state"] = existing_state
|
|
482
|
+
return merged
|
|
438
483
|
|
|
439
484
|
|
|
440
485
|
def emit_failure(message):
|
|
@@ -469,7 +514,10 @@ def main():
|
|
|
469
514
|
sections = []
|
|
470
515
|
if use_sections:
|
|
471
516
|
try:
|
|
472
|
-
sections = assemble_refactor_sections(
|
|
517
|
+
sections = assemble_refactor_sections(
|
|
518
|
+
pipeline_mode, sections_dir, browser_enabled,
|
|
519
|
+
browser_tool=replacements["{{BROWSER_TOOL}}"],
|
|
520
|
+
)
|
|
473
521
|
rendered = render_from_sections(sections, replacements)
|
|
474
522
|
except FileNotFoundError as exc:
|
|
475
523
|
LOGGER.warning("Refactor section assembly failed (%s), falling back to legacy template", exc)
|
|
@@ -504,6 +552,18 @@ def main():
|
|
|
504
552
|
checkpoint = generate_refactor_checkpoint(
|
|
505
553
|
args.refactor_id, args.session_id, pipeline_mode, sections if use_sections else None,
|
|
506
554
|
)
|
|
555
|
+
if not any(step.get("skill") == "prizmkit-test" for step in checkpoint["steps"]):
|
|
556
|
+
emit_failure("Refactor checkpoint is missing the mandatory prizmkit-test stage")
|
|
557
|
+
checkpoint["refactor_state"] = refactor_checkpoint_metadata(
|
|
558
|
+
replacements["{{ARTIFACT_DIR}}"],
|
|
559
|
+
stage="plan",
|
|
560
|
+
status="PLAN_READY",
|
|
561
|
+
stage_result=None,
|
|
562
|
+
repair_scope=None,
|
|
563
|
+
repair_round=0,
|
|
564
|
+
next_stage="prizmkit-implement",
|
|
565
|
+
resume_from="prizmkit-implement",
|
|
566
|
+
)
|
|
507
567
|
|
|
508
568
|
if (args.resume_phase != "null" or is_continuation(args)) and os.path.exists(checkpoint_path):
|
|
509
569
|
try:
|
|
@@ -10,6 +10,137 @@ import os
|
|
|
10
10
|
import re
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
MAX_OUTER_REPAIR_ROUNDS = 3
|
|
14
|
+
REPAIR_SCOPES_REQUIRING_REVIEW = {
|
|
15
|
+
"production",
|
|
16
|
+
"runtime",
|
|
17
|
+
"schema",
|
|
18
|
+
"dependency",
|
|
19
|
+
"public-interface",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def route_pipeline_repair(stage_result, repair_scope=None, repair_round=0):
|
|
24
|
+
"""Map review/test outcomes to bounded, safe L4 continuation routes."""
|
|
25
|
+
try:
|
|
26
|
+
current_round = int(repair_round)
|
|
27
|
+
except (TypeError, ValueError):
|
|
28
|
+
current_round = MAX_OUTER_REPAIR_ROUNDS
|
|
29
|
+
if current_round < 0:
|
|
30
|
+
current_round = MAX_OUTER_REPAIR_ROUNDS
|
|
31
|
+
|
|
32
|
+
result = {
|
|
33
|
+
"stage_result": stage_result,
|
|
34
|
+
"repair_scope": repair_scope,
|
|
35
|
+
"repair_round": current_round,
|
|
36
|
+
"blocked": False,
|
|
37
|
+
"resumable": False,
|
|
38
|
+
"next_stage": None,
|
|
39
|
+
"resume_from": None,
|
|
40
|
+
"route": [],
|
|
41
|
+
"reason": "",
|
|
42
|
+
"blocked_reason": None,
|
|
43
|
+
"terminal_status": None,
|
|
44
|
+
}
|
|
45
|
+
if stage_result == "TEST_PASS":
|
|
46
|
+
result.update(
|
|
47
|
+
next_stage="prizmkit-retrospective",
|
|
48
|
+
resume_from="prizmkit-retrospective",
|
|
49
|
+
reason="authoritative test evidence passed",
|
|
50
|
+
)
|
|
51
|
+
return result
|
|
52
|
+
if stage_result == "TEST_BLOCKED":
|
|
53
|
+
result.update(
|
|
54
|
+
blocked=True,
|
|
55
|
+
resumable=False,
|
|
56
|
+
reason="bounded automatic recovery cannot safely edit production",
|
|
57
|
+
blocked_reason="test_blocked",
|
|
58
|
+
terminal_status="WORKFLOW_BLOCKED",
|
|
59
|
+
)
|
|
60
|
+
return result
|
|
61
|
+
if stage_result not in {"REVIEW_NEEDS_FIXES", "TEST_FAIL"}:
|
|
62
|
+
result.update(
|
|
63
|
+
blocked=True,
|
|
64
|
+
reason="unknown stage result is unsafe",
|
|
65
|
+
blocked_reason="unknown_stage_result",
|
|
66
|
+
terminal_status="WORKFLOW_BLOCKED",
|
|
67
|
+
)
|
|
68
|
+
return result
|
|
69
|
+
if current_round >= MAX_OUTER_REPAIR_ROUNDS:
|
|
70
|
+
result.update(
|
|
71
|
+
blocked=True,
|
|
72
|
+
reason="maximum outer repair rounds reached",
|
|
73
|
+
blocked_reason="repair_round_limit",
|
|
74
|
+
terminal_status="WORKFLOW_BLOCKED",
|
|
75
|
+
)
|
|
76
|
+
return result
|
|
77
|
+
|
|
78
|
+
result["repair_round"] = current_round + 1
|
|
79
|
+
if stage_result == "REVIEW_NEEDS_FIXES":
|
|
80
|
+
result.update(
|
|
81
|
+
next_stage="prizmkit-implement",
|
|
82
|
+
resume_from="prizmkit-implement",
|
|
83
|
+
route=["prizmkit-implement", "prizmkit-code-review", "prizmkit-test"],
|
|
84
|
+
reason="review findings require implementation and fresh review",
|
|
85
|
+
)
|
|
86
|
+
return result
|
|
87
|
+
if repair_scope == "test-infrastructure":
|
|
88
|
+
result.update(
|
|
89
|
+
next_stage="prizmkit-implement",
|
|
90
|
+
resume_from="prizmkit-implement",
|
|
91
|
+
route=["prizmkit-implement", "prizmkit-test"],
|
|
92
|
+
reason="test infrastructure failure must not edit production speculatively",
|
|
93
|
+
)
|
|
94
|
+
return result
|
|
95
|
+
if repair_scope in REPAIR_SCOPES_REQUIRING_REVIEW:
|
|
96
|
+
result.update(
|
|
97
|
+
next_stage="prizmkit-implement",
|
|
98
|
+
resume_from="prizmkit-implement",
|
|
99
|
+
route=["prizmkit-implement", "prizmkit-code-review", "prizmkit-test"],
|
|
100
|
+
reason="production-facing failure requires review before retesting",
|
|
101
|
+
)
|
|
102
|
+
return result
|
|
103
|
+
result.update(
|
|
104
|
+
blocked=True,
|
|
105
|
+
reason="unknown repair scope has no safe automatic route",
|
|
106
|
+
blocked_reason="unsafe_repair_scope",
|
|
107
|
+
terminal_status="WORKFLOW_BLOCKED",
|
|
108
|
+
)
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def pipeline_checkpoint_metadata(artifact_dir, evidence=None, stage="plan",
|
|
113
|
+
status="PLAN_READY", stage_result=None,
|
|
114
|
+
repair_scope=None, repair_round=0,
|
|
115
|
+
next_stage="prizmkit-implement",
|
|
116
|
+
resume_from="prizmkit-implement",
|
|
117
|
+
blocked_reason=None, terminal_status=None):
|
|
118
|
+
"""Build family-neutral semantic L4 metadata without replacing L1 state."""
|
|
119
|
+
evidence = evidence or {}
|
|
120
|
+
current_stage = None if terminal_status else stage
|
|
121
|
+
semantic_next_stage = None if terminal_status else next_stage
|
|
122
|
+
return {
|
|
123
|
+
"schema_version": 1,
|
|
124
|
+
"artifact_dir": artifact_dir,
|
|
125
|
+
"orchestrator": "prizmkit-l4",
|
|
126
|
+
"stage": stage,
|
|
127
|
+
"current_stage": current_stage,
|
|
128
|
+
"status": status,
|
|
129
|
+
"stage_result": stage_result,
|
|
130
|
+
"repair_scope": repair_scope,
|
|
131
|
+
"repair_round": repair_round,
|
|
132
|
+
"authoritative_evidence_paths": {
|
|
133
|
+
"manifest": evidence.get("manifest_path"),
|
|
134
|
+
"verdict": evidence.get("verdict_path"),
|
|
135
|
+
"validation": evidence.get("validation_path"),
|
|
136
|
+
},
|
|
137
|
+
"next_stage": semantic_next_stage,
|
|
138
|
+
"resume_from": resume_from,
|
|
139
|
+
"blocked_reason": blocked_reason,
|
|
140
|
+
"terminal_status": terminal_status,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
13
144
|
def read_text_file(path):
|
|
14
145
|
"""Read and return the text content of a file, plus an error string."""
|
|
15
146
|
abs_path = os.path.abspath(path)
|
|
@@ -257,8 +388,19 @@ def merge_checkpoint_state(existing, fresh, project_root, validator=None, logger
|
|
|
257
388
|
previous_status = previous.get("status", "pending") if isinstance(previous, dict) else "pending"
|
|
258
389
|
if previous_status == "completed":
|
|
259
390
|
artifacts = step.get("required_artifacts", [])
|
|
260
|
-
|
|
391
|
+
skill = step.get("skill", "")
|
|
392
|
+
stage_result = previous.get("stage_result") if isinstance(previous, dict) else None
|
|
393
|
+
verdict_valid = (
|
|
394
|
+
(skill != "prizmkit-code-review" or stage_result == "REVIEW_PASS")
|
|
395
|
+
and (skill != "prizmkit-test" or stage_result == "TEST_PASS")
|
|
396
|
+
)
|
|
397
|
+
if verdict_valid and validator(skill, artifacts):
|
|
261
398
|
step["status"] = "completed"
|
|
399
|
+
if stage_result:
|
|
400
|
+
step["stage_result"] = stage_result
|
|
401
|
+
evidence = previous.get("authoritative_evidence_paths")
|
|
402
|
+
if isinstance(evidence, dict):
|
|
403
|
+
step["authoritative_evidence_paths"] = evidence
|
|
262
404
|
continue
|
|
263
405
|
if logger is not None:
|
|
264
406
|
logger.warning(
|
|
@@ -271,6 +413,15 @@ def merge_checkpoint_state(existing, fresh, project_root, validator=None, logger
|
|
|
271
413
|
chain_broken = True
|
|
272
414
|
step["status"] = "pending"
|
|
273
415
|
|
|
416
|
+
workflow_type = fresh.get("workflow_type", "")
|
|
417
|
+
state_key = {
|
|
418
|
+
"feature-pipeline": "feature_state",
|
|
419
|
+
"bugfix-pipeline": "bugfix_state",
|
|
420
|
+
"refactor-pipeline": "refactor_state",
|
|
421
|
+
}.get(workflow_type)
|
|
422
|
+
if state_key and isinstance(existing.get(state_key), dict):
|
|
423
|
+
fresh[state_key] = dict(existing[state_key])
|
|
424
|
+
|
|
274
425
|
return fresh
|
|
275
426
|
|
|
276
427
|
|
|
@@ -327,21 +478,19 @@ def detect_dev_server_port(project_root):
|
|
|
327
478
|
|
|
328
479
|
|
|
329
480
|
def browser_enabled_from_item(item):
|
|
330
|
-
"""Return browser enabled/tool/steps with
|
|
481
|
+
"""Return browser enabled/tool/steps with explicit opt-in semantics."""
|
|
331
482
|
browser_interaction = item.get("browser_interaction") if isinstance(item, dict) else None
|
|
332
483
|
env_value = os.environ.get("BROWSER_VERIFY", "").lower()
|
|
333
484
|
if env_value == "false":
|
|
334
485
|
return False, "auto", "", False
|
|
335
486
|
|
|
336
|
-
enabled =
|
|
487
|
+
enabled = False
|
|
337
488
|
tool = "auto"
|
|
338
489
|
blocking = False
|
|
339
490
|
steps = []
|
|
340
491
|
|
|
341
|
-
if isinstance(browser_interaction,
|
|
342
|
-
enabled =
|
|
343
|
-
elif isinstance(browser_interaction, dict):
|
|
344
|
-
enabled = browser_interaction.get("enabled", True)
|
|
492
|
+
if isinstance(browser_interaction, dict):
|
|
493
|
+
enabled = True
|
|
345
494
|
tool = browser_interaction.get("tool", "auto")
|
|
346
495
|
blocking = bool(browser_interaction.get("blocking", False))
|
|
347
496
|
steps = browser_interaction.get("verify_steps", []) or []
|
|
@@ -46,6 +46,7 @@ SESSION_STATUS_VALUES = [
|
|
|
46
46
|
"infra_error",
|
|
47
47
|
"context_overflow",
|
|
48
48
|
"stalled_context_continuation",
|
|
49
|
+
"workflow_blocked",
|
|
49
50
|
"commit_missing",
|
|
50
51
|
"docs_missing",
|
|
51
52
|
"merge_conflict",
|
|
@@ -88,6 +89,7 @@ def parse_args():
|
|
|
88
89
|
parser.add_argument("--continuation-summary-path", default=None, help="Optional continuation summary artifact path.")
|
|
89
90
|
parser.add_argument("--no-progress-count", type=int, default=None, help="Consecutive context-overflow sessions without objective progress.")
|
|
90
91
|
parser.add_argument("--progress-fingerprint", default=None, help="JSON progress fingerprint captured after the session.")
|
|
92
|
+
parser.add_argument("--checkpoint-state", default=None, help="JSON semantic L4 checkpoint snapshot captured after the session.")
|
|
91
93
|
return parser.parse_args()
|
|
92
94
|
|
|
93
95
|
|
|
@@ -253,6 +255,37 @@ def _load_progress_fingerprint(raw):
|
|
|
253
255
|
return {"unparsed": str(raw)}
|
|
254
256
|
|
|
255
257
|
|
|
258
|
+
SEMANTIC_CHECKPOINT_FIELDS = (
|
|
259
|
+
"current_stage",
|
|
260
|
+
"next_stage",
|
|
261
|
+
"stage_result",
|
|
262
|
+
"repair_scope",
|
|
263
|
+
"repair_round",
|
|
264
|
+
"authoritative_evidence_paths",
|
|
265
|
+
"blocked_reason",
|
|
266
|
+
"terminal_status",
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _load_checkpoint_state(raw):
|
|
271
|
+
if not raw:
|
|
272
|
+
return {}
|
|
273
|
+
try:
|
|
274
|
+
data = json.loads(raw)
|
|
275
|
+
except (TypeError, ValueError):
|
|
276
|
+
return {}
|
|
277
|
+
if not isinstance(data, dict):
|
|
278
|
+
return {}
|
|
279
|
+
return {key: data.get(key) for key in SEMANTIC_CHECKPOINT_FIELDS}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _sync_semantic_checkpoint(status_data, args):
|
|
283
|
+
semantic = _load_checkpoint_state(getattr(args, "checkpoint_state", None))
|
|
284
|
+
if semantic:
|
|
285
|
+
status_data.update(semantic)
|
|
286
|
+
return {key: status_data.get(key) for key in SEMANTIC_CHECKPOINT_FIELDS}
|
|
287
|
+
|
|
288
|
+
|
|
256
289
|
def _set_continuation_common(status_data, args, session_id):
|
|
257
290
|
if args.active_dev_branch:
|
|
258
291
|
status_data["active_dev_branch"] = args.active_dev_branch
|
|
@@ -494,6 +527,7 @@ def action_update(args, bug_list_path, state_dir):
|
|
|
494
527
|
fingerprint = _load_progress_fingerprint(args.progress_fingerprint)
|
|
495
528
|
if fingerprint is not None:
|
|
496
529
|
bs["last_progress_fingerprint"] = fingerprint
|
|
530
|
+
semantic_checkpoint = _sync_semantic_checkpoint(bs, args)
|
|
497
531
|
|
|
498
532
|
|
|
499
533
|
if session_status == "success":
|
|
@@ -560,6 +594,19 @@ def action_update(args, bug_list_path, state_dir):
|
|
|
560
594
|
if err:
|
|
561
595
|
error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
|
|
562
596
|
return
|
|
597
|
+
elif session_status == "workflow_blocked":
|
|
598
|
+
# Semantic terminal state: preserve partial work without consuming any retry budget.
|
|
599
|
+
new_status = "needs_info"
|
|
600
|
+
bs["continuation_pending"] = False
|
|
601
|
+
bs["needs_attention"] = True
|
|
602
|
+
bs["terminal_status"] = "WORKFLOW_BLOCKED"
|
|
603
|
+
bs["blocked_reason"] = (
|
|
604
|
+
semantic_checkpoint.get("blocked_reason") or "workflow_blocked"
|
|
605
|
+
)
|
|
606
|
+
err = update_bug_in_list(bug_list_path, bug_id, new_status)
|
|
607
|
+
if err:
|
|
608
|
+
error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
|
|
609
|
+
return
|
|
563
610
|
elif session_status == "stalled_context_continuation":
|
|
564
611
|
# No-progress context-overflow stall pauses automation without consuming retry budgets.
|
|
565
612
|
set_stalled_context_continuation_metadata(bs, args, session_id)
|
|
@@ -616,6 +663,7 @@ def action_update(args, bug_list_path, state_dir):
|
|
|
616
663
|
"infra_error_count": bs.get("infra_error_count", 0),
|
|
617
664
|
"max_infra_retries": max_infra_retries,
|
|
618
665
|
"resume_from_phase": bs.get("resume_from_phase"),
|
|
666
|
+
"checkpoint_state": semantic_checkpoint,
|
|
619
667
|
"updated_at": bs["updated_at"],
|
|
620
668
|
}
|
|
621
669
|
if session_status in ("commit_missing", "docs_missing", "merge_conflict"):
|
|
@@ -630,6 +678,11 @@ def action_update(args, bug_list_path, state_dir):
|
|
|
630
678
|
summary["restart_policy"] = "context_overflow_continuation"
|
|
631
679
|
summary.update(continuation_metadata_summary(bs))
|
|
632
680
|
summary["artifacts_preserved"] = True
|
|
681
|
+
elif session_status == "workflow_blocked":
|
|
682
|
+
summary["restart_policy"] = "terminal_blocked"
|
|
683
|
+
summary.update(continuation_metadata_summary(bs))
|
|
684
|
+
summary["checkpoint_state"] = semantic_checkpoint
|
|
685
|
+
summary["artifacts_preserved"] = True
|
|
633
686
|
elif session_status == "stalled_context_continuation":
|
|
634
687
|
summary["restart_policy"] = "needs_attention"
|
|
635
688
|
summary.update(continuation_metadata_summary(bs))
|