aboutsummaryrefslogtreecommitdiff
path: root/.ai/workflows/inbox.org
diff options
context:
space:
mode:
Diffstat (limited to '.ai/workflows/inbox.org')
-rw-r--r--.ai/workflows/inbox.org25
1 files changed, 18 insertions, 7 deletions
diff --git a/.ai/workflows/inbox.org b/.ai/workflows/inbox.org
index 6faa20f..914433d 100644
--- a/.ai/workflows/inbox.org
+++ b/.ai/workflows/inbox.org
@@ -103,7 +103,7 @@ The full question-battery answers live in the session log and the =working/= dir
* Core §3 — The disposition ladder
-Every item that clears the value gate gets one disposition. The first six are the per-item outcomes; *park* is the no-approvals shared-asset path from core §2.
+Every item that clears the value gate gets exactly one disposition: *implement now*, *fold into an existing TODO*, *file as a TODO*, or *reject*. *Park* is the no-approvals shared-asset path from core §2. Whichever it gets, nothing stays in =inbox/=.
** Implement now
Small, scoped, clear, no design call required. The work is the disposition. Do the work, commit per the project's commit flow, delete the inbox file. The commit message references the inbox item by filename so the provenance lands in =git log=.
@@ -124,8 +124,17 @@ On a =<destination>\tstrong= or =<destination>\tweak= result, stamp the new TODO
*Blocking-dependency handoff.* A special shape: another project sends a note that *this* project's work is blocking one of theirs ("your task X is blocked on us — we need Y"). File or link the owning task, tag it =:blocker:=, and name the requesting project in the body (see the cross-project dependency convention in =todo-format.md=). The =:blocker:= tag makes =open-tasks.org= surface that task *first*, since clearing it unblocks the other project. Dedup against an existing task rather than filing a duplicate. When the work later lands, drop =:blocker:= and notify the waiting project (=inbox-send <their-project> --text "Delivered: <what> — you're unblocked."=) so it can lift its own =:blocked:=.
-** Defer
-Rename in place to =inbox/PROCESSED-<original-filename>= and add a brief comment line at the top: =# Deferred YYYY-MM-DD: <condition>=. Don't accumulate deferred items indefinitely — sweep them on a future process pass when the condition is met or the deferral has aged out.
+** Deferral is not a disposition: file it or delete it
+There is no rung that leaves an item in =inbox/= under another name. An item whose work waits is a *task*, so file it (core §3 "File as TODO") with the waiting condition in its body. An item worth keeping for reference is *content*, so move it to =docs/design/= and link it from whatever task cites it. An item that is neither gets deleted. Every path ends with the inbox file gone.
+
+The retired rung renamed deferred items in place to =inbox/PROCESSED-<original>=, and it failed twice in ways worth naming, because the shape recurs:
+
+1. *It accumulated.* The rung told you not to let deferrals pile up and gave that instruction no enforcement, so nothing surfaced them and nothing owned them. Rulesets reached 40 before a manual sweep on 2026-07-27, and the rest of the fleet was still carrying 114 when this rung was removed on 2026-08-20.
+2. *It lost the content it was meant to preserve.* A =PROCESSED-= file is not a durable home, so a task citing one as its source breaks the moment somebody sweeps. Rulesets' =todo.org= carried exactly that dangling reference.
+
+Both follow from one defect: =PROCESSED-*= was a third state that is neither a tracked task nor gone. It sat in =inbox/=, hidden from =inbox-status=, absent from =todo.org=, and carried by no review cycle. Filing and deleting are the two states that already have homes and cadences, which is why they are the only two on offer.
+
+*Legacy files.* A =PROCESSED-*= file predating this change is not grandfathered. It is an undispositioned item. Give it the same choice as anything else: file it, move its content to =docs/design/=, or delete it.
** Reject — by source
- *From Craig* — push back honestly in chat. State why you won't implement; offer the conditions under which you would, if any. The inbox file stays until Craig confirms — override re-enters as accept, acknowledgment deletes the file. Don't theatre the pushback: if you don't genuinely think Craig is wrong, just do the work.
@@ -188,13 +197,13 @@ The point is to avoid adding ungraded =TODO= entries to a project that's never a
* Mode: process
-Reads the project-local =inbox/= dir. Entry: a trigger phrase, or startup Phase C on a non-empty inbox. Exit: inbox empty (excluding =.gitkeep= and intentional =PROCESSED-*=), session log updated, =:LAST_INBOX_PROCESS:= stamped.
+Reads the project-local =inbox/= dir. Entry: a trigger phrase, or startup Phase C on a non-empty inbox. Exit: inbox empty (excluding =.gitkeep= and the =lint-followups.org= pipeline artifact), session log updated, =:LAST_INBOX_PROCESS:= stamped.
** Phase A — Inventory (one parallel batch)
Issue these reads in one parallel batch:
-1. List =inbox/= excluding =.gitkeep= and =PROCESSED-*= prefixes (use =\ls -la inbox/= per the protocols.org exa-alias note).
+1. List =inbox/= excluding =.gitkeep= (use =\ls -la inbox/= per the protocols.org exa-alias note). A =PROCESSED-*= file from before the deferral rung was retired is a legacy item, not an artifact: list it and disposition it like any other.
2. Read =notes.org= *Project-Specific Context* if mission isn't already loaded in the session.
3. Read =todo.org='s top-of-file priority scheme if present.
@@ -245,7 +254,7 @@ Disposition recommendation: <implement / fold into <TODO> / file [#X] :tags: / r
1. <recommendation as item 1>
2. <alternative>
-3. Defer — leave in inbox under PROCESSED-<topic>.<ext> until <condition>
+3. Delete — nothing worth filing and no reference worth keeping
4. Something else
#+end_example
@@ -259,7 +268,7 @@ Apply each disposition per the ladder (core §3). The flow is autonomous past Cr
** Phase E — Close out
-Verify =inbox/= is empty (excluding =.gitkeep= and any intentional =PROCESSED-*= files). Run =\ls -la inbox/= and confirm.
+Verify =inbox/= is empty (excluding =.gitkeep= and =lint-followups.org=). Run =\ls -la inbox/= and confirm. Nothing is left behind under a renamed prefix, because deferral-in-place is not a disposition.
Update the session log per =protocols.org= with one short paragraph: count processed, count accepted (implement/fold/file split), count rejected (Craig/handoff/script split), and the commit SHA if a commit landed.
@@ -356,6 +365,8 @@ Close the loop per the reply-to-sender discipline (core §4): confirm what lande
=.ai/scripts/inbox-status= lists unprocessed handoffs and exits nonzero when any are pending. Exclusions match the wrap-up sanity check (=.gitkeep=, =lint-followups.org=, =PROCESSED-*=). Exit 0 = clean, 1 = pending, 2 = no inbox/ or bad usage. Use =-q= for the count-only form the cadence check calls.
+*The =PROCESSED-*= exclusion is transitional, not a supported state.* Nothing creates such a file any more, so the exclusion can only ever match a legacy item from before the deferral rung was retired. It stays for one reason: 114 of them were sitting across five projects on 2026-08-20, and dropping the exclusion would have made every one pending at once, blocking the next session of each project behind a cleanup it didn't ask for. The sweep is tracked as its own task instead. When it finishes, the exclusion comes out of this script, the wrap-up check, and =scripts/status.sh= together, and the ladder's "not grandfathered" rule stops needing a caveat.
+
** Close out — before finishing
End the way it started: clean worktree, green suite. Before stopping the loop or reporting the pass done: