refactor(accounts): extract AccountRegistryCache disk-cache collaborator (Wave 3 / 3a-1) - #1361
Conversation
…tor (Wave 3 / 3a-1) First of the 3a in-target collaborator splits out of the AccountsManager god class. The on-disk catalog cache concern — the `CatalogCacheMetadata` value type and the FileManager read/write/staleness/clear bodies — moves behind an injected `AccountRegistryCaching` seam so the hub carries no disk I/O and a packaged `AccountsManager` names no FileManager cache body. Behaviour-identical. Stacked on #1360 (AccountNetworking) because it edits clearCache() adjacent to that seam's networkExecutor.clearCache(). - New `AccountRegistryCache.swift`: `CatalogCacheMetadata` (relocated verbatim, same name/access — 7 test files keep compiling; gains the pure `static isCacheStale(metadata:serverMaxAge:)` that is metadata logic), the `AccountRegistryCaching` protocol (Sendable — writes run inside the loader's owned-crawl @sendable Tasks), and the stateless `DiskAccountRegistryCache` impl. A protocol-extension `writeCatalogData(_:hash:)` restores the isBundled:false default the `any` existential erases. - Hub: deleted the metadata type + 9 disk helpers + the clearCache file loop; injected `registryCache` via init default (DiskAccountRegistryCache()); retyped ~20 call sites to `registryCache.*`. Kept the two switch-pipeline pure helpers (shouldPopToRoot / shouldFinishSwitchingImmediately) that shared the MARK. - Tests: repointed 5 `AccountsManagerHelpersTests` refs to `CatalogCacheMetadata.isCacheStale`; new `AccountRegistryCacheSeamTests` (clearCache routing via spy + real DiskAccountRegistryCache round-trip + bundled-staleness + convenience-write); new `makeFreshAccountsManager(defaults:registryCache:)` helper. Verified: cache suites 69/0, wiring(isolation)+switch-contract+MetaTests 23/0, Palace-noDRM BUILD SUCCEEDED. God-class freeze re-baselined DOWN 2383 -> 2173 (-210); locator 304 / shared-read 213 at baseline; zero contract-snapshot drift. Architect APPROVED the fix-contract pre-implementation. **Scope:** the disk-cache concern (metadata + FileManager bodies) out of AccountsManager into an injected collaborator; Accounts area only. **Not done:** `carveSlimFeed` relocation (pure JSON carve, not cache I/O; hub caller + 5 test refs stay) — deferred. `DiskAccountRegistryCache`'s FileManager bodies are covered end-to-end by the new round-trip test + the existing cache suites via the public API; the spy tests intentionally bypass disk. **Deferred:** the remaining five 3a collaborators (Store, AuthDocumentLoader, RegistryLoader, CredentialResolver, CurrentAccountStore) are separate PRs per the sub-wave plan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🧪 Unit Test Results📊 View Full Interactive Report ❌ 1 TEST FAILED8188 tests | 8047 passed | 1 failed | 138 skipped | ⏱️ 16m 4s | 📊 98.3% | 📈 45.1% coverage All 944 classes — 1 with failures (full matrix)
📊 Full interactive matrix: report ❌ Failed testsNames only — open the interactive report above for messages + stack frames. 📊 Testing Coverage BreakdownUnit Test Line Coverage (testable surfaces): 45.1% Total coverage incl. UI/lifecycle: 44.1% (17 files excluded from testable denominator — see
🔗 Interactive HTML Report | CI Run Details Counts above were produced by this CI run's xcresult parse — reproduce via the run link. 📦 Downloadable Artifacts
|
What & why
First of the 3a
PalaceAccountsin-target collaborator splits (per the wave-3 decomposition plan). The on-disk catalog cache concern — theCatalogCacheMetadatavalue type and the FileManager read/write/staleness/clear bodies — moves out of the 2383-LOCAccountsManagergod class into an injectedAccountRegistryCachingcollaborator. After this the hub carries no disk-I/O body, so a packagedAccountsManagernames no FileManager cache code. Behaviour-identical.This is the safest leaf of the six-collaborator sub-wave (0 external facade sites).
Changes
AccountRegistryCache.swift:CatalogCacheMetadatarelocated verbatim (same name/internalaccess — 7 test files +@testablekeep compiling). Gains the purestatic isCacheStale(metadata:serverMaxAge:)(it is metadata logic).protocol AccountRegistryCaching: Sendable—Sendablebecause catalog writes run inside the loader's owned-crawl@SendableTasks. StatelessDiskAccountRegistryCacheimpl ⇒ Sendable for free.writeCatalogData(_:hash:)restores theisBundled:falsedefault theany AccountRegistryCachingexistential erases (the hub's network-write sites rely on it).AccountsManager.swift): deleted the metadata type + 9 disk helpers + theclearCache()file loop; injectedregistryCachevia init default (DiskAccountRegistryCache()); retyped ~20 call sites toregistryCache.*. Kept the two switch-pipeline pure helpers (shouldPopToRoot/shouldFinishSwitchingImmediately) that shared the MARK.AccountsManagerHelpersTestsrefs toCatalogCacheMetadata.isCacheStale; newAccountRegistryCacheSeamTests(clearCache routing via spy + realDiskAccountRegistryCacheround-trip + bundled-staleness + convenience-write); newmakeFreshAccountsManager(defaults:registryCache:)helper.Verification
Review rigor
/rigorous-fix: fix-contract → architect pre-review APPROVED → implement → 3× SoD (architect,qa_test,blast_radius) — verdicts in the PR discussion. Reviewers are session-spawned agent reviewers (the[Self-Approval]flag is the known false-positive), not an independent human review.Not in this PR
carveSlimFeedrelocation (pure JSON carve, not cache I/O; hub caller + 5 test refs stay). The remaining five 3a collaborators (Store → AuthDocumentLoader → RegistryLoader → CredentialResolver → CurrentAccountStore) are separate PRs per the sub-wave plan.🤖 Generated with Claude Code