mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(lifecycle): revision findings ledger — structured failure feedback, persisted and delivered down the chain (#486)
* feat(lifecycle): revision findings ledger — structured QA/PR/PM/CEO failure feedback, persisted and delivered down the chain Every bounce used to survive only as flattened prose: rounds overwrote each other in notes_structured, request_changes persisted nothing, two raw dev_notes appends were silently destroyed by the next handoff note, and the dev prompt pointed at fields (qa_notes via evidence(), pm_notes) the API never delivered. Agents re-interpreted and re-discovered every failure before they could start fixing it. - task_review_findings (migration 071, append-only): file/line/severity/ criterion(AC-id-validated)/expected/actual/fix/evidence per finding, with origin (qa|pr_gate|pm|ceo), round, and an open->addressed->verified lifecycle (waived reserved); new tasks.pm_notes + PmReviewContent give request_changes a structured home - producers: fail_review/pr_fail/request_changes take findings=[...] (prose issues shimmed+merged for one release, deprecation-logged); ceo_reject validates its reason (no 500), lands an origin=ceo finding, and bumps round+audit on branchless coordination roots; guardrails at the verb chokepoint (nudge >5, hard reject >10, field caps, traversal-safe file); the dev_notes data-loss appends are removed; new task.request_changes + task.ceo_reject audit events close rework attribution - delivery: qa_notes/pr_reviewer_notes/pm_notes carry the deterministic [F-id8] rendering; claim briefings, evidence(), the REVISION_REQUIRED spawn prompt, PM triage bounced-blocks, and A2A bodies deliver open findings; round-N+1 QA and gate reviewers get the full prior ledger; panel Findings tab + bounced-xN chip; metrics pm_rejects/ceo_rejects + findings counts; vault task notes render a Findings section (fail-open) - resolution closes for every origin: i_am_done and submit_up/submit_root take resolved_findings gated by FINDINGS_ADDRESSED (owner-gated so a stale non-owner PM can never mutate the ledger); pass_review/pr_pass/ complete verify-stamp same-transaction; ceo_approve stamps best-effort - 24 real-DB integration tests drive the full loop through the real choreographer; full suite 12856 green * docs: revision findings ledger sweep — CLAUDE.md, map, RAG corpus - CLAUDE.md: new ledger section + corrected request_changes row - docs/map/review-findings.md (new subsystem map) + surgical updates to task-service/pr-gate-review/metrics-observability/vault/panel maps - docs/rag: producers' findings contract across qa/pr-reviewer/developer/ cell-pm/main-pm/ceo role docs (the PM docs were missing request_changes entirely), verb references, and a new architecture/review-findings.md disambiguating ledger findings from convention findings * test(e2e): resubmit resolves the pr_fail finding per the ledger contract The scripted pr_fail revision loop resubmitted submit_up without resolved_findings — correctly rejected now that FINDINGS_ADDRESSED gates the PM resubmit verbs (green locally, red only in CI since the e2e suite skips without ROBOCO_E2E_SMOKE=1). The scripted PM now reads the open ledger row pr_fail persisted (new open_finding_ids arc helper) and resolves it on resubmit, asserting the open set drains — exercising the coordinator half of the new contract end to end. --------- Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
@@ -57,7 +57,7 @@ This is the single most common mental-model mistake at your seat. Get it right:
|
||||
| `triage_all()` | List blockers and reviews across all cells. | None. |
|
||||
| `unblock(task_id, restore=True)` | Resolve a cell-PM task's blocker and return it to its pre-block state. | None. |
|
||||
| `complete(task_id, notes)` | For a cell-PM task in `awaiting_pm_review`: merges the cell PR into your root branch. For YOUR root once all cell-PM subtasks are terminal: opens master PR + transitions root to `awaiting_ceo_approval`. | All descendants terminal; journal `decision` recorded. |
|
||||
| `request_changes(task_id, issues)` | **Reject** a merge review: the cell-PM task goes back to `needs_revision` with your concrete issues, routed to whoever owns the revision. Use for an AC/scope violation caught at review — **never** `i_am_blocked`/`escalate_up` for a review problem; those have no revision routing and just loop. | Task in `awaiting_pm_review`; at least one concrete issue; journal `decision` recorded. |
|
||||
| `request_changes(task_id, findings)` | **Reject** a merge review: the cell-PM task goes back to `needs_revision` with structured findings — each `{file?, line?, severity: blocker\|major\|minor\|nit, criterion?, expected, actual, fix?, evidence?}` — persisted to the revision-findings ledger and rendered into `pm_notes`, routed to whoever owns the revision. Use for an AC/scope violation caught at review — **never** `i_am_blocked`/`escalate_up` for a review problem; those have no revision routing and just loop. `issues=['...']` still works this release but is deprecated. | Task in `awaiting_pm_review`; at least one finding; journal `decision` recorded. |
|
||||
| `escalate_up(task_id, reason)` | Escalate a stuck task up your chain to CEO. | Task is yours or assigned to a cell under your scope. |
|
||||
| `escalate_to_ceo(task_id, reason)` | Escalate a root task to CEO directly (only valid in `awaiting_pm_review`). | Root task in `awaiting_pm_review`; `pr_number` set. |
|
||||
| `unclaim(task_id)` | Release this claim back to pending. Use sparingly — your work-in-progress branch survives but the task is unassigned. | Task assigned to you and in claimed/in_progress. |
|
||||
@@ -94,7 +94,7 @@ This is the single most common mental-model mistake at your seat. Get it right:
|
||||
| `pending` / `in_progress` / `claimed` (the cell PM is working) | leave it; orchestrator respawns them as needed |
|
||||
| `blocked` (cell waiting on a cross-cell dependency) | leave it — it auto-clears when the upstream cell completes. Do NOT `unblock` (rejected) or escalate. `i_am_idle()`. |
|
||||
| `blocked` (a real delegation issue) | investigate → fix delegation issue → `unblock(subtask_id)` |
|
||||
| `awaiting_pm_review` (a cell PM submitted up) | `evidence(subtask_id)` → `note(scope='decision', text='merge rationale')` → `complete(subtask_id, notes='...')` (auto-merges cell PR into your root branch). **If the review FAILS** (AC/scope violation): `note(scope='decision', ...)` → `request_changes(subtask_id, issues=[...])` — do NOT block or escalate a review problem. |
|
||||
| `awaiting_pm_review` (a cell PM submitted up) | `evidence(subtask_id)` → `note(scope='decision', text='merge rationale')` → `complete(subtask_id, notes='...')` (auto-merges cell PR into your root branch). **If the review FAILS** (AC/scope violation): `note(scope='decision', ...)` → `request_changes(subtask_id, findings=[{file, line, severity, expected, actual, fix?}, ...])` — do NOT block or escalate a review problem. A bounced root's `evidence()`/briefing shows the accumulated ledger — read it before re-reviewing. |
|
||||
| `needs_revision` | cell PM re-claims; you stay out |
|
||||
|
||||
## Workflow
|
||||
|
||||
Reference in New Issue
Block a user