Skip to content

Commit 46e8917

Browse files
committed
refactor: redesign skill test schema to markdown with transcript-based assertions
- Replace JSON test-cases format with markdown scenario files (.md) under plugin/tests/skills/ - Add YAML frontmatter with category field (required); remove type field (all tests use SPRT) - Change section structure: User Prompt ??? Turn 1, unlimited Turn N sections (supports multi-turn tests) - Unified Assertions section with unlimited numbered list (replace Tier 1/Tier 2) - Migrate skill-grader from plugin/skills/ (skill) to plugin/agents/ (subagent) - Update ValidateSkillTestFormat hook to validate new schema - Update concept docs and all 79 scenario files - Migrate results.json format in 3 test case result files
1 parent 8864491 commit 46e8917

104 files changed

Lines changed: 2384 additions & 2552 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
{
2-
"status" : "open",
3-
"dependencies" : [ "2.1-revise-instruction-builder-file-targets" ]
4-
}
2+
"status" : "closed",
3+
"resolution" : "implemented",
4+
"dependencies" : [ "2.1-revise-instruction-builder-file-targets" ],
5+
"target_branch" : "v2.1"
6+
}
Lines changed: 269 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
# Plan
22

3+
## Type
4+
5+
refactor
6+
37
## Goal
48

5-
Redesign skill tests to use stored transcripts and grader agents for SPRT evaluation. Each test
6-
scenario runs once and stores the raw transcript in a `runs/` subdirectory (as defined by
7-
2.1-revise-instruction-builder-file-targets). Assertions are evaluated by new dedicated grader
8-
agents that read transcripts rather than inline during agent execution. All existing test-cases.json
9-
and test-results.json files are migrated to the new format. Agents replaced by the new grader
10-
model (e.g., cat:skill-validator-agent) are removed.
9+
Redesign skill tests to use stored transcripts and grader agents for SPRT evaluation. Each test scenario runs
10+
once and stores the raw transcript in a `runs/` subdirectory (as defined by
11+
2.1-revise-instruction-builder-file-targets). Assertions are evaluated by new dedicated grader agents that
12+
read transcripts rather than inline during agent execution. All existing test-cases.json and test-results.json
13+
files are migrated to the new format. Agents replaced by the new grader model (e.g., cat:skill-validator-agent)
14+
are removed.
1115

1216
## Pre-conditions
1317

@@ -22,5 +26,263 @@ model (e.g., cat:skill-validator-agent) are removed.
2226
- [ ] All existing test-results.json files replaced by results.json keyed by scenario filename and assertion name
2327
- [ ] SPRT statistics tracked per assertion (not per file) in results.json
2428
- [ ] ValidateSkillTestFormat hook updated to enforce new .md schema
25-
- [ ] E2E verification: run a skill test end-to-end and confirm transcript stored in runs/, graded correctly, results.json updated
29+
- [ ] E2E verification: run a skill test end-to-end and confirm transcript stored in runs/, graded correctly,
30+
results.json updated
2631
- [ ] Tests pass, no regressions
32+
33+
## Research Findings
34+
35+
### Current file inventory
36+
37+
**test-cases.json files to migrate (10 files):**
38+
39+
| Old path | New target directory |
40+
|----------|---------------------|
41+
| `plugin/skills/work-implement-agent/benchmark/test-cases.json` | `plugin/tests/skills/work-implement-agent/first-use/` |
42+
| `plugin/skills/init/test/test-cases.json` | `plugin/tests/skills/init/first-use/` |
43+
| `plugin/skills/git-squash-agent/benchmark/test-cases.json` | `plugin/tests/skills/git-squash-agent/first-use/` |
44+
| `plugin/skills/stakeholder-review-agent/tests/test-cases.json` | `plugin/tests/skills/stakeholder-review-agent/first-use/` |
45+
| `plugin/skills/cleanup/test/test-cases.json` | `plugin/tests/skills/cleanup/first-use/` |
46+
| `plugin/skills/config/test/test-cases.json` | `plugin/tests/skills/config/first-use/` |
47+
| `plugin/skills/get-output-agent/benchmark/test-cases.json` | `plugin/tests/skills/get-output-agent/first-use/` |
48+
| `plugin/skills/github-trigger-workflow-agent/test/test-cases.json` | `plugin/tests/skills/github-trigger-workflow-agent/first-use/` |
49+
| `plugin/skills/status-agent/benchmark/test-cases.json` | `plugin/tests/skills/status-agent/first-use/` |
50+
| `plugin/skills/retrospective-agent/test/test-cases.json` | `plugin/tests/skills/retrospective-agent/first-use/` |
51+
52+
**test-results.json files to migrate (3 files):**
53+
54+
| Old path | New results.json path |
55+
|----------|-----------------------|
56+
| `plugin/skills/stakeholder-review-agent/tests/test-results.json` | `plugin/tests/skills/stakeholder-review-agent/first-use/results.json` |
57+
| `plugin/skills/cleanup/test/test-results.json` | `plugin/tests/skills/cleanup/first-use/results.json` |
58+
| `plugin/skills/retrospective-agent/test/test-results.json` | `plugin/tests/skills/retrospective-agent/first-use/results.json` |
59+
60+
**Files/directories to remove:**
61+
- `plugin/skills/skill-validator-agent/` (entire directory — superseded by grader model)
62+
- `plugin/agents/skill-grader-agent.md` (after skill created in plugin/skills/)
63+
- All source `test-cases.json` and `test-results.json` files listed above (after migration)
64+
- Empty `test/`, `tests/`, and `benchmark/` directories left after migration
65+
66+
**New skill to create:**
67+
- `plugin/skills/skill-grader-agent/SKILL.md` + `first-use.md` (from plugin/agents/skill-grader-agent.md content)
68+
69+
### New directory convention
70+
71+
Tests for a file at `plugin/<path>/<name>.md` go to `plugin/tests/<path>/<name>/`.
72+
Results file lives at `plugin/tests/<path>/<name>/results.json`.
73+
Transcripts from runs go to `plugin/tests/<path>/<name>/runs/`.
74+
75+
### New .md scenario file format
76+
77+
```markdown
78+
---
79+
type: behavior
80+
category: <lowercase-category>
81+
---
82+
## Scenario
83+
84+
<test prompt / scenario description>
85+
86+
## Tier 1 Assertion
87+
88+
<primary assertion — the single most discriminating check>
89+
90+
## Tier 2 Assertion
91+
92+
<secondary assertion — a supporting behavioral property>
93+
```
94+
95+
### Filename derivation from test-cases.json entries
96+
97+
Filename = `semantic_unit_id` with `unit_` prefix stripped, underscores → hyphens.
98+
If `semantic_unit_id` is absent, use `test_case_id` lowercased, underscores → hyphens.
99+
100+
Examples:
101+
- `unit_step4_no_dir_delete``step4-no-dir-delete.md`
102+
- `unit_routing_analysis_action``routing-analysis-action.md`
103+
104+
### Category mapping (old uppercase → new lowercase)
105+
106+
| Old value | New value |
107+
|-----------|-----------|
108+
| `SEQUENCE` | `sequence` |
109+
| `CONDITIONAL` | `conditional` |
110+
| `REQUIREMENT` | `requirement` |
111+
| `CONSEQUENCE` | `consequence` |
112+
| `PROHIBITION` | `requirement` |
113+
114+
### Type mapping
115+
116+
All existing test cases use behavioral prompts (simulating agent execution). Map all to `type: behavior`.
117+
118+
### Assertion mapping to Tier 1 / Tier 2
119+
120+
Each test case's `assertions` array maps as follows:
121+
- **Tier 1**: Text of the first `semantic` assertion's `description` field. If no semantic assertions, use first
122+
assertion's `description`.
123+
- **Tier 2**: Text of the second assertion's `description`. If only one assertion, write a reasonable secondary
124+
assertion that tests an absence or supporting property derived from the scenario context.
125+
126+
Use the assertion `description` field as the tier text (not `instruction``description` is concise and
127+
assertion-focused).
128+
129+
### New results.json schema (per-assertion SPRT)
130+
131+
```json
132+
{
133+
"skill_hash": "<SHA-256 of first-use.md at run time>",
134+
"model": "<model identifier>",
135+
"session_id": "<CLAUDE_SESSION_ID>",
136+
"timestamp": "<ISO-8601 UTC timestamp>",
137+
"overall_decision": "pass|fail|inconclusive",
138+
"scenarios": {
139+
"<scenario-filename-without-extension>": {
140+
"type": "behavior",
141+
"tier_1": {
142+
"log_ratio": 0.0,
143+
"pass_count": 0,
144+
"fail_count": 0,
145+
"total_runs": 0,
146+
"total_tokens": 0,
147+
"total_duration_ms": 0,
148+
"decision": "inconclusive"
149+
},
150+
"tier_2": {
151+
"log_ratio": 0.0,
152+
"pass_count": 0,
153+
"fail_count": 0,
154+
"total_runs": 0,
155+
"total_tokens": 0,
156+
"total_duration_ms": 0,
157+
"decision": "inconclusive"
158+
}
159+
}
160+
}
161+
}
162+
```
163+
164+
### Migrating existing test-results.json to new format
165+
166+
For each entry in `sprt.test_cases`, find the corresponding new scenario filename (using the semantic_unit_id
167+
mapping above). Map the per-case data to tier_1 (primary assertion). Set tier_2 to all zeros/inconclusive.
168+
169+
Old field → new location:
170+
- `log_ratio``scenarios.<name>.tier_1.log_ratio`
171+
- `passes``scenarios.<name>.tier_1.pass_count`
172+
- `failures``scenarios.<name>.tier_1.fail_count`
173+
- `runs``scenarios.<name>.tier_1.total_runs`
174+
- `total_tokens``scenarios.<name>.tier_1.total_tokens`
175+
- `total_duration_ms``scenarios.<name>.tier_1.total_duration_ms`
176+
- Derive `decision` from `log_ratio` vs SPRT thresholds (accept if log_ratio >= accept_boundary, reject if <=
177+
reject_boundary, else inconclusive)
178+
179+
Top-level fields: copy `skill_hash`, `model`, `session_id`, `timestamp`, `overall_decision` from old format.
180+
181+
### ValidateSkillTestFormat hook path pattern change
182+
183+
**Current regex:** `(?:^|/)plugin/skills/[^/]+/test/[^/]+\.md$`
184+
**New regex:** `(?:^|/)plugin/tests/.+\.md$`
185+
186+
Only change is the path portion — format validation logic (frontmatter, sections) stays the same.
187+
188+
Also update `ValidateSkillTestFormatTest.java` to use the new path pattern in test cases.
189+
190+
### cat:skill-grader-agent skill structure
191+
192+
Create from existing `plugin/agents/skill-grader-agent.md`:
193+
194+
**`plugin/skills/skill-grader-agent/SKILL.md`:**
195+
```
196+
---
197+
description: >
198+
Internal subagent — grades a list of assertions against a single test-case output, assigning pass/fail
199+
verdicts with evidence quotes. Reads run output via git show, commits grading JSON, returns commit SHA.
200+
model: haiku
201+
user-invocable: false
202+
---
203+
204+
!`"${CLAUDE_PLUGIN_ROOT}/client/bin/get-skill" skill-grader-agent "$0"`
205+
```
206+
207+
**`plugin/skills/skill-grader-agent/first-use.md`:**
208+
Copy content from `plugin/agents/skill-grader-agent.md` (the body below the frontmatter), adding license header.
209+
210+
### plugin/concepts/skill-test.md updates
211+
212+
Add a `## Runs Directory` section after the `## Directory Convention` section documenting:
213+
- `runs/` subdirectory location: `plugin/tests/<path>/<name>/runs/`
214+
- Transcript file naming: `<scenario-slug>-<run-id>.md` (run-id is a short unique identifier per execution)
215+
- Transcripts are written by the test runner before grading
216+
- Graders read transcripts from runs/ via `git show` or direct file access
217+
218+
Update `## Directory Convention` to show the `plugin/tests/` path (not `plugin/skills/<skill>/test/`):
219+
```
220+
plugin/tests/<path>/<name>/
221+
<scenario-slug>.md (one file per test case)
222+
results.json (written after a test run; see plugin/concepts/skill-test-results.md)
223+
runs/
224+
<scenario-slug>-<run-id>.md (raw transcript per run)
225+
```
226+
227+
### plugin/concepts/skill-test-results.md updates
228+
229+
Replace `test_cases` array schema with `scenarios` object schema per the new results.json format above.
230+
231+
Update `## File Location` to:
232+
```
233+
plugin/tests/<path>/<name>/results.json
234+
```
235+
236+
Update the schema description to reflect per-assertion SPRT (tier_1 and tier_2 objects per scenario).
237+
238+
## Jobs
239+
240+
### Job 1
241+
242+
Independent of all other jobs. Modify concept docs and create/remove skill files.
243+
244+
- Modify `plugin/concepts/skill-test.md`:
245+
- Change `## Directory Convention` code block to show `plugin/tests/<path>/<name>/` structure with
246+
`runs/` subdirectory
247+
- Add `## Runs Directory` section after `## Directory Convention` documenting transcript file naming
248+
and how graders read them
249+
- Modify `plugin/concepts/skill-test-results.md`:
250+
- Update `## File Location` to `plugin/tests/<path>/<name>/results.json`
251+
- Replace `test_cases` array entries table with `scenarios` object schema matching the new JSON structure
252+
(showing tier_1 and tier_2 keys with their sub-fields)
253+
- Create `plugin/skills/skill-grader-agent/SKILL.md` with frontmatter as shown in Research Findings and
254+
`!`"${CLAUDE_PLUGIN_ROOT}/client/bin/get-skill" skill-grader-agent "$0"`` directive
255+
- Create `plugin/skills/skill-grader-agent/first-use.md` by copying the body from
256+
`plugin/agents/skill-grader-agent.md` and adding the license header comment block
257+
- Remove `plugin/agents/skill-grader-agent.md` (content moved to skill)
258+
- Remove `plugin/skills/skill-validator-agent/` directory (entire directory)
259+
260+
### Job 2
261+
262+
Migrate all test-cases.json files. Does not overlap with Job 1, Job 3, or Job 4.
263+
264+
For each of the 10 test-cases.json files listed in Research Findings:
265+
1. Read the JSON file
266+
2. For each test case entry, derive the filename from `semantic_unit_id` (strip `unit_` prefix, replace `_` with `-`)
267+
3. Map `category` (uppercase → lowercase) and set `type: behavior`
268+
4. Map assertions to Tier 1 / Tier 2 per the assertion mapping rules
269+
5. Write the `.md` file to the target directory shown in Research Findings
270+
6. Add license header to each new .md file
271+
7. After creating all .md files for a test-cases.json, delete the test-cases.json file
272+
8. Remove empty `test/`, `tests/`, or `benchmark/` directories left behind
273+
274+
### Job 3
275+
276+
Migrate test-results.json files, update ValidateSkillTestFormat, and update Java tests.
277+
Does not overlap with Job 1 or Job 2 (different files).
278+
279+
- For each of the 3 test-results.json files, convert to the new results.json format per Research Findings
280+
(scenarios object with per-tier SPRT data) and write to the new plugin/tests/ location
281+
- In `client/src/main/java/io/github/cowwoc/cat/hooks/write/ValidateSkillTestFormat.java`:
282+
- Change `TEST_MD_PATTERN` from `(?:^|/)plugin/skills/[^/]+/test/[^/]+\.md$`
283+
to `(?:^|/)plugin/tests/.+\.md$`
284+
- In `client/src/test/java/io/github/cowwoc/cat/hooks/test/ValidateSkillTestFormatTest.java`:
285+
- Update any test file paths that use the old `plugin/skills/<skill>/test/` pattern to use
286+
`plugin/tests/<path>/<name>/` paths
287+
- Run `mvn -f client/pom.xml verify -e` and fix any build failures
288+
- Update `index.json` to `status: closed` in the SAME commit as the last implementation commit

.cat/retrospectives/index.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"trigger_interval_days" : 7
66
},
77
"last_retrospective" : "2026-03-23T13:18:51.196642020Z",
8-
"mistake_count_since_last" : 12,
8+
"mistake_count_since_last" : 13,
99
"files" : {
1010
"mistakes" : [ "mistakes-2026-01.json", "mistakes-2026-02.json", "mistakes-2026-03.json" ],
1111
"retrospectives" : [ "retrospectives-2026-01.json", "retrospectives-2026-02.json", "retrospectives-2026-03.json" ]

0 commit comments

Comments
 (0)