aboutsummaryrefslogtreecommitdiff
path: root/todo.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-18 19:55:43 -0500
committerCraig Jennings <c@cjennings.net>2026-07-18 19:55:43 -0500
commitbc1d81d835237343a4ced82a9025f2dc34f45865 (patch)
tree173150aadac7932eb55759bf294fb18ca2b453a7 /todo.org
parent6523ed5b789689a2b77925fb3825570b2d8e5686 (diff)
downloadrulesets-bc1d81d835237343a4ced82a9025f2dc34f45865.tar.gz
rulesets-bc1d81d835237343a4ced82a9025f2dc34f45865.zip
chore(todo): file four backlog tasks from the inbox pass
Filed as [#B] work items with their origin proposals preserved under docs/design/: the todo-cleanup dated-seal archiving model, the dated-log planning-line strip plus its lint backstop, a hook to enforce the task-boundary inbox check, and home's colloquialisms / "the list" before-close-queue convention. The first two both touch todo-cleanup.el and are cross-linked to build as one batch. The last two carry the design worked out this session so they start warm.
Diffstat (limited to 'todo.org')
-rw-r--r--todo.org149
1 files changed, 149 insertions, 0 deletions
diff --git a/todo.org b/todo.org
index cdf2397..d06ae3f 100644
--- a/todo.org
+++ b/todo.org
@@ -1310,6 +1310,155 @@ having a skill to generate or check OV-1-shaped artifacts. Don't build
speculatively — defense-specific notations are narrow enough that each
skill should be driven by a concrete contract need, not aspiration.
+** TODO [#B] todo-cleanup.el dated-seal archiving :feature:solo:
+Redefine =--archive-done= aging from a 7-day roll-into-one-file model to a
+one-month retention with dated seals. Craig ratified the design in the work
+project 2026-07-17; origin handoff preserved at
+[[file:docs/design/2026-07-17-todo-cleanup-dated-seal-proposal.md]].
+
+Changes to =.ai/scripts/todo-cleanup.el= (canonical in
+=claude-templates/.ai/scripts/=):
+- =tc-archive-retain-days= default 7 → 31.
+- Aging predicate: archive a level-2 DONE/CANCELLED subtree when CLOSED is
+ older than the retain window OR CLOSED is unparseable. The unparseable case
+ already archives per the docstring; make it explicit in the contract.
+- New seal step (flag, e.g. =--seal=): rename the working =tc-archive-file=
+ (=task-archive.org=) → =resolved-YYYY-MM-DD.org= beside it; next aging
+ recreates a fresh working file. Auto-seal-at-quarter vs manual flag is an
+ open call — default manual (the per-project rotation task covers cadence).
+- Update the file-aging tests (=test-todo-cleanup.el= lines 362, 378, 491,
+ 513, 518) for the new retain default and the seal/rename behavior. The
+ gitignore-inheritance logic (=tc--ensure-archive-gitignored=) applies to both
+ names unchanged.
+
+TDD, canonical-then-mirror per the sync-check invariant. Home's planning-line
+strip proposal (filed alongside) also touches todo-cleanup.el =--convert-subtasks=
+— the two can be built as one batch.
+
+** TODO [#B] Strip stale planning lines on dated completion + lint backstop :feature:solo:
+Two linked fixes so a closed sub-task can't keep polluting the org agenda. Origin:
+home handoff 2026-07-17; design preserved at
+[[file:docs/design/2026-07-17-dated-log-planning-line-strip-proposal.md]]. A dated-log
+heading (no TODO keyword) that still carries an active =SCHEDULED:= renders as
+weeks-overdue on the agenda forever — invisible to a keyword scan and surviving
+=--archive-done=. Root cause: the completion rewrite strips keyword/priority/tags
+but nothing strips the planning line, and an interactive org close only stamps
+=CLOSED:=.
+
+1. =claude-rules/todo-format.md= (canonical rule) — in the "=***= and deeper —
+ rewrite to a dated event-log entry" section, add a step: remove any
+ =SCHEDULED:=/=DEADLINE:= line when rewriting to the dated form. Apply the same
+ to the VERIFY dated-completion path.
+2. =.ai/scripts/lint-org.el= (canonical in =claude-templates/.ai/scripts/=) — new
+ checker =dated-log-heading-active-timestamp=: flag any dated-log heading (the
+ =YYYY-MM-DD ... @ ...= form, no TODO keyword) carrying an active =<...>=
+ SCHEDULED or DEADLINE. The mechanical backstop for #1, mirroring
+ =subtask-done-not-dated=.
+3. =todo-cleanup.el= =--convert-subtasks= — drop the planning line alongside its
+ existing CLOSED-timestamp pull.
+
+Build notes: the checker's regex must key on "no TODO keyword" so it never flags a
+live TODO that legitimately carries a SCHEDULED. TDD, canonical-then-mirror. Batches
+with the dated-seal task above (both touch todo-cleanup.el).
+
+** TODO [#B] Enforce the task-boundary inbox check via a hook :feature:
+Today the "check =inbox/= at every task boundary" rule (protocols.org, "Inbox
+Monitoring Cadence") is prose-only — present in all 27 projects' synced
+protocols.org, but nothing mechanically enforces it, so it holds only as well as
+the agent's adherence. Convert it to a hook so a pending handoff can't slip past a
+turn unseen. Design worked out with Craig 2026-07-18.
+
+*** The one decision to settle at kickoff
+Hard-block vs soft-nudge (this is why the task isn't =:solo:= — it's a preference
+call). My recommendation: *soft-nudge*. Answer this first, then the rest is
+mechanical.
+- *Hard-block*: the Stop hook blocks EVERY yield while items are pending, forcing
+ the agent to process before it can return control. Strongest guarantee, but it
+ also fires when the agent pauses mid-task to ask Craig a clarifying question
+ (that pause is also a Stop), pushing inbox processing ahead of the question.
+- *Soft-nudge*: use the =stop_hook_active= flag to inject the reason once per turn,
+ then let the turn end if the agent chooses not to act. Stronger than today's
+ prose rule, no clarifying-question hijack.
+
+*** Why the Stop event
+The harness has no "task boundary" event. But the rule's own definition — "after
+finishing a unit of work, before reporting back or asking what's next" — maps onto
+the Stop event (agent finishing its turn, about to yield). Every "reporting back"
+is a Stop. PostToolUse is wrong granularity (fires per tool call); UserPromptSubmit
+is the START of the next task, useful only as a complement (below).
+
+*** Mechanism
+A Stop hook returns =\{"decision":"block","reason":"N pending handoffs — process
+per inbox.org before yielding."\}= when =inbox-status -q= exits 1. The harness then
+keeps the agent going with that reason injected instead of returning to Craig. The
+loop self-terminates: once items are dispositioned (deleted or renamed
+=PROCESSED-=, which =inbox-status= excludes), the next Stop exits 0 and the turn
+ends. The harness passes =stop_hook_active: true= on the re-entry — check it to
+nudge once rather than wedge on an item the agent genuinely can't process.
+
+*** The complement (optional, pair with the Stop hook)
+A =UserPromptSubmit= hook that runs =inbox-status= and injects a one-line "N
+pending handoffs" note into context at the start of Craig's next instruction.
+Non-blocking; guarantees the agent sees pending items the moment a new task starts.
+Catches the "arrived while away" case from the other direction. Can ship alone
+(pure visibility) or alongside the Stop hook. Recommended: ship both.
+
+*** Placement + files
+- Global, in =~/.claude/settings.json= (the =Stop= array already holds
+ =ai-wrap-teardown.sh= — add a second entry, or a combined script).
+- Ship the script from =claude-templates/.claude/hooks/= (e.g.
+ =inbox-boundary-check.sh=); =make install-hooks= links it; wire it in the tracked
+ =settings.json= so it travels. Mirror the reference pattern in
+ =hooks/ai-wrap-teardown.sh= — reads =cwd= from stdin JSON via =jq=, basenames to
+ the project.
+- Self-skips where inapplicable: =inbox-status= exits 2 with no =inbox/= dir, so
+ the hook no-ops in any project without an inbox. One hook, every project, no
+ config.
+
+*** Verify
+- bats around the hook script (=hooks/tests/=): exit-1 inbox → block JSON emitted;
+ exit-0 → no output; =stop_hook_active: true= input → single-nudge path; no
+ =inbox/= → clean no-op. Follow the existing hook-test pattern.
+- Live: drop a test handoff, confirm the agent is pushed to process it at turn end.
+
+*** Honest limitation to carry forward
+No hook can perfectly tell "a unit of work finished" from "the agent paused for any
+other reason" — the harness exposes only "the turn is ending," not "a task is
+ending." The design leans on those two being usually the same in Craig's workflow.
+That's the tradeoff hard-block vs soft-nudge is really about.
+
+** TODO [#B] "Colloquialisms and Expansions" + "the list" before-close-queue convention :feature:
+Home proposes two linked cross-project norms; Craig recommends rolling them out.
+Origin: home handoff 2026-07-18, design preserved at
+[[file:docs/design/2026-07-18-colloquialisms-and-the-list-proposal.md]]. Needs Craig's
+adoption decision + a small design pass before implementation — that's why it's
+filed, not applied.
+
+The two parts:
+1. *"the list" = a before-close FIFO queue.* "Put X on the list" / "add X to the
+ list" appends X to a session-scoped Before-Close Queue, worked oldest-first at
+ wrap-up before teardown, unfinished items surfaced rather than dropped. Resets
+ when the session anchor archives. Anything that must outlive the session is a
+ =todo.org= task instead.
+2. *"Colloquialisms and Expansions" shorthand dictionary.* A per-project (or
+ shared) map of Craig shorthand → expansion the agent applies without asking.
+ Seed entries: "the list" → the queue above; "tell <project> <msg>" → drop the
+ message in that project's inbox via =inbox-send= (already the sanctioned
+ handoff, so this entry is near-documentation).
+
+Durable wiring (why rulesets, not home-local): (a) a colloquialisms reference in
+the template — a =protocols.org= section or a shipped reference file; (b) a
+=wrap-it-up.org= step that processes the Before-Close Queue before teardown.
+=wrap-it-up.org= is a synced rulesets-owned workflow, so home can't wire (b)
+durably from downstream — it stubbed the norm via its local =notes.org= for now.
+
+Design pass to settle first: where the colloquialisms reference lives (protocols.org
+section vs a new shipped reference file); where the queue itself lives (home used a
+=* Before-Close Queue= heading in =session-context.org=); and the exact wrap-it-up
+insertion point (before the teardown/valediction, alongside the roam-inbox
+sub-step). Then it's a synced-file change (canonical-then-mirror) + a test that the
+wrap step drains the queue.
+
* Rulesets Resolved
** CANCELLED [#C] ntfy phone channel as general two-way agent-comms :feature:spec:
CLOSED: [2026-07-13 Mon]