prizmkit 1.1.106 → 1.1.108
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/bin/create-prizmkit.js +4 -0
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/config.py +81 -14
- package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +19 -8
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +0 -1
- package/bundled/dev-pipeline/prizmkit_runtime/launch_profiles.py +18 -0
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +22 -2
- package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +56 -5
- package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +0 -8
- package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +11 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +298 -63
- package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +243 -37
- package/bundled/dev-pipeline/scripts/continuation.py +0 -5
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +10 -82
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +7 -64
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +40 -63
- package/bundled/dev-pipeline/scripts/utils.py +123 -0
- package/bundled/dev-pipeline/templates/agent-prompts/critic-plan-challenge.md +4 -3
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +5 -6
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +36 -35
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +53 -80
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +43 -78
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +5 -17
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +6 -18
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +14 -48
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +7 -14
- package/bundled/dev-pipeline/templates/sections/feature-context.md +0 -4
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-opencli.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +0 -14
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +0 -14
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-base.md +0 -2
- package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-lite-suffix.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan-full.md +6 -8
- package/bundled/dev-pipeline/templates/sections/phase-critic-plan.md +3 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +4 -16
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +4 -17
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase-plan-agent.md +2 -9
- package/bundled/dev-pipeline/templates/sections/phase-plan-lite.md +1 -8
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +15 -16
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +3 -10
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +3 -10
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +2 -9
- package/bundled/dev-pipeline/templates/sections/phase0-init.md +0 -7
- package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +2 -15
- package/bundled/dev-pipeline/tests/conftest.py +0 -1
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +395 -21
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +50 -14
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +154 -2
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +431 -3
- package/bundled/dev-pipeline/tests/test_unified_cli.py +857 -5
- package/bundled/skills/_metadata.json +4 -4
- package/bundled/skills/app-planner/SKILL.md +1 -1
- package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
- package/bundled/skills/bug-fix-workflow/SKILL.md +174 -128
- package/bundled/skills/bug-planner/SKILL.md +101 -15
- package/bundled/skills/bug-planner/references/severity-rules.md +20 -8
- package/bundled/skills/feature-planner/SKILL.md +87 -8
- package/bundled/skills/feature-planner/assets/planning-guide.md +34 -10
- package/bundled/skills/feature-workflow/SKILL.md +100 -81
- package/bundled/skills/{prizm-kit → prizmkit}/SKILL.md +1 -1
- package/bundled/skills/prizmkit-code-review/SKILL.md +12 -13
- package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +10 -10
- package/bundled/skills/refactor-planner/SKILL.md +88 -7
- package/bundled/skills/refactor-planner/references/fast-path.md +2 -1
- package/bundled/skills/refactor-planner/references/planning-phases.md +29 -11
- package/bundled/skills/refactor-workflow/SKILL.md +116 -57
- package/bundled/templates/project-memory-template.md +1 -1
- package/package.json +1 -1
- package/src/ai-cli-launch.js +194 -0
- package/src/config.js +26 -14
- package/src/index.js +11 -44
- package/src/platforms.js +10 -3
- package/src/prompts.js +60 -2
- package/src/scaffold.js +26 -14
- package/bundled/dev-pipeline/scripts/prizmkit-test-gate.py +0 -446
- package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +0 -7
- package/bundled/dev-pipeline/templates/agent-prompts/dev-resume.md +0 -5
- package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +0 -20
- package/bundled/dev-pipeline/tests/test_prizmkit_test_gate.py +0 -107
- package/bundled/skills/prizmkit-code-review/references/dev-agent-prompt.md +0 -30
|
@@ -19,12 +19,11 @@ import os
|
|
|
19
19
|
import re
|
|
20
20
|
import sys
|
|
21
21
|
|
|
22
|
-
from utils import enrich_global_context, load_json_file,
|
|
22
|
+
from utils import enrich_global_context, load_json_file, read_checkpoint_system_section, resolve_prompt_platform, setup_logging
|
|
23
23
|
from continuation import add_continuation_args, append_continuation_handoff, is_continuation
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
DEFAULT_MAX_RETRIES = 3
|
|
27
|
-
DEFAULT_MAX_LOG_SIZE = 2097152
|
|
28
27
|
|
|
29
28
|
LOGGER = setup_logging("generate-bugfix-prompt")
|
|
30
29
|
|
|
@@ -66,27 +65,6 @@ def read_text_file(path):
|
|
|
66
65
|
|
|
67
66
|
|
|
68
67
|
|
|
69
|
-
def _format_bytes(n):
|
|
70
|
-
"""Format a byte count to a human-readable string."""
|
|
71
|
-
if n >= 1048576:
|
|
72
|
-
return "{}MB".format(n // 1048576)
|
|
73
|
-
elif n >= 1024:
|
|
74
|
-
return "{}KB".format(n // 1024)
|
|
75
|
-
return "{}B".format(n)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def _parse_non_negative_int_env(name, default):
|
|
79
|
-
"""Parse a non-negative integer environment variable."""
|
|
80
|
-
value = os.environ.get(name, str(default))
|
|
81
|
-
try:
|
|
82
|
-
parsed = int(value)
|
|
83
|
-
except ValueError:
|
|
84
|
-
raise ValueError("{} must be a non-negative integer".format(name))
|
|
85
|
-
if parsed < 0:
|
|
86
|
-
raise ValueError("{} must be a non-negative integer".format(name))
|
|
87
|
-
return parsed
|
|
88
|
-
|
|
89
|
-
|
|
90
68
|
def _parse_positive_int_env(name, default):
|
|
91
69
|
"""Parse a positive integer environment variable."""
|
|
92
70
|
value = os.environ.get(name, str(default))
|
|
@@ -99,23 +77,6 @@ def _parse_positive_int_env(name, default):
|
|
|
99
77
|
return parsed
|
|
100
78
|
|
|
101
79
|
|
|
102
|
-
def load_log_size_section(script_dir):
|
|
103
|
-
"""Load the optional log-size awareness prompt section."""
|
|
104
|
-
max_log_size = _parse_non_negative_int_env("MAX_LOG_SIZE", DEFAULT_MAX_LOG_SIZE)
|
|
105
|
-
if max_log_size == 0:
|
|
106
|
-
return ""
|
|
107
|
-
|
|
108
|
-
section_path = os.path.join(
|
|
109
|
-
script_dir, "..", "templates", "sections", "log-size-awareness.md",
|
|
110
|
-
)
|
|
111
|
-
if not os.path.isfile(section_path):
|
|
112
|
-
return ""
|
|
113
|
-
|
|
114
|
-
content, err = read_text_file(section_path)
|
|
115
|
-
if err:
|
|
116
|
-
return ""
|
|
117
|
-
return content
|
|
118
|
-
|
|
119
80
|
def find_bug(bugs, bug_id):
|
|
120
81
|
"""Find and return the bug dict matching the given ID."""
|
|
121
82
|
for bug in bugs:
|
|
@@ -287,17 +248,9 @@ def build_replacements(args, bug, global_context, script_dir):
|
|
|
287
248
|
project_root = _args_project_root(args, script_dir)
|
|
288
249
|
|
|
289
250
|
# Platform-aware agent/team path resolution
|
|
290
|
-
platform =
|
|
251
|
+
platform = resolve_prompt_platform(project_root)
|
|
291
252
|
home_dir = os.path.expanduser("~")
|
|
292
253
|
|
|
293
|
-
if not platform:
|
|
294
|
-
if os.path.isdir(os.path.join(project_root, ".codex", "agents")):
|
|
295
|
-
platform = "codex"
|
|
296
|
-
elif os.path.isdir(os.path.join(project_root, ".claude", "agents")):
|
|
297
|
-
platform = "claude"
|
|
298
|
-
else:
|
|
299
|
-
platform = "codebuddy"
|
|
300
|
-
|
|
301
254
|
if platform == "claude":
|
|
302
255
|
agents_dir = os.path.join(project_root, ".claude", "agents")
|
|
303
256
|
team_config_path = os.path.join(project_root, ".claude", "team-info.json")
|
|
@@ -373,12 +326,7 @@ def build_replacements(args, bug, global_context, script_dir):
|
|
|
373
326
|
browser_enabled = True
|
|
374
327
|
browser_verify_steps = " # (reproduce bug and verify fix)"
|
|
375
328
|
|
|
376
|
-
max_log_size = _parse_non_negative_int_env("MAX_LOG_SIZE", DEFAULT_MAX_LOG_SIZE)
|
|
377
|
-
|
|
378
329
|
replacements = {
|
|
379
|
-
"{{LOG_SIZE_AWARENESS}}": load_log_size_section(script_dir),
|
|
380
|
-
"{{MAX_LOG_SIZE}}": str(max_log_size),
|
|
381
|
-
"{{MAX_LOG_SIZE_HUMAN}}": _format_bytes(max_log_size),
|
|
382
330
|
"{{SESSION_LOG_PATH}}": os.path.join(
|
|
383
331
|
".prizmkit", "state", "bugfix", args.bug_id,
|
|
384
332
|
"sessions", args.session_id, "logs", "session.log",
|
|
@@ -398,12 +346,15 @@ def build_replacements(args, bug, global_context, script_dir):
|
|
|
398
346
|
),
|
|
399
347
|
"{{ENVIRONMENT}}": format_environment(bug.get("environment")),
|
|
400
348
|
"{{GLOBAL_CONTEXT}}": format_global_context(global_context, project_root),
|
|
401
|
-
"{{PLATFORM_CONVENTIONS}}": read_platform_conventions(project_root),
|
|
402
349
|
"{{TEAM_CONFIG_PATH}}": team_config_path,
|
|
403
350
|
"{{DEV_SUBAGENT_PATH}}": dev_subagent,
|
|
404
351
|
"{{REVIEWER_SUBAGENT_PATH}}": reviewer_subagent,
|
|
405
352
|
"{{SESSION_STATUS_PATH}}": session_status_path,
|
|
406
353
|
"{{PROJECT_ROOT}}": project_root,
|
|
354
|
+
"{{CHECKPOINT_PATH}}": os.path.join(
|
|
355
|
+
".prizmkit", "bugfix", args.bug_id, "workflow-checkpoint.json",
|
|
356
|
+
),
|
|
357
|
+
"{{CHECKPOINT_SYSTEM}}": read_checkpoint_system_section(script_dir),
|
|
407
358
|
"{{FIX_SCOPE}}": fix_scope,
|
|
408
359
|
"{{TIMESTAMP}}": "", # Placeholder, agent fills in the timestamp
|
|
409
360
|
"{{BROWSER_ENABLED}}": "true" if browser_enabled else "false",
|
|
@@ -659,15 +610,6 @@ def main():
|
|
|
659
610
|
|
|
660
611
|
# Build replacements
|
|
661
612
|
replacements = build_replacements(args, bug, global_context, script_dir)
|
|
662
|
-
if is_continuation(args):
|
|
663
|
-
replacements["{{LOG_SIZE_AWARENESS}}"] = ""
|
|
664
|
-
|
|
665
|
-
# Add checkpoint path to replacements
|
|
666
|
-
checkpoint_rel = os.path.join(
|
|
667
|
-
".prizmkit", "bugfix", args.bug_id, "workflow-checkpoint.json",
|
|
668
|
-
)
|
|
669
|
-
replacements["{{CHECKPOINT_PATH}}"] = checkpoint_rel
|
|
670
|
-
|
|
671
613
|
# Render the template
|
|
672
614
|
rendered = render_template(template_content, replacements, bug)
|
|
673
615
|
|
|
@@ -678,6 +620,7 @@ def main():
|
|
|
678
620
|
|
|
679
621
|
# Generate checkpoint file
|
|
680
622
|
project_root = _args_project_root(args, script_dir)
|
|
623
|
+
checkpoint_rel = replacements["{{CHECKPOINT_PATH}}"]
|
|
681
624
|
checkpoint_path = os.path.join(project_root, checkpoint_rel)
|
|
682
625
|
checkpoint_dir = os.path.dirname(checkpoint_path)
|
|
683
626
|
os.makedirs(checkpoint_dir, exist_ok=True)
|
|
@@ -19,12 +19,11 @@ import os
|
|
|
19
19
|
import re
|
|
20
20
|
import sys
|
|
21
21
|
|
|
22
|
-
from utils import enrich_global_context, load_json_file,
|
|
22
|
+
from utils import enrich_global_context, load_json_file, read_checkpoint_system_section, resolve_prompt_platform, setup_logging
|
|
23
23
|
from continuation import add_continuation_args, append_continuation_handoff, is_continuation
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
DEFAULT_MAX_RETRIES = 3
|
|
27
|
-
DEFAULT_MAX_LOG_SIZE = 2097152
|
|
28
27
|
|
|
29
28
|
LOGGER = setup_logging("generate-refactor-prompt")
|
|
30
29
|
|
|
@@ -135,6 +134,7 @@ def parse_args():
|
|
|
135
134
|
parser.add_argument("--resume-phase", required=True, help='Phase to resume from, or "null" for fresh start')
|
|
136
135
|
parser.add_argument("--state-dir", default=None, help="State directory (default: .prizmkit/state/refactor)")
|
|
137
136
|
parser.add_argument("--output", required=True, help="Output path for the rendered prompt")
|
|
137
|
+
parser.add_argument("--project-root", default=None, help="AI-visible project root used for rendered prompt paths")
|
|
138
138
|
parser.add_argument("--template", default=None, help="Custom template path. Defaults to {script_dir}/../templates/refactor-bootstrap-prompt.md")
|
|
139
139
|
parser.add_argument("--mode", default=None, help="Pipeline execution mode override: lite, standard, full")
|
|
140
140
|
parser.add_argument("--critic", default=None, help="Enable critic agent: true/false")
|
|
@@ -156,27 +156,6 @@ def read_text_file(path):
|
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
|
|
159
|
-
def _format_bytes(n):
|
|
160
|
-
"""Format a byte count to a human-readable string."""
|
|
161
|
-
if n >= 1048576:
|
|
162
|
-
return "{}MB".format(n // 1048576)
|
|
163
|
-
elif n >= 1024:
|
|
164
|
-
return "{}KB".format(n // 1024)
|
|
165
|
-
return "{}B".format(n)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def _parse_non_negative_int_env(name, default):
|
|
169
|
-
"""Parse a non-negative integer environment variable."""
|
|
170
|
-
value = os.environ.get(name, str(default))
|
|
171
|
-
try:
|
|
172
|
-
parsed = int(value)
|
|
173
|
-
except ValueError:
|
|
174
|
-
raise ValueError("{} must be a non-negative integer".format(name))
|
|
175
|
-
if parsed < 0:
|
|
176
|
-
raise ValueError("{} must be a non-negative integer".format(name))
|
|
177
|
-
return parsed
|
|
178
|
-
|
|
179
|
-
|
|
180
159
|
def _parse_positive_int_env(name, default):
|
|
181
160
|
"""Parse a positive integer environment variable."""
|
|
182
161
|
value = os.environ.get(name, str(default))
|
|
@@ -189,23 +168,6 @@ def _parse_positive_int_env(name, default):
|
|
|
189
168
|
return parsed
|
|
190
169
|
|
|
191
170
|
|
|
192
|
-
def load_log_size_section(script_dir):
|
|
193
|
-
"""Load the optional log-size awareness prompt section."""
|
|
194
|
-
max_log_size = _parse_non_negative_int_env("MAX_LOG_SIZE", DEFAULT_MAX_LOG_SIZE)
|
|
195
|
-
if max_log_size == 0:
|
|
196
|
-
return ""
|
|
197
|
-
|
|
198
|
-
section_path = os.path.join(
|
|
199
|
-
script_dir, "..", "templates", "sections", "log-size-awareness.md",
|
|
200
|
-
)
|
|
201
|
-
if not os.path.isfile(section_path):
|
|
202
|
-
return ""
|
|
203
|
-
|
|
204
|
-
content, err = read_text_file(section_path)
|
|
205
|
-
if err:
|
|
206
|
-
return ""
|
|
207
|
-
return content
|
|
208
|
-
|
|
209
171
|
def find_refactor(refactors, refactor_id):
|
|
210
172
|
"""Find and return the refactor dict matching the given ID."""
|
|
211
173
|
for refactor in refactors:
|
|
@@ -422,22 +384,39 @@ def resolve_project_root(script_dir):
|
|
|
422
384
|
return os.path.abspath(pipeline_parent)
|
|
423
385
|
|
|
424
386
|
|
|
387
|
+
def _project_root_from_prizmkit_path(path):
|
|
388
|
+
"""Infer project root from a path nested under .prizmkit/."""
|
|
389
|
+
if not path:
|
|
390
|
+
return ""
|
|
391
|
+
current = os.path.abspath(path)
|
|
392
|
+
if not os.path.isdir(current):
|
|
393
|
+
current = os.path.dirname(current)
|
|
394
|
+
while current and current != os.path.dirname(current):
|
|
395
|
+
if os.path.basename(current) == ".prizmkit":
|
|
396
|
+
return os.path.abspath(os.path.dirname(current))
|
|
397
|
+
current = os.path.dirname(current)
|
|
398
|
+
return ""
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _args_project_root(args, script_dir):
|
|
402
|
+
"""Return explicit AI-visible project root, plan-path root, or script-layout default."""
|
|
403
|
+
explicit = getattr(args, "project_root", None)
|
|
404
|
+
if explicit:
|
|
405
|
+
return os.path.abspath(explicit)
|
|
406
|
+
plan_root = _project_root_from_prizmkit_path(getattr(args, "refactor_list", ""))
|
|
407
|
+
if plan_root:
|
|
408
|
+
return plan_root
|
|
409
|
+
return resolve_project_root(script_dir)
|
|
410
|
+
|
|
411
|
+
|
|
425
412
|
def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
426
413
|
"""Build the full dict of placeholder -> replacement value."""
|
|
427
|
-
project_root =
|
|
414
|
+
project_root = _args_project_root(args, script_dir)
|
|
428
415
|
|
|
429
416
|
# Platform-aware agent/team path resolution
|
|
430
|
-
platform =
|
|
417
|
+
platform = resolve_prompt_platform(project_root)
|
|
431
418
|
home_dir = os.path.expanduser("~")
|
|
432
419
|
|
|
433
|
-
if not platform:
|
|
434
|
-
if os.path.isdir(os.path.join(project_root, ".codex", "agents")):
|
|
435
|
-
platform = "codex"
|
|
436
|
-
elif os.path.isdir(os.path.join(project_root, ".claude", "agents")):
|
|
437
|
-
platform = "claude"
|
|
438
|
-
else:
|
|
439
|
-
platform = "codebuddy"
|
|
440
|
-
|
|
441
420
|
if platform == "claude":
|
|
442
421
|
agents_dir = os.path.join(project_root, ".claude", "agents")
|
|
443
422
|
team_config_path = os.path.join(project_root, ".claude", "team-info.json")
|
|
@@ -454,10 +433,16 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
|
454
433
|
dev_subagent = os.path.join(agents_dir, f"prizm-dev-team-dev{agent_ext}")
|
|
455
434
|
reviewer_subagent = os.path.join(agents_dir, f"prizm-dev-team-reviewer{agent_ext}")
|
|
456
435
|
|
|
457
|
-
# Session status
|
|
436
|
+
# Session status is controlled by the main runner state dir, even when
|
|
437
|
+
# rendered project paths are AI-visible worktree paths.
|
|
438
|
+
state_dir = (
|
|
439
|
+
os.path.abspath(args.state_dir)
|
|
440
|
+
if args.state_dir
|
|
441
|
+
else os.path.join(project_root, ".prizmkit", "state", "refactor")
|
|
442
|
+
)
|
|
458
443
|
session_status_path = os.path.join(
|
|
459
|
-
|
|
460
|
-
"
|
|
444
|
+
state_dir, args.refactor_id, "sessions", args.session_id,
|
|
445
|
+
"session-status.json",
|
|
461
446
|
)
|
|
462
447
|
|
|
463
448
|
# Scope
|
|
@@ -518,12 +503,7 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
|
518
503
|
browser_enabled = True
|
|
519
504
|
browser_verify_steps = " # (validate UI renders correctly and feature still works)"
|
|
520
505
|
|
|
521
|
-
max_log_size = _parse_non_negative_int_env("MAX_LOG_SIZE", DEFAULT_MAX_LOG_SIZE)
|
|
522
|
-
|
|
523
506
|
replacements = {
|
|
524
|
-
"{{LOG_SIZE_AWARENESS}}": load_log_size_section(script_dir),
|
|
525
|
-
"{{MAX_LOG_SIZE}}": str(max_log_size),
|
|
526
|
-
"{{MAX_LOG_SIZE_HUMAN}}": _format_bytes(max_log_size),
|
|
527
507
|
"{{SESSION_LOG_PATH}}": os.path.join(
|
|
528
508
|
".prizmkit", "state", "refactor", args.refactor_id,
|
|
529
509
|
"sessions", args.session_id, "logs", "session.log",
|
|
@@ -557,8 +537,8 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
|
|
|
557
537
|
"{{CHECKPOINT_PATH}}": os.path.join(
|
|
558
538
|
".prizmkit", "refactor", args.refactor_id, "workflow-checkpoint.json",
|
|
559
539
|
),
|
|
540
|
+
"{{CHECKPOINT_SYSTEM}}": read_checkpoint_system_section(script_dir),
|
|
560
541
|
"{{TIMESTAMP}}": "", # Placeholder — agent fills in timestamp
|
|
561
|
-
"{{PLATFORM_CONVENTIONS}}": read_platform_conventions(project_root),
|
|
562
542
|
"{{BROWSER_ENABLED}}": "true" if browser_enabled else "false",
|
|
563
543
|
"{{BROWSER_TOOL}}": browser_tool,
|
|
564
544
|
"{{BROWSER_VERIFY_STEPS}}": browser_verify_steps,
|
|
@@ -726,9 +706,6 @@ def main():
|
|
|
726
706
|
|
|
727
707
|
# Build replacements
|
|
728
708
|
replacements = build_replacements(args, refactor, refactors, global_context, script_dir)
|
|
729
|
-
if is_continuation(args):
|
|
730
|
-
replacements["{{LOG_SIZE_AWARENESS}}"] = ""
|
|
731
|
-
|
|
732
709
|
# Render the template
|
|
733
710
|
rendered = render_template(template_content, replacements, args.resume_phase, refactor)
|
|
734
711
|
|
|
@@ -738,7 +715,7 @@ def main():
|
|
|
738
715
|
emit_failure(err)
|
|
739
716
|
|
|
740
717
|
# Generate checkpoint file
|
|
741
|
-
project_root =
|
|
718
|
+
project_root = _args_project_root(args, script_dir)
|
|
742
719
|
checkpoint_rel = os.path.join(
|
|
743
720
|
".prizmkit", "refactor", args.refactor_id, "workflow-checkpoint.json",
|
|
744
721
|
)
|
|
@@ -79,6 +79,46 @@ def error_out(message, code=1):
|
|
|
79
79
|
sys.exit(code)
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def read_checkpoint_system_section(script_dir):
|
|
83
|
+
"""Read the shared checkpoint prompt section for feature/bugfix/refactor prompts."""
|
|
84
|
+
path = os.path.join(
|
|
85
|
+
os.path.abspath(script_dir), "..", "templates", "sections", "checkpoint-system.md"
|
|
86
|
+
)
|
|
87
|
+
try:
|
|
88
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
89
|
+
return f.read()
|
|
90
|
+
except IOError:
|
|
91
|
+
return """## Workflow Checkpoint System
|
|
92
|
+
|
|
93
|
+
A checkpoint file tracks your progress through this workflow:
|
|
94
|
+
|
|
95
|
+
**Path**: `{{CHECKPOINT_PATH}}`
|
|
96
|
+
|
|
97
|
+
### Checkpoint Update Helper
|
|
98
|
+
|
|
99
|
+
Use this helper to update checkpoint status. Do not hand-edit `workflow-checkpoint.json` directly.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
python3 .prizmkit/dev-pipeline/scripts/update-checkpoint.py \\
|
|
103
|
+
--checkpoint-path {{CHECKPOINT_PATH}} \\
|
|
104
|
+
--step <step-id-or-skill-name> \\
|
|
105
|
+
--status <in_progress|completed|failed|skipped> \\
|
|
106
|
+
--note "<optional note>"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- Use the step `skill` value such as `prizmkit-implement`, or the step id such as `S04`.
|
|
110
|
+
- Omit `--note` when there is no useful failure or handoff note.
|
|
111
|
+
|
|
112
|
+
### Rules
|
|
113
|
+
|
|
114
|
+
1. **Before each skill**: Read `workflow-checkpoint.json`, verify the previous step has `status: "completed"` or `status: "skipped"`. If it is still `"pending"` or `"in_progress"`, complete it first before moving on.
|
|
115
|
+
2. **Starting a skill**: Use the checkpoint update helper to mark the current step as `status: "in_progress"`.
|
|
116
|
+
3. **After each skill completes**: Use the checkpoint update helper to mark the current step as `status: "completed"`.
|
|
117
|
+
4. **On failure**: Use the checkpoint update helper to mark the step as `status: "failed"`, write `failure-log.md` with the reason, and continue only when the workflow rules allow it.
|
|
118
|
+
5. **On session exit**: The checkpoint file reflects your actual progress. Do NOT manually set future steps to `"completed"`.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
|
|
82
122
|
def pad_right(text, width):
|
|
83
123
|
"""Pad text with spaces to fill width, accounting for ANSI escape codes."""
|
|
84
124
|
i = 0
|
|
@@ -520,6 +560,89 @@ def enrich_global_context(global_context, project_root):
|
|
|
520
560
|
return global_context
|
|
521
561
|
|
|
522
562
|
|
|
563
|
+
|
|
564
|
+
def read_json_object(path):
|
|
565
|
+
"""Read a JSON object, returning an empty dict when unavailable."""
|
|
566
|
+
try:
|
|
567
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
568
|
+
data = json.load(f)
|
|
569
|
+
except (IOError, OSError, json.JSONDecodeError):
|
|
570
|
+
return {}
|
|
571
|
+
return data if isinstance(data, dict) else {}
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def platform_from_command(command):
|
|
575
|
+
"""Map an AI CLI command/config value to a PrizmKit platform name."""
|
|
576
|
+
cmd = str(command or "").strip().lower()
|
|
577
|
+
if not cmd:
|
|
578
|
+
return ""
|
|
579
|
+
base = os.path.basename(cmd.split()[0])
|
|
580
|
+
if base in ("claude", "claude-code") or "claude" in base:
|
|
581
|
+
return "claude"
|
|
582
|
+
if base in ("codex", "openai-codex") or "codex" in base:
|
|
583
|
+
return "codex"
|
|
584
|
+
if base in ("cbc", "codebuddy") or "codebuddy" in base:
|
|
585
|
+
return "codebuddy"
|
|
586
|
+
return ""
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
def valid_prompt_platform(value):
|
|
590
|
+
"""Normalize a platform value for prompt path rendering."""
|
|
591
|
+
value = str(value or "").strip().lower()
|
|
592
|
+
if value in ("claude", "codex", "codebuddy"):
|
|
593
|
+
return value
|
|
594
|
+
return ""
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def resolve_prompt_platform(project_root):
|
|
598
|
+
"""Resolve the platform whose agent paths should appear in prompts.
|
|
599
|
+
|
|
600
|
+
Explicit ``PRIZMKIT_PLATFORM`` wins. Otherwise prefer active/configured AI
|
|
601
|
+
CLI because mixed installs contain several platform directories. Filesystem
|
|
602
|
+
markers are only a final fallback.
|
|
603
|
+
"""
|
|
604
|
+
explicit = valid_prompt_platform(os.environ.get("PRIZMKIT_PLATFORM", ""))
|
|
605
|
+
if explicit:
|
|
606
|
+
return explicit
|
|
607
|
+
|
|
608
|
+
for env_name in ("AI_CLI", "CLAUDECODE", "CLAUDE_CODE"):
|
|
609
|
+
detected = platform_from_command(os.environ.get(env_name, ""))
|
|
610
|
+
if detected:
|
|
611
|
+
return detected
|
|
612
|
+
|
|
613
|
+
config = read_json_object(os.path.join(project_root, ".prizmkit", "config.json"))
|
|
614
|
+
for key in ("ai_cli", "aiCli"):
|
|
615
|
+
detected = platform_from_command(config.get(key, ""))
|
|
616
|
+
if detected:
|
|
617
|
+
return detected
|
|
618
|
+
detected = valid_prompt_platform(config.get("platform", ""))
|
|
619
|
+
if detected:
|
|
620
|
+
return detected
|
|
621
|
+
|
|
622
|
+
manifest = read_json_object(os.path.join(project_root, ".prizmkit", "manifest.json"))
|
|
623
|
+
options = manifest.get("options", {}) if isinstance(manifest.get("options"), dict) else {}
|
|
624
|
+
for value in (manifest.get("aiCli", ""), options.get("aiCli", "")):
|
|
625
|
+
detected = platform_from_command(value)
|
|
626
|
+
if detected:
|
|
627
|
+
return detected
|
|
628
|
+
detected = valid_prompt_platform(manifest.get("platform", ""))
|
|
629
|
+
if detected:
|
|
630
|
+
return detected
|
|
631
|
+
|
|
632
|
+
marker_order = (
|
|
633
|
+
("claude", os.path.join(project_root, ".claude", "agents")),
|
|
634
|
+
("codex", os.path.join(project_root, ".codex", "agents")),
|
|
635
|
+
("codebuddy", os.path.join(project_root, ".codebuddy", "agents")),
|
|
636
|
+
)
|
|
637
|
+
for candidate, marker in marker_order:
|
|
638
|
+
if os.path.isdir(marker):
|
|
639
|
+
return candidate
|
|
640
|
+
|
|
641
|
+
raise RuntimeError(
|
|
642
|
+
"PrizmKit agents not found. None of .claude/agents/, .codex/agents/, or .codebuddy/agents/ exists. "
|
|
643
|
+
"Run `npx prizmkit install` first, set .prizmkit/config.json ai_cli/platform, or set PRIZMKIT_PLATFORM=claude|codex|codebuddy explicitly."
|
|
644
|
+
)
|
|
645
|
+
|
|
523
646
|
def read_platform_conventions(project_root):
|
|
524
647
|
"""Resolve the platform-specific project conventions file.
|
|
525
648
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"Read {{CRITIC_SUBAGENT_PATH}}. For feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}):
|
|
2
2
|
**MODE: Plan Challenge**
|
|
3
3
|
1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` FIRST — Section 3 has project context, Section 4 has file manifest.
|
|
4
|
-
2.
|
|
5
|
-
3.
|
|
6
|
-
4.
|
|
4
|
+
2. Use context-snapshot.md as the shared source of truth. Do not create or enter AI tool-created `.claude/worktrees/...` subagent worktrees; use default/no worktree isolation and do not request worktree isolation.
|
|
5
|
+
3. PrizmKit pipeline-managed linked git worktrees under `.prizmkit/state/worktrees/...` are a separate runner feature controlled by `USE_WORKTREE`; do not confuse them with AI tool-created `.claude/worktrees/...`.
|
|
6
|
+
4. Read additional `.prizmkit/prizm-docs/` or source excerpts only when needed to verify a specific challenge.
|
|
7
|
+
5. Challenge plan.md against the project's existing architecture, patterns, and style.
|
|
7
8
|
Write `.prizmkit/specs/{{FEATURE_SLUG}}/challenge-report.md` with findings (or 'No significant challenges')."
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"Read {{REVIEWER_SUBAGENT_PATH}}. For feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}):
|
|
2
|
-
1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/spec.md` (if it exists) for goals and Verification Gates; if spec.md does not exist, read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` Section 1 Task Contract instead
|
|
3
|
-
2. Read `.prizmkit/specs/{{FEATURE_SLUG}}/plan.md` for architecture decisions and completed tasks
|
|
4
|
-
3.
|
|
5
|
-
4.
|
|
6
|
-
|
|
7
|
-
Report: verdict (PASS/NEEDS_FIXES), number of rounds, findings fixed/rejected."
|
|
2
|
+
1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/spec.md` (if it exists) for goals and Verification Gates; if spec.md does not exist, read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` Section 1 Task Contract instead.
|
|
3
|
+
2. Read `.prizmkit/specs/{{FEATURE_SLUG}}/plan.md` for architecture decisions and completed tasks.
|
|
4
|
+
3. Review the current workspace changes and return structured findings only. Do not run `/prizmkit-code-review`, do not apply fixes, do not run test suites, and do not spawn other agents.
|
|
5
|
+
4. The main orchestrator owns the review-fix loop: Reviewer Agent → filter → orchestrator fix.
|
|
6
|
+
Report: PASS/NEEDS_FIXES, findings with severity/location/problem/suggestion/verification, and a concise summary."
|
|
@@ -44,7 +44,7 @@ Infer what needs to be done from the feature context above and follow the standa
|
|
|
44
44
|
- Do NOT push to remote — the user will push manually.
|
|
45
45
|
- Write all artifacts to `.prizmkit/specs/{{FEATURE_SLUG}}/`.
|
|
46
46
|
- If a step fails after 3 attempts, write a status report and stop.
|
|
47
|
-
- **
|
|
47
|
+
- **Never re-read unmodified files**: once you read a file into context, do NOT read it again unless it was modified by an Edit/Write after your last read — use `grep -n`/`sed -n` for specific lines. Before issuing a Read, ask: "Have I read this file before, and has it changed since?" If no — do NOT read it. Subagents (Critic, Reviewer) must rely on context-snapshot.md rather than re-reading files the orchestrator already read.
|
|
48
48
|
- **Read offset safety**: if Read returns "shorter than offset"/"empty" — run `wc -l` then `sed -n`, do NOT retry same offset.
|
|
49
49
|
- **Hard Round Cap**: after 6 total test-fix rounds, STOP trial-and-error. Switch to read-once-then-rewrite. Do NOT exceed 7 rounds.
|
|
50
50
|
- **Layered test**: debug with single-file tests, only run full suite as gate when single-file is green.
|
|
@@ -46,22 +46,18 @@ You are running in **headless non-interactive mode** with a FINITE context windo
|
|
|
46
46
|
|
|
47
47
|
1. **context-snapshot.md is your single source of truth** — After Phase 1 builds it, ALWAYS read context-snapshot.md instead of re-reading individual source files
|
|
48
48
|
2. **Never re-read your own writes** — After you create/modify a file, do NOT read it back to verify. Trust your write was correct.
|
|
49
|
-
3. **
|
|
49
|
+
3. **Never re-read unmodified files** — Once you have read a file into context, do NOT read it again unless it was modified by an Edit/Write operation after your last read. Use `grep -n '<pattern>' <file>` or `sed -n '<start>,<end>p' <file>` for targeted line lookups instead of full-file Read. Before issuing a Read, ask yourself: "Have I read this file before, and has it changed since?" If the answer is "no, it hasn't changed" — do NOT read it. This applies to all files including those summarized in context-snapshot.md Section 4. Subagents (Critic, Reviewer) must receive context-snapshot.md and rely on it rather than independently re-reading the same files the orchestrator already read.
|
|
50
|
+
4. **Stay focused** — Do NOT explore code unrelated to this feature. No curiosity-driven reads.
|
|
50
51
|
4. **One task at a time** — In Phase 3 (implement), complete and test one task before starting the next.
|
|
51
52
|
5. **Minimize tool output** — Never load full command output into context. First capture to a temp file (`cmd 2>&1 | tee /tmp/out.txt | tail -20`), then scan the head/tail to identify relevant fields, and use targeted filtering (`grep`, `sed`, `awk`) to extract only the information needed for the current task. Only read the filtered result — never the raw full output.
|
|
52
53
|
6. **No intermediate commits** — Do NOT run `git add`/`git commit` during Phase 1-3. All changes are committed once at the end in Phase 4 via `/prizmkit-committer`.
|
|
53
|
-
7. **Capture test output once** — When running test suites, always use
|
|
54
|
-
8. **Scaffold / generated file awareness** — Files created by scaffolding tools (`npm init`, `npx create-*`, etc.) are boilerplate. Tag them, record in context-snapshot.md, and NEVER re-read them. If you need to modify one, edit directly without reading first.
|
|
54
|
+
7. **Capture test output once** — When running test suites, always use `<test-command> 2>&1 | tee /tmp/test-out.txt | tail -20`. Then grep `/tmp/test-out.txt` for details. Never re-run the suite just to apply a different filter.
|
|
55
55
|
9. **Package version verification (BLOCKING)** — Before writing ANY dependency version, verify it exists via registry query (`npm view <pkg> dist-tags.latest`, `pip index versions <pkg>`, etc.). NEVER guess version numbers.
|
|
56
56
|
10. **Build artifact hygiene** — After build/compile, ensure output is in `.gitignore`. Never commit binaries/build output.
|
|
57
|
-
11. **
|
|
58
|
-
12. **Read offset safety (BLOCKING)** — If Read returns "shorter than offset"/"File is empty"/"Wasted call" — do NOT retry same offset. Run `wc -l <file>` to get real line count, then `sed -n` for exact range. 2 consecutive offset errors → STOP Reading that file. Never guess offsets — `grep -n '<anchor>'` first.
|
|
57
|
+
11. **Read offset safety (BLOCKING)** — If Read returns "shorter than offset"/"File is empty"/"Wasted call" — do NOT retry same offset. Run `wc -l <file>` to get real line count, then `sed -n` for exact range. 2 consecutive offset errors → STOP Reading that file. Never guess offsets — `grep -n '<anchor>'` first.
|
|
59
58
|
|
|
60
59
|
---
|
|
61
60
|
|
|
62
|
-
{{LOG_SIZE_AWARENESS}}
|
|
63
|
-
---
|
|
64
|
-
|
|
65
61
|
## PrizmKit Directory Convention
|
|
66
62
|
|
|
67
63
|
```
|
|
@@ -115,7 +111,7 @@ ls .prizmkit/specs/{{FEATURE_SLUG}}/ 2>/dev/null
|
|
|
115
111
|
|
|
116
112
|
If plan.md missing, run `/prizmkit-plan` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to generate `plan.md`:
|
|
117
113
|
- The plan.md should include: key components, data flow, files to create/modify, and a Tasks section with `[ ]` checkboxes (each task = one implementable unit). Keep under 80 lines.
|
|
118
|
-
- Resolve
|
|
114
|
+
- Resolve uncertain requirements from the feature description, existing code, and conservative existing-project patterns.
|
|
119
115
|
|
|
120
116
|
**Database Design Gate** (if feature involves data persistence — new tables, schema changes, new entities):
|
|
121
117
|
Before proceeding past CP-1:
|
|
@@ -125,7 +121,7 @@ Before proceeding past CP-1:
|
|
|
125
121
|
|
|
126
122
|
**CP-1**: plan.md exists with Tasks section.
|
|
127
123
|
|
|
128
|
-
### Phase 3: Implement
|
|
124
|
+
### Phase 3: Implement
|
|
129
125
|
|
|
130
126
|
**Build artifacts**: After any build/compile command (`go build`, `npm run build`, `tsc`, etc.), ensure the output binary or build directory is in `.gitignore`:
|
|
131
127
|
```bash
|
|
@@ -134,51 +130,56 @@ grep -q '^/binary-name$' .gitignore || echo '/binary-name' >> .gitignore
|
|
|
134
130
|
```
|
|
135
131
|
Never commit compiled binaries, build output, or generated artifacts.
|
|
136
132
|
|
|
137
|
-
**3a.**
|
|
138
|
-
|
|
139
|
-
You know this project's tech stack. Identify ALL test commands that apply (e.g., `go test ./...`, `npm test`, `cargo test`, `pytest`, `make test`, etc.). Record them as `TEST_CMDS` (one or more commands). Then record baseline:
|
|
140
|
-
```bash
|
|
141
|
-
# Run each test command, capture output
|
|
142
|
-
($TEST_CMD) 2>&1 | tee /tmp/test-baseline.txt | tail -20
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**3b.** Run `/prizmkit-implement` — this handles the full implementation cycle:
|
|
133
|
+
**3a.** Run `/prizmkit-implement` — this handles the implementation cycle:
|
|
146
134
|
- Reads plan.md Tasks section from `.prizmkit/specs/{{FEATURE_SLUG}}/`
|
|
147
135
|
- Reads context from `context-snapshot.md` (Prizm docs, TRAPS, file manifest)
|
|
148
136
|
- Implements task-by-task, marking each `[x]` immediately
|
|
149
137
|
- Creates/updates L2 `.prizm` docs when creating new modules or significantly modifying existing ones — AI selectively decides which modules warrant L2 based on complexity and importance
|
|
150
|
-
-
|
|
138
|
+
- Does not run the scoped/full test gate; testing happens after code review in the PrizmKit Test phase
|
|
151
139
|
- Writes '## Implementation Log' to `context-snapshot.md`
|
|
152
140
|
|
|
153
|
-
**3b
|
|
154
|
-
|
|
155
|
-
**3c.** After implement completes, verify:
|
|
141
|
+
**3b.** After implement completes, verify:
|
|
156
142
|
1. All tasks in plan.md are `[x]`
|
|
157
143
|
2. **Verification Gate Self-Check**: for each acceptance criterion, write one line of evidence (test name / file:line / fixture path). Any gate without evidence is BLOCKED, not success.
|
|
158
|
-
3.
|
|
159
|
-
4.
|
|
160
|
-
|
|
144
|
+
3. Use only tiny targeted checks when needed for local debugging; the scoped feature test gate runs after review.
|
|
145
|
+
4. If any criterion is not met, fix it within this feature scope before proceeding.
|
|
146
|
+
|
|
147
|
+
**CP-2**: All acceptance criteria met or blocked gates documented in `failure-log.md`. Test execution is deferred until after code review.
|
|
161
148
|
|
|
162
|
-
|
|
149
|
+
### Review — Code Review
|
|
163
150
|
|
|
164
|
-
|
|
151
|
+
Review the completed implementation before the scoped feature test gate runs. Use `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` so the code-review skill can read spec, plan, context snapshot, implementation log, and current diff artifacts. Do not require or read a prior `/prizmkit-test` report here; test generation and test-fix looping happen in the next phase.
|
|
165
152
|
|
|
166
|
-
|
|
153
|
+
Run `/prizmkit-code-review` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/`.
|
|
167
154
|
|
|
168
|
-
|
|
169
|
-
2. **Check termination**: All pass → done | Plateau (same failures 3 rounds) → stop | Failures decreased → continue
|
|
170
|
-
3. **Fix and iterate**: analyze, fix, re-run `($TEST_CMD)`, go back to step 1
|
|
155
|
+
The skill runs an internal review-fix loop (Reviewer Agent → filter → orchestrator fix, max 3 rounds) and writes `review-report.md` to the artifact directory.
|
|
171
156
|
|
|
172
|
-
**
|
|
157
|
+
**Gate Check — Review Report**:
|
|
158
|
+
After `/prizmkit-code-review` returns, verify the review report:
|
|
159
|
+
```bash
|
|
160
|
+
grep -q "## Verdict" .prizmkit/specs/{{FEATURE_SLUG}}/review-report.md && echo "GATE:PASS" || echo "GATE:MISSING"
|
|
161
|
+
```
|
|
162
|
+
If GATE:MISSING:
|
|
163
|
+
- Do not re-run `/prizmkit-code-review` in an unbounded report-repair loop.
|
|
164
|
+
- Perform one bounded status check; retry at most once: inspect the skill output, `review-report.md` path, and any Reviewer agent spawn messages.
|
|
165
|
+
- If the missing report is caused by Reviewer agent spawn or review skill error, retry `/prizmkit-code-review` at most once only if it appears transient.
|
|
166
|
+
- If the report is still missing after that single check/retry, write `failure-log.md` with the spawn/skill error and last observable state, then either perform a safe inline fallback review (spec/plan/diff/tests → write `review-report.md` with `## Verdict`) or stop with a clear recovery failure.
|
|
173
167
|
|
|
174
|
-
|
|
168
|
+
Read `review-report.md` and check the Verdict:
|
|
169
|
+
- `PASS` → proceed to next phase
|
|
170
|
+
- `NEEDS_FIXES` → the skill exhausted its max rounds; log the remaining findings and proceed (do not retry externally)
|
|
175
171
|
|
|
172
|
+
**CP-3**: Review complete, report written.
|
|
176
173
|
|
|
177
174
|
### Scoped Feature Test Gate — PrizmKit Test
|
|
178
175
|
|
|
179
176
|
Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` after review and before commit.
|
|
180
177
|
|
|
181
|
-
Before invoking the skill, create
|
|
178
|
+
Before invoking the skill, create a current-run marker so stale reports are ignored:
|
|
179
|
+
```bash
|
|
180
|
+
mkdir -p .prizmkit/specs/{{FEATURE_SLUG}}
|
|
181
|
+
touch .prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started
|
|
182
|
+
```
|
|
182
183
|
|
|
183
184
|
Gate requirements:
|
|
184
185
|
- Generate or update tests only for this feature's changed files, changed public interfaces, and acceptance criteria.
|