prizmkit 1.1.127 → 1.1.129

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 (50) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/claude/command-adapter.js +2 -75
  3. package/bundled/dev-pipeline/assets/skill-subagent-integration.md +14 -11
  4. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +88 -58
  5. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +4 -3
  6. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +53 -1
  7. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +33 -17
  8. package/bundled/dev-pipeline/prizmkit_runtime/runtime_helper.py +0 -1
  9. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +28 -26
  10. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +1 -1
  11. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +4 -3
  12. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +1 -1
  13. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +3 -3
  14. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +2 -2
  15. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +22 -21
  16. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +4 -4
  17. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +5 -5
  18. package/bundled/dev-pipeline/templates/sections/bugfix-mission.md +1 -1
  19. package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +11 -4
  20. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +1 -1
  21. package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +3 -2
  22. package/bundled/dev-pipeline/templates/sections/directory-convention-full.md +3 -2
  23. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +1 -1
  24. package/bundled/dev-pipeline/templates/sections/phase-commit.md +1 -1
  25. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +1 -1
  26. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +1 -1
  27. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +12 -5
  28. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +12 -5
  29. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +1 -1
  30. package/bundled/dev-pipeline/templates/sections/phase0-init.md +1 -1
  31. package/bundled/dev-pipeline/templates/sections/refactor-mission.md +1 -1
  32. package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +13 -6
  33. package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +1 -1
  34. package/bundled/dev-pipeline/templates/sections/subagent-timeout-recovery.md +6 -4
  35. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +1 -1
  36. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +106 -7
  37. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +139 -11
  38. package/bundled/dev-pipeline/tests/test_runtime_helper.py +9 -3
  39. package/bundled/dev-pipeline/tests/test_unified_cli.py +225 -24
  40. package/bundled/skills/_metadata.json +3 -3
  41. package/bundled/skills/feature-planner/SKILL.md +2 -2
  42. package/bundled/skills/prizmkit/SKILL.md +1 -1
  43. package/bundled/skills/prizmkit-code-review/SKILL.md +63 -122
  44. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +9 -36
  45. package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +21 -111
  46. package/package.json +1 -1
  47. package/src/manifest.js +8 -3
  48. package/src/scaffold.js +5 -16
  49. package/bundled/skills/prizmkit-code-review/assets/reviewer-role.json +0 -19
  50. package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -120
@@ -16,17 +16,6 @@ Within that execution, append sections only. Never edit or replace an earlier pr
16
16
 
17
17
  ## Progress Sections
18
18
 
19
- ### Risk Assessment
20
-
21
- ```markdown
22
- ## Risk Assessment
23
-
24
- - Risk: <low|medium|high>
25
- - Independent Reviewer Limit: <0|1|2>
26
- - Reasons:
27
- - <concrete behavioral reason>
28
- ```
29
-
30
19
  ### Main-Agent Review Round
31
20
 
32
21
  ```markdown
@@ -36,6 +25,7 @@ Within that execution, append sections only. Never edit or replace an earlier pr
36
25
  - Findings: <count>
37
26
  - Accepted: <count>
38
27
  - Rejected: <count>
28
+ - Unresolved: <count>
39
29
  - Next: <next action>
40
30
  ```
41
31
 
@@ -44,34 +34,18 @@ Within that execution, append sections only. Never edit or replace an earlier pr
44
34
  ```markdown
45
35
  ## Repair Verification
46
36
 
47
- - Source: <main|reviewer-1|reviewer-2>
48
37
  - Fixed Findings: <count>
49
38
  - Verification: <evidence summary>
50
39
  - Next: <next action>
51
40
  ```
52
41
 
53
- ### Independent Reviewer Running
54
-
55
- ```markdown
56
- ## Independent Reviewer <N>
57
-
58
- - Status: RUNNING
59
- - Risk Trigger: <medium|high>
60
- - Attempt: <1|2>
61
- ```
62
-
63
- ### Independent Reviewer Result
42
+ ### Final Verification
64
43
 
65
44
  ```markdown
66
- ## Independent Reviewer <N> Result
45
+ ## Final Verification
67
46
 
68
- - Status: <COMPLETED|BLOCKED>
69
- - Result: <PASS|FINDINGS|BLOCKED>
70
- - Findings: <count>
71
- - Accepted: <count>
72
- - Rejected: <count>
73
- - Accepted High: <count>
74
- - Next: <next action>
47
+ - Status: <COMPLETED|FAILED>
48
+ - Evidence: <evidence summary>
75
49
  ```
76
50
 
77
51
  ## Final Result
@@ -81,10 +55,8 @@ Exactly one Final Result terminates a completed execution:
81
55
  ```markdown
82
56
  ## Final Result
83
57
 
84
- - Verdict: <PASS|NEEDS_FIXES|BLOCKED>
85
- - Risk: <low|medium|high>
58
+ - Verdict: <PASS | NEEDS_FIXES>
86
59
  - Main Review Rounds: <count>
87
- - Independent Reviewers Started: <count>
88
60
  - Accepted Findings: <count>
89
61
  - Fixed Findings: <count>
90
62
  - Rejected Findings: <count>
@@ -96,8 +68,9 @@ Exactly one Final Result terminates a completed execution:
96
68
 
97
69
  - Start of a new execution removes stale progress and terminal results from prior executions.
98
70
  - A phase appends its result before the next phase starts.
99
- - Append RUNNING before each independent Reviewer launch or retry.
100
- - Do not modify a RUNNING section after completion; append its Result section.
71
+ - Finding counts satisfy `accepted + rejected + unresolved = findings`.
72
+ - `PASS` requires every accepted finding fixed and zero unresolved findings.
73
+ - `NEEDS_FIXES` requires at least one unfixed accepted or unresolved finding.
101
74
  - An IN_PROGRESS report without Final Result is incomplete.
102
75
  - Generic or incidental verdict text outside the last Final Result does not prove completion.
103
76
  - Do not append any section after Final Result.
@@ -9,15 +9,10 @@ import sys
9
9
  from pathlib import Path
10
10
  from typing import Any
11
11
 
12
- VERDICTS = {"PASS", "NEEDS_FIXES", "BLOCKED"}
13
- RISKS = {"low", "medium", "high"}
12
+ VERDICTS = {"PASS", "NEEDS_FIXES"}
14
13
  EVENTS = {
15
- "risk-assessment",
16
14
  "main-review-round",
17
15
  "repair-verification",
18
- "reviewer-running",
19
- "reviewer-result",
20
- "infrastructure-failure",
21
16
  "final-verification",
22
17
  }
23
18
  FINAL_HEADING = "## Final Result"
@@ -49,13 +44,6 @@ def _require_count(data: dict[str, Any], name: str, *, maximum: int | None = Non
49
44
  return value
50
45
 
51
46
 
52
- def _require_risk(data: dict[str, Any]) -> str:
53
- risk = data.get("risk")
54
- if risk not in RISKS:
55
- raise ReportStateError(f"risk has invalid value: {risk!r}")
56
- return risk
57
-
58
-
59
47
  def _report_text(path: Path) -> str:
60
48
  try:
61
49
  return path.read_text(encoding="utf-8")
@@ -87,24 +75,6 @@ def _render_event(data: dict[str, Any]) -> str:
87
75
  if event not in EVENTS:
88
76
  raise ReportStateError(f"event has invalid value: {event!r}")
89
77
 
90
- if event == "risk-assessment":
91
- risk = _require_risk(data)
92
- reasons = data.get("reasons")
93
- if not isinstance(reasons, list) or not reasons or not all(
94
- isinstance(reason, str) and reason.strip() for reason in reasons
95
- ):
96
- raise ReportStateError("reasons must be a non-empty string array")
97
- limit = {"low": 0, "medium": 1, "high": 2}[risk]
98
- lines = [
99
- "## Risk Assessment",
100
- "",
101
- f"- Risk: {risk}",
102
- f"- Independent Reviewer Limit: {limit}",
103
- "- Reasons:",
104
- ]
105
- lines.extend(f" - {reason.strip()}" for reason in reasons)
106
- return "\n".join(lines)
107
-
108
78
  if event == "main-review-round":
109
79
  round_number = _require_count(data, "round", maximum=10)
110
80
  if round_number < 1:
@@ -112,8 +82,11 @@ def _render_event(data: dict[str, Any]) -> str:
112
82
  findings = _require_count(data, "findings")
113
83
  accepted = _require_count(data, "accepted")
114
84
  rejected = _require_count(data, "rejected")
115
- if accepted + rejected != findings:
116
- raise ReportStateError("accepted + rejected must equal findings")
85
+ unresolved = _require_count(data, "unresolved")
86
+ if accepted + rejected + unresolved != findings:
87
+ raise ReportStateError(
88
+ "accepted + rejected + unresolved must equal findings"
89
+ )
117
90
  return "\n".join(
118
91
  [
119
92
  f"## Main Review Round {round_number}",
@@ -122,93 +95,30 @@ def _render_event(data: dict[str, Any]) -> str:
122
95
  f"- Findings: {findings}",
123
96
  f"- Accepted: {accepted}",
124
97
  f"- Rejected: {rejected}",
98
+ f"- Unresolved: {unresolved}",
125
99
  f"- Next: {_require_text(data, 'next')}",
126
100
  ]
127
101
  )
128
102
 
129
103
  if event == "repair-verification":
130
- source = _require_text(data, "source")
131
- if source not in {"main", "reviewer-1", "reviewer-2"}:
132
- raise ReportStateError(f"source has invalid value: {source!r}")
133
104
  return "\n".join(
134
105
  [
135
106
  "## Repair Verification",
136
107
  "",
137
- f"- Source: {source}",
138
108
  f"- Fixed Findings: {_require_count(data, 'fixed_findings')}",
139
109
  f"- Verification: {_require_text(data, 'verification')}",
140
110
  f"- Next: {_require_text(data, 'next')}",
141
111
  ]
142
112
  )
143
113
 
144
- if event == "reviewer-running":
145
- reviewer = _require_count(data, "reviewer", maximum=2)
146
- if reviewer < 1:
147
- raise ReportStateError("reviewer must be 1 or 2")
148
- risk = _require_risk(data)
149
- if risk == "low" or (risk == "medium" and reviewer == 2):
150
- raise ReportStateError("reviewer exceeds the semantic risk limit")
151
- attempt = data.get("attempt", 1)
152
- if attempt not in {1, 2}:
153
- raise ReportStateError("attempt must be 1 or 2")
154
- return "\n".join(
155
- [
156
- f"## Independent Reviewer {reviewer}",
157
- "",
158
- "- Status: RUNNING",
159
- f"- Risk Trigger: {risk}",
160
- f"- Attempt: {attempt}",
161
- ]
162
- )
163
-
164
- if event == "reviewer-result":
165
- reviewer = _require_count(data, "reviewer", maximum=2)
166
- if reviewer < 1:
167
- raise ReportStateError("reviewer must be 1 or 2")
168
- result = data.get("result")
169
- if result not in {"PASS", "FINDINGS", "BLOCKED"}:
170
- raise ReportStateError(f"result has invalid value: {result!r}")
171
- findings = _require_count(data, "findings")
172
- accepted = _require_count(data, "accepted")
173
- rejected = _require_count(data, "rejected")
174
- accepted_high = _require_count(data, "accepted_high")
175
- if accepted + rejected != findings or accepted_high > accepted:
176
- raise ReportStateError("reviewer finding counts are inconsistent")
177
- status = "BLOCKED" if result == "BLOCKED" else "COMPLETED"
178
- return "\n".join(
179
- [
180
- f"## Independent Reviewer {reviewer} Result",
181
- "",
182
- f"- Status: {status}",
183
- f"- Result: {result}",
184
- f"- Findings: {findings}",
185
- f"- Accepted: {accepted}",
186
- f"- Rejected: {rejected}",
187
- f"- Accepted High: {accepted_high}",
188
- f"- Next: {_require_text(data, 'next')}",
189
- ]
190
- )
191
-
192
- if event == "infrastructure-failure":
193
- reviewer = _require_count(data, "reviewer", maximum=2)
194
- attempt = _require_count(data, "attempt", maximum=2)
195
- if reviewer < 1 or attempt < 1:
196
- raise ReportStateError("reviewer and attempt must be at least 1")
197
- return "\n".join(
198
- [
199
- f"## Independent Reviewer {reviewer} Infrastructure Failure",
200
- "",
201
- f"- Attempt: {attempt}",
202
- f"- Evidence: {_require_text(data, 'evidence')}",
203
- f"- Next: {_require_text(data, 'next')}",
204
- ]
205
- )
206
-
114
+ status = _require_text(data, "status")
115
+ if status not in {"COMPLETED", "FAILED"}:
116
+ raise ReportStateError(f"status has invalid value: {status!r}")
207
117
  return "\n".join(
208
118
  [
209
119
  "## Final Verification",
210
120
  "",
211
- f"- Status: {_require_text(data, 'status')}",
121
+ f"- Status: {status}",
212
122
  f"- Evidence: {_require_text(data, 'evidence')}",
213
123
  ]
214
124
  )
@@ -227,28 +137,28 @@ def append_final_result(path: Path, data: Any) -> None:
227
137
  verdict = valid.get("verdict")
228
138
  if verdict not in VERDICTS:
229
139
  raise ReportStateError(f"verdict has invalid value: {verdict!r}")
230
- risk = _require_risk(valid)
231
140
  main_rounds = _require_count(valid, "main_review_rounds", maximum=10)
232
- reviewers = _require_count(valid, "independent_reviewers_started", maximum=2)
233
- if reviewers > {"low": 0, "medium": 1, "high": 2}[risk]:
234
- raise ReportStateError("independent_reviewers_started exceeds risk limit")
235
141
  accepted = _require_count(valid, "accepted_findings")
236
142
  fixed = _require_count(valid, "fixed_findings")
237
143
  rejected = _require_count(valid, "rejected_findings")
238
144
  unresolved = _require_count(valid, "unresolved_findings")
239
- if verdict == "PASS" and unresolved:
240
- raise ReportStateError("PASS cannot contain unresolved findings")
241
- if verdict == "NEEDS_FIXES" and not unresolved:
242
- raise ReportStateError("NEEDS_FIXES requires unresolved findings")
145
+ if fixed > accepted:
146
+ raise ReportStateError("fixed_findings cannot exceed accepted_findings")
147
+ if verdict == "PASS" and (unresolved or fixed != accepted):
148
+ raise ReportStateError(
149
+ "PASS requires every accepted finding fixed and no unresolved findings"
150
+ )
151
+ if verdict == "NEEDS_FIXES" and not unresolved and fixed == accepted:
152
+ raise ReportStateError(
153
+ "NEEDS_FIXES requires an unfixed accepted or unresolved finding"
154
+ )
243
155
 
244
156
  section = "\n".join(
245
157
  [
246
158
  FINAL_HEADING,
247
159
  "",
248
160
  f"- Verdict: {verdict}",
249
- f"- Risk: {risk}",
250
161
  f"- Main Review Rounds: {main_rounds}",
251
- f"- Independent Reviewers Started: {reviewers}",
252
162
  f"- Accepted Findings: {accepted}",
253
163
  f"- Fixed Findings: {fixed}",
254
164
  f"- Rejected Findings: {rejected}",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.127",
3
+ "version": "1.1.129",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/manifest.js CHANGED
@@ -19,6 +19,7 @@ const MANIFEST_DIR = '.prizmkit';
19
19
  * Read the manifest from a project directory.
20
20
  * @param {string} projectRoot
21
21
  * @returns {Promise<Object|null>} parsed manifest or null if not found
22
+ * @throws {Error} when a present manifest cannot be read or parsed
22
23
  */
23
24
  export async function readManifest(projectRoot) {
24
25
  const manifestPath = path.join(projectRoot, MANIFEST_DIR, MANIFEST_FILE);
@@ -26,9 +27,13 @@ export async function readManifest(projectRoot) {
26
27
  return null;
27
28
  }
28
29
  try {
29
- return await fs.readJSON(manifestPath);
30
- } catch {
31
- return null;
30
+ const manifest = await fs.readJSON(manifestPath);
31
+ if (manifest === null || Array.isArray(manifest) || typeof manifest !== 'object') {
32
+ throw new TypeError('manifest root must be a JSON object');
33
+ }
34
+ return manifest;
35
+ } catch (error) {
36
+ throw new Error(`Failed to read PrizmKit manifest at ${manifestPath}: ${error.message}`, { cause: error });
32
37
  }
33
38
  }
34
39
 
package/src/scaffold.js CHANGED
@@ -81,6 +81,7 @@ const RETIRED_POWERSHELL_RUNTIME_FILES = new Set([
81
81
  'lib/heartbeat.ps1',
82
82
  ]);
83
83
  const LEGACY_TEAM_NAME = ['prizm', 'dev', 'team'].join('-');
84
+ const RETIRED_CODE_REVIEW_AGENT_BASENAME = 'prizmkit-code-reviewer';
84
85
  const LEGACY_AGENT_BASENAMES = [
85
86
  `${LEGACY_TEAM_NAME}-dev`,
86
87
  `${LEGACY_TEAM_NAME}-reviewer`,
@@ -102,7 +103,10 @@ export async function removeRetiredAgentTeamArtifacts(platform, projectRoot, dry
102
103
  : path.join(projectRoot, '.codebuddy', 'agents');
103
104
  const agentExtensions = platform === 'codex' ? ['.toml', '.md'] : ['.md'];
104
105
 
105
- for (const basename of LEGACY_AGENT_BASENAMES) {
106
+ const retiredBasenames = platform === 'claude'
107
+ ? [...LEGACY_AGENT_BASENAMES, RETIRED_CODE_REVIEW_AGENT_BASENAME]
108
+ : LEGACY_AGENT_BASENAMES;
109
+ for (const basename of retiredBasenames) {
106
110
  for (const extension of agentExtensions) {
107
111
  const filePath = path.join(agentDir, `${basename}${extension}`);
108
112
  if (!await fs.pathExists(filePath)) continue;
@@ -226,12 +230,10 @@ export async function installSkills(platform, skills, projectRoot, dryRun, runti
226
230
 
227
231
  // Load Claude command adapter for skill conversion
228
232
  let convertSkillToCommand;
229
- let getClaudeSkillAgentDefinitions;
230
233
  let convertSkillToCodex;
231
234
  if (platform === 'claude') {
232
235
  const commandAdapter = await loadAdapter('claude', 'command-adapter.js');
233
236
  convertSkillToCommand = commandAdapter.convertSkillToCommand;
234
- getClaudeSkillAgentDefinitions = commandAdapter.getClaudeSkillAgentDefinitions;
235
237
  } else if (platform === 'codex') {
236
238
  const codexSkillAdapter = await loadAdapter('codex', 'skill-adapter.js');
237
239
  convertSkillToCodex = codexSkillAdapter.convertSkill;
@@ -323,19 +325,6 @@ export async function installSkills(platform, skills, projectRoot, dryRun, runti
323
325
  await fs.copy(path.join(corePath, subdir), path.join(assetTargetDir, subdir));
324
326
  }
325
327
  }
326
-
327
- const roleManifestPath = path.join(corePath, 'assets', 'reviewer-role.json');
328
- const roleManifest = await fs.pathExists(roleManifestPath)
329
- ? await fs.readJson(roleManifestPath)
330
- : null;
331
- const agentDefinitions = getClaudeSkillAgentDefinitions(skillName, roleManifest);
332
- if (agentDefinitions.length > 0) {
333
- const agentsDir = path.join(projectRoot, '.claude', 'agents');
334
- await fs.ensureDir(agentsDir);
335
- for (const definition of agentDefinitions) {
336
- await fs.writeFile(path.join(agentsDir, definition.fileName), definition.content);
337
- }
338
- }
339
328
  console.log(chalk.green(` ✓ .claude/commands/${skillName}.md`));
340
329
  } else if (platform === 'codex') {
341
330
  const content = await fs.readFile(skillMdPath, 'utf8');
@@ -1,19 +0,0 @@
1
- {
2
- "protocol_version": 2,
3
- "role_name": "prizmkit-code-reviewer",
4
- "description": "Use only as the one fresh independent read-only Reviewer for a completed /prizmkit-code-review round.",
5
- "observational_capabilities": [
6
- "read-files",
7
- "search-content",
8
- "search-paths"
9
- ],
10
- "unavailable_capabilities": [
11
- "workspace-mutation",
12
- "shell-execution",
13
- "downstream-execution-creation",
14
- "delegation-equivalent-behavior",
15
- "orchestration-reentry",
16
- "skill-invocation"
17
- ],
18
- "execution_mode": "foreground-independent-review"
19
- }
@@ -1,120 +0,0 @@
1
- # Reviewer Prompt Contract
2
-
3
- Use this complete template for every Reviewer execution. Fill the documented placeholders with current-round context. Do not include previous-round findings, verdicts, filtering decisions, rejection reasons, or repair explanations.
4
-
5
- ```text
6
- You are the sole independent read-only Reviewer for this round of `/prizmkit-code-review`.
7
-
8
- ## Execution Boundary
9
-
10
- Perform the complete review yourself.
11
-
12
- Do not create, schedule, resume, continue, request, or coordinate any separate downstream execution unit. Do not re-enter orchestration, invoke a skill, delegate review work, or ask the Main Agent to create a helper.
13
-
14
- Do not modify, create, delete, rename, stage, or commit workspace files. Use only read-only inspection capabilities.
15
-
16
- If you cannot complete the review in this execution context, return `BLOCKED` with the missing capability or context. Do not delegate and do not return a partial `PASS`.
17
-
18
- ## Independent Input Boundary
19
-
20
- Review only the current state supplied below. No previous-round findings, verdicts, filtering decisions, rejection reasons, repair descriptions, or Reviewer reasoning are part of your input.
21
-
22
- ## Goals and Acceptance Criteria
23
-
24
- {goals and acceptance criteria from spec.md, or "No spec artifact found; infer the requested behavior from the user goal and current change."}
25
-
26
- ## Plan and Intended Change
27
-
28
- {relevant architecture decisions and completed tasks from plan.md, or a concise current task description}
29
-
30
- ## Applicable Rules and Contracts
31
-
32
- {relevant Prizm docs, project rules, public and internal contracts, or "No additional project rules identified."}
33
-
34
- ## Test Evidence
35
-
36
- {current scoped test evidence, or "No scoped test report found."}
37
-
38
- ## Current Change
39
-
40
- - Repository and Reviewer-visible checkout: {path or platform-visible location}
41
- - Base revision: {base revision when known}
42
- - Changed paths and states: {staged, unstaged, untracked, deleted, and renamed inventory}
43
- - Review access: {active checkout, or forced worktree used only for baseline and surrounding context}
44
-
45
- ## Supplied Git Diff
46
-
47
- ### Staged
48
-
49
- {complete staged diff, or "No staged changes."}
50
-
51
- ### Unstaged
52
-
53
- {complete unstaged diff, or "No unstaged tracked changes."}
54
-
55
- ## Supplied Untracked Files
56
-
57
- {path and full content of every untracked file, or "No untracked files."}
58
-
59
- Treat the supplied diffs, path states, and untracked file contents as the authoritative current change. Use read-only file inspection for targeted surrounding context, callers, dependents, contracts, and tests. Do not depend on shell or Git execution being available.
60
-
61
- If a platform-forced worktree does not contain the active checkout's dirty or untracked changes, use the worktree only for baseline and surrounding-context reads. You are not required to calculate hashes or prove equivalence between physical checkouts. If an essential changed file or diff is missing from the supplied input, return `BLOCKED` and identify exactly what is missing.
62
-
63
- ## Complete Current-Change Review
64
-
65
- Review the complete current change independently. Do not limit inspection to one file or one suspected issue.
66
-
67
- Evaluate applicable dimensions:
68
-
69
- 1. Requirement and acceptance-criteria alignment
70
- 2. Implementation completeness
71
- 3. Correctness and concrete failure scenarios
72
- 4. Error handling
73
- 5. Security and authorization
74
- 6. Data integrity
75
- 7. Transaction and concurrency behavior
76
- 8. Public and internal contracts
77
- 9. Backward compatibility and regression risks
78
- 10. Test adequacy and evidence compatibility
79
- 11. Project-rule compliance
80
-
81
- Use both directions in this review:
82
-
83
- - Code-forward: changed code → affected symbols → callers and dependents → concrete failure scenarios
84
- - Requirement-backward: requirements and contracts → required behavior → implementation path → side effects → test evidence
85
-
86
- Read unchanged callers, dependents, shared patterns, or tests when needed. Prefer targeted read-only inspection. Do not perform a broad repository scan without a concrete cross-cutting reason.
87
-
88
- ## Finding Standard
89
-
90
- Report every concrete defect you find, including low-severity issues. Exclude pure style preferences and speculative concerns that lack a concrete wrong behavior, contract violation, regression path, security weakness, data-integrity risk, or misleading test result.
91
-
92
- ## Output Contract
93
-
94
- Respond with exactly this structure:
95
-
96
- ### Result: PASS | FINDINGS | BLOCKED
97
-
98
- ### Findings
99
-
100
- If the result is `PASS`, write:
101
-
102
- No issues found.
103
-
104
- If the result is `BLOCKED`, write only the missing capability or essential context and the required action.
105
-
106
- If the result is `FINDINGS`, repeat this block for every concrete issue:
107
-
108
- #### Finding N: <short title>
109
- - Severity: high | medium | low
110
- - Location: filepath:line (or "project-level")
111
- - Problem: concrete wrong behavior and why it matters
112
- - Failure scenario: inputs or state that produce the wrong result
113
- - Reasoning: concise evidence connecting the current code to the failure
114
- - Suggested repair: smallest safe repair approach
115
- - Verification: how to prove the repair
116
-
117
- ### Summary
118
-
119
- One or two sentences describing the current change and result. Do not expose private reasoning traces.
120
- ```