prizmkit 1.1.85 → 1.1.87

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 (42) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +462 -4
  3. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
  4. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +14 -0
  5. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +18 -3
  6. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +18 -3
  7. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +2 -2
  8. package/bundled/dev-pipeline/templates/sections/phase-commit.md +2 -2
  9. package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +260 -0
  10. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +5 -1
  11. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +5 -1
  12. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +429 -0
  13. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +462 -4
  14. package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +1 -1
  15. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +14 -0
  16. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +18 -3
  17. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +18 -3
  18. package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +2 -2
  19. package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +2 -2
  20. package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +186 -0
  21. package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +5 -1
  22. package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +5 -1
  23. package/bundled/skills/_metadata.json +1 -1
  24. package/bundled/skills/prizmkit-code-review/SKILL.md +7 -2
  25. package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +6 -2
  26. package/bundled/skills/prizmkit-test/SKILL.md +107 -13
  27. package/bundled/skills/prizmkit-test/references/boundary-coverage-protocol.md +220 -0
  28. package/bundled/skills/prizmkit-test/references/examples.md +82 -9
  29. package/bundled/skills/prizmkit-test/references/service-boundary-test-catalog.md +225 -0
  30. package/bundled/skills/prizmkit-test/references/test-generation-steps.md +74 -14
  31. package/bundled/skills/prizmkit-test/references/test-report-template.md +74 -5
  32. package/bundled/skills/prizmkit-test/scripts/validate_boundary_report.py +347 -0
  33. package/bundled/skills-windows/prizmkit-code-review/SKILL.md +7 -2
  34. package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +6 -2
  35. package/bundled/skills-windows/prizmkit-test/SKILL.md +107 -13
  36. package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +220 -0
  37. package/bundled/skills-windows/prizmkit-test/references/examples.md +82 -9
  38. package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +225 -0
  39. package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +74 -14
  40. package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +74 -5
  41. package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +347 -0
  42. package/package.json +1 -1
@@ -0,0 +1,260 @@
1
+ ### Scoped Feature Test Gate — PrizmKit Test
2
+
3
+ **Goal**: Generate and verify tests for this feature's changed scope before code review.
4
+
5
+ Create a start marker immediately before invoking the skill so the gate can reject stale reports from older sessions:
6
+
7
+ ```bash
8
+ mkdir -p .prizmkit/specs/{{FEATURE_SLUG}}/
9
+ test_gate_marker=".prizmkit/specs/{{FEATURE_SLUG}}/.prizmkit-test-started"
10
+ touch "$test_gate_marker"
11
+ ```
12
+
13
+ Run `/prizmkit-test` with the feature artifact directory:
14
+
15
+ ```text
16
+ /prizmkit-test scope=this-change artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/
17
+ ```
18
+
19
+ Rules:
20
+ - This gate is feature-pipeline only. Do NOT use `.prizmkit/bugfix/` or `.prizmkit/refactor/` artifact directories here.
21
+ - Generate or update tests only for this feature's changed files, changed public interfaces, and acceptance criteria.
22
+ - Record unrelated historical coverage gaps under `Out of Scope Gaps`; do not generate tests for them and do not fail this feature because of them.
23
+ - If generated tests fail because implementation is wrong, fix implementation within this feature scope and rerun the affected tests.
24
+ - If failures are baseline or unrelated to this feature, document them in the report and continue only when no in-scope failure remains unexplained.
25
+
26
+ **Gate Check — Test Report**:
27
+ After `/prizmkit-test` returns, locate the newest test report created after the start marker and validate that it belongs to this feature scope, has a PASS verdict, and has passed the boundary completion/validation gates before writing the checkpoint pointer:
28
+ ```bash
29
+ feature_artifact_dir=".prizmkit/specs/{{FEATURE_SLUG}}/"
30
+ latest_test_report=$(python3 - "$test_gate_marker" <<'PY'
31
+ import os
32
+ import sys
33
+
34
+ marker = sys.argv[1]
35
+ try:
36
+ marker_mtime = os.path.getmtime(marker)
37
+ except OSError:
38
+ sys.exit(0)
39
+
40
+ matches = []
41
+ for root, _dirs, files in os.walk(".prizmkit/test"):
42
+ if "test-report.md" not in files:
43
+ continue
44
+ path = os.path.join(root, "test-report.md")
45
+ try:
46
+ report_mtime = os.path.getmtime(path)
47
+ except OSError:
48
+ continue
49
+ if report_mtime >= marker_mtime:
50
+ matches.append((report_mtime, path))
51
+
52
+ if matches:
53
+ print(sorted(matches)[-1][1])
54
+ PY
55
+ )
56
+ if [ -n "$latest_test_report" ]; then
57
+ report_mode=$(awk '
58
+ /^## Scope[[:space:]]*$/ { in_scope=1; next }
59
+ /^## / && in_scope { exit }
60
+ in_scope && /^- Mode:/ { sub(/^- Mode:[[:space:]]*/, ""); print; exit }
61
+ ' "$latest_test_report")
62
+ report_artifact_dir=$(awk '
63
+ /^## Scope[[:space:]]*$/ { in_scope=1; next }
64
+ /^## / && in_scope { exit }
65
+ in_scope && /^- Artifact Dir:/ { sub(/^- Artifact Dir:[[:space:]]*/, ""); print; exit }
66
+ ' "$latest_test_report")
67
+ report_verdict=$(awk '
68
+ /^## Verdict[[:space:]]*$/ { in_verdict=1; next }
69
+ in_verdict && NF { gsub(/^[[:space:]]+|[[:space:]]+$/, ""); print; exit }
70
+ ' "$latest_test_report")
71
+ boundary_gate_passed=$(awk '
72
+ /^## Boundary Completion Gate[[:space:]]*$/ { in_gate=1; next }
73
+ /^## / && in_gate { exit }
74
+ in_gate && /^-?[[:space:]]*Completion gate passed:[[:space:]]*yes[[:space:]]*$/ { print "yes"; exit }
75
+ ' "$latest_test_report")
76
+ boundary_missing=$(awk '
77
+ /^## Boundary Completion Gate[[:space:]]*$/ { in_gate=1; next }
78
+ /^## / && in_gate { exit }
79
+ in_gate && /^-?[[:space:]]*Boundary-missing:/ { sub(/^.*:[[:space:]]*/, ""); print; exit }
80
+ ' "$latest_test_report")
81
+ happy_path_only=$(awk '
82
+ /^## Boundary Completion Gate[[:space:]]*$/ { in_gate=1; next }
83
+ /^## / && in_gate { exit }
84
+ in_gate && /^-?[[:space:]]*Happy-path-only:/ { sub(/^.*:[[:space:]]*/, ""); print; exit }
85
+ ' "$latest_test_report")
86
+ boundary_columns_ok=$(awk '
87
+ /^## Boundary Matrix[[:space:]]*$/ { in_matrix=1; next }
88
+ /^## / && in_matrix { exit }
89
+ in_matrix && /^\|/ {
90
+ if ($0 ~ /\|[[:space:]]*Module[[:space:]]*\|/ &&
91
+ $0 ~ /\|[[:space:]]*Interface[[:space:]]*\|/ &&
92
+ $0 ~ /\|[[:space:]]*Service Type[[:space:]]*\|/ &&
93
+ $0 ~ /\|[[:space:]]*Happy Path[[:space:]]*\|/ &&
94
+ $0 ~ /\|[[:space:]]*Request Validation[[:space:]]*\|/ &&
95
+ $0 ~ /\|[[:space:]]*Auth \/ Permission \/ Ownership[[:space:]]*\|/ &&
96
+ $0 ~ /\|[[:space:]]*Domain Invariants[[:space:]]*\|/ &&
97
+ $0 ~ /\|[[:space:]]*Collection \/ Pagination[[:space:]]*\|/ &&
98
+ $0 ~ /\|[[:space:]]*Date \/ Time[[:space:]]*\|/ &&
99
+ $0 ~ /\|[[:space:]]*State Transitions[[:space:]]*\|/ &&
100
+ $0 ~ /\|[[:space:]]*Dependency Failure[[:space:]]*\|/ &&
101
+ $0 ~ /\|[[:space:]]*Response Contract[[:space:]]*\|/ &&
102
+ $0 ~ /\|[[:space:]]*N\/A Reasons[[:space:]]*\|/ &&
103
+ $0 ~ /\|[[:space:]]*Final Status[[:space:]]*\|/) { print "yes"; exit }
104
+ }
105
+ ' "$latest_test_report")
106
+ boundary_incomplete=$(awk '
107
+ /^## Boundary Matrix[[:space:]]*$/ { in_matrix=1; next }
108
+ /^## / && in_matrix { exit }
109
+ in_matrix && /boundary-missing|happy-path-only|unresolved/ { print "yes"; exit }
110
+ ' "$latest_test_report")
111
+ boundary_validation_result=$(awk '
112
+ /^## Boundary Validation[[:space:]]*$/ { in_validation=1; next }
113
+ /^## / && in_validation { exit }
114
+ in_validation && /^-?[[:space:]]*Validator result:/ { sub(/^.*:[[:space:]]*/, ""); print; exit }
115
+ ' "$latest_test_report" | tr '[:upper:]' '[:lower:]')
116
+ openapi_file=""
117
+ for openapi_candidate in \
118
+ openapi.yaml openapi.yml swagger.yaml swagger.yml \
119
+ docs/openapi.yaml docs/openapi.yml docs/swagger.yaml docs/swagger.yml \
120
+ api/openapi.yaml api/openapi.yml api/swagger.yaml api/swagger.yml
121
+ do
122
+ if [ -f "$openapi_candidate" ]; then
123
+ openapi_file="$openapi_candidate"
124
+ break
125
+ fi
126
+ done
127
+ boundary_validator_passed=0
128
+ for boundary_validator in \
129
+ .claude/command-assets/prizmkit-test/scripts/validate_boundary_report.py \
130
+ .codebuddy/skills/prizmkit-test/scripts/validate_boundary_report.py \
131
+ .agents/skills/prizmkit-test/scripts/validate_boundary_report.py
132
+ do
133
+ if [ -f "$boundary_validator" ]; then
134
+ boundary_validator_args=(--report "$latest_test_report")
135
+ if [ -n "$openapi_file" ]; then
136
+ boundary_validator_args+=(--openapi "$openapi_file")
137
+ fi
138
+ if python3 "$boundary_validator" "${boundary_validator_args[@]}" >/dev/null 2>&1; then
139
+ boundary_validator_passed=1
140
+ break
141
+ fi
142
+ fi
143
+ done
144
+
145
+ scope_fresh_ok=$(python3 - "$latest_test_report" "$test_gate_marker" <<'PY'
146
+ import os
147
+ import sys
148
+
149
+ report_path, marker_path = sys.argv[1], sys.argv[2]
150
+ try:
151
+ report_mtime = os.path.getmtime(report_path)
152
+ marker_mtime = os.path.getmtime(marker_path)
153
+ except OSError:
154
+ print("0")
155
+ sys.exit(0)
156
+ if report_mtime < marker_mtime:
157
+ print("0")
158
+ sys.exit(0)
159
+ try:
160
+ with open(report_path, "r", encoding="utf-8") as report_file:
161
+ report_text = report_file.read()
162
+ except OSError:
163
+ print("0")
164
+ sys.exit(0)
165
+
166
+ def scope_list(name):
167
+ in_scope = False
168
+ in_list = False
169
+ marker = f"- {name}:"
170
+ values = []
171
+ for raw_line in report_text.splitlines():
172
+ line = raw_line.strip()
173
+ if line == "## Scope":
174
+ in_scope = True
175
+ continue
176
+ if in_scope and line.startswith("## "):
177
+ break
178
+ if not in_scope:
179
+ continue
180
+ if line == marker:
181
+ in_list = True
182
+ continue
183
+ if in_list:
184
+ if raw_line.startswith(" -") or raw_line.startswith("\t-"):
185
+ value = line[2:].strip().strip("`")
186
+ if value and value not in {"{...}", "..."}:
187
+ values.append(value)
188
+ continue
189
+ if line.startswith("- "):
190
+ break
191
+ return values
192
+
193
+ source_files = scope_list("In-Scope Source Files")
194
+ test_files = scope_list("In-Scope Test Files")
195
+ if not source_files or not test_files:
196
+ print("0")
197
+ sys.exit(0)
198
+
199
+ project_root = os.path.realpath(os.getcwd())
200
+ ignored = {"none", "n/a", "not applicable", "(none)", "{...}", "..."}
201
+ for listed_file in source_files + test_files:
202
+ normalized = listed_file.strip().strip("`")
203
+ if not normalized or normalized.lower() in ignored:
204
+ print("0")
205
+ sys.exit(0)
206
+ candidate = normalized if os.path.isabs(normalized) else os.path.join(os.getcwd(), normalized)
207
+ candidate_real = os.path.realpath(candidate)
208
+ try:
209
+ if os.path.commonpath([project_root, candidate_real]) != project_root:
210
+ print("0")
211
+ sys.exit(0)
212
+ except ValueError:
213
+ print("0")
214
+ sys.exit(0)
215
+ if not os.path.isfile(candidate_real):
216
+ print("0")
217
+ sys.exit(0)
218
+ if os.path.getmtime(candidate_real) > report_mtime:
219
+ print("0")
220
+ sys.exit(0)
221
+ print("1")
222
+ PY
223
+ )
224
+
225
+ artifact_ok=0
226
+ case "$report_artifact_dir" in
227
+ "$feature_artifact_dir"|"${feature_artifact_dir%/}") artifact_ok=1 ;;
228
+ esac
229
+
230
+ boundary_ok=0
231
+ if [ "$boundary_columns_ok" = "yes" ] && [ -z "$boundary_incomplete" ] && [ "$boundary_gate_passed" = "yes" ] && [ "$boundary_missing" = "0" ] && [ "$happy_path_only" = "0" ] && [ "$boundary_validator_passed" = "1" ] && [ "$scope_fresh_ok" = "1" ]; then
232
+ case "$boundary_validation_result" in
233
+ passed) boundary_ok=1 ;;
234
+ esac
235
+ fi
236
+
237
+ if [ "$report_mode" = "this-change" ] && [ "$artifact_ok" = "1" ] && [ "$report_verdict" = "PASS" ] && [ "$boundary_ok" = "1" ]; then
238
+ printf "%s\n" "$latest_test_report" > .prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt
239
+ echo "GATE:PASS $latest_test_report"
240
+ else
241
+ echo "GATE:FAIL verdict=$report_verdict mode=$report_mode artifact_dir=$report_artifact_dir boundary_gate=$boundary_gate_passed boundary_missing=$boundary_missing happy_path_only=$happy_path_only boundary_validation=$boundary_validation_result validator_passed=$boundary_validator_passed scope_fresh=$scope_fresh_ok openapi=$openapi_file report=$latest_test_report"
242
+ fi
243
+ else
244
+ echo "GATE:MISSING"
245
+ fi
246
+ ```
247
+
248
+ Gate outcomes:
249
+ - `GATE:PASS` → append the report path and a 3-5 bullet summary to `context-snapshot.md` under `## PrizmKit Test Gate`, then update the checkpoint.
250
+ - `GATE:FAIL` with `NEEDS_FIXES` → read the report's `In-Scope Failures`, fix the feature implementation or generated tests within this feature scope, rerun `/prizmkit-test`, and repeat the gate check. Do not proceed to code review while the verdict is not `PASS`.
251
+ - `GATE:FAIL` with `BLOCKED`, wrong mode, wrong artifact dir, or unreadable report → write `.prizmkit/specs/{{FEATURE_SLUG}}/failure-log.md` with the scoped test failure and stop for recovery.
252
+ - `GATE:MISSING` → perform one bounded status check: inspect `/prizmkit-test` output and `.prizmkit/test/` for a report directory. If no current-run report exists, write `failure-log.md` and stop for recovery.
253
+
254
+ Only after `GATE:PASS`, run the update script to set step `prizmkit-test` to `"completed"`:
255
+ ```bash
256
+ python3 $PIPELINE_DIR/scripts/update-checkpoint.py \
257
+ --checkpoint-path {{CHECKPOINT_PATH}} \
258
+ --step prizmkit-test \
259
+ --status completed
260
+ ```
@@ -1,4 +1,8 @@
1
- ### Review + Test — Code Review
1
+ ### Review — Code Review
2
+
3
+ Precondition: the `prizmkit-test` checkpoint is completed and `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt` points to the scoped test report.
4
+
5
+ Before invoking review, read `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt`, read the referenced `/prizmkit-test` report, and confirm the summary in `context-snapshot.md` under `## PrizmKit Test Gate` matches it. The code-review skill must receive this context through `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` and the Reviewer must assess generated/updated test quality, `In-Scope Failures`, `Baseline Failures`, `Out of Scope Gaps`, boundary coverage if present, and the scoped report verdict.
2
6
 
3
7
  Run `/prizmkit-code-review` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/`.
4
8
 
@@ -1,4 +1,8 @@
1
- ### Review + Test — Code Review
1
+ ### Review — Code Review
2
+
3
+ Precondition: the `prizmkit-test` checkpoint is completed and `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt` points to the scoped test report.
4
+
5
+ Before invoking review, read `.prizmkit/specs/{{FEATURE_SLUG}}/test-report-path.txt`, read the referenced `/prizmkit-test` report, and confirm the summary in `context-snapshot.md` under `## PrizmKit Test Gate` matches it. The code-review skill must receive this context through `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/` and the Reviewer must assess generated/updated test quality, `In-Scope Failures`, `Baseline Failures`, `Out of Scope Gaps`, boundary coverage if present, and the scoped report verdict.
2
6
 
3
7
  Run `/prizmkit-code-review` with `artifact_dir=.prizmkit/specs/{{FEATURE_SLUG}}/`.
4
8