test(server): unit-test skill-loader template + dispatch prompt builder (#273 follow-up) #287

Merged
charles merged 1 commit from test/s11-skill-loader into main 2026-04-23 23:08:29 +00:00
Collaborator

PR #273 s11 extraction follow-up. Covers skill-loader.ts.

Coverage (18 tests across 8 describe blocks)

  • interpolate — string/numeric sub, repeats, unknown-placeholder fallback to literal {{key}}, non-word keys skipped, no-placeholder passthrough
  • STATELESS_SKILLS — pinned to {review, design-review}; tripwire against silent additions
  • skillForEvent — stateless skill always returns base; no-session → base; active session → -delta; delta missing → fallback to base
  • buildPromptForDispatch — interpolates + no appendix heading when null; appends under heading when set; whitespace-only appendix treated as empty
  • shouldApplyCavemancaveman: true unconditional; caveman_labels label-gated; missing token_economy short-circuits to false
  • maybeApplyCavemanAppendix — passthrough when not applied; appended for caveman: true; appended on label match
  • applyArtifactStyleAppendix — always appends; empty task safe

Behaviour surprises

  1. interpolate's regex is /\{\{(\w+)\}\}/g — placeholders with hyphens or dots ({{repo.owner}}) are silently ignored. Test pins the current contract.
  2. shouldApplyCaveman short-circuits to false when token_economy is undefined — deliberate legacy-fixture escape hatch; noted in-line.
  3. skillForEvent's delta-fallback path is a bare try/catch; any file-read error silently falls back to the full template. Tested via breakdown (no delta variant). If someone adds breakdown-delta.md, this test will need a new skill name.
  4. skillForAgent is not in skill-loader.ts despite what the task brief said — it lives in http/webhook-routing.ts and already has dedicated coverage at webhook-routing.test.ts:160. Not duplicated.

Isolation seam

CLAUDE_HOOKS_STATE_DIR + mkdtemp in beforeEach (same pattern as sessions.test.ts), plus clearing the module-level skillCache before each test. No mock.module.

Checks

  • bunx tsc --noEmit -p apps/server/tsconfig.json — EXIT=0
  • bun test apps/server/src/domain/analytics/skill-loader.test.ts — 18/18 pass (~55 ms)
  • Full suite: +18 passes, no regressions
PR #273 s11 extraction follow-up. Covers `skill-loader.ts`. ## Coverage (18 tests across 8 describe blocks) - `interpolate` — string/numeric sub, repeats, unknown-placeholder fallback to literal `{{key}}`, non-word keys skipped, no-placeholder passthrough - `STATELESS_SKILLS` — pinned to `{review, design-review}`; tripwire against silent additions - `skillForEvent` — stateless skill always returns base; no-session → base; active session → `-delta`; delta missing → fallback to base - `buildPromptForDispatch` — interpolates + no appendix heading when null; appends under heading when set; whitespace-only appendix treated as empty - `shouldApplyCaveman` — `caveman: true` unconditional; `caveman_labels` label-gated; missing `token_economy` short-circuits to false - `maybeApplyCavemanAppendix` — passthrough when not applied; appended for `caveman: true`; appended on label match - `applyArtifactStyleAppendix` — always appends; empty task safe ## Behaviour surprises 1. `interpolate`'s regex is `/\{\{(\w+)\}\}/g` — placeholders with hyphens or dots (`{{repo.owner}}`) are silently ignored. Test pins the current contract. 2. `shouldApplyCaveman` short-circuits to `false` when `token_economy` is `undefined` — deliberate legacy-fixture escape hatch; noted in-line. 3. `skillForEvent`'s delta-fallback path is a bare `try/catch`; any file-read error silently falls back to the full template. Tested via `breakdown` (no delta variant). If someone adds `breakdown-delta.md`, this test will need a new skill name. 4. `skillForAgent` is **not** in `skill-loader.ts` despite what the task brief said — it lives in `http/webhook-routing.ts` and already has dedicated coverage at `webhook-routing.test.ts:160`. Not duplicated. ## Isolation seam `CLAUDE_HOOKS_STATE_DIR` + `mkdtemp` in `beforeEach` (same pattern as `sessions.test.ts`), plus clearing the module-level `skillCache` before each test. No `mock.module`. ## Checks - `bunx tsc --noEmit -p apps/server/tsconfig.json` — EXIT=0 - `bun test apps/server/src/domain/analytics/skill-loader.test.ts` — 18/18 pass (~55 ms) - Full suite: +18 passes, no regressions
test(server): unit-test skill-loader template + dispatch prompt builder (#273 follow-up)
All checks were successful
qa / qa (pull_request) Successful in 4m10s
qa / dockerfile (pull_request) Successful in 10s
ea7336349e
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
charles deleted branch test/s11-skill-loader 2026-04-23 23:08:30 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!287
No description provided.