Skip to content

feat(desktop): show the running build on the sidebar footer - #3430

Open
Joob1n wants to merge 2 commits into
apache:mainfrom
Joob1n:feat/sidebar-build-stamp
Open

feat(desktop): show the running build on the sidebar footer#3430
Joob1n wants to merge 2 commits into
apache:mainfrom
Joob1n:feat/sidebar-build-stamp

Conversation

@Joob1n

@Joob1n Joob1n commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

PR-BUILD-HYGIENE-0 put a build stamp on the About page so a dev build could be told apart from a release. It works, and it is two clicks and a scroll away — so the question it answers gets asked where it cannot answer it.

I hit exactly that while working in this repo: a locally built app was mistaken for the installed release, and a change that had merged looked like it had not landed. The version was on screen the whole time, one page away.

The rail footer already had the shape for it. .maka-sidebar-footer-row is a flex row whose settings item is flex: 1, so a sibling lands flush right — the slot the update button uses.

⚙ Settings                    v0.1.11 · 4d223d0

Order is settings, stamp, update button. The button is an action and keeps the edge, where a control is reached for; the stamp is a label, and outside the button it would move every time an update arrived or was installed. A dev build never renders that button — app-update-service.ts short-circuits to not-available when !isPackaged — so on a dev build the stamp sits at the edge on its own, and on a release it yields without changing its relation to Settings.

The commit appears only on a dev build: build-info.ts reads .git/HEAD and returns null once packaged, which is exactly the case where a version number alone cannot separate two builds. Seven hex characters is what git log --oneline prints and how a commit is quoted in review.

Read once at mount through window.maka.app.info() — neither value can change without the process restarting. A failed read renders nothing: an orientation label showing an error where a version belongs is worse than one that is absent, and the About page reports that failure where a user went looking for it.

Verification

Ran npm run dev and read the footer on a dev build:

⚙ 设置                                    v0.1.11 · 44c0741

A release renders v0.1.11 alone, since build-info.ts has no .git to read once packaged.

image

Tests cover both build shapes, the pre-resolution empty state, and the order against the update button. The order assertion was checked in both directions — moving the stamp past the button fails that test and only that test — so it pins the layout rather than describing it.

Gates run: build, lint, format:check, typecheck, knip on apps/desktop and packages/ui, astryx:surface-inventory, astryx:theme --check. Suites: @maka/ui 187 (183 before this change), @maka/desktop 1023. Storybook builds and all 145 stories render.

Not run: Windows and Linux packaging; this is renderer-only and platform-independent, but the rail is only exercised on macOS here.

Review focus

The collapsed rail. The stamp is hidden below 48px rather than clipped or allowed to widen the rail — and readSessionListCollapsed() returns true when nothing is stored, so a first run has the rail collapsed and the stamp does not appear until it is expanded.

I do not think a truncated version string earns 48px, and the About page still carries it. But this is the judgement most worth a second opinion: if the rail's default state matters more than its width, the fallback is a shorter form (0.1.11 — no prefix, no commit) at a smaller size rather than nothing at all.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Claude Code — traced the existing build-info plumbing, made the change, wrote the tests, and ran the verification above. Generated-by is on the commit. Reviewed and submitted by the contributor of record.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

`PR-BUILD-HYGIENE-0` put a build stamp on the About page so a dev build could
be told apart from a release. It works, and it is two clicks and a scroll
away — so the question it answers gets asked where it cannot answer it. This
session hit exactly that: a locally built app was mistaken for the installed
release, and a merged change looked like it had not landed.

The rail footer already had the shape for it. `.maka-sidebar-footer-row` is a
flex row whose settings item is `flex: 1`, so a sibling lands flush right —
the slot the update button uses today.

Order is settings, stamp, update button. The button is an action and keeps the
edge, where a control is reached for; the stamp is a label, and putting it
outside the button would move it every time an update arrived or was
installed. A dev build never renders that button at all — `app-update-service`
short-circuits to `not-available` when `!isPackaged` — so on a dev build the
stamp sits at the edge on its own, and on a release it yields without changing
its relation to Settings.

`v0.1.11` on a release, `v0.1.11 · 4d223d0` on a dev build. The commit is
present only when unpackaged, since `build-info.ts` reads `.git/HEAD` and
returns null once there is no repository to read — which is exactly the case
where a version number alone cannot separate two builds. Seven hex characters
is what `git log --oneline` prints and how a commit is quoted in review.

Collapsed, the rail is 48px and the stamp is hidden rather than clipped or
allowed to widen it. The About page still carries it, and a collapsed rail is
a deliberate request for less.

Read once at mount through `window.maka.app.info()`: neither value can change
without the process restarting. A failed read renders nothing — an
orientation label that shows an error where a version belongs is worse than
one that is absent, and the About page reports that failure where a user went
looking for it.

Tests cover both build shapes, the pre-resolution empty state, and the order
against the update button — verified to fail when the stamp is moved past it.

Claude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J

Generated-by: Claude Code (Claude Opus 5)
@Joob1n
Joob1n force-pushed the feat/sidebar-build-stamp branch from 44c0741 to 96f1bc8 Compare August 21, 2026 14:11
@Joob1n

Joob1n commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@Astro-Han , could you merge this pr?

@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.

Thanks for putting the build identity where developers actually look, and for reusing the existing app:info path rather than introducing another main-process authority. The expanded/collapsed behavior and the release-versus-development formatting are clear, and the live test check is green.

I’m leaving one non-blocking P2 follow-up below.

The only correctness gap I found is specific to the development workflow: a normal Git worktree has a .git file containing a gitdir pointer, rather than a .git directory. The existing build-info resolver therefore returns commit: null in that checkout, so this footer falls back to the version alone and still cannot distinguish that locally built tree from a packaged release. The clean fix is to extend the existing main-process build-info authority to follow worktree metadata and cover that case with a focused resolver test; the renderer should remain a pure consumer of app:info rather than growing a second Git reader.

As a small P3 polish item, at the supported 180px expanded width a packaged build with an update reminder can slightly truncate the Settings label. The icon, action, and accessible name remain available, so this is not a merge blocker; making the stamp the shrinkable/ellipsis item while preserving its full title would keep both pieces readable.

AI-assisted review disclosure: OpenAI Codex coordinated the exact-head review. I independently verified the current head, base, CI and review state, traced the app:info/build-info data flow against current main, reproduced the Git-worktree behavior, and checked the sidebar geometry. The recommendation above is my reviewed judgment; no unverified AI output is being presented as a finding.

.info()
.then((info) => {
if (cancelled) return;
setStamp({ version: info.appVersion, commit: info.buildCommit });

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.

[P2] Thanks for wiring the footer to the existing app:info result. One development-path gap remains: when Maka is run from a normal Git worktree, .git is a file containing a gitdir pointer, so the current main-process build-info resolver returns commit: null. This makes the new stamp render only v<version> and fails to distinguish the locally built tree from a packaged release—the exact problem this change is meant to solve for contributors. Could we extend the existing build-info authority to follow worktree metadata and add a focused resolver test, while keeping the renderer as a pure app:info consumer rather than adding a second Git reader here?

Two findings from @Astro-Han's review of the sidebar build stamp.

**P2 — a worktree's `.git` is a file, and the resolver only read directories.**

`resolveCommit` opened `<root>/.git/HEAD`. In a linked worktree `.git` is a
file holding `gitdir: <path>` into `<main>/.git/worktrees/<name>`, so the read
found nothing and the stamp fell back to the version alone — in exactly the
checkout where it matters most, since a worktree's HEAD is the one that
differs from the tree a developer thinks they are running.

Fixed in the main-process `build-info` authority as asked; the renderer stays
a pure consumer of `app:info`. A relative `gitdir:` resolves against the
checkout, which is how Git writes it for a worktree created inside the repo.

Verified against a real worktree in this checkout rather than fixtures alone:
the repository root reports `96f1bc8` and the worktree reports `5d9a5b0`,
each matching `git rev-parse` — two different commits, which is the
distinction the stamp exists to make.

The resolver had no test file at all. It has one now: ordinary clone, worktree
by absolute and by relative pointer, detached HEAD, packed refs, and the two
unreadable cases, where absence stays a supported answer rather than throwing
out of `app:info`.

**P3 — the Settings label could clip at the 180px minimum.**

The stamp was `flex: none` and the settings row `flex: 1`, so with an update
button present the label lost the argument. The stamp is now the shrinkable
item — it ellipsises and keeps its full value in `title`, while the label a
user reads and the row they aim at stay intact.

Claude-Session: https://claude.ai/code/session_014ajaRxC4jydavY9nYUFj5J

Generated-by: Claude Code (Claude Opus 5)
@Joob1n

Joob1n commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Both addressed in 45aba559d.

P2 — the worktree case reproduces, and the fix is in build-info as you asked.

resolveCommit opened <root>/.git/HEAD, and in a linked worktree .git is a file holding gitdir: <path>. Confirmed against a real worktree in this checkout before changing anything: the resolver returned commit: null there.

The main process now follows the pointer, resolving a relative gitdir: against the checkout since that is how Git writes it for a worktree created inside the repository. The renderer stays a pure consumer of app:info.

Verified on the same real worktree afterwards: repository root reports 96f1bc8, worktree reports 5d9a5b0, each matching git rev-parse — two different commits, which is the distinction the stamp exists to make.

The resolver had no test file. It has one now covering ordinary clone, worktree by absolute and relative pointer, detached HEAD, packed refs, and the two unreadable cases — where absence stays a supported answer rather than throwing out of app:info, which carries much more than the commit.

P3 — the stamp yields, the label does not.

It was flex: none against a flex: 1 settings row, so at 180px with an update button the label lost. The stamp is now the shrinkable item: it ellipsises and keeps the full build in its title, while the label a user reads and the row they aim at stay intact.

Gates: build, lint, format:check, typecheck. Suites: desktop 1030 (1023 before, +7 from the new resolver test), ui 187.

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.

2 participants