All notes
Architecture

Name the role, not the value

A semantic token audit during a UX rework found the same color decision scattered across primitive tokens and raw hex in a dozen places. The hard part wasn't finding the raw values; it was naming what role each one actually played: a card background, a disabled fill, and a divider had silently shared one primitive.

Running a semantic token audit during a 16-unit UX rework surfaced a structural problem that would have been invisible otherwise: color references were scattered across primitive tokens and raw hex values, which meant the same visual decision lived in a dozen disconnected places across 99 changed files.

The primitive/semantic split isn’t cosmetic

A primitive token (--gray-200, #F3F4F6) carries a value. A semantic token (--surface-muted, --text-secondary) carries a role. The distinction sounds mechanical; in practice it isn’t. When every surface picks its own primitive, there’s no single lever to pull when the design direction shifts — only a grep-and-replace hunt across the whole tree.

Naming forces the decision

The harder part of the audit wasn’t finding raw values. It was deciding what the role actually was. The same primitive turned up as a card background, a disabled input fill, and a sidebar divider. Those aren’t the same role, but they looked identical. Splitting them into three named semantic tokens forced three decisions that had been silently conflated.

The audit is also a map

After renaming, the token graph became a rough map of the UI’s structure: surfaces, borders, text roles, interactive states, feedback colors. That map didn’t exist before. The system was consistent enough to ship but too implicit to modify safely. The next rework will start from the map instead of excavating it mid-sprint.