aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-13 01:38:42 -0500
committerCraig Jennings <c@cjennings.net>2026-06-13 01:38:42 -0500
commit62cd707c2b78508e35177f553b72258ac6114198 (patch)
tree667ba86fca8cbb5f1638c2296c01775282db0aef
parent7b65b2dd04d97c2dc34e5afa715a07ce14b851ae (diff)
downloadrulesets-62cd707c2b78508e35177f553b72258ac6114198.tar.gz
rulesets-62cd707c2b78508e35177f553b72258ac6114198.zip
docs(design): resolve wrap-up routing spec decisions (Reading B)
All six decisions resolved. The router's input is filed keepers that belong to another project, not raw inbox files (Reading B). That keeps it a separate sub-step from the inbox gate (D1) and distinct from the defer-and-stage router (D5). Transcript routing is deferred to vNext (D4). I reworked the design to match: the input definition, a candidate-set note bounding the router to session-filed keepers rather than the standing backlog, and Phase 3. The cookie reads [6/6] and the Status moved to ready for review. The A-vs-B input ambiguity was the root under D1 and D5. Reading B keeps the inbox gate, the router, and defer-and-stage each simple instead of entangling all three.
-rw-r--r--docs/design/wrapup-routing-spec.org44
-rw-r--r--todo.org4
2 files changed, 26 insertions, 22 deletions
diff --git a/docs/design/wrapup-routing-spec.org b/docs/design/wrapup-routing-spec.org
index 396fb45..0091806 100644
--- a/docs/design/wrapup-routing-spec.org
+++ b/docs/design/wrapup-routing-spec.org
@@ -4,7 +4,7 @@
#+TODO: TODO | DONE SUPERSEDED CANCELLED
* Metadata
-| Status | draft |
+| Status | ready for review |
|----------+-----------------------------------------------------|
| Owner | Craig Jennings |
|----------+-----------------------------------------------------|
@@ -51,7 +51,7 @@ The friction is small per-item but recurring, and the manual cross-project edit
** User-facing (the wrap interaction)
-The router is a new sub-step of =wrap-it-up.org='s Step 3, running after the existing inbox sanity check. When it finds inbox items whose recommended home is a different project, it surfaces them as a list, one line each: the item, the recommended destination project, and a confidence marker when the inference is weak. Then two options, batch-level:
+The router is a new sub-step of =wrap-it-up.org='s Step 3, running after the existing inbox sanity check. Its input is filed keepers, not raw inbox files (decision: Reading B): tasks =process-inbox= accepted and filed into the local =todo.org= this session whose inferred home is a different project. When the router finds such a keeper, it surfaces it in a list, one line each: the task, the recommended destination project, and a confidence marker when the inference is weak. Then two options, batch-level:
1. Go with the recommendations — apply every recommended move.
2. Skip — leave the whole batch in place. A skip is a clean wrap.
@@ -62,6 +62,8 @@ A move of a task/event relocates it into the destination project's "Open Work" s
** Implementer (the mechanics)
+*Candidate set (what the router considers).* Reading B means the router does not scan the whole local backlog — it would otherwise suggest moving legitimate local tasks every wrap. The candidate set is keepers =process-inbox= filed this session whose inferred home differs from the current project. How those are marked is an implementation detail for Phase 3/4: either =process-inbox= tags a cross-project-candidate keeper at file time, or the router infers from a =CREATED= stamp dated this session plus content. The reviewer should pin which; the design constraint is "session-filed inbox keepers only, never the standing backlog."
+
*Destination discovery.* Widen the project-discovery filter from "directory with a =.ai/protocols.org= marker" (what =inbox-send.py= and the =ai= launcher use) to "directory with a =todo.org= containing a level-1 'Open Work' heading." A plain code repo Craig keeps a =todo.org= in is a valid destination; an =.ai/= directory is not required.
*Destination anchor.* Reuse =todo-cleanup.el='s existing matcher: =tc--find-section= locates the unique level-1 heading containing "Open Work" (case-insensitive) and returns =nil= / ='multiple= when absent or ambiguous. A destination whose =todo.org= lacks a clean Open Work heading is surfaced and skipped, never guessed at.
@@ -82,14 +84,14 @@ A move of a task/event relocates it into the destination project's "Open Work" s
** Fold the router into the existing Inbox sanity check step
- Good, because one inbox step is simpler than two.
- Bad, because the sanity check *gates* the wrap (blocks until clean) and the router is *optional* (skip is clean). Merging a blocking check with an optional action muddies both.
-- Neutral, because the two could share discovery code while staying separate steps. (This is open decision D1.)
+- Neutral, because the two share discovery code while staying separate steps. (Resolved: D1 keeps them separate, with the router acting on filed keepers rather than inbox files.)
** Reuse process-inbox's "file as TODO" with a destination argument
- Good, because it avoids a second mechanism.
- Bad, because =process-inbox= runs per-item mid-session against the local project; the router runs at wrap, batch-level, cross-project. Different cadence, different scope.
- Neutral, because both ultimately call the same atomic move helper — the helper is the shared primitive, the two callers stay distinct.
-* Decisions [/]
+* Decisions [6/6]
** DONE Reuse the Open Work matcher for destination anchoring
- Context: the move needs a reliable insertion point in the destination =todo.org=; guessing risks corrupting another project's file.
@@ -106,23 +108,20 @@ A move of a task/event relocates it into the destination project's "Open Work" s
- Decision: We will treat the batch "go" as the authorization, leave the move visible in the destination's git diff, and stamp a one-line provenance note (source project + date) on each moved task.
- Consequences: easier — the boundary rule is honored without a per-move prompt. Harder — the destination's next session sees an externally-authored task it didn't file, so the provenance note is load-bearing, not decorative.
-** TODO Separate router step or merge into the inbox sanity check
-- Owner / by-when: Craig / before implementation.
-- Context: the sanity check gates the wrap; the router is optional. archsetup leans separate; so do I (a blocking check and an optional action read more clearly apart). But it's Craig's wrap-cadence call.
-- Decision: We will (proposed) keep the router a *separate* optional sub-step running after the sanity check, sharing only the discovery code.
-- Consequences: easier — each step has one job, the optional one can't accidentally block. Harder — two inbox-touching steps in one wrap, slightly more workflow prose.
+** DONE Separate router step, operating on filed keepers (Reading B)
+- Context: the sanity check gates the wrap on inbox/ contents; the router is optional. The deeper question was the router's input — raw inbox files (Reading A, which overlaps the sanity check) or already-filed keepers that belong elsewhere (Reading B, a todo-routing concern).
+- Decision: We will keep the router a separate optional sub-step after the sanity check, and its input is Reading B: accepted keepers process-inbox filed into the local =todo.org= whose inferred home is another project. The sanity check stays a pure inbox gate; the router is a todo-routing action that shares only the destination-discovery code.
+- Consequences: easier — each step has one job, the gate can't be muddied by an optional action, and the router never competes with the inbox gate over the same files. Harder — the candidate set (which local tasks the router considers) needs a marking mechanism (see the Implementer "candidate set" note); Reading A's "dispose raw inbox files at wrap" convenience is given up.
-** TODO Transcript routing — scope and trigger
-- Owner / by-when: Craig / before any transcript work starts.
+** DONE Transcript routing deferred to vNext
- Context: transcripts file as artifacts, not tasks, and a meeting usually produces both a recording to keep and action items to track. Two unknowns block it: where recordings accumulate (a recordings inbox, a downloads dir, wherever the meeting tooling drops them), and whether filing should also extract action items into the destination's =todo.org=.
-- Decision: We will (proposed) defer transcript routing to vNext, file the recording as an artifact only, and let action items route through the v1 task-router as a separate batch — keeping documents and tasks orthogonal.
-- Consequences: easier — v1 ships without the unresolved source-location dependency. Harder — a meeting's recording and its action items get handled by two mechanisms, which Craig may prefer combined into one "process this transcript" move.
+- Decision: We will defer transcript routing to vNext. Both the source-location dependency and the file-only-vs-extract-action-items question are deferred with it, to be settled when the vNext work is specced. v1 ships task routing only.
+- Consequences: easier — v1 isn't blocked on the unresolved source location. Harder — until vNext, a meeting recording still has no automatic home; only its action items (if filed as tasks) route through v1.
-** TODO Reconcile with the process-inbox defer-and-stage router
-- Owner / by-when: Craig + author / before implementation.
-- Context: the 2026-06-12 Skeptical Review added a defer-and-stage path in =process-inbox.org= that files a =[#B]= VERIFY for shared-asset proposals parked for review. That also moves an inbox item toward a =todo.org= task — overlapping surface with this router.
-- Decision: We will (proposed) keep them distinct: defer-and-stage parks a *proposal under review* locally as a VERIFY; this router moves an *accepted keeper* to its home project. Shared primitive is the atomic move helper, not the policy.
-- Consequences: easier — two clear, non-competing policies. Harder — the workflows must state the boundary so a future reader doesn't collapse them into one and reintroduce the ambiguity.
+** DONE Keep defer-and-stage and the router as distinct policies
+- Context: the 2026-06-12 Skeptical Review added a defer-and-stage path in =process-inbox.org= that files a =[#B]= VERIFY for shared-asset proposals parked for review. That also turns an inbox item into a =todo.org= task — overlapping surface with this router.
+- Decision: We will keep them distinct. Defer-and-stage parks a proposal-under-review locally as a VERIFY; the router moves an accepted keeper to its home project as a TODO. They differ on review status (proposal vs accepted) and destination (local vs cross-project), and share only the atomic move helper, not the policy. Reading B makes the split clean: the router acts on accepted keepers, never on proposals under review.
+- Consequences: easier — two clear, non-competing policies on one shared primitive. Harder — the workflow prose must name the boundary so a future reader doesn't collapse them and reintroduce the ambiguity.
* Implementation phases
@@ -132,8 +131,8 @@ A discovery function returning every project with a =todo.org= that has a clean
** Phase 2 — Atomic cross-project move helper
Extend =todo-cleanup.el= (or sibling tool) with a "move this subtree into project X's Open Work" operation that inserts at the destination and removes the source as one step, stamping the provenance line. ERT coverage: successful move, missing-destination-heading refusal, source-removal-on-success, no-partial-move-on-failure.
-** Phase 3 — Recommendation engine
-Infer destination from item content against the discovered list, with a confidence label. Unit-tested: strong match (project named in item), weak match (topic-only → low-confidence), no match (stays put). Pure function over (item, project-list) → (destination, confidence).
+** Phase 3 — Recommendation engine + candidate-set marking
+Infer destination from item content against the discovered list, with a confidence label. Pure function over (item, project-list) → (destination, confidence). Unit-tested: strong match (project named in item), weak match (topic-only → low-confidence), no match (stays put). Also settle the candidate-set marking (tag at file time vs CREATED-this-session inference) so the router considers only session-filed inbox keepers, never the standing backlog.
** Phase 4 — Wrap-up step wiring
Add the router sub-step to =wrap-it-up.org= Step 3: surface the batch, the two options, apply-on-go via the Phase 2 helper. Per the D1/D5 decisions once settled. Sync the =.ai/= mirror.
@@ -175,3 +174,8 @@ Only after the transcript-scope decision resolves. File a recording into the des
- What: initial draft. Problem, goals/scope tiers, two-altitude design, alternatives, six decisions (three DONE from grounding, three TODO for Craig), five implementation phases, acceptance criteria, readiness dimensions, risks.
- Why: the archsetup 2026-06-13 handoff cleared the spec bar in inbox triage and was filed spec-bound rather than applied. This draft turns the proposal into a reviewable design with the open questions isolated as decision tasks.
- Artifacts: proposal source at =docs/design/2026-06-13-wrapup-inbox-transcript-routing-proposal.org=; grounded against =wrap-it-up.org= Step 3, =todo-cleanup.el= =tc--find-section=, and =inbox-send.py= discovery.
+
+** 2026-06-13 Sat @ 01:36:28 -0500 — Craig Jennings + Claude Code (rulesets) — author
+- What: resolved all three open decisions. The router's input is Reading B (filed keepers that belong elsewhere, not raw inbox files), so D1 keeps it a separate sub-step from the inbox gate and D5 keeps it distinct from the defer-and-stage router; D4 defers transcript routing to vNext. Reworked the design (input definition, a candidate-set note bounding the router to session-filed keepers) and Phase 3 to match. Cookie now [6/6]; Status moved to ready-for-review.
+- Why: Craig chose Reading B after the A-vs-B input ambiguity surfaced as the root under D1 and D5. Reading B keeps the inbox gate, the router, and defer-and-stage each simple instead of entangling three mechanisms.
+- Artifacts: this spec; the candidate-set marking mechanism is the one detail flagged for spec-review to pin.
diff --git a/todo.org b/todo.org
index 7ff30de..aa6aa1b 100644
--- a/todo.org
+++ b/todo.org
@@ -39,9 +39,9 @@ Tags are assigned and refreshed by =task-audit=; =task-review= keeps them honest
:CREATED: [2026-06-13 Sat]
:LAST_REVIEWED: 2026-06-13
:END:
-Optional wrap-up step that surfaces inbox items belonging to another project, recommends a destination, and batch-moves them into that project's =todo.org= Open Work section (transcript filing deferred to vNext). Spec drafted, decisions D1/D4/D5 awaiting Craig before implementation-ready.
+Optional wrap-up step that surfaces filed keepers belonging to another project, recommends a destination, and batch-moves them into that project's =todo.org= Open Work section (transcript filing deferred to vNext). All six decisions resolved (Reading B: the router acts on session-filed keepers, separate from the inbox gate and from defer-and-stage). Spec ready for review.
-Spec: [[file:docs/design/wrapup-routing-spec.org]]. Source proposal: [[file:docs/design/2026-06-13-wrapup-inbox-transcript-routing-proposal.org]] (archsetup handoff 2026-06-13). Next: =spec-review= once the open decisions resolve.
+Spec: [[file:docs/design/wrapup-routing-spec.org]]. Source proposal: [[file:docs/design/2026-06-13-wrapup-inbox-transcript-routing-proposal.org]] (archsetup handoff 2026-06-13). Next: =spec-review=.
** TODO [#B] Helper-instance support — concurrent same-project Claude :feature:spec:
:PROPERTIES: