Skip to content

fix(reconciler): branch-fallback Phase 2 so features without prNumber reconcile#3642

Merged
mabry1985 merged 1 commit into
mainfrom
fix/reconciler-branch-fallback
May 23, 2026
Merged

fix(reconciler): branch-fallback Phase 2 so features without prNumber reconcile#3642
mabry1985 merged 1 commit into
mainfrom
fix/reconciler-branch-fallback

Conversation

@mabry1985
Copy link
Copy Markdown
Contributor

Closes #3613.

Summary

Every PR in this session's dogfood loop (#3636, #3637, #3638, #3639) sat in `[review]` until manual re-dispatch — even though the 60-second `PostMergeReconciler` poll was firing on schedule (44+ executions, 2ms each, no failures).

Root cause: three of the original stuck features (#3593, #3611, #3612) had `prNumber: null` and `prUrl: null` on disk, because the PR-creation write path (PostAgentHook recovery or normal REVIEW phase) didn't always persist the metadata back to `feature.json`. The reconciler's filter required both fields, so those features were silently skipped every tick.

Fix

`PostMergeReconcilerCheck` now runs in two phases:

Phase 1 (existing): features with `prNumber` + `prUrl` → `gh pr view` direct lookup. Transitions to `done` if merged.

Phase 2 (new): features with `branchName` but missing `prNumber` or `prUrl` → `gh pr list --head --state merged --limit 1`. When a merged PR is found, writes `prNumber`/`prUrl`/`prMergedAt` back to the feature so subsequent ticks short-circuit through Phase 1.

This is a safety-net fix — it doesn't remove the underlying need to plug the write-path gap that drops PR metadata, but it eliminates the permanent-stuck case where a feature has no way to be picked up by the reconciler.

Verification

  • `npm run test:server -- tests/unit/services/post-merge-reconciler-check.test.ts` — 15/15 pass.
  • `npm run test:server` — 3386 passed, 23 skipped (no regressions; +1 net from the new Phase 2 tests).
  • `npm run typecheck` — server clean.
  • Prettier — clean on touched files.

Test plan

  • After this lands and the server restarts, any feature already stuck in `[review]` with a `branchName` (even without `prNumber`) should transition to `done` on the next poll tick (~60s).
  • Dispatch a new feature through auto-mode; once its PR is merged via GitHub auto-merge, confirm the feature flips to `done` autonomously without manual re-dispatch.
  • Inspect `feature.json` after the transition: it should now have `prNumber`, `prUrl`, `prMergedAt` populated (Phase 2 writes these back).

🤖 Generated with Claude Code

… still reconcile

Closes #3613.

Every PR in this session's dogfood loop (#3636, #3637, #3638, #3639)
sat in [review] until manual re-dispatch — even though the 60-second
PostMergeReconciler poll was firing on schedule (44+ executions, 2ms
each, no failures). Root cause: three of the original stuck features
(#3593, #3611, #3612) had `prNumber: null` and `prUrl: null` on disk,
because the PR-creation write path (PostAgentHook recovery or normal
REVIEW) didn't always persist the metadata back to feature.json. The
reconciler's filter required both fields, so those features were
silently skipped every tick.

Fix: PostMergeReconcilerCheck now runs in two phases.

Phase 1 (existing): features with `prNumber` + `prUrl` → `gh pr view`
direct lookup, transitions to done if merged.

Phase 2 (new): features with `branchName` but missing `prNumber` or
`prUrl` → `gh pr list --head <branch> --state merged --limit 1`.
When a merged PR is found, writes `prNumber`/`prUrl`/`prMergedAt` back
to the feature so subsequent ticks short-circuit through Phase 1.

This is a safety-net fix — it doesn't remove the underlying need to
plug the write-path gap that drops PR metadata, but it eliminates the
permanent-stuck case where a feature has no way to be picked up by
the reconciler.

Tests: 15/15 passing. The two original "skips features without
prNumber/prUrl" tests are now "falls back to branchName lookup"
covering the new path. The "zero counts" test now requires *also*
missing branchName to assert the skip path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@mabry1985 mabry1985 enabled auto-merge (squash) May 23, 2026 07:24
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

Warning

Review limit reached

@mabry1985, we couldn't start this review because you've used your available PR reviews for now.

Your plan currently allows 2 reviews/hour. Refill in 21 minutes and 36 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 33da3c8a-ecf3-4259-bf74-9f0110f59818

📥 Commits

Reviewing files that changed from the base of the PR and between 356dc9d and a9159da.

📒 Files selected for processing (2)
  • apps/server/src/services/maintenance/checks/post-merge-reconciler-check.ts
  • apps/server/tests/unit/services/post-merge-reconciler-check.test.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/reconciler-branch-fallback

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

Code Review — ? finding(s)

Async review running parallel to CodeRabbit. Findings are advisory; not all are merge blockers.

protoLabs Code Review Report

  • Generated: 2026-05-23T07:25:21Z
  • Git head: 1cfc251857f13b829290c46cee3d6f56c695b2f9
  • Features mapped: 3
  • Findings: 0

No findings recorded.

@mabry1985 mabry1985 merged commit 694ea84 into main May 23, 2026
7 checks passed
@mabry1985 mabry1985 deleted the fix/reconciler-branch-fallback branch May 23, 2026 07:28
mabry1985 added a commit that referenced this pull request May 24, 2026
)

The Post-Merge reconciler check called `gh pr view --json state,merged`
but `merged` is not a valid field on `gh pr view` (the available
boolean-ish field is `mergedAt` — null when unmerged, ISO string when
merged). Every call exited non-zero with "Unknown JSON field: merged",
the catch handler logged at debug level (effectively /dev/null), and
the feature was silently skipped every tick.

Observed in this session: the 60-second reconciler timer fired 1168
times with 0 failures (because the catch swallows them) and 0
reconciliations across two PRs that had been merged for hours. The
WebhookHealthCheck flagged "PR has been in review for 1023 min with
no CI events" but nothing tied it back to the reconciler being broken.

Fix:
- gh args: `--json state,mergedAt` instead of `state,merged`
- isMerged predicate: `state === 'MERGED' || mergedAt != null`
- catch handler: bumped from `debug` to `warn` so this class of bug
  surfaces immediately if it happens again
- updated tests + interface type

The Phase 2 (branch-fallback) path I shipped in #3642 was correct on
its own merits — but Phase 1 silently failing is what made Phase 2
appear necessary in the first place. Both paths now work as intended.

Co-authored-by: Automaker <automaker@localhost>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(reconciliation): merged-PR features stay in [review] indefinitely on the board

1 participant