cratis-engineering-regression-cluster · git:20261019.0539e65 · 2026-10-19 · sha256 7f5ce1c65bc99a8f

cratis-engineering-regression-cluster git:20261019.0539e65A

Immutable. This exact content never changes and is served at /api/v1/blob/7f5ce1c65bc99a8f.

---
name: cratis-engineering-regression-cluster
description: Stop fixing instances when one surface keeps breaking - name the failure class, add the gate that owns it, prove the gate fails, then fix the instance. Use when a third bug, regression, revert or review finding lands on the same screen, endpoint, command, workflow or module, when the same kind of fix keeps being reapplied, or when asked why something keeps breaking. Not for a first or isolated bug (fix it with a regression specification), for proving a consolidation dropped nothing (use cratis-engineering-consolidation-guard), or for a boundary that reports success after failing (use cratis-engineering-effect-boundaries).
license: LICENSE
---

# The third issue on one surface names a failure class

Each bug fixed alone adds one specification for one symptom. When the same
**surface** (one screen, endpoint, command, query, workflow, module or rule
area) breaks a third time, the instances share a cause that no specification
owns yet, and the fourth instance is already on its way. Stop fixing instances:
name the **failure class**, give it an **owning gate**, then fix the instance.

## Count first

Before fixing an issue, count the earlier ones on its surface:

```bash
gh issue list --state all --search "<surface> in:title,body" --limit 50
git log --oneline -- <paths of the surface>
```

Count bugs, regressions, reverts and review findings, open or closed. Fewer
than three: fix the instance with a regression specification. Three or more:
follow the steps below before writing the fix.

## Steps

1. **Name the failure class** in one sentence that states the property being
   violated, not the symptom. Each earlier issue must be an instance of it, and
   a reader must be able to recognize the next one by it. "Owner filter shows
   archived items" is a symptom; "list filters are not exercised through the
   rendered list by any test" is a class.
2. **Choose the owning gate by enforcement kind**, preferring the earliest that
   can catch the class: an analyzer (compile time), a lint rule, a CI check or
   verification script, or one specification suite that covers every member of
   the class (every filter, every endpoint), not one specification per bug. A
   class that only judgment can catch gets a review checklist entry, and the
   choice is stated as judgment-shaped; see the enforcement rule in
   [authoring-skills.md](../../rules/authoring-skills.md).
3. **Prove the gate fails** on the current broken instance, or on the earlier
   instances with their fixes reverted, before fixing anything. A gate that
   passes on the broken code owns nothing; follow
   [guards-and-fuses.md](../../rules/guards-and-fuses.md) so it cannot pass
   vacuously.
4. **Register the class.** When the repository keeps a failure-class table or
   gate inventory, add one row: class, owning gate, where it runs. Otherwise
   put the class name in the gate's failure message and the specification or
   check name, so the next failure names its class.
5. **Fix the instance**; the gate turns green. Run it with the repository's
   normal gates, and make it a required CI check when it lives in CI.
6. **Close the loop.** Link the earlier issues to the class in the pull request
   comment, and leave a prose rule only for the judgment-shaped part.

## Report

State the surface and the issues counted, the class sentence, the gate and
where it runs, that it failed before the fix and passes after, and anything
left judgment-shaped.

## Pitfalls

- **A fourth instance specification.** Copying the third fix's specification
  for the new symptom covers the symptom, not the class.
- **A prose rule instead of a gate.** Rules nobody enforces were already in
  place for the earlier instances; text costs context and catches nothing.
- **A class named after the symptom.** If the next instance would not be
  recognized by the sentence, the class is still too narrow.
- **A gate that never ran red.** Without the failing run, nothing shows it can
  catch the class.
- **A loose surface.** Three unrelated bugs in one large module are not a
  cluster; narrow the surface until the issues share a cause.