Skip to content

Commit 3700a92

Browse files
authored
v0.18.11.0 feat: Track 2B (audit cutover) + Track 4C (skill prose corpus) — suite 113s→13s (#63)
* chore: gitignore node_modules * feat(test): Track 4C — LLM-as-judge for skill prose (v0.18.10.0) `tests/helpers/llm-judge.ts` exposes `callJudge<T>(prompt, validator)` — an Anthropic SDK wrapper hardened against the failure modes the eng-review surfaced: maxRetries:0 (no compounding retries), one explicit 1× 429 retry, stop_reason check before regex extract, baked-in validator, strict isJudgeScore predicate (rejects NaN/Infinity/decimals/0/6/null/wrong-types/ empty-reasoning), pinned Sonnet model + temperature:0 + max_tokens:1024. `tests/llm-judge.test.ts` runs 13 mocked-Anthropic-client unit tests covering every helper branch: happy path, stop_reason mismatch, no-JSON, JSON.parse failure, validator rejection, 429 retry success, non-429 no-retry, plus 6 isJudgeScore cases. `tests/skill-llm-eval.test.ts` is the paid evaluation, gated on `process.env.EVALS === '1'` (exact match) plus a strict ANTHROPIC_API_KEY check that throws if EVALS=1 without a key. Sequential test.each over 4 fixtures in `tests/fixtures/skill-prose-corpus/` (3 positive: roadmap- reassessment, test-plan-extraction, pair-review-test-list; plus 1 shallow negative-control). Each fixture is markdown with YAML frontmatter carrying provenance (source skill commit, repo commit, input prompt, model, UTC timestamp, worktree state). Positive fixtures must score ≥3 on every axis; negative-control must score ≤2 on at least one axis (catches the failure mode where the judge rewards plausible-sounding prose over substance). 60s per-test timeout. Cost ~\$0.05–0.15 per EVALS=1 run. Touchfiles map gains `tests/skill-llm-eval.test.ts → tests/fixtures/ skill-prose-corpus/**` so fixture edits select only the eval test. CLAUDE.md ## Testing documents the EVALS=1 contract. PROGRESS row + CHANGELOG entry capture the locked decisions and codex catches. @anthropic-ai/sdk added as devDependency; bun.lock committed. Source: /plan-eng-review session in workspace valletta (kbitz/llm-judge- skill-prose, 2026-05-03), 14 decisions resolved, 10 codex catches batch- applied. Tool-use migration + judge-floor tightening 3→4 deferred to ROADMAP Future. The 4-fixture corpus is initial-synthesized (each fixture's provenance documents this); replace with real captures as the skills produce them. * feat: Track 2B — cut bin/roadmap-audit over to TS implementation Track 2A (v0.18.6.0) shipped the TS port at src/audit/** as "dark code" with full byte-parity verified by tests/audit-shadow.test.ts. The binary at bin/roadmap-audit was never wired up, so the snapshot suite kept paying the bash cost — and tests/audit-shadow.test.ts paid it a second time per fixture for parity verification. Cutover: bin/roadmap-audit becomes a 7-line POSIX-sh shim exec bun "$(dirname "$0")/../src/audit/cli.ts" "$@" tests/audit-shadow.test.ts deleted — parity check is obsolete when the runner IS the oracle. The 3,868-line bash binary is preserved in git history at e4f883b (PR #58, the original "dark code" commit). Manual touchfile entries for tests/{audit-snapshots,audit-cli-contract} .test.ts gain src/audit/** so audit code edits retrigger the snapshot suite under diff selection (the static import graph doesn't connect them because the tests spawn the binary rather than importing). Measured impact on a 2-core MacBook: tests/audit-snapshots.test.ts 111s → 7.3s (~15×) full suite (bun run test:full) 113s → 32s (~3.5×) test count: 828 → 805 (delta = the 23 deleted shadow parity tests) Phase 1's stated end-state ("bin/roadmap-audit is a compiled bun binary") is now met — shim form rather than `bun build --compile` artifact, but equivalent semantics with simpler deploy (no per-platform binary, source grep-able at src/audit/**, instant dev iteration without rebuilds). ROADMAP.md gains "Track 2B: Cut bin/roadmap-audit over to TS implementation ✓ Complete" under Group 2. * refactor: drop SDK eval path, replace with in-session routing rule The Track 4C eng-review locked an SDK-driven judge path: tests/helpers/ llm-judge.ts (Anthropic SDK wrapper), tests/llm-judge.test.ts (mocked units), tests/skill-llm-eval.test.ts (paid eval gated on EVALS=1 + ANTHROPIC_API_KEY). The plan was implemented and reviewed during /ship, then reconsidered: - The eval test only runs on machines that already have `claude` authenticated. It never runs in CI. - Requiring a separate ANTHROPIC_API_KEY plus a separate Anthropic SDK dependency adds setup friction with no ecological payoff — the user is the only person running it, on a machine that's already paying for Claude via Claude Code. - The corpus + rubric retain their value as calibration material; the test infrastructure around them does not. Dropping: - tests/helpers/llm-judge.ts (callJudge helper, 173 LOC) - tests/llm-judge.test.ts (13 mocked unit tests, 135 LOC) - tests/skill-llm-eval.test.ts (paid eval test, 165 LOC) - @anthropic-ai/sdk devDependency - bun.lock (no deps remaining) - tests/skill-llm-eval.test.ts touchfiles entry Keeping: - tests/fixtures/skill-prose-corpus/ (4 reference fixtures, full YAML-frontmatter provenance preserved) - The three-axis rubric (clarity / completeness / actionability, 1–5 each, ≥3 on positives, ≤2 on at least one axis for the control) Adding (CLAUDE.md ## Testing): Routing rule — when skills/*.md is edited in a session, Claude proactively recommends judging the changed prose against the corpus and rubric in-session. No new code, no new dep, no new env var, no separate billing — uses the existing Claude Code session with prompt caching across fixtures. Stale Future entries removed: - "Migrate callJudge to tool-use forced JSON" (no callJudge to migrate) - "Raise judge floor 3 → 4 after 5–10 EVALS runs" (no scheduled run to retune) ROADMAP Track 4C entry rewritten to reflect the actual shipped shape and marked ✓ Complete. CHANGELOG and PROGRESS rows rewritten. Suite runtime: 32s → 13.6s (the SDK was apparently loading 18s of transitive deps just to skip the test). Total impact across the PR (Track 2B + Track 4C combined): full bun test:full was 113s before the cutover, now 13.6s on the same hardware with one less dep.
1 parent ae63c46 commit 3700a92

14 files changed

Lines changed: 486 additions & 4016 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
# Conductor context
22
.context/
3+
4+
# Bun / Node
5+
node_modules/

CHANGELOG.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,74 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [0.18.11.0] - 2026-05-04
6+
7+
### Changed (Track 2B — bin/roadmap-audit cutover to TS)
8+
9+
`bin/roadmap-audit` is now a 7-line POSIX-sh shim that invokes
10+
`src/audit/cli.ts` via `bun`. Track 2A (v0.18.6.0) shipped the TS port
11+
with full byte-parity verified by `tests/audit-shadow.test.ts` but never
12+
wired the binary up — the test ran every snapshot fixture twice (bash
13+
oracle + TS shadow) and the snapshot suite continued paying bash cost.
14+
The cutover makes the TS implementation the single source of truth.
15+
`tests/audit-shadow.test.ts` is deleted (parity check is obsolete: oracle
16+
and runner are now the same code). Manual touchfile entries for
17+
`tests/audit-snapshots.test.ts` and `tests/audit-cli-contract.test.ts`
18+
gain `src/audit/**` so audit code edits retrigger the snapshot suite via
19+
diff selection. The 3,868-line bash binary is preserved in git history
20+
at commit `e4f883b` (PR #58) for archaeology — no recovery path needed
21+
since parity was verified at the time of port.
22+
23+
**Measured impact on a 2-core MacBook:**
24+
`tests/audit-snapshots.test.ts` 111s → 7.3s (~15×). Full suite via
25+
`bun run test:full` 113s → 32s (~3.5×). Phase 1's stated end-state
26+
("`bin/roadmap-audit` is a compiled bun binary") is met (shim form, not
27+
`bun build --compile` artifact — equivalent semantics, simpler deploy:
28+
no per-platform binary, source is grep-able at `src/audit/**`). The
29+
remaining ~32s suite is dominated by `tests/update.test.ts` (~11s,
30+
shells out to `bin/update-{check,run}` and the bash `setup` script) —
31+
that's the next leverage point but lives in Group 5's install pipeline
32+
scope, not Group 2.
33+
34+
### Added (Track 4C — Skill prose corpus + in-session judging routing rule)
35+
36+
`tests/fixtures/skill-prose-corpus/` ships 4 markdown fixtures with rich
37+
YAML-frontmatter provenance: 3 positive examples representing what good
38+
output looks like for `/roadmap` reassessment, `/test-plan` extraction,
39+
and `/pair-review` test-list generation, plus a `4-shallow-control`
40+
negative example that's deliberately vague and generic. Each fixture
41+
records its source skill commit, the repo commit at capture time, the
42+
input prompt that produced the prose, the generation model, a UTC
43+
timestamp, and the worktree state — so future replacements with
44+
real-captured runs can match the structural contract.
45+
46+
The corpus is **reference material, not a test fixture.** There is no
47+
automated judge running under `bun test`. The eng-review's original SDK
48+
+ `EVALS=1` + `ANTHROPIC_API_KEY` pattern was reconsidered during /ship
49+
and dropped: the test only runs on machines that already have `claude`
50+
authenticated (it never runs in CI), so requiring a separate API key
51+
plus a separate Anthropic SDK dependency was setup friction with no
52+
ecological payoff. Instead, `CLAUDE.md ## Testing` adds a routing rule:
53+
when `skills/*.md` is edited in a session, Claude proactively recommends
54+
judging the changed prose against the corpus and the three-axis rubric
55+
(clarity / completeness / actionability, 1–5 each, ≥3 expected on
56+
positives, ≤2 expected on at least one axis for the control) in-session.
57+
Cost is whatever the existing Claude Code session is paying anyway with
58+
prompt caching across fixtures; cadence is opportunistic (only on real
59+
prose changes), not scheduled.
60+
61+
This shape moves the workflow from "rare paid test that nobody runs" to
62+
"automatic prompt at the moment that warrants it" while keeping the
63+
fixtures + rubric as the calibration anchor. The two follow-ups the
64+
eng-review deferred to `Future` (tool-use migration, judge-floor
65+
tightening 3 → 4) are obsolete in this shape: there's no judge code to
66+
migrate and no scheduled run to retune.
67+
68+
### Changed
69+
70+
`node_modules/` added to `.gitignore` (was previously leaking into
71+
untracked file lists during /ship cycles).
72+
573
## [0.18.10.0] - 2026-05-04
674

775
### Added (Track 4D — Audit-compliance test for gstack-extend invariants)

CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ git diff tests/fixtures/source-tag-hash-corpus.json # review hash drift
3636

3737
`scripts/score-extractor.ts` is a manual harness for scoring `/test-plan` extractor JSON output against vendored fixtures (`tests/fixtures/extractor-corpus/`). Run via `bun scripts/score-extractor.ts --help`.
3838

39+
`tests/fixtures/skill-prose-corpus/` is a reference corpus of skill output prose — 3 positive examples (`/roadmap` reassessment, `/test-plan` extraction, `/pair-review` test list) plus a `4-shallow-control` negative control. There is no automated judge test; the corpus is calibration material for the rubric (clarity / completeness / actionability, 1–5 each, ≥3 expected on positives, ≤2 expected on at least one axis for the control). When skill prose changes — i.e. any edit to `skills/*.md` in a session — Claude should proactively recommend judging the changed prose against the corpus and rubric in-session. Sample request: "score the new skill prose against tests/fixtures/skill-prose-corpus and the rubric." This runs in the existing Claude Code session (no API key, no separate billing, prompt caching across fixtures), keeps the human in the loop for taste decisions, and skips the cost overhead of an SDK-driven test that would only run on this machine anyway.
40+
3941
## Skill routing
4042

4143
When the user's request matches an available skill, ALWAYS invoke it using the Skill

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.18.10.0
1+
0.18.11.0

0 commit comments

Comments
 (0)