Snag
A move-in and move-out condition report for Nigerian tenancies, sealed with a key that never leaves the phone. Native Swift, iOS only, by decision.
- Swift 6
- SwiftUI
- CryptoKit
- ARKit
- RoomPlan
- PDFKit
- ActivityKit
- XCUITest
The problem
A Lagos tenant pays one or two years’ rent in advance plus a caution fee against damage. Two years later the landlord inspects, names the damage and deducts, and the tenant argues about a cracked tile that was cracked on move-in day and cannot prove it. Nobody wrote anything down. The Lagos Tenancy Law says the deposit is refundable less lawful deductions; it does not say how anybody establishes what was there before.
The dispute happens in two years to one tenant in ten. What every tenant does on move-in day is walk the flat and notice what is wrong. The evidence is the wedge, not the dispute — a report is worth making for one tenant with no landlord on the other side, on day one.
What I built
- The walk. A template names the rooms; prompts above the shutter are what a Lagos flat has and a tenant forgets — the meter, the water heater, the burglary bars. Every photograph is judged for darkness and blur, stripped of everything but the picture, and hashed the moment it is taken. Fine is a real answer, because a report that only lists faults reads as a complaint.
- The seal. The report is one canonical byte encoding — big-endian, length-prefixed, no floats, asserted byte-for-byte by a checked-in fixture — signed with a P-256 key in the Secure Enclave where there is one. The sealed bundle carries the public key, so any phone with Snag, or a 200-line Python verifier written from the format document alone, says unaltered since signing or altered, and nothing in between. CI runs both verifiers against the app’s own bundle and eight tampers of it, and they must agree.
- The other side. The landlord counter-signs on the tenant’s phone, on glass, and the drawn signature is bound into the bundle like a photograph. The PDF — nine pages, a page per room, a contact sheet, a QR on the cover — travels on WhatsApp as one file. A move-out walk shows the move-in photograph beside the shutter and lists what changed. A scan added months later is a second signature beside the first, touching nothing the first one signed.
- Three tiers, the word beside every number. Photographed on any iPhone; measured by tapping the floor’s corners through ARKit; scanned into a floor plan by RoomPlan on a LiDAR phone. A phone that cannot scan is never told it is missing something, because for that tenant nothing is.
- Five languages, chosen in the app. English, Naijá, Yorùbá, Hausa and Igbo; a gate fails the build on any string any language lacks, and the PDF keeps the English above the translation, because the English is what was written.
Decisions worth naming
- Evidence, never proof. A signature proves the report has not changed since it was signed. It does not prove when, because the clock is the phone’s and there is no server. The report says so on its own last page, and a word-list gate keeps the stronger word out of the app in every language — it caught “burglary proof”, the Lagos term, in the Pidgin, and was right to.
- The domain imports nothing. Not Foundation. Every signature ever made is over bytes this package produces, so those bytes must not depend on any platform encoder. Enforced by a gate that is proved to fire.
- Nothing is sent. No server, no account, no analytics; a gate fails on any network path in the source. The one exception — the tenant’s own iCloud, private database, opt-in, every bundle verified on the way down — is confined to one folder and named in an ADR.
- Never a number about money. No deduction, no repair estimate. That is the fintech line and the legal-advice line, and they are the same line.
- A tampered bundle is never hidden. Twice a bundle that failed to decode tried to disappear from the list; twice a rule was written so it is shown as what it is — altered.
What is not finished
- A handset. ARKit and RoomPlan do not run in a simulator; both tiers are built and proved with a fixture room, and the gate is a tape measure in a real room, within five per cent. The viewfinder, the torch, Face ID, the Live Activity and CloudKit wait for the same afternoon.
- A real handover, watched. A tenant and a landlord in a doorway, one phone, two signatures, the bundle opened on the other phone.
- Readers. A tenancy lawyer reading the PDF for an hour and not asking for a change, and a native speaker of each of the four languages, whose absence the language picker admits.