|
| 1 | +# 0026 — Request lifecycle honesty: withdrawal + staleness |
| 2 | + |
| 3 | +## Goal |
| 4 | +A pending decision never lies about its relevance (owner-observed |
| 5 | +2026-08-11: a 4-hour-old test write sat in Review looking as urgent as |
| 6 | +a fresh ask — "feels like I missed something / it's not working"). |
| 7 | +An actionable item must carry its freshness, and the requester must be |
| 8 | +able to take back a request that stopped mattering. |
| 9 | + |
| 10 | +## Plan |
| 11 | +1. [ ] **`cancel_write` MCP tool** (the missing fourth verb — |
| 12 | + park/poll/resolve/WITHDRAW; `tasks/cancel` in the MCP Tasks spec is |
| 13 | + the direct precedent ADR-0032 already mirrors): the requesting |
| 14 | + client cancels its own still-pending write by id; cancelled ≠ |
| 15 | + denied (a distinct outcome, recorded in Activity like |
| 16 | + denied/expired — never traceless). Ungated (cancelling your own |
| 17 | + request needs no human approval; it only ever REDUCES pending |
| 18 | + work). At-most-once semantics shared with resolve. |
| 19 | +2. [ ] **Staleness presentation** in Review + banner + floating |
| 20 | + prompt: age-tiered treatment (fresh <15m renders as-is; older gets |
| 21 | + a visible age emphasis + "expires in Nh" from the 24h clock) — the |
| 22 | + §1 thesis applied to time-honesty of asks. No auto-dismiss of |
| 23 | + actionable items (the VS Code severity rule holds; expiry is the |
| 24 | + only terminal timer). |
| 25 | +3. [ ] **Requester liveness hint** (design question, research first): |
| 26 | + should a pending write surface "requester last polled Nm ago" — |
| 27 | + check_write_status calls are the natural heartbeat — so an |
| 28 | + abandoned request is visibly abandoned? Cheap to record; decide |
| 29 | + presentation against the no-noise bar. |
| 30 | +4. [ ] Session-side hygiene rule for THIS workflow (rides the memory, |
| 31 | + not Mill): a test write parked for demonstration gets cancelled by |
| 32 | + its requester when the demonstration ends. |
| 33 | +5. [ ] **Badge staleness on write resolution (BUG, diagnosed live |
| 34 | + 2026-08-11)**: ResolveMCPWrite (and the expiry sweep) never emits on |
| 35 | + the pending-changed channel, so the sidebar badge held a phantom 1 |
| 36 | + against an empty queue — resolution paths must ping the same ONE |
| 37 | + signal parks do (goal 0005's model, missing emit). |
| 38 | +6. [ ] **Resolved writes appear in Review's Recently-resolved** — today |
| 39 | + a denied/approved/cancelled write vanishes from Review entirely |
| 40 | + (only trace: session-only Activity, gone on restart). The queue's |
| 41 | + own history must include write resolutions, durably (the persisted |
| 42 | + 24h outcome records already exist — surface them). |
| 43 | +7. [ ] **Activity MCP-write rows get actions**: expandable detail + |
| 44 | + jump-to-the-target-workflow (runs already drill down; writes are |
| 45 | + action-dead — owner: "so what I can do and nothing I can do"). |
| 46 | +8. [ ] **Stuck-ENQUEUED runs surface honestly** (a run enqueued-forever |
| 47 | + reads as live; found: a zombie ENQUEUED run from a morning error) — |
| 48 | + age-visible like item 2, plus a Stop affordance where cancel is |
| 49 | + legal. |
| 50 | + |
| 51 | +## Acceptance |
| 52 | +A parked-then-obsolete request can be withdrawn by its requester and |
| 53 | +shows as cancelled in Activity; a lingering pending item visibly |
| 54 | +communicates its age and time-to-expiry; the owner never again reads |
| 55 | +staleness as breakage. |
0 commit comments