OPER-207
Persist NEEDS_RESCOPE reason to ticket body + sticky label
Suggested
Justin Cooke
Body
--- feature_id: FEAT-studio-planning-validation --- ## Context Planner rescope this session: OPER-184 through OPER-194 all NEEDS_RESCOPE with `labels: []` and no in-body trailer explaining why. The rescope reason (which of the 9 `PLANNING_REJECTION_REASONS` fired) is written to `PlanningValidation.verdict` + `.reasons` but there is no user-visible surface on the ticket itself. Determining the reason required reading `apps/web/src/lib/planning-validator.ts` source and correlating field state. This is a discovery-cost problem: every rescope this week has cost the filer 5-10 minutes to figure out which reason fired, when the system already knows. Contrast with admission failures — those DO get a body trailer (`<!-- admission-rejected -->` with the reason). Rescope failures should get the same treatment. ## What Extend the planner rescope path (in `apps/web/src/lib/plan-validation-runner.ts` or the rescope call site) to: 1. On NEEDS_RESCOPE transition, append to Task.body: ``` --- <!-- planner-rescope: <reason_code> --> **Planner rescope (<reason_code>):** <ADMISSION_ISSUE_MESSAGES[reason_code]> ``` 2. Also add a sticky label `rescope:<reason_code>` (e.g., `rescope:missing_verify_cmd`) so the rescope queue is filterable by reason kind. 3. On successful re-admission (see OPER-193), strip both the trailer and the sticky label. 4. Idempotent: if the same reason fires again, no duplicate trailer or label. 5. If MULTIPLE reasons fire on the same rescope: append each as a bullet in a single trailer block; multiple sticky labels. Downstream effect: the rescope queue UI at `/qa/live-fixes` becomes actionable — the filer can see WHY without opening the audit log. ## Acceptance Criteria - [ ] Rescope path appends `<!-- planner-rescope: <reason> -->` trailer to Task.body - [ ] Rescope path adds sticky label `rescope:<reason_code>` - [ ] Successful re-admission strips trailer and label (interacts cleanly with OPER-193 auto-reheal) - [ ] Multiple reasons on the same rescope: bulleted list in one trailer, multiple labels - [ ] Idempotent: repeated rescopes with same reason do not duplicate trailer - [ ] `/qa/live-fixes` (OPER-178) can filter by rescope reason via label - [ ] Unit tests cover: single reason, multiple reasons, idempotent repeat, re-admission cleanup, label filter query ## Blocked-by None. Complements OPER-193 (admission auto-reheal) — the two together close the ticket-flow-observability loop for the filer. ## Size / Band S / assurance (append-to-body + label add on rescope; matches existing admission-rejected pattern). ## Discovered by Session 2026.09.13 status check found ten NEEDS_RESCOPE tickets with no visible reason. Diagnostic cost: 15 minutes reading source to determine `missing_verify_cmd` was the root cause. Would have been zero if the trailer existed.
Attachments
Loading attachments…
Comments
Loading comments…