finish SwiftData migration with @Query views
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s

- Drive chat list, timeline and forward picker from SwiftData @Query
  instead of AppModel's in-memory arrays; inject the per-account
  ModelContext from RootView with an in-memory fallback.
- Physically delete locally deleted messages (context.delete) and
  purge rows marked deleted by older builds on store open, so @Query
  views never resurrect them.
- Delete the legacy JSON snapshot only after a successful import save
  and restore the completeUntilFirstUserAuthentication data protection
  attribute on the store file.
- Mirror the old ChatArchive tolerant decoding in LegacyArchiveImporter
  so snapshots from older schema versions (missing reactions,
  isGroupMessage, roster fields) still import.
- Cover the new behaviour in ArchiveStoreTests and guard it with new
  verify.sh invariants; update AGENTS.md, ARCHITECTURE.md and
  SECURITY.md.
This commit is contained in:
wt
2026-08-29 00:57:08 +07:00
parent 277d8654c3
commit 2884810ec4
16 changed files with 653 additions and 65 deletions
+39 -1
View File
@@ -80,6 +80,12 @@ required=(
Tests/VideoNoteStopPolicyTests.swift
Tests/MessageReplySwipeTests.swift
Tests/WatchVoiceMessageTests.swift
Tests/ArchiveStoreTests.swift
Sources/Shared/Models/ChatMessage.swift
Sources/Shared/Models/Conversation.swift
Sources/Shared/Persistence/ArchiveStore.swift
Sources/Shared/Persistence/ArchiveMetadataRecord.swift
Sources/Shared/Persistence/LegacyArchiveImporter.swift
Brand/LumaIcon-1024.png
Resources/AppAssets.xcassets/AppIcon.appiconset/Contents.json
Regenerate-Luma-Project.command
@@ -257,6 +263,38 @@ grep -q 'lastSuccessfulMAMCursor' Sources/Shared/Persistence/ArchiveStore.swift
echo "The durable archive store must persist the XEP-0313 UID cursor"
exit 1
}
if test -f Sources/Shared/Persistence/ChatArchive.swift; then
echo "The legacy JSON ChatArchive actor must stay removed"
exit 1
fi
grep -q '@Query' Sources/Shared/UI/MainChatView.swift || {
echo "Chat list must be SwiftData @Query-driven"
exit 1
}
grep -q '@Query' Sources/Shared/UI/ChatView.swift || {
echo "Chat timeline must be SwiftData @Query-driven"
exit 1
}
grep -q '@Query' Sources/Shared/UI/ForwardMessageView.swift || {
echo "Forward destination list must be SwiftData @Query-driven"
exit 1
}
grep -q '\.modelContext' Sources/Shared/UI/RootView.swift || {
echo "RootView must inject the SwiftData ModelContext"
exit 1
}
grep -q 'modelContext.delete(message)' Sources/Shared/Models/AppModel.swift || {
echo "Local message deletion must remove the SwiftData row"
exit 1
}
grep -q 'purgeLocallyDeletedMessages' Sources/Shared/Persistence/ArchiveStore.swift || {
echo "ArchiveStore must purge locally deleted rows for @Query views"
exit 1
}
grep -q 'completeUntilFirstUserAuthentication' Sources/Shared/Persistence/ArchiveStore.swift || {
echo "The SwiftData store must keep the data protection attribute"
exit 1
}
grep -q 'ArchiveSyncCursorPolicy.requestPosition' Sources/Shared/XMPP/XMPPService.swift || {
echo "MAM reconnects must prefer the durable archive UID over timestamps"
exit 1
@@ -358,7 +396,7 @@ grep -q 'scrollDismissesKeyboard(.interactively)' Sources/Shared/UI/ChatView.swi
echo "Interactive keyboard dismissal is missing"
exit 1
}
grep -q 'selectedTimelineEntries' Sources/Shared/UI/ChatView.swift || {
grep -q 'rebuildTimelineEntries' Sources/Shared/UI/ChatView.swift || {
echo "Chat rows and day boundaries must use the cached stable timeline"
exit 1
}