feat(notify): prove dormant diagnostics namespace isolation - #110
Conversation
Document the future opt-in namespace's visibility across synchronized peers, file browsers, backups, versions, conflicts, remote history, and tombstones. Record that the M4 foundation is dormant and test-only, uses a separate helper state store, changes no Syncthing configuration, creates no namespace automatically, and sends no contract data to Cloud Relay. Limit currently tested support to an explicit Docker host bind mount and mark other packaging targets unsupported until isolation and rollback are proven.
Implement the fixed Decision 023 deterministic CBOR schemas, dual-signature ownership chains, stable installation bindings, and canonical namespace filenames as an unreachable internal foundation. Add shared Go/Swift golden records and four-language consent snapshots that disclose visibility and retention while remaining unreferenced by the app product flow. Keep the installed helper and app unchanged: no endpoint, listener, namespace creation, filesystem access, Syncthing mutation, Relay call, evidence transition, deployment, or rollout is introduced.
Add a separate crash-safe namespace state store and Linux descriptor-relative filesystem foundation with fixed protocol paths, create-once records, root and mount identity checks, complete ownership-chain validation, fail-closed collisions, and bounded idempotent cleanup. Add an explicit test-only preparation flow and Docker host-bind harness proving a read-only container root, separate state, read-only config, no parent-vault access, dropped capabilities, no network, and child-mount rejection. Run the harness in pull-request CI. Document visibility, retention, unsupported deployment targets, existing-user behavior, and rollback. Keep installed helper, app, Syncthing, Trigger v1, and Cloud Relay paths unchanged.
📝 WalkthroughWalkthroughAdds a dormant diagnostics namespace foundation with signed CBOR records, secure Linux filesystem operations, atomic state storage, installer preparation, extensive tests, localized disclosure copy, Docker confinement checks, and CI integration. Runtime and product activation remain explicitly blocked. ChangesDiagnostics namespace foundation
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 @.github/workflows/ci.yml:
- Line 96: Update the actions/checkout step to set persist-credentials to false,
ensuring this read-only job does not store the GITHUB_TOKEN in the repository’s
Git configuration.
🪄 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: c0d855db-5773-465a-ad70-ab79f3861c92
📒 Files selected for processing (27)
.github/workflows/ci.ymlCHANGELOG.mdPRIVACY.mddocs/architecture.mdios/VaultSync/de.lproj/Localizable.stringsios/VaultSync/en.lproj/Localizable.stringsios/VaultSync/es.lproj/Localizable.stringsios/VaultSync/zh-Hans.lproj/Localizable.stringsios/VaultSyncTests/DiagnosticsNamespaceM4GoldenTests.swiftios/VaultSyncTests/Fixtures/diagnostics-namespace-m4.jsonnotify/README.mdnotify/diagnostics_contract_model_test.gonotify/diagnostics_namespace_filesystem.gonotify/diagnostics_namespace_filesystem_linux.gonotify/diagnostics_namespace_filesystem_test.gonotify/diagnostics_namespace_filesystem_unsupported.gonotify/diagnostics_namespace_installer.gonotify/diagnostics_namespace_installer_linux.gonotify/diagnostics_namespace_installer_unsupported.gonotify/diagnostics_namespace_linux_test.gonotify/diagnostics_namespace_protocol.gonotify/diagnostics_namespace_protocol_test.gonotify/diagnostics_namespace_store.gonotify/diagnostics_namespace_store_test.gonotify/tests/m4-docker/Dockerfilenotify/tests/m4-docker/README.mdnotify/tests/m4-docker/run.sh
📜 Review details
🧰 Additional context used
📓 Path-based instructions (12)
**
⚙️ CodeRabbit configuration file
**:![]()
VaultSync
Self-hosted Obsidian vault sync for iPhone and iPad.
Your notes sync peer-to-peer over Syncthing, straight into Obsidian's iOS sandbox — no note cloud, no account, no tracking.![]()
![]()
![]()
🔭 Why VaultSync
- Peer-to-peer & private — syncs directly between your own devices over Syncthing. No note cloud, no account, no tracking.
- Lands in Obsidian — files sync into Obsidian's iOS sandbox, where the app already looks for them.
- Pair by QR, resolve conflicts — connect your server in seconds; settle Markdown conflicts with side-by-side diffs.
- Server changes can wake your iPhone — optional Cloud Relay asks iOS to wake the app after the helper observes a server change. T...
Files:
notify/tests/m4-docker/Dockerfileios/VaultSync/zh-Hans.lproj/Localizable.stringsnotify/diagnostics_namespace_installer_unsupported.goios/VaultSync/de.lproj/Localizable.stringsnotify/tests/m4-docker/README.mdPRIVACY.mdios/VaultSyncTests/Fixtures/diagnostics-namespace-m4.jsonios/VaultSync/es.lproj/Localizable.stringsnotify/diagnostics_namespace_filesystem_test.gonotify/diagnostics_namespace_filesystem_unsupported.goCHANGELOG.mdios/VaultSync/en.lproj/Localizable.stringsnotify/README.mdnotify/diagnostics_namespace_installer.godocs/architecture.mdnotify/tests/m4-docker/run.shnotify/diagnostics_namespace_store_test.gonotify/diagnostics_namespace_filesystem.goios/VaultSyncTests/DiagnosticsNamespaceM4GoldenTests.swiftnotify/diagnostics_contract_model_test.gonotify/diagnostics_namespace_protocol_test.gonotify/diagnostics_namespace_installer_linux.gonotify/diagnostics_namespace_store.gonotify/diagnostics_namespace_protocol.gonotify/diagnostics_namespace_linux_test.gonotify/diagnostics_namespace_filesystem_linux.go
**/*
⚙️ 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:
notify/tests/m4-docker/Dockerfileios/VaultSync/zh-Hans.lproj/Localizable.stringsnotify/diagnostics_namespace_installer_unsupported.goios/VaultSync/de.lproj/Localizable.stringsnotify/tests/m4-docker/README.mdPRIVACY.mdios/VaultSyncTests/Fixtures/diagnostics-namespace-m4.jsonios/VaultSync/es.lproj/Localizable.stringsnotify/diagnostics_namespace_filesystem_test.gonotify/diagnostics_namespace_filesystem_unsupported.goCHANGELOG.mdios/VaultSync/en.lproj/Localizable.stringsnotify/README.mdnotify/diagnostics_namespace_installer.godocs/architecture.mdnotify/tests/m4-docker/run.shnotify/diagnostics_namespace_store_test.gonotify/diagnostics_namespace_filesystem.goios/VaultSyncTests/DiagnosticsNamespaceM4GoldenTests.swiftnotify/diagnostics_contract_model_test.gonotify/diagnostics_namespace_protocol_test.gonotify/diagnostics_namespace_installer_linux.gonotify/diagnostics_namespace_store.gonotify/diagnostics_namespace_protocol.gonotify/diagnostics_namespace_linux_test.gonotify/diagnostics_namespace_filesystem_linux.go
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_namespace_installer_unsupported.gonotify/diagnostics_namespace_filesystem_test.gonotify/diagnostics_namespace_filesystem_unsupported.gonotify/diagnostics_namespace_installer.gonotify/tests/m4-docker/run.shnotify/diagnostics_namespace_store_test.gonotify/diagnostics_namespace_filesystem.gonotify/diagnostics_contract_model_test.gonotify/diagnostics_namespace_protocol_test.gonotify/diagnostics_namespace_installer_linux.gonotify/diagnostics_namespace_store.gonotify/diagnostics_namespace_protocol.gonotify/diagnostics_namespace_linux_test.gonotify/diagnostics_namespace_filesystem_linux.go
**/*.{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:
notify/diagnostics_namespace_installer_unsupported.gonotify/tests/m4-docker/README.mdPRIVACY.mdnotify/diagnostics_namespace_filesystem_test.gonotify/diagnostics_namespace_filesystem_unsupported.goCHANGELOG.mdnotify/README.mdnotify/diagnostics_namespace_installer.godocs/architecture.mdnotify/tests/m4-docker/run.shnotify/diagnostics_namespace_store_test.gonotify/diagnostics_namespace_filesystem.goios/VaultSyncTests/DiagnosticsNamespaceM4GoldenTests.swiftnotify/diagnostics_contract_model_test.gonotify/diagnostics_namespace_protocol_test.gonotify/diagnostics_namespace_installer_linux.gonotify/diagnostics_namespace_store.gonotify/diagnostics_namespace_protocol.gonotify/diagnostics_namespace_linux_test.gonotify/diagnostics_namespace_filesystem_linux.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_namespace_installer_unsupported.gonotify/diagnostics_namespace_filesystem_test.gonotify/diagnostics_namespace_filesystem_unsupported.gonotify/diagnostics_namespace_installer.gonotify/diagnostics_namespace_store_test.gonotify/diagnostics_namespace_filesystem.gonotify/diagnostics_contract_model_test.gonotify/diagnostics_namespace_protocol_test.gonotify/diagnostics_namespace_installer_linux.gonotify/diagnostics_namespace_store.gonotify/diagnostics_namespace_protocol.gonotify/diagnostics_namespace_linux_test.gonotify/diagnostics_namespace_filesystem_linux.go
**/*.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:
notify/tests/m4-docker/README.mdPRIVACY.mdCHANGELOG.mdnotify/README.mddocs/architecture.md
docs/**/*.md
📄 CodeRabbit inference engine (docs/troubleshooting.md)
docs/**/*.md: After applying each troubleshooting fix, retry from the app to confirm whether the issue is resolved.
For a missing Device ID or “Sync Engine Not Running,” force-close and reopen VaultSync, keep it foregrounded for 20–30 seconds, confirm the Device ID, rescan the vault, and reboot if necessary.
vaultsync-notifymust read the Syncthing API key fromconfig.xml; permission or authentication failures should be diagnosed as wrong-file or read-permission problems before changing credentials.
Runvaultsync-notifyas the user owning Syncthing’s mode-0600config.xml, or configure the appropriate containerPUID/PGID.
SetSYNCTHING_CONFIGwhen the Syncthing configuration is not auto-detected, and remove or correctSYNCTHING_API_KEYoverrides that replace automatic detection.
For relay failures, verify internet access,RELAY_URL, server egress rules, relay health with curl, and the app’s relay diagnostics; confirm delivery through an updated “Last Trigger Received” timestamp.
A relay HTTP 429 from--doctorcounts as success because it proves the trigger endpoint is reachable; an inactive subscription is a warning fixed through app subscription or provisioning.
Peer-state warnings from--doctormust not fail the command: offline peers are normal, and--healthcheckmust skip peer-state diagnostics.
For missing pending shares, verify the desktop folder shares the exact iOS Device ID, ensure Syncthing is online and unpaused, refresh pending shares, and re-share if needed.
For APNs issues, retry APNs registration, verify a token appears, retry provisioning, and confirm delivery with “Last Trigger Received”; notification permission is not required for silent wake-ups.
When connecting Obsidian storage, chooseOn My iPhone → Obsidianor the vault root containing.obsidian, then confirm detected vaults or pending shares.
VaultSync must not move, recreate, or delete vault folders automatically; recovery from moved or deleted folders requires ma...
Files:
docs/architecture.md
docs/**
⚙️ CodeRabbit configuration file
docs/**: # ArchitectureVaultSync embeds Syncthing's Go reference implementation as an iOS library via gomobile — no reimplementation of the protocol in Swift, and guaranteed wire compatibility.
┌─────────────────────────────────┐ │ SwiftUI Frontend │ iOS-native UI, Swift 6 ├─────────────────────────────────┤ │ Swift ↔ Go Bridge │ thin API via gomobile │ │ → exported as .xcframework ├─────────────────────────────────┤ │ syncthing/lib (Go) │ protocol, discovery, sync └─────────────────────────────────┘ ↕ filesystem ┌─────────────────────────────────┐ │ Obsidian Vault (direct) │ Obsidian's iOS sandbox └─────────────────────────────────┘🔄 Sync strategy
- Foreground — Syncthing runs unrestricted: immediate, continuous sync.
- Background —
BGAppRefreshTask(requested ~15 min out; iOS decides the actual timing) +BGProcessingTask(overnight catch-up: multi-minute budget while charging with network) +BGContinuedProcessingTask(iOS 26+, longer runtime for user-initiated tasks). A ~30s grace window after backgrounding lets in-flight work finish.- Push (Cloud Relay) — optional. Near-realtime
server → iPhonewake-ups via APNs silent push. See relay-spec.md.VaultSync is intentionally asymmetric:
Direction Path Server → iPhone vaultsync-notifyspots outgoing changes → Cloud Relay silent push → VaultSync wakes and pulls.iPhone → Server iOS doesn't guarantee timely background execution for local edits. The reliable path is to open VaultSync and let embedded Syncthing run in the foreground — a Shortcuts automation can do that automatically whenever you leave Obsidian. Cloud Relay is a
server → iPhoneacceleration path, not a guarantee of symmetric real-time background sync.Relay and sync proof hierarchy
VaultSync models proof as independent fi...
Files:
docs/architecture.md
.github/workflows/**/*.yml
⚙️ CodeRabbit configuration file
.github/workflows/**/*.yml: Review CI for correct Go test tags, Xcode/iOS simulator assumptions, secret scoping,
dependency integrity, permissions, Docker publishing safety, and unnecessary privilege escalation.
Files:
.github/workflows/ci.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/DiagnosticsNamespaceM4GoldenTests.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/DiagnosticsNamespaceM4GoldenTests.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/DiagnosticsNamespaceM4GoldenTests.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/DiagnosticsNamespaceM4GoldenTests.swift
🧠 Learnings (1)
📚 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/DiagnosticsNamespaceM4GoldenTests.swift
🪛 ast-grep (0.44.1)
notify/diagnostics_namespace_filesystem_linux.go
[warning] 617-617: Narrowing a non-constant integer to a smaller fixed-width type (int8/int16/int32, uint8/uint16/uint32) can silently overflow or wrap, yielding negative or truncated values that are dangerous in size, length, or index logic. Validate the source value is within the target type's range before converting (e.g. bounds-check, or use a checked helper), and avoid narrowing untrusted or len()/parsed values.
Context: uint32(os.Geteuid())
Note: [CWE-190] Integer Overflow or Wraparound.
(integer-overflow-narrowing-conversion-go)
[warning] 632-632: Narrowing a non-constant integer to a smaller fixed-width type (int8/int16/int32, uint8/uint16/uint32) can silently overflow or wrap, yielding negative or truncated values that are dangerous in size, length, or index logic. Validate the source value is within the target type's range before converting (e.g. bounds-check, or use a checked helper), and avoid narrowing untrusted or len()/parsed values.
Context: uint32(os.Geteuid())
Note: [CWE-190] Integer Overflow or Wraparound.
(integer-overflow-narrowing-conversion-go)
[warning] 659-659: File path is assembled with fmt.Sprintf and passed straight into a file read (os.ReadFile / os.Open / ioutil.ReadFile). Interpolating untrusted segments into a path format string permits '../' traversal. Validate and sanitize each path segment before use (e.g. reject inputs containing '..', resolve with filepath.Clean and enforce a directory-bound check with filepath.Rel, rejecting any result that escapes the allowed base directory) instead of formatting the path with fmt.Sprintf.
Context: os.ReadFile(fmt.Sprintf("/proc/self/fdinfo/%d", file.Fd()))
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(os-readfile-sprintf-path-go)
🪛 zizmor (1.26.1)
.github/workflows/ci.yml
[warning] 96-96: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🔇 Additional comments (33)
notify/diagnostics_namespace_protocol.go (1)
101-658: LGTM!notify/diagnostics_namespace_protocol_test.go (1)
17-432: LGTM!ios/VaultSyncTests/Fixtures/diagnostics-namespace-m4.json (1)
1-7: LGTM!ios/VaultSyncTests/DiagnosticsNamespaceM4GoldenTests.swift (2)
33-82: LGTM!Also applies to: 157-182
85-118: LGTM!ios/VaultSync/en.lproj/Localizable.strings (1)
811-812: LGTM!ios/VaultSync/es.lproj/Localizable.strings (1)
811-812: LGTM!ios/VaultSync/zh-Hans.lproj/Localizable.strings (1)
811-812: LGTM!notify/diagnostics_contract_model_test.go (3)
289-289: LGTM!
311-320: 🎯 Functional CorrectnessAllow-list extension mirrors the existing pairing pattern — looks correct.
Scoping is symmetric with the pre-existing
pairing/pairingProtocolCarrierhandling, which is the right shape for adding a new dormant carrier. The exactfixture.Capabilities/fixture.Domainskey names ("namespace" / "namespace.*") live in a fixture not included in this review batch, so I can't fully confirm the string match here, but the structure is sound.
348-396: LGTM! Good defense-in-depth: the newTestDiagnosticsNamespaceFoundationCannotMutateSyncthingOrReachNetworkglob-scans every non-testdiagnostics_namespace_*.gofile for network/Syncthing/Relay carriers, which is exactly the kind of automated guardrail that keeps a "dormant" foundation honestly dormant as it grows.notify/README.md (1)
130-154: LGTM!CHANGELOG.md (2)
11-11: LGTM!
22-22: LGTM!PRIVACY.md (2)
3-3: LGTM!
76-117: LGTM! Solid, honest privacy disclosure — it correctly gets ahead of the feature by disclosing visibility/retention risk before any runtime wiring exists, consistent with the dormancy guarantees enforced in the Go tests.docs/architecture.md (2)
114-133: LGTM!
144-152: LGTM!ios/VaultSync/de.lproj/Localizable.strings (1)
810-812: LGTM! Placeholder count, quoting style, and terminology all check out against the English source string.notify/diagnostics_namespace_filesystem.go (1)
1-197: LGTM!notify/diagnostics_namespace_filesystem_test.go (1)
1-63: LGTM!notify/diagnostics_namespace_installer.go (1)
1-63: LGTM!notify/diagnostics_namespace_installer_linux.go (2)
1-76: LGTM!Also applies to: 83-274
77-82: 🔒 Security & PrivacyReopen path is already fenced
openDiagnosticsNamespaceRoot()Lstat-checks the full alias, opens it as anos.Root, and SameFile-checks the alias/root/anchor identities, so thefilepath.Joinreopen does not bypass the existing confinement checks.> Likely an incorrect or invalid review comment.notify/diagnostics_namespace_installer_unsupported.go (1)
1-19: LGTM!notify/diagnostics_namespace_store_test.go (1)
1-206: LGTM!notify/tests/m4-docker/Dockerfile (1)
1-10: LGTM!notify/diagnostics_namespace_filesystem_linux.go (1)
29-408: LGTM!notify/diagnostics_namespace_filesystem_unsupported.go (1)
5-39: LGTM!notify/diagnostics_namespace_store.go (1)
56-333: LGTM!notify/tests/m4-docker/README.md (1)
1-26: LGTM!notify/tests/m4-docker/run.sh (1)
1-69: LGTM!notify/diagnostics_namespace_linux_test.go (1)
16-653: LGTM!
Disable checkout credential persistence in the read-only M4 Docker confinement job. Keep the proof behavior and all runtime surfaces unchanged.


Summary
Safety boundaries
The installed helper and app do not call this foundation. There is no listener, endpoint, capability advertisement, automatic discovery, automatic namespace creation, Syncthing configuration mutation, Relay call, production service, deployment, or product flow. Decision 024 is unchanged. Trigger v1 and Cloud Relay v1 remain unchanged. Upload attestation, controlled download, roundtrip evidence, and authenticated operational correlation remain unimplemented.
Real Syncthing-matcher integration and a production installer are intentionally absent, so runtime support is not claimed. The dormant preparation primitive only accepts an externally evaluated fail-closed ignore verdict plus explicit operator confirmation. Swift remains test-only for the new records and consent copy.
Docker evidence
notify/tests/m4-docker/run.shproves one narrow shape:VaultSync Diagnosticshost bind, separate state, and read-only config;no-new-privilegesis set, and no parent-vault path is visible; andinstallationschild is rejected by Linux mount identity.Docker named volumes, rootless Docker, NAS packages, Linux host packaging, macOS, and Windows remain unsupported for this capability.
Compatibility, privacy, and rollback
Existing users receive no folder, mount, state, pairing, credential, migration, or configuration change. The wire surface is unchanged because no installed entrypoint references the new code. Namespace state is separate from credential state and contains only opaque bindings, a fixed mount alias, manifest digest, device, and inode.
Cleanup targets at most three exact authenticated operation files and never upgrades evidence. Missing files are idempotent success; changed, linked, raced, sparse, unknown, conflict, or unverified entries remain untouched. Root records, authorizations, credentials, backups, versions, conflict copies, remote history, and tombstones are never cleanup targets. Rollback removes only future capability availability; it does not delete state or synchronized history.
Validation
cd notify && go test ./... -count=1cd notify && go test -race ./... -count=1cd notify && go vet ./...notify/tests/m4-docker/run.shsh -nfor the Docker harnessgovulncheck1.6.0 for Notify and the Go bridgecd go && make patch && go test -tags noassets ./bridge -count=1gofmt, andgit diff --check