prizmkit 1.1.38 → 1.1.40

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.1.38",
3
- "bundledAt": "2026-04-19T13:50:39.931Z",
4
- "bundledFrom": "487e85a"
2
+ "frameworkVersion": "1.1.40",
3
+ "bundledAt": "2026-04-20T14:02:15.471Z",
4
+ "bundledFrom": "a703bde"
5
5
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: prizm-dev-team-critic
3
- description: Adversarial challenger that questions plan fitness and code integration quality. Evaluates whether plans and implementations truly fit the project's existing architecture, style, and patterns. Does NOT verify correctness (that's Reviewer's job) — instead challenges strategic decisions and integration quality. Use when performing adversarial plan or code challenge.
3
+ description: Adversarial challenger that questions plan fitness against the project's existing architecture, style, and patterns. Evaluates whether plans truly fit the project before implementation begins. Does NOT verify correctness (that's Reviewer's job) — instead challenges strategic decisions and integration planning. Use when performing adversarial plan challenge.
4
4
  tools: Read, Glob, Grep, Bash
5
5
  disallowedTools: Agent, Write, Edit
6
6
  model: inherit
@@ -13,9 +13,7 @@ You are the **Critic Agent**, the adversarial challenger of the PrizmKit-integra
13
13
 
14
14
  You are the team's "devil's advocate" — you challenge decisions, question assumptions, and find hidden risks that others miss. You do NOT verify correctness (that is Reviewer's job) and you do NOT check document consistency (that is Analyze's job). Your unique value is asking: **"Does this BELONG in this project? Is this the RIGHT approach? What are you NOT seeing?"**
15
15
 
16
- You operate in two modes, determined by the `MODE` field in your prompt:
17
- 1. **Plan Challenge**: Before implementation, challenge the plan's fitness for the project
18
- 2. **Code Challenge**: After implementation, challenge the code's integration quality
16
+ You operate in **Plan Challenge** mode: before implementation, you challenge the plan's fitness for the project. Code-level review is handled by the Code Review skill's built-in review-fix loop (Reviewer Agent → filter → Dev Agent).
19
17
 
20
18
  ### Project Context
21
19
 
@@ -33,7 +31,7 @@ Before any challenge, you MUST understand the project:
33
31
  3. Ground every challenge in specific evidence (file paths, code patterns, existing conventions)
34
32
  4. Write `challenge-report.md` with structured findings
35
33
  5. Keep the report ≤50 lines — focus on HIGH and CRITICAL only, skip LOW
36
- 6. Clearly state the MODE you are operating in (Plan Challenge or Code Challenge)
34
+ 6. Clearly state you are operating in Plan Challenge mode
37
35
 
38
36
  ### Never Do (NEVER)
39
37
 
@@ -52,7 +50,7 @@ CRIT-01: Always read .prizm-docs/ and existing source before challenging
52
50
  CRIT-02: Every challenge must reference a specific file path or code pattern as evidence
53
51
  CRIT-03: Maximum 10 challenges per report (focus on highest impact)
54
52
  CRIT-04: Severity levels: CRITICAL (architecture mismatch), HIGH (style/robustness gap), MEDIUM (minor inconsistency)
55
- CRIT-05: If no significant challenges found, write "No significant challenges — plan/code fits the project well" and exit
53
+ CRIT-05: If no significant challenges found, write "No significant challenges — plan fits the project well" and exit
56
54
  CRIT-06: Do NOT re-raise issues already covered by Analyze (document consistency) or Reviewer (correctness)
57
55
  CRIT-07: Read comparable existing code in the same module for style baseline before flagging style issues
58
56
  CRIT-08: When challenging a decision, always suggest a concrete alternative
@@ -87,40 +85,14 @@ CRIT-10: In voting mode, write to your assigned report file (challenge-report-{A
87
85
 
88
86
  ---
89
87
 
90
- ## Mode 2: Code Challenge
91
-
92
- **Precondition**: Dev has completed implementation. All tasks `[x]`, tests pass. Implementation Log exists in `context-snapshot.md`.
93
-
94
- **Goal**: Challenge whether the implemented code integrates well with the existing project — not whether it's correct (that's Reviewer's job).
95
-
96
- ### Challenge Dimensions
97
-
98
- | Dimension | What to Challenge | Evidence Source |
99
- |-----------|------------------|----------------|
100
- | **Style Consistency** | Do naming conventions, code structure, and patterns match existing code in the same module? | Read existing files in the same directory/module |
101
- | **Robustness** | Are edge cases handled? Error paths? Data validation? What happens with unexpected input not covered by the spec? | Read the new code, compare error handling patterns with existing code |
102
- | **Integration Cohesion** | Does the new code interact naturally with existing code? Are abstractions consistent? Are import patterns standard? | Read call sites, compare with existing integrations |
103
- | **Hidden Impact** | Could the new code have side effects on existing functionality? Shared state, global config, database constraints, event handlers? | Read shared modules, config files, database schemas |
104
-
105
- ### Workflow
106
-
107
- 1. Read `context-snapshot.md` — Implementation Log section for what changed
108
- 2. Read `.prizm-docs/root.prizm` and affected module docs (RULES, PATTERNS)
109
- 3. Read the actual source files changed (from Implementation Log)
110
- 4. Read comparable existing files in the same module for style baseline
111
- 5. For each dimension, compare new code against existing code patterns
112
- 6. Write `challenge-report.md` to `.prizmkit/specs/<feature-slug>/` (overwrite any existing report)
113
-
114
- ---
115
-
116
88
  ## Output Format
117
89
 
118
90
  Write `challenge-report.md` (or `challenge-report-{A,B,C}.md` in voting mode):
119
91
 
120
92
  ```markdown
121
- ## Challenge Report — [Plan Challenge | Code Challenge]
93
+ ## Challenge Report — Plan Challenge
122
94
  Feature: <FEATURE_ID> — <FEATURE_TITLE>
123
- Mode: [Plan Challenge | Code Challenge]
95
+ Mode: Plan Challenge
124
96
  Challenges Found: N (X critical, Y high, Z medium)
125
97
 
126
98
  ### CHALLENGE-1: [CRITICAL] Title
@@ -307,7 +307,7 @@ pending, in_progress, completed, failed, skipped
307
307
  | Phase Implementation | `phase-implement-lite.md`, `phase-implement-full.md`, `phase-implement-agent.md` | Three execution modes |
308
308
  | Phase Review | `phase-review-full.md`, `phase-review-agent.md` | Full & Agent variants |
309
309
  | Phase Plan | `phase-plan-lite.md`, `phase-plan-agent.md` | Lite & Agent variants |
310
- | Phase Critic | `phase-critic-plan.md`, `phase-critic-plan-full.md`, `phase-critic-code.md` | Plan vs Code review, single vs multi |
310
+ | Phase Critic | `phase-critic-plan.md`, `phase-critic-plan-full.md` | Plan review (single and multi) |
311
311
  | Phase Commit | `phase-commit.md`, `phase-commit-full.md` | Standard & Full variants |
312
312
 
313
313
  ### Singleton Sections
@@ -623,7 +623,6 @@ SECTION_TO_SKILL = {
623
623
  [".prizmkit/specs/{slug}/plan.md"]),
624
624
  "phase-critic-plan": ("critic-plan-review", "Critic: Plan Review", []),
625
625
  "phase-implement": ("prizmkit-implement", "Implement + Test", []),
626
- "phase-critic-code": ("critic-code-review", "Critic: Code Review", []),
627
626
  "phase-review": ("prizmkit-code-review", "Code Review", []),
628
627
  "phase-browser": ("browser-verification", "Browser Verification", []),
629
628
  "phase-deploy": ("deploy-verification", "Deploy Verification", []),
@@ -1043,12 +1042,6 @@ def assemble_sections(pipeline_mode, sections_dir, init_done, is_resume,
1043
1042
  load_section(sections_dir,
1044
1043
  "test-failure-recovery-agent.md")))
1045
1044
 
1046
- # --- Critic: Code Challenge (only if critic enabled, agent tiers) ---
1047
- if critic_enabled and pipeline_mode in ("standard", "full"):
1048
- sections.append(("phase-critic-code",
1049
- load_section(sections_dir,
1050
- "phase-critic-code.md")))
1051
-
1052
1045
  # --- AC Verification Checklist (all tiers) ---
1053
1046
  ac_checklist_path = os.path.join(sections_dir, "ac-verification-checklist.md")
1054
1047
  if os.path.isfile(ac_checklist_path):
@@ -260,6 +260,39 @@ def build_replacements(args, bug, global_context, script_dir):
260
260
  # Determine verification type
261
261
  vtype = bug.get("verification_type", "automated")
262
262
 
263
+ # Browser interaction - extract from bug if present
264
+ browser_interaction = bug.get("browser_interaction")
265
+ browser_enabled = False
266
+ browser_verify_steps = ""
267
+ browser_tool = "auto"
268
+
269
+ # Environment override
270
+ browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
271
+ if browser_verify_env == "false":
272
+ browser_interaction = None
273
+
274
+ # Extract browser config (same logic as feature pipeline)
275
+ if browser_interaction and isinstance(browser_interaction, bool):
276
+ browser_enabled = True
277
+ browser_tool = "auto"
278
+ browser_verify_steps = " # (no specific verify goals — reproduce the bug and verify it's fixed)"
279
+ elif browser_interaction and isinstance(browser_interaction, dict):
280
+ browser_tool = browser_interaction.get("tool", "auto")
281
+ if browser_tool not in ("playwright-cli", "opencli", "auto"):
282
+ LOGGER.warning("Unknown browser_interaction.tool '%s', defaulting to 'auto'", browser_tool)
283
+ browser_tool = "auto"
284
+
285
+ steps = browser_interaction.get("verify_steps", [])
286
+ if steps:
287
+ browser_enabled = True
288
+ browser_verify_steps = "\n".join(
289
+ " # Step {}: {}".format(i + 1, step)
290
+ for i, step in enumerate(steps)
291
+ )
292
+ elif browser_interaction.get("url") or browser_interaction.get("enabled", True):
293
+ browser_enabled = True
294
+ browser_verify_steps = " # (reproduce bug and verify fix)"
295
+
263
296
  replacements = {
264
297
  "{{RUN_ID}}": args.run_id,
265
298
  "{{SESSION_ID}}": args.session_id,
@@ -284,13 +317,17 @@ def build_replacements(args, bug, global_context, script_dir):
284
317
  "{{PROJECT_ROOT}}": project_root,
285
318
  "{{FIX_SCOPE}}": fix_scope,
286
319
  "{{TIMESTAMP}}": "", # Placeholder, agent fills in the timestamp
320
+ "{{BROWSER_ENABLED}}": "true" if browser_enabled else "false",
321
+ "{{BROWSER_TOOL}}": browser_tool,
322
+ "{{BROWSER_VERIFY_STEPS}}": browser_verify_steps,
287
323
  }
288
324
 
289
325
  return replacements
290
326
 
291
327
 
292
328
  def process_conditional_blocks(content, bug):
293
- """Handle conditional blocks based on verification_type."""
329
+ """Handle conditional blocks based on verification_type and browser_interaction."""
330
+ # Handle verification type blocks
294
331
  vtype = bug.get("verification_type", "automated")
295
332
  is_manual_or_hybrid = vtype in ("manual", "hybrid")
296
333
 
@@ -306,6 +343,64 @@ def process_conditional_blocks(content, bug):
306
343
  "", content, flags=re.DOTALL,
307
344
  )
308
345
 
346
+ # Handle browser interaction blocks
347
+ browser_interaction = bug.get("browser_interaction")
348
+ browser_enabled = False
349
+ browser_tool = "auto"
350
+
351
+ # Check environment override
352
+ browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
353
+ if browser_verify_env == "false":
354
+ browser_interaction = None
355
+
356
+ # Determine if browser is enabled
357
+ if browser_interaction:
358
+ if isinstance(browser_interaction, bool):
359
+ browser_enabled = True
360
+ elif isinstance(browser_interaction, dict):
361
+ steps = browser_interaction.get("verify_steps", [])
362
+ if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
363
+ browser_enabled = True
364
+ browser_tool = browser_interaction.get("tool", "auto")
365
+
366
+ # Process browser interaction blocks
367
+ browser_open = "{{IF_BROWSER_INTERACTION}}"
368
+ browser_close = "{{END_IF_BROWSER_INTERACTION}}"
369
+
370
+ if browser_enabled:
371
+ # Keep content, remove tags
372
+ content = content.replace(browser_open + "\n", "")
373
+ content = content.replace(browser_open, "")
374
+ content = content.replace(browser_close + "\n", "")
375
+ content = content.replace(browser_close, "")
376
+ else:
377
+ # Remove entire block
378
+ pattern = re.escape(browser_open) + r".*?" + re.escape(browser_close) + r"\n?"
379
+ content = re.sub(pattern, "", content, flags=re.DOTALL)
380
+
381
+ # Process browser tool selection blocks (nested inside browser interaction)
382
+ tool_variants = ["PLAYWRIGHT", "OPENCLI", "AUTO"]
383
+ active_variant = {
384
+ "playwright-cli": "PLAYWRIGHT",
385
+ "opencli": "OPENCLI",
386
+ "auto": "AUTO",
387
+ }.get(browser_tool, "AUTO")
388
+
389
+ for variant in tool_variants:
390
+ tool_open = "{{{{IF_BROWSER_TOOL_{}}}}}".format(variant)
391
+ tool_close = "{{{{END_IF_BROWSER_TOOL_{}}}}}".format(variant)
392
+
393
+ if variant == active_variant and browser_enabled:
394
+ # Keep content, remove tags
395
+ content = content.replace(tool_open + "\n", "")
396
+ content = content.replace(tool_open, "")
397
+ content = content.replace(tool_close + "\n", "")
398
+ content = content.replace(tool_close, "")
399
+ else:
400
+ # Remove entire block
401
+ pat = re.escape(tool_open) + r".*?" + re.escape(tool_close) + r"\n?"
402
+ content = re.sub(pat, "", content, flags=re.DOTALL)
403
+
309
404
  return content
310
405
 
311
406
 
@@ -529,6 +624,26 @@ def main():
529
624
 
530
625
  # Success
531
626
  bug_model = bug.get("model", "")
627
+ # Extract browser interaction state for output
628
+ browser_interaction = bug.get("browser_interaction")
629
+ browser_enabled = False
630
+ browser_tool = "auto"
631
+
632
+ browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
633
+ if browser_verify_env == "false":
634
+ browser_interaction = None
635
+
636
+ if browser_interaction:
637
+ if isinstance(browser_interaction, bool):
638
+ browser_enabled = True
639
+ elif isinstance(browser_interaction, dict):
640
+ steps = browser_interaction.get("verify_steps", [])
641
+ if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
642
+ browser_enabled = True
643
+ browser_tool = browser_interaction.get("tool", "auto")
644
+ if browser_tool not in ("playwright-cli", "opencli", "auto"):
645
+ browser_tool = "auto"
646
+
532
647
  output = {
533
648
  "success": True,
534
649
  "output_path": os.path.abspath(args.output),
@@ -537,6 +652,8 @@ def main():
537
652
  "pipeline_mode": pipeline_mode,
538
653
  "agent_count": agent_count,
539
654
  "critic_enabled": critic_enabled,
655
+ "browser_enabled": browser_enabled,
656
+ "browser_tool": browser_tool
540
657
  }
541
658
  print(json.dumps(output, indent=2, ensure_ascii=False))
542
659
  sys.exit(0)
@@ -420,6 +420,39 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
420
420
  else:
421
421
  new_tests_str = "- (none specified)"
422
422
 
423
+ # Browser interaction - extract from refactor if present
424
+ browser_interaction = refactor.get("browser_interaction")
425
+ browser_enabled = False
426
+ browser_verify_steps = ""
427
+ browser_tool = "auto"
428
+
429
+ # Environment override
430
+ browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
431
+ if browser_verify_env == "false":
432
+ browser_interaction = None
433
+
434
+ # Extract browser config (same logic as feature and bugfix pipelines)
435
+ if browser_interaction and isinstance(browser_interaction, bool):
436
+ browser_enabled = True
437
+ browser_tool = "auto"
438
+ browser_verify_steps = " # (no specific verify goals — validate UI renders correctly and feature still works)"
439
+ elif browser_interaction and isinstance(browser_interaction, dict):
440
+ browser_tool = browser_interaction.get("tool", "auto")
441
+ if browser_tool not in ("playwright-cli", "opencli", "auto"):
442
+ LOGGER.warning("Unknown browser_interaction.tool '%s', defaulting to 'auto'", browser_tool)
443
+ browser_tool = "auto"
444
+
445
+ steps = browser_interaction.get("verify_steps", [])
446
+ if steps:
447
+ browser_enabled = True
448
+ browser_verify_steps = "\n".join(
449
+ " # Step {}: {}".format(i + 1, step)
450
+ for i, step in enumerate(steps)
451
+ )
452
+ elif browser_interaction.get("url") or browser_interaction.get("enabled", True):
453
+ browser_enabled = True
454
+ browser_verify_steps = " # (validate UI renders correctly and feature still works)"
455
+
423
456
  replacements = {
424
457
  "{{RUN_ID}}": args.run_id,
425
458
  "{{SESSION_ID}}": args.session_id,
@@ -452,16 +485,17 @@ def build_replacements(args, refactor, refactors, global_context, script_dir):
452
485
  ),
453
486
  "{{TIMESTAMP}}": "", # Placeholder — agent fills in timestamp
454
487
  "{{PLATFORM_CONVENTIONS}}": read_platform_conventions(project_root),
488
+ "{{BROWSER_ENABLED}}": "true" if browser_enabled else "false",
489
+ "{{BROWSER_TOOL}}": browser_tool,
490
+ "{{BROWSER_VERIFY_STEPS}}": browser_verify_steps,
455
491
  }
456
492
 
457
493
  return replacements
458
494
 
459
495
 
460
- def process_conditional_blocks(content, resume_phase):
461
- """Handle conditional blocks based on resume_phase.
462
-
463
- - {{IF_FRESH_START}}...{{END_IF_FRESH_START}} — include only on fresh start (resume_phase == "null")
464
- """
496
+ def process_conditional_blocks(content, resume_phase, refactor):
497
+ """Handle conditional blocks based on resume_phase and browser_interaction."""
498
+ # Handle fresh start blocks
465
499
  is_resume = resume_phase != "null"
466
500
 
467
501
  if is_resume:
@@ -475,13 +509,72 @@ def process_conditional_blocks(content, resume_phase):
475
509
  content = content.replace("{{END_IF_FRESH_START}}\n", "")
476
510
  content = content.replace("{{END_IF_FRESH_START}}", "")
477
511
 
512
+ # Handle browser interaction blocks
513
+ browser_interaction = refactor.get("browser_interaction")
514
+ browser_enabled = False
515
+ browser_tool = "auto"
516
+
517
+ # Check environment override
518
+ browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
519
+ if browser_verify_env == "false":
520
+ browser_interaction = None
521
+
522
+ # Determine if browser is enabled
523
+ if browser_interaction:
524
+ if isinstance(browser_interaction, bool):
525
+ browser_enabled = True
526
+ elif isinstance(browser_interaction, dict):
527
+ steps = browser_interaction.get("verify_steps", [])
528
+ if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
529
+ browser_enabled = True
530
+ browser_tool = browser_interaction.get("tool", "auto")
531
+
532
+ # Process browser interaction blocks
533
+ browser_open = "{{IF_BROWSER_INTERACTION}}"
534
+ browser_close = "{{END_IF_BROWSER_INTERACTION}}"
535
+
536
+ if browser_enabled:
537
+ # Keep content, remove tags
538
+ content = content.replace(browser_open + "\n", "")
539
+ content = content.replace(browser_open, "")
540
+ content = content.replace(browser_close + "\n", "")
541
+ content = content.replace(browser_close, "")
542
+ else:
543
+ # Remove entire block
544
+ pattern = re.escape(browser_open) + r".*?" + re.escape(browser_close) + r"\n?"
545
+ content = re.sub(pattern, "", content, flags=re.DOTALL)
546
+
547
+ # Process browser tool selection blocks (nested inside browser interaction)
548
+ tool_variants = ["PLAYWRIGHT", "OPENCLI", "AUTO"]
549
+ active_variant = {
550
+ "playwright-cli": "PLAYWRIGHT",
551
+ "opencli": "OPENCLI",
552
+ "auto": "AUTO",
553
+ }.get(browser_tool, "AUTO")
554
+
555
+ for variant in tool_variants:
556
+ tool_open = "{{{{IF_BROWSER_TOOL_{}}}}}".format(variant)
557
+ tool_close = "{{{{END_IF_BROWSER_TOOL_{}}}}}".format(variant)
558
+
559
+ if variant == active_variant and browser_enabled:
560
+ # Keep content, remove tags
561
+ content = content.replace(tool_open + "\n", "")
562
+ content = content.replace(tool_open, "")
563
+ content = content.replace(tool_close + "\n", "")
564
+ content = content.replace(tool_close, "")
565
+ else:
566
+ # Remove entire block
567
+ pat = re.escape(tool_open) + r".*?" + re.escape(tool_close) + r"\n?"
568
+ content = re.sub(pat, "", content, flags=re.DOTALL)
569
+
478
570
  return content
479
571
 
480
572
 
481
- def render_template(template_content, replacements, resume_phase):
573
+
574
+ def render_template(template_content, replacements, resume_phase, refactor):
482
575
  """Render the template by processing conditionals and replacing placeholders."""
483
576
  # Step 1: Process conditional blocks
484
- content = process_conditional_blocks(template_content, resume_phase)
577
+ content = process_conditional_blocks(template_content, resume_phase, refactor)
485
578
 
486
579
  # Step 2: Replace all {{PLACEHOLDER}} variables
487
580
  for placeholder, value in replacements.items():
@@ -560,7 +653,7 @@ def main():
560
653
  replacements = build_replacements(args, refactor, refactors, global_context, script_dir)
561
654
 
562
655
  # Render the template
563
- rendered = render_template(template_content, replacements, args.resume_phase)
656
+ rendered = render_template(template_content, replacements, args.resume_phase, refactor)
564
657
 
565
658
  # Write the output
566
659
  err = write_output(args.output, rendered)
@@ -610,13 +703,35 @@ def main():
610
703
 
611
704
  # Success
612
705
  refactor_model = refactor.get("model", "")
706
+
707
+ # Extract browser state for JSON output
708
+ browser_interaction = refactor.get("browser_interaction")
709
+ browser_enabled = False
710
+ browser_tool = "auto"
711
+
712
+ browser_verify_env = os.environ.get("BROWSER_VERIFY", "").lower()
713
+ if browser_verify_env == "false":
714
+ browser_interaction = None
715
+
716
+ if browser_interaction:
717
+ if isinstance(browser_interaction, bool):
718
+ browser_enabled = True
719
+ elif isinstance(browser_interaction, dict):
720
+ steps = browser_interaction.get("verify_steps", [])
721
+ if steps or browser_interaction.get("url") or browser_interaction.get("enabled", True):
722
+ browser_enabled = True
723
+ browser_tool = browser_interaction.get("tool", "auto")
724
+
613
725
  output = {
614
726
  "success": True,
615
727
  "output_path": os.path.abspath(args.output),
728
+ "checkpoint_path": checkpoint_path,
616
729
  "model": refactor_model,
617
730
  "pipeline_mode": pipeline_mode,
618
731
  "agent_count": agent_count,
619
732
  "critic_enabled": critic_enabled,
733
+ "browser_enabled": browser_enabled,
734
+ "browser_tool": browser_tool,
620
735
  }
621
736
  print(json.dumps(output, indent=2, ensure_ascii=False))
622
737
  sys.exit(0)
@@ -228,33 +228,6 @@ grep -q "## Implementation Log" .prizmkit/specs/{{FEATURE_SLUG}}/context-snapsho
228
228
  ```
229
229
  If GATE:MISSING — send message to Dev (re-spawn if needed): "Write the '## Implementation Log' section to context-snapshot.md before I can proceed to review. Include: files changed/created, key decisions, deviations from plan, notable discoveries."
230
230
 
231
- {{IF_CRITIC_ENABLED}}
232
- ### Phase 4.5: Code Challenge — Critic Agent
233
-
234
- **Guard**: Verify critic agent file exists before spawning:
235
- ```bash
236
- ls {{CRITIC_SUBAGENT_PATH}} 2>/dev/null && echo "CRITIC:READY" || echo "CRITIC:MISSING"
237
- ```
238
- If CRITIC:MISSING — skip Phase 4.5 entirely and proceed to Phase 5. Log: "Critic agent not installed — skipping Code Challenge."
239
-
240
- Spawn Critic agent (Agent tool, subagent_type="prizm-dev-team-critic", mode="plan", run_in_background=false).
241
-
242
- Prompt:
243
- > "Read {{CRITIC_SUBAGENT_PATH}}. For feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}):
244
- > **MODE: Code Challenge**
245
- > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` — Implementation Log section shows what Dev changed.
246
- > 2. Read `.prizm-docs/root.prizm` and relevant module docs for RULES/PATTERNS.
247
- > 3. Read the actual source files changed (from Implementation Log).
248
- > 4. Read comparable existing source files in the same module for style comparison.
249
- > 5. Challenge code integration quality: style fit, robustness, existing code cohesion, hidden impact.
250
- > Write `.prizmkit/specs/{{FEATURE_SLUG}}/challenge-report.md` (overwrite) with findings (or 'No significant challenges')."
251
-
252
- Wait for Critic to return.
253
- - Read challenge-report.md. For items marked CRITICAL/HIGH: spawn Dev to fix, then proceed to Review.
254
-
255
- **CP-3.5**: Code challenges reviewed and resolved.
256
- {{END_IF_CRITIC_ENABLED}}
257
-
258
231
  ### Phase 5: Review + Test — Reviewer Subagent
259
232
 
260
233
  Spawn Reviewer subagent (Agent tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false).
@@ -293,33 +293,6 @@ Wait for Dev to return. **If Dev times out before all tasks are `[x]`**:
293
293
 
294
294
  All tasks `[x]`, tests pass.
295
295
 
296
- {{IF_CRITIC_ENABLED}}
297
- ### Phase 4.5: Code Challenge — Critic Agent
298
-
299
- **Guard**: Verify critic agent file exists before spawning:
300
- ```bash
301
- ls {{CRITIC_SUBAGENT_PATH}} 2>/dev/null && echo "CRITIC:READY" || echo "CRITIC:MISSING"
302
- ```
303
- If CRITIC:MISSING — skip Phase 4.5 entirely and proceed to Phase 5. Log: "Critic agent not installed — skipping Code Challenge."
304
-
305
- Spawn Critic agent (Agent tool, subagent_type="prizm-dev-team-critic", mode="plan", run_in_background=false).
306
-
307
- Prompt:
308
- > "Read {{CRITIC_SUBAGENT_PATH}}. For feature {{FEATURE_ID}} (slug: {{FEATURE_SLUG}}):
309
- > **MODE: Code Challenge**
310
- > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` — Implementation Log section shows what Dev changed.
311
- > 2. Read `.prizm-docs/root.prizm` and relevant module docs for RULES/PATTERNS.
312
- > 3. Read the actual source files changed (from Implementation Log).
313
- > 4. Read comparable existing source files in the same module for style comparison.
314
- > 5. Challenge code integration quality: style fit, robustness, existing code cohesion, hidden impact.
315
- > Write `.prizmkit/specs/{{FEATURE_SLUG}}/challenge-report.md` (overwrite) with findings (or 'No significant challenges')."
316
-
317
- Wait for Critic to return.
318
- - Read challenge-report.md. For items marked CRITICAL/HIGH: spawn Dev to fix, then proceed to Review.
319
-
320
- **CP-3.5**: Code challenges reviewed and resolved.
321
- {{END_IF_CRITIC_ENABLED}}
322
-
323
296
  ### Phase 5: Review + Test — Reviewer Agent
324
297
 
325
298
  Spawn Reviewer agent (Agent tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false).
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "title": "Dev-Pipeline Bug Fix List",
4
- "description": "Schema for .prizmkit/plans/bug-fix-list.json \u2014 standardized input for the Bug Fix Pipeline",
4
+ "description": "Schema for .prizmkit/plans/bug-fix-list.json standardized input for the Bug Fix Pipeline",
5
5
  "type": "object",
6
6
  "required": [
7
7
  "$schema",
@@ -51,7 +51,7 @@
51
51
  "title": {
52
52
  "type": "string",
53
53
  "minLength": 1,
54
- "description": "Bug title \u2014 brief description of the symptom"
54
+ "description": "Bug title brief description of the symptom"
55
55
  },
56
56
  "description": {
57
57
  "type": "string",
@@ -175,7 +175,7 @@
175
175
  },
176
176
  "critic": {
177
177
  "type": "boolean",
178
- "description": "Enable adversarial critic review for this bug fix. Default: true for high severity bugs, false for others.",
178
+ "description": "Enable adversarial plan challenge before implementation. Default: true for high severity bugs, false for others.",
179
179
  "default": false
180
180
  },
181
181
  "critic_count": {
@@ -194,6 +194,25 @@
194
194
  "model": {
195
195
  "type": "string",
196
196
  "description": "AI model ID for this bug fix. Overrides $MODEL env var."
197
+ },
198
+ "browser_interaction": {
199
+ "type": "object",
200
+ "description": "Browser verification config for bugs reproducible via UI. Supports playwright-cli and opencli. AI auto-detects dev server command, URL, and port from project config at runtime.",
201
+ "properties": {
202
+ "tool": {
203
+ "type": "string",
204
+ "enum": ["playwright-cli", "opencli", "auto"],
205
+ "default": "auto",
206
+ "description": "Browser tool to use. 'auto' (default) = AI chooses at runtime. 'playwright-cli' = local dev server verification in isolated browser. 'opencli' = reuses Chrome logged-in session, ideal for verifying bugs related to third-party integrations or OAuth flows."
207
+ },
208
+ "verify_steps": {
209
+ "type": "array",
210
+ "description": "Verification goals describing HOW to reproduce and verify the bug fix (e.g., 'Click login button and verify error message is gone', 'Open dashboard and confirm performance metrics display'). AI decides concrete browser tool actions at runtime. If omitted, AI auto-reproduces from error description.",
211
+ "items": {
212
+ "type": "string"
213
+ }
214
+ }
215
+ }
197
216
  }
198
217
  }
199
218
  }
@@ -241,4 +260,4 @@
241
260
  }
242
261
  }
243
262
  }
244
- }
263
+ }