Skip to content

feat(desktop): separate Git review empty and error states - #5963

Open
ggbdpq wants to merge 3 commits into
apache:mainfrom
ggbdpq:feat/changes-git-review-states
Open

ggbdpq wants to merge 3 commits into
apache:mainfrom
ggbdpq:feat/changes-git-review-states

Conversation

@ggbdpq

@ggbdpq ggbdpq commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #5940 — the Changes (Git review) panel treated every unreadable source alike: one error Banner with Retry. Split the failure surface into the distinct states the issue asks for:

  • not_git_repository → neutral guidance on the EmptyState surface (no red Banner, no Retry): what Changes needs, the task directory it looked at, and the next step (git init here, or move the task into a repository). Retrying cannot create a repository.
  • workspace_unavailable → keeps its error Banner and Retry (restoring the directory makes a retry succeed) and adds recovery guidance pointing at restore-or-relocate paths.
  • git_failed / unborn_repository → unchanged error Banner + Retry (an unborn repository gains commits; a failed read can succeed).
  • empty (no differences) and invalid_base_branch (auto-recovered in load()) stay as they were.

The task directory reaches the panel through an optional cwd on the GitReviewReadResult failure branch, filled by the git-review:read handler from the Session's declared workspace (and from the directory the read ran in for the other reasons). The app-default workspacePath is deliberately not used — it is not the task directory. No second relocation mechanism, no automatic git init, no non-Git diff: the guidance names the existing authorities.

Out of the four states, only the renderer mapping was missing — GitReviewReadResult already carried the five failure reasons and the copy layer already had per-reason strings; this PR separates the rendering and adds the two guidance strings plus a directory line, in all three locales (en / zh-CN / zh-TW).

Verification

Check Command Result
New DOM tests, before the fix node --test --test-force-exit apps/desktop/dist/main/__tests__/session-review-panel-recovery.test.js exit 1 — 2 new tests fail against the old panel (not a Git repository rendered with Retry; unavailable workspace missing recovery guidance)
New DOM tests, after same exit 0 — pass 10 / fail 0 (incl. guards that git_failed/unborn_repository keep Retry and that git_failed shows no directory line)
Adjacent suites git-review-main / session-review-base-branch / review-base-branch-preferences exit 0 — 16 pass
packages/core full suite npm run test:dist exit 0 — 915 pass
Format npx biome format . exit 0
Locale hygiene node scripts/check-locale-hygiene.mjs exit 0
Renderer architecture ratchet node apps/desktop/scripts/check-renderer-architecture.mjs exit 0
Desktop typecheck npm run typecheck (preload / main / renderer / storybook) exit 0

Not run locally (left to CI): Playwright e2e and the live Storybook smoke — the story assertions (ChangesSourceNotGit now guidance-without-Retry; new ChangesWorkspaceUnavailable) are covered by typecheck:stories and the DOM suite here.

AI use

Coding, test authoring and verification runs were performed by GLM-5.3-Flash (ZCode) under human direction; the human reviewed the diff and the verification matrix.

Checklist

  • Tests fail before the fix and pass after (2 new red→green tests, plus guards locking the Retry-retaining states)
  • Copy added in all three locales (en / zh-CN / zh-TW)
  • Renderer architecture check and locale hygiene pass (no frozen-file touches; workbar is not on the legacy list)
  • Scope stays inside the issue's: no auto-init, no non-Git snapshots, no default-directory allocation, no second relocation mechanism

The Changes panel treated every unreadable source alike: one error
Banner with Retry. A directory that is not a repository can never
succeed on retry, so the shared failure surface invited a retry that
could not help (apache#5940).

Map the failure reasons to distinct states in SessionReviewPanel:

- not_git_repository: neutral guidance (EmptyState surface, not the
  red Banner) naming what Changes needs, the task directory it looked
  at, and the next step (git init here or move the task into a
  repository); no Retry, since retrying cannot create a repository.
- workspace_unavailable: keeps its error Banner and Retry (restoring
  the directory makes a retry succeed) and adds recovery guidance
  pointing at restore-or-relocate paths.
- git_failed and unborn_repository: unchanged error Banner + Retry.
- empty (no differences) and invalid_base_branch (auto-recovered in
  load()) stay as they were.

The task directory reaches the panel through an optional `cwd` on the
GitReviewReadResult failure branch; the git-review:read handler fills
it from the Session's declared workspace (and from the directory the
read ran in, for the other reasons). The app default workspacePath is
deliberately not used — it is not the task directory.

Stories: ChangesSourceNotGit now asserts guidance without Retry;
new ChangesWorkspaceUnavailable covers the recovery Banner.

Fixes apache#5940
Generated-by: GLM-5.3-Flash (ZCode)
@github-actions github-actions Bot added the effort/M Under 500 readable lines label Oct 4, 2026

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.

Review of exact head 6163e59e (single commit on merge-base e57b0295). GitHub reports MERGEABLE (merge state BLOCKED). CI test was still pending when I reviewed; label passes.

No P0-P2 findings. The state split is correct.

What I checked:

  • Reason routing: not_git_repository gets a neutral EmptyState with no Retry. workspace_unavailable gets an error Banner with recovery copy and Retry. unborn_repository and git_failed keep the old Banner and Retry. invalid_base_branch is still handled in load() (pin is dropped and the read retried) and otherwise falls through to gitFailed, as before. empty excludes both new states, so no double rendering.
  • cwd plumbing: readGitReview has a single caller (runtime-host-workspace-ipc-main.ts). Every non-ok result now carries cwd. The preload/ports pass GitReviewReadResult through untouched, and cwd is optional on the core type, so a result without it degrades to "no path line". The renderer shows the path only for the two guidance states, and the git_failed test pins that.
  • Markup: Astryx Banner renders description in a <div> and Text defaults to <span>, so nesting the path line is valid.
  • Copy: zh-CN, zh-TW and en all define the three new keys.

Two P3 inline: (1) "not a repository" no longer has an in-place Retry, but its copy tells the user to run git init; (2) remote-host sessions hit an early workspace_unavailable and now get "moved/deleted, restore it" recovery copy that does not apply.

) : null}
{/* A source that cannot be read is a failure, not an absence — it takes
the same Banner the load error above does, not an EmptyState. */}
{guidance ? (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: the not-a-repository state no longer has a reload affordance, but its copy suggests an in-place fix. notGitRepositoryHelp says "Initialize one here (git init)". The premise "retrying cannot turn a directory into a repository" holds only until the user does exactly that. The panel reloads on window focus/visibilitychange, on agent tool_result/complete, and on re-activation. But the workbar has a terminal tool (workbar-tool-definitions.ts, right/bottom placement), so it can sit in the bottom panel next to Changes on the right. Running git init there fires none of those triggers, and the panel stays on "not a Git repository" with no button until the user changes focus or tab. Consider keeping a low-emphasis Retry/Refresh here, or dropping the "here (git init)" wording. Note that after git init the next read becomes unborn_repository, which does show Retry.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 795f4c1: the guidance keeps the git-init wording and gains a low-emphasis ghost Refresh button that re-reads the source. Once git init lands, the next read reports unborn_repository, which already carries Retry.

@@ -40,17 +40,32 @@ export function registerRuntimeHostWorkspaceIpc(
return { ok: false as const, reason: 'workspace_unavailable' as const };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: this early workspace_unavailable now gets misleading recovery copy. allowLocalWorkspace is !usesHostWorkspace (runtime-host-boot.ts:1727/1763). Remote/host-workspace runtime targets therefore always return this result, with no cwd. Before this PR the panel just said "This task directory is unavailable". It now adds "may have been moved, deleted, or become inaccessible. Restore it or switch the project's working directory, then retry" plus a Retry that can never succeed, because the directory exists and the desktop host simply doesn't read it. Consider a distinct reason (or a flag) for "Changes is not available for this runtime host", or at least keep this branch out of the new guidance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 0f2b62e: the early return now reports a distinct local_workspace_disabled reason (core enum + doc), rendered as a neutral "not available for this runtime host" state — no recovery guidance, no directory line, no Retry. The panel's empty and sourceError guards were extended so the new reason cannot fall into either the diff-empty or the error surface.

ggbdpq added 2 commits October 4, 2026 22:51
The workbar's terminal tool can share the screen with the Changes panel,
so a reader may run `git init` right next to it. None of the panel's
automatic reload triggers (window focus, visibilitychange, agent tool
results, re-activation) fire while the panel keeps focus, so the
guidance used to stay stuck with no way forward until the reader
refocused the window. Keep the git-init guidance and add a low-emphasis
Refresh that re-reads the source; once the repository appears the next
read reports unborn_repository, which already carries Retry.

Review feedback on apache#5963 (Astro-Han, P3: guidance state had no reload
affordance despite the "Initialize one here (git init)" wording).
Generated-by: GLM-5.3-Flash (ZCode)
…rkspace

`allowLocalWorkspace` is `!usesHostWorkspace`, so remote/runtime-host
targets always failed the git-review read before any directory was
looked at, and they reported it as `workspace_unavailable`. The panel
then showed the "may have been moved, deleted..." recovery guidance
plus a Retry that could never succeed — the directory exists; the
desktop host simply never reads it. Give the early return its own
`local_workspace_disabled` reason and render it as a neutral "not
available for this runtime host" state with no recovery guidance, no
directory path line, and no Retry.

Review feedback on apache#5963 (Astro-Han, P3: misleading recovery copy on
the runtime-host early return).
Generated-by: GLM-5.3-Flash (ZCode)

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review notice: This comment was posted by an automated review agent. It is not an independent human review and does not replace one.

Incremental review: 6163e59e → 0f2b62e2 (two new commits, 795f4c19 and 0f2b62e2). The merge-base with main is unchanged (e57b0295), so the delta is exactly 6163e59e..0f2b62e2. GitHub reports MERGEABLE (merge state BLOCKED). CI test is still pending on this head.

Both P3s from the previous pass are resolved. No new findings.

  • Not-a-repository has no reload affordance → fixed in 795f4c19. The guidance state keeps its git-init wording and now has a low-emphasis ghost Refresh button (session-review-panel.tsx:330-336) that calls load(). There is still no Retry, which keeps the "nothing failed" framing. The test now checks that Retry is absent, that Refresh is present, and that clicking it triggers a second read (reads 1→2). The story asserts 刷新. All three locales define refresh.
  • Remote hosts got recovery advice that could never work → fixed in 0f2b62e2. The allowLocalWorkspace === false early return now sends its own reason, local_workspace_disabled (runtime-host-workspace-ipc-main.ts:45, added to the core union at git-review.ts:77). The panel shows it as a neutral EmptyState with no path line, no recovery copy and no Retry, and leaves it out of both sourceError and empty, so nothing renders twice. The new test pins the absence of "may have been moved", "Task directory:", the error banner and Retry.

What I checked:

  • Union consumers: a grep for the reason literals at the new head turns up only the IPC producer, git-review-main.ts (not_git_repository only), the renderer predicates and the stories. There is no exhaustive switch that the new member breaks. Preload passes the result through unchanged, and main and renderer ship in the same bundle, so there is no version-skew window.
  • Copy: zh-CN, zh-TW and en all define runtimeHostWorkspaceUnavailable, runtimeHostWorkspaceUnavailableHelp and refresh.
  • Refresh while loading: isLoading={loading} handles repeated clicks. load() bumps the revision, so a stale read can't overwrite a newer one.

What I could not judge: I did not run the suite, and CI test is still pending on this head.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/M Under 500 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(desktop): separate Git review empty and error states

2 participants