# Externals **How a repository records what it depends on, and finds out when it changes.** ## Pull what you use **You fetch a copy of somebody's document and keep it** at `.loom/externals//.md`. *The path says where it came from, so nothing has to record an origin.* **Pull what you need to understand, not everything it depends on.** *A document you fetch may refer to others; follow one when you hit something you do not know. **Pre-resolving that is how you get a `node_modules`.*** ## Two facets beside it - **`.usages.md`** — *what we use, and **which of our artifacts depend on it*** - **`.gaps.md`** — *what we expected here and did not find* > **A usage that does not name what it justifies is half a usage.** *"We use the > tailnet approach" is weak. **"We use the tailnet approach — see > `manifests/ingress.yaml`" is the whole value**, because it answers the only > question reconciliation asks.* ## Freshness is a conditional request **Locked on the publisher's `ETag`, verbatim — never a hash you compute.** *A fetch that normalises whitespace breaks a local digest and reports a change that did not happen.* | | | |---|---| | **`304`** | nothing changed | | **`200`** | changed — the new copy is a candidate, not a replacement | | **`410`** | gone — follow whatever the response points at | | **`404`** | **unresolved.** *Report both readings; do not pick one* | **`404` is two different answers wearing one status.** *The document was withdrawn, or you no longer have access — **and over HTTP they are indistinguishable**, because a host that distinguished them would leak the existence of things you may not see.* > **Say both. Do not guess.** *They want different actions — re-pull elsewhere, > versus ask somebody for access — and a tool that picks one will be wrong half > the time silently.* *Over ssh they **are** distinguishable — permission denied against repository not found — so a client that has both transports should say which it used.* ## Reconciliation runs the other way **You cannot fold your facets back into their document.** *So the question is not what do we rewrite here:* > **Given what changed in theirs, what do we change in ours?** **The facets usually survive unchanged.** *What moves is the manifests, the config, the code that a usage named — which is why a usage names them.* **And gaps reconcile too**, which is the half nobody builds for: *a new version may have filled one, and nothing will tell you.* **The new copy replaces the old pair wholesale.** *There is no merging a document you do not own.* ## Venues, for things you cannot fetch **`.loom/venues/.md`** — *Kafka, React, HTTP.* **Choices we made about something with no document to hang them on.** *If there is a document, hang it there instead: **put a choice where reconciliation will look for it.*** ## Gaps that belong to nobody **`.loom/gaps/`** — *a need with no owner.* **The test: could you say whose job this is?** *If yes, it is a claim against them and belongs in their `.gaps.md`.* > **Moving a file from `gaps/` into an external's `.gaps.md` is how a gap gets > homed.** *The position is the claim.* **A gap records the local workaround beside the need.** *"We are using Docker Hub for now."* **Forgetting it was provisional is the disease; the provisional answer is fine** — and when the gap is finally homed, every workaround that should be retired is findable.