From 694ff89b51873f4edf3328b639f421d8e0178dc9 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 20 Aug 2026 10:18:30 +0200 Subject: docs: close item 124, record the spinner defect, keep 121 open Item 124 shipped and is proven: the index moved from a 7200rpm platter to NVMe with the mail staying at /data/Mail. Cold start went from 38618 ms to 668 ms for a complete walk, and 2008 ms to 50 ms for the first rows. Counts held at 49174 messages / 5594 inbox / 100 tags at every step, and Delete then Restore round-tripped through the account's trash by hand. Item 121 stays open, and its entry now says why. The measured platter figures are the evidence FOR building the indicator, not against it: a mechanical disk is the cheap configuration, not an exotic one, and a user with a large Maildir on spinning rust has nowhere to migrate to. Fixing one developer's hardware is not fixing the application. The constraint that pointed at item 124 as the answer is replaced by one saying the opposite, and prefaulting stays rejected on its own merits since it is worst on the low-memory machines most likely to have a slow disk. Item 125 is new, found by hand during the migration. mailsync.sh exits 75 (EX_TEMPFAIL) when another run holds the lock, and the sync indicator never clears; because an edit made during a sync is held until the sync ends, a Delete sat queued for a completion that could not arrive and looked like it had done nothing. Nothing was lost, since held edits reach the disk, but the user cannot tell that. Also records in CLAUDE.md that notmuch_database_get_path() is not the mail root, that database.hook_dir defaults into the index directory and silently stops post-new under a split config, and that the ordinary fixture layout cannot tell the two accessors apart. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01YDq53rMd3AQp7QmcZzpuBM --- CLAUDE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'CLAUDE.md') diff --git a/CLAUDE.md b/CLAUDE.md index 2065a10..a6e19e5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -222,6 +222,27 @@ confirmation dialogs for tag mutations. All actions funnel through one `applyTag multi-row selections go through `applyTagsToThreads`, which resolves every thread in ONE combined `thread:a or thread:b` query rather than one query per thread. +**`notmuch_database_get_path()` is not the mail root, and assuming it is +moves mail somewhere mbsync cannot see.** notmuch can split the index from the +mail with `mail_root` and `path` as separate keys, which is how the Xapian +index goes on faster storage while the Maildir stays put. Under that layout +`get_path()` returns the INDEX directory. `mailRootOf()` in `notmuchworker.cpp` +wraps `notmuch_config_get(NOTMUCH_CONFIG_MAIL_ROOT)`, which is correct under +BOTH layouts, so there is no conditional and no reason to reach for the old +accessor again. Item 124, and the developer's own index has run split since +2026-08-20, so this is live rather than hypothetical. + +The consequences were asymmetric, which is why it is worth remembering: a wrong +root made message paths resolve to `../..` escapes that match no account, a +display defect, but `moveMessages` composes its destination from the same root, +so Delete would have written into the Xapian tree. Two related traps sit outside +the code. `database.hook_dir` defaults to `/.notmuch/hooks`, so a +split config silently stops running `post-new` while `notmuch new` still reports +success; it must be set explicitly. And a test cannot see any of this in the +ordinary fixture layout, where the index lives inside the mail root and both +accessors return the same string: `NotmuchFixture::splitIndex()` exists for +that, and a test without it passes whichever accessor the code uses. + **The Maildir path is deliberately not configurable.** notmuch stores it as `database.path` and libnotmuch reads it; duplicating it would create two sources of truth. The only escape hatch is `general/notmuch_config`, pointing at an alternate notmuch config. -- cgit v1.2.3