# One home

> Every fact has one home, as shown in one limit].

Page: Methodology · Build
Canonical: https://banes-lab.com/disciplined-methodology/build#one-home

This section is stop 36 of 102 in the learning route. Previous: [21 - Tools live in the tree](https://banes-lab.com/disciplined-methodology/build/tools-live-in-the-tree.md). Next: [23 - The filesystem is the architecture](https://banes-lab.com/disciplined-methodology/build/the-filesystem-is-the-architecture.md).

Every fact has one home, as shown in [F1·c one limit](https://banes-lab.com/disciplined-methodology/build#one-home-panel-c). Any other place that repeats the fact either derives it from that home, as shown in [F1·d one truth per concern](https://banes-lab.com/disciplined-methodology/build#one-home-panel-d), or holds a copy that will drift sooner or later. The principle is [single source of truth](https://banes-lab.com/records/arch/single-source-of-truth.md), and [DRY](https://banes-lab.com/records/arch/duplicate-code.md) is its everyday name. It applies equally to a number in a config, a location in a script, a word in a filename and a sentence in a document, and each of these has one mechanism that holds it. For a location, that mechanism is shown in [F1·a a location declaration](https://banes-lab.com/disciplined-methodology/build#one-home-panel-a) and [F1·b the lookup](https://banes-lab.com/disciplined-methodology/build#one-home-panel-b). The architecture page states the same split under [definitions own what, code owns how](https://banes-lab.com/software-architecture/model/definitions-own-what.md), and [derived state](https://banes-lab.com/disciplined-methodology/verify/derived-state.md) describes the [verification](https://banes-lab.com/records/arch/verification.md) side of it.

### One home per fact

The same fact gets stated in several places, and the places stop agreeing. A limit lives in the tool's config, in a checker, in a script and in three documents. You change it in the config, and the other five keep enforcing the old value. A copy is cheaper to make than a derivation, and the two agree on the day of copying, so the drift is invisible until it costs something.

For this reason I give every fact one home, and any second appearance is either derived from it or treated as a defect. The second appearance is a lookup rather than a copy, even where the copy would be shorter. In practice, a home is chosen for each fact, and every other appearance is derived from it by a generator or a lookup. Any copy that cannot be derived is deleted.

To check this, change the fact at its home. Every other appearance should follow without a second edit, and any appearance that stayed behind was a copy. A declaration file is the one exempt place, because there the string is the declaration rather than a copy of one. Every consumer reads that file by key, and the exemption never widens to a second file.

Three sources of truth carry most of the tree. The first is for quality: every tool's configuration is built in memory from one declaration, a validator refuses a second configuration on disk, and because the defaults are catalogued, the declaration carries only the deviations. The second is for locations: one declaration holds where every member lives, branches compose so each directory is spelled once, and every script resolves a location by key, so a rename is one edit. This is [configuration externalization](https://banes-lab.com/records/arch/configuration-externalization.md), and a path spelled out in a script is [hardcoded configuration](https://banes-lab.com/records/arch/hardcoded-configuration.md). The third is for naming: one [closed vocabulary](https://banes-lab.com/records/arch/closed-vocabulary.md) holds every word a filename may carry, and an undeclared word is an edit to the vocabulary that has to be approved, not a naming choice.

A location is never spelled out in a string, and the check for that recognises four shapes: a declared location written as a literal anywhere; the same location assembled from parts, after local constants, arrays and concatenation are folded; a literal tail appended to a lookup when a key already covers the whole path; and any path-shaped string with no anchor at all. Where the path sits makes no difference, so a path in an array entry or a template is the same defect as a path in a value.

The location declaration is shaped so that composing locations costs nothing. A branch declares its own place under a root key, and every key beneath it resolves relative to that place, so a directory is spelled once and a rename is one edit. A branch that declares a root also resolves as a leaf, so a key keeps working after it gains children. The keys are generic and the values are the project's own: the governance tooling finds the application by a fixed key whatever the directory is called, so renaming the directory means editing one value. The lookup is typed over the declared keys, so a key that does not exist fails to compile instead of resolving to nothing at run time. The declaration answers one question only, where a member lives and which governed roots sit inside it. What lives below a root belongs to the naming vocabulary and is not listed here again.

F1·a a location declaration

```yaml
app:
root: <application-root>
member: <application-member>          # → <application-root>/<application-member>
builds: <build-output>                # → <application-root>/<build-output>
testing:
root: <test-root>
app: <application-suite>              # → <test-root>/<application-suite>
governance:
root: <governance-host>
rules: <rule-host>                    # → <governance-host>/<rule-host>
reports: <report-root>                # → <governance-host>/<report-root>
```

F1·b the lookup

```typescript
type LocationKey = "app.root" | "app.member" | "app.builds" | "testing.app" | "governance.rules";

export declare function relativePath(key: LocationKey): string;
export declare function absolutePath(key: LocationKey): string;

const ruleHost = absolutePath("governance.rules");
const suite = relativePath("testing.app");
```

F1·c one limit

```mermaid
flowchart TB
subgraph copies["Three homes"]
s1["settings · lines-per-file: 200"]
c1["checker · MAX_LINES = 150"]
r1["readme · files never exceed 150 lines"]
end
subgraph home["One home"]
s2["settings · lines-per-file: 200"]
c2["checker · reads lines-per-file from the settings"]
r2["readme · states the shape, never the number"]
s2 -- derived --> c2
s2 -. no number to copy .-> r2
end
s1 -. drift .- c1
c1 -. drift .- r1
```

F1·d one truth per concern

```mermaid
flowchart TB
subgraph truths["One truth per concern"]
quality["Quality config · one file, every tool's config built in memory from it"]
paths["Locations · one declaration, every location resolved by key"]
vocabulary["Naming · one closed vocabulary"]
end
tools["Every tool"]
scripts["Every script"]
checks["Every check"]
quality -- in memory --> tools
paths -- by key --> scripts
vocabulary -- parsed --> checks
drift["A per-tool config on disk · a spelled path · an undeclared word"]
drift -. refused .-> truths
```

## Links to

- [Single Source of Truth](https://banes-lab.com/records/arch/single-source-of-truth.md)
- [Do Not Repeat Yourself (DRY)](https://banes-lab.com/records/arch/duplicate-code.md)
- [Definitions own what, code owns how](https://banes-lab.com/software-architecture/model/definitions-own-what.md)
- [Derived state](https://banes-lab.com/disciplined-methodology/verify/derived-state.md)
- [Verification](https://banes-lab.com/records/arch/verification.md)
- [Configuration Externalization](https://banes-lab.com/records/arch/configuration-externalization.md)
- [Hardcoded Configuration](https://banes-lab.com/records/arch/hardcoded-configuration.md)
- [Closed Vocabulary](https://banes-lab.com/records/arch/closed-vocabulary.md)

## Linked from

- [The loop](https://banes-lab.com/disciplined-methodology/start/the-loop.md)
- [Rules with names](https://banes-lab.com/disciplined-methodology/start/rules-with-names.md)
- [A seat is a contract](https://banes-lab.com/disciplined-methodology/start/a-seat-is-a-contract.md)
- [Worth before work](https://banes-lab.com/disciplined-methodology/plan/worth-before-work.md)
- [Coordination is software](https://banes-lab.com/disciplined-methodology/collaborate/coordination-is-software.md)
- [Proxies give way](https://banes-lab.com/disciplined-methodology/ship/when-not.md)
- [Definitions own what, code owns how](https://banes-lab.com/software-architecture/model/definitions-own-what.md)

## Evidence in the code

- [configuration/strings](https://banes-lab.com/anatomy/tree/folder-configuration-strings.md)
- [core/ids](https://banes-lab.com/anatomy/tree/folder-core-ids.md)
- [tabLink](https://banes-lab.com/source/tree/core/assets/link.assets.ts.md)
