Atlas 06 of 07
AtlasKit
The iOS side: a Swift package that talks to every module, built before there was an app to put it in.
- 45
- Tests
- 2
- Modules spoken to
What it does
The iOS side, built as a Swift package before there was an app to put it in: the contract models, a typed client for all four endpoints, the module registry, an event stream and an MJPEG reader. It builds and tests from a terminal, with no simulator.
- Talks to any module
- Reads the manifest and renders what is in it. There is no per-module code and no lookup table of event types, which is what lets a module the app has never seen appear correctly.
- Streams events live
- A WebSocket feed with reconnection, plus the history query behind the same envelope. Rows display the `title` and `body` the service already rendered, verbatim.
- Reads an MJPEG stream
- A boundary parser that does not grow without bound when fed garbage — a stream parser that buffers until it finds a boundary will buffer forever if the boundary never arrives.
- Models the mirror's panels
- The mirror's state has a Swift twin, including the local extrapolation of playback position — clamped, so it never shows 4:31 of a 3:58 track.
How it works
Built inside-out
There is no Atlas.xcodeproj yet. Everything that is not a view is a Swift package, and it is
finished: the contract models, a typed client for all four endpoints, the module registry, the
event stream, an MJPEG reader, and the mirror’s panel models.
- The obvious thing
- Why it fails
- Instead
An Xcode project is the worst place to put the code most likely to be wrong. It needs a simulator to run, a project file to open, and a GUI to drive — so the parts that are pure logic get tested least, despite being the parts a test can actually pin down.
Inverting it means swift test runs the whole thing in under a second from a terminal, and
the app target, when it exists, will be views over something already proven.
What it knows about a module
Nothing module-specific. It reads the manifest and renders whatever is in it, which is the entire reason the contract exists — a module the app has never heard of shows up correctly because there is nothing to hard-code.
Event rows display the title and body the service already rendered, verbatim. The app does
no formatting and holds no lookup table of event types, so a service can invent a new kind of
alert and every phone displays it properly without an update.
Status
The package is complete and verified against both running services. The remaining work is the
app shell around it: a project file, a target, and the screens wired to ModulesView and
FeedView. That is the part that needs a Mac with Xcode open rather than a test suite, which is
why it is last.
Testing
45 passing in 5 suites · swift test
The whole reason the logic lives in a package rather than in an Xcode project: it builds and tests from the command line, with no simulator and no project file. The part most likely to be wrong is therefore the part most easily verified, which is the opposite of how an iOS codebase usually ends up.
What the tests defend
- The contract tests decode **and re-encode** every envelope. Round-tripping rather than decoding once catches the failure where a decoder silently discards an unknown field — which reads as working perfectly until the app has to send one back.
- The MJPEG parser has a test asserting it does not grow without bound when fed garbage. A stream parser that buffers until it finds a boundary will happily buffer forever if the boundary never arrives, and the symptom on a phone is not a crash but a slow death somebody blames on the camera.
- The Spotify progress bar is tested for never running past the end of the track. It advances locally between polls, so it is extrapolating — and an extrapolation with no clamp shows 4:31 of a 3:58 song, which looks like a bug in the mirror rather than in the phone.
- A live suite runs end-to-end against an actually-running service: it fetches a real manifest, confirms it is rejected without a token, and decodes event envelopes produced by the Python pipeline. Both sides validating the same schema is good; watching the bytes cross is better.
Built with
- Client
- Swift 6async/awaitURLSession
- Interface
- SwiftUISwift Testing
- Transports
- WebSocketMJPEGJSON