Back to Development
developmentL3 SystematicCode Review & Quality

Architecture guardrails: Bug → Codify → Lint Rule

A systematic process for converting recurring bugs into permanent lint rules turns each incident into an improvement to the quality gate, progressively hardening the codebase against known failure modes.

  • ·AI review agent runs as a first-pass reviewer on every PR before human review
  • ·Lint rules enforce architectural standards (not just style) - the "Bug to Codify to Lint Rule" pipeline is active
  • ·At least 3 architectural guardrail rules have been created from past bugs or incidents
  • ·AI review agent findings are categorized by severity (info, warning, blocking)
  • ·New lint rules are proposed automatically when recurring review comments are detected

Evidence

  • ·CI configuration showing AI review agent as required check
  • ·Lint rule change history showing rules created from incident post-mortems
  • ·AI review agent output logs with severity categories

What It Is

The Bug → Codify → Lint Rule process is a systematic practice where each recurring architectural violation or class of bug is converted into a machine-enforced constraint. When a bug caused by an architectural violation is found, the team doesn't just fix the bug - they codify the constraint as a custom lint rule so the same class of bug can never slip through review again.

The three-step cycle is:

  1. Bug - A bug caused by an architectural violation reaches production (or is caught in review). The team identifies the root cause: "We called the payment service directly from the UI layer, bypassing the validation layer."
  2. Codify - The team articulates the architectural constraint explicitly: "UI layer code must not import from payment module directly - it must go through checkout-service." This is documented as an architectural decision record (ADR).
  3. Lint Rule - The constraint is implemented as a custom lint rule (import restriction, module boundary check, forbidden API usage). The rule is added to CI and fails any future PR that violates it.

At L3 (Systematic), this process is habitual - it happens after every incident where an architectural violation was the root cause. The result is a lint configuration that grows progressively more comprehensive, with each addition representing a real-world failure mode that has been permanently eliminated.

This is distinct from ad-hoc lint rule addition. The Bug → Codify → Lint Rule cycle is triggered by actual failures, not theoretical concerns. Every rule in the configuration represents something that actually went wrong, which means the rules have high relevance and clear justification.

Why It Matters

The compounding nature of this practice is its core value. Each iteration:

  • Permanently eliminates a failure class - The bug that triggered the rule will never happen again via the same path. Not "we'll be more careful" - mechanically impossible to merge.
  • Creates institutional memory in code - The lint rule with its comment ("Added after incident-2024-11: payment calls bypassing validation caused overcharging") is institutional memory that persists through team turnover.
  • Makes the quality gate progressively stronger - A codebase with 50 custom lint rules based on real incidents has a dramatically higher quality floor than one with only default rules. This isn't a step function - it's continuous improvement.
  • Enables faster review and AI generation - Every constraint that's machine-enforced is a constraint that reviewers don't need to mentally check. At L4-L5, where AI agents generate large amounts of code quickly, the lint rules serve as an automated safety net that catches AI code violating constraints the AI wasn't aware of.
  • Surfaces architectural ambiguity - Sometimes the attempt to write a lint rule reveals that the architectural constraint isn't actually clear. "Don't call the database from the HTTP layer" - but what about health check endpoints? The act of codifying the rule forces the team to articulate the constraint precisely.

The process at L4 and L5 extends naturally: as AI agents generate more code, the lint rules protect against AI-specific failure modes. "AI agents tend to use direct SQL rather than the ORM in unfamiliar contexts" becomes a lint rule: "no raw SQL strings outside the migration files." The Bug → Codify → Lint Rule cycle applies to AI-generated bugs as much as human-generated ones.

Tip

Maintain a ARCHITECTURE_RULES.md alongside your lint configuration that maps each custom rule to the incident or decision that created it. This document becomes a valuable onboarding resource - new team members can read the history of architectural decisions and understand why each constraint exists.

Getting Started

6 steps to get from here to the next level

Common Pitfalls

Mistakes teams actually make at this stage - and how to avoid them

How Different Roles See It

B
BobHead of Engineering

Bob's team has had three separate incidents caused by code making direct database calls in HTTP handler functions. Each time, the post-mortem includes "we should be more careful about this." After the third incident, a senior engineer points out that they've said "be more careful" twice before. Bob wants to break the pattern.

What Bob should do - role-specific action plan

S
SarahProductivity Lead

Sarah tracks post-merge bugs as a quality metric. Her data shows that 30% of post-merge bugs over the past year fall into patterns that have appeared before - the same architectural violations causing different surface-level bugs. She wants to demonstrate that quality is improving, but the recurring pattern suggests it isn't.

What Sarah should do - role-specific action plan

V
VictorStaff Engineer - AI Champion

Victor has been writing the same review comment - "use the repository pattern, don't query the DB directly" - for two years. He's written it on 30+ PRs. After a production incident last month where a direct DB call caused a connection pool exhaustion under load, he's ready to automate it.

What Victor should do - role-specific action plan