docs: add ADRs for cache concurrency and git signing fallback (guard — from commits 42bb6c4, 6dbcc33)

This commit is contained in:
lucaronin
2026-04-24 08:03:58 +02:00
parent b7f482bf27
commit 2308b269c8
3 changed files with 75 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
---
type: ADR
id: "0077"
title: "Concurrent-safe vault cache replacement"
status: active
date: 2026-04-24
---
## Context
ADR-0014 and ADR-0024 established Tolaria's git-based persistent vault cache and moved it outside the vault directory. That cache was still being rewritten with a simple temp-file-and-rename flow.
Once Tolaria started reopening the same vault from multiple windows/processes more often, that write model became too optimistic: two scans could both build valid cache payloads from different moments in time, and the slower writer could still atomically replace a fresher cache written by another window. The cache needed cross-window safety without introducing a long-lived coordinator process or making vault open dependent on heavyweight IPC.
## Decision
**Tolaria now treats vault-cache replacement as a best-effort compare-and-swap operation instead of an unconditional atomic overwrite.**
- Each scan still builds the next cache payload in memory and writes it to a temp file first.
- Before replacing the real cache file, Tolaria acquires a short-lived lock file for that vault cache path.
- After the lock is acquired, Tolaria rechecks the on-disk cache fingerprint and only renames the temp file into place if another window/process has not already refreshed the cache.
- If the cache changed underneath the current scan, Tolaria skips the replace and keeps the newer on-disk cache.
- Stale cache-write locks are garbage-collected after a short timeout so a crashed writer does not block future refreshes.
## Options considered
- **Lock + fingerprint guarded replacement** (chosen): keeps the cache file external and file-based, avoids overwriting fresher cache state from another Tolaria window, and preserves graceful fallback to filesystem rescans. Cons: cache writes become best-effort rather than guaranteed after every scan.
- **Keep unconditional temp-file + rename**: simplest implementation, but concurrent windows can regress the cache to an older view even though each individual replace is atomic.
- **Centralized cache service or long-lived process mutex**: strongest coordination story, but too much operational complexity for a local desktop app and would create new failure modes around boot, process lifetime, and IPC.
## Consequences
- Tolaria's cache correctness model is now "latest successful guarded replace wins," not "every scan must write a cache file."
- Cache refreshes must tolerate a skipped write when another window/process already produced a fresher cache.
- Temp-file writes and renames still provide corruption resistance, but freshness is protected separately by the writer lock and fingerprint check.
- Cache-write failures remain non-fatal: Tolaria logs them and falls back to rebuilding from the filesystem when needed.
- Re-evaluate if Tolaria later needs stronger cross-process coordination than lock-file + fingerprint checks can provide.

View File

@@ -0,0 +1,36 @@
---
type: ADR
id: "0078"
title: "Scoped unsigned fallback for app-managed git commits"
status: active
date: 2026-04-24
---
## Context
ADR-0021, ADR-0059, and ADR-0070 all assume Tolaria can create and advance a local git-backed vault without asking users to debug git internals first. In practice, inherited `commit.gpgsign` settings were breaking that promise: a missing or misconfigured GPG/SSH signing helper could block the initial `Initial vault setup` commit during onboarding and could also strand later app-triggered commits behind opaque signing failures.
Tolaria needed a policy that kept signed workflows intact when the user's signing setup actually works, while still ensuring app-managed git operations do not become unusable just because a desktop environment cannot reach the signing helper.
## Decision
**Tolaria uses a scoped unsigned fallback for app-managed commits instead of requiring signing to succeed unconditionally.**
- The onboarding/setup commit (`Initial vault setup`) always runs with `commit.gpgsign=false` for that single git invocation.
- Normal app-managed `git_commit` calls still honor the user's existing git signing configuration first.
- If a commit fails and Git's error matches a signing-helper failure, Tolaria retries that same app-managed commit once with signing disabled.
- Tolaria does not rewrite the user's git config and does not broaden the retry to unrelated commit failures.
## Options considered
- **Scoped unsigned fallback for app-managed commits** (chosen): keeps onboarding and local commit flows resilient while still preserving signed commits when the user's environment supports them. Cons: some Tolaria-created commits may be unsigned on machines with broken signing setups.
- **Require signing to succeed for every commit**: simplest policy, but it turns missing desktop GPG/SSH helpers into app-breaking failures during onboarding and normal use.
- **Disable signing for all Tolaria-triggered commits**: maximally robust, but it would silently bypass working signing setups and weaken users' expected git security posture.
## Consequences
- New vault creation is no longer blocked by inherited signing settings that only fail in Tolaria's app context.
- Users with healthy signing setups still get signed Tolaria commits after the first normal attempt succeeds.
- Signing-failure detection must stay narrow so Tolaria does not mask unrelated git errors behind an unsigned retry.
- Tolaria's git integration now explicitly prefers "complete the app-managed commit safely" over "preserve signing at all costs" when the signing helper is unavailable.
- Re-evaluate if Tolaria later exposes per-vault git policy controls or needs a richer user-facing explanation for when a fallback unsigned commit was used.

View File

@@ -132,3 +132,5 @@ proposed → active → superseded
| [0074](0074-explicit-external-ai-tool-setup-and-least-privilege-desktop-scope.md) | Explicit external AI tool setup and least-privilege desktop scope | active |
| [0075](0075-crash-safe-note-rename-transactions.md) | Crash-safe note rename transactions | active |
| [0076](0076-note-retargeting-separates-type-and-folder-moves.md) | Note retargeting separates type changes from folder moves | active |
| [0077](0077-concurrent-safe-vault-cache-replacement.md) | Concurrent-safe vault cache replacement | active |
| [0078](0078-scoped-unsigned-fallback-for-app-managed-git-commits.md) | Scoped unsigned fallback for app-managed git commits | active |