prizmkit 1.1.124 → 1.1.125

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 (24) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/claude/command-adapter.js +4 -6
  3. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +3 -4
  4. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
  5. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +4 -3
  6. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +4 -3
  7. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +7 -2
  8. package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +5 -4
  9. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +4 -4
  10. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +5 -4
  11. package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +6 -5
  12. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +2 -1
  13. package/bundled/dev-pipeline/tests/test_unified_cli.py +16 -10
  14. package/bundled/skills/_metadata.json +4 -4
  15. package/bundled/skills/prizmkit-code-review/SKILL.md +90 -96
  16. package/bundled/skills/prizmkit-code-review/assets/reviewer-role.json +3 -5
  17. package/bundled/skills/prizmkit-code-review/references/review-report-template.md +18 -31
  18. package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +44 -62
  19. package/bundled/skills/prizmkit-code-review/scripts/render_review_report.py +86 -112
  20. package/package.json +1 -1
  21. package/bundled/skills/prizmkit-code-review/references/reviewer-execution-protocol.md +0 -179
  22. package/bundled/skills/prizmkit-code-review/references/reviewer-workspace-protocol.md +0 -118
  23. package/bundled/skills/prizmkit-code-review/scripts/check_loop.py +0 -380
  24. package/bundled/skills/prizmkit-code-review/scripts/workspace_snapshot.py +0 -222
@@ -1,7 +1,7 @@
1
1
  {
2
- "protocol_version": 1,
2
+ "protocol_version": 2,
3
3
  "role_name": "prizmkit-code-reviewer",
4
- "description": "Use only as the single fresh independent Reviewer launched by /prizmkit-code-review after its strict preflight gate authorizes the round.",
4
+ "description": "Use only as the one fresh independent read-only Reviewer for a completed /prizmkit-code-review round.",
5
5
  "observational_capabilities": [
6
6
  "read-files",
7
7
  "search-content",
@@ -15,7 +15,5 @@
15
15
  "orchestration-reentry",
16
16
  "skill-invocation"
17
17
  ],
18
- "execution_mode": "foreground-single-authority",
19
- "max_descendant_execution_units": 0,
20
- "max_delegation_depth": 0
18
+ "execution_mode": "foreground-independent-review"
21
19
  }
@@ -1,53 +1,40 @@
1
1
  # Review Report Output Template
2
2
 
3
- Use this template to render `{artifact_dir}/review-report.md` from the persisted structured result. Report regeneration must not rerun Reviewer execution.
3
+ Write the final result to `{artifact_dir}/review-report.md`. This is the only required persisted review artifact.
4
4
 
5
5
  ```markdown
6
6
  # Review Report
7
7
 
8
- ## Verdict: <PASS|NEEDS_FIXES>
8
+ ## Verdict: <PASS|NEEDS_FIXES|BLOCKED>
9
9
  ## Rounds Completed: <number>
10
- ## Reviewers Started: <number>
11
- ## Review Mode: <independent-reviewer-verified-snapshot|not-run-no-changes>
12
- ## Reviewer Strategy: <semantic strategy summary|not-applicable>
13
- ## Execution Protocol: <COMPLIANT|BLOCKED|VIOLATION|NOT_APPLICABLE>
14
- ## Capability Attestation: <VERIFIED|FAILED|NOT_APPLICABLE>
15
- ## Descendant Execution Units Observed: <number>
16
- ## Delegation Depth Observed: <number>
17
- ## Snapshot Verification: <VERIFIED|FAILED|NOT_APPLICABLE>
18
- ## Snapshot Identity: <identity|failure reason|not-applicable>
19
- ## Blocker Code: <REVIEW_INFRASTRUCTURE_BLOCKED|REVIEW_ORCHESTRATION_VIOLATION|WORKSPACE_MISMATCH|REVIEW_SAFETY_LIMIT_REACHED|INVALID_REVIEW_RESULT|NONE>
20
10
  ## Total Findings: <total> → Fixed: <fixed>, Rejected: <rejected>, Unresolved: <unresolved>
21
11
 
22
- ## Round <N>
23
-
24
- - Snapshot Identity: <identity>
25
- - Reviewer Execution Identity: <identity>
26
- - Result: <PASS|NEEDS_FIXES>
27
- - Findings: <count>
28
- - Accepted: <count>
29
- - Rejected: <count>
12
+ ## Findings
30
13
 
31
14
  ### Finding <N>: <short title>
32
15
 
33
16
  - Severity: <high|medium|low>
34
- - Dimension: <dimension>
35
17
  - Location: <filepath:line|project-level>
36
18
  - Problem: <what was wrong and why it mattered>
37
19
  - Failure Scenario: <concrete input or state>
38
- - Status: <fixed in round N|rejected — concrete evidence|unresolved — reason>
20
+ - Disposition: <fixed in round N|rejected — concrete evidence|unresolved — reason>
21
+
22
+ ## Blocker
23
+
24
+ <Include only for BLOCKED: concise infrastructure failure and required action.>
39
25
 
40
- ## Final Summary
26
+ ## Summary
41
27
 
42
- <One to three sentences covering the valid review outcome and any remaining blocker. Do not expose Reviewer reasoning traces.>
28
+ <One to three sentences covering the final outcome. Do not expose private reasoning traces.>
43
29
  ```
44
30
 
45
31
  ## Report Rules
46
32
 
47
- - No-change review starts no Reviewer, uses zero completed rounds, and records execution plus snapshot metadata as `NOT_APPLICABLE`.
48
- - Findings from a violating or mismatched Reviewer are discarded and excluded from totals.
49
- - A violating or mismatched round is not completed.
50
- - `PASS` requires no workspace changes or a usable complete Reviewer result with zero accepted findings.
51
- - The ten-round safety fuse with accepted findings is `NEEDS_FIXES`, never `PASS`.
52
- - Only `PASS` and `NEEDS_FIXES` are external verdicts. Blocker codes are diagnostic metadata.
53
- - Persist structured state before Markdown rendering so a report-only failure can be recovered without repeating review.
33
+ - A no-change review uses zero completed rounds and returns `PASS`.
34
+ - A usable Reviewer result counts as one completed round.
35
+ - Reviewer launch failure, abnormal exit, or unusable output returns `BLOCKED` and does not add a completed round.
36
+ - `PASS` requires no accepted or unresolved finding. This includes a Reviewer `PASS` and a findings result where the Main Agent rejects every finding with concrete evidence.
37
+ - The tenth completed round with accepted findings returns `NEEDS_FIXES`.
38
+ - `BLOCKED` describes review infrastructure or missing essential context, not a code defect.
39
+ - Overwrite the same report on each execution; keep raw round output only in the session log.
40
+ - Do not persist a separate review state file.
@@ -1,6 +1,6 @@
1
1
  # Reviewer Prompt Contract
2
2
 
3
- Use this complete template for every Reviewer execution in Phase 1. Fill documented placeholders only. Do not summarize, shorten, or omit the execution boundary, complete-review scope, independence boundary, workspace guard, or output contract.
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
4
 
5
5
  ```text
6
6
  You are the sole independent read-only Reviewer for this round of `/prizmkit-code-review`.
@@ -9,61 +9,60 @@ You are the sole independent read-only Reviewer for this round of `/prizmkit-cod
9
9
 
10
10
  Perform the complete review yourself.
11
11
 
12
- Do not create, schedule, resume, continue, request, or coordinate any separate downstream execution unit. Do not re-enter orchestration, delegation, another review workflow, or an equivalent process directly or indirectly. Do not ask the Main Agent to create a helper on your behalf.
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
13
 
14
- Do not modify, create, delete, rename, stage, or commit workspace files. Do not run a command or tool that changes the review view.
14
+ Do not modify, create, delete, rename, stage, or commit workspace files. Use only read-only inspection capabilities.
15
15
 
16
- If you cannot complete the review within this execution context, stop and return `REVIEW_INFRASTRUCTURE_BLOCKED`. Do not delegate or provide a partial PASS.
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
17
 
18
18
  ## Independent Input Boundary
19
19
 
20
- Review only the current state supplied below. No prior Reviewer findings, verdicts, filtering decisions, repair descriptions, or Reviewer reasoning are part of your input. Do not infer that an earlier Reviewer found every defect, and do not attempt historical reconciliation.
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
21
 
22
- ## Spec Goals
22
+ ## Goals and Acceptance Criteria
23
23
 
24
- {goals and acceptance criteria from spec.md}
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
25
 
26
- ## Plan Decisions
26
+ ## Plan and Intended Change
27
27
 
28
- {architecture decisions and task list from plan.md}
28
+ {relevant architecture decisions and completed tasks from plan.md, or a concise current task description}
29
29
 
30
30
  ## Applicable Rules and Contracts
31
31
 
32
32
  {relevant Prizm docs, project rules, public and internal contracts, or "No additional project rules identified."}
33
33
 
34
- ## Scoped Test Evidence
34
+ ## Test Evidence
35
35
 
36
- {current test report summary and identities. If absent, write "No scoped /prizmkit-test report found." Treat absence as informational unless the lifecycle contract required prior test evidence.}
36
+ {current scoped test evidence, or "No scoped test report found."}
37
37
 
38
- ## Workspace Manifest
38
+ ## Current Change
39
39
 
40
- {repository identity, baseline identity, snapshot identity, path inventory, change states, staged and unstaged composition, rename/delete state, content identities, and supporting-context identities}
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}
41
44
 
42
- ## Review Payload
45
+ ## Supplied Git Diff
43
46
 
44
- {complete logical representation of every manifest entry plus distinguishable unchanged caller and dependent context}
47
+ ### Staged
45
48
 
46
- ## Reviewer Strategy
49
+ {complete staged diff, or "No staged changes."}
47
50
 
48
- {concise diagnostic description of how this platform established observational access and made mutation, downstream execution, delegation-equivalent behavior, and orchestration re-entry unavailable}
51
+ ### Unstaged
49
52
 
50
- ## Workspace Equivalence Guard
53
+ {complete unstaged diff, or "No unstaged tracked changes."}
51
54
 
52
- Validate the manifest and payload before ordinary review:
55
+ ## Supplied Untracked Files
53
56
 
54
- 1. Every manifest path and state is represented.
55
- 2. Staged, unstaged, untracked, deleted, and renamed changes are preserved.
56
- 3. Content and snapshot identities match.
57
- 4. Supporting caller or dependent context is distinguishable from changed content.
58
- 5. No unexplained changed path, stale content, mixed-round content, or unverifiable entry exists.
57
+ {path and full content of every untracked file, or "No untracked files."}
59
58
 
60
- Physical path, checkout layout, host, or transport may differ. Content-equivalent current state is the invariant.
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.
61
60
 
62
- If equivalence cannot be proven, stop before ordinary review and return `WORKSPACE_MISMATCH` with concrete mismatch evidence. Do not return code findings from an unverified snapshot.
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.
63
62
 
64
- ## Complete Current-State Review
63
+ ## Complete Current-Change Review
65
64
 
66
- Review the complete current change set independently. Do not limit inspection to files changed by the latest repair or to previously identified categories.
65
+ Review the complete current change independently. Do not limit inspection to one file or one suspected issue.
67
66
 
68
67
  Evaluate applicable dimensions:
69
68
 
@@ -79,60 +78,43 @@ Evaluate applicable dimensions:
79
78
  10. Test adequacy and evidence compatibility
80
79
  11. Project-rule compliance
81
80
 
82
- Use both inspection directions inside this one review:
81
+ Use both directions in this review:
83
82
 
84
83
  - Code-forward: changed code → affected symbols → callers and dependents → concrete failure scenarios
85
84
  - Requirement-backward: requirements and contracts → required behavior → implementation path → side effects → test evidence
86
85
 
87
- Read unchanged callers, dependents, or shared patterns when needed to evaluate impact.
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.
88
87
 
89
- ## Review Efficiency
88
+ ## Finding Standard
90
89
 
91
- Complete the review directly instead of delegating it. Prefer direct read-only inspection and targeted verification.
92
-
93
- Use existing valid test evidence when it answers the question. Prefer the narrowest verification that can establish or refute a concrete issue. Do not rerun an equivalent check when relevant code and inputs have not changed.
94
-
95
- Avoid broad builds, tests, lint, or type checks as exploratory defaults. A broad command remains valid when a concrete cross-cutting risk genuinely requires it; state why narrower evidence is insufficient.
96
-
97
- Non-normative examples:
98
-
99
- - A repository-wide test or build without a concrete reason is often redundant with the formal Test Gate.
100
- - A focused module or test-case invocation is usually better when investigating one failure scenario.
101
-
102
- These examples do not prohibit command names. The governing rule is targeted, non-duplicative evidence gathering.
103
-
104
- ## Finding Coverage
105
-
106
- Report every concrete issue you find, including uncertain or low-severity issues. Do not filter for importance or confidence; the Main Agent performs downstream filtering. Exclude pure style or naming preferences that cannot cause incorrect behavior, contract drift, regression, security weakness, or misleading evidence.
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.
107
91
 
108
92
  ## Output Contract
109
93
 
110
94
  Respond with exactly this structure:
111
95
 
112
- ### Result: PASS | NEEDS_FIXES | WORKSPACE_MISMATCH | REVIEW_INFRASTRUCTURE_BLOCKED
96
+ ### Result: PASS | FINDINGS | BLOCKED
113
97
 
114
- ### Execution Compliance
115
- - Status: COMPLIANT | BLOCKED
116
- - Descendant execution units created: 0
117
- - Delegation depth: 0
98
+ ### Findings
118
99
 
119
- ### Snapshot Verification
120
- - Status: VERIFIED | FAILED
121
- - Identity: <snapshot identity or mismatch summary>
100
+ If the result is `PASS`, write:
122
101
 
123
- ### Findings
124
- (If PASS, write "No issues found." If WORKSPACE_MISMATCH or REVIEW_INFRASTRUCTURE_BLOCKED, include only blocker evidence and required action.)
102
+ No issues found.
125
103
 
126
- #### Finding N
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>
127
109
  - Severity: high | medium | low
128
- - Confidence: high | medium | low
129
- - Dimension: requirement-alignment | defect | completeness | error-handling | security | data-integrity | concurrency | contract | compatibility | test-quality | rules-compliance
130
110
  - Location: filepath:line (or "project-level")
131
111
  - Problem: concrete wrong behavior and why it matters
132
112
  - Failure scenario: inputs or state that produce the wrong result
133
- - Suggestion: recommended repair approach
113
+ - Reasoning: concise evidence connecting the current code to the failure
114
+ - Suggested repair: smallest safe repair approach
134
115
  - Verification: how to prove the repair
135
116
 
136
117
  ### Summary
137
- One or two sentences describing the verified current state and overall result. Do not expose private reasoning traces.
118
+
119
+ One or two sentences describing the current change and result. Do not expose private reasoning traces.
138
120
  ```
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- """Render review-report.md from completed structured review state."""
2
+ """Render the final review-report.md from minimal review data."""
3
3
 
4
4
  from __future__ import annotations
5
5
 
@@ -9,102 +9,94 @@ import sys
9
9
  from pathlib import Path
10
10
  from typing import Any
11
11
 
12
- VERDICTS = {"PASS", "NEEDS_FIXES"}
13
- EXECUTION_PROTOCOLS = {"BLOCKED", "COMPLIANT", "NOT_APPLICABLE", "VIOLATION"}
14
- ATTESTATIONS = {"FAILED", "NOT_APPLICABLE", "VERIFIED"}
15
- SNAPSHOT_STATUSES = {"FAILED", "NOT_APPLICABLE", "VERIFIED"}
16
- BLOCKERS = {
17
- "INVALID_REVIEW_RESULT",
18
- "NONE",
19
- "REVIEW_INFRASTRUCTURE_BLOCKED",
20
- "REVIEW_ORCHESTRATION_VIOLATION",
21
- "REVIEW_SAFETY_LIMIT_REACHED",
22
- "WORKSPACE_MISMATCH",
23
- }
24
- REVIEW_MODES = {
25
- "independent-reviewer-verified-snapshot",
26
- "not-run-no-changes",
27
- }
12
+ VERDICTS = {"PASS", "NEEDS_FIXES", "BLOCKED"}
13
+ DISPOSITIONS = ("fixed", "rejected", "unresolved")
28
14
 
29
15
 
30
16
  class ReportStateError(ValueError):
31
- """Raised when persisted state cannot produce a trustworthy report."""
17
+ """Raised when review data cannot produce a valid final report."""
32
18
 
33
19
 
34
- def _require_enum(state: dict[str, Any], name: str, allowed: set[str]) -> str:
35
- value = state.get(name)
36
- if value not in allowed:
37
- raise ReportStateError(f"{name} has invalid value: {value!r}")
38
- return value
39
-
40
-
41
- def _require_count(state: dict[str, Any], name: str) -> int:
42
- value = state.get(name)
20
+ def _require_count(data: dict[str, Any], name: str) -> int:
21
+ value = data.get(name)
43
22
  if not isinstance(value, int) or isinstance(value, bool) or value < 0:
44
23
  raise ReportStateError(f"{name} must be a non-negative integer")
45
24
  return value
46
25
 
47
26
 
48
- def validate_state(state: Any) -> dict[str, Any]:
49
- """Validate the minimum completed state required for report regeneration."""
50
- if not isinstance(state, dict):
51
- raise ReportStateError("state must be a JSON object")
52
-
53
- _require_enum(state, "verdict", VERDICTS)
54
- _require_enum(state, "review_mode", REVIEW_MODES)
55
- _require_enum(state, "execution_protocol", EXECUTION_PROTOCOLS)
56
- _require_enum(state, "capability_attestation", ATTESTATIONS)
57
- _require_enum(state, "snapshot_verification", SNAPSHOT_STATUSES)
58
- _require_enum(state, "blocker_code", BLOCKERS)
59
- rounds_completed = _require_count(state, "rounds_completed")
60
- reviewers_started = _require_count(state, "reviewers_started")
61
- descendants = _require_count(state, "descendant_execution_units_observed")
62
- delegation_depth = _require_count(state, "delegation_depth_observed")
63
-
64
- rounds = state.get("rounds")
65
- findings = state.get("findings")
66
- if not isinstance(rounds, list) or not isinstance(findings, list):
67
- raise ReportStateError("rounds and findings must be arrays")
68
- if rounds_completed != len(rounds):
69
- raise ReportStateError("rounds_completed must equal the rounds array length")
70
- if reviewers_started < rounds_completed:
71
- raise ReportStateError("reviewers_started cannot be below rounds_completed")
72
-
73
- if state["review_mode"] == "not-run-no-changes":
74
- if any((rounds_completed, reviewers_started, descendants, delegation_depth)):
75
- raise ReportStateError("no-change review cannot contain execution activity")
76
- if state["verdict"] != "PASS":
77
- raise ReportStateError("no-change review must have PASS verdict")
78
-
79
- if state["verdict"] == "PASS" and state["blocker_code"] != "NONE":
80
- raise ReportStateError("PASS cannot include a blocker code")
81
- if state["execution_protocol"] == "COMPLIANT":
82
- if descendants != 0 or delegation_depth != 0:
83
- raise ReportStateError("COMPLIANT execution requires zero descendants and depth")
27
+ def validate_data(data: Any) -> dict[str, Any]:
28
+ if not isinstance(data, dict):
29
+ raise ReportStateError("review data must be a JSON object")
30
+
31
+ verdict = data.get("verdict")
32
+ if verdict not in VERDICTS:
33
+ raise ReportStateError(f"verdict has invalid value: {verdict!r}")
34
+
35
+ rounds_completed = _require_count(data, "rounds_completed")
36
+ if rounds_completed > 10:
37
+ raise ReportStateError("rounds_completed cannot exceed ten")
38
+
39
+ findings = data.get("findings")
40
+ if not isinstance(findings, list):
41
+ raise ReportStateError("findings must be an array")
42
+
43
+ summary = data.get("summary")
44
+ if not isinstance(summary, str) or not summary.strip():
45
+ raise ReportStateError("summary must be a non-empty string")
84
46
 
85
47
  for index, finding in enumerate(findings, start=1):
86
48
  if not isinstance(finding, dict):
87
49
  raise ReportStateError(f"finding {index} must be an object")
88
- required = {"title", "severity", "dimension", "location", "problem", "failure_scenario", "status"}
50
+ required = {
51
+ "title",
52
+ "severity",
53
+ "location",
54
+ "problem",
55
+ "failure_scenario",
56
+ "disposition",
57
+ }
89
58
  missing = sorted(required - finding.keys())
90
59
  if missing:
91
60
  raise ReportStateError(
92
61
  f"finding {index} missing fields: {', '.join(missing)}"
93
62
  )
94
-
95
- return state
63
+ disposition = finding["disposition"]
64
+ if not isinstance(disposition, str) or not disposition.startswith(DISPOSITIONS):
65
+ raise ReportStateError(f"finding {index} has invalid disposition")
66
+
67
+ unresolved = sum(
68
+ finding["disposition"].startswith("unresolved") for finding in findings
69
+ )
70
+ blocker = data.get("blocker")
71
+
72
+ if verdict == "PASS" and unresolved:
73
+ raise ReportStateError("PASS cannot contain unresolved findings")
74
+ if verdict == "NEEDS_FIXES" and not unresolved:
75
+ raise ReportStateError("NEEDS_FIXES requires an unresolved finding")
76
+ if verdict == "BLOCKED":
77
+ if not isinstance(blocker, str) or not blocker.strip():
78
+ raise ReportStateError("BLOCKED requires a non-empty blocker")
79
+ if unresolved:
80
+ raise ReportStateError("BLOCKED cannot classify code findings as unresolved")
81
+ elif blocker is not None:
82
+ raise ReportStateError("only BLOCKED may include blocker")
83
+
84
+ return data
96
85
 
97
86
 
98
87
  def _finding_totals(findings: list[dict[str, Any]]) -> tuple[int, int, int]:
99
- fixed = sum(finding["status"].startswith("fixed") for finding in findings)
100
- rejected = sum(finding["status"].startswith("rejected") for finding in findings)
101
- unresolved = len(findings) - fixed - rejected
88
+ fixed = sum(finding["disposition"].startswith("fixed") for finding in findings)
89
+ rejected = sum(
90
+ finding["disposition"].startswith("rejected") for finding in findings
91
+ )
92
+ unresolved = sum(
93
+ finding["disposition"].startswith("unresolved") for finding in findings
94
+ )
102
95
  return fixed, rejected, unresolved
103
96
 
104
97
 
105
- def render_report(state: Any) -> str:
106
- """Return deterministic Markdown without launching or resuming a Reviewer."""
107
- valid = validate_state(state)
98
+ def render_report(data: Any) -> str:
99
+ valid = validate_data(data)
108
100
  findings = valid["findings"]
109
101
  fixed, rejected, unresolved = _finding_totals(findings)
110
102
 
@@ -113,69 +105,51 @@ def render_report(state: Any) -> str:
113
105
  "",
114
106
  f"## Verdict: {valid['verdict']}",
115
107
  f"## Rounds Completed: {valid['rounds_completed']}",
116
- f"## Reviewers Started: {valid['reviewers_started']}",
117
- f"## Review Mode: {valid['review_mode']}",
118
- f"## Reviewer Strategy: {valid.get('reviewer_strategy', 'not-applicable')}",
119
- f"## Execution Protocol: {valid['execution_protocol']}",
120
- f"## Capability Attestation: {valid['capability_attestation']}",
121
- f"## Descendant Execution Units Observed: {valid['descendant_execution_units_observed']}",
122
- f"## Delegation Depth Observed: {valid['delegation_depth_observed']}",
123
- f"## Snapshot Verification: {valid['snapshot_verification']}",
124
- f"## Snapshot Identity: {valid.get('snapshot_identity', 'not-applicable')}",
125
- f"## Blocker Code: {valid['blocker_code']}",
126
108
  f"## Total Findings: {len(findings)} → Fixed: {fixed}, Rejected: {rejected}, Unresolved: {unresolved}",
127
109
  "",
128
110
  ]
129
111
 
130
- if valid["review_mode"] == "not-run-no-changes":
131
- lines.extend(["## Round 0: PASS — no workspace changes to review", ""])
132
- else:
133
- for review_round in valid["rounds"]:
112
+ if findings:
113
+ lines.extend(["## Findings", ""])
114
+ for index, finding in enumerate(findings, start=1):
134
115
  lines.extend(
135
116
  [
136
- f"## Round {review_round['round']}",
117
+ f"### Finding {index}: {finding['title']}",
137
118
  "",
138
- f"- Snapshot Identity: {review_round['snapshot_identity']}",
139
- f"- Reviewer Execution Identity: {review_round['reviewer_execution_identity']}",
140
- f"- Result: {review_round['result']}",
141
- f"- Findings: {review_round['findings_count']}",
142
- f"- Accepted: {review_round['accepted_count']}",
143
- f"- Rejected: {review_round['rejected_count']}",
119
+ f"- Severity: {finding['severity']}",
120
+ f"- Location: {finding['location']}",
121
+ f"- Problem: {finding['problem']}",
122
+ f"- Failure Scenario: {finding['failure_scenario']}",
123
+ f"- Disposition: {finding['disposition']}",
144
124
  "",
145
125
  ]
146
126
  )
147
127
 
148
- for index, finding in enumerate(findings, start=1):
149
- lines.extend(
150
- [
151
- f"### Finding {index}: {finding['title']}",
152
- "",
153
- f"- Severity: {finding['severity']}",
154
- f"- Dimension: {finding['dimension']}",
155
- f"- Location: {finding['location']}",
156
- f"- Problem: {finding['problem']}",
157
- f"- Failure Scenario: {finding['failure_scenario']}",
158
- f"- Status: {finding['status']}",
159
- "",
160
- ]
161
- )
162
-
163
- lines.extend(["## Final Summary", "", valid["final_summary"], ""])
128
+ if valid["verdict"] == "BLOCKED":
129
+ lines.extend(["## Blocker", "", valid["blocker"], ""])
130
+
131
+ lines.extend(["## Summary", "", valid["summary"], ""])
164
132
  return "\n".join(lines)
165
133
 
166
134
 
167
135
  def parse_args() -> argparse.Namespace:
168
136
  parser = argparse.ArgumentParser(description=__doc__)
169
- parser.add_argument("state", type=Path, help="completed review-result-state.json")
170
137
  parser.add_argument("output", type=Path, help="review-report.md destination")
138
+ parser.add_argument(
139
+ "input",
140
+ nargs="?",
141
+ type=Path,
142
+ help="optional JSON input path; reads standard input when omitted",
143
+ )
171
144
  return parser.parse_args()
172
145
 
173
146
 
174
147
  def main() -> int:
175
148
  args = parse_args()
176
149
  try:
177
- state = json.loads(args.state.read_text(encoding="utf-8"))
178
- report = render_report(state)
150
+ raw = args.input.read_text(encoding="utf-8") if args.input else sys.stdin.read()
151
+ data = json.loads(raw)
152
+ report = render_report(data)
179
153
  args.output.parent.mkdir(parents=True, exist_ok=True)
180
154
  args.output.write_text(report, encoding="utf-8")
181
155
  except (OSError, json.JSONDecodeError, ReportStateError, KeyError) as error:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.124",
3
+ "version": "1.1.125",
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": {