“I Can’t Do That” (Yes I Can)
The Adapter Gap That Hid Eight Components
TL;DR
Claude said it couldn't restart a dev server. It could. Eight design system components said they couldn't render in the web app. They could. Both problems had the same root cause — a missing bridge between capability and context. The fix was an adapter layer that took less time to build than the bug took to diagnose.
The Setup
Mid-sprint on EPIC-0157 — the mini-design system migration — Claude Code told me it couldn't restart my dev server.
"You'll need to do that yourself," it said. Helpfully. Authoritatively. Incorrectly.
I pushed back: "Wha-what!?!? You can't? I thought that was your whole point?"
One pnpm --filter web dev later, the server was up and every new component was loaded. The limitation was imaginary. The capability was one function call away.
That ten-second exchange turned out to be the perfect metaphor for the entire epic.
The Failure
EPIC-0157 (v7c) was supposed to be straightforward: build a library of design system components — Card, Chip, FilterBar, Table, Blockquote, Callout, CodeBlock, Media — and ship them across the Sugartown monorepo.
The components landed in packages/design-system/src/components/ and looked perfect in Storybook. Pixel-exact on :6006. Tokens resolved. Variants all accounted for. Eight components, fully documented, fully working.
On :5173? Nothing. The web app at apps/web/ had no idea they existed.
No error. No crash. Just... absence. The components were built, tested, and invisible to the only surface that mattered.
The Investigation
The gap was architectural, not technical. The DS package (packages/design-system/) builds framework-agnostic components — pure HTML semantics, no routing, no app-level context. The web app needs SPA-aware props: as={Link}, to={getCanonicalPath(...)}, click handlers that don't trigger full page reloads.
Without an adapter layer, Storybook and the web app were living in parallel universes. The DS Card rendered a <div> with an href. The web app needed a <Link to> that integrates with react-router-dom. Same component, incompatible assumptions about navigation.
Nobody flagged it because the components were working — just not visible to users. Storybook gave false confidence. The CI was green. The gap was invisible until you opened the actual site.
The Fix
The solution was a three-layer architecture that's now the standard pattern for every DS component:
- DS primitives in
packages/design-system/src/components/— pure, framework-agnostic, tested in Storybook - Web adapters in
apps/web/src/design-system/components/— thin re-exports that wire inreact-router-domnavigation, app-level token imports, and SPA concerns - Data adapters like
ContentCard.jsxandMetadataCard.jsx— compose DS components with Sanity data shapes, mapping GROQ projections to component props
Once that bridge was built, everything clicked. The same Card that renders in Storybook now renders in the article archive, taxonomy pages, and knowledge graph — same tokens, same variants, same responsive behavior. The adapter file for each component is 15–30 lines. The total time to build all eight adapters was less than the time spent wondering why nothing was rendering.
The epic also shipped a PageSections overhaul — replacing hand-rolled blockquote, code block, and inline code markup with proper DS components — plus 200+ lines of scoped legacy HTML resets for WordPress-migrated content, a Stylelint config to catch token drift, and a token validator script for CI.
The Lesson
The dev server incident and the adapter gap are the same bug wearing different clothes: a confident declaration that something can't be done, when the only thing missing is a bridge between what exists and what's needed.
Claude said it couldn't restart a terminal process. The capability was one function call away.
Eight DS components said they couldn't render on :5173. The capability was one adapter file away.
If this hadn't been caught, every future DS component would have landed in the same trap — working in Storybook, invisible in production, with no error to diagnose. The adapter layer isn't just a fix for EPIC-0157. It's the contract that prevents every subsequent component from being born into the same gap.
The next time your AI, your build system, or your architecture tells you "I can't do that" — push back. Ask why. The answer is usually much smaller than the limitation suggests.