# What can drift, seen through how it drifts

> This section covers the coverage grid and its two closed axes.

Page: Architecture · Coverage
Canonical: https://banes-lab.com/software-architecture/coverage#what-can-drift-seen-through-how-it-drifts

This section is stop 69 of 102 in the learning route. Previous: [01 - From intent to predicate](https://banes-lab.com/software-architecture/coverage/an-architecture-is-its-predicate-set.md). Next: [03 - A cell that resists an invariant](https://banes-lab.com/software-architecture/coverage/a-cell-that-resists-an-invariant.md). It builds on [01 - From intent to predicate](https://banes-lab.com/software-architecture/coverage/an-architecture-is-its-predicate-set.md), [01 - An anti-pattern is a decay path](https://banes-lab.com/software-architecture/decay/an-anti-pattern-is-a-decay-path.md).

This section covers the coverage grid and its two closed axes. The [dimensions](https://banes-lab.com/ontology/reasoning/the-dimensions.md) are what can drift and the [lenses](https://banes-lab.com/ontology/reasoning/the-lenses.md) are how it drifts, and a cell is one invariant that must hold, watched by a predicate or declared unwatched with its reason, as shown in [B1·a two axes, one cell](https://banes-lab.com/software-architecture/coverage#what-can-drift-seen-through-how-it-drifts-panel-a) and [B1·b a corner](https://banes-lab.com/software-architecture/coverage#what-can-drift-seen-through-how-it-drifts-panel-b) and typed in [B1·c a rule surface](https://banes-lab.com/software-architecture/coverage#what-can-drift-seen-through-how-it-drifts-panel-c). Because both axes are closed, the cells are enumerable, so the cells nothing watches are enumerable too, and a rule set is measured against the grid rather than against the incidents that happened to produce it.

### Two closed axes

A rule set with no denominator reports how many checks exist, which says nothing about how many drift classes have none. A suite reports hundreds of passing tests, the surface that fails in production was one none of them reached, and the green run was evidence over the wrong set. Without closed axes there is nothing to divide by, so coverage is reported as a count that grows with every incident and never says what is missing.

For this reason coverage is a grid of what can drift against how it drifts, and an unmeasured cell is unknown rather than clean. The axes are closed before anything is counted, so the count has a denominator. In practice, the dimensions along which the system can drift and the lenses through which each drift is seen are named as two lists. Every existing check is placed in the cell it watches, one invariant per cell, and an empty cell is read as a drift class nothing watches.

To check this, take the checks you have and place each in its cell, then count the empty cells. If you cannot place a check, its invariant was never stated, and if you cannot count the empties, the axes were never closed. The grid enumerates where drift can be watched and says nothing about which cells deserve a rule. A full grid is not the goal. The goal is a grid whose every cell is watched, unwatched with a stated reason, or marked undecided, and the undecided cells carry the design decisions still to make.

### The axes, and a cell read off them

A module reaching across a boundary is relation seen relationally, and a [circular dependency](https://banes-lab.com/records/arch/circular-dependency.md) is relation seen structurally. Two files claiming one role is identity seen structurally. A manifest entry rotting is composition seen through evolution. A discriminated union gaining a case nothing handles is change seen sequentially. A registry written and never read is function seen functionally. Intent living in a comment is meaning seen semantically. The same defect at every scale is scale seen fractally, and a convention followed everywhere except here is novelty seen as anomaly.

### Projected onto correctness

The same grid projected onto [correctness](https://banes-lab.com/records/arch/correctness.md) is the [test-surface catalogue](https://banes-lab.com/ontology/reasoning/the-test-surfaces.md). Every surface a unit can fail in names its failure modes, its technique, its predicate and its evidence source, and its verdict domain carries unknown as a value distinct from pass. [Property-based testing](https://banes-lab.com/records/arch/property-based-testing.md) and [specification-based testing](https://banes-lab.com/records/arch/specification-based-testing.md) are techniques a surface names, and [chaos engineering](https://banes-lab.com/records/arch/chaos-engineering.md) is the technique for the surfaces only a running system can fail in.

An unmeasured surface is unknown rather than clean, as described in [unknown is not pass](https://banes-lab.com/disciplined-methodology/verify/unknown-is-not-pass.md) and recorded in [the evidence verdict](https://banes-lab.com/records/algo/evidence-verdict.md). [Test pyramid inversion](https://banes-lab.com/records/arch/test-pyramid-inversion.md) and the [mock mirage](https://banes-lab.com/records/arch/mock-mirage.md) are the two ways a green run stops being evidence, and [completion](https://banes-lab.com/records/algo/coverage-completion.md) is the absence of required surfaces still unknown, never a percentage, because a percentage averages the surfaces that matter with the ones that cannot fail.

B1·a two axes, one cell

```mermaid
flowchart LR
subgraph dimensions["What can drift"]
identity["identity"]
relation["relation"]
change["change"]
meaning["meaning"]
end
subgraph lenses["How it drifts"]
structural["structurally"]
relational["relationally"]
sequential["sequentially"]
semantic["semantically"]
end
cell["A cell · one invariant, watched, unwatched with a reason, or undecided"]
identity --> cell
relation --> cell
change --> cell
meaning --> cell
structural --> cell
relational --> cell
sequential --> cell
semantic --> cell
```

B1·b a corner

```mermaid
block-beta
columns 5
corner[" "] structural["structural"] relational["relational"] sequential["sequential"] semantic["semantic"]
identity["identity"] i1["watched"] i2["unwatched · declared"] i3["undecided"] i4["watched"]
relation["relation"] r1["watched"] r2["watched"] r3["undecided"] r4["unwatched · declared"]
change["change"] c1["undecided"] c2["watched"] c3["watched"] c4["undecided"]
meaning["meaning"] m1["unwatched · declared"] m2["undecided"] m3["watched"] m4["watched"]
```

B1·c a rule surface

```typescript
export const DIMENSIONS = ["identity", "composition", "structure", "relation", "space", "time", "state", "change", "behaviour", "function", "cause", "meaning", "scale", "probability", "novelty"] as const;
export const LENSES = ["structural", "temporal", "spatial", "statistical", "frequency", "sequential", "relational", "behavioural", "functional", "semantic", "causal", "predictive", "anomaly", "evolutionary", "fractal", "transformational", "invariant", "optimisation", "complexity"] as const;

export type Dimension = (typeof DIMENSIONS)[number];
export type Lens = (typeof LENSES)[number];

export type Cell =
| { readonly kind: "watched"; readonly invariant: string; readonly predicate: GateId }
| { readonly kind: "unwatched"; readonly invariant: string; readonly because: string }
| { readonly kind: "undecided"; readonly question: string };

export type CellKey = readonly [Dimension, Lens];
export type RuleSurface = ReadonlyMap<CellKey, Cell | null>;

export const emptyCells = (surface: RuleSurface): readonly CellKey[] =>
[...surface.entries()].flatMap(([cell, held]) => (held === null ? [cell] : []));
```

## Links to

- [The dimensions](https://banes-lab.com/ontology/reasoning/the-dimensions.md)
- [The lenses](https://banes-lab.com/ontology/reasoning/the-lenses.md)
- [Circular Dependency](https://banes-lab.com/records/arch/circular-dependency.md)
- [Correctness](https://banes-lab.com/records/arch/correctness.md)
- [The test surfaces](https://banes-lab.com/ontology/reasoning/the-test-surfaces.md)
- [Property-Based Testing](https://banes-lab.com/records/arch/property-based-testing.md)
- [Specification-Based Testing](https://banes-lab.com/records/arch/specification-based-testing.md)
- [Chaos Engineering](https://banes-lab.com/records/arch/chaos-engineering.md)
- [Unknown is not pass](https://banes-lab.com/disciplined-methodology/verify/unknown-is-not-pass.md)
- [Evidence Verdict](https://banes-lab.com/records/algo/evidence-verdict.md)
- [Test Pyramid Inversion](https://banes-lab.com/records/arch/test-pyramid-inversion.md)
- [Mock Mirage](https://banes-lab.com/records/arch/mock-mirage.md)
- [Coverage Completion](https://banes-lab.com/records/algo/coverage-completion.md)

## Linked from

- [Unknown is not pass](https://banes-lab.com/disciplined-methodology/verify/unknown-is-not-pass.md)
- [Coverage is derived](https://banes-lab.com/disciplined-methodology/verify/coverage-is-derived.md)
- [From intent to predicate](https://banes-lab.com/software-architecture/coverage/an-architecture-is-its-predicate-set.md)
- [The test surfaces](https://banes-lab.com/ontology/reasoning/the-test-surfaces.md)
