Execute the V1 to V3 migration end-to-end in tests - #568
Merged
Merged
Conversation
The willMigrate closures that snapshot plaintext killphrases and search passphrases into pending sidecar files were never invoked by any test, and the Phase B rehash was only covered in isolation. Build a real on-disk V1 store, reopen it through the real migration plan, run the rehash services, and prove behaviorally that the digests verify the original phrases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The V1 → V3 schema migration — the path that moves plaintext killphrases and search passphrases out of the store and into salted-HMAC digests — was never actually executed by any test.
PersistedSchemaMigrationPlanTestsasserts only the declaration shape (two custom stages,willMigrate != nil), and every testModelContainerin the repo omitsmigrationPlan:. ThewillMigrateclosures, the pending-rehash sidecar files, and the Phase B rehash-on-first-unlock were all unexercised, including the documented plaintext-on-disk window between the phases.Changes (test-only)
New
PersistedSchemaMigrationExecutionTests— builds a real on-disk V1 store with plaintext phrases, reopens it through the realPersistedSchemaMigrationPlanexactly as the production opener does, then runs the real rehash services:v1ToV3_migration_writesPendingSidecarsForNonBlankPhrases—willMigratesnapshots exactly the non-blank(itemID, phrase)pairs into both sidecar files.v1ToV3_migration_skipsBlankAndNilPhrases— no sidecar entries fornil/empty phrases.rehashServices_consumeSidecarsAndDigestsVerifyOriginalPhrases— afterKillphraseRehashService/SearchPassphraseRehashServicerun: sidecars are consumed (securely cleared), killphrase deletion fires with the original phrase (the only public observation point for killphrase digests — deliberate, MANIFESTO C5), and the passphrase-hidden item is unreachable without the matcher but returned with it.rehashServices_idempotentWhenSidecarMissing— writer never invoked when there is nothing pending.Each test gets its own temp directory (created in
init, removed indeinit) to avoid cross-test flake. One real-world catch surfaced while writing these: the persistedvisibility/searchableLevelstrings are theVaultEncodingConstantsvalues ("ALWAYS", "ONLY_PASSPHRASE"), not the Swift enum case names — the tests now seed with the real constants.Local verification: suite passes, full VaultFeedTests scheme green on iPhone 18 Pro Max / iOS 27.0.
🤖 Generated with Claude Code