Conversation
|
Warning Review limit reached
Next review available in: 3 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThe PR makes stale merger-status reconciliation aware of renamed terminal lanes.
Confidence Score: 5/5The PR appears safe to merge, with the resolved terminal-column union preserving legacy behavior while covering renamed lanes. The resolver always retains the prior
|
| Filename | Overview |
|---|---|
| packages/engine/src/self-healing.ts | Replaces literal terminal-column queries with a role-resolved union while retaining legacy columns and deduplicating candidate tasks. |
| packages/engine/src/tests/self-healing-query-filter-blindness.test.ts | Adds regression coverage for stale merger statuses in renamed terminal lanes and verifies settled cards remain untouched. |
| scripts/lib/lifecycle-column-census-baseline.json | Updates the expected hardcoded lifecycle-query count to reflect removal of the two literal reads. |
| .changeset/self-healing-stale-merger-status-query.md | Documents the renamed-column merger-queue fix as a patch release. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Roles[TERMINAL_ROLES] --> Resolver[Resolve project columns]
Resolver --> Columns[Deduplicated terminal columns]
Columns --> Queries[List tasks in each column]
Queries --> Tasks[Deduplicate tasks by ID]
Tasks --> Filter{Status is merging or merging-pr?}
Filter -->|Yes| Clear[Clear stale status]
Filter -->|No| Preserve[Leave task unchanged]
Reviews (1): Last reviewed commit: "fix(engine): a finished task blocked the..." | Re-trigger Greptile
…eeps 33 and 34) The two WORKSPACE sweeps, converted together because they are one domain and one file region. reconcileWorkspacePartialLands re-enqueues a workspace task whose per-repo lands are partial or zero. Literal read -> on a renamed board it never ran, so a task sat with SOME repos merged and some not, and nothing to finish the job. That is the worst resting state in this series: not a stalled task but an inconsistent one. reconcileOrphanedWorkspaceWorktrees removes the per-repo worktrees a finished workspace task left behind. Literal read -> disk held by tasks that finished, growing quietly with no signal. The cleanup resolves `complete` ONLY, not the terminal union: its own comment calls done tasks "the canonical safe to clean set" because their lands are finalized, and an archived row is a different claim. Same call as #2934, opposite of #2899, and each time the code already said which it meant. Reverts measured, each alone: - partial-land read + verdict restored -> that case fails, the card is never listed - orphaned-worktree read restored -> that case fails, the done card is never listed Fusion-Task-Id: KB-SELF-HEALING-QUERIES
…ard (sixteenth sweep) reconcileStaleMergerStatus clears a `merging`/`merging-pr` status left on a card that already reached a terminal lane. Two literal reads meant that on a renamed board it was never cleared — and unlike the rest of this series the damage is not confined to the stranded card: the stale status holds the MERGER QUEUE for every task behind it. ONE union read over TERMINAL_ROLES, not two buckets. Nothing here treats complete and archived differently — the only filter is on `status` — so splitting them would encode a distinction the code does not make. Deduped, since the two roles can share a column (the P1 on #2879). No per-card lane verdict: this sweep has no column comparison to convert, so adding one would be inventing a gate rather than resolving an existing one. Revert measured: with the literal reads restored the new case fails — the card is never listed, so its stale status is never cleared. Fusion-Task-Id: KB-SELF-HEALING-QUERIES
…eeps 33 and 34) The two WORKSPACE sweeps, converted together because they are one domain and one file region. reconcileWorkspacePartialLands re-enqueues a workspace task whose per-repo lands are partial or zero. Literal read -> on a renamed board it never ran, so a task sat with SOME repos merged and some not, and nothing to finish the job. That is the worst resting state in this series: not a stalled task but an inconsistent one. reconcileOrphanedWorkspaceWorktrees removes the per-repo worktrees a finished workspace task left behind. Literal read -> disk held by tasks that finished, growing quietly with no signal. The cleanup resolves `complete` ONLY, not the terminal union: its own comment calls done tasks "the canonical safe to clean set" because their lands are finalized, and an archived row is a different claim. Same call as #2934, opposite of #2899, and each time the code already said which it meant. Reverts measured, each alone: - partial-land read + verdict restored -> that case fails, the card is never listed - orphaned-worktree read restored -> that case fails, the done card is never listed Fusion-Task-Id: KB-SELF-HEALING-QUERIES
|
Superseded by #2944 — folded into The conversion and its revert measurements are carried over in the commit message. Nothing here is dropped. |
…olds 23 PRs) (#2944) **Consolidation of 23 open PRs into one.** Every one shared a single root cause and mostly touched a single file; 23 CI runs for that was indefensible. Folds and supersedes: #2867 #2869 #2876 #2879 #2883 #2891 #2899 #2901 #2902 #2905 #2906 #2914 #2916 #2918 #2919 #2920 #2922 #2927 #2929 #2932 #2934 #2937 #2939. (#2865, #2882, #2897, #2909, #2912 already merged and are not re-folded.) ## The root cause A self-healing sweep selects its work with `listTasks({ column: "in-review" })`. On a board whose lanes are renamed that returns **nothing**, so the sweep never runs — no error, no log line, no failed task. Several sweeps had already had their *predicates* converted to resolved lanes, which dropped a census count and changed nothing, because the query above the loop had already returned an empty list. **26 sweeps converted.** Each one: read the project's columns for the role, then decide each card against **its own** workflow, with the legacy ids unioned so a board mid-rename is never skipped. ## What each sweep stops silently failing to do | | | | --- | --- | | stale merger status | one finished card held the **merge queue** for everything behind it | | stale `blockedBy` / completed-task release | dependents stayed blocked on work that had already finished — the board stops moving | | workspace partial lands | a task left with **some repos merged and some not** | | mid-merge retry stamp | the card stalled *and* the operator's manual Retry was gated by the same stamp | | in-progress limbo / no-progress failures | dead cards held a work slot forever | | partial-progress retry | real work parked failed with its **retry budget unspent** | | orphaned-execution signal | visibility only — the one signal pointing at an orphan went silent | | zero-commit audit | went **half-blind**: the error arm kept working, the lane arm did not | Plus: ghost review cards, transient merge failures, misclassified failures, branch misbinding, missing-worktree failures, merged-but-unfinished finalization, done-metadata repair, self-owned branch conflicts, orphan-only scope violations, post-done wedges, idle assigned agents, PR-conflict worktree ownership, and orphaned workspace worktrees. ## Two defects the conversion itself introduced, both caught and fixed 1. **Missed pairs.** Widening a read without converting the guards beneath it is *worse than not converting*: the sweep starts admitting renamed-board cards and then mis-decides every one. Review caught a second guard on a re-read row; the audit that triggered found **five more**, one of which gates the `reviewProof` triple-proof — a renamed review card would have been moved backward with the safety check silently skipped. Column guards 86 → 81. 2. **Duplicate processing.** The literal reads were disjoint by construction; resolved reads are not, so a column carrying two role flags put one card in two buckets — duplicate moves, duplicate audit rows, inflated counts. Both now have ratchets. `self-healing-converted-sweeps-have-no-literal-lane-guards.test.ts` **derives** its sweep list (a sweep counts as converted when its body calls `resolveProjectColumnsForRoles`), so it cannot go stale, and it carries two positive controls because a broken regex finds no offenders and a broken derivation iterates nothing — an empty loop registers no tests and reads green. ## Deliberately unchanged - 22 `moveTask` destinations carrying `recoveryRehome: true` — `moves.ts` exempts these so a card stranded in an undeclared column stays rescuable. - One literal in `clearStaleBlockedBy`'s log-dedup closure (allowed by name in the ratchet, with the reason). - `surfaceInReviewStalls` — hot list-read path, needs a batched prefetch; that is a performance design decision, not a conversion. - `scheduler.ts` and `replan-target.ts` — built on `resolveTaskWorkflowIrSync`, which returns the default IR for every task in production. Converting there produces inert code. ## The fold itself is worth one note All 23 branches appended to the **same test file at the same anchor**, so every automatic strategy — git 3-way, `merge-file --union`, and three hand-written resolvers — interleaved them mid-block. Two attempts committed conflict markers before I caught it. The file is therefore **reconstructed**: head authored once, body assembled as the union of each branch's own intact top-level segments keyed by test title, with the nested `already-merged hard blocker` describe appended whole (flattening it orphaned its helper). Verified by *parsing after every step* rather than trusting the merge — which is how each interleaving was caught. ## Verification `pnpm test:gate` 161 + 487 + 13 + 71. Scoped suites 592 passed (self-healing, the blindness suite at 68 cases, the ratchet, and the notification suite). `tsc` engine clean; `pnpm lint`, `check:changesets`, `lifecycle-column-census --strict` and `check-sql-column-literals` all clean, each run explicitly. Each folded conversion was individually revert-proven on its original branch — the read reverted alone, and the per-card verdict reverted alone — and those measurements are recorded in the commit messages carried into this branch. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
reconcileStaleMergerStatusclears amerging/merging-prstatus left on a card that already reached a terminal lane. Two literal reads meant that on a renamed board it was never cleared.Unlike every other sweep in this series, the damage is not confined to the stranded card: the stale status holds the merger queue for every task behind it. One finished card, and the board stops merging.
One union read, not two buckets
The sweeps before this one split their reads per role because the buckets were treated differently downstream. Here nothing distinguishes complete from archived — the only filter is on
status— so a single union overTERMINAL_ROLESis the honest shape. Splitting them would encode a distinction the code does not make.Deduped, since the two roles can share a column (the P1 reviewed on #2879).
No per-card verdict, deliberately
This sweep has no column comparison to convert. Adding one would be inventing a gate rather than resolving an existing one, which is out of scope for a conversion — the same reason the redundant guards in #2891 and #2897 were converted rather than deleted.
Revert result
A non-vacuous companion (same terminal lane, no stale status → untouched) rules out a sweep that clears whatever it finds.
Verification
pnpm test:gate161 + 487 + 13 + 71, plusself-healing.test.ts412;tscengine clean;pnpm lint,check:changesets, census--strictclean, each run explicitly.