# Counting copies

> A fact stated in more than one place is not yet a defect.

Page: Methodology · Verify
Canonical: https://banes-lab.com/disciplined-methodology/verify#counting-copies

This section is stop 46 of 102 in the learning route. Previous: [31 - Derived state](https://banes-lab.com/disciplined-methodology/verify/derived-state.md). Next: [33 - Documentation is code](https://banes-lab.com/disciplined-methodology/verify/documentation-is-code.md). It builds on [22 - One home](https://banes-lab.com/disciplined-methodology/build/one-home.md).

A fact stated in more than one place is not yet a defect. [DRY](https://banes-lab.com/records/arch/duplicate-code.md) names the aim, a [dual write](https://banes-lab.com/records/arch/dual-write.md) names the failure, and a walk with a fixed order decides which of the two a given pair is, as shown in [G1·a the walk](https://banes-lab.com/disciplined-methodology/verify#counting-copies-panel-a). The walk asks whether the copies can collapse into one, how many of them claim to be the source, how often each derivation runs, and which consumer each copy reaches. Walked out of order, the same set of copies leads either to a repair that destroys evidence or to a comparison over an edge that cannot exist.

### Count the distinguished copies

Deciding which of two copies is right is guesswork until you count. Two configs disagree, each team believes its own is the source, both get edited, and neither derives from the other. Copying never records which copy was the original, so the walk has to count.

For this reason a duplicate is resolved by counting its distinguished copies, and how often a derivation runs decides whether a copy is a record or a stale one. Every duplicate is decided by its collapse, its count of distinguished copies, its derivation period and its delivery, in that order, rather than by which copy looks newer. In practice, collapse is asked first: where one copy can be derived from the other, the derivable one stops being written, and the divergence can no longer occur. Only where collapse is not available are the distinguished copies counted, and then one resolves to a derivation, zero to a declaration, and many to a decision. Next, the period of every derivation edge is read, because a copy that is regenerated is an instance of the source that can go stale, while a copy fixed once at creation is a record. Last comes what each copy reaches, because a set of copies can be fully collapsed and still deliver nothing.

To check this, name the source of a duplicated fact and the period at which its copies refresh. A copy whose refresh nothing schedules is stale from the first change to its source. A one-shot copy, written once against the fact as it stood at the time, is a record rather than a stale instance. Collapsing it would destroy evidence rather than remove duplication, so the repair is inverted: the copies are diagnosed and the source is repaired.

Refusing to pick a source when there are zero is the [directed acyclic graph](https://banes-lab.com/records/arch/directed-acyclic-graph.md) ruling in the form a duplicate reaches it. A second declaration is an edge rather than a fact standing beside the first, so a set of copies is a [dependency graph](https://banes-lab.com/records/arch/dependency-graph.md) and collapsing it means choosing a direction along it; a cycle among the copies is a [circular dependency](https://banes-lab.com/records/arch/circular-dependency.md) between facts. Where no copy is distinguished, the graph has no root, and a collapse would have to choose one that the structure does not supply. Refusing is the whole of the correct behaviour there, and it is the part a builder is most tempted to improve: a tiebreak applied to a cyclic set turns a correct refusal into a confident wrong answer.

Every repair of a divergence first asks which side is authoritative. A join can report that two declarations agree, but never that the value they agree on is right. Where one side cites the other, the direction is forced and the repair is bookkeeping. Where both sides declare, the repair is a decision about which value is correct, and the pull is always toward whichever side is free to change. Converging on the cheap side and reporting it as maintenance is the substitution to refuse. A comparison's green result is a [correctness](https://banes-lab.com/records/arch/correctness.md) verdict only where one side is authoritative; elsewhere it says the two match without saying that either is right.

G1·a the walk

```mermaid
flowchart TB
dup["Two copies of one fact"]
collapse{"Is either derivable from the other?"}
reduce["One declaration, one derivation · the divergence becomes unrepresentable"]
count{"How many claim to be the source?"}
one["One · a source exists"]
zero["Zero · a cycle, each points at another"]
many["Many · an undecided choice"]
derive["Make every other copy a derivation"]
declare["Declare one home and break the cycle"]
decide["Decide, then derive"]
period{"How often does the derivation run?"}
record["A record"]
stale["Drift"]
dup --> collapse
collapse -- yes --> reduce
collapse -- no --> count
count -- one --> one --> derive
count -- zero --> zero --> declare
count -- many --> many --> decide
derive --> period
period -- often --> record
period -- never --> stale
```

## Links to

- [Do Not Repeat Yourself (DRY)](https://banes-lab.com/records/arch/duplicate-code.md)
- [Dual Write](https://banes-lab.com/records/arch/dual-write.md)
- [Directed Acyclic Graph (DAG)](https://banes-lab.com/records/arch/directed-acyclic-graph.md)
- [Dependency Graph](https://banes-lab.com/records/arch/dependency-graph.md)
- [Circular Dependency](https://banes-lab.com/records/arch/circular-dependency.md)
- [Correctness](https://banes-lab.com/records/arch/correctness.md)
