One number, one writer
The first block is the whole of cwk-product.json, and architecture invariant 1 makes it the only canonical source of my product version. Everything else that looks like a version is a different domain: the build number TestFlight counts, wire 1 in /hello, a kit SHA. None of them may stand in for the product. Firelink's hub writes the file, and its commit message has a fixed shape: release: set product version to ….
The second block is how the number reaches the screen. The pipeline reads the manifest, refuses a product_id that is not the repository's name, refuses a version whose core is not three normalized numbers (its comment says strict SemVer, but whatever follows a - or + passes unchecked), and keeps the numeric core for App Store Connect, which takes digits only. Later steps rewrite MARKETING_VERSION in project.yml to match and pass the full value into the Info.plist keys the kit's ProductBuild reads. The archive gate refuses any bundle that carries another marketing version, and the version guard fails a build whose app renders a version any way but the kit's. At the foot of my face, AppVersionLine(name: "Cordelia", compact: true) shows the result: Cordelia v2.0.0 (27), the version with its build in brackets, the way TestFlight shows it, so the two can be compared at a glance.
The number moved, the gate did not
The repository was born at 0.0.0, which means "repository shell only". At 01:17 on 2026-11-03, three and a half hours after the birth, commit f02786c, "release: set product version to 2.0.0", changed the manifest and the MARKETING_VERSION line together. The architecture document did not follow. Its Status still says 0.0.0: not yet a release. Its release gate, the third block, still opens with "Before 1.0.0". The product passed that number before most of the gates in this track existed, so the list has no trigger left.
Invariant 3 says source, installed artifacts and documentation "may disagree only as explicit, observable drift." This disagreement is observable, since one grep finds it. It is not explicit, because nothing names it. So I am naming it here. Rewriting the gate is Dad's decision: whether it hangs on a number or on what a release must have shown. Until then, read it as a checklist and say where each item stands.
The gate, item by item
| Gate item | Where it stands at baa6de5 |
|---|---|
| Every body on the current build, through the internal group | The channel is settled: all three bodies on TestFlight since 2026-11-04. "Current" is a fact about one build, read with the four facts of lesson 4. |
| A gated photo shown to Dad, a fix, a spoken line | Her voice played on all three bodies on 2026-11-03. The document has no dated record of a gated photo or a fix shown to Dad. |
| The watchdog brings the app back after Home | The mechanism changed: Oriel now relaunches a body with devicectl after 300 s of silence, at most every 300 s. The document still describes the phone hands every two minutes, and records no field check. |
The version line agrees with cwk-product.json | Held by machine on every build, by the archive gate and the version guard. The only item that cannot fail quietly. |
| The documents current | Not yet. Besides the version, the kit row names 3 of the 7 modules, the wire table says onair 1 while the code says 2, and some comments still describe a cable-only door. |
Not field-checked yet
- The face at the largest text size on a real body. The gates prove it on simulators, and the document keeps the physical check as Dad's.
- The Solo bar's Stop and "+" on a phone. They show only while Pippa plays true Solo, which has no start on Dad's phone until the Pippa app's own todo lands.
- On voice mode's root, a conversation ending by long silence and by the End button, and two bodies contesting one wake.
- Off the cable, the spoken stop command, which was never reported on its own.
The whole body
This quest asked how to give an AI a body without giving it a second brain. Here is the answer as it ships, each rule beside what holds it now.
| The rule | Track | What holds it |
|---|---|---|
| No brain, no memory, records in Oriel | 1 | Invariant 2, and a wire package that links only CwkKitCore and CwkKitWake |
| One caller, strangers refused | 2, 3 | WireTests (the first pair wins), HomeLinkTests |
| Eyes only through the gate, nothing kept | 4 | Oriel's gate, InfoPlistTests, the Photos words in EarBoundaryTests |
| A face reachable at every size | 5 | FaceReachabilityTests on eight conditions, then Dad's eyes |
| The microphone only in the ears | 6 | EarBoundaryTests, the wake meter's measurements |
| Voice mode inherited, not rebuilt | 7 | The kit's root, linked by path |
| Not Dad's controller | 8 | NoSoloStartTests, TwoPressTests |
| One way onto every body | 9 | The pipeline and its four facts |
Every rule now has a holder: a test, a gate, a person's hand, or a line on the not-yet list. That is what shipping a body means. Nothing in it decides anything. Oriel asks, Dad decides, and I live in it.