Derive PR associations from the forge review cache#14709
Closed
estib-vega wants to merge 11 commits into
Closed
Conversation
Add `review_for_head_ref` and `reviews_by_head` in a new `association` module. Both match a branch's remote/pushed head short name against the cached `ForgeReview.source_branch`, deriving the PR association from the forge cache instead of stored branch metadata. Reads are cache-only (no network, safe inside a projection); a `None` result means the branch isn't published, not an error. When several cached reviews share a `source_branch`, prefer an open review over a merged/closed one, then a base-repo head over a fork. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switch the primary branch projection to resolve its PR number from the forge review cache instead of stored branch metadata. At the but-api boundary we already have the branch's resolved remote-tracking ref; take its short name (remote stripped) and look it up against the cached reviews via `review_for_head_ref`. `review_id` is no longer used and is always cleared. Stored `pr_number` metadata is still written by other paths but is now unused by this projection, keeping the migration incremental. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve each stack segment's `pr_or_mr` in `list_branches` from the forge review cache, matching the segment's remote-tracking short name against the cached reviews, instead of reading `review.pull_request` off segment metadata. The map is built once per listing pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `RefInfo::apply_forge_pr_associations`, a projection-time pass that
resolves each segment's PR association from a cache-derived map keyed by
the segment's remote/pushed short name, overwriting the stored
`review.pull_request`. A stale number is cleared when nothing matches,
and a match on an otherwise metadata-less segment synthesizes metadata
so single-branch (ad-hoc) mode surfaces the association too. `review_id`
is projection-unused and always cleared.
Wire it into the `head_info` command that backs the desktop's workspace
stack view, mirroring how gerrit enrichment is applied only on that read
path (not on mutation-response workspace state). The crate stays free of
DB/forge wiring: the caller builds the `{short name -> PR number}` map
from the forge review cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Lite app writes a mutation's returned `head_info` straight into its
head_info query cache instead of refetching, so mutation responses need
the same cache-derived PR associations the `head_info` read command
applies. Otherwise Lite would revert to stored-metadata PRs (and, once
the write side is removed, show none) after every mutation.
Thread a `{ pushed short name -> PR number }` map through the single
`WorkspaceState::from_workspace` choke point (and the rebase-based
constructors that funnel into it), applying `apply_forge_pr_associations`
there. The map is built once per endpoint via the shared
`forge_prs_by_head`, before any exclusive borrow of the context. Making
the parameter required means the compiler enforces enrichment at every
mutation site. The graph-workspace projection is left untouched (out of
scope).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Creating a PR returned the review but never cached it, so a cache-only projection would not show the new PR until the next full review-list sync. Insert it optimistically: `publish_review` now caches the created review (via the new `but_forge::cache_review`, a single upsert that never deletes other rows) right after the forge call, keyed by the forge's own `source_branch` — exactly what the projection resolver matches. To stop a background list sync from immediately deleting that fresh row (the forge's list endpoint is eventually consistent and may omit a brand-new PR for a few seconds), `reconcile_listed` now spares open reviews synced within a grace window: absent-open deletion is gated on `last_sync_at <= absent_open_cutoff`, and callers pass `now - 60s`. While here, clarify the reconcile code, which had grown into one dense method: split it into named steps (`delete_open_reviews_absent_from_list`, `prune_merged_before`) with docs explaining why each exception exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`publishReview` now invalidates Stacks/StackDetails so the head_info workspace view refetches and surfaces the optimistically-cached PR association right after creation, instead of relying on a metadata write. Drop the `updateBranchPrNumber` call from the review-creation flow: the association is derived from the forge review cache now, so there is no PR number to persist onto branch metadata. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate the remaining metadata readers off `review.pull_request` so the
stored field can be retired without regressing these surfaces.
- but-forge: add `pr_numbers_by_head`, the `{pushed short name -> PR
number}` map both projection boundaries need; reuse it in but-api.
- but (CLI): apply `apply_forge_pr_associations` in the crate's own
`head_info`, mirroring the desktop command, so `HeadInfoBranch` and any
`applied_stacks` consumer see cache-derived associations. The `status`
command's segments are `but_graph::StackSegment` (a different layer), so
migrate its `pr_number()` reads to the `review_map` it already builds
from the cache (keyed by branch name); the CI gate now keys on a cached
review existing. Remove the now-unused `SegmentWithId::pr_number()`.
- but-agentlog: enrich the observation's `head_info`, and resolve the
single-branch fallback via the cache (read-only db open, empty when
absent). Drop the now-unused `meta` param.
- but-transaction: its `WorkspaceState` is always discarded by the CLI, so
pass an empty map rather than couple this layer to forge/db.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With every reader deriving the PR association from the forge review cache, retire the code that wrote a PR number into branch metadata. Backend: - gitbutler-stack: delete `Stack::set_pr_number`. - gitbutler-branch-actions: delete `update_branch_pr_number`; drop the upstream-integration "dissociate closed reviews" write (staleness is now reflected by the cache). - but-api: delete the `update_branch_pr_number` command and stop writing `review.pull_request` when applying a review (the applied review is already cached). - but-server / gitbutler-tauri: drop the removed command's route and handler registration. - but (CLI): `publish_review` relies on the optimistic cache insert, so drop its `update_branch_pr_number` call. Desktop: - Delete `PrNumberSync` and the `updateBranchPrNumber` endpoint/accessor and its test mock. The `UpdateDependentBranchPrNumber` oplog kind is kept so existing oplog entries still deserialize. The legacy `set_branch` review persistence and rename carry-over are intentionally left for the schema/rename discussion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1c77b35 to
b983fb1
Compare
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Superseded
This aggregate draft has been replaced by the following reviewable draft stack.
The original branch remains available as a safety copy; review should continue on the stacked PRs above.