Conversation
1850701 to
6487c58
Compare
Astro-Han
left a comment
There was a problem hiding this comment.
The picker holds up end to end — I traced the value from the Astryx trigger to the git command and found no correctness bug. One behavior I'd like a decision on, plus a few smaller things.
Behavior worth confirming
The resolved default is now persisted, so it stops following the repo. resolveAdoptedBaseBranch returns the backend's resolved branch when nothing is pinned (session-review-base-branch-model.ts:85-97) and the panel writes it to storage (session-review-panel.tsx:143-153). So a Session that never opens the picker pins a branch on its first read and keeps it for the life of that Session, across restarts. Before this PR every read re-resolved, so the panel tracked origin/HEAD. The blast radius is narrow — BASE_BRANCH_PRIORITY ranks refs/remotes/origin/HEAD first (git-review-main.ts:403-410) and that ref survives a rename of the default branch — but in a repo with no origin/HEAD the pin freezes on refs/heads/main and will not follow a later rename to trunk. If the goal is only "the trigger must name a real branch", the resolved snapshot.baseBranch could be displayed without being persisted (persist only an explicit pick) and the dynamic default would survive. Either way, the Summary should say the implicit default gets stored, since that is a behavior change beyond "the choice persists".
Findings
- The
invalid_base_branchrecovery path has no test. The clear-the-pin-and-retry-once branch (session-review-panel.tsx:123-135) is the headline answer to a pinned branch disappearing, butsession-review-panel-recovery.test.tsonly drives thegit_failedcase, and the model test stops atresolveAdoptedBaseBranch. A case wherereview.readreturnsinvalid_base_branchonce and then succeeds would cover it: request sequence['refs/heads/gh-pages', undefined], pin cleared in storage, no error banner. invalid_base_branchdropsbrancheseven though it is in scope.branchesis captured atgit-review-main.ts:67, but the rejection at:71-73returns without it, while the contract documents it as "available even when computing the selected branch diff fails" (packages/core/src/git-review.ts:66-67) —unborn_repositoryandgit_failedboth include it. Spreading it here too would make the contract uniform and let the panel keep the picker if the retry ever failed.copy.invalidBaseBranchlooks unreachable now. The panel always clears the pin and retries with no selection, and the backend only rejects a non-nullbaseBranch, so I could not construct a path where the banner atsession-review-panel.tsx:233renders in any of the three locales. Keeping it as a guard is fine; worth a line in the PR so nobody hunts for it.- nit — the picker offers the current branch as a comparison base. Options include it (the updated
git-review-main.test.tsfixture hasfeature/reviewas bothcurrentBranchand an option). Picking it diffs againstmerge-base(base, HEAD), i.e. HEAD, so the panel silently becomes "uncommitted changes" while the header still readsfeature → feature.resolveBaseBranchdeliberately skips the current branch (git-review-main.ts:431); marking that optiondisabledwould close the gap. - nit —
visibleFileCountis not reset when the base changes (session-review-panel.tsx:91,216), so a "show 20 more" position from the previous comparison carries into the new one and the button can appear or vanish. Pre-existing for Session switches, newly reachable through the picker. - nit — the buffer-overflow change is missing from the Summary and CHANGELOG.
runDiffAllowTruncated(git-review-main.ts:220-245) changes what a huge branch diff produces, and the PR answers "Yes — described under Summary above" to the behavior question. Related: the sibling--name-statuscall at:175is not wrapped, and a mid-file cut can leave a listed file with an empty or partial diff — acceptable degradation, but it belongs in the description. - nit — unrelated change: the PTY-output wait in
packages/runtime/src/__tests__/shell-run-manager.test.tsis unrelated to this panel; better as its own PR. - nit — copy conventions: the sibling ICU plural uses
{count, number}(packages/ui/src/astryx-copy.ts:150,commandPalette.resultCount), the newsearch.resultCountuses{count}. Also the comment abovesearch("Selector and MultiSelector render the same two search affordances") is stale —emptySearch/resultCountare Selector-only, MultiSelector has its own catalog keys. - nit —
options={[...props.baseBranchOptions]}(session-review-base-branch-picker.tsx:51) allocates per render and defeats Selector'sfilteredItemsmemo; auseMemoon the panel side would keep it stable. - nit — process: only the first commit carries
Generated-by: pi (…), whileCONTRIBUTING.mdasks for the trailer on each affected commit, kept through squash; andCONTRIBUTING.mdasks for before/after images on UI changes — the Storybook measurements are useful evidence, but nothing is attached. docs/superpowers/plans/2026-09-10-review-branch-refs.mdis the only file underdocs/superpowers/; tracked plans elsewhere live indocs/archive/ordocs/. Consider moving or dropping it.- Heads-up: merge state is
DIRTY(conflicts withmain); thetestcheck is green.
Verified, no issue found
Selector.onChangehands back the optionvaluein the non-clearable variant (@astryxdesign/core@0.5.2,Selector.d.ts), so what gets persisted is the canonical ref, not a label; the first read omitsbaseBranchentirely (reviewBaseBranchRequestValue).- Search filters on
option.label(Selector.js:260), so short branch names are searchable, and@astryx.selector.emptySearchResults/.resultCountdo exist in the Astryx catalog (locales/en.json:1270,1274), so the Chinese overrides land. - The
%(refname:short)bug is real: git reportsrefs/remotes/<remote>/HEADas a bare<remote>(refs/remotes/author/HEAD → authoron git 2.50 here), which the old.endsWith('/HEAD')filter let through. Enumerating%(refname)and stripping the namespace is the right fix. - Ordering cannot drift: one
BASE_BRANCH_PRIORITYlist feeds bothlistBaseBranches(:450) andresolveBaseBranch(:414), and the unranked/label tiebreak reads correctly. - Ambiguity is rejected rather than guessed: same-label local vs remote, tag vs branch, and tag-only names all fail closed (
resolveRequestedBaseBranch,:440), and the orphan-history and tag-named-maincases behave. - The CSS selectors are real (
themeProps('popover-surface'),themeProps('item')); the layer renders inline inside the wrapper unless its parent has an unsafe writing context, and the popover ispopover="auto"(top layer), sooverflow-y: autoon.maka-session-review-panelwill not clip it. - Contract blast radius is small:
baseBranchOptionsis only consumed by the desktop app, the IPC already validatedbaseBranch(runtime-host-workspace-ipc-main.ts:66-79), and both new test files sit undersrc/main/__tests__wheretest:dist(dist/main/**/*.test.js) picks them up.
8b51ef2 to
08c5a2c
Compare
3ef391c to
fa20b51
Compare
|
Could we have a before after comparison picture in the pr body? It would help clarify things easier. Thanks! |
Remove the composer footer's Git-branch chip and the read pipeline that fed it (#5487): the chip was that pipeline's only consumer, so nothing is left stranded. The branch is ambient session state the agent owns, not a parameter of the send, so the composer's control row is the wrong home for a read-only value there — and it was the one item on that row drawn as a hand-rolled span instead of an Astryx primitive. The workbar's Review face names the current branch once #5120 lands; this lands first so the two never show the same fact twice. Migration: none. Between this merge and #5120's there is no surface naming the branch — a deliberate gap over duplicating the readout. #5120 needs a trivial rebase on git-review-main.ts and packages/core/src/git-review.ts to drop the readGitBranch / GitBranchReadResult it inherited from #5487. Refs #2171, #5487 Generated-by: Maka
5942af5 to
abce327
Compare
|
@Astro-Han done |
29afb1b to
951cb66
Compare
Let each session select a comparison branch by canonical ref, with searchable localized options and persisted explicit choices. Keep implicit defaults dynamic, recover automatically when a saved branch disappears, and reset pagination when the comparison changes. Preserve branch options when diff computation fails and show truncated output when a large unified diff exceeds the process buffer. Add recovery and ref-resolution coverage, switch feedback, stories, and surface inventory documentation. Generated-by: pi (DeepSeek V4.1 Flash) Generated-by: OpenAI Codex
Generated-by: Codex
Regenerate the file-level inventory after 0f11ae7 added a Text usage to the review base branch picker without regenerating. The markdown row had drifted from the generator; the .paths list was already in sync. Keeps the astryx:surface-inventory coverage gate green. Generated-by: Maka
dcc385e to
f6ffba1
Compare
|
@Astro-Han Thanks for the detailed review. Most items are addressed, including keeping implicit defaults dynamic. A few behavior, documentation, and process points remain open:
|
Summary
The Changes panel previously compared only against the backend-resolved base branch, so stacked work could include inherited changes with no way to choose another comparison base. This PR adds a searchable base-branch picker beside the current branch (
current → base).baseBranchand follow the repository default; displaying the resolved default does not pin it. If a saved branch becomes invalid, the panel clears the saved selection and retries once with the dynamic default.{ label, value }: readable names in the UI, fully qualifiedrefs/heads/...orrefs/remotes/...values for comparisons and storage. Unique legacy names migrate to canonical refs; ambiguous names and tag-only refs are rejected. Local and remote branches with identical labels remain distinct.The backend enumerates full refs instead of relying on
%(refname:short), keepsorigin/HEADselectable, and shares the preferred-branch ordering with default resolution. The remote HEAD's resolved target takes precedence; the current branch can also be the base, with staged and unstaged changes still included.Fixes #5119
Before:

After:

Verification
Checked against PR head
abce32742c4c384acbb87842ade7746bf4f38296on 2026-09-20:npm --workspace @maka/desktop run build:main— passed.node --test --test-force-exit apps/desktop/dist/main/__tests__/git-review-main.test.js apps/desktop/dist/main/__tests__/session-review-base-branch.test.js apps/desktop/dist/main/__tests__/session-review-panel-recovery.test.js— 19/19 passed. Covers full-ref and legacy-name resolution, tag/name collisions, default ordering, per-Session persistence, corrupt storage, recovery after invalid selections or failed diffs, switch feedback, and output-buffer truncation.Earlier verification recorded in this PR (not revalidated against the current head): desktop typecheck, architecture checks, Biome and renderer build passed; desktop tests reported 2461/2462 with a
settings-ipc-helpersTavily failure. Storybook checks covered filtering, localized search feedback, long-name ellipsis, and updating/closing the picker after selection. The screenshots above are retained from that earlier verification.Review focus
{ label, value }and can include branch context in failure results. Legacy saved names are accepted only when they identify one enumerated branch.READYline and cursor position before taking the PID-observation baseline; it does not change runtime production behavior.AI use
Select exactly one:
Tool(s) and scope: pi (DeepSeek V4.1 Flash) — implementation and earlier local verification. Codex — PR description refresh and the focused build/test verification listed above.
Checklist
Does this PR entail a change in behavior?