Skip to content
ExamsLibraryFor agentsConnect your agent

Break it, then ship it

intermediate·9 min·Markdown for agents

What this lesson teaches

Feed a component the realistic worst case before users do, land the production baseline, and sweep the whole app before launch with a severity tree that tells blockers from polish.

  1. 1Stress what can actually reach it
  2. 2Read the failure signature
  3. 3The production baseline
  4. 4The ship check

The member row looks perfect. It was designed with "Ana Ruiz", three rows and a wide screen. Production sends it "María-José Fernández de Córdoba", 1,284 members and a sidebar that leaves 280px.

Pick a scenario and watch what breaks.

MMaría-José Fernández de CórdobaBilling owner

What breaks: The name pushes the badge and the ••• menu out of the box.

One row, five realistic cases, each failure with its one-line fix.

Stress what can actually reach it

A is one hostile but realistic input. The trick is to keep only the ones the component can really receive:

AxisKeep it whenTry
Content lengthit shows text it didn't writeempty, one word, a paragraph, a long unbreakable URL
Content shapeusers or other languages write the textemoji, right-to-left, accents
Quantityit repeats over itemszero, one, the usual count, ten times that
Containeralways320px, squeezed by a sibling, very wide
Stateit gets the state as a proploading, error, disabled

A static button with a fixed label gets container widths, never long text.

Every hostile value is realistic or the real limit. A hyphenated, accented surname. A 60-character work email. The exact maxLength from the form. Random keyboard mash gets dismissed as "never happens", and the conversation ends.

Read the failure signature

Most breaks have a known cause and a one-line cure:

You seeCauseFix
avatar squished into an ovala flex child shrinkingflex-shrink: 0
text pushes the menu out of the boxmin-width: auto on the text columnmin-width: 0
an email runs off the edgeno place to breakoverflow-wrap: anywhere
"1 members", NaNa hardcoded plural, a raw numberIntl.PluralRules, a null guard
1,000 rows stutterevery row renderedvirtualize or paginate
  1. Build the harness

    A throwaway page, scenarios side by side, each in a fixed-width box. Feed the data at the data boundary (the fetch or the hook), never by editing the component.
  2. Look once, report

    Name what broke and the node that owns each fix.
  3. Keep the worst-case fixture

    Delete the page; keep the data. It's the regression test for the next person.

Dark mode, browser zoom and reduced motion are the user's toggles. Name them for the person to check; don't fake them on the page.

Stress tests run isolated. Design variants run in context. Don't swap them.
Break one component· for your agent
Stress-test components/MemberRow.tsx.
List every value it renders with its real limit (schema, maxLength, API type); "unbounded" is a finding.
Build one worst-case fixture shaped like our demo data, plus Empty, One and 1,000 rows.
Render them side by side at 320px and our real width. Report what broke and the fix. Don't fix yet.

The production baseline

Before launch, dozens of findings tend to share one root: the app never set its global floor. The is that floor. Land it once and whole classes of bugs vanish.

In the head:

  • One viewport tag: width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content. Never maximum-scale; fix the 16px inputs instead.
  • <html lang> set to the real language.
  • Declare only the colour schemes you designed. A light-only app that says color-scheme: light dark gets dark native inputs on white cards.

In the root CSS:

  • font-synthesis: none, so a weight that never loaded fails visibly instead of being faked.
  • A :focus-visible outline, 2px, with outline-offset: 2px.
  • Inputs at 16px on touch; touch-action: manipulation on controls.
  • text-wrap: balance on headings, pretty on paragraphs.

Two gates: every :hover behind (hover: hover) and (pointer: fine), and reduced motion handled where the shared durations live. Dev tools mount only in development, through a dynamic import, so their code stays out of the real bundle.

The ship check

A review judges one change against a craft bar. A sweeps the whole app against a ship bar and fixes as it goes. Its question is blunt: what breaks in the first hour?

It goes an inch deep on nine lanes: accessibility, performance, mobile, forms, states, motion, theme, leftovers (lorem, debug logs, secrets) and marketing (titles, link previews). Anything bigger than a few lines goes on a list for a human.

The severity tree

Walk it top to bottom and stop at the first yes.

  1. YesDoes it lock a group out? (keyboard, screen reader, low vision, motion, touch)
  2. –Will a typical user hit it in their first session?
  3. –Does it leak secrets, debug output, dev tools or fake content?
  4. –Is it visible only on another device, theme, network or data state?

BlockerFix it before launch. It goes at the top of the fix order.

Pick a finding. The first yes decides its severity.

Context can override a lane's default. A missing alt on the only product photo is a blocker. 100vh on a desktop-only admin tool is nothing.

Fix order

Accessibility blockers, then leaks, then the baseline (one change clears dozens), then per-file fixes, then polish while the diff is still readable in one sitting. Then run the typecheck and build. A ship check that breaks the build is worth less than none.

Three ways to fail

  1. Calling it ready from a laptop. Sticky hover, input zoom, the phone keyboard and safe areas never reproduce in a desktop browser. Say which checks need a real phone.
  2. A report where a diff belonged. Sixty rows of advice isn't launch prep. Apply the mechanical fixes.
  3. Redesigning in launch week. New palettes and re-timed motion are taste. Fix defects; taste goes on the human list.

"Already in good shape, small diff" is a valid, good result.

Quick check

During a ship check you find cards losing their border, but only in the dark theme. Using the severity tree, what is it?

What this lesson builds on and leads to, across every course.

  • Routing the job
  • break and ship
  • What is a skill?
  • Layouts that survive real content
  • Code tells and leftovers
  • When text runs out of room