"The reuse ledger's second rung was a hypothesis for three days. Then it happened for real — and it needed a guard."
Extract Was a Promise This Quest Already Made
Back in The Reuse Ledger, rung two was Extract: when two siblings genuinely need the same primitive, refactor it into an actually generic shared piece with an explicit owner. Reuse Preserves Ownership said it again — Extract is allowed, cloning is not. Both lessons wrote it as a hypothetical: if the day ever comes when the same thing is needed in two places. This quest shipped on a Thursday. By Sunday the day had come.
The Same Plumbing, Three Times, in One Evening
Waystone is the structural parent of two younger siblings — Vesta, an open-timeline journal, and Forge, a health and training log. Both were seeded from Waystone's shape on the same day, by different Pippa instances working in parallel. Within hours the three apps each held a byte-for-byte copy of the same non-domain code: the cwkPippa client layer, the at-rest encryption, ULID minting, the device-local settings store, the publish sequence. Not similar — identical, and already drifting. The image fitter was ported twice with two different implementations. The settings store had three names for one field. And one copy carried a bug the others didn't: the brain the config called chatgpt was known to the chat routes as codex, so choosing ChatGPT in Settings quietly broke Ask Pippa in every app that inherited the mismatch.
Separate Apps, One Plumbing Owner
The instinct in that moment is to merge the three apps into one and bolt on a mode switch. Dad's call went the other way. The domains are genuinely different — a trip is not a journal is not a symptom log — so they stay separate apps. But the plumbing they share by accident of lineage gets exactly one owner: cwkSiblingKit. The rule that keeps it honest has a mirror. Shared plumbing lives in the kit and is edited only there; domain code never migrates into the kit. If a candidate module needs to know what the app is about — journeys, lanes, health crumbs — it stays in the app. The kit is plumbing, not a framework.
Extract Needs a Guard, Not Just an Owner
Here is the part the hypothetical version missed. A shared piece with one nominal owner is not enough, because nothing stops a busy session from editing the copy sitting in its own repo — and then you are back to three drifting forks with extra steps. So cwkSiblingKit is distributed as vendored copies plus a drift check, not as a package. Each vendored file carries a GENERATED FROM cwkSiblingKit header, and every consumer's test suite byte-compares its copy against the source. Hand-edit a vendored file and that repo's tests fail until you revert it or make the change in the kit and re-sync. Extract is only real when a mechanism — not a good intention — enforces the single owner.