C.W.K.
Stream
Lesson 01 of 04 · published

Compose, Don't Copy

~13 min · firelink, single-source-of-truth, composition, dry

Level 0Cold Ash
0 XP0/32 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"The master file is always accurate for exactly one day: the day you wrote it."

The God-File Temptation

The obvious way to build a family hub is one big list. A FAMILY dictionary: every member, its title, its host, its ports, its capabilities, its health. It feels great for an afternoon. Then Ember moves to a new port and the list is wrong. Then a repo is renamed and the list is wrong in a different place. Then someone adds a service and forgets the list entirely. The master file doesn't fail loudly — it drifts, quietly, into confident lies.

The problem isn't laziness; it's that the master file duplicates facts other places already own. The roster already knows the title. The network ledger already knows the port. The repo on disk already knows its Git state. Copying those into one file means every future change has two homes, and the second one always lags.

One Owner, Then Compose

Firelink's answer is to name a single canonical owner for each kind of fact and never copy it:

  • Title, one-liner, lifecycle → the roster document.
  • Hosts, ports, URLs, 'no network' declarations → the network ledger.
  • Bundle IDs, service labels, adapter IDs, peer allowlists → Firelink's own operation-policy file.
  • Disk, Git, installed app, process, endpoint state → live discovery, measured fresh.
  • GitHub presence → a GitHub query.
  • Human-facing product release → each repo's cwk-product.json.

Then Firelink composes these owners into one typed model at read time. There is deliberately no static FAMILY list, no separate frontend operation list, no second service allowlist, no duplicate native-app allowlist. Every consumer — census, APIs, WebUI, the launcher's catalog, operation policy — reads the one composed registry.

Why Composition Beats a Copy

When each fact has exactly one home, a change has exactly one place to make it, and the composed view is correct the next time it's read. There's no reconciliation between the master file and reality because there's no master file to reconcile. The operation-policy file that Firelink does own is carefully scoped to hold only things no other ledger owns — adapter IDs, bundle IDs, peer allowlists — and it explicitly must not duplicate a title or a URL that a shared ledger already carries.

Compose facts from their owners; never copy them into a master file. A hand-maintained aggregate is correct exactly once — the moment you save it — and drifts from that instant. If you must store an aggregate, derive it at read time from the single owners, so it can never disagree with them.

Code

The god-file (rots) vs composition (stays true)·python
# ANTI-PATTERN: one handwritten master file, duplicating owned facts.
FAMILY = {
    "cwkEmber": {"title": "Ember", "host": "server", "port": 8100,
                 "can_deploy": True, "status": "running"},   # all 5 will drift
    # ...20 more entries, each a second home for a fact someone else owns
}

# FIRELINK: name one owner per fact, compose at read time.
def build_registry():
    members = eligible_members(PROJECTS_DIR)        # filesystem owns membership
    return [
        compose(
            id=m,
            decoration = roster.get(m),             # roster owns title/lifecycle
            network    = network_ledger.get(m),     # ledger owns host/port/url
            policy     = member_operations.get(m),   # policy owns adapters/bundles
            observed   = probe(m),                   # live discovery owns runtime
        )
        for m in members
    )
# No FAMILY dict. Change a port in ONE place; the next read is correct.

External links

Exercise

Find a place in a system you know where the same fact lives in two spots (a config and a database, a README and the code, a spreadsheet and the app). Name which copy is authoritative and which one is the shadow. Then describe how you'd delete the shadow and derive it from the owner instead. If you can't tell which copy is authoritative, you've found exactly the bug this principle prevents.
Hint
The shadow is usually the convenient one — the file you edit by hand because it's easier than changing the real owner. That convenience is the whole trap: the easy copy is the one that drifts.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.