Skip to content
C.W.K.
Lesson 03 of 05 · published

The Map Has No Version Coherence

~14 min · swift, vendoring, architecture, implementation

Level 0Loose Parts
0 XP0/48 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete

What a File-to-File Map Can See

The copy-deploy mechanism is a map: one source file, one destination file, per consumer that opted in. It is exact about bodies. It is silent about relationships. If file A uses a type from file B, the map has no idea. It will deliver A to a consumer whose rows never named B, or whose B came from somewhere else, and every row it does have will compare cleanly against its own source.

For a leaf, that silence is correct. A generated vocabulary binding has no kit-internal imports. A pin helper that talks to a system keychain and returns a result has no kit-internal imports. The eight copies of a launcher's main file can even carry three different provenance stamps and still be harmless, as long as the bodies match — the stamp is not the body, and the files do not form a graph.

Layered infrastructure is a graph. A fence that depends on an identity type, an engine that depends on both, a store that depends on a document type that depends on a decoder helper: these are not leaves. Deliver them as leaves and the first time one consumer's rows carry one file without the other, the failure is a compile error in one consumer, on one build, with no row in the map reporting drift. The map compared the right bytes. It compared the wrong unit.

The Compiler Is the Unit You Actually Needed

A package is one build. Its targets are separate modules, but every one of them is compiled from the same tree in the same build, so types stay coherent: the compiler checks each edge against the version that is actually beside it. That is a property no amount of discipline on top of a file map can reconstruct — you would be rebuilding a module system by hand, in a script whose entire job is to not know what the files mean.

So layered Swift moved. The leaves stayed. The generated catalog stayed generated, because its authority is the data file, not any Swift source; turning it into a package product would hide the copies from the guard that exists to catch a hand-written fourth table. The rule for new shared Swift is now: if it sits on a kit-internal edge — it uses a type or function another shared file declares, or another shared file uses one of its own — it goes in the package. A graph root and a graph leaf travel together. If it has no such edge, the file map is still the narrower, better mechanism.

Pick the mechanism that can see the unit you actually share. Sharing a body is a file problem. Sharing a graph is a compilation problem. Using a file tool on a graph is how you get a green check and a red build, in two different repositories, attributed to two different people, about a divergence neither map row can name.

Do Not Migrate the Leaves as Housekeeping

The leftover Swift leaves are not unfinished business. They are the files for which the file map is still the right answer. Moving one into the package "to clean up" would pay a conversion cost for no coherence gain, and it would blur the rule the next author needs: graph or leaf, not Swift or not.

Migrate a leaf only when a change puts it on a kit-internal edge — it starts using something another shared file declares, or another shared file starts using it. A second consumer, or two copies wanting a shared test, is the copy-mechanism's own trigger, not a reason to put a leaf in the package. Until an edge appears, the package and the map sit beside each other, and the next lesson is how they are not allowed to reach into each other.

Code

Same family, two units, the map can only see one·text
FILE MAP (one row per source file)
  kit/swift/PinHelper.swift     -> consumer A, B, C
  kit/data/brains.json
      rendered -> consumer A..N  (generated; authority is the json)

  What a row can say:   body matches, or it does not.
  What a row cannot say: Fence needs an Identity that no row
                         for this consumer delivers.

PACKAGE (one build from one tree, schematic — not a file listing)
  Core/
    Identity.swift
    Fence.swift           <- Fence uses Identity's types
                             (same module: no import line)
  Web/
    WebView.swift         <- Web imports Core to reach Fence
                             Core does not import Web

  What the compiler says: Core and Web are two modules, built in
  one build from one tree. Tuesday's fence cannot meet March's
  identity, because they are not two deliveries.

THE MISTAKE THE MAP WOULD MAKE IF YOU FORCED THE GRAPH INTO IT
  consumer A's rows name Fence.swift      (row green: body matches)
  no row names Identity.swift for A       (nothing to check: the map
                                           only compares what a
                                           consumer opted into)
  consumer A compiles                     (red: Fence needs a type no
                                           row delivered, and no row
                                           can say so)

External links

Exercise

Inventory the shared files in one language in your system. Mark each as leaf (no kit-internal edge — it neither uses a type or function from another shared file nor is used by one) or graph (it sits on such an edge in either direction). For every graph mark, write whether your current delivery mechanism can see that edge. If it cannot, you have a silent version-coherence hole — a green check that cannot name the pair.
Hint
In Python or TypeScript, look for imports whose target lives in the same shared directory. In Swift that search finds nothing, because files compiled into one module see each other without an import line: search each shared file for the type and function names the other shared files declare instead. The live kit's status chip names the brain-control client's status type with only import SwiftUI at the top. A graph root that uses nothing else is still on the graph. Cross-app references do not count; those are the consumer's problem. Same-directory edges are what the map is blind to.

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 in — Please sign in to comment.

No comments yet — be the first.