T5 — Mock-Protocol Drift Detection (a central conformance registry, reframed for the real codebase)
T5 was spec'd as "wrap MockKeychainStorage, MockSupabaseClient, StubAIEngineClient, CountingAIEngineClient in a shared MockValidation.swift that fails build if protocol surface drifts." Two facts from the actual codebase changed the shape: none of those four named mocks exist, and four of the six real mocks are private to their own test files. So a literal central drift detector over the named mocks is impossible and low-value. The durable form is a central conformance registry — one minimal compile-time anchor per test-mocked protocol — so a protocol-surface drift fails the build at a single labelled point. Six anchors; build-for-testing green. The mechanism caught its own author: the first build failed because EmailAuthProviding has seven methods, not the four anchored.
What do T1 / T2 / T3 mean?▾
T5 — Mock-Protocol Drift Detection
Status: shipped 2026-06-10. RICE 40.0.
The scoping reframe (the third this week)
T5 was spec'd (2026-05-13) as "wrap MockKeychainStorage, MockSupabaseClient, StubAIEngineClient, CountingAIEngineClient in a shared MockValidation.swift that fails build if protocol surface drifts." Two facts from the actual codebase changed the shape:
- None of those four named mocks exist. The real test doubles are
MockAnalyticsAdapter,MockGoogleAuthProvider,MockURLSession,StubAppleAuthProvider,StubEmailAuthProvider,TestAdapter. - Four of the six are
privateto their own test files (good encapsulation) — a central file can't reference them — and Swift already compile-enforces eachMock: Protocoldeclaration, so re-asserting them is redundant.
So a literal "central drift detector over the named mocks" is impossible and low-value. (This joins T10 — the AI is deterministic, not generative — and T3 — the test bundle ships a real passkey relying-party ID — as cases where running/reading the code corrected the 2026-05-13 plan.)
The durable form for this codebase
A central conformance registry: FitTrackerTests/MockProtocolConformanceTests.swift defines one minimal anchor per test-mocked protocol — the smallest type that satisfies it. The anchor exists only to pin the protocol's surface at compile time; it's never called. If a protocol's surface drifts (a requirement added / renamed / re-signed), the matching anchor fails to compile and this one labelled file is the failure point — instead of a confusing error deep inside whichever private mock happened to break, on whatever unrelated PR touched the protocol.
Six anchors: AnalyticsProvider, GoogleAuthProviding, AppleAuthProviding, EmailAuthProviding, URLSessionProtocol, AIInputAdapter. Plus the two app-target mocks that ARE shareable (MockAnalyticsAdapter, MockGoogleAuthProvider) are bound to their protocol type and smoke-tested, so the registry tracks the live types, not just the anchors.
Why a registry beats per-mock conformance
Swift catches drift at each Mock: Protocol site — but those sites are scattered across private test files, and a protocol change surfaces as an error wherever the mock lives, with no single "these are the protocols we mock" inventory. The registry adds: (a) one documented place listing every mocked protocol ↔ its double, (b) a single, clearly-labelled compile failure on drift, and (c) protection against a protocol's only mock being deleted/orphaned without notice (the anchor still pins the surface).
Verification
build-for-testing green — the whole point of T5 is compile-time, so a successful test-target build is the assertion that all six protocol surfaces still match their anchors. The runtime tests additionally prove the two shareable mocks bind + respond.
Where to read more
- Source case study:
docs/case-studies/t5-mock-protocol-drift-case-study.md - Spec:
docs/master-plan/test-coverage-master-plan-2026-05-13.md§4 T5 - Sibling reframes (same week):
ai-golden-set-evals,t3-signinservice-passkey-tests
- •The original spec was unbuildable as written: none of the four named mocks (
MockKeychainStorage,MockSupabaseClient,StubAIEngineClient,CountingAIEngineClient) exist, and four of the six real mocks areprivateto their own test files — so the central registry pins protocol *surfaces* via minimal anchors rather than wrapping the actual mocks. - •Verification is compile-time only (
build-for-testinggreen) — the registry asserts protocol surfaces still match their anchors, but exercises no runtime behavior beyond two shareable app-target mocks; a known false-negative class remains (a protocol gaining an optional/defaulted requirement the anchor masks).
- Anchors duplicate private mocks in a way that adds maintenance burden without catching new drift.
- A protocol gains an optional/defaulted requirement the anchor masks (false negative).