Skip to content

feat: add explicit diagnostics app control plane - #125

Merged
psimaker merged 4 commits into
mainfrom
agent/app-capability-pairing-namespace-enablement
Jul 14, 2026
Merged

feat: add explicit diagnostics app control plane#125
psimaker merged 4 commits into
mainfrom
agent/app-capability-pairing-namespace-enablement

Conversation

@psimaker

@psimaker psimaker commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Scope

  • Add the explicit Decision 022/023 app control plane for one user-selected homeserver and already-shared folder.
  • Negotiate the Decision 024 capability with mutually signed canonical messages and honest unavailable/unsupported states.
  • Require QR-pinned TLS 1.3, a separately confirmed transcript fingerprint, and fixed local/LAN/VPN paths.
  • Store installation and scoped credentials only in a dedicated non-synchronizable, device-only Keychain service bound to protected app storage.
  • Provide explicit app/helper/TLS rotation, revocation, lost-key recovery, and restart-safe byte-identical retries.
  • Gate namespace enablement on a separate app action and operator creation, then validate immutable helper-countersigned records through symlink-resistant fixed-path reads.
  • Reuse one durably staged installation app key across independent folder rotations and block another generation until every non-revoked authorization catches up.
  • Add localized consent and recovery copy for en, de, es, and zh-Hans.

Safety and compatibility

  • Existing-user upgrade, launch, Settings inspection, Relay wake-up, and ordinary sync create no key, pairing, request, namespace, peer, share, trust decision, or artifact.
  • No discovery, mDNS, UPnP, public default port, Relay tunnel, automatic namespace creation, trust adoption, or Syncthing configuration mutation is added.
  • Old apps ignore the additive helper records; old or disabled helpers remain capability unavailable without fallback.
  • App downgrade retains credentials and namespace copies but resumes no operation; re-upgrade requires read-only reconstruction, a fresh capability check, and current authorization.
  • Backups, versions, conflicts, peer copies, history, and tombstones may retain namespace artifacts; revocation and recovery do not claim deletion.
  • Decision 024 and Trigger/Relay v1 wire behavior remain unchanged.

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 generate
  • Focused diagnostics runtime suite: 20 passed
  • Full iOS simulator suite on iPhone 17 Pro / iOS 26.5: 425 passed, 0 failed, 0 skipped
  • go test -tags noassets ./bridge -count=1
  • cd notify && go test ./... -count=1
  • cd notify && go vet ./...
  • Notify formatting and publication-safety policy checks
  • Design-token lint
  • Strings key parity: 862 keys across en/de/es/zh-Hans
  • All localized app and widget plist files passed lint
  • Diff, footer, credential/token/PEM, and high-entropy scans passed

psimaker added 2 commits July 15, 2026 00:17
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.
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Controlled diagnostics runtime

Layer / File(s) Summary
Readiness and privacy documentation
PRIVACY.md, docs/*.md
Documents helper 2.0.2 status, explicit pairing and namespace controls, credential boundaries, compatibility, evidence limits, and verification scope.
Deterministic encoding and cryptographic bindings
ios/VaultSync/Services/DiagnosticsCBOR.swift
Adds bounded canonical CBOR, cryptographic helpers, transcript fingerprints, and Syncthing identifier validation.
Protocol messages and pinned transport
ios/VaultSync/Services/Diagnostics*Protocol.swift, ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
Implements capability, namespace, pairing, lifecycle, signing, validation, and pinned TLS transport flows.
Credential persistence and pairing orchestration
ios/VaultSync/Services/DiagnosticsCredentialStore.swift, ios/VaultSync/Services/DiagnosticsPairingController.swift
Adds device-only credential and record storage plus pairing, namespace, lifecycle, revocation, recovery, and deadline state machines.
Controlled diagnostics UI and localization
ios/VaultSync/Views/*, ios/VaultSync/*lproj/*, ios/project.yml
Adds Settings access, pairing and credential-maintenance screens, configurable QR scanning, camera permission text, and localized diagnostics strings.
Runtime coverage and contract allowlists
ios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift, ios/VaultSyncTests/DiagnosticsUploadM5Tests.swift, notify/diagnostics_contract_model_test.go
Adds protocol, persistence, state-machine, transport, filesystem, and contract-carrier tests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Poem

Canonical bytes align,
Keys turn softly, states advance,
QR sparks a handshake bright,
Namespaces wait for signed consent,
Tests guard every dance.

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Private Note Leakage ✅ Passed New network bodies use digests/IDs only; currentFolderPath stays local in fixed-file reads, and logs are generic/non-sensitive.
Bounded Ios Background Work ✅ Passed PASS: this PR adds async diagnostics flows, but no BGTask/expiration-handler background code; the operations are state-bounded and errors stay generic, so the check is not applicable.
Bridge Contract Compatibility ✅ Passed PASS: No bridge surface changed; go/bridge still uses primitive/string/JSON returns and empty-string success, and SyncBridgeService/bridge tests remain unchanged.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise, conventional-commit styled, and accurately summarizes the main change.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/app-capability-pairing-namespace-enablement

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.
@psimaker
psimaker marked this pull request as ready for review July 14, 2026 22:49

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
ios/VaultSync/Services/DiagnosticsPairingProtocol.swift (1)

627-633: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Same unixSeconds/wallSeconds clock-bounds helper duplicated in four places. Each copy independently rounds Date().timeIntervalSince1970 down and guards the same [0, UInt64.max) range before converting to UInt64, throwing DiagnosticsProtocolError.invalidMessage otherwise — the same logic feeding every issued/expires and clock-skew check across the protocol.

  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift#L627-L633: promote this unixSeconds (or move it next to checkedAdding, which the other files already call as a shared utility) into a single internal helper, e.g. on DiagnosticsPairingProtocol or DiagnosticsCrypto.
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift#L119-L125: replace DiagnosticsCapabilityProtocol.unixSeconds with a call to the shared helper.
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift#L657-L663: replace DiagnosticsNamespaceProtocol.unixSeconds with a call to the shared helper.
  • ios/VaultSync/Services/DiagnosticsPairingController.swift#L1433-L1439: replace wallSeconds()'s body with a call to the shared helper (keep the wallSeconds name/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

📥 Commits

Reviewing files that changed from the base of the PR and between 42cadb2 and 85b83e3.

📒 Files selected for processing (25)
  • PRIVACY.md
  • docs/app-capability-pairing-namespace-readiness.md
  • docs/architecture.md
  • docs/helper-runtime-packaging-readiness.md
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingController.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/SettingsView.swift
  • ios/VaultSync/de.lproj/InfoPlist.strings
  • ios/VaultSync/de.lproj/Localizable.strings
  • ios/VaultSync/en.lproj/InfoPlist.strings
  • ios/VaultSync/en.lproj/Localizable.strings
  • ios/VaultSync/es.lproj/InfoPlist.strings
  • ios/VaultSync/es.lproj/Localizable.strings
  • ios/VaultSync/zh-Hans.lproj/InfoPlist.strings
  • ios/VaultSync/zh-Hans.lproj/Localizable.strings
  • ios/VaultSyncTests/DiagnosticsAppRuntimeM3Tests.swift
  • ios/VaultSyncTests/DiagnosticsUploadM5Tests.swift
  • ios/project.yml
  • notify/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.strings
  • ios/VaultSync/es.lproj/InfoPlist.strings
  • ios/VaultSync/zh-Hans.lproj/InfoPlist.strings
  • ios/VaultSync/de.lproj/InfoPlist.strings
  • ios/VaultSync/de.lproj/Localizable.strings
  • ios/VaultSync/zh-Hans.lproj/Localizable.strings
  • ios/project.yml
  • ios/VaultSyncTests/DiagnosticsUploadM5Tests.swift
  • ios/VaultSync/es.lproj/Localizable.strings
  • ios/VaultSync/en.lproj/Localizable.strings
  • ios/VaultSync/Views/SettingsView.swift
  • docs/architecture.md
  • docs/app-capability-pairing-namespace-readiness.md
  • docs/helper-runtime-packaging-readiness.md
  • PRIVACY.md
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • notify/diagnostics_contract_model_test.go
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/VaultSync/Services/DiagnosticsPairingController.swift
  • ios/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.swift
  • ios/VaultSync/Views/SettingsView.swift
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/VaultSync/Services/DiagnosticsPairingController.swift
  • ios/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.swift
  • ios/VaultSync/Views/SettingsView.swift
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/VaultSync/Services/DiagnosticsPairingController.swift
  • ios/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.swift
  • ios/VaultSync/Views/SettingsView.swift
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/VaultSync/Services/DiagnosticsPairingController.swift
  • ios/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.swift
  • ios/VaultSync/Views/SettingsView.swift
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/VaultSync/Services/DiagnosticsPairingController.swift
  • ios/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.swift
  • ios/VaultSync/Views/SettingsView.swift
  • docs/architecture.md
  • docs/app-capability-pairing-namespace-readiness.md
  • docs/helper-runtime-packaging-readiness.md
  • PRIVACY.md
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • notify/diagnostics_contract_model_test.go
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/VaultSync/Services/DiagnosticsPairingController.swift
  • ios/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 supported vaultsync-notify installation 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; --healthcheck must omit peer-state checks so offline peers do not make the container unhealthy.
Explain that vaultsync-notify reads the Syncthing API key from config.xml; permission or wrong-file errors should be diagnosed through the process user, SYNCTHING_CONFIG, and any SYNCTHING_API_KEY override 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.md
  • docs/app-capability-pairing-namespace-readiness.md
  • docs/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.md
  • docs/app-capability-pairing-namespace-readiness.md
  • docs/helper-runtime-packaging-readiness.md
  • PRIVACY.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.swift
  • ios/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.swift
  • ios/VaultSync/Services/DiagnosticsCBOR.swift
  • ios/VaultSync/Views/QRScannerView.swift
  • ios/VaultSync/Views/ControlledDiagnosticsView.swift
  • ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
  • ios/VaultSync/Services/DiagnosticsCapabilityNamespaceProtocol.swift
  • ios/VaultSync/Services/DiagnosticsCredentialStore.swift
  • ios/VaultSync/Services/DiagnosticsPairingProtocol.swift
  • ios/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 & Availability

No additional in-flight guard needed. DiagnosticsPairingController.perform(_:) already serializes these async actions with isBusy, so the button-triggered Task calls 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-localized String values, and the didScan.withLock guard properly closes the race that could otherwise let multiple QR detections trigger onScan more 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 in ControlledDiagnosticsView.swift/QRScannerView.swift and 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/luhn32 against Syncthing's own implementation: the alphabet and the alternating-factor Luhn-mod-32 arithmetic match exactly. Syncthing's luhn32 uses factor := 1, doubles/halves the factor per character, and folds addend = (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 Sendable asserts thread-safety that the read-then-write logic doesn't actually provide.

installationCredential() and advanceInstallationAppKey() 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-serialized DiagnosticsPairingController.perform(), but the @unchecked Sendable conformance on the class itself asserts it's safe to call from any concurrent context. If a background task (e.g., a BGAppRefreshTask handler) 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 DiagnosticsCredentialStore outside the MainActor-gated controller? If any does, this class should own its own serialization (e.g., an internal NSLock/serial queue) rather than relying on caller discipline.


294-517: LGTM!

validate/validateNamespaceState cross-check pending-lifecycle fields against lastOutgoing/lastIncoming and 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 proposedInstallationAppKey are all consistent and restart-safe on every path I traced.


1482-1527: LGTM!

DiagnosticsNamespaceFileReader.read is a careful symlink-resistant, TOCTOU-safe read (per-component openat+O_NOFOLLOW, fstat on 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

Comment thread ios/VaultSync/es.lproj/Localizable.strings Outdated
Comment thread ios/VaultSync/Services/DiagnosticsPinnedTransport.swift
Comment thread ios/VaultSync/Views/ControlledDiagnosticsView.swift
Comment thread ios/VaultSync/zh-Hans.lproj/InfoPlist.strings Outdated
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.
@psimaker
psimaker merged commit 7622b22 into main Jul 14, 2026
31 of 32 checks passed
@psimaker
psimaker deleted the agent/app-capability-pairing-namespace-enablement branch July 14, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant