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>
4.3 KiB
package, version, tier, decision, date, deciders, adr, filter-results, verification-commands, accepted-cves
| package | version | tier | decision | date | deciders | adr | filter-results | verification-commands | accepted-cves | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| clsx | ^2.1.1 | feature | approved | 2026-05-14 |
|
null |
|
|
Filter: license
package.json declares "license": "MIT". MIT is on the allowlist. Pass.
Filter: types
clsx ships its own .d.ts declarations at dist/clsx.d.ts. No @types/clsx package needed.
The TypeScript surface covers the full public API (ClassValue, overloads). Pass.
Filter: maintenance
Last npm release: 2.1.1 published 2024-02-06 (15 months ago at evaluation date — within the 18-month threshold). GitHub shows open PR/issue activity within the last 3 months. The library is small, intentionally stable, and actively maintained. Pass.
Filter: boundary-fit
clsx is a pure string-concatenation utility. It imports nothing from Node.js or browser globals; it has zero transitive dependencies. Adding it to packages/navigation as a feature-tagged package introduces no boundary violations under ADR-006 or ADR-010. It does not import @sentry/*, @opentelemetry/*, or any core-reserved vendor SDK. Pass.
Filter: shadow-check
The locked workspace must-haves are: zod, inversify, payload, @trpc/server, superjson, reflect-metadata. None of these perform CSS class-name composition. There is no existing utility in the workspace for this purpose. Pass.
Filter: eu-residency
clsx is a pure in-process string utility. It performs no network calls, transmits no user data, and has no SaaS endpoint. EU residency filter does not apply.
Filter: cve-scan
pnpm audit --audit-level=moderate returns 0 vulnerabilities for clsx@2.1.1 at evaluation time. No accepted advisories.
Filter: named-consumer
Named consumer: packages/navigation/src/ui/components/navigation-menu.tsx — the NavigationMenuLink component must compute conditional class names for the active/inactive link state. Without clsx this is implemented as a ternary chain that becomes unreadable past three conditions. The component exists today; this is not a hypothetical future use case.
Secondary consumer: packages/navigation/src/ui/components/mobile-nav.tsx — open-state drawer overlay class computation. Both components are blocked on this adoption.
Prompt: replaces
Replaces inline ternary chains like `base-class ${isActive ? 'active' : ''} ${isDisabled ? 'disabled' : ''}`. No library is being retired — this is a first-time adoption of a class-composition utility. No parallel adoption risk.
Prompt: migration-cost-out
Mechanical. clsx is called only at the component leaf level. Removal means replacing clsx(...) calls with equivalent template-literal ternaries — a mechanical sed-style refactor bounded to the packages/navigation/src/ui/ subtree. No data format dependencies, no vendor lock-in, no protocol coupling.
Prompt: alternatives-considered
-
classnames— functional equivalent, MIT, widely used. Rejected in favour ofclsxbecauseclsxis the successor written by the same author with better TypeScript support and 2× faster benchmarks at comparable bundle size (330 B vs 440 B minzipped).classnameswould also pass all eight filters;clsxis strictly preferable. -
Inline ternary chains (no library) — the current approach. Adequate for one or two conditions; degrades rapidly past three. The
navigation-menucomponent already has four conditional classes; this is the threshold where a utility library pays for itself. Rejected as the status quo. -
tailwind-merge— superset ofclsxthat also de-duplicates conflicting Tailwind classes. Overkill for this use case (navigation components use a small, non-conflicting class set). Higher migration cost out (data-format dependency on Tailwind class semantics). Deferred.