aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-31 01:11:55 -0500
committerCraig Jennings <c@cjennings.net>2026-05-31 01:11:55 -0500
commit6f49edb17dd23b63e1cb6b4f11ffd0df1a546105 (patch)
treefa3eef1e286c5a3d9521b2b5736000168494ab5d
parent8c0eca8375db2c2d346f5fd08ac752209349f94e (diff)
downloadrulesets-6f49edb17dd23b63e1cb6b4f11ffd0df1a546105.tar.gz
rulesets-6f49edb17dd23b63e1cb6b4f11ffd0df1a546105.zip
chore(ai): archive session record and resolved tasks
-rw-r--r--.ai/sessions/2026-05-31-01-11-inbox-monitoring-workflow-and-infra-fixes.org84
-rw-r--r--todo.org76
2 files changed, 121 insertions, 39 deletions
diff --git a/.ai/sessions/2026-05-31-01-11-inbox-monitoring-workflow-and-infra-fixes.org b/.ai/sessions/2026-05-31-01-11-inbox-monitoring-workflow-and-infra-fixes.org
new file mode 100644
index 0000000..5dbacef
--- /dev/null
+++ b/.ai/sessions/2026-05-31-01-11-inbox-monitoring-workflow-and-infra-fixes.org
@@ -0,0 +1,84 @@
+#+TITLE: Session — lint-org verbatim-asterisk checker fix
+#+DATE: 2026-05-30
+
+* Summary
+
+** Active Goal
+
+Post-wrap continuation of 2026-05-30 (the prior session wrapped at 86326c1). A string of infrastructure fixes driven by Craig's directives and cross-project handoffs, capped by building an inbox-monitoring system. Six commits: 4b24597, 1f79945, 9a1bea9, 143feda, e446dab, ddcde66, 8c0eca8 — all pushed.
+
+** Decisions
+
+- *Linting shouldn't flag unfixable items* (Craig's rule): fixable → fix; unfixable false positive → message rulesets' inbox about the checker + rule. Applied to the recurring verbatim-asterisk misplaced-heading false positives.
+- *Act-vs-file rule* (Craig): when I decide to act → just do it, no asking; when I decide to file → ask first, filing = option 1, "do it now" = option 2; always ask if unsure. Codified in monitor-inbox.org + protocols.org.
+- *Startup rsync skip-when-dirty* (jr-estate handoff): option 1, scoped to the synced source paths so unrelated rulesets dirt doesn't block the sync.
+- *Per-agent session-context* (Codex Phase 1): AI_AGENT_ID resolves the active path via a helper, backward-compatible (unset → the legacy singleton). Fixes the two-agents-one-project race without the broader runtime refactor.
+- *cmail-action send is the default email path* (org-drill handoff): surfaced in protocols.org; send-email.org off the msmtp heredoc; send gained --cc/--bcc + threading.
+- *Inbox monitoring as a template workflow* (Craig: "general workflow, for sure"): task-boundary cadence + opt-in background /loop + the act-vs-file rule + reply discipline, with an inbox-status script.
+
+** Data Collected / Findings
+
+- lint-org verbatim-asterisk false positives are recurring and unfixable in source — the fix is suppressing the class in the checker, not editing todo.org.
+- The startup-rsync propagation anomaly (two files missing from jr-estate) was a timeline artifact (files added in 664bf01 after jr-estate's rsync ran), not a Phase A bug.
+- cmail send was a working-but-invisible capability — an org-drill session claimed it couldn't send, then hand-rolled MIME through msmtp. Root cause: discoverability (protocols said nothing about email).
+
+** Files Modified
+
+- =lint-org.el= (+ test) — suppress verbatim-asterisk misplaced-heading (lo--verbatim-asterisk-at-line-p).
+- =startup.org= — Phase A sync guarded skip-when-dirty (scoped to synced paths), renumbered steps.
+- =session-context-path= (new script + bats), =protocols.org= / =startup.org= / =wrap-it-up.org= — AI_AGENT_ID-aware session-context path.
+- =cmail-action.py= (+ test) — --cc/--bcc/--in-reply-to/--references via build_message.
+- =protocols.org= — "Sending Email" subsection + "Inbox Monitoring Cadence" subsection; =send-email.org= Step 4 rewrite.
+- =monitor-inbox.org= (new template workflow), =inbox-status= (new script + bats), =INDEX.org= entry.
+- =todo.org= — two [#B] tasks (startup-dirty, Codex Phase 1) marked DONE.
+
+** Next Steps
+
+- *Inbox monitoring is now active* — check inbox-status at task boundaries going forward. The opt-in background =/loop= is available when unattended watching is wanted.
+- *All today's handoffs confirmed back* to their senders (jr-estate, health, work, org-drill); inbox empty.
+- *Signal MCP install at the desktop* still the oldest open carryover (GPG pinentry blocks it remotely).
+- Parked [#B]/[#C]: cross-project pattern catalog, the broader runtime-neutral arc (parent of Codex Phase 1).
+- Everything reaches downstream projects on their next template sync.
+
+* Session Log
+
+** 2026-05-30 ~17:20 CDT — post-wrap continuation: lint-org false-positive fix
+
+The prior session wrapped at 86326c1 (archived as =.ai/sessions/2026-05-30-16-06-drill-deck-anki-buildout-and-script-tests.org=). Craig then gave two post-wrap directives.
+
+First (4b24597): the wrap-up lint pass kept re-flagging two verbatim-asterisk misplaced-heading items (=** DONE=, =** Startup Pull Ordering= shown as verbatim refs in prose) that aren't fixable in todo.org. Per Craig's rule — linting shouldn't flag unfixable items; fixable→fix, else message rules' inbox — I filed a checker-bug report to this project's inbox (inbox-send excludes the sender, so a direct write) and dropped the two items from lint-followups.org.
+
+Then Craig said "fix the org checker" (1f79945). Added =lo--verbatim-asterisk-at-line-p= to =lint-org.el= (mirrors the markdown-bold detector, checks the reported line and the one before it since org-lint marks the blank line after the offender), and the misplaced-heading dispatch now suppresses verbatim-asterisk matches silently like the cj-comment case. TDD: flipped =lo-verbatim-asterisk-is-suppressed= + the mixed-fixture assertion (red), implemented (green). Updated header comments. Verified: 24/24 ERT, =lint-org --check todo.org= → judgment=0, sync-check clean, full suite 405/1skip green. Removed the now-resolved inbox bug report in the same commit. Pushed =4b24597..1f79945=.
+
+Craig then asked for a fresh session-context file (this one).
+
+** 2026-05-30 ~17:30 CDT — task 1: startup-rsync-dirty guard
+
+From jr-estate's handoff: Phase A's =rsync -a --delete= copies rulesets working-tree WIP into downstream projects when rulesets is dirty at their session start. Implemented option 1 (skip-when-dirty), scoped to the synced source paths: startup.org Phase A step 3 now guards the protocols/workflows/scripts rsyncs behind =git status --porcelain= on =claude-templates/.ai/{protocols.org,workflows/,scripts/}= — skips with a message when dirty, syncs when clean. Scoped to the synced paths so unrelated rulesets dirt (stray session-context.org) doesn't block the sync. Folded the three rsyncs into one guarded block, renumbered the Phase A list, added a Notes bullet. Verified the dirty-detection live (flagged my own WIP startup.org → skip). Resolved the reported propagation anomaly: cross-project-broadcast.org + page-signal.org were added in 664bf01 on 2026-05-29, after jr-estate's rsync ran — timeline, not a bug. Marked the [#B] task DONE. sync-check clean, suite 405/1skip green.
+
+Next: task 2 (Codex Phase 1 — AI_AGENT_ID + session-context.d/<id>.org).
+
+** 2026-05-30 ~17:45 CDT — task 2: Codex Phase 1 (AI_AGENT_ID)
+
+Fixed the singleton-session-context race backward-compatibly. New =.ai/scripts/session-context-path= helper resolves the active path from =AI_AGENT_ID=: unset → legacy =.ai/session-context.org= (one-agent default unchanged, per the spec's compatibility rule), set → =.ai/session-context.d/<sanitized-id>.org=. TDD: wrote session-context-path.bats (red, script absent), wrote the helper (green) — 5 cases (unset/empty/set/two-distinct/unsafe-chars). Wired startup.org's existence check + wrap-it-up.org's rename through the helper, each with a singleton fallback for older checkouts; wrap folds the agent id into the archive name. protocols.org documents the rule (new "Agent-scoped path" subsection). Verified the two-agent simulation (distinct paths per id) — the task's stated verification. sync-check clean, full suite 405/1skip + the 5 new bats green. Marked the [#B] task DONE. Pushed =9a1bea9..143feda=. The broader runtime-neutral arc stays parked under the parent [#C] spec.
+
+Both requested tasks (1 then 2) complete. Commits this session: 4b24597, 1f79945, 9a1bea9, 143feda (plus the wrap commit 86326c1 that closed the prior session).
+
+** 2026-05-30 ~22:00 CDT — inbox monitoring discussion + org-drill handoff (cmail discoverability)
+
+Craig asked to monitor the inbox + respond to handoffs, build infra for it, and discuss the act-vs-file rules + cadence. Discussed; Craig set the operating rule: when I decide to file → ask first (file = option 1 recommended, do-now = option 2); when I decide to act → just do it, no asking; always ask if unsure.
+
+Demonstrated the rule on the live org-drill handoff (cmail send was a working-but-invisible capability — an org-drill session claimed it couldn't send, then hand-rolled MIME through msmtp). All three asks read as act-now, so I did them, no asking:
+- #1 + #2 (ddcde66, docs): added a "Sending Email" subsection to protocols.org (cmail = default personal account, dmail = work, cmail-action send = the tool, with examples); rewrote send-email.org Step 4 off the inline-Python/msmtp heredoc to cmail-action send.
+- #3 (e446dab, feat, TDD): cmail-action send gained --cc/--bcc (repeatable) + --in-reply-to/--references via build_message; 4 new tests, test _args helper updated, 57 cmail tests + full suite 409/1skip green.
+Confirmed back to org-drill via inbox-send; inbox empty.
+
+STILL OPEN — the monitoring infrastructure build. Craig resolved the act-vs-file rule but not: (a) cadence default (proposed: check at every task boundary during a session + opt-in background /loop), (b) project-workflow vs template scope, (c) new inbox-status script vs extend cross-agent-status. Need those calls before building the monitor-inbox workflow + script.
+
+** 2026-05-31 — monitoring infrastructure built (8c0eca8)
+
+Craig: "proceed with your recommendations. general workflow, for sure." Built all three recommendations as a template (general) workflow:
+- =inbox-status= script (template, +x, mirror) — lists unprocessed handoffs (excludes .gitkeep / lint-followups.org / PROCESSED-*), exit 0 clean / 1 pending / 2 no-inbox-or-usage, =-q= count-only. 5 bats cases, live-verified.
+- =monitor-inbox.org= template workflow — the cadence (task-boundary default + opt-in background =/loop=) + the act-vs-file decision rule + the reply discipline, layered over process-inbox.org (no duplication of the value gate). INDEX.org entry added.
+- protocols.org "Inbox Monitoring Cadence" subsection (read every session) so the habit actually fires: check inbox-status at task boundaries, act-now silent / file asks (file = option 1) / ask if unsure, always reply to senders.
+Verified: sync-check clean, full suite 409/1skip + 5 new bats green. The cadence is now active — checked the inbox at this boundary (0 pending).
diff --git a/todo.org b/todo.org
index dbe3820..380244b 100644
--- a/todo.org
+++ b/todo.org
@@ -1176,45 +1176,6 @@ Broader refactor proposes runtimes/ adapter manifests, generic install commands,
Before any implementation: needs a real review pass on the spec, and a decision on whether to do Phase 1 alone (low risk, fixes the race) vs commit to the larger arc.
-** DONE [#B] Startup Phase A rsync propagates dirty rulesets WIP into downstream projects :feature:
-CLOSED: [2026-05-30 Sat]
-:PROPERTIES:
-:CREATED: [2026-05-29 Fri]
-:LAST_REVIEWED: 2026-05-29
-:END:
-Fixed via option 1 (skip-when-dirty), scoped to the synced source paths: startup.org Phase A now guards the protocols/workflows/scripts rsyncs behind a =git status --porcelain= check on =claude-templates/.ai/{protocols.org,workflows/,scripts/}=, skipping the sync when any are dirty. The propagation anomaly (cross-project-broadcast.org / page-signal.org not reaching jr-estate) was a timeline artifact: both files were added in 664bf01 on 2026-05-29, after jr-estate's Phase A rsync had already run — correct behavior, not a bug.
-
-From jr-estate handoff 2026-05-29. When rulesets has uncommitted WIP at the moment a downstream project starts a session, Phase A.0 reports "dirty, skipping pull" and proceeds. Phase A's =rsync -a --delete= then runs against the dirty rulesets working tree and copies the WIP state into the downstream project's =.ai/workflows/= and =.ai/scripts/=. The downstream project's =git status= then shows drift the user did not author. Two bad recovery paths: commit the drift as "chore: sync .ai tooling from templates" (creates fake commit history about template state) or leave it dirty (noisy wrap-ups, pressure to commit anyway).
-
-Three options proposed in the handoff:
-1. *Skip-when-dirty.* Make Phase A's workflows/ and scripts/ rsync no-op when Phase A.0 reports rulesets dirty. Simplest defense.
-2. *Clean-files-only.* Restrict the rsync to files git considers unmodified in rulesets. Untracked files in rulesets do not propagate. Most precise.
-3. *Clean-ref-based.* Cache the last-known-clean state as a git tag or ref and rsync from that ref rather than the working tree. Most decoupled, also the most infrastructure.
-
-Recommendation (mine): option 1. The downstream impact of skipping a sync once is small (the next session with rulesets clean catches up), and the implementation is one =if [ "$dirty" -eq 0 ]= guard around the existing rsync block. Option 2 adds shellout complexity per file; option 3 requires tagging discipline that has no other reason to exist.
-
-The original handoff also noted a related anomaly: even with =--delete=, two files that DO exist in rulesets canonical (=cross-project-broadcast.org=, =page-signal.org=) did NOT propagate to jr-estate. Worth confirming whether that was a transient rsync issue or evidence of a deeper Phase A bug. Could be ordering: those files were added to rulesets AFTER the jr-estate Phase A rsync ran, in which case the behavior is correct and the report is misreading the timeline.
-
-Source: =inbox/2026-05-29-0832-from-jr-estate-investigate-startup-rsync-carried-dirty.org= (processed and deleted).
-
-** DONE [#B] Codex Phase 1 — AI_AGENT_ID + session-context.d/<id>.org :feature:
-CLOSED: [2026-05-30 Sat]
-:PROPERTIES:
-:CREATED: [2026-05-28 Thu]
-:LAST_REVIEWED: 2026-05-28
-:END:
-Shipped backward-compatibly. New =.ai/scripts/session-context-path= helper resolves the active path from =AI_AGENT_ID=: unset → the legacy =.ai/session-context.org= singleton (one-agent default unchanged, per the spec's compatibility rule), set → =.ai/session-context.d/<sanitized-id>.org=. startup.org's existence check and wrap-it-up.org's rename now resolve through the helper (with a singleton fallback for older checkouts); wrap folds the agent id into the archive name. protocols.org documents the rule. Verified: 5 bats cases + a two-agent simulation showing distinct paths per id. Larger runtime-neutral arc (runtimes/ manifests, launcher refactor) stays parked under the parent spec.
-
-Lifted from the broader codex runtime spec ([[file:docs/design/2026-05-28-generic-agent-runtime-spec.org]]) as the immediate-correctness slice independent of the larger arc. The singleton =.ai/session-context.org= is unsafe under simultaneous agents — two LLMs running in the same project at the same time would overwrite each other's session state.
-
-Scope: introduce an =AI_AGENT_ID= environment variable and split the single =session-context.org= into a per-agent =session-context.d/<id>.org= directory. No other phases of the runtime refactor are in this task — keep the surface small, fix the race, ship.
-
-Touches: =.ai/protocols.org= (rename rule + recovery anchor), =.ai/workflows/startup.org= (Phase A check), wrap-up workflow (rename target), per-project session record discoverability.
-
-Verification: simulate two agents sharing a project (separate AI_AGENT_ID values) and confirm session-context writes land in distinct files without interleaving.
-
-Parent: see [[Generic agent runtime support — Codex spec v0]] above for the larger arc this is sliced from.
-
** TODO [#B] Add Signal MCP server (rymurr/signal-mcp) :feature:
SCHEDULED: <2026-05-29 Fri>
:PROPERTIES:
@@ -2431,3 +2392,40 @@ Files to update:
Investigation: search =.ai/sessions/=, =.ai/notes.org=, inbox archive, and git log for mentions of these workflow docs. Identify review/response/design iterations, dates, and contributors (including agents where known: Claude Code, Codex, local models). Distinguish high-confidence history (commits, dated session entries) from inferred (chat-only context). Recommend whether enough evidence exists to populate the section, and draft the entries if so.
Dependency: spec-review.org and spec-response.org have uncommitted edits in flight. Wait for those to land before writing to the files. The read-only research portion (search sessions, identify iterations, draft entries to a scratch file) can run in parallel without conflict.
+** DONE [#B] Startup Phase A rsync propagates dirty rulesets WIP into downstream projects :feature:
+CLOSED: [2026-05-30 Sat]
+:PROPERTIES:
+:CREATED: [2026-05-29 Fri]
+:LAST_REVIEWED: 2026-05-29
+:END:
+Fixed via option 1 (skip-when-dirty), scoped to the synced source paths: startup.org Phase A now guards the protocols/workflows/scripts rsyncs behind a =git status --porcelain= check on =claude-templates/.ai/{protocols.org,workflows/,scripts/}=, skipping the sync when any are dirty. The propagation anomaly (cross-project-broadcast.org / page-signal.org not reaching jr-estate) was a timeline artifact: both files were added in 664bf01 on 2026-05-29, after jr-estate's Phase A rsync had already run — correct behavior, not a bug.
+
+From jr-estate handoff 2026-05-29. When rulesets has uncommitted WIP at the moment a downstream project starts a session, Phase A.0 reports "dirty, skipping pull" and proceeds. Phase A's =rsync -a --delete= then runs against the dirty rulesets working tree and copies the WIP state into the downstream project's =.ai/workflows/= and =.ai/scripts/=. The downstream project's =git status= then shows drift the user did not author. Two bad recovery paths: commit the drift as "chore: sync .ai tooling from templates" (creates fake commit history about template state) or leave it dirty (noisy wrap-ups, pressure to commit anyway).
+
+Three options proposed in the handoff:
+1. *Skip-when-dirty.* Make Phase A's workflows/ and scripts/ rsync no-op when Phase A.0 reports rulesets dirty. Simplest defense.
+2. *Clean-files-only.* Restrict the rsync to files git considers unmodified in rulesets. Untracked files in rulesets do not propagate. Most precise.
+3. *Clean-ref-based.* Cache the last-known-clean state as a git tag or ref and rsync from that ref rather than the working tree. Most decoupled, also the most infrastructure.
+
+Recommendation (mine): option 1. The downstream impact of skipping a sync once is small (the next session with rulesets clean catches up), and the implementation is one =if [ "$dirty" -eq 0 ]= guard around the existing rsync block. Option 2 adds shellout complexity per file; option 3 requires tagging discipline that has no other reason to exist.
+
+The original handoff also noted a related anomaly: even with =--delete=, two files that DO exist in rulesets canonical (=cross-project-broadcast.org=, =page-signal.org=) did NOT propagate to jr-estate. Worth confirming whether that was a transient rsync issue or evidence of a deeper Phase A bug. Could be ordering: those files were added to rulesets AFTER the jr-estate Phase A rsync ran, in which case the behavior is correct and the report is misreading the timeline.
+
+Source: =inbox/2026-05-29-0832-from-jr-estate-investigate-startup-rsync-carried-dirty.org= (processed and deleted).
+** DONE [#B] Codex Phase 1 — AI_AGENT_ID + session-context.d/<id>.org :feature:
+CLOSED: [2026-05-30 Sat]
+:PROPERTIES:
+:CREATED: [2026-05-28 Thu]
+:LAST_REVIEWED: 2026-05-28
+:END:
+Shipped backward-compatibly. New =.ai/scripts/session-context-path= helper resolves the active path from =AI_AGENT_ID=: unset → the legacy =.ai/session-context.org= singleton (one-agent default unchanged, per the spec's compatibility rule), set → =.ai/session-context.d/<sanitized-id>.org=. startup.org's existence check and wrap-it-up.org's rename now resolve through the helper (with a singleton fallback for older checkouts); wrap folds the agent id into the archive name. protocols.org documents the rule. Verified: 5 bats cases + a two-agent simulation showing distinct paths per id. Larger runtime-neutral arc (runtimes/ manifests, launcher refactor) stays parked under the parent spec.
+
+Lifted from the broader codex runtime spec ([[file:docs/design/2026-05-28-generic-agent-runtime-spec.org]]) as the immediate-correctness slice independent of the larger arc. The singleton =.ai/session-context.org= is unsafe under simultaneous agents — two LLMs running in the same project at the same time would overwrite each other's session state.
+
+Scope: introduce an =AI_AGENT_ID= environment variable and split the single =session-context.org= into a per-agent =session-context.d/<id>.org= directory. No other phases of the runtime refactor are in this task — keep the surface small, fix the race, ship.
+
+Touches: =.ai/protocols.org= (rename rule + recovery anchor), =.ai/workflows/startup.org= (Phase A check), wrap-up workflow (rename target), per-project session record discoverability.
+
+Verification: simulate two agents sharing a project (separate AI_AGENT_ID values) and confirm session-context writes land in distinct files without interleaving.
+
+Parent: see [[Generic agent runtime support — Codex spec v0]] above for the larger arc this is sliced from.