feat: add explicit diagnostics app control plane - #125
Conversation
Implement pinned capability negotiation, restart-safe mutual pairing, device-only credentials, explicit lifecycle controls, and operator-gated namespace authorization without transfer artifacts. Keep upgrades mutation-free and preserve strict evidence, trust, and compatibility boundaries.
Add production-wire, persistence, lifecycle, namespace, compatibility, privacy, and no-transfer regression coverage. Document the unreleased control-plane scope and update the exact runtime isolation allowlists without enabling transfer domains.
📝 WalkthroughWalkthroughChangesControlled diagnostics runtime
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 7✅ Passed checks (7 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Validate persisted monotonic expiries against an absolute upper bound so legitimate IEEE-754 rounding cannot reject an exact five-minute deadline. Exercise namespace and credential lifecycle flows at the runner-observed fractional clock value.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
ios/VaultSync/Services/DiagnosticsPairingProtocol.swift (1)
627-633: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSame
unixSeconds/wallSecondsclock-bounds helper duplicated in four places. Each copy independently roundsDate().timeIntervalSince1970down and guards the same[0, UInt64.max)range before converting toUInt64, throwingDiagnosticsProtocolError.invalidMessageotherwise — the same logic feeding every issued/expires and clock-skew check across the protocol.
ios/VaultSync/Services/DiagnosticsPairingProtocol.swift#L627-L633: promote thisunixSeconds(or move it next tocheckedAdding, which the other files already call as a shared utility) into a single internal helper, e.g. onDiagnosticsPairingProtocolorDiagnosticsCrypto.ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift#L119-L125: replaceDiagnosticsCapabilityProtocol.unixSecondswith a call to the shared helper.ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift#L657-L663: replaceDiagnosticsNamespaceProtocol.unixSecondswith a call to the shared helper.ios/VaultSync/Services/DiagnosticsPairingController.swift#L1433-L1439: replacewallSeconds()'s body with a call to the shared helper (keep thewallSecondsname/wrapper if useful for call-site clarity).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ios/VaultSync/Services/DiagnosticsPairingProtocol.swift` around lines 627 - 633, Consolidate the duplicated clock-bounds conversion into one shared internal helper, preserving the existing floor rounding, [0, UInt64.max) validation, and DiagnosticsProtocolError.invalidMessage behavior. In ios/VaultSync/Services/DiagnosticsPairingProtocol.swift#L627-L633, promote unixSeconds (or place it beside checkedAdding); in ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift#L119-L125 and `#L657-L663`, replace both protocol-local unixSeconds implementations with calls to it; in ios/VaultSync/Services/DiagnosticsPairingController.swift#L1433-L1439, make wallSeconds delegate to the shared helper while retaining its wrapper name if useful.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ios/VaultSync/es.lproj/Localizable.strings`:
- Line 820: Update the Spanish translations for “Authorize Next Namespace Epoch”
and the related authorization/setup strings in the specified ranges to use a
consistent explicit term such as “espacio de nombres” (or retain “namespace”),
then obtain native-speaker review of the security wording.
In `@ios/VaultSync/Services/DiagnosticsPinnedTransport.swift`:
- Around line 174-211: The urlSession(_:didReceive:completionHandler:) trust
path must validate the certificate chain before accepting a matching pin. After
the SPKI pin succeeds and before marking authenticated or calling
.useCredential, temporarily configure the trust with the presented certificate
as an anchor, evaluate it with SecTrustEvaluateWithError, and cancel the
challenge if evaluation fails; restore or limit anchor configuration to this
evaluation only.
In `@ios/VaultSync/Views/ControlledDiagnosticsView.swift`:
- Around line 263-266: Update the button actions around “Check Explicit Operator
Step” and the corresponding “Authorize Next Namespace Epoch” action to handle a
missing folderPath(record.folderID) explicitly instead of returning silently.
Show the existing user-facing error or alert mechanism with a clear message that
the folder was renamed or removed, while preserving the current Task flow when
the path is available.
In `@ios/VaultSync/zh-Hans.lproj/InfoPlist.strings`:
- Line 2: Update the NSCameraUsageDescription translation to explicitly state
that VaultSync scans Syncthing Device ID QR codes and controlled-diagnostics
pairing QR codes, replacing the inaccurate reference to scanning selected
settings while preserving the existing Chinese localization style.
---
Nitpick comments:
In `@ios/VaultSync/Services/DiagnosticsPairingProtocol.swift`:
- Around line 627-633: Consolidate the duplicated clock-bounds conversion into
one shared internal helper, preserving the existing floor rounding, [0,
UInt64.max) validation, and DiagnosticsProtocolError.invalidMessage behavior. In
ios/VaultSync/Services/DiagnosticsPairingProtocol.swift#L627-L633, promote
unixSeconds (or place it beside checkedAdding); in
ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift#L119-L125
and `#L657-L663`, replace both protocol-local unixSeconds implementations with
calls to it; in
ios/VaultSync/Services/DiagnosticsPairingController.swift#L1433-L1439, make
wallSeconds delegate to the shared helper while retaining its wrapper name if
useful.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a19fb56e-bd68-48b6-b346-5272058121e2
📒 Files selected for processing (25)
PRIVACY.mddocs/app-capability-pairing-namespace-readiness.mddocs/architecture.mddocs/helper-runtime-packaging-readiness.mdios/VaultSync/Services/DiagnosticsCBOR.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingController.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/SettingsView.swiftios/VaultSync/de.lproj/InfoPlist.stringsios/VaultSync/de.lproj/Localizable.stringsios/VaultSync/en.lproj/InfoPlist.stringsios/VaultSync/en.lproj/Localizable.stringsios/VaultSync/es.lproj/InfoPlist.stringsios/VaultSync/es.lproj/Localizable.stringsios/VaultSync/zh-Hans.lproj/InfoPlist.stringsios/VaultSync/zh-Hans.lproj/Localizable.stringsios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swiftios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/project.ymlnotify/diagnostics_contract_model_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*
⚙️ CodeRabbit configuration file
**/*: VaultSync syncs private Obsidian notes through Syncthing. Treat data loss,
privacy leaks, security regressions, and broken sync behavior as high priority.
Do not nitpick formatting unless it affects maintainability, correctness, or public API clarity.
Flag any accidental logging, telemetry, crash reporting, or network transfer of note contents,
vault paths, filenames with private context, API keys, APNs tokens, relay keys, or security-scoped bookmark data.
Files:
ios/VaultSync/en.lproj/InfoPlist.stringsios/VaultSync/es.lproj/InfoPlist.stringsios/VaultSync/zh-Hans.lproj/InfoPlist.stringsios/VaultSync/de.lproj/InfoPlist.stringsios/VaultSync/de.lproj/Localizable.stringsios/VaultSync/zh-Hans.lproj/Localizable.stringsios/project.ymlios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/VaultSync/es.lproj/Localizable.stringsios/VaultSync/en.lproj/Localizable.stringsios/VaultSync/Views/SettingsView.swiftdocs/architecture.mddocs/app-capability-pairing-namespace-readiness.mddocs/helper-runtime-packaging-readiness.mdPRIVACY.mdios/VaultSync/Services/DiagnosticsCBOR.swiftnotify/diagnostics_contract_model_test.goios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPairingController.swiftios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
ios/project.yml
⚙️ CodeRabbit configuration file
ios/project.yml: This generates the Xcode project and Info.plist. Review changes for bundle ID,
entitlements, background modes, URL schemes, signing settings, and accidental secret exposure.
Files:
ios/project.yml
**/*.swift
📄 CodeRabbit inference engine (Custom checks)
For Swift background execution changes, pass if work is bounded, cancellation-aware, handles expiration callbacks, and records errors without leaking private vault data. Fail only when background work can continue unbounded, miss cleanup, or violate iOS background execution constraints.
Files:
ios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/VaultSync/Views/SettingsView.swiftios/VaultSync/Services/DiagnosticsCBOR.swiftios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPairingController.swiftios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
ios/**/*.swift
📄 CodeRabbit inference engine (README.md)
ios/**/*.swift: Develop the iOS/iPadOS app using Swift 6 and SwiftUI, targeting iOS/iPadOS 18 or later.
Use VoiceOver and Dynamic Type throughout the iOS/iPadOS app.
Support localization in English, German, Spanish, and Simplified Chinese.
Files:
ios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/VaultSync/Views/SettingsView.swiftios/VaultSync/Services/DiagnosticsCBOR.swiftios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPairingController.swiftios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
⚙️ CodeRabbit configuration file
ios/**/*.swift: Focus on Swift 6 strict concurrency, Sendable/MainActor correctness, Task cancellation,
retain cycles, memory pressure, SwiftUI observation state, StoreKit/APNs flows, and iOS background execution limits.
Pay special attention to BGAppRefreshTask and BGContinuedProcessingTask behavior, expiration handling,
bounded work, and cleanup when the app is suspended or terminated.
Files:
ios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/VaultSync/Views/SettingsView.swiftios/VaultSync/Services/DiagnosticsCBOR.swiftios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPairingController.swiftios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
ios/**/*.{swift,plist}
📄 CodeRabbit inference engine (README.md)
ios/**/*.{swift,plist}: Use BGAppRefreshTask and BGContinuedProcessingTask when available for background processing, while allowing iOS to decide whether and when the app runs.
Implement APNs silent push handling for optional Cloud Relay wake-ups.
Files:
ios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/VaultSync/Views/SettingsView.swiftios/VaultSync/Services/DiagnosticsCBOR.swiftios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPairingController.swiftios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
**/*.{md,sh,go,swift}
📄 CodeRabbit inference engine (README.md)
Keep Relay-side request observation and wake-ups received on the iPhone as separate diagnostics evidence; one must not be treated as proof of the other.
Files:
ios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/VaultSync/Views/SettingsView.swiftdocs/architecture.mddocs/app-capability-pairing-namespace-readiness.mddocs/helper-runtime-packaging-readiness.mdPRIVACY.mdios/VaultSync/Services/DiagnosticsCBOR.swiftnotify/diagnostics_contract_model_test.goios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPairingController.swiftios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
docs/**/*.md
📄 CodeRabbit inference engine (docs/troubleshooting.md)
docs/**/*.md: Troubleshooting documentation should map each symptom to a fix, and users should retry from the app after applying each fix.
Document the supportedvaultsync-notifyinstallation topologies separately: Docker, systemd, launchd, Docker Compose, and Windows PowerShell.
Treat HTTP 429 from the relay trigger endpoint as a successful reachability result, not a doctor failure.
Treat inactive subscriptions and peer-state warnings as non-failing diagnostic conditions;--healthcheckmust omit peer-state checks so offline peers do not make the container unhealthy.
Explain thatvaultsync-notifyreads the Syncthing API key fromconfig.xml; permission or wrong-file errors should be diagnosed through the process user,SYNCTHING_CONFIG, and anySYNCTHING_API_KEYoverride rather than requesting a pasted key.
When troubleshooting relay connectivity, verify internet access,RELAY_URL, egress rules, the relay health endpoint, and the app's relay diagnostics; a successful health check proves reachability, while an updated Last Trigger Received proves delivery.
APNs background wake-ups require a valid APNs token and provisioned device, but do not require notification permission; retry APNs registration and provisioning before testing a trigger.
VaultSync should not move, recreate, or delete vault folders automatically; recovery from moved, replaced, or deleted folders requires the user's manual decision and may involve removing and re-accepting the share.
Security-scoped bookmark failures should be resolved by reconnecting and reselecting the Obsidian folder, then rescanning; removing a vault only stops syncing on that iPhone and must not affect other devices.
Foreground iPhone-to-server syncing is reliable only while VaultSync is open; iOS background execution is system-controlled and not guaranteed.
When a required Syncthing device is disconnected, verify that it is online, connectivity exists through LAN/VPN/relay, and its device ID is unchanged before re...
Files:
docs/architecture.mddocs/app-capability-pairing-namespace-readiness.mddocs/helper-runtime-packaging-readiness.md
**/*.md
⚙️ CodeRabbit configuration file
**/*.md: Review public documentation for technical accuracy, privacy/security claims, App Store-facing wording,
setup correctness, and consistency with the free app plus optional Cloud Relay subscription model.
Files:
docs/architecture.mddocs/app-capability-pairing-namespace-readiness.mddocs/helper-runtime-packaging-readiness.mdPRIVACY.md
notify/**/*.{sh,go}
📄 CodeRabbit inference engine (README.md)
The optional notify sidecar must support server-side wake-up requests and must not receive notes, file or folder names, or vault structure.
Files:
notify/diagnostics_contract_model_test.go
notify/**/*.go
⚙️ CodeRabbit configuration file
notify/**/*.go: Review goroutine lifecycle, context cancellation, HTTP timeouts, signal handling, debounce behavior,
Syncthing REST API polling, relay API calls, error classification, and API-key handling.
Flag leaked request bodies, note metadata, Syncthing API keys, relay keys, or APNs-related secrets.
Files:
notify/diagnostics_contract_model_test.go
🧠 Learnings (2)
📚 Learning: 2026-07-12T23:03:04.680Z
Learnt from: psimaker
Repo: psimaker/vaultsync PR: 107
File: ios/VaultSyncTests/DiagnosticsContractTests.swift:39-46
Timestamp: 2026-07-12T23:03:04.680Z
Learning: In iOS Swift tests that use CryptoKit’s `Curve25519.Signing.PrivateKey.signature(for:)` (Ed25519), don’t assert that a generated signature’s bytes exactly match deterministic “golden”/fixture signatures. CryptoKit signatures may be randomized (different but valid for the same key+message). Instead, verify correctness by calling `isValidSignature` (or equivalent) against (1) the golden bytes and (2) the freshly generated signature, and avoid byte-for-byte equality assertions between CryptoKit output and reference vectors.
Applied to files:
ios/VaultSyncTests/DiagnosticsUploadM5Tests.swiftios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
📚 Learning: 2026-06-10T18:47:10.724Z
Learnt from: psimaker
Repo: psimaker/vaultsync PR: 38
File: ios/VaultSync/Views/ContentView.swift:605-611
Timestamp: 2026-06-10T18:47:10.724Z
Learning: In the SwiftUI codebase under ios/VaultSync, do not flag missing localization for SwiftUI string literals used as Text("…") or DisclosureGroup("…") titles/labels. In SwiftUI, these string literals are treated as LocalizedStringKey and resolve via the app’s Localizable.strings automatically—so they only need attention if the corresponding key is actually missing. Only require an explicit localization helper (e.g., L10n.tr(…)) when the string is not being passed through SwiftUI’s LocalizedStringKey path (e.g., plain String values provided to non-SwiftUI APIs).
Applied to files:
ios/VaultSync/Views/SettingsView.swiftios/VaultSync/Services/DiagnosticsCBOR.swiftios/VaultSync/Views/QRScannerView.swiftios/VaultSync/Views/ControlledDiagnosticsView.swiftios/VaultSync/Services/DiagnosticsPinnedTransport.swiftios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swiftios/VaultSync/Services/DiagnosticsCredentialStore.swiftios/VaultSync/Services/DiagnosticsPairingProtocol.swiftios/VaultSync/Services/DiagnosticsPairingController.swift
🪛 ast-grep (0.44.1)
ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
[warning] 209-209: This URLSession authentication-challenge delegate accepts the server's trust unconditionally by constructing URLCredential(trust:) and replying with .useCredential, which disables TLS certificate validation and exposes the app to man-in-the-middle attacks. Evaluate the server trust first (e.g. SecTrustEvaluateWithError) and implement certificate or public-key pinning, or return .performDefaultHandling to use the system's default validation.
Context: URLCredential(trust: trust)
Note: [CWE-295] Improper Certificate Validation.
(insecure-tls-trust-all-certs-swift)
🪛 LanguageTool
docs/app-capability-pairing-namespace-readiness.md
[style] ~18-~18: Consider removing “of” to be more concise
Context: ...iguration. The first mutation requires all of the following explicit actions: 1. The use...
(ALL_OF_THE)
🪛 SwiftLint (0.65.0)
ios/VaultSync/Services/DiagnosticsCBOR.swift
[Warning] 346-346: Prefer failable String(bytes:encoding:) initializer when converting Data to String
(optional_data_string_conversion)
ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
[Warning] 147-147: Prefer failable String(bytes:encoding:) initializer when converting Data to String
(optional_data_string_conversion)
ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
[Warning] 654-654: Prefer failable String(bytes:encoding:) initializer when converting Data to String
(optional_data_string_conversion)
🔇 Additional comments (32)
PRIVACY.md (1)
78-81: LGTM!Also applies to: 191-231
docs/app-capability-pairing-namespace-readiness.md (1)
1-171: LGTM!docs/architecture.md (1)
97-102: LGTM!Also applies to: 202-204
docs/helper-runtime-packaging-readiness.md (1)
200-203: LGTM!ios/VaultSync/Views/ControlledDiagnosticsView.swift (2)
1-120: LGTM!Also applies to: 288-460, 462-566
121-287: 🩺 Stability & AvailabilityNo additional in-flight guard needed.
DiagnosticsPairingController.perform(_:)already serializes these async actions withisBusy, so the button-triggeredTaskcalls won’t overlap.> Likely an incorrect or invalid review comment.ios/VaultSync/Views/QRScannerView.swift (1)
8-32: LGTM! The parameterized title/messages correctly reuse already-localizedStringvalues, and thedidScan.withLockguard properly closes the race that could otherwise let multiple QR detections triggeronScanmore than once.Also applies to: 58-58, 84-84, 111-117, 170-179
ios/VaultSync/Views/SettingsView.swift (1)
71-80: LGTM!ios/VaultSync/de.lproj/InfoPlist.strings (1)
2-2: LGTM!ios/VaultSync/zh-Hans.lproj/Localizable.strings (1)
813-915: LGTM! Spot-checked every new localization key against its usage inControlledDiagnosticsView.swift/QRScannerView.swiftand the coverage and format-specifier placement look correct.ios/project.yml (1)
81-81: LGTM!ios/VaultSync/de.lproj/Localizable.strings (1)
813-915: LGTM!ios/VaultSync/en.lproj/InfoPlist.strings (1)
2-2: LGTM!ios/VaultSync/en.lproj/Localizable.strings (1)
813-915: LGTM!ios/VaultSync/es.lproj/InfoPlist.strings (1)
2-2: LGTM!ios/VaultSync/Services/DiagnosticsCBOR.swift (3)
29-256: LGTM!
258-333: LGTM!
335-415: Syncthing device-ID parsing verified against upstream.Checked
rawDeviceID/luhn32against Syncthing's own implementation: the alphabet and the alternating-factor Luhn-mod-32 arithmetic match exactly. Syncthing'sluhn32usesfactor := 1, doubles/halves the factor per character, and foldsaddend = (addend / n) + (addend % n)into the running sum, which is the same computation as this Swift port. No changes needed.ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift (1)
4-664: LGTM!The capability/namespace protocol schemas (expected label sets, signature domains, epoch chaining in
validateHelperEpochManifest, installation-binding derivation) are internally consistent across every builder/validator pair I cross-checked.ios/VaultSync/Services/DiagnosticsPairingProtocol.swift (1)
4-641: LGTM!The message-type schema tables, signature-domain separation, and lifecycle continuation/field-forwarding logic are internally consistent across every path I traced (bootstrap chain, all three rotation kinds, revocation).
ios/VaultSync/Services/DiagnosticsPinnedTransport.swift (1)
40-155: LGTM!Path whitelist, disabled redirects, TLS 1.3-only configuration, bounded streaming read, and strict per-status-code Content-Length/Content-Type checks are all solid.
ios/VaultSync/Services/DiagnosticsCredentialStore.swift (2)
120-232: 🗄️ Data Integrity & Integration | ⚡ Quick win
@unchecked Sendableasserts thread-safety that the read-then-write logic doesn't actually provide.
installationCredential()andadvanceInstallationAppKey()each do a read-decide-write sequence against the marker file and Keychain with no lock. Today this is presumably safe because the only caller is the MainActor-serializedDiagnosticsPairingController.perform(), but the@unchecked Sendableconformance on the class itself asserts it's safe to call from any concurrent context. If a background task (e.g., aBGAppRefreshTaskhandler) or a second controller instance ever calls into this store concurrently with the main-actor path, two callers could both observe "no installation credential yet" and race to create/write one, corrupting the marker↔Keychain pairing invariant this class otherwise protects so carefully.Could you confirm no other call site (background task, extension, etc.) invokes
DiagnosticsCredentialStoreoutside the MainActor-gated controller? If any does, this class should own its own serialization (e.g., an internalNSLock/serial queue) rather than relying on caller discipline.
294-517: LGTM!
validate/validateNamespaceStatecross-check pending-lifecycle fields againstlastOutgoing/lastIncomingand enforce the namespace-field completeness invariants per state very thoroughly.ios/VaultSync/Services/DiagnosticsPairingController.swift (2)
87-1467: LGTM!The bootstrap/lifecycle state machine, local-deadline gating, capability-state invalidation on every credential mutation, and the installation-key catch-up/reuse logic in
proposedInstallationAppKeyare all consistent and restart-safe on every path I traced.
1482-1527: LGTM!
DiagnosticsNamespaceFileReader.readis a careful symlink-resistant, TOCTOU-safe read (per-componentopenat+O_NOFOLLOW,fstaton the descriptor, exact-size read with a trailing-byte check).ios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift (5)
9-183: LGTM!
185-510: LGTM!
512-829: LGTM!
831-1150: LGTM!
1153-1880: LGTM!ios/VaultSyncTests/DiagnosticsUploadM5Tests.swift (1)
233-281: LGTM!notify/diagnostics_contract_model_test.go (1)
293-294: LGTM!Also applies to: 317-332
Evaluate the exact SPKI-pinned private TLS trust before accepting a challenge and prevent certificate fetch fallback. Surface missing-folder namespace actions and clarify Spanish namespace and Simplified Chinese camera-permission security copy.
Scope
Safety and compatibility
Evidence boundary
This is an unreleased control-plane milestone. It creates no upload, response, cleanup, download, or roundtrip transfer artifact. Upload, download, roundtrip, cleanup, real-device, rollout, and Store evidence remain unset. Signatures prove authorship and exact bindings, not transport route, byte provenance, future delivery, or global sync health.
Verification
cd ios && xcodegen generatego test -tags noassets ./bridge -count=1cd notify && go test ./... -count=1cd notify && go vet ./...