Problem
The review_state_label disposition ternary in planAgentMaintenanceActions
(src/settings/agent-actions.ts) picks exactly one of four mutually-exclusive
labels each pass — ready-to-merge, manual-review, migration-collision,
changes-requested — based on the PR's current verdict/gate/hold state. But it
only ever ADDS the chosen label; it never removes a sibling left over from a
prior pass.
Concretely: a PR held with manual-review (or changes-requested) during an
earlier red-CI/guardrail/blocker pass keeps that label forever, even once the
PR becomes genuinely healthy and ready-to-merge gets added alongside it.
This has a second-order effect: the AI-review freeze
(isFrozenForManualReview in src/queue/processors.ts) checks whether the
live PR carries the configured manual-review label to decide whether to reuse
the last-published AI verdict instead of running a fresh one. A manual-review
label that never clears means that freeze can stay engaged indefinitely for a
PR that has long since been fixed, producing a review comment whose
deterministic parts (checks, gate result, linked-issue status) are fresh while
the AI-authored "Review summary"/"Blockers" prose is stale.
Fix
Add a cleanup pass, in the same review_state_label-gated section, that
removes any of the three OTHER disposition labels still live on the PR once
the ternary resolves to a different one — mirroring the existing
clearLinkedIssueFlag pattern already used for the pending-closure label.
The owner/automation "not reviewGood" fallback hold's own manual-review
reason is excluded from this cleanup when it's still independently warranted
the same pass, since it can re-add the label later in that same call.
Problem
The
review_state_labeldisposition ternary inplanAgentMaintenanceActions(
src/settings/agent-actions.ts) picks exactly one of four mutually-exclusivelabels each pass —
ready-to-merge,manual-review,migration-collision,changes-requested— based on the PR's current verdict/gate/hold state. But itonly ever ADDS the chosen label; it never removes a sibling left over from a
prior pass.
Concretely: a PR held with
manual-review(orchanges-requested) during anearlier red-CI/guardrail/blocker pass keeps that label forever, even once the
PR becomes genuinely healthy and
ready-to-mergegets added alongside it.This has a second-order effect: the AI-review freeze
(
isFrozenForManualReviewinsrc/queue/processors.ts) checks whether thelive PR carries the configured manual-review label to decide whether to reuse
the last-published AI verdict instead of running a fresh one. A manual-review
label that never clears means that freeze can stay engaged indefinitely for a
PR that has long since been fixed, producing a review comment whose
deterministic parts (checks, gate result, linked-issue status) are fresh while
the AI-authored "Review summary"/"Blockers" prose is stale.
Fix
Add a cleanup pass, in the same
review_state_label-gated section, thatremoves any of the three OTHER disposition labels still live on the PR once
the ternary resolves to a different one — mirroring the existing
clearLinkedIssueFlagpattern already used for the pending-closure label.The owner/automation "not reviewGood" fallback hold's own manual-review
reason is excluded from this cleanup when it's still independently warranted
the same pass, since it can re-add the label later in that same call.