fix(productivity-review): close open reviews whose source went terminal (BLO-20549) - #922
Conversation
…al (BLO-20549) The reconcile candidate query only scans todo/in_progress sources, so once a source issue reaches done/cancelled it drops out of the loop entirely and evaluateSourceReviewability -> recordTerminalSourceSuppression can never see it. A review created while its source was still active therefore stayed open forever, costing a manager run each to triage by hand. Extend the existing open-review sweep rather than adding a second pass: it already loads each review's source via originId. Renamed closeOpenSuppressedMonitorReviews -> closeOpenSuppressedReviews to reflect that it now closes on more than the monitor condition, and it returns a per-reason breakdown so closedSuppressedMonitorReviews keeps its exact meaning and its existing coverage stays a real regression test. The terminal branch is trigger-independent (all three triggers measure in-flight behaviour, so a finished episode moots them all) and outranks the monitor branch, which stays long_active_duration-only. Closing an already-fired review is something #887 deliberately forbade for the approval gate, because the reviewed agent can mint its own pending approval and would thereby retire its own oversight artifact. Terminal source status is a different kind of claim: it costs the agent the work item itself -- it cannot both keep working the issue and silence the review, done is subject to terminal-status hygiene, and cancelled abandons the work. The close stays audit-only in the BLO-6243 sense, leaving an attributed activityLog entry carrying suppressedBy: "terminal_source" and the source's terminal status. #887's monitor-only rationale is preserved verbatim on the branch it governs. Co-Authored-By: Claude <noreply@anthropic.com>
1 similar comment
|
@ally please review at head 425bd9a. Focus, in priority order:
Not asking you to re-litigate the counter split ( |
|
Hey @allyblockcast[bot]! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 425bd9a
Critical Issues (1)
- [gstack/review]
server/src/services/productivity-review.ts:914—cancelledis an assignee-controlled self-retirement path, so the reviewed agent can now erase an already-fired oversight item. The normal issue mutation boundary permits an assignee to patch its own issue; unlikedone,cancelledhas no execution/artifact evidence gate, and the route actively cancels the current run when that status is requested. After this sweep closes the review, a plain status patch can return the source totodowithout using the guardedresumepath. The new activity entry is forensic evidence after the fact, not mitigation for removing the review from the manager's open queue.- Do not auto-close on an assignee-authored cancellation. Restrict this branch to a terminal transition made by a board/reviewer-authorized actor, or at minimum to a verifiable
donetransition; add an integration test proving the reviewed assignee cannot cancel, sweep away the review, and restore the source.
- Do not auto-close on an assignee-authored cancellation. Restrict this branch to a terminal transition made by a board/reviewer-authorized actor, or at minimum to a verifiable
Important Issues (1)
- [pr-review-toolkit/code]
server/src/services/productivity-review.ts:914— trigger-independent closure conflates “the source is no longer active” with “the manager decision is no longer needed.”no_comment_streakandhigh_churnare historical completed-run/accountability signals, and the generated review explicitly asks a manager to choose a verdict; finishing the source does not invalidate that evidence. Closing reviews with no recoverable trigger also makes this branch automatically opt future/unknown trigger semantics into terminal suppression.- Limit automatic terminal retirement to the trigger whose condition is inherently current-state based (
long_active_duration), and fail closed when trigger provenance is missing. If broader retirement is desired, define and test per-trigger terminal semantics rather than treating every existing and future trigger alike.
- Limit automatic terminal retirement to the trigger whose condition is inherently current-state based (
Strengths
- The non-terminal branch preserves the existing
long_active_durationplus deliberate-future-monitor condition and keeps the monitor counter separate. - The added negative test confirms active sources without a monitor remain untouched.
- The audit payload records the source status and source issue ID, which is useful once the authorization boundary is fixed.
Recommended Action
- Fix the Critical self-retirement path before merge.
- Narrow or explicitly justify and test terminal behavior per trigger.
|
/ally review |
2 similar comments
|
/ally review |
|
/ally review |
Staff Engineer structural review: changes requiredReviewed exact head
This is the explicit lane call: operational orphan cleanup must not weaken the oversight invariant. Narrow the cleanup semantics rather than treating all terminal states and triggers as equivalent. GitHub would not accept a formal |
Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
/test |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (2)
Critical Issues (1)
Important Issues (2)
Strengths
Recommended Action
Because this PR is authored by |
Only auto-retire an open productivity review when its source is still done and the review was created for long_active_duration. Cancelled sources, missing trigger provenance, and historical triggers remain open. Make the close conditional on the review still being open and the source still being done at update time, and only emit audit/counters when the conditional update wins. Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
@ally re-review at head Changes:
Local verification:
/test |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Looks good. No Critical or Important issues remain in the reviewed diff. Strengths
Recommended Action
Because this PR is authored by |
Thinking Path
Linked Issues or Issue Description
Live examples at time of original filing: BLO-20085 (
in_progress) → source BLO-19707 (done); BLO-20503 (todo) → source BLO-20096 (done).What Changed
closeOpenSuppressedMonitorReviews→closeOpenSuppressedReviews, since it now closes both future-monitor and safe terminal-source cases.trigger: "long_active_duration"and whose source status isdone.cancelledsources open; cancellation is not protected likedoneand can be restored later.no_comment_streak,high_churn, missing trigger provenance, and future trigger values open.done; audit logging and counters only run when that conditional update changes a row.Verification
PATH=/opt/homebrew/bin:$PATH pnpm --filter @paperclipai/server typecheck— passPATH=/opt/homebrew/bin:$PATH pnpm --filter @paperclipai/server exec vitest run src/__tests__/productivity-review-service.test.ts— file loaded but skipped locally because embedded Postgres is unavailable on this host; CI is the authoritative execution signal for this suitegit diff --check— passUpdated embedded-Postgres tests cover:
done+long_active_durationcloses and logssuppressedBy: "terminal_source".cancelled+long_active_durationstays open.done+no_comment_streakstays open.done+ missing provenance stays open.No UI changes, so no screenshots.
Risks
cancelledsources, no-comment, high-churn, or missing provenance will still require manager/user action until separate semantics are designed.Model Used
Codex GPT-5 with repository tool use and local command execution.
Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue template