aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-11 18:22:12 -0500
committerCraig Jennings <c@cjennings.net>2026-06-11 18:22:12 -0500
commit647bc6119a19b9d8dc1d1860e6b253c1390b1e9b (patch)
tree69e3b6a0a1728af26eedc1df8751f74143f57caa
parentf9fce0dae795d8e17bb79d967da152c15077345c (diff)
downloadrulesets-647bc6119a19b9d8dc1d1860e6b253c1390b1e9b.tar.gz
rulesets-647bc6119a19b9d8dc1d1860e6b253c1390b1e9b.zip
feat(triage): deltas-only sweep summaries and silent telegram dev groups
A sweep now reports only what changed: a new invite, a moved or cancelled event, a message needing attention. Unchanged sources get no block. An all-quiet sweep renders as one line. Scan failures keep their loud banner and the suggested-actions line stays when actions are queued. Telegram dev-community group traffic (zed, GNU Emacs, Kitty) is dropped from sweep reports entirely unless Craig asks. Real DMs from known contacts still surface as Action.
-rw-r--r--.ai/workflows/triage-intake.org28
-rw-r--r--.ai/workflows/triage-intake.telegram.org20
-rw-r--r--claude-templates/.ai/workflows/triage-intake.org28
-rw-r--r--claude-templates/.ai/workflows/triage-intake.telegram.org20
4 files changed, 74 insertions, 22 deletions
diff --git a/.ai/workflows/triage-intake.org b/.ai/workflows/triage-intake.org
index 173f051..b804de1 100644
--- a/.ai/workflows/triage-intake.org
+++ b/.ai/workflows/triage-intake.org
@@ -104,10 +104,20 @@ One markdown summary surfaced inline to Craig. Order:
A failed scan is never folded into "quiet." Quiet means the scan ran and found nothing; a failure means the sweep is blind on that channel, and the reader must know which. The same applies to a precondition skip the user hasn't standing-approved (e.g. a messaging client that needs a temporary server spin-up): run the lifecycle or report the failure — don't silently narrow the sweep.
1. *Top signals to act on* — bullet list of 3-7 items, ordered by urgency, *Action only*. Each bullet links to the source (permalink, thread URL, PR number).
-2. *Per-source breakdown* — one short section per *loaded* source, in =ORDER=, using that plugin's =Render= shape: Action items detailed, FYI items as a short list, Noise as a tally only ("Noise: 12 trash candidates, 4 keep, 0 starred").
-3. *Suggested actions* — explicit list of state changes Craig could take this run (trash these N messages, mark-read these M, star this Action item, respond to this invite, merge PRs #X and #Y, etc.).
+2. *Per-source breakdown* — one short section per loaded source *that has changes*, in =ORDER=, using that plugin's =Render= shape: Action items detailed, FYI items as a short list, Noise as a tally only ("Noise: 12 trash candidates, 4 keep, 0 starred").
+3. *Suggested actions* — explicit list of state changes Craig could take this run (trash these N messages, mark-read these M, star this Action item, respond to this invite, merge PRs #X and #Y, etc.). This line stays whenever there are queued actions, regardless of how quiet the sweep was.
-Format target: scannable in 30 seconds, full read in 2 minutes. Don't pad. If a source returned zero items, write "Calendar — quiet" or "PRs — nothing new since 14:30 yesterday."
+*Deltas only.* The summary reports what *changed* since the anchor: a new invite, a new/moved/cancelled calendar event, a new message needing attention. A source with no changes gets no block — no "Calendar — quiet", no "PRs — nothing new" roll-call. A sweep where nothing changed anywhere renders as a single line:
+
+#+begin_example
+17:39 sweep: no changes
+#+end_example
+
+(Craig, 2026-06-11: "we only need to report if anything's changed when we do triage intake. did someone send me a new invite? did christine throw something on my calendar that wasn't there earlier? did someone cancel a meeting?")
+
+Scan failures are the standing exception: a failed or skipped scan always renders loudly per point 0 above and is never folded into the no-change line — "no changes" is a claim about channels the sweep could actually see.
+
+Format target: scannable in 30 seconds, full read in 2 minutes. Don't pad.
**** Sub-step: write each Action item into =todo.org= as its own =:quick:= task
@@ -253,7 +263,13 @@ If both fail, fall through to the resolution order above (prep doc → session f
** Output Template
-The summary follows this shape (omit any source that genuinely returned nothing; render one block per *loaded* source in =ORDER=, using each plugin's =Render= shape):
+The summary follows this shape (deltas only: a source with no changes gets no block; when *nothing* changed anywhere, the whole summary collapses to the one-line form below — plus any scan-failure banners and the suggested-actions line if actions are queued):
+
+#+begin_example
+17:39 sweep: no changes
+#+end_example
+
+When there are changes, render one block per changed source in =ORDER=, using each plugin's =Render= shape:
#+begin_example
**Anchor:** <previous run timestamp> → now (<elapsed> elapsed)
@@ -287,6 +303,7 @@ Order matters: top-signals first because that's what Craig reads in 30 seconds b
7. *Running this alongside daily-prep.* Daily-prep already does this as Phase 3 — don't duplicate.
8. *Mixing Action and FYI in the top-signals list.* Top signals = Action only. FYI lives in the per-source detail.
9. *Reporting a failed or skipped scan as a quiet source.* A hung receive, a dead daemon, or a skipped spin-up looks identical to "no new messages" in the output unless it's flagged. The 2026-06-10 sweep shipped with Signal silently missing because the scan hung on an account lock. Failures lead the summary, in their own banner line.
+10. *Rendering a per-source quiet roll-call.* "Calendar — quiet" / "PRs — nothing new" lines on every silent source bury the one change that matters and pad a no-change sweep into a report. Deltas only: changed sources get blocks, unchanged sources get nothing, and an all-quiet sweep is one line (Craig's 2026-06-11 ruling in Phase C).
* History / Design Notes
@@ -306,6 +323,9 @@ Gap-window bug: a run had Phase A fire at 13:35 and the sentinel set at 15:04, s
**** 2026-05-13: Move the sentinel from mtime to content (cross-machine survivability)
The sentinel is checked into git, but git tracks content, not mtime — so an mtime anchor is per-machine. Fix: write the captured epoch into the sentinel's content (=EPOCH ISO-8601=), read with =awk 'NR==1 {print $1}'=, mtime as back-compat fallback.
+**** 2026-06-11: Deltas-only reporting (Phase C + Output Template + Common Mistake 10)
+Craig, via the work project's same-day handoff: "we only need to report if anything's changed when we do triage intake." Sweep summaries report deltas only — a new invite, a new/moved/cancelled event, a new message needing attention. Unchanged sources get no block (the "Calendar — quiet" roll-call is retired), and an all-quiet sweep renders as a single "HH:MM sweep: no changes" line. Failures keep their loud banner (never folded into the no-change line) and the suggested-actions line stays when actions are queued. Same ruling: the telegram plugin's dev-community group traffic is dropped from reports entirely unless Craig asks (see that plugin's 2026-06-11 note).
+
**** 2026-06-10: Loud failure surfacing (Phase C item 0 + Common Mistake 9)
Craig: "highlight any failures in daily triage loudly. I get important communication from all these channels." Trigger: the 2026-06-10 sweep shipped with Signal silently missing — a standalone receive hung on the account lock while the signel daemon owned it, and the failure looked identical to a quiet source. Failures now lead the summary in a ⚠ SCAN FAILED banner; the signal and telegram plugins' failure paths point at this rule.
diff --git a/.ai/workflows/triage-intake.telegram.org b/.ai/workflows/triage-intake.telegram.org
index a318f12..9caa4e1 100644
--- a/.ai/workflows/triage-intake.telegram.org
+++ b/.ai/workflows/triage-intake.telegram.org
@@ -200,9 +200,11 @@ work contact is Action, full stop.
unsolicited, no prior thread.
- =Deleted Account-NNNN= threads, blank-title chats, bot channels
(=Z-Library Official=), Telegram's own =✔️Telegram= service notices.
-- *FYI:* unread in dev-community groups Craig follows — =GNU Emacs=, =zed=,
- =Kitty=, and similar. Worth awareness, no response owed. List the group +
- unread count; don't enumerate the messages.
+- *Noise-keep (never reported):* unread in dev-community groups Craig follows —
+ =GNU Emacs=, =zed=, =Kitty=, and similar. Skipped in sweep reports entirely —
+ not even a name + count line — unless Craig specifically asks about them
+ (Craig's ruling, 2026-06-11, via the work project's handoff). Leave them
+ unread; they're reading material, not signal.
- *Action:* a real text/voice/media message from a *known personal contact* in
an existing one-to-one thread — an explicit ask, a question, a reply owed. On
a spam-heavy account these are rare; when one appears, surface it prominently
@@ -217,13 +219,17 @@ groups + 0 real personal DMs. Expect most sweeps to look like this — a clean
#+begin_example
**Telegram — N unread chats (M real after filtering).** <one-line summary>
- Action: <real DMs from known contacts, sender + gist, reply owed called out>
-- FYI: <dev groups — name + count>
- Noise: K joined-Telegram notices, J spam/bot/deleted (tally only)
#+end_example
-Omit the block if there are zero unread chats. If the only unread is
-join-notices + spam + groups (the common case), render the one-line summary plus
-the Noise tally and skip Action entirely.
+Dev-community group traffic never appears here — no FYI line, no name + count —
+unless Craig asks for it in that sweep (2026-06-11 ruling). Real DMs from known
+contacts still surface as Action.
+
+Omit the block entirely when there's nothing but group traffic, join-notices,
+and spam — under the engine's deltas-only rule that's a no-change source. Render
+the block only when there's an Action item or a Noise tally worth a state-change
+suggestion (e.g. a trash batch).
** Actions
diff --git a/claude-templates/.ai/workflows/triage-intake.org b/claude-templates/.ai/workflows/triage-intake.org
index 173f051..b804de1 100644
--- a/claude-templates/.ai/workflows/triage-intake.org
+++ b/claude-templates/.ai/workflows/triage-intake.org
@@ -104,10 +104,20 @@ One markdown summary surfaced inline to Craig. Order:
A failed scan is never folded into "quiet." Quiet means the scan ran and found nothing; a failure means the sweep is blind on that channel, and the reader must know which. The same applies to a precondition skip the user hasn't standing-approved (e.g. a messaging client that needs a temporary server spin-up): run the lifecycle or report the failure — don't silently narrow the sweep.
1. *Top signals to act on* — bullet list of 3-7 items, ordered by urgency, *Action only*. Each bullet links to the source (permalink, thread URL, PR number).
-2. *Per-source breakdown* — one short section per *loaded* source, in =ORDER=, using that plugin's =Render= shape: Action items detailed, FYI items as a short list, Noise as a tally only ("Noise: 12 trash candidates, 4 keep, 0 starred").
-3. *Suggested actions* — explicit list of state changes Craig could take this run (trash these N messages, mark-read these M, star this Action item, respond to this invite, merge PRs #X and #Y, etc.).
+2. *Per-source breakdown* — one short section per loaded source *that has changes*, in =ORDER=, using that plugin's =Render= shape: Action items detailed, FYI items as a short list, Noise as a tally only ("Noise: 12 trash candidates, 4 keep, 0 starred").
+3. *Suggested actions* — explicit list of state changes Craig could take this run (trash these N messages, mark-read these M, star this Action item, respond to this invite, merge PRs #X and #Y, etc.). This line stays whenever there are queued actions, regardless of how quiet the sweep was.
-Format target: scannable in 30 seconds, full read in 2 minutes. Don't pad. If a source returned zero items, write "Calendar — quiet" or "PRs — nothing new since 14:30 yesterday."
+*Deltas only.* The summary reports what *changed* since the anchor: a new invite, a new/moved/cancelled calendar event, a new message needing attention. A source with no changes gets no block — no "Calendar — quiet", no "PRs — nothing new" roll-call. A sweep where nothing changed anywhere renders as a single line:
+
+#+begin_example
+17:39 sweep: no changes
+#+end_example
+
+(Craig, 2026-06-11: "we only need to report if anything's changed when we do triage intake. did someone send me a new invite? did christine throw something on my calendar that wasn't there earlier? did someone cancel a meeting?")
+
+Scan failures are the standing exception: a failed or skipped scan always renders loudly per point 0 above and is never folded into the no-change line — "no changes" is a claim about channels the sweep could actually see.
+
+Format target: scannable in 30 seconds, full read in 2 minutes. Don't pad.
**** Sub-step: write each Action item into =todo.org= as its own =:quick:= task
@@ -253,7 +263,13 @@ If both fail, fall through to the resolution order above (prep doc → session f
** Output Template
-The summary follows this shape (omit any source that genuinely returned nothing; render one block per *loaded* source in =ORDER=, using each plugin's =Render= shape):
+The summary follows this shape (deltas only: a source with no changes gets no block; when *nothing* changed anywhere, the whole summary collapses to the one-line form below — plus any scan-failure banners and the suggested-actions line if actions are queued):
+
+#+begin_example
+17:39 sweep: no changes
+#+end_example
+
+When there are changes, render one block per changed source in =ORDER=, using each plugin's =Render= shape:
#+begin_example
**Anchor:** <previous run timestamp> → now (<elapsed> elapsed)
@@ -287,6 +303,7 @@ Order matters: top-signals first because that's what Craig reads in 30 seconds b
7. *Running this alongside daily-prep.* Daily-prep already does this as Phase 3 — don't duplicate.
8. *Mixing Action and FYI in the top-signals list.* Top signals = Action only. FYI lives in the per-source detail.
9. *Reporting a failed or skipped scan as a quiet source.* A hung receive, a dead daemon, or a skipped spin-up looks identical to "no new messages" in the output unless it's flagged. The 2026-06-10 sweep shipped with Signal silently missing because the scan hung on an account lock. Failures lead the summary, in their own banner line.
+10. *Rendering a per-source quiet roll-call.* "Calendar — quiet" / "PRs — nothing new" lines on every silent source bury the one change that matters and pad a no-change sweep into a report. Deltas only: changed sources get blocks, unchanged sources get nothing, and an all-quiet sweep is one line (Craig's 2026-06-11 ruling in Phase C).
* History / Design Notes
@@ -306,6 +323,9 @@ Gap-window bug: a run had Phase A fire at 13:35 and the sentinel set at 15:04, s
**** 2026-05-13: Move the sentinel from mtime to content (cross-machine survivability)
The sentinel is checked into git, but git tracks content, not mtime — so an mtime anchor is per-machine. Fix: write the captured epoch into the sentinel's content (=EPOCH ISO-8601=), read with =awk 'NR==1 {print $1}'=, mtime as back-compat fallback.
+**** 2026-06-11: Deltas-only reporting (Phase C + Output Template + Common Mistake 10)
+Craig, via the work project's same-day handoff: "we only need to report if anything's changed when we do triage intake." Sweep summaries report deltas only — a new invite, a new/moved/cancelled event, a new message needing attention. Unchanged sources get no block (the "Calendar — quiet" roll-call is retired), and an all-quiet sweep renders as a single "HH:MM sweep: no changes" line. Failures keep their loud banner (never folded into the no-change line) and the suggested-actions line stays when actions are queued. Same ruling: the telegram plugin's dev-community group traffic is dropped from reports entirely unless Craig asks (see that plugin's 2026-06-11 note).
+
**** 2026-06-10: Loud failure surfacing (Phase C item 0 + Common Mistake 9)
Craig: "highlight any failures in daily triage loudly. I get important communication from all these channels." Trigger: the 2026-06-10 sweep shipped with Signal silently missing — a standalone receive hung on the account lock while the signel daemon owned it, and the failure looked identical to a quiet source. Failures now lead the summary in a ⚠ SCAN FAILED banner; the signal and telegram plugins' failure paths point at this rule.
diff --git a/claude-templates/.ai/workflows/triage-intake.telegram.org b/claude-templates/.ai/workflows/triage-intake.telegram.org
index a318f12..9caa4e1 100644
--- a/claude-templates/.ai/workflows/triage-intake.telegram.org
+++ b/claude-templates/.ai/workflows/triage-intake.telegram.org
@@ -200,9 +200,11 @@ work contact is Action, full stop.
unsolicited, no prior thread.
- =Deleted Account-NNNN= threads, blank-title chats, bot channels
(=Z-Library Official=), Telegram's own =✔️Telegram= service notices.
-- *FYI:* unread in dev-community groups Craig follows — =GNU Emacs=, =zed=,
- =Kitty=, and similar. Worth awareness, no response owed. List the group +
- unread count; don't enumerate the messages.
+- *Noise-keep (never reported):* unread in dev-community groups Craig follows —
+ =GNU Emacs=, =zed=, =Kitty=, and similar. Skipped in sweep reports entirely —
+ not even a name + count line — unless Craig specifically asks about them
+ (Craig's ruling, 2026-06-11, via the work project's handoff). Leave them
+ unread; they're reading material, not signal.
- *Action:* a real text/voice/media message from a *known personal contact* in
an existing one-to-one thread — an explicit ask, a question, a reply owed. On
a spam-heavy account these are rare; when one appears, surface it prominently
@@ -217,13 +219,17 @@ groups + 0 real personal DMs. Expect most sweeps to look like this — a clean
#+begin_example
**Telegram — N unread chats (M real after filtering).** <one-line summary>
- Action: <real DMs from known contacts, sender + gist, reply owed called out>
-- FYI: <dev groups — name + count>
- Noise: K joined-Telegram notices, J spam/bot/deleted (tally only)
#+end_example
-Omit the block if there are zero unread chats. If the only unread is
-join-notices + spam + groups (the common case), render the one-line summary plus
-the Noise tally and skip Action entirely.
+Dev-community group traffic never appears here — no FYI line, no name + count —
+unless Craig asks for it in that sweep (2026-06-11 ruling). Real DMs from known
+contacts still surface as Action.
+
+Omit the block entirely when there's nothing but group traffic, join-notices,
+and spam — under the engine's deltas-only rule that's a no-change source. Render
+the block only when there's an Action item or a Noise tally worth a state-change
+suggestion (e.g. a trash batch).
** Actions