prizmkit 1.0.58 → 1.0.66

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/adapters/claude/command-adapter.js +1 -2
  3. package/bundled/dev-pipeline/README.md +4 -5
  4. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +23 -17
  5. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +17 -4
  6. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +1 -1
  7. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +8 -11
  8. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +12 -16
  9. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +24 -41
  10. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +26 -38
  11. package/bundled/dev-pipeline/templates/session-status-schema.json +1 -1
  12. package/bundled/dev-pipeline/tests/conftest.py +15 -10
  13. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +168 -0
  14. package/bundled/skills/_metadata.json +1 -1
  15. package/bundled/skills/bug-fix-workflow/SKILL.md +5 -8
  16. package/bundled/skills/bug-planner/SKILL.md +5 -1
  17. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +156 -0
  18. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +3 -3
  19. package/bundled/skills/dev-pipeline-launcher/SKILL.md +1 -1
  20. package/bundled/skills/prizm-kit/SKILL.md +9 -7
  21. package/bundled/skills/prizm-kit/assets/project-memory-template.md +1 -1
  22. package/bundled/skills/prizmkit-analyze/SKILL.md +4 -5
  23. package/bundled/skills/prizmkit-code-review/SKILL.md +10 -2
  24. package/bundled/skills/prizmkit-committer/SKILL.md +1 -1
  25. package/bundled/skills/prizmkit-implement/SKILL.md +13 -3
  26. package/bundled/skills/prizmkit-plan/SKILL.md +17 -6
  27. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +15 -1
  28. package/bundled/skills/prizmkit-retrospective/SKILL.md +1 -1
  29. package/bundled/skills/prizmkit-specify/SKILL.md +8 -4
  30. package/bundled/skills/refactor-workflow/SKILL.md +14 -6
  31. package/bundled/team/prizm-dev-team.json +1 -1
  32. package/package.json +1 -1
  33. package/src/scaffold.js +1 -1
@@ -18,7 +18,7 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
18
18
 
19
19
  **CRITICAL SESSION LIFECYCLE RULE**: You MUST NOT exit until ALL work is complete and session-status.json is written. When you spawn subagents, you MUST **wait for each to finish** (run_in_background=false) before proceeding. Do NOT spawn an agent in the background and exit — that kills the session.
20
20
 
21
- **MANDATORY TEAM REQUIREMENT**: You MUST use the `prizm-dev-team` multi-agent team. This is NON-NEGOTIABLE. All implementation and review work MUST be performed by the appropriate team agents (Dev, Reviewer). You are the orchestrator — handle coordination, planning, and commit phases directly.
21
+ **MANDATORY TEAM REQUIREMENT**: You MUST use the `prizm-dev-team` agents (Dev + Reviewer). This is NON-NEGOTIABLE. All implementation and review work MUST be performed by the appropriate team agents (Dev, Reviewer). You are the orchestrator — handle coordination, planning, and commit phases directly.
22
22
 
23
23
  **BUG FIX DOCUMENTATION POLICY**: Bug fixes MUST NOT be recorded as new documentation entries:
24
24
  - Run `/prizmkit-retrospective` with structural sync only (Job 1) — skip knowledge injection unless a genuinely new TRAP was discovered
@@ -28,8 +28,7 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
28
28
 
29
29
  ### Team Definition Reference
30
30
 
31
- - **Source of truth**: `{{TEAM_CONFIG_PATH}}`
32
- - **Installed team config**: `{{TEAM_CONFIG_PATH}}`
31
+ - **Team config**: `{{TEAM_CONFIG_PATH}}`
33
32
 
34
33
  ### Bug Description
35
34
 
@@ -74,16 +73,11 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
74
73
 
75
74
  ### Step 1: Initialize
76
75
 
77
- #### Team Setup: Reuse or Create
76
+ #### Agent Setup
78
77
 
79
- 1. **Check if a team already exists and can be reused**:
80
- - Read the team config file at `{{TEAM_CONFIG_PATH}}`
81
- - If valid, reuse it. Set `TEAM_REUSED=true`
82
-
83
- 2. **If no reusable team**, create a new one:
84
- - Reference `{{TEAM_CONFIG_PATH}}`
85
- - Call `TeamCreate` with `team_name="prizm-dev-team-{{BUG_ID}}"` and `description="Fixing {{BUG_TITLE}}"`
86
- - Set `TEAM_REUSED=false`
78
+ Reference `{{TEAM_CONFIG_PATH}}` for agent definitions:
79
+ - Dev: `{{DEV_SUBAGENT_PATH}}`
80
+ - Reviewer: `{{REVIEWER_SUBAGENT_PATH}}`
87
81
 
88
82
  3. Create bug fix artifacts directory:
89
83
  ```bash
@@ -96,7 +90,7 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
96
90
 
97
91
  **Goal**: Classify the bug, identify scope and severity, check known issues, produce fix-plan.md.
98
92
 
99
- - Spawn Dev agent (Task tool, subagent_type="prizm-dev-team-dev", run_in_background=false)
93
+ - Spawn Dev agent (Agent tool, subagent_type="prizm-dev-team-dev", run_in_background=false)
100
94
  Prompt: "Read {{DEV_SUBAGENT_PATH}}. For bug {{BUG_ID}} ('{{BUG_TITLE}}'):
101
95
  1. Run `/prizmkit-tool-error-triage` with the bug description and error source
102
96
  2. Check `.prizm-docs/` TRAPS sections for matching known issues
@@ -133,7 +127,7 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
133
127
 
134
128
  **Goal**: Create an automated reproduction that proves the bug exists.
135
129
 
136
- - Spawn Dev agent (Task tool, subagent_type="prizm-dev-team-dev", run_in_background=false)
130
+ - Spawn Dev agent (Agent tool, subagent_type="prizm-dev-team-dev", run_in_background=false)
137
131
  Prompt: "Read {{DEV_SUBAGENT_PATH}}. For bug {{BUG_ID}}:
138
132
  1. Read the fix plan from `.prizmkit/bugfix/{{BUG_ID}}/fix-plan.md`
139
133
  2. Run `/prizmkit-tool-bug-reproducer` with the bug description and triage results
@@ -155,7 +149,7 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
155
149
 
156
150
  **Goal**: Implement the fix. The reproduction test goes from red to green.
157
151
 
158
- - Spawn Dev agent (Task tool, subagent_type="prizm-dev-team-dev", run_in_background=false)
152
+ - Spawn Dev agent (Agent tool, subagent_type="prizm-dev-team-dev", run_in_background=false)
159
153
  Prompt: "Read {{DEV_SUBAGENT_PATH}}. For bug {{BUG_ID}}:
160
154
  1. Read the fix plan from `.prizmkit/bugfix/{{BUG_ID}}/fix-plan.md`
161
155
  2. Read `.prizm-docs/` for affected modules (TRAPS, RULES, PATTERNS)
@@ -177,7 +171,7 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
177
171
 
178
172
  **Goal**: Ensure fix correctness and no regressions.
179
173
 
180
- - Spawn Reviewer agent (Task tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false)
174
+ - Spawn Reviewer agent (Agent tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false)
181
175
  Prompt: "Read {{REVIEWER_SUBAGENT_PATH}}. For bug {{BUG_ID}}:
182
176
  1. Run `/prizmkit-code-review` scoped to CHANGED FILES ONLY
183
177
  2. Review dimensions (adjusted for bug fix):
@@ -206,17 +200,19 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
206
200
 
207
201
  **Goal**: Commit the fix, update TRAPS, generate fix-report.md.
208
202
 
209
- - Spawn Dev agent (Task tool, subagent_type="prizm-dev-team-dev", run_in_background=false)
210
- Prompt: "Read {{DEV_SUBAGENT_PATH}}. For bug {{BUG_ID}}:
211
- 1. Run `/prizmkit-committer` with:
212
- - Commit message: `fix({{FIX_SCOPE}}): {{BUG_TITLE}}`
213
- - Include both fix code and reproduction test
214
- - Do NOT run `/prizmkit-retrospective` with REGISTRY archiving
215
- - Do NOT push (user will push manually)
216
- 2. If a new pitfall was discovered (not previously in TRAPS):
217
- - Update the affected module's TRAPS section in `.prizm-docs/`
218
- - Format: `- TRAP: <description> | FIX: <solution> | DATE: YYYY-MM-DD`
219
- 3. Write the complete fix report to `.prizmkit/bugfix/{{BUG_ID}}/fix-report.md`
203
+ **This phase is executed by YOU (the orchestrator), NOT a subagent.**
204
+
205
+ 1. If a new pitfall was discovered (not previously in TRAPS):
206
+ - Update the affected module's TRAPS section in `.prizm-docs/`
207
+ - Format: `- TRAP: <description> | FIX: <solution> | DATE: YYYY-MM-DD`
208
+
209
+ 2. Run `/prizmkit-committer` with:
210
+ - Commit message: `fix({{FIX_SCOPE}}): {{BUG_TITLE}}`
211
+ - Include both fix code and reproduction test
212
+ - Do NOT run `/prizmkit-retrospective` with REGISTRY archiving
213
+ - Do NOT push (user will push manually)
214
+
215
+ 3. Write the complete fix report to `.prizmkit/bugfix/{{BUG_ID}}/fix-report.md`
220
216
 
221
217
  The fix-report.md MUST contain these sections:
222
218
  - Bug Resolution Summary (ID, title, status, phases completed, duration)
@@ -224,8 +220,7 @@ You are the **bug fix session orchestrator**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}
224
220
  - Verification Results (reproduction test before/after, regression tests, review verdict)
225
221
  - Knowledge Captured (TRAPS updated, prevention recommendation)
226
222
  - Acceptance Criteria Verification (checklist with pass/fail for each criterion)
227
- "
228
- - **Wait for Dev to return**
223
+
229
224
  - **CP-BF-5**: Commit recorded, fix-report.md written, TRAPS updated (if applicable)
230
225
 
231
226
  ### Step 3: Report Session Status
@@ -258,17 +253,11 @@ Write to: `{{SESSION_STATUS_PATH}}`
258
253
 
259
254
  **Status values**: `success` (all phases done) | `partial` (can resume) | `failed` (unrecoverable)
260
255
 
261
- ### Step 4: Team Cleanup (conditional)
262
-
263
- **Only if you CREATED the team** (`TEAM_REUSED=false`), clean up with `TeamDelete`.
264
- **If you REUSED an existing team** (`TEAM_REUSED=true`), do NOT call `TeamDelete`.
265
-
266
256
  ## Critical Paths
267
257
 
268
258
  | Resource | Path |
269
259
  |----------|------|
270
260
  | Team Definition (source of truth) | `{{TEAM_CONFIG_PATH}}` |
271
- | Team Config (installed) | `{{TEAM_CONFIG_PATH}}` |
272
261
  | Bug Fix Artifacts Dir | `.prizmkit/bugfix/{{BUG_ID}}/` |
273
262
  | Fix Plan | `.prizmkit/bugfix/{{BUG_ID}}/fix-plan.md` |
274
263
  | Fix Report | `.prizmkit/bugfix/{{BUG_ID}}/fix-report.md` |
@@ -279,13 +268,12 @@ Write to: `{{SESSION_STATUS_PATH}}`
279
268
 
280
269
  ## Reminders
281
270
 
282
- - **MANDATORY**: Use `prizm-dev-team` — single-agent execution is FORBIDDEN
271
+ - **MANDATORY**: Use `prizm-dev-team` agents — single-agent execution is FORBIDDEN
283
272
  - **Only 2 artifact files per bug**: fix-plan.md + fix-report.md — NEVER more
284
- - **Do NOT create** spec.md, plan.md, or tasks.md for bug fixes
273
+ - **Do NOT create** spec.md or plan.md for bug fixes
285
274
  - **Do NOT run** `/prizmkit-retrospective` knowledge injection for bugs (structural sync only, unless genuinely new TRAP discovered)
286
275
  - **Commit with** `fix(<scope>):` prefix, NOT `feat:`
287
276
  - **Update TRAPS** in `.prizm-docs/` only if a genuinely new pitfall was discovered
288
277
  - Dev agents use TDD approach: reproduction test goes from RED → GREEN
289
278
  - ALWAYS write session-status.json before exiting
290
279
  - Do NOT use `run_in_background=true` when spawning agents
291
- - Only call `TeamDelete` if you created the team
@@ -72,7 +72,7 @@
72
72
  "properties": {
73
73
  "spec_path": { "type": "string" },
74
74
  "plan_path": { "type": "string" },
75
- "tasks_path": { "type": "string" }
75
+ "context_snapshot_path": { "type": "string" }
76
76
  }
77
77
  },
78
78
  "timestamp": {
@@ -9,13 +9,18 @@ import sys
9
9
  _scripts_dir = os.path.join(os.path.dirname(__file__), "..", "scripts")
10
10
  sys.path.insert(0, _scripts_dir)
11
11
 
12
- # generate-bootstrap-prompt.py has a hyphenated filename that Python can't
13
- # import normally. Load it via importlib and register under an underscore name
14
- # so test files can do: `from generate_bootstrap_prompt import ...`
15
- _spec = importlib.util.spec_from_file_location(
16
- "generate_bootstrap_prompt",
17
- os.path.join(_scripts_dir, "generate-bootstrap-prompt.py"),
18
- )
19
- _mod = importlib.util.module_from_spec(_spec)
20
- sys.modules["generate_bootstrap_prompt"] = _mod
21
- _spec.loader.exec_module(_mod)
12
+
13
+ def _load_hyphenated_module(module_name, filename):
14
+ """Load a hyphenated .py file and register it as an importable module."""
15
+ spec = importlib.util.spec_from_file_location(
16
+ module_name,
17
+ os.path.join(_scripts_dir, filename),
18
+ )
19
+ mod = importlib.util.module_from_spec(spec)
20
+ sys.modules[module_name] = mod
21
+ spec.loader.exec_module(mod)
22
+
23
+
24
+ # Register hyphenated script files so tests can import them with underscores.
25
+ _load_hyphenated_module("generate_bootstrap_prompt", "generate-bootstrap-prompt.py")
26
+ _load_hyphenated_module("generate_bugfix_prompt", "generate-bugfix-prompt.py")
@@ -0,0 +1,168 @@
1
+ """Tests for generate-bugfix-prompt.py core functions."""
2
+
3
+ from generate_bugfix_prompt import (
4
+ find_bug,
5
+ format_acceptance_criteria,
6
+ format_global_context,
7
+ format_error_source_details,
8
+ format_environment,
9
+ process_conditional_blocks,
10
+ render_template,
11
+ )
12
+
13
+
14
+ # ---------------------------------------------------------------------------
15
+ # find_bug
16
+ # ---------------------------------------------------------------------------
17
+
18
+ class TestFindBug:
19
+ def test_found(self):
20
+ bugs = [{"id": "B-001", "title": "A"}, {"id": "B-002", "title": "B"}]
21
+ assert find_bug(bugs, "B-002") == {"id": "B-002", "title": "B"}
22
+
23
+ def test_not_found(self):
24
+ assert find_bug([{"id": "B-001"}], "B-999") is None
25
+
26
+ def test_empty_list(self):
27
+ assert find_bug([], "B-001") is None
28
+
29
+ def test_non_dict_items(self):
30
+ assert find_bug(["garbage", 42, None, {"id": "B-001"}], "B-001") == {"id": "B-001"}
31
+
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # format_error_source_details
35
+ # ---------------------------------------------------------------------------
36
+
37
+ class TestFormatErrorSourceDetails:
38
+ def test_none(self):
39
+ result = format_error_source_details(None)
40
+ assert "no error source" in result
41
+
42
+ def test_empty_dict(self):
43
+ result = format_error_source_details({})
44
+ assert "no error source" in result
45
+
46
+ def test_stack_trace(self):
47
+ source = {"type": "stack_trace", "stack_trace": "Error at line 42"}
48
+ result = format_error_source_details(source)
49
+ assert "Error at line 42" in result
50
+ assert "Stack Trace" in result
51
+
52
+ def test_error_message(self):
53
+ source = {"type": "unknown", "error_message": "Something went wrong"}
54
+ result = format_error_source_details(source)
55
+ assert "Something went wrong" in result
56
+
57
+ def test_log_pattern(self):
58
+ source = {"type": "log_pattern", "log_snippet": "FATAL: connection refused"}
59
+ result = format_error_source_details(source)
60
+ assert "connection refused" in result
61
+
62
+ def test_failed_test(self):
63
+ source = {"type": "failed_test", "failed_test_path": "tests/auth.test.js"}
64
+ result = format_error_source_details(source)
65
+ assert "tests/auth.test.js" in result
66
+
67
+ def test_user_report(self):
68
+ source = {"type": "user_report", "reproduction_steps": ["Click login", "Enter bad password"]}
69
+ result = format_error_source_details(source)
70
+ assert "Click login" in result
71
+ assert "Enter bad password" in result
72
+
73
+
74
+ # ---------------------------------------------------------------------------
75
+ # format_environment
76
+ # ---------------------------------------------------------------------------
77
+
78
+ class TestFormatEnvironment:
79
+ def test_none(self):
80
+ assert "not specified" in format_environment(None)
81
+
82
+ def test_empty(self):
83
+ assert "not specified" in format_environment({})
84
+
85
+ def test_with_values(self):
86
+ result = format_environment({"os": "Linux", "node": "20.1"})
87
+ assert "**node**: 20.1" in result
88
+ assert "**os**: Linux" in result
89
+
90
+ def test_skips_empty_values(self):
91
+ result = format_environment({"os": "Linux", "browser": ""})
92
+ assert "**os**: Linux" in result
93
+ assert "browser" not in result
94
+
95
+
96
+ # ---------------------------------------------------------------------------
97
+ # process_conditional_blocks
98
+ # ---------------------------------------------------------------------------
99
+
100
+ class TestProcessConditionalBlocks:
101
+ def test_automated_removes_manual_block(self):
102
+ tpl = "before\n{{IF_VERIFICATION_MANUAL_OR_HYBRID}}\nmanual content\n{{END_IF_VERIFICATION_MANUAL_OR_HYBRID}}\nafter"
103
+ bug = {"verification_type": "automated"}
104
+ result = process_conditional_blocks(tpl, bug)
105
+ assert "manual content" not in result
106
+ assert "before" in result
107
+ assert "after" in result
108
+
109
+ def test_manual_keeps_block(self):
110
+ tpl = "before\n{{IF_VERIFICATION_MANUAL_OR_HYBRID}}\nmanual content\n{{END_IF_VERIFICATION_MANUAL_OR_HYBRID}}\nafter"
111
+ bug = {"verification_type": "manual"}
112
+ result = process_conditional_blocks(tpl, bug)
113
+ assert "manual content" in result
114
+ assert "IF_VERIFICATION" not in result
115
+
116
+ def test_hybrid_keeps_block(self):
117
+ tpl = "{{IF_VERIFICATION_MANUAL_OR_HYBRID}}hybrid{{END_IF_VERIFICATION_MANUAL_OR_HYBRID}}"
118
+ bug = {"verification_type": "hybrid"}
119
+ result = process_conditional_blocks(tpl, bug)
120
+ assert "hybrid" in result
121
+
122
+ def test_default_is_automated(self):
123
+ tpl = "{{IF_VERIFICATION_MANUAL_OR_HYBRID}}content{{END_IF_VERIFICATION_MANUAL_OR_HYBRID}}"
124
+ bug = {}
125
+ result = process_conditional_blocks(tpl, bug)
126
+ assert "content" not in result
127
+
128
+
129
+ # ---------------------------------------------------------------------------
130
+ # render_template (integration)
131
+ # ---------------------------------------------------------------------------
132
+
133
+ class TestRenderTemplate:
134
+ def test_placeholders_replaced(self):
135
+ tpl = "Bug: {{BUG_ID}} — {{BUG_TITLE}}"
136
+ replacements = {"{{BUG_ID}}": "B-042", "{{BUG_TITLE}}": "Login crash"}
137
+ bug = {"verification_type": "automated"}
138
+ result = render_template(tpl, replacements, bug)
139
+ assert result == "Bug: B-042 — Login crash"
140
+
141
+ def test_conditional_and_replacement(self):
142
+ tpl = (
143
+ "{{IF_VERIFICATION_MANUAL_OR_HYBRID}}manual{{END_IF_VERIFICATION_MANUAL_OR_HYBRID}}"
144
+ "id={{BUG_ID}}"
145
+ )
146
+ replacements = {"{{BUG_ID}}": "B-001"}
147
+ bug = {"verification_type": "automated"}
148
+ result = render_template(tpl, replacements, bug)
149
+ assert "manual" not in result
150
+ assert "id=B-001" in result
151
+
152
+
153
+ # ---------------------------------------------------------------------------
154
+ # Reuse shared helpers (same as bootstrap prompt — verify they are present)
155
+ # ---------------------------------------------------------------------------
156
+
157
+ class TestSharedHelpers:
158
+ def test_format_acceptance_criteria_items(self):
159
+ result = format_acceptance_criteria(["Fix works", "No regression"])
160
+ assert "- Fix works" in result
161
+ assert "- No regression" in result
162
+
163
+ def test_format_acceptance_criteria_empty(self):
164
+ assert "none specified" in format_acceptance_criteria([])
165
+
166
+ def test_format_global_context_dict(self):
167
+ result = format_global_context({"lang": "Python"})
168
+ assert "**lang**: Python" in result
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.58",
2
+ "version": "1.0.66",
3
3
  "skills": {
4
4
  "prizm-kit": {
5
5
  "description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
@@ -112,15 +112,13 @@ If the fix causes test regressions:
112
112
 
113
113
  **Goal**: Commit the fix with proper conventions.
114
114
 
115
- 1. **Run `/prizmkit-retrospective`** (Job 1: structural sync only):
116
- - Update `.prizm-docs/` if file structure changed
117
- - Add TRAPS entry only if a genuinely new pitfall was discovered
118
- - Skip knowledge injection for routine bug fixes
119
- 2. **Run `/prizmkit-committer`**:
115
+ 1. **Run `/prizmkit-committer`**:
120
116
  - Commit message: `fix(<scope>): <description>`
121
117
  - Include both fix code and reproduction test
122
118
  - Do NOT push (user decides when to push)
123
- 3. **If bug came from bug-fix-list.json**: inform user to update bug status
119
+ - Do NOT run `/prizmkit-retrospective` bug fixes do not update `.prizm-docs/` (per project rules: "bugs are incomplete features, recording bug details causes doc bloat with no AI value")
120
+ - `/prizmkit-committer` is a pure commit tool — it does NOT modify `.prizm-docs/` or any project files
121
+ 2. **If bug came from bug-fix-list.json**: inform user to update bug status
124
122
  ```
125
123
  Bug B-001 fixed and committed.
126
124
  To update the bug list: manually set B-001 status to "fixed" in bug-fix-list.json
@@ -163,7 +161,7 @@ Only 2 artifact files per bug, consistent with the pipeline convention.
163
161
  | `bug-planner` | **this skill** | User picks one bug to fix interactively |
164
162
  | `bugfix-pipeline-launcher` | **this skill** | User wants to fix a stuck/complex bug manually |
165
163
  | **this skill** | `bugfix-pipeline-launcher` | After fixing, user wants to continue with remaining bugs |
166
- | **this skill** | `prizmkit-retrospective` | Built into Phase 5 (structural sync) |
164
+ | **this skill** | `prizmkit-committer` | Built into Phase 5 (pure commit, no doc sync) |
167
165
 
168
166
  ## Output
169
167
 
@@ -171,4 +169,3 @@ Only 2 artifact files per bug, consistent with the pipeline convention.
171
169
  - `.prizmkit/bugfix/<BUG_ID>/fix-plan.md`
172
170
  - `.prizmkit/bugfix/<BUG_ID>/fix-report.md`
173
171
  - Git commit with `fix(<scope>):` prefix
174
- - Updated `.prizm-docs/` TRAPS (if new pitfall discovered)
@@ -135,7 +135,11 @@ ALERT: Error rate spike: 500 errors/min on /api/login endpoint
135
135
  ### Phase 4: Generate & Validate
136
136
 
137
137
  1. **Generate `bug-fix-list.json`**: Conform to `dev-pipeline/templates/bug-fix-list-schema.json`
138
- 2. **Validate against schema**: Run the validation checks below
138
+ 2. **Validate against schema**: Run the validation script:
139
+ ```bash
140
+ python3 ${SKILL_DIR}/scripts/validate-bug-list.py bug-fix-list.json --feature-list feature-list.json
141
+ ```
142
+ If the script is not available, perform the validation checks manually (see checklist below).
139
143
  3. **Write file** to project root (or user-specified path)
140
144
  4. **Output**: File path, summary, and next steps
141
145
 
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Validate bug-fix-list.json against the PrizmKit bug-fix-list schema.
4
+
5
+ Usage:
6
+ python3 validate-bug-list.py [bug-fix-list.json] [--feature-list feature-list.json]
7
+
8
+ Exit codes:
9
+ 0 = valid
10
+ 1 = validation errors found
11
+ 2 = file not found or JSON parse error
12
+ """
13
+
14
+ import json
15
+ import sys
16
+ import os
17
+ import re
18
+
19
+ VALID_SEVERITIES = {"critical", "high", "medium", "low"}
20
+ VALID_SOURCE_TYPES = {"stack_trace", "user_report", "failed_test", "log_pattern", "monitoring_alert"}
21
+ VALID_VERIFICATION_TYPES = {"automated", "manual", "hybrid"}
22
+ VALID_STATUSES = {"pending", "in_progress", "fixed", "failed", "skipped", "needs_info"}
23
+ BUG_ID_PATTERN = re.compile(r"^B-\d{3}$")
24
+
25
+
26
+ def validate(bug_list_path, feature_list_path=None):
27
+ errors = []
28
+ warnings = []
29
+
30
+ # Load bug-fix-list.json
31
+ try:
32
+ with open(bug_list_path) as f:
33
+ data = json.load(f)
34
+ except FileNotFoundError:
35
+ print(f"ERROR: File not found: {bug_list_path}", file=sys.stderr)
36
+ return 2
37
+ except json.JSONDecodeError as e:
38
+ print(f"ERROR: Invalid JSON in {bug_list_path}: {e}", file=sys.stderr)
39
+ return 2
40
+
41
+ # Load feature-list.json (optional, for cross-reference)
42
+ feature_ids = set()
43
+ if feature_list_path:
44
+ try:
45
+ with open(feature_list_path) as f:
46
+ fl_data = json.load(f)
47
+ feature_ids = {f.get("id") for f in fl_data.get("features", [])}
48
+ except (FileNotFoundError, json.JSONDecodeError):
49
+ warnings.append(f"Could not load feature-list.json at {feature_list_path}")
50
+
51
+ # Top-level required fields
52
+ if "$schema" not in data:
53
+ errors.append("Missing required field: $schema")
54
+ elif data["$schema"] != "dev-pipeline-bug-fix-list-v1":
55
+ errors.append(f"Invalid $schema: expected 'dev-pipeline-bug-fix-list-v1', got '{data['$schema']}'")
56
+
57
+ if not data.get("project_name"):
58
+ errors.append("Missing or empty required field: project_name")
59
+
60
+ bugs = data.get("bugs", [])
61
+ if not bugs:
62
+ errors.append("Missing or empty required field: bugs")
63
+
64
+ # Per-bug validation
65
+ seen_ids = set()
66
+ seen_priorities = set()
67
+
68
+ for i, bug in enumerate(bugs):
69
+ prefix = f"bugs[{i}]"
70
+
71
+ # Required fields
72
+ bug_id = bug.get("id", "")
73
+ if not bug_id:
74
+ errors.append(f"{prefix}: missing required field 'id'")
75
+ elif not BUG_ID_PATTERN.match(bug_id):
76
+ errors.append(f"{prefix}: id '{bug_id}' does not match pattern B-NNN")
77
+
78
+ if bug_id in seen_ids:
79
+ errors.append(f"{prefix}: duplicate bug id '{bug_id}'")
80
+ seen_ids.add(bug_id)
81
+
82
+ if not bug.get("title"):
83
+ errors.append(f"{prefix} ({bug_id}): missing required field 'title'")
84
+
85
+ if not bug.get("description"):
86
+ errors.append(f"{prefix} ({bug_id}): missing required field 'description'")
87
+
88
+ severity = bug.get("severity", "")
89
+ if severity not in VALID_SEVERITIES:
90
+ errors.append(f"{prefix} ({bug_id}): invalid severity '{severity}' — must be one of {VALID_SEVERITIES}")
91
+
92
+ # error_source
93
+ error_source = bug.get("error_source", {})
94
+ source_type = error_source.get("type", "") if isinstance(error_source, dict) else ""
95
+ if source_type not in VALID_SOURCE_TYPES:
96
+ errors.append(f"{prefix} ({bug_id}): invalid error_source.type '{source_type}' — must be one of {VALID_SOURCE_TYPES}")
97
+
98
+ # verification_type
99
+ vtype = bug.get("verification_type", "")
100
+ if vtype not in VALID_VERIFICATION_TYPES:
101
+ errors.append(f"{prefix} ({bug_id}): invalid verification_type '{vtype}' — must be one of {VALID_VERIFICATION_TYPES}")
102
+
103
+ # acceptance_criteria
104
+ ac = bug.get("acceptance_criteria", [])
105
+ if not ac or not isinstance(ac, list):
106
+ errors.append(f"{prefix} ({bug_id}): missing or empty acceptance_criteria array")
107
+
108
+ # status
109
+ status = bug.get("status", "")
110
+ if status not in VALID_STATUSES:
111
+ errors.append(f"{prefix} ({bug_id}): invalid status '{status}' — must be one of {VALID_STATUSES}")
112
+
113
+ # Priority uniqueness
114
+ priority = bug.get("priority")
115
+ if priority is not None:
116
+ if priority in seen_priorities:
117
+ warnings.append(f"{prefix} ({bug_id}): duplicate priority {priority}")
118
+ seen_priorities.add(priority)
119
+
120
+ # Cross-reference affected_feature
121
+ affected_feature = bug.get("affected_feature")
122
+ if affected_feature and feature_ids and affected_feature not in feature_ids:
123
+ warnings.append(f"{prefix} ({bug_id}): affected_feature '{affected_feature}' not found in feature-list.json")
124
+
125
+ # Output results
126
+ if errors:
127
+ print(f"VALIDATION FAILED — {len(errors)} error(s), {len(warnings)} warning(s)\n")
128
+ for e in errors:
129
+ print(f" ERROR: {e}")
130
+ for w in warnings:
131
+ print(f" WARN: {w}")
132
+ return 1
133
+ else:
134
+ bug_count = len(bugs)
135
+ severity_counts = {}
136
+ for b in bugs:
137
+ s = b.get("severity", "unknown")
138
+ severity_counts[s] = severity_counts.get(s, 0) + 1
139
+ sev_str = ", ".join(f"{k}={v}" for k, v in sorted(severity_counts.items()))
140
+ print(f"VALIDATION PASSED — {bug_count} bugs ({sev_str})")
141
+ if warnings:
142
+ for w in warnings:
143
+ print(f" WARN: {w}")
144
+ return 0
145
+
146
+
147
+ if __name__ == "__main__":
148
+ bug_list = sys.argv[1] if len(sys.argv) > 1 else "bug-fix-list.json"
149
+ feature_list = None
150
+
151
+ if "--feature-list" in sys.argv:
152
+ idx = sys.argv.index("--feature-list")
153
+ if idx + 1 < len(sys.argv):
154
+ feature_list = sys.argv[idx + 1]
155
+
156
+ sys.exit(validate(bug_list, feature_list))
@@ -5,11 +5,11 @@ description: "Launch and manage the bugfix pipeline from within an AI CLI sessio
5
5
 
6
6
  # Bugfix-Pipeline Launcher
7
7
 
8
- Launch the autonomous bug fix pipeline from within a cbc conversation. The pipeline runs as a fully detached background process -- closing the cbc session does NOT stop the pipeline.
8
+ Launch the autonomous bug fix pipeline from within an AI CLI conversation. The pipeline runs as a fully detached background process -- closing the AI CLI session does NOT stop the pipeline.
9
9
 
10
10
  ### Execution Mode
11
11
 
12
- Always use daemon mode via `dev-pipeline/launch-bugfix-daemon.sh` for start/stop/status/log actions. Foreground `run-bugfix.sh` can be terminated by AI CLI command timeout (e.g. cbc 120s), while daemon mode survives session timeout — this prevents half-finished bug fixes that leave the codebase in an inconsistent state.
12
+ Always use daemon mode via `dev-pipeline/launch-bugfix-daemon.sh` for start/stop/status/log actions. Foreground `run-bugfix.sh` can be terminated by AI CLI command timeout, while daemon mode survives session timeout — this prevents half-finished bug fixes that leave the codebase in an inconsistent state.
13
13
 
14
14
  ### When to Use
15
15
 
@@ -246,7 +246,7 @@ SESSION_TIMEOUT=3600 dev-pipeline/retry-bug.sh B-001 bug-fix-list.json
246
246
  ### Integration Notes
247
247
 
248
248
  - **After bug-planner**: This is the natural next step. When user finishes bug planning and has `bug-fix-list.json`, suggest launching the bugfix pipeline.
249
- - **Session independence**: The bugfix pipeline runs completely detached. User can close cbc, open a new session later, and use this skill to check progress or stop the pipeline.
249
+ - **Session independence**: The bugfix pipeline runs completely detached. User can close the AI CLI, open a new session later, and use this skill to check progress or stop the pipeline.
250
250
  - **Single instance**: Only one bugfix pipeline can run at a time. The PID file prevents duplicates.
251
251
  - **Feature pipeline coexistence**: Bugfix and feature pipelines use separate state directories (`bugfix-state/` vs `state/`), so they can run simultaneously without conflict.
252
252
  - **State preservation**: Stopping and restarting the bugfix pipeline resumes from where it left off -- completed bugs are not re-fixed.
@@ -9,7 +9,7 @@ Launch the autonomous development pipeline from within an AI CLI conversation. T
9
9
 
10
10
  ### Execution Mode
11
11
 
12
- Always use daemon mode via `dev-pipeline/launch-daemon.sh` for start/stop/status/log actions. Foreground `run.sh` can be terminated by AI CLI command timeout (e.g. cbc 120s, claude may vary), while daemon mode survives session timeout — this prevents half-finished features that leave the codebase in an inconsistent state.
12
+ Always use daemon mode via `dev-pipeline/launch-daemon.sh` for start/stop/status/log actions. Foreground `run.sh` can be terminated by AI CLI session timeout, while daemon mode survives session closure — this prevents half-finished features that leave the codebase in an inconsistent state.
13
13
 
14
14
  ### When to Use
15
15
 
@@ -27,16 +27,16 @@ PrizmKit is a comprehensive, independent AI development toolkit that covers the
27
27
 
28
28
  The full workflow generates spec, plan, and task artifacts that create a traceable record of what was built and why — this matters for future maintainability and AI context loading.
29
29
 
30
- **Use fast path (implement -> commit directly):**
30
+ **Use fast path (plan → implement commit):**
31
31
  - Bug fixes with clear root cause
32
32
  - Single-file config or typo fixes
33
33
  - Simple refactors (rename, extract)
34
34
  - Documentation-only changes
35
35
  - Test additions for existing code
36
36
 
37
- The fast path skips artifact generation because these changes don't introduce new concepts that future sessions need to understand.
37
+ The fast path skips specify and analyze but still generates a simplified plan.md (with Tasks section) so that implement has a task list to follow.
38
38
 
39
- For fast-path changes, you can directly use the implement command with inline task description, then the commit command.
39
+ For fast-path changes, you can directly generate a simplified plan.md, then use implement and commit commands.
40
40
 
41
41
  ## Workflow Example
42
42
 
@@ -47,17 +47,19 @@ For fast-path changes, you can directly use the implement command with inline ta
47
47
  /prizmkit-analyze → checks spec↔plan consistency, finds gaps
48
48
  /prizmkit-implement → executes tasks in order, marks [x] as done
49
49
  /prizmkit-code-review → reviews against spec, outputs PASS/NEEDS FIXES
50
- /prizmkit-committer updates .prizm-docs/, commits feat(avatar): add upload
50
+ /prizmkit-retrospective syncs .prizm-docs/ with code changes
51
+ /prizmkit-committer → commits feat(avatar): add upload
51
52
  ```
52
53
 
53
54
  **Fast path** for fixing a null pointer bug:
54
55
  ```
55
- /prizmkit-implement → "fix null check in UserService.getAvatar()"
56
+ /prizmkit-plan → "fix null check in UserService.getAvatar()" (simplified plan.md)
57
+ /prizmkit-implement → executes tasks from plan.md
56
58
  /prizmkit-committer → commits fix(user): handle null avatar gracefully
57
59
  ```
58
60
 
59
61
  ### Fast Path Commands
60
- `/prizmkit-implement` → `/prizmkit-committer`
62
+ `/prizmkit-plan` → `/prizmkit-implement` → `/prizmkit-committer`
61
63
 
62
64
  ### Bug Fix Documentation Policy
63
65
 
@@ -140,7 +142,7 @@ Not sure which skill to use? Follow this:
140
142
  | Fix one specific bug right now, interactively | `bug-fix-workflow` |
141
143
  | Refactor/restructure code without changing behavior | `refactor-workflow` |
142
144
  | Add a single small feature (spec → plan → implement) | `/prizmkit-specify` → `/prizmkit-plan` → `/prizmkit-implement` |
143
- | Quick bug fix or config change | Fast path: `/prizmkit-implement` → `/prizmkit-committer` |
145
+ | Quick bug fix or config change | Fast path: `/prizmkit-plan` → `/prizmkit-implement` → `/prizmkit-committer` |
144
146
 
145
147
  ### Tier Definitions
146
148