prizmkit 1.1.86 → 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.
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +462 -4
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +14 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +18 -3
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +18 -3
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +2 -2
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +2 -2
- package/bundled/dev-pipeline/templates/sections/phase-prizmkit-test.md +260 -0
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +5 -1
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +5 -1
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +429 -0
- package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +462 -4
- package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +14 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +18 -3
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +18 -3
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +2 -2
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +2 -2
- package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +186 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +5 -1
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +5 -1
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/prizmkit-code-review/SKILL.md +7 -2
- package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +6 -2
- package/bundled/skills/prizmkit-test/SKILL.md +106 -14
- package/bundled/skills/prizmkit-test/references/boundary-coverage-protocol.md +220 -0
- package/bundled/skills/prizmkit-test/references/examples.md +82 -9
- package/bundled/skills/prizmkit-test/references/test-generation-steps.md +68 -12
- package/bundled/skills/prizmkit-test/references/test-report-template.md +73 -9
- package/bundled/skills/prizmkit-test/scripts/validate_boundary_report.py +347 -0
- package/bundled/skills-windows/prizmkit-code-review/SKILL.md +7 -2
- package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +6 -2
- package/bundled/skills-windows/prizmkit-test/SKILL.md +106 -14
- package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +220 -0
- package/bundled/skills-windows/prizmkit-test/references/examples.md +82 -9
- package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +4 -4
- package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +68 -12
- package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +73 -9
- package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +347 -0
- 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
|
|
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
|
|
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
|
|