aboutsummaryrefslogtreecommitdiffstats
path: root/assets/hooks
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-25 11:33:29 +0200
committerDanilo M. <danix@danix.xyz>2026-08-25 11:33:29 +0200
commit7a810640b2fabafd8da524b275cb4453a1953df6 (patch)
tree588e5e4c4e165d82bda6aa1f2df64e317c5b56e2 /assets/hooks
parent0c98e07afc848b5563263945c94076125e265f79 (diff)
downloadqtmaildir-7a810640b2fabafd8da524b275cb4453a1953df6.tar.gz
qtmaildir-7a810640b2fabafd8da524b275cb4453a1953df6.zip
chore(hooks): log how many messages the sent carve-out matched
Item 164 diagnostics. A `notmuch tag` that matches nothing succeeds, so the carve-out logged "applied over N folder(s)" whether it stripped `inbox` from four messages or from none. A draft kept `inbox` on a pass whose log claimed the carve-out had run, and that line could not tell the two cases apart. Count before tagging, since the tag is what makes the count zero, and report it alongside the folder count. Nothing branches on the value: a failed count yields `?` rather than failing the sync, because the tag reports its own status separately. This does not fix item 164, whose trigger is still unreproduced. It makes the next occurrence self-explaining: `0 message(s)` means the message was never in tag:new scope, and a non-zero count means the tag ran over it and something re-added the tag afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UUQS6n3cmsFrsjCNmwNtf8
Diffstat (limited to 'assets/hooks')
-rwxr-xr-xassets/hooks/post-new27
1 files changed, 26 insertions, 1 deletions
diff --git a/assets/hooks/post-new b/assets/hooks/post-new
index 5102103..428ec29 100755
--- a/assets/hooks/post-new
+++ b/assets/hooks/post-new
@@ -104,10 +104,21 @@ def strip_inbox_from_sent(run):
return True
query = f"{SCOPE} and ({qtmaildirconf.sent_query(folders)})"
+
+ # Counted BEFORE the tag, because the tag is what makes the count zero.
+ # A `notmuch tag` that matches nothing SUCCEEDS, so the old log line said
+ # "applied" whether it stripped four messages or none, and item 164 is
+ # exactly the case where that distinction is the whole question: a draft
+ # kept `inbox` on a pass whose log claimed the carve-out had run. The
+ # count is the only thing that separates "the tag ran and something
+ # re-added inbox afterwards" from "the message was never in scope".
+ matched = count(query)
+
if not run(["-inbox"], query):
return False
- log(f"sent-folder carve-out applied over {len(folders)} folder(s)")
+ log(f"sent-folder carve-out applied over {len(folders)} folder(s), "
+ f"{matched} message(s)")
return True
@@ -116,6 +127,20 @@ def protected_removals(rule):
return sorted(PROTECTED_REMOVALS.intersection(rule.remove))
+def count(query):
+ """How many messages a query matches, or `?` if the count itself failed.
+
+ Diagnostic only: nothing branches on this. A failure here must not fail
+ the sync, because the carve-out's own tag is what matters and it reports
+ its own status separately.
+ """
+ result = subprocess.run(["notmuch", "count", "--", query],
+ capture_output=True, text=True)
+ if result.returncode != 0:
+ return "?"
+ return result.stdout.strip() or "?"
+
+
def run_tag(arguments, query):
result = subprocess.run(["notmuch", "tag"] + arguments + ["--", query],
capture_output=True, text=True)