What Does 'Resilient' Mean? — Defining Drift and Invariants

Published: (February 3, 2026 at 05:48 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Drift in CSS Design

In Part 1, I argued that CSS architecture should shift from “rules to memorize and follow” to a “feedback system.” But what exactly does resilient (drift‑resistant) design mean? This part defines the phenomenon of design degradation as drift and introduces the concept of invariants to prevent it.

CSS design doesn’t collapse all at once. Small decision inconsistencies accumulate, and by the time you notice, coherence is lost. I call this drift.

Breaking Down

In this series, “breaking down” refers specifically to three things:

  1. Component boundary ambiguity – where one component ends and another begins differs from person to person.
  2. Layout responsibility confusion – whether margin belongs to the parent or child varies file by file.
  3. Naming and structural inconsistency – naming conventions and file organization vary across the project.

Example: Common drift in a BEM project

SituationDrift
One team member writes margin on the child component itself; another specifies it from the parent.“Is this element an independent component or part of its parent?” – answers differ by person.
Modifier granularity varies from file to file.

None of these are “rule violations.” The interpretive latitude in guidelines allows decision drift, and that latitude widens as teams grow.

AI Drift

Introducing AI coding agents doesn’t change the structure. Even with guidelines packed into the context window, output varies where judgment is required. Human drift simply becomes AI drift.

Weakness of Convention‑Based Designs

Convention‑based designs share a structural weakness:

  • Memorization burden – the longer the guidelines, the harder it is for everyone to accurately remember and apply them.
  • Subjective decisions – questions like “where does one component end?” have no objective answer.
  • Verification difficulty – whether something violates a convention can’t be determined mechanically; you can only rely on reviews.

When all three are present, drift is inevitable. Reviews maintain quality only while the reviewer’s judgment stays consistent, and reviewers are human – their judgment drifts too.

Invariants

Programming has the concept of invariants – conditions that must hold at every point in a program (e.g., an array index staying within bounds, an account balance never going negative). These conditions are mechanically enforced through types and assertions.

The same idea applies to CSS architecture: eliminate rules whose answers change based on interpretation, and adopt only conditions that can be mechanically evaluated as true or false.

Concrete Examples

Convention‑based (requires interpretation)Invariant (mechanically verifiable)
“Decompose components into appropriate granularity.”“A Block’s direct children can only be Blocks or Elements.” (terms defined in Part 4)
“Parents manage layout.”margin-top can only be specified from the parent’s > .child selector.
“Keep naming consistent.”Blocks use 2‑word kebab‑case; Elements use a single word.
“Distinguish between state and variation.”Variants use data-variant; States use data-state.

The left column requires human interpretation to judge correctness. The right column can be judged through string‑pattern and selector‑structure matching, making automated lint verification possible. The right‑hand examples are actual invariants used in SpiraCSS, which I’ve developed and use in production. Part 4 covers them in detail.

Properties of a Viable Invariant

Not every rule can become an invariant. To function as one, a rule needs these properties:

  • Binary evaluation – violation or compliance is determined unambiguously (no gray zones).
  • Syntax‑verifiable – can be determined through source‑code syntax analysis alone (no runtime needed).
  • Locally verifiable – can be determined by looking at the target file alone (no project‑wide scanning needed).

If the design is composed entirely of rules meeting these criteria, a lint tool can serve as the “gatekeeper.” Humans don’t need to make judgment calls — just follow the tool’s verdict. The same goes for AI agents.

Addressing Objections

“Isn’t this just freezing preferences rather than defining ‘correctness’?”

That’s a fair objection. “Write margin from the parent” isn’t the only correct approach, but there’s value in fixing design preferences to make all authors converge on the same output — especially when the pool of authors includes both humans and AI. Having an unwavering standard itself supports team productivity.

The Feedback Loop

Defining invariants alone won’t preserve the design. Without detecting violations and communicating what’s wrong and how to fix it, corrections don’t happen. The sequence:

  1. Define invariants.
  2. Detect violations.
  3. Present fix instructions.

forms a feedback loop. The next part dives deeper into designing this loop. When lint returns not just “what’s wrong” but also “how to fix it,” error messages must be thoughtfully crafted.

Next Steps

Part 3 — The Feedback Loop — Designing Lint That Tells You What to Fix and How (later this week)

Resources

  • SpiraCSS – design specs, tools, and source code are open source.
    • Website:
    • GitHub:
Back to Blog

Related posts

Read more »

Build an Accessible Audio Controller

Overview After two days of ARIA theory lessons on freeCodeCamp, the next workshop focused on building an accessible audio controller. The session began with a...

You don't need CSS preprocessor

CSS Pre‑processors: Are They Still Worth It? There was a time when CSS preprocessors seemed like a magical elixir for any CSS problems. It was only necessary to...