aboutsummaryrefslogtreecommitdiff
path: root/inbox
diff options
context:
space:
mode:
Diffstat (limited to 'inbox')
-rw-r--r--inbox/PROCESSED-2026-07-04-1302-from-home-task-for-rulesets-document-and-decide.org5
-rw-r--r--inbox/PROCESSED-2026-07-05-0420-from-archsetup-proposal-incoming-ui-prototyping.org5
-rw-r--r--inbox/PROCESSED-2026-07-05-0420-from-archsetup-ui-prototyping-process-proposal.org79
-rw-r--r--inbox/PROCESSED-2026-07-06-1054-from-archsetup-off-workspace-captures-rule.md38
-rw-r--r--inbox/PROCESSED-2026-07-08-1124-from-work-proposal-triage-intake-personal-gmail.org5
-rw-r--r--inbox/PROCESSED-2026-07-08-1124-from-work-triage-intake.personal-gmail.org68
-rw-r--r--inbox/PROCESSED-2026-07-09-0649-from-work-pr-review-rule-tightening-from-a.org11
-rw-r--r--inbox/PROCESSED-2026-07-09-1341-from-work-bug-data-loss-wrap-org-table-el-and.org28
-rw-r--r--inbox/PROCESSED-2026-07-09-1400-from-work-handoff-ai-attribution-cleanup-done.org22
-rw-r--r--inbox/PROCESSED-2026-07-09-1636-from-chime-staleness-proposal.txt17
-rw-r--r--inbox/PROCESSED-2026-07-09-1745-from-chime-matrix-proposal.txt35
11 files changed, 313 insertions, 0 deletions
diff --git a/inbox/PROCESSED-2026-07-04-1302-from-home-task-for-rulesets-document-and-decide.org b/inbox/PROCESSED-2026-07-04-1302-from-home-task-for-rulesets-document-and-decide.org
new file mode 100644
index 0000000..1abc1a6
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-04-1302-from-home-task-for-rulesets-document-and-decide.org
@@ -0,0 +1,5 @@
+#+TITLE: Task for rulesets: document (and decide ownership of) the Si
+#+SOURCE: from home
+#+DATE: 2026-07-04 13:02:07 -0500
+
+Task for rulesets: document (and decide ownership of) the Signal pager. Context: home retired the ntfy phone-notification channel (phone-notify/phone-recv, self-hosted ntfy on ratio) on 2026-07-04 in favor of paging over Signal, and tore the ntfy system down. But the Signal pager isn't documented anywhere — no pager script in ~/.local/bin, and the notify script doesn't reference Signal. What exists on ratio: signal-cli 0.14.5, configured with account 404211. The interface (a send wrapper, how a workflow pages Craig, how replies are read) is uncaptured, so no session can actually use the channel yet. This is the successor to the ntfy tooling's rulesets-ownership question (the 6/17 two-way-comms proposal): a phone paging channel is cross-machine tooling, so its canonical home + docs belong in rulesets. Suggested deliverable: a documented Signal pager (send + read-replies), the signal-cli setup/account notes, and the sync path — the Signal equivalent of what the retired ntfy runbook covered. Craig flagged this as a task for rulesets to finish.
diff --git a/inbox/PROCESSED-2026-07-05-0420-from-archsetup-proposal-incoming-ui-prototyping.org b/inbox/PROCESSED-2026-07-05-0420-from-archsetup-proposal-incoming-ui-prototyping.org
new file mode 100644
index 0000000..480d006
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-05-0420-from-archsetup-proposal-incoming-ui-prototyping.org
@@ -0,0 +1,5 @@
+#+TITLE: Proposal incoming (ui-prototyping-process-proposal.org): a U
+#+SOURCE: from archsetup
+#+DATE: 2026-07-05 04:20:42 -0500
+
+Proposal incoming (ui-prototyping-process-proposal.org): a UI/UX prototype process for specs with a non-trivial UI — research-first during brainstorming, then ~5 full working prototype directions, iterate one to final, name <spec-name>-prototype-<N>.html, link final in the spec + keep old iterations in the spec history. Worked example is archsetup's timer-panel spec + its 3 prototypes. Suggested it fold into spec-create/spec-review or a new ui-prototyping rule — your value gate decides placement.
diff --git a/inbox/PROCESSED-2026-07-05-0420-from-archsetup-ui-prototyping-process-proposal.org b/inbox/PROCESSED-2026-07-05-0420-from-archsetup-ui-prototyping-process-proposal.org
new file mode 100644
index 0000000..e0677eb
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-05-0420-from-archsetup-ui-prototyping-process-proposal.org
@@ -0,0 +1,79 @@
+#+TITLE: Proposal — UI/UX prototype process for specs with a non-trivial UI
+#+AUTHOR: Craig Jennings (via archsetup session)
+#+DATE: 2026-07-05
+
+* Intro / why this is coming to you
+
+Working the timer-panel spec in archsetup, we found the right way to settle a
+UI design: research first, then build a handful of full working prototypes,
+then iterate one to a final — all before committing GTK code. It worked well
+enough that Craig wants it as a standing part of the spec process for any spec
+whose deliverable has a non-trivial UI. This is the write-up, proposed for the
+rulesets layer (spec-create / spec-review, or a new =ui-prototyping= rule —
+your call on placement).
+
+Worked example living now in archsetup: =docs/specs/2026-07-02-timer-panel-spec.org=
+plus =docs/prototypes/2026-07-02-timer-panel-prototype-{1,2,3}.html=. The spec's
+"Prototype iterations" subsection and its new design decisions show the shape in
+practice.
+
+* The process
+
+** 1. Trigger — non-trivial UI only
+Applies when a spec's deliverable is a real UI: a panel, a multi-control
+surface, a visual layout with interacting parts. Not a single dialog, a CLI
+flag, or a one-off prompt. If "which of these layouts is right?" can't be
+answered from a sentence, it qualifies.
+
+** 2. Research first — during brainstorming, before prototyping
+Before any prototype, survey how existing and best-in-class tools solve the same
+UX and functionality (the category's well-regarded apps, prior art, conventions
+users already expect). Feed the findings into the spec's Goals and Design so the
+UX and functionality are understood *before* a single prototype. Prototyping
+blind wastes iterations re-deriving what a 20-minute survey would have told you.
+Cite the sources in the spec.
+
+** 3. Brainstorm the UX + functionality in the spec
+Informed by the research, write the goals, the interactions, and the functional
+surface into the spec. This is the "what and why" the prototypes will make real.
+
+** 4. Prototype — ~5 initial directions, then iterate to a final
+Build about five *distinct directions* (genuinely different layouts /
+interaction models, not variations of one) as full working prototypes over one
+shared engine, in the project's design language. Pick a direction, then iterate
+*that one* across numbered passes to the final design. Each meaningful pass is
+saved as its own numbered prototype so the design history is walkable.
+
+** 5. Full working prototypes, not mockups
+The prototypes must be *functional* — real state, real controls, real behavior —
+so decisions are made against how it feels to use, not against a picture. A
+static mockup hides the interaction problems that only surface when you drive it.
+
+** 6. Naming + location
+=docs/prototypes/<spec-name>-prototype-<N>.html=, where =<spec-name>= is the
+spec's dated slug (dropping the =-spec= suffix) and =N= is the iteration number.
+E.g. for =2026-07-02-timer-panel-spec.org= →
+=2026-07-02-timer-panel-prototype-1.html=, =-2.html=, =-3.html=.
+
+** 7. Link from the spec; keep old iterations in history
+The spec links the *final* prototype in its design section, and keeps links to
+*every* prior iteration in a "Prototype iterations" subsection under the status
+heading — newest last — so the design's evolution is walkable from the spec.
+
+** 8. Decisions get written down once seen working
+A design decision is recorded in the spec's Decisions only after it's been seen
+working in a prototype. "Resolved live through the prototype iteration" — the
+prototype is the evidence.
+
+* Suggested placement (your value gate decides)
+
+- =spec-create=: for a non-trivial-UI spec, add a "research → brainstorm →
+ prototype (5 directions → iterate)" step, and require the "Prototype
+ iterations" subsection.
+- =spec-review=: for a non-trivial-UI spec, verify the prototype process ran —
+ research cited, final prototype linked, iterations in history, decisions
+ backed by a prototype.
+- Or a standalone =claude-rules/ui-prototyping.md= that both workflows point at.
+
+Not prescribing which — sending the content and the worked example; apply the
+rulesets value gate and place it where it fits.
diff --git a/inbox/PROCESSED-2026-07-06-1054-from-archsetup-off-workspace-captures-rule.md b/inbox/PROCESSED-2026-07-06-1054-from-archsetup-off-workspace-captures-rule.md
new file mode 100644
index 0000000..03538af
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-06-1054-from-archsetup-off-workspace-captures-rule.md
@@ -0,0 +1,38 @@
+# Proposal: never use the user's active workspace for agent windows/captures
+
+From an archsetup session (2026-07-06). Craig's request, verbatim intent: when I open an app or take a screenshot for my own verification, don't do it on his active workspace — put it somewhere that doesn't interrupt what he's doing. He then asked to make this a rule for everyone and send it to rulesets.
+
+## Why
+
+During the audio-panel work I repeatedly launched the GTK panel and `imv` on Craig's live desktop to screenshot and verify. Each one popped onto his current workspace and stole focus/attention mid-task. Agents doing visual verification on a user's live session shouldn't hijack the workspace the user is actively working in.
+
+## The rule (proposed text, ready to place)
+
+**Never open a window or take a screenshot on the user's active workspace.** When visual verification needs a real window on the user's live desktop, keep it off the workspace they're working in:
+
+- **Captures for your own verification** — render and grab the window off the user's physical screen, then tear it down. On Hyprland this is a virtual headless output (verified non-disruptive on ratio 2026-07-06 — the physical monitor stayed on its workspace, focused, throughout):
+
+ ```sh
+ hyprctl output create headless # virtual output on its own workspace
+ setsid <app> >/tmp/x.log 2>&1 </dev/null &
+ addr=$(hyprctl -j clients | python3 -c 'import json,sys; print(next((c["address"] for c in json.load(sys.stdin) if c.get("class")=="<CLASS>"), ""))')
+ hyprctl dispatch movetoworkspacesilent "<ws-on-headless>,address:$addr" # silent = keeps the user's focus
+ grim -o HEADLESS-<n> /tmp/shot.png # capture the virtual output only
+ pkill -f '<app>$'; hyprctl output remove HEADLESS-<n> # tear down, restore the display
+ ```
+
+ Key constraint: `grim` captures a *visible output*, so a window merely parked on another Hyprland workspace can't be screenshotted — it must render on the headless (or another real) output. That's why a headless output, not just "another workspace," is the tool for self-captures. (A nested compositor — weston/cage/sway — is the alternative on non-Hyprland Wayland or when a headless output isn't available; it needs the compositor installed.)
+
+- **Showing the user something** — open it on a *separate* real workspace and tell them which one, so it never grabs their active workspace. They switch when ready. (Craig's viewer preference is `imv`; launch it through the compositor — `hyprctl dispatch exec "imv <files>"` — so it survives the agent's shell, not a bare `&` job that gets reaped.)
+
+- **Always clean up** — close the window and remove any headless output afterward; verify the user's display is restored (physical monitor back to its workspace, no orphan processes).
+
+The principle is environment-general (don't commandeer the user's active workspace for agent-side visual work); the recipe above is the Hyprland/Wayland implementation. Other environments implement the same principle with their own off-screen mechanism.
+
+## Placement suggestion (your call — "appropriate places")
+
+I'd lean toward a short standalone rule file (e.g. `claude-rules/desktop-capture.md`) since it's a distinct concern, cross-referenced from `verification.md` (it's part of how visual verification is done) and `interaction.md` (it's about not disrupting the user). It could instead be a section in `verification.md`. The `imv`/viewer preference and the "launch through the compositor" mechanic could also land wherever `emacs.md`'s screenshot note lives. Pick whatever fits the layer best.
+
+## Companion (local, already applied)
+
+Captured as archsetup auto-memory (`display-images-via-imv.md`) as the stopgap; this inbox note is the propagation to canonical per the cross-project rule for rulesets-owned changes.
diff --git a/inbox/PROCESSED-2026-07-08-1124-from-work-proposal-triage-intake-personal-gmail.org b/inbox/PROCESSED-2026-07-08-1124-from-work-proposal-triage-intake-personal-gmail.org
new file mode 100644
index 0000000..6fb315b
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-08-1124-from-work-proposal-triage-intake-personal-gmail.org
@@ -0,0 +1,5 @@
+#+TITLE: Proposal: triage-intake.personal-gmail.org edit (copy sent a
+#+SOURCE: from work
+#+DATE: 2026-07-08 11:24:19 -0500
+
+Proposal: triage-intake.personal-gmail.org edit (copy sent alongside this note). Two additions to the Scan section, both from a 2026-07-08 work-session investigation: (1) a warning that the Gmail MCP listMessages tool caps at maxResults=100 and exposes no pageToken parameter, so >100 unread piles silently truncate — with the date-slice walk (before:<oldest-day>, dedupe by id) as the recipe, and a note that resultSizeEstimate is unreliable (stuck at 201 while the real union exceeded 300); (2) a mandatory cheap backlog-residue probe each sweep (q="is:unread in:inbox before:<anchor-date>" maxResults=5) that loudly surfaces any pre-anchor unread instead of letting anchored sweeps claim 'no changes' over a window they never saw. Root cause this fixes: ~300 unread accumulated invisibly Jun 4 - Jul 4 because anchored scans never look behind the anchor and the 7/4 catch-up hit the 100 cap. Companion: the work project's project-owned triage-intake.deepsat-gmail.org got the same two additions directly (work tool names); no other plugins in the gmail family. The engine file needs no change.
diff --git a/inbox/PROCESSED-2026-07-08-1124-from-work-triage-intake.personal-gmail.org b/inbox/PROCESSED-2026-07-08-1124-from-work-triage-intake.personal-gmail.org
new file mode 100644
index 0000000..ca81f5d
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-08-1124-from-work-triage-intake.personal-gmail.org
@@ -0,0 +1,68 @@
+#+TITLE: Triage Intake — Personal Gmail Source
+#+AUTHOR: Craig Jennings & Claude
+#+DATE: 2026-05-26
+
+# Source plugin for the triage-intake engine. See triage-intake.org for the
+# contract and the Phase A-D orchestration. This file declares ONE source.
+
+* Source: personal-gmail
+:PROPERTIES:
+:ORDER: 20
+:ENABLED: mcp google-docs-personal present
+:ANCHOR: epoch
+:SUBAGENT_OVER: 50
+:END:
+
+** Scan
+
+Personal Gmail unread in the inbox since the anchor:
+
+#+begin_src text
+mcp__google-docs-personal__listMessages q="is:unread in:inbox after:<anchor-epoch>" maxResults=100
+#+end_src
+
+⚠ *Express the cutoff as the literal UNIX epoch* — =after:1778856990=, not =after:YYYY/MM/DD=. Gmail's =after:YYYY/MM/DD= operator only supports day resolution; the =YYYY/MM/DD HH:MM:SS= form is NOT valid syntax — Gmail parses the space as a term separator, treats =HH:MM:SS= as a search term that never matches, and returns 0 results, silently masking unread mail. The engine supplies =<anchor-epoch>= because this source declares =ANCHOR: epoch=.
+
+⚠ *Do NOT add =-category:promotions -category:social=.* That filter masked 67 promo+social messages across two runs (2026-05-04, 2026-05-06), both needing a follow-up sweep. Pull the full unfiltered set; the trash-leaning bias in Classify handles promotions and social directly.
+
+⚠ *The MCP caps at =maxResults=100= and exposes NO =pageToken= parameter.* The response carries a =nextPageToken=, but the tool can't consume it, so a pile over 100 is silently truncated — the tail below the cap never gets classified, and every later anchored sweep skips it (it predates the new anchor). This is exactly how a 300+ backlog accumulated invisibly by 2026-07-08. Two consequences:
+
+- *Never treat a 100-row result as complete.* When a scan returns exactly 100, walk the tail in *date slices*: re-query with =before:<oldest-full-day-seen>= (day resolution), repeat until a page returns fewer than 100, dedupe by message id across slices (the day-resolution boundary overlaps).
+- *Never report =resultSizeEstimate= as a count.* It's unreliable — observed stuck at "201" across three different queries whose real union exceeded 300.
+
+*** Backlog-residue check (every sweep — cheap, mandatory)
+
+The anchored scan is blind to anything unread from *before* the anchor. After it, run one probe for pre-anchor residue:
+
+#+begin_src text
+mcp__google-docs-personal__listMessages q="is:unread in:inbox before:<anchor-YYYY/MM/DD>" maxResults=5
+#+end_src
+
+If it returns any messages, surface one loud line in the sweep summary: "Backlog: unread predating the anchor exists (N+ shown; date-slice to inventory)" and offer a backlog sweep. Never fold the residue into a quiet sweep — an anchored "no changes" claim is only true for the window the scan saw. (Added 2026-07-08 after ~300 pre-anchor unread accumulated unseen; the probe returns actual messages, so it works where the estimate lies.)
+
+** Classify
+
+Bias: *trash-leaning* — personal Gmail is high noise volume.
+
+- *Noise-trash:* newsletters, Substacks, retail/SaaS marketing, social digests, redundant aggregator digests (Notion/Miro daily), wrong-recipient mail, past-event calendar artifacts.
+- *Noise-keep:* receipts, order confirmations, statements — low value but worth the audit trail.
+- *FYI:* substantive personal mail with no action owed.
+- *Action:* an explicit ask, a reply owed, a time-sensitive personal matter.
+
+** Render
+
+#+begin_example
+**Personal Gmail — N unread.** <one-line classification summary>
+- Action: <items, if any, with thread links>
+- FYI: <items, if any>
+- Noise: N trash candidates, M keep
+#+end_example
+
+Omit the block if zero unread.
+
+** Actions
+
+- trash :: =mcp__google-docs-personal__trashMessage= id=<message-id> (recoverable from Gmail Trash for 30 days)
+- mark-read :: =mcp__google-docs-personal__modifyMessageLabels= id=<message-id> removeLabelIds=["UNREAD"]
+- star+read :: =mcp__google-docs-personal__modifyMessageLabels= id=<message-id> addLabelIds=["STARRED"] removeLabelIds=["UNREAD"]
+- attach-fetch:: =.ai/scripts/gmail-fetch-attachments.py --profile personal --message-id <message-id> --output-dir <PATH>=
diff --git a/inbox/PROCESSED-2026-07-09-0649-from-work-pr-review-rule-tightening-from-a.org b/inbox/PROCESSED-2026-07-09-0649-from-work-pr-review-rule-tightening-from-a.org
new file mode 100644
index 0000000..80dc4bc
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-09-0649-from-work-pr-review-rule-tightening-from-a.org
@@ -0,0 +1,11 @@
+#+TITLE: PR-review rule tightening from a DeepSat review session (Cra
+#+SOURCE: from work
+#+DATE: 2026-07-09 06:49:14 -0500
+
+PR-review rule tightening from a DeepSat review session (Craig, 2026-07-09). Two changes to the review-code skill:
+
+1. No praise on approvals — stronger than the current 'Posted Summary Voice' rule. That section currently permits 'the verdict plus at most a bare positive ("Clean.", "Solid fix.")'. Craig's ruling: an approve summary carries NO praise at all, not even the bare positive. Lead the summary with the substantive pointer (the inline design note), then the verdict. Example he approved: 'One design note inline, not a blocker. Approving.' The praise-strips / correction-explains split still holds for findings; approvals just drop the praise clause entirely. Suggest editing the 'Posted Summary Voice' section (and /voice personal pattern #40 if it encodes the 'bare positive allowed' carve-out) to remove the bare-positive permission.
+
+2. Always show inline comment text at the review gate — Phase 5 / the publish-flow gate should require printing the FULL inline prose that will post, alongside the summary body, never the summary alone with the inline merely described ('I'd pair it with one inline on...'). Craig approves the exact words that post under his name, so the exact words must be on screen. Suggest making this explicit in review-code Phase 5 (Terminal display) and in commits.md Step 2 Shape 1 (the print-the-draft step).
+
+Both are cross-project (any PR review), so they belong in the rulesets layer, not just the DeepSat project. Also captured in the work project's harness memory as feedback_no_praise_on_approvals_show_inline for immediate use.
diff --git a/inbox/PROCESSED-2026-07-09-1341-from-work-bug-data-loss-wrap-org-table-el-and.org b/inbox/PROCESSED-2026-07-09-1341-from-work-bug-data-loss-wrap-org-table-el-and.org
new file mode 100644
index 0000000..a128d0a
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-09-1341-from-work-bug-data-loss-wrap-org-table-el-and.org
@@ -0,0 +1,28 @@
+#+TITLE: BUG (data loss): wrap-org-table.el and lint-org.el corrupt o
+#+SOURCE: from work
+#+DATE: 2026-07-09 13:41:56 -0500
+
+BUG (data loss): wrap-org-table.el and lint-org.el corrupt org example blocks.
+
+Both scripts scan for lines beginning with "|" and rewrite them as org tables. They do not skip #+begin_example / #+begin_src / #+begin_quote regions, so ASCII art using pipe characters gets mangled into tables. Both write to disk with no confirmation.
+
+Reproduced 2026-07-09 in the work project against an architecture doc containing an ASCII pipeline diagram that uses | and v as flow arrows:
+
+ Before: After:
+ | | |
+ v |---|
+ v
+
+and a plain indented block became a bordered org table with |---| rules inserted between every line.
+
+Two separable defects:
+
+1. Table detection is line-based. Both helpers should use org-element-at-point (or org-in-block-p) to skip example/src/quote/verse blocks rather than matching /^\s*|/.
+
+2. lint-org.el mutates its input. Passing five files to it reformatted all five on disk -- one of them by 1949 lines. Its documented job is to report judgment items. A linter must not write. If the reformat is wanted, it belongs behind an explicit --fix flag.
+
+Impact: silent data loss on any org file that mixes tables and example blocks, which is most architecture docs. In this case the good content was already staged in git and was recoverable. It would not have been otherwise.
+
+No local fix attempted: .ai/scripts/ is rulesets-owned and the startup rsync would revert it. Filed as a task on the work side (Org-table helpers corrupt example blocks) so it is tracked there until the canonical fix lands.
+
+Suggested test: run wrap-org-table.el against a file containing a #+begin_example block whose lines start with "|" and assert the block is byte-identical afterward.
diff --git a/inbox/PROCESSED-2026-07-09-1400-from-work-handoff-ai-attribution-cleanup-done.org b/inbox/PROCESSED-2026-07-09-1400-from-work-handoff-ai-attribution-cleanup-done.org
new file mode 100644
index 0000000..a37a54a
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-09-1400-from-work-handoff-ai-attribution-cleanup-done.org
@@ -0,0 +1,22 @@
+#+TITLE: HANDOFF: AI-attribution cleanup done from the work session (
+#+SOURCE: from work
+#+DATE: 2026-07-09 14:00:05 -0500
+
+HANDOFF: AI-attribution cleanup done from the work session (Craig approved doing it from here).
+
+What changed in rulesets, uncommitted in your working tree:
+
+1. 103 files: rewrote the org header "#+AUTHOR: Craig Jennings & Claude" to "#+AUTHOR: Craig Jennings". Breakdown: 43 .ai/workflows, 43 claude-templates/.ai/workflows, 5 docs/specs, 5 docs/design, 2 .ai (notes, protocols), 2 claude-templates/.ai, 2 references, 1 working/. Exactly one line changed per file (103 insertions, 103 deletions, zero non-AUTHOR lines). Prose mentions of Claude were not touched.
+
+2. claude-rules/commits.md: added "Document author metadata" to the No-AI-Attribution list, plus a new subsection "Generated documents carry the human author only". It explains that the propagation mechanism is imitation (no template stamps the line; agents copy it from neighbouring files), names the employer-policy stakes, and carves out two exceptions.
+
+Held back deliberately, please confirm you agree:
+- .ai/sessions/ (14 files) left as-is. They are historical records of what happened, not live artifacts.
+- docs/design/2026-05-28-generic-agent-runtime-spec.org and its -review sibling keep "#+AUTHOR: Codex". Codex actually wrote them, so renaming would be a false attribution rather than removing one.
+- .ai/scripts/tests/fixtures/todo-sample.org keeps "#+AUTHOR: synthetic fixture" (test data).
+
+Not committed. The tracked tree was clean at 0/0 against origin/main before these edits, so the diff is exactly this change and nothing else. Review and commit on your side.
+
+Why it came up: the work project noticed its generated daily-prep docs carry the co-author line. Craig pointed out that his own repo tolerates it, but employers whose policy is that work product carries employee names alone would not. Nothing has leaked yet: the arch docs pushed to the company GHE lost the #+AUTHOR line in the pandoc conversion. The exposure was prospective, via a planned Markdown-to-Notion publisher.
+
+Companion item already in your inbox: the wrap-org-table.el / lint-org.el data-loss bug (2026-07-09-1341).
diff --git a/inbox/PROCESSED-2026-07-09-1636-from-chime-staleness-proposal.txt b/inbox/PROCESSED-2026-07-09-1636-from-chime-staleness-proposal.txt
new file mode 100644
index 0000000..cc741b2
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-09-1636-from-chime-staleness-proposal.txt
@@ -0,0 +1,17 @@
+Proposal: task-review-staleness.sh should accept org-style :LAST_REVIEWED: values, or fail loudly.
+
+Hit this in chime today. I stamped :LAST_REVIEWED: [2026-07-09 Thu] — an org inactive timestamp, matching the CREATED: and CLOSED: cookies sitting right next to it in the same drawer. The script expects a bare 2026-07-09.
+
+The failure is silent and inverted. In count mode, `date -d "[2026-07-09 Thu]"` fails, and the unparseable branch counts the task as STALE. So a freshly-reviewed task reports as never-reviewed, and a full review pass leaves the startup nudge saying exactly what it said before. In list mode the sort-key regex also rejects it, so the task sorts as 0000-00-00 (oldest) and gets re-walked first. Both modes punish the stamp for being in the wrong format, and neither says so.
+
+I fixed my side (bare dates, matching the precedent in home/todo.org). The trap is worth closing, because the bracketed form is the plausible guess: every other date in an org PROPERTIES drawer is bracketed, and nothing in task-review.org or todo-format.md says LAST_REVIEWED is different.
+
+Two options, either fine:
+
+1. Accept both. Strip a leading bracket and a trailing weekday + bracket before parsing, inside extract_tasks. Org-native stamps then work and existing bare stamps keep working.
+
+2. Fail loudly. When a LAST_REVIEWED value is present but unparseable, print a warning naming the file, line, and value rather than folding it into the stale count. A malformed stamp is a data error, and treating it as "never reviewed" hides it forever.
+
+I lean toward both: accept the org form, warn on anything still unparseable. Today a project can run task reviews for months while the staleness count never drops, and nothing ever explains why.
+
+Also worth a line in todo-format.md or task-review.org stating the expected format. The script is currently the only place it's written down, and you have to read its awk to find it.
diff --git a/inbox/PROCESSED-2026-07-09-1745-from-chime-matrix-proposal.txt b/inbox/PROCESSED-2026-07-09-1745-from-chime-matrix-proposal.txt
new file mode 100644
index 0000000..53c20c8
--- /dev/null
+++ b/inbox/PROCESSED-2026-07-09-1745-from-chime-matrix-proposal.txt
@@ -0,0 +1,35 @@
+Proposal: todo-format.md's bug matrix should warn against double-counting rarity.
+
+Adding the severity x frequency matrix to chime today, I mis-graded a bug by exactly one mistake, and I think the rule invites it.
+
+The task: chime's async watchdog interrupts a child that outlives its timeout, but never escalates to kill. I graded it Minor severity ("a zombie child and a leaked process buffer accumulate slowly") x rare edge case ("the watchdog must fire AND the child must survive SIGINT") = P4 = [#D].
+
+Then I read async.el. Its cleanup guards on (eq 'exit (process-status proc)) and only kills the process buffer in the zero-exit branch, so a signal-killed child (status 'signal) skips it entirely. Every watchdog interrupt leaks a buffer; the surviving-SIGINT zombie is the rare sub-case, not the leak. And the watchdog nils the process handle, so the same tick spawns a replacement — if the hang cause persists, another child is abandoned every timeout period. Roughly 30 leaked buffers an hour, indefinitely, invisibly. A real incident had a child stuck 15+ hours.
+
+Severity was the wrong input, not frequency. "Accumulates slowly" describes a bounded trickle. This accumulates at a fixed rate forever once entered, with no workaround short of restarting Emacs. That's Major. Major x rare edge = P3 = [#C], which is where it landed.
+
+The generalizable error: I let the rarity of *entering* the failure state discount the *severity* of being in it. But frequency already carries that rarity. Grading it twice buries exactly the bugs that compound — the ones where a rare trigger produces unbounded harm.
+
+Suggested addition to the matrix section:
+
+ Don't double-count rarity. Grade severity by the rate of harm once the
+ failure state is entered, not by how rare it is to enter. Frequency
+ already carries the rarity; letting it discount severity too grades the
+ same fact twice, and that buries compounding bugs. A leak that repeats
+ every timeout period until the process restarts is Major even when
+ reaching that state is a rare edge case.
+
+Two smaller additions I made to chime's scheme, both of which I'd put in the global rule:
+
+ Record the grading in the task body — the severity band, the frequency
+ row, and the arithmetic. A bare priority cookie can't be argued with; a
+ stated read can be re-checked against the source and corrected. That's
+ how this task moved [#D] -> [#C] an hour after I graded it.
+
+ Disagreeing with a grade means fixing an input. If a letter looks wrong,
+ re-read the severity band and the frequency row against the source and
+ correct whichever is wrong. Don't override the letter directly — that
+ turns the matrix into a formality and puts you back to grading by
+ instinct.
+
+The last one is the one I care about. Craig's first instinct on seeing the [#D] was to restore the [#B] it had before. The matrix earns its keep only if a disagreement forces a re-read of the inputs rather than a manual override, and the rule text currently doesn't say so.