prizmkit 1.1.101 → 1.1.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +1 -1
  3. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +14 -2
  4. package/bundled/dev-pipeline/prizmkit_runtime/runner_status.py +9 -3
  5. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +5 -1
  6. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +62 -4
  7. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +13 -13
  8. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +1 -1
  9. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +1 -1
  10. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +2 -2
  11. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +6 -7
  12. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +1 -1
  13. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +1 -1
  14. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +7 -7
  15. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +7 -7
  16. package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +8 -17
  17. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +2 -2
  18. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +1 -3
  19. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +1 -3
  20. package/bundled/dev-pipeline/templates/sections/phase0-test-baseline.md +3 -8
  21. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +2 -2
  22. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +1 -1
  23. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +11 -7
  24. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +107 -11
  25. package/bundled/dev-pipeline/tests/test_unified_cli.py +76 -0
  26. package/bundled/skills/_metadata.json +1 -1
  27. package/package.json +1 -1
  28. package/src/config.js +9 -7
  29. package/src/external-skills.js +14 -14
  30. package/src/manifest.js +8 -3
  31. package/src/platforms.js +25 -0
  32. package/src/scaffold.js +11 -6
  33. package/src/upgrade.js +11 -2
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.1.101",
3
- "bundledAt": "2026-07-06T10:58:41.729Z",
4
- "bundledFrom": "fa258ae"
2
+ "frameworkVersion": "1.1.104",
3
+ "bundledAt": "2026-07-06T16:42:02.971Z",
4
+ "bundledFrom": "05c5c13"
5
5
  }
@@ -320,7 +320,7 @@ def _payload_command(family: RunnerFamily, paths, list_path: Path, options: Daem
320
320
 
321
321
 
322
322
  def _daemon_env(options: DaemonStartOptions) -> dict[str, str]:
323
- env: dict[str, str] = {}
323
+ env: dict[str, str] = {"PRIZMKIT_LIVE_OUTPUT": "0"}
324
324
  for token in shlex.split(options.env_overrides):
325
325
  if "=" in token:
326
326
  key, value = token.split("=", 1)
@@ -37,14 +37,16 @@ class RunnerEnvironment:
37
37
 
38
38
  stop_on_failure: bool = False
39
39
  auto_push: bool = False
40
- use_worktree: bool = True
40
+ use_worktree: bool = False
41
41
  dev_branch: str = ""
42
42
  enable_deploy: bool = False
43
43
  verbose: bool = False
44
+ live_output: bool = True
44
45
  heartbeat_interval_seconds: int = 30
45
46
  heartbeat_stale_threshold_seconds: int = 600
46
47
  stale_kill_threshold_seconds: int = 600
47
48
  max_log_size: int | None = None
49
+ max_retries: int = 3
48
50
  strict_behavior_check: bool = True
49
51
 
50
52
  @classmethod
@@ -53,10 +55,11 @@ class RunnerEnvironment:
53
55
  return cls(
54
56
  stop_on_failure=_truthy(values.get("STOP_ON_FAILURE")),
55
57
  auto_push=_truthy(values.get("AUTO_PUSH")),
56
- use_worktree=not _falsey(values.get("USE_WORKTREE")),
58
+ use_worktree=_truthy(values.get("USE_WORKTREE")),
57
59
  dev_branch=values.get("DEV_BRANCH", ""),
58
60
  enable_deploy=_truthy(values.get("ENABLE_DEPLOY")),
59
61
  verbose=_truthy(values.get("VERBOSE")),
62
+ live_output=not _falsey(values.get("PRIZMKIT_LIVE_OUTPUT")),
60
63
  heartbeat_interval_seconds=_int_value(values, "HEARTBEAT_INTERVAL", 30),
61
64
  heartbeat_stale_threshold_seconds=_int_value(
62
65
  values,
@@ -65,6 +68,7 @@ class RunnerEnvironment:
65
68
  ),
66
69
  stale_kill_threshold_seconds=_int_value(values, "STALE_KILL_THRESHOLD", 600),
67
70
  max_log_size=_optional_int(values.get("MAX_LOG_SIZE")),
71
+ max_retries=max(0, _int_value(values, "MAX_RETRIES", 3)),
68
72
  strict_behavior_check=not _falsey(values.get("STRICT_BEHAVIOR_CHECK")),
69
73
  )
70
74
 
@@ -77,6 +81,7 @@ class RunnerInvocation:
77
81
  list_path: Path
78
82
  item_id: str = ""
79
83
  item_filter: str = ""
84
+ max_retries: int | None = None
80
85
  max_infra_retries: int = 3
81
86
  mode: str | None = None
82
87
  critic: bool | None = None
@@ -228,6 +233,7 @@ def parse_invocation(
228
233
  list_path = family.plan_path
229
234
  item_id = ""
230
235
  item_filter = ""
236
+ max_retries: int | None = None
231
237
  max_infra_retries = 3
232
238
  mode: str | None = None
233
239
  critic: bool | None = None
@@ -259,6 +265,11 @@ def parse_invocation(
259
265
  item_filter = args[index]
260
266
  elif arg.startswith("--features="):
261
267
  item_filter = arg.split("=", 1)[1]
268
+ elif arg == "--max-retries" and index + 1 < len(args):
269
+ index += 1
270
+ max_retries = max(0, _safe_int(args[index], 3))
271
+ elif arg.startswith("--max-retries="):
272
+ max_retries = max(0, _safe_int(arg.split("=", 1)[1], 3))
262
273
  elif arg == "--max-infra-retries" and index + 1 < len(args):
263
274
  index += 1
264
275
  max_infra_retries = _safe_int(args[index], 3)
@@ -293,6 +304,7 @@ def parse_invocation(
293
304
  list_path=list_path,
294
305
  item_id=item_id,
295
306
  item_filter=item_filter,
307
+ max_retries=max_retries,
296
308
  max_infra_retries=max_infra_retries,
297
309
  mode=mode,
298
310
  critic=critic,
@@ -8,7 +8,7 @@ import sys
8
8
  from dataclasses import dataclass
9
9
  from pathlib import Path
10
10
 
11
- from .runner_models import RunnerFamily, RunnerInvocation
11
+ from .runner_models import RunnerEnvironment, RunnerFamily, RunnerInvocation
12
12
 
13
13
 
14
14
  @dataclass(frozen=True)
@@ -30,6 +30,12 @@ class StatusCommandResult:
30
30
  return self.stdout.strip() or self.stderr.strip()
31
31
 
32
32
 
33
+ def _resolved_max_retries(invocation: RunnerInvocation) -> int:
34
+ if invocation.max_retries is not None:
35
+ return max(0, invocation.max_retries)
36
+ return RunnerEnvironment.from_env().max_retries
37
+
38
+
33
39
  def run_status_action(
34
40
  family: RunnerFamily,
35
41
  action: str,
@@ -38,7 +44,7 @@ def run_status_action(
38
44
  item_id: str = "",
39
45
  session_status: str = "",
40
46
  session_id: str = "",
41
- max_retries: int = 3,
47
+ max_retries: int | None = None,
42
48
  active_dev_branch: str = "",
43
49
  base_branch: str = "",
44
50
  last_fatal_error_code: str = "",
@@ -47,7 +53,7 @@ def run_status_action(
47
53
  progress_fingerprint: object | None = None,
48
54
  project_root: Path | None = None,
49
55
  ) -> StatusCommandResult:
50
- """Invoke an existing updater script and parse JSON output when present."""
56
+ max_retries = _resolved_max_retries(invocation) if max_retries is None else max(0, max_retries)
51
57
  command = [
52
58
  sys.executable,
53
59
  str(family.updater_script),
@@ -114,6 +114,8 @@ def _run_pipeline(family: RunnerFamily, invocation: RunnerInvocation, paths) ->
114
114
  details.append(f"{item_id}:{final_status}")
115
115
  if final_status == "completed":
116
116
  continue
117
+ if final_status == "pending":
118
+ continue
117
119
  if RunnerEnvironment.from_env().stop_on_failure:
118
120
  return PipelineRunResult(False, processed, "stop_on_failure", final_status, tuple(details))
119
121
  if final_status in {"failed", "needs_info"}:
@@ -218,6 +220,7 @@ def _process_item(
218
220
  heartbeat_path=session_paths.heartbeat_json,
219
221
  effort=config.effort,
220
222
  verbose=env.verbose,
223
+ live_output=env.live_output,
221
224
  use_stream_json=stream_json,
222
225
  stale_kill_threshold_seconds=env.stale_kill_threshold_seconds,
223
226
  )
@@ -401,6 +404,7 @@ def _resolve_invocation_paths(invocation: RunnerInvocation, project_root: Path)
401
404
  list_path=(project_root / invocation.list_path).resolve(),
402
405
  item_id=invocation.item_id,
403
406
  item_filter=invocation.item_filter,
407
+ max_retries=invocation.max_retries,
404
408
  max_infra_retries=invocation.max_infra_retries,
405
409
  mode=invocation.mode,
406
410
  critic=invocation.critic,
@@ -418,5 +422,5 @@ def _help_text(family: RunnerFamily) -> str:
418
422
  return (
419
423
  f"Python foreground runner for {family.kind}.\n"
420
424
  "Supported legacy options include plan list path, item id, --features for feature, "
421
- "--max-infra-retries, --mode, --critic/--no-critic, --resume-phase, and --dry-run."
425
+ "--max-retries, --max-infra-retries, --mode, --critic/--no-critic, --resume-phase, and --dry-run."
422
426
  )
@@ -8,6 +8,7 @@ import os
8
8
  import queue
9
9
  import shutil
10
10
  import subprocess
11
+ import sys
11
12
  import threading
12
13
  import time
13
14
  from collections import Counter
@@ -45,6 +46,7 @@ class AISessionConfig:
45
46
  heartbeat_path: Path | None = None
46
47
  effort: str | None = None
47
48
  verbose: bool = False
49
+ live_output: bool = False
48
50
  use_stream_json: bool = False
49
51
  stream_json_format: str = ""
50
52
  permission_mode: str = "dangerously-skip-permissions"
@@ -152,7 +154,14 @@ def build_ai_session_command(config: AISessionConfig) -> AISessionCommand:
152
154
  platform = _normalize_platform(config.platform)
153
155
  prompt = _prompt_text(config.prompt_path)
154
156
  if platform == "claude":
155
- argv = [config.cli_command, "-p", prompt, "--dangerously-skip-permissions"]
157
+ argv = [
158
+ config.cli_command,
159
+ "-p",
160
+ prompt,
161
+ "--dangerously-skip-permissions",
162
+ "--disallowedTools",
163
+ "EnterWorktree",
164
+ ]
156
165
  if config.verbose or config.use_stream_json:
157
166
  argv.append("--verbose")
158
167
  if config.use_stream_json:
@@ -175,6 +184,7 @@ def build_ai_session_command(config: AISessionConfig) -> AISessionCommand:
175
184
  timeout = _codex_subagent_timeout(config)
176
185
  if timeout > 0:
177
186
  argv.extend(["--config", f"agents.job_max_runtime_seconds={timeout}"])
187
+ argv.extend(["--profile", "no-worktree"])
178
188
  argv.extend(["exec", "--cd", str(config.cwd), "--skip-git-repo-check"])
179
189
  if config.use_stream_json:
180
190
  argv.append("--json")
@@ -186,7 +196,7 @@ def build_ai_session_command(config: AISessionConfig) -> AISessionCommand:
186
196
  argv.append("-")
187
197
  return AISessionCommand(tuple(argv), prompt, "codex", "stdin")
188
198
 
189
- argv = [config.cli_command, "--print", "-y"]
199
+ argv = [config.cli_command, "--print", "-y", "--disallowedTools", "EnterWorktree"]
190
200
  if config.verbose:
191
201
  argv.append("--verbose")
192
202
  if config.use_stream_json:
@@ -355,12 +365,45 @@ def _write_progress_summary(progress_path: Path | None, summary: ProgressSummary
355
365
  progress_path.write_text(json.dumps(summary.to_dict(), indent=2, sort_keys=True) + "\n", encoding="utf-8")
356
366
 
357
367
 
368
+ def _emit_live_line(message: str) -> None:
369
+ """Print foreground runner status without interfering with file logging."""
370
+ print(message, file=sys.stderr, flush=True)
371
+
372
+
373
+ def _emit_live_output(line: str) -> None:
374
+ """Forward AI CLI output for verbose foreground runs."""
375
+ sys.stdout.write(line)
376
+ sys.stdout.flush()
377
+
378
+
379
+ def _emit_session_start(config: AISessionConfig, command: AISessionCommand, session_log: Path, backup_log: Path) -> None:
380
+ _emit_live_line("[prizmkit] AI session started")
381
+ _emit_live_line(f"[prizmkit] Provider: {command.provider}")
382
+ _emit_live_line(f"[prizmkit] Prompt: {config.prompt_path}")
383
+ _emit_live_line(f"[prizmkit] Session log: {session_log}")
384
+ _emit_live_line(f"[prizmkit] Backup log: {backup_log}")
385
+ if config.progress_path is not None:
386
+ _emit_live_line(f"[prizmkit] Progress: {config.progress_path}")
387
+ if config.heartbeat_path is not None:
388
+ _emit_live_line(f"[prizmkit] Heartbeat: {config.heartbeat_path}")
389
+ if config.verbose:
390
+ _emit_live_line("[prizmkit] VERBOSE=1: forwarding live AI CLI output below")
391
+
392
+
393
+ def _emit_session_finish(result: AISessionResult) -> None:
394
+ duration = max(0.0, result.ended_epoch - result.started_epoch)
395
+ status = result.termination_reason or f"exit_code={result.exit_code}"
396
+ _emit_live_line(f"[prizmkit] AI session finished ({status}, {duration:.1f}s)")
397
+ _emit_live_line(f"[prizmkit] Session log: {result.session_log}")
398
+
399
+
358
400
  def _reader_thread(
359
401
  pipe,
360
402
  session_log: Path,
361
403
  backup_log: Path,
362
404
  output_queue: "queue.Queue[str]",
363
405
  progress_path: Path | None = None,
406
+ live_output: bool = False,
364
407
  ) -> None:
365
408
  lines: list[str] = []
366
409
  tracker = None
@@ -379,6 +422,8 @@ def _reader_thread(
379
422
  with backup_log.open("a", encoding="utf-8") as backup_fh:
380
423
  backup_fh.write(line)
381
424
  output_queue.put(line)
425
+ if live_output:
426
+ _emit_live_output(line)
382
427
  lines.append(line)
383
428
  if progress_path is not None:
384
429
  if tracker is not None:
@@ -464,12 +509,22 @@ class AISessionLauncher:
464
509
  environment_unsets=("CLAUDECODE",),
465
510
  stdin_text=command.stdin_text,
466
511
  )
512
+ if self.config.live_output:
513
+ _emit_session_start(self.config, command, session_log, backup_log)
514
+
467
515
  handle = launch_process(spec, stderr=subprocess.STDOUT)
468
516
  assert handle.popen is not None
469
517
  output_queue: queue.Queue[str] = queue.Queue()
470
518
  reader = threading.Thread(
471
519
  target=_reader_thread,
472
- args=(handle.popen.stdout, session_log, backup_log, output_queue, self.config.progress_path),
520
+ args=(
521
+ handle.popen.stdout,
522
+ session_log,
523
+ backup_log,
524
+ output_queue,
525
+ self.config.progress_path,
526
+ self.config.live_output and self.config.verbose,
527
+ ),
473
528
  daemon=True,
474
529
  )
475
530
  reader.start()
@@ -536,7 +591,7 @@ class AISessionLauncher:
536
591
  self.config.progress_path.write_text(json.dumps(merged_progress, indent=2, sort_keys=True) + "\n", encoding="utf-8")
537
592
  final_summary = _summary_from_progress_dict(merged_progress, summary)
538
593
  ended = time.time()
539
- return AISessionResult(
594
+ result = AISessionResult(
540
595
  command=command,
541
596
  exit_code=handle.popen.returncode,
542
597
  timed_out=timed_out,
@@ -550,3 +605,6 @@ class AISessionLauncher:
550
605
  started_epoch=started,
551
606
  ended_epoch=ended,
552
607
  )
608
+ if self.config.live_output:
609
+ _emit_session_finish(result)
610
+ return result
@@ -676,7 +676,7 @@ def determine_pipeline_mode(complexity):
676
676
  SECTION_TO_SKILL = {
677
677
  "phase0-init": ("prizmkit-init", "Project Bootstrap",
678
678
  [".prizmkit/prizm-docs/root.prizm", ".prizmkit/config.json"]),
679
- "phase0-test-baseline": ("test-baseline", "Test Baseline", []),
679
+ "phase0-test-baseline": ("test-baseline", "Detect Test Commands", []),
680
680
  "phase-context-snapshot": ("context-snapshot", "Build Context Snapshot",
681
681
  [".prizmkit/specs/{slug}/context-snapshot.md"]),
682
682
  "phase-specify-plan": ("context-snapshot-and-plan", "Specify & Plan",
@@ -1559,6 +1559,18 @@ def assemble_sections(pipeline_mode, sections_dir, init_done, is_resume,
1559
1559
  load_section(sections_dir,
1560
1560
  "phase-implement-agent.md")))
1561
1561
 
1562
+ # Verification Gates are included in Task Contract. Keep AC in one place so
1563
+ # background context and implementation prompts cannot redefine scope.
1564
+ # --- Review ---
1565
+ if pipeline_mode == "full":
1566
+ sections.append(("phase-review",
1567
+ load_section(sections_dir,
1568
+ "phase-review-full.md")))
1569
+ else:
1570
+ sections.append(("phase-review",
1571
+ load_section(sections_dir,
1572
+ "phase-review-agent.md")))
1573
+
1562
1574
  # --- Test Failure Recovery Protocol (tier-specific) ---
1563
1575
  if pipeline_mode == "lite":
1564
1576
  sections.append(("test-failure-recovery",
@@ -1574,18 +1586,6 @@ def assemble_sections(pipeline_mode, sections_dir, init_done, is_resume,
1574
1586
  load_section(sections_dir,
1575
1587
  "phase-prizmkit-test.md")))
1576
1588
 
1577
- # Verification Gates are included in Task Contract. Keep AC in one place so
1578
- # background context and implementation prompts cannot redefine scope.
1579
- # --- Review (only for agent tiers) ---
1580
- if pipeline_mode == "full":
1581
- sections.append(("phase-review",
1582
- load_section(sections_dir,
1583
- "phase-review-full.md")))
1584
- elif pipeline_mode == "standard":
1585
- sections.append(("phase-review",
1586
- load_section(sections_dir,
1587
- "phase-review-agent.md")))
1588
-
1589
1589
  # --- Browser Verification (conditional, tool-aware) ---
1590
1590
  if browser_enabled:
1591
1591
  if browser_tool == "opencli":
@@ -61,7 +61,7 @@ Before returning, append `## Implementation Log` to `context-snapshot.md` with:
61
61
  - Do not run git commands; staging and commit are handled by the orchestrator.
62
62
  - **Edit safety**: If an Edit fails with 'String to replace not found', grep for the target text before retrying. Never guess file offsets — verify them with a Read or grep first.
63
63
  - **Read safety**: If 3 consecutive Reads to the same file return 'shorter than offset' or 'Wasted call', STOP and report BLOCKED.
64
- - **Test early**: Run `{{TEST_CMD}}` after every 3 successful Edit operations. Capture output to /tmp/test-out.txt and grep for failures.
64
+ - **Test gate placement**: Do not run mandatory periodic or full-suite tests here. The scoped/full test gate runs after code review; only use tiny targeted checks when needed for local debugging.
65
65
 
66
66
  Do not return success unless:
67
67
  1. implementation tasks are complete;
@@ -2,6 +2,6 @@
2
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
3
  2. Read `.prizmkit/specs/{{FEATURE_SLUG}}/plan.md` for architecture decisions and completed tasks
4
4
  3. Run /prizmkit-code-review with artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/. The skill will run its internal review-fix loop (Reviewer → filter → Dev fix, max 3 rounds) and write review-report.md.
5
- 4. Run the full test suite using `{{TEST_CMD}}`. When running tests: `({{TEST_CMD}}) 2>&1 | tee /tmp/review-test-out.txt | tail -20`, then grep `/tmp/review-test-out.txt` for details — do NOT re-run the suite multiple times.
5
+ 4. Do not run test suites here. The orchestrator runs `/prizmkit-test` after review completes and then fixes code/tests until the scoped gate passes.
6
6
  5. review-report.md will be written to .prizmkit/specs/{{FEATURE_SLUG}}/ by prizmkit-code-review.
7
7
  Report: verdict (PASS/NEEDS_FIXES), number of rounds, findings fixed/rejected."
@@ -30,9 +30,9 @@ Infer what needs to be done from the feature context above and follow the standa
30
30
 
31
31
  3. **Implement**: Run `/prizmkit-implement` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to execute the plan using TDD (write tests first, then implement).
32
32
 
33
- 4. **Test**: Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to generate and verify tests only for this feature's changed scope. Do not use bugfix/refactor artifact directories for this gate.
33
+ 4. **Review**: Run `/prizmkit-code-review` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to review and auto-fix changes against the spec (internal review-fix loop, max 3 rounds).
34
34
 
35
- 5. **Review**: Run `/prizmkit-code-review` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to review and auto-fix changes against the spec (internal review-fix loop, max 3 rounds).
35
+ 5. **Test**: Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` to generate and verify tests only for this feature's changed scope after review. Do not use bugfix/refactor artifact directories for this gate.
36
36
 
37
37
  6. **Retrospective**: Run `/prizmkit-retrospective` to sync `.prizmkit/prizm-docs/` with code changes.
38
38
 
@@ -145,9 +145,9 @@ You know this project's tech stack. Identify ALL test commands that apply (e.g.,
145
145
  **3b.** Run `/prizmkit-implement` — this handles the full implementation cycle:
146
146
  - Reads plan.md Tasks section from `.prizmkit/specs/{{FEATURE_SLUG}}/`
147
147
  - Reads context from `context-snapshot.md` (Prizm docs, TRAPS, file manifest)
148
- - Implements task-by-task with TDD, marking each `[x]` immediately
148
+ - Implements task-by-task, marking each `[x]` immediately
149
149
  - 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
- - Runs tests using `TEST_CMD` after each task
150
+ - Defers scoped/full test execution until after review
151
151
  - Writes '## Implementation Log' to `context-snapshot.md`
152
152
 
153
153
  **3b-checkpoint.** Context management — if plan.md has more than 5 tasks, update durable checkpoints/artifacts after every 3 tasks, minimize output, and continue. If context overflow occurs in a headless run, the runner starts a fresh continuation session from those checkpoints and artifacts. In an interactive Claude Code session operated manually outside the headless pipeline, `/compact` may be used as an optional convenience only.
@@ -155,10 +155,9 @@ You know this project's tech stack. Identify ALL test commands that apply (e.g.,
155
155
  **3c.** After implement completes, verify:
156
156
  1. All tasks in plan.md are `[x]`
157
157
  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. **Layered test strategy**: debug with single-file tests (`npx vitest run <file> -t '<name>'`), only run full suite as gate when single-file is green. Never run full suite while a single-file test is still red.
159
- 4. Run the full test suite to ensure nothing is broken
160
- 5. Verify each acceptance criterion from Section 1 of context-snapshot.md is met check mentally, do NOT re-read files you already wrote
161
- 6. If any criterion is not met, fix it now using the convergence-based recovery loop below
158
+ 3. **Layered test strategy**: do not run mandatory periodic/full-suite tests during implementation. Use only tiny targeted checks when needed for local debugging; the scoped feature test gate runs after review.
159
+ 4. Verify each acceptance criterion from Section 1 of context-snapshot.md is met — check mentally, do NOT re-read files you already wrote
160
+ 5. If any criterion is not met, fix it now using the convergence-based recovery loop below
162
161
 
163
162
  **CP-2**: All acceptance criteria met, all tests pass.
164
163
 
@@ -177,7 +176,7 @@ When tests fail, use convergence recovery — keep fixing while progress is bein
177
176
 
178
177
  ### Scoped Feature Test Gate — PrizmKit Test
179
178
 
180
- Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` after implementation and before review/commit.
179
+ Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` after review and before commit.
181
180
 
182
181
  Before invoking the skill, create `.prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started` so stale reports are ignored.
183
182
 
@@ -302,7 +302,7 @@ If GATE:MISSING — send message to Dev (re-spawn if needed): "Write the '## Imp
302
302
 
303
303
  ### Scoped Feature Test Gate — PrizmKit Test
304
304
 
305
- Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` after implementation and before review/commit.
305
+ Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` after review and before commit.
306
306
 
307
307
  Before invoking the skill, create `.prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started` so stale reports are ignored.
308
308
 
@@ -320,7 +320,7 @@ All tasks `[x]`, tests pass.
320
320
 
321
321
  ### Scoped Feature Test Gate — PrizmKit Test
322
322
 
323
- Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` after implementation and before review/commit.
323
+ Run `/prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` after review and before commit.
324
324
 
325
325
  Before invoking the skill, create `.prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started` so stale reports are ignored.
326
326
 
@@ -19,15 +19,15 @@ grep -c '^\- \[ \]' .prizmkit/specs/{{FEATURE_SLUG}}/plan.md 2>/dev/null || true
19
19
  **3b.** Run `/prizmkit-implement` directly — you (the orchestrator) execute the full cycle:
20
20
  - Read plan.md Tasks from `.prizmkit/specs/{{FEATURE_SLUG}}/`
21
21
  - Use context-snapshot.md Section 4 File Manifest for targeted reads — do NOT re-read files already summarized there
22
- - Implement task-by-task with TDD, marking each `[x]` immediately
22
+ - Implements task-by-task, marking each `[x]` immediately
23
23
  - Creates/updates L2 `.prizm` docs when creating new modules
24
- - Runs tests using `TEST_CMD`
24
+ - Defers scoped/full test execution until after the code-review loop completes
25
25
  - If plan.md has >5 tasks: update checkpoints after every 3 tasks
26
26
 
27
- **3c. Layered test strategy** (replaces "run full suite every 3 Edits"):
28
- - Debugging a single test: `npx vitest run <test-file> -t '<test name>'` (or per-stack equivalent). Capture to `/tmp/test-out.txt`, grep for failures.
29
- - Only when single-file is green, run ONE full `{{TEST_CMD}}` as the gate.
30
- - Never run full suite while a single-file test is still red.
27
+ **3c. Focused checks only (no test gate here)**:
28
+ - During implementation, do not run mandatory periodic or full-suite tests.
29
+ - If a tiny targeted check is needed to understand a local failure, run only the smallest relevant command and capture output to `/tmp/test-out.txt`.
30
+ - The scoped feature test gate runs after code review; do not declare implementation success based on an early full-suite run.
31
31
 
32
32
  **3d. Verification Gate Self-Check (BLOCKING — before declaring implement done)**:
33
33
  For each Verification Gate from the Task Contract, write one evidence line to Implementation Log:
@@ -45,7 +45,7 @@ For each Verification Gate from the Task Contract, write one evidence line to Im
45
45
  - Gate Evidence section
46
46
  - unresolved blockers
47
47
 
48
- **CP-2**: All tasks `[x]`, Implementation Log written with Gate Evidence, Test Failure Recovery Protocol's Success Rule satisfied. Blocked gates → `failure-log.md`, not success.
48
+ **CP-2**: All tasks `[x]`, Implementation Log written with Gate Evidence, and blocked gates documented in `failure-log.md`. Test execution is deferred until after code review.
49
49
 
50
50
  **Checkpoint update**:
51
51
  ```bash
@@ -20,15 +20,15 @@ Save pre-existing failing tests as `BASELINE_FAILURES`.
20
20
  **3b.** Run `/prizmkit-implement` directly — you (the orchestrator) execute the full cycle:
21
21
  - Read plan.md Tasks from `.prizmkit/specs/{{FEATURE_SLUG}}/`
22
22
  - Use context-snapshot.md Section 4 File Manifest for targeted reads — do NOT re-read files already summarized there
23
- - Implement task-by-task with TDD, marking each `[x]` immediately
23
+ - Implements task-by-task, marking each `[x]` immediately
24
24
  - Creates/updates L2 `.prizm` docs when creating new modules
25
- - Runs tests using `TEST_CMD`
25
+ - Defers scoped/full test execution until after the code-review loop completes
26
26
  - If plan.md has >5 tasks: update checkpoints after every 3 tasks
27
27
 
28
- **3c. Layered test strategy** (replaces "run full suite every 3 Edits"):
29
- - Debugging a single test: `npx vitest run <test-file> -t '<test name>'` (or per-stack equivalent). Capture to `/tmp/test-out.txt`, grep for failures.
30
- - Only when single-file is green, run ONE full `{{TEST_CMD}}` as the gate.
31
- - Never run full suite while a single-file test is still red.
28
+ **3c. Focused checks only (no test gate here)**:
29
+ - During implementation, do not run mandatory periodic or full-suite tests.
30
+ - If a tiny targeted check is needed to understand a local failure, run only the smallest relevant command and capture output to `/tmp/test-out.txt`.
31
+ - The scoped feature test gate runs after code review; do not declare implementation success based on an early full-suite run.
32
32
 
33
33
  **3d. Verification Gate Self-Check (BLOCKING — before declaring implement done)**:
34
34
  For each Verification Gate from the Task Contract, write one evidence line to Implementation Log:
@@ -46,7 +46,7 @@ For each Verification Gate from the Task Contract, write one evidence line to Im
46
46
  - Gate Evidence section
47
47
  - unresolved blockers
48
48
 
49
- **CP-2**: All tasks `[x]`, Implementation Log written with Gate Evidence, Test Failure Recovery Protocol's Success Rule satisfied. Blocked gates → `failure-log.md`, not success.
49
+ **CP-2**: All tasks `[x]`, Implementation Log written with Gate Evidence, and blocked gates documented in `failure-log.md`. Test execution is deferred until after code review.
50
50
 
51
51
  **Checkpoint update**:
52
52
  ```bash
@@ -1,33 +1,24 @@
1
- ### Implement + Test
1
+ ### Implement
2
2
 
3
3
  **Protocol references**:
4
4
  - Follow Context Budget Rules §8 for scaffold/generated files.
5
5
  - Follow Context Budget Rules §9 before package install/build commands that resolve dependencies.
6
6
  - Follow Context Budget Rules §10 after build/compile commands.
7
7
 
8
- **3a.** Detect test commands and record baseline:
9
-
10
- 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`. Then record baseline:
11
- ```bash
12
- # Run each test command, capture output
13
- ($TEST_CMD) 2>&1 | tee /tmp/test-baseline.txt | tail -20
14
- ```
15
-
16
- **3b.** Run `/prizmkit-implement` — this handles the full implementation cycle:
8
+ **3a.** Run `/prizmkit-implement` this handles the implementation cycle:
17
9
  - Reads plan.md Tasks section from `.prizmkit/specs/{{FEATURE_SLUG}}/`
18
10
  - Reads context from `context-snapshot.md` (Prizm docs, TRAPS, file manifest)
19
- - Implements task-by-task with TDD, marking each `[x]` immediately
11
+ - Implements task-by-task, marking each `[x]` immediately
20
12
  - 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
21
- - Runs tests using `TEST_CMD` after each task
13
+ - Does not run the scoped/full test gate; testing happens after code review in the PrizmKit Test phase
22
14
  - Writes '## Implementation Log' to `context-snapshot.md`
23
15
 
24
- **3c.** After implement completes, verify:
16
+ **3b.** After implement completes, verify:
25
17
  1. All tasks in plan.md are `[x]`
26
- 2. Run the full test suite to ensure no new regressions remain
27
- 3. Verify each Verification Gate from the Task Contract — check mentally, do NOT re-read files you already wrote
28
- 4. If any gate is unmet or blocked, follow the Test Failure Recovery Protocol
18
+ 2. Verify each Verification Gate from the Task Contract using code/file evidence already in context — do NOT re-read files you already wrote
19
+ 3. If any gate is unmet or blocked, write `failure-log.md` and stop for recovery
29
20
 
30
- **CP-2**: Implementation may proceed only when all tasks are `[x]` and the Test Failure Recovery Protocol's Success Rule is satisfied. Blocked gates must be documented in `failure-log.md` and are not success.
21
+ **CP-2**: Implementation may proceed only when all tasks are `[x]` and blocked gates are documented in `failure-log.md`. Test execution is deferred until after code review.
31
22
 
32
23
 
33
24
  **Checkpoint update**: Run the update script to set step `prizmkit-implement` to `"completed"`:
@@ -1,6 +1,6 @@
1
1
  ### Scoped Feature Test Gate — PrizmKit Test
2
2
 
3
- **Goal**: Generate and verify tests for this feature's changed scope before code review without embedding the full gate implementation in this prompt.
3
+ **Goal**: After code review completes, generate and verify tests for this feature's changed scope without embedding the full gate implementation in this prompt.
4
4
 
5
5
  Create a start marker immediately before invoking the skill so the gate can reject stale reports from older sessions:
6
6
 
@@ -34,6 +34,6 @@ python3 "$PIPELINE_DIR/scripts/prizmkit-test-gate.py" check \
34
34
 
35
35
  Gate outcomes:
36
36
  - `GATE:PASS` → append the report path and a 3-5 bullet summary to `context-snapshot.md` under `## PrizmKit Test Gate`, then proceed to the next checkpoint step. The gate script already wrote `test-report-path.txt` and marked `prizmkit-test` completed.
37
- - `GATE:FAIL` with `NEEDS_FIXES` → read the report's `In-Scope Failures`, fix the feature implementation or generated tests within this feature scope, rerun `/prizmkit-test`, and repeat the gate check. Do not proceed to code review while the verdict is not `PASS`.
37
+ - `GATE:FAIL` with `NEEDS_FIXES` → read the report's `In-Scope Failures`, fix the feature implementation or generated tests within this feature scope, rerun `/prizmkit-test`, and repeat the gate check. Do not proceed to retrospective/commit while the verdict is not `PASS`.
38
38
  - `GATE:FAIL` with `BLOCKED`, wrong mode, wrong artifact dir, unreadable report, stale scope, boundary failure, validator failure, or checkpoint update failure → write `.prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md` with the scoped test failure and stop for recovery.
39
39
  - `GATE:MISSING` → perform one bounded status check: inspect `/prizmkit-test` output and `.prizmkit/test/` for a report directory. If no current-run report exists, write `failure-log.md` and stop for recovery.
@@ -1,8 +1,6 @@
1
1
  ### Review — Code Review
2
2
 
3
- Precondition: the `prizmkit-test` checkpoint is completed and `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt` points to the scoped test report.
4
-
5
- Before invoking review, read `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt`, read the referenced `/prizmkit-test` report, and confirm the summary in `context-snapshot.md` under `## PrizmKit Test Gate` matches it. The code-review skill must receive this context through `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` and the Reviewer must assess generated/updated test quality, `In-Scope Failures`, `Baseline Failures`, `Out of Scope Gaps`, boundary coverage if present, and the scoped report verdict.
3
+ 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.
6
4
 
7
5
  Run `/prizmkit-code-review` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/`.
8
6
 
@@ -1,8 +1,6 @@
1
1
  ### Review — Code Review
2
2
 
3
- Precondition: the `prizmkit-test` checkpoint is completed and `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt` points to the scoped test report.
4
-
5
- Before invoking review, read `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt`, read the referenced `/prizmkit-test` report, and confirm the summary in `context-snapshot.md` under `## PrizmKit Test Gate` matches it. The code-review skill must receive this context through `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` and the Reviewer must assess generated/updated test quality, `In-Scope Failures`, `Baseline Failures`, `Out of Scope Gaps`, boundary coverage if present, and the scoped report verdict.
3
+ 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.
6
4
 
7
5
  Run `/prizmkit-code-review` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/`.
8
6
 
@@ -1,15 +1,10 @@
1
- ### Phase 0: Record Test Baseline & Detect Test Commands
1
+ ### Phase 0: Detect Test Commands
2
2
 
3
3
  **Step 1 — Detect test commands**: 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`.
4
4
 
5
- **Step 2 — Record pre-existing failure baseline**:
6
- ```bash
7
- # Run each test command, capture output
8
- ($TEST_CMD) 2>&1 | tee /tmp/test-baseline.txt | tail -20
9
- ```
10
- Save the list of **pre-existing failing tests** (if any) as `BASELINE_FAILURES`. These are known failures that existed before this session — Dev must NOT be blamed for them, but must list them in COMPLETION_SIGNAL.
5
+ **Step 2 — Do not run tests yet**: This phase only records the commands that will be used by the post-review PrizmKit Test gate. Do not run baseline, periodic, or full-suite tests here; test execution happens after code review.
11
6
 
12
- > **Test Output Rule**: Always capture test output to a temp file (`tee /tmp/test-out.txt`). Then grep the file instead of re-running the suite.
7
+ > **Test Output Rule**: When the post-review gate runs, capture test output to a temp file (`tee /tmp/test-out.txt`). Then grep the file instead of re-running the suite.
13
8
 
14
9
 
15
10
  **Checkpoint update**: Run the update script to set step `test-baseline` to `"completed"`: