Adds the /evaluate-library skill runbook at .claude/skills/evaluate-library/ with SKILL.md (8-filter + 3-prompt protocol, collect-cheap-skip-expensive ordering, trace-write step, skip sentinel), POLICY.md (ADR-022 summary ≤2 pages), TRACE-TEMPLATE.md (complete YAML frontmatter + 11 headings in order), and EXAMPLES/ with one approved (clsx) and one rejected (trpc-to-openapi, named-consumer: fail) worked trace. Updates session-start.sh to surface the skill in session pointers. The skill is auto-registered by the harness on SKILL.md creation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
100 lines
4.6 KiB
Markdown
100 lines
4.6 KiB
Markdown
---
|
|
package: trpc-to-openapi
|
|
version: "^1.2.0"
|
|
tier: core
|
|
decision: rejected
|
|
date: 2026-05-14
|
|
deciders: [danijel, claude-sonnet-4-6]
|
|
adr: null
|
|
filter-results:
|
|
license: MIT
|
|
types: native
|
|
maintenance: active
|
|
boundary-fit: pass
|
|
shadow-check: pass
|
|
eu-residency: n/a
|
|
cve-scan: clean
|
|
named-consumer: fail
|
|
verification-commands:
|
|
- npm info trpc-to-openapi license
|
|
- npm info trpc-to-openapi time.modified
|
|
- pnpm audit --audit-level=moderate
|
|
accepted-cves: []
|
|
---
|
|
|
|
## Filter: license
|
|
|
|
<!-- Result: MIT -->
|
|
|
|
`package.json` declares `"license": "MIT"`. On the allowlist. Pass.
|
|
|
|
## Filter: types
|
|
|
|
<!-- Result: native -->
|
|
|
|
`trpc-to-openapi` ships TypeScript declarations (`.d.ts`) alongside the compiled output. Full API surface typed. Pass.
|
|
|
|
## Filter: maintenance
|
|
|
|
<!-- Result: active -->
|
|
|
|
Last npm release: `1.2.0` published within the past 12 months at evaluation date. GitHub shows active issue triage. Pass.
|
|
|
|
## Filter: boundary-fit
|
|
|
|
<!-- Result: pass -->
|
|
|
|
`trpc-to-openapi` would land in a `core`-tagged package alongside the tRPC router configuration. Core packages are permitted to hold tRPC-adjacent tooling. The library imports `@trpc/server` (already a workspace must-have) and standard `zod` types. No boundary violations under ADR-006 or ADR-010. Pass.
|
|
|
|
## Filter: shadow-check
|
|
|
|
<!-- Result: pass -->
|
|
|
|
No existing workspace library performs OpenAPI spec generation from tRPC routers. `trpc-to-openapi` does not duplicate any locked must-have. Pass.
|
|
|
|
## Filter: eu-residency
|
|
|
|
<!-- Result: n/a -->
|
|
|
|
`trpc-to-openapi` is a pure in-process code-generation utility. It produces an OpenAPI JSON spec at build time or request time; it transmits nothing to a vendor endpoint. EU residency filter does not apply.
|
|
|
|
## Filter: cve-scan
|
|
|
|
<!-- Result: clean -->
|
|
|
|
`pnpm audit --audit-level=moderate` returns 0 vulnerabilities at evaluation time. Pass.
|
|
|
|
## Filter: named-consumer
|
|
|
|
<!-- Result: fail -->
|
|
|
|
**No named consumer exists.**
|
|
|
|
The proposal arose during a 2026-05-14 grill session exploring whether to expose the tRPC router surface as a REST API for external consumers. The session established that **all current callers are TypeScript** and use `createCaller` directly — there are no HTTP REST clients calling the API, and no external consumers are blocked waiting for an OpenAPI spec.
|
|
|
|
The hypothetical consumers cited were:
|
|
|
|
- "External partners might want a REST API someday" — speculative; no partner is waiting.
|
|
- "A mobile client might prefer REST over tRPC-HTTP" — hypothetical; no mobile client exists.
|
|
- "OpenAPI docs improve DX for third-party integrations" — no third-party integration is in flight.
|
|
|
|
The grill-session question "who calls this code path today, or who is blocked waiting for it?" had the honest answer: nobody. The library would have shipped approximately 30 lines of `.meta({...})` annotations per router and a `superjson`-incompatible HTTP handler configuration in exchange for zero downstream consumers — pure carrying cost.
|
|
|
|
This trace exists as a permanent record per ADR-022 §4 so future agents do not re-evaluate `trpc-to-openapi` without first answering whether a named consumer now exists. If a concrete external integration is later planned, re-open this evaluation with the integration as the named consumer, re-run all eight filters, and write a new trace.
|
|
|
|
## Prompt: replaces
|
|
|
|
Nothing is being retired. The adoption would have been additive alongside the existing `createCaller` usage path.
|
|
|
|
## Prompt: migration-cost-out
|
|
|
|
**Hard.** Once `.meta({...})` annotations are added to tRPC procedures, they accumulate across routers over time. Removal requires stripping those annotations, deleting the OpenAPI spec generation step, and coordinating with any REST consumers that may have formed since adoption. The `superjson`-incompatible HTTP handler creates a parallel request path that would need to be decommissioned. Hard-rated because of the scattered annotation surface.
|
|
|
|
## Prompt: alternatives-considered
|
|
|
|
1. **`@anatine/zod-nestjs` + NestJS** — full REST framework alternative; overkill for a tRPC-native repo and would require replacing the tRPC layer entirely. Not a serious alternative for this use case.
|
|
|
|
2. **Custom OpenAPI spec, hand-authored** — maintain a `openapi.yaml` alongside the tRPC router. Zero runtime cost; no dependency; the spec is always exactly what consumers need. Viable if a named consumer materialises and the schema surface is stable. The correct path when named-consumer passes.
|
|
|
|
3. **No action (status quo)** — current approach: TypeScript callers use `createCaller`; no REST surface exposed. Correct given that no named consumer exists today. This is the chosen outcome.
|