Files
mdcaldav/docker/mdcaldav.toml
Tyler Perkins 6dd3829cfa
Some checks failed
CI / test (push) Failing after 6s
CI / image (push) Has been skipped
Write against the file, not a stale cache; stop indexing conflict files
Two deployment bugs that both present as "the client says done but the
markdown never changes, and nothing errors".

1. upload() diffed the client's VTODO against the cached in-memory task.
   When that cache disagreed with disk the diff came out empty, apply()
   returned early, and Radicale answered 2xx having written nothing.

   The cache goes stale on NFS: refresh_if_stale() compares stat(), and a
   `- [ ]` to `- [x]` toggle does not change the file's size, so mtime is
   the only signal — which NFS attribute caching hides for the length of
   the attr timeout. Add Index.refresh_file(), which compares the actual
   bytes, and call it before diffing.

2. docker/mdcaldav.toml set `exclude`, which REPLACES the built-in list
   rather than extending it, silently dropping the Syncthing patterns.
   Against a real Syncthing vault this reindexes `*.sync-conflict-*` (and
   `.stversions/`, which holds whole historical copies of every note): the
   task list gains duplicates, and completing one can write to a conflict
   file the user never opens while the note they are watching stays put.
   Drop the override so the defaults apply.

Also switch the container to a polling observer. inotify reports nothing
for a network mount written by another host, so `watch = true` was a
silent no-op exactly where it was most wanted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 15:58:16 -04:00

36 lines
1.4 KiB
TOML

[vault]
path = "/vault"
include = ["**/*.md"]
# `exclude` is deliberately not set: setting it REPLACES the built-in list,
# which is where the Syncthing patterns live (`.stversions/**`, which holds
# whole historical copies of your notes, and `*.sync-conflict-*`). Overriding
# it with just the VCS/editor globs silently reindexes both — you get duplicate
# tasks, and a completion can land in a conflict file you never open while the
# note you are actually looking at stays unchanged.
# To add your own, restate the defaults from config.DEFAULT_EXCLUDE too.
# Keeps the index warm off the request path. Purely a latency optimization:
# every read path calls refresh_if_stale(), so freshness does not depend on it.
watch = true
# Poll rather than wait on inotify. A containerized vault is usually a bind
# mount, and often a network one (NFS, CIFS) — inotify reports nothing at all
# for changes written by another host, so the watcher would sit silent. Set to
# 0 to use inotify when the vault is genuinely local.
poll_interval = 2.0
[collections]
group_by = "directory"
depth = 1
[write]
allow_create = true
allow_delete = true
inbox = "inbox.md"
inbox_heading = "## Inbox"
delete_children = "cascade"
# Recommended until you trust write-back. Kept outside the vault.
backup_dir = "/data/backups"
[index]
# Must NOT live inside /vault — it is a derived cache, not a note.
db = "/data/index.db"