Desktop Material

Desktop Material — Active parity handoff

August 7 chrome, every feature back on top of it — 2026-08-15

Read this first; it supersedes the two entries below it. The requested end state is now live: the interface is the August 7 chrome, and every feature is back.

Those are not in tension, and the proof is two diffs rather than an assurance:

Check Result
app/src/ui/repository.tsx vs 02d627e662 byte-identical — the workspace, rail, tabs and avatar are August 7
app/src/ui/app.tsx vs 02d627e662 81 insertions, 0 deletions — purely feature wiring

Restored: Support Tickets, the authenticator (entries, TOTP, QR registration, secret vault), the regex builder, the destructive-action gate, the every-element appearance locks, the offline docs browser, agent sessions, the newer runner surface, and the personal-vocabulary, School-mode and dialog-emoji settings. Also back: diff line wrapping, hunk-expansion focus order, commit-drop insertion ordering, menu first-character navigation and the worktree list's merge-branch handling — the five post-August-7 fixes that were never MD3 and had been taken out indiscriminately.

Material mode stays retired. This is the earlier M3 design with the features on it, not the MD3 shell returning; see the entry further down for why the app is still Material Design 3 throughout.

How this was done, and why not by hand

app/ was restored wholesale from 9c9755d844, whose tree already was "August 7 chrome plus every feature" — the surgical route the revert jer had produced before the literal revert removed it. Rebuilding 42,638 lines by hand would have been slower and strictly worse: this way the result is verifiable by git diff rather than by review.

Verified, against a real baseline

Check Result
npx tsc --noEmit -p tsconfig.json exit 0, zero errors
app/ vs 9c9755d844 identical (empty diff)
The 50-file contract suite 64 failing of 465
The 26 failures the literal revert introduced 0 remain

64 of 465 is exactly the pre-revert baseline, so the 21 reintroduced defects tracked on issue #196 are all resolved — the AI merge editor's security guards, the 158-glyph font contract, the accessibility and layout contracts, and the destructive-action honesty guards all pass again. The 5 obsolete guards in that issue are no longer obsolete, because the features they guard exist again.

[!NOTE] The remaining 64 were already red before any of this and are unrelated to the revert or the restore. They are the standing contract debt, not new.

Lint, captures, packaging and a built-artifact run were not performed.

The interface is now literally August 7, and the features went with it — 2026-08-15

Read this first. app/src/ui and app/styles were hard-reverted to 02d627e662 (2026-08-07 21:10). This was requested explicitly and confirmed after the cost below was put in writing, so it is a decision, not an accident. 146 files changed: 361 insertions, 42,638 deletions, 95 files deleted.

What this deleted, deliberately

Support Tickets, the authenticator (entries, TOTP, QR registration, secret vault), the regex builder, the destructive-action gate, the every-element appearance locks, the offline docs browser, the self-hosted runner manager's newer surface, and agent sessions. Their app/src/lib modules (docs-browser/, md3-locks/, authenticator/, md3-view-preferences.ts, stores/authenticator-store.ts, rewrite-surface-registry.ts) and 22 test files went with them.

[!WARNING] Several of these are contracts the shared agent instructions require of every user-facing app. This tree no longer satisfies them. That is a known, requested state — do not "fix" it by restoring them without asking.

It also took post-August-7 work that was never MD3

Reverting the whole of app/src/ui is indiscriminate, and these went too: diff line wrapping, hunk-expansion focus order, commit-drop insertion ordering, menu first-character navigation, and the worktree list's merge-branch handling. Each was an accessibility or behaviour fix, not chrome. They are recoverable from history if wanted; they are named here so nobody has to rediscover the loss.

The 98-glyph icon font is back, and that has teeth

August 7 ships material-symbols-rounded-prototype-98.woff2, not the 158-glyph official subset. MaterialSymbolNames in app/src/ui/lib/material-symbol.tsx documents itself as "the exact ligatures bundled" in that prototype, and a unit contract compares it to font-assets-manifest.json.

A ligature name the font does not carry renders as its literal English word. So do not widen that union to satisfy a call site — 14 names (calendar_month, construction, description, edit_note, folder, help, inbox, menu, merge_type, more_vert, play_circle, smart_toy, sort, wrap_text) were referenced by the newer palette catalog and are not in the 98-glyph set. That catalog was reverted to August 7 rather than the union widened, which is why the tree compiles. Subset the real font first if a new icon is ever needed.

One deliberate non-revert, and why

ISelfHostedRunnerSetupRequest.accountKey and ISelfHostedRunnerRemoveRequest.accountKey are now optional. The August 7 runner UI has no account picker, but multi-account infrastructure elsewhere in app/src/lib survives and is used widely, so reverting the types was not an option. validateSetupRequest resolves the key through SelfHostedRunnerAccountCredentials.onlyAccountKeyForEndpoint and returns ValidatedSelfHostedRunnerSetupRequest, so every later step still has a concrete account. It refuses when two signed-in accounts share an endpoint rather than guessing — guessing would register a runner as a user who never chose it.

Known incoherence left in place

app/src/lib/settings-search/settings-search-catalog.ts and app/src/lib/collection-surface-registry.ts still list rows for surfaces the August 7 Settings does not render, and lib/personal-vocabulary.ts, lib/school-mode.ts, lib/dialog-emoji.ts and lib/support-tickets.ts are still imported by i18n.ts and that catalog. They were not deleted, because deleting them breaks i18n. Auditing that catalog against the August 7 Settings is real remaining work.

Verified for this revert — including what is red

Check Result
npx tsc --noEmit -p tsconfig.json exit 0, zero errors
Prettier on all 44 changed source files clean
node script/test.mjs 8,564 tests, 89 failing across 50 files
Lint, captures, packaging, built-artifact run not performed, not claimed

A baseline was taken, by running the same 50 files at 9c9755d844 (the commit immediately before the revert) in the same checkout:

Failing leaf tests
Before the revert (9c9755d844) 64
After the revert 89
New, caused by the revert 26
Fixed by the revert 1

So 64 of the 89 were already red and are not this revert's doing. The 26 new ones split two ways, and the split is the important part:

Five are obsolete guards — they guard deleted features and can never pass

feature-ledger-test.ts (3: "still declares every dialog the app could open", "still has a live route to every dialog it declares", "still ships every UI feature area"), collection-surface-registry-test.ts (1), support-ticket-recovery-test.ts (1).

Twenty-one are the revert reintroducing real defects

[!WARNING] These are not stale guards. Do not delete them to make the suite green — each is catching something the August 7 tree genuinely does wrong, which is why it was written in the first place.

Area Tests What it means
ai-merge-editor-test.tsx 6 Includes "renders hostile HTML-looking content only as plain text" — a security guard — plus "does not reintroduce CodeMirror hidden input buffers" and "refuses an over-limit result instead of emitting silently truncated code"
bundled-fonts-test.ts, material-symbol-test.tsx 4 The 98-glyph prototype font is back; see the icon-font section above
button-token-test.ts 2 --button-height 25px vs 40px again — the trap that hid a sub-minimum touch target once already
responsive-repository-surfaces-style-test.ts 3 Narrow-width and short-height layout: missing-repository actions no longer stack, sheets escape their viewport insets
popover-clipping-contract-test.ts, post-shell-style-test.ts 2 Popovers unbounded; the floating-popover available-height token is gone
command-palette-size-contract-test.ts 1 Palette results unusable at 200% zoom in a short viewport
self-hosted-runner-removal-dialog-test.tsx 1 An irreversible removal hides itself while running
shallow-clone-ui-test.ts 1 Post-clone runner provisioning no longer explicit, no longer blocks public repositories
issue-134-workflow-paths-test.ts 1 The editable conflict result is off the native full-value control

Accepting the August 7 interface means accepting these until each is fixed against August 7's chrome. They are tracked on the issue linked from the changelog entry for this revert.

One of the two MD3 designs was retired — the app is still Material Design 3 — 2026-08-15

[!IMPORTANT] The app did not stop being Material Design 3. It has had two M3 designs. The second one — the MD3 shell with its eight destination views — is the one that was retired. The first one is what renders now, and it is M3 throughout. Do not read the rest of this entry, or the phrase "Material mode", as saying Material Design left the product. It did not, and nothing here is a licence to "restore M3" against the design system that is already live.

Read this before the 2026-08-14 entry, which it supersedes on one point. The revert was carried through: finish/ui-revert-to-2026-08-07 merged into main as 92b3ef9164, removing 60,309 lines — the second design's shell, its eight destination views, its controllers, adapters and its thirteen test files. The Material mode setting no longer exists, because the alternate shell it switched to no longer exists. The 2026-08-14 entry's heading "Nothing was deleted, and nothing needs re-adding" described main on that date and is no longer true of the tree; it is left in place as the record of what was decided then, with a correction note attached.

The design system that is live right now

The chrome the revert restored is the earlier M3 design, and it consumes the same M3 foundations the second design did:

Evidence Where
--md-sys-color-* system tokens declared on :root app/styles/_material.scss — its own first line reads "Material Design 3 foundations for Desktop Material"
M3 motion tokens app/styles/material/_motion.scss
Material Symbols icon font, 158-glyph subset app/styles/fonts/material-symbols-rounded-subset-158.woff2
M3 components in the shared UI library app/src/ui/lib/material-symbol.tsx, material-switch.tsx, material-context-menu.tsx
M3 surface partials app/styles/_material-controls.scss, _material-shell.scss, app/styles/ui/_material-rail.scss, _material-cards.scss, _material-switch.scss, _material-symbol.scss
MaterialSymbol call sites 69 files under app/src

The --button-height fix recorded below is itself proof of this: the value that won came from _material.scss, because the M3 layer is imported second and is the live one.

What the retirement kept, deliberately: 46 md3 files remain, and they are dialogs rather than chrome — the destructive-action gate, the regex builder, the toasts, the menu overlay, the compose dialog, the authenticator and Support Tickets. That is the line the revert itself drew, and the four commits on the merged jer restore every setting the shell's removal had stranded (lib/personal-vocabulary, lib/school-mode, lib/dialog-emoji, lib/md3-locks, lib/authenticator) into the classic Settings surface.

Two user-visible defects were fixed on the way, and both are worth knowing about because each had shipped: --button-height was declared 25px in _variables.scss and 40px in _material.scss, the Material layer is imported second and wins, so the 25px was dead and under the minimum touch target; and the revert had swapped the 158-glyph Material Symbols subset for a 98-glyph prototype while the code still asked for 158 names, so an interface shipped with English words rendered where icons belong.

wip/stopped-fleets-2026-08-14 merged as fe1db0dbb5, and only its GitLab design-conformance work survived — five of its seven files built on the shell that is now gone. That closes open item 3 below and leaves one open: the header avatar's account switcher is still broken. The reverted rail avatar works (onToggleAccountSwitcher, railAvatarButtonRef); the header's does not, and the fix that was in flight targeted files that no longer exist, so it must be rewritten against the reverted chrome rather than ported.

Verified for this integration: npx tsc --noEmit -p tsconfig.json exit 0, zero errors, on the merged tree at fe1db0dbb5. The test suite, lint, captures, packaging and CI were not run in this lane and are not claimed.

UI reverted to the pre-rewrite interface — 2026-08-14

Read this first if you are picking up UI work. The default interface was changed back at the user's explicit and repeated request: "please revert the ui to how it was one week ago before this rewrite", "the new ui is causing more issues than good", "and keep all features".

What "the pre-rewrite UI" actually is

The pre-rewrite tip is f443f3cd10 (2026-08-11, "Report the lint state of app.tsx honestly in the handoff"), named as such by app/src/lib/interface-mode.ts itself. Reading git show f443f3cd10:app/src/ui/app.tsx shows renderApp() rendered <Md3Shell views={md3NoViews} renderLegacyDestination={…}> with the navigation drawer — every destination falling through to the classic repository workspace.

That is identical to what renderClassicApp() does today. The shell existed and rendered before the rewrite; what the rewrite (0f5525ec89, "Render the app through the MD3 shell") added was the eight real MD3 destination views.

So the revert did not require removing the rewrite. Three changes were enough:

Change File
renderClassicApp() asks for the drawer again, not the rail app/src/ui/app.tsx
shellProvidesNavigation={false} — the workspace rail draws its own tabs, Settings and avatar again app/src/ui/app.tsx
InterfaceModeDefault is 'classic' app/src/lib/interface-mode.ts

Nothing was deleted, and nothing needs re-adding

Superseded on 2026-08-15 — do not act on this subsection. It was accurate for main on 2026-08-14. The second MD3 design's destinations, controllers, adapters and navigation rail have since been deleted by 92b3ef9164, and the Material mode setting went with the shell it switched to. navigation='rail' has no caller and no shell to serve. The app is still Material Design 3 — the restored chrome is the earlier M3 design, on the same --md-sys-color-* foundations; see the 2026-08-15 entry for the evidence. The claim that no features were lost still holds — every stranded setting was restored into classic Settings — but it now holds for a different reason. See the 2026-08-15 entry at the top of this file.

The user asked to "use the git commits to add features back once reverted". No features were lost, so there is nothing to add back. Every MD3 destination, controller, adapter, command-palette entry, localized string and the navigation rail itself are all still in the tree. Material mode is one setting away (Settings → Appearance, or the command palette's "Use Classic mode" toggle). A caller passing navigation='rail' still gets the rail.

If a specific feature does turn out to be unreachable from the pre-rewrite chrome, that is a real bug and should be fixed by making it reachable — not by switching the default back.

Work stopped mid-flight, preserved not discarded

Resolved on 2026-08-15. That jer merged as fe1db0dbb5 and was then deleted. Only the GitLab work below survived; the account-switcher work built on the deleted shell and did not. The header-avatar defect it describes is still real and is now the one open item from this entry.

Two multi-agent fleets were running when the revert was requested and were stopped so they could not write into a tree being rewound. Their unfinished work is preserved on the jer wip/stopped-fleets-2026-08-14, commit 064fdab5fd. It is incomplete and unverified. It covers:

Known open items in the reverted UI

  1. Actions is offered where it cannot work. The rail's extra classic destinations are gated by md3ClassicSectionAvailable (app.tsx), but actions is one of the fixed eight in md3Destinations() (md3-navigation-drawer.tsx), so it renders unconditionally. In Classic mode views is md3NoViews, so selecting it falls through to the workspace and RepositoryView.getSelectedSection() silently lands on Changes. The tab it replaced was gated on supportsGitHubActions(). Do not just drop it from md3Destinations() — those eight are the design contract asserted by md3-contract-conformance-test.ts, and Material mode legitimately shows Actions because its real view handles the unavailable case.
  2. Two red tests in the one-click Windows build contract, pre-existing: bounds only printenvz lock metadata and timestamp rounding for native freshness and passes the detected Visual Studio path only to the direct native rebuild. Confirmed at pristine HEAD.
  3. GitLab does not match the designfixed on 2026-08-15 by fe1db0dbb5; all five strings and the endpoint default now match, with the design's masked glpat- token placeholder. The structural note below (bordered three-column grid vs unbordered 460px flex column) is the part that remains open. The original entry, for the record: description says "Connect GitLab.com … instance" where the design says "Sign in to gitlab.com … server"; URL label "GitLab server" vs "GitLab server URL"; default endpoint https://gitlab.com vs https://gitlab.example.com; token placeholder "Token with api scope" vs glpat-••••••••••••••••; button "Add GitLab account" vs "Sign in to GitLab". Structurally the shipped .provider-sign-in-card is a bordered three-column grid; the design is an unbordered flex column, 460px, 48px monospace fields, outlined pill button. The design is a single-state mock — keep the connected-accounts list, the provider error region, the loading state and the disabled-until-valid logic, and add the reduced-motion block and focus rings the mock lacks.

Traps this session paid for, worth not repeating

Repository snapshot as of 2026-08-14 (historical — see the 2026-08-15 entry above)

Checked at 2026-08-14T16:23:33Z against the fetched default branch and GitHub state.

This is a current-state reconciliation only. It does not turn a dated local check into CI, installer, test, or capture evidence, and it does not certify any earlier milestone beyond the evidence that milestone recorded. Every dated handoff below remains historical: open, pending, not claimed, and remaining work describe the boundary at that entry's time. Reconcile a historic item with later commits and the current tracker or release state before treating it as live work.

2026-08-13 — Bound DOM assertions in the agent-session panel test

app/test/unit/agent-sessions-panel-test.tsx no longer passes nullable query results or DOM nodes to Node's object-formatting assertions. The remaining absence checks use boolean identity and the parent/focus checks use assertSameNode, so a failed expectation reports the small mismatch instead of synchronously serializing the jsdom document until it exhausts memory.

Implementation commit: 418e56a592722b72ee9f8ff4f6eb1dec2f8469bb.

Tests, lint, review, captures, and packaging were intentionally not run in this lane.

2026-08-11 — The MD3 shell is assembled, wired and documented

Scope. Assemble the Material Design 3 rewrite into the application chrome, keep the pre-rewrite chrome alongside it, and bring the documentation, the changelog and the site current in the same change.

Commit. 5aa2b582c23de7256dbed0b860b79934f618272e — "Assemble the MD3 shell and keep the classic chrome that came before it". It follows the nine rewrite commits listed in the August 11 ROADMAP entry.

What landed

Verification actually performed

Check Result
npx tsc --noEmit -p tsconfig.json Clean at 5aa2b58, and clean again on the whole tree after the concurrent destination-wiring work settled
ESLint (--rulesdir ./eslint-rules) on touched files Clean except app/src/ui/app.tsx, which reports three errors that belong to the concurrent destination-wiring work, not to this change — see below
Prettier --check on touched files Clean
feature-ledger-test.ts Pass — nothing went missing
md3-contract-conformance-test.ts Pass
docs-browser-bundle-test.ts Pass after regeneration
i18n-test, command-palette-catalog-test, settings-search-test, palette-settings-coverage-test, command-palette-appearance-test 84 pass, 0 fail
script/validate-changelog.ts Pass

Not claimed: no installer was built, no remote CI run was observed, no release was published, and no capture of the new shell exists. The screenshot gallery still photographs the pre-rewrite chrome.

app/src/ui/app.tsx is red on lint, and not because of this change. The three errors are @typescript-eslint/member-ordering on md3MenuPayload and md3SelectedAgentSessionPath (both must be declared before the constructor) and one react/jsx-no-bind on the workflow-dispatch onSubmit arrow. All three belong to the destination-wiring work that was rewriting this file at the same time — that pass added 779 lines to it — and none of them is on a line this change touched. They were left rather than fixed because moving a member declaration in a file somebody else is actively rewriting is how a conflict is manufactured. Whoever lands that pass owns them.

Two defects found and repaired while documenting

Remaining work, named

  1. The carry-over handlers are not wired. buildMd3CarryOverExtensions is not called from app.tsx, so none of the forty-four renders in a menu today. This is not a capability loss: views is md3NoViews, so every destination renders the real repository workspace and build runner, and both legacy surfaces are on by default. Each becomes unreachable only when a destination's MD3 view replaces the legacy surface, so the change that wires a view must supply that view's handlers and check md3UnplacedCarryOverCommands.
  2. Two carry-over entries need a decision. Log match navigation and log group collapse: the contract filters the log rather than dimming it, which may supersede match-stepping. Both survive in runMenu. Neither has been retired, and retiring one requires a retired record in app/test/fixtures/feature-ledger.json with a reason.
  3. Captures. Every gallery frame still shows the pre-rewrite chrome. The capture-coverage contract (ab2374968) enumerates what must be replaced.
  4. The MD3 primitives do not ripple. Md3IconButton, Md3TonalButton and Md3GhostButton render their own <button> and never call attachRipple. Recorded in the ripple feature document as the same open follow-up the toolbar controls already carry.
  5. Uncommitted at handoff. The source-side repairs in item "Two defects" above touch app/src/ui/app.tsx and app/src/lib/i18n-resources.ts, which were being rewritten concurrently by the destination-wiring work. They are in the working tree and deliberately not committed here, so that in-flight work is not swept into a documentation commit. command-palette-catalog.ts, settings-search-catalog.ts and teleport-targets.ts carry the matching registrations and are in the same state, because their new rows reference i18n keys that live in the uncommitted catalog.

2026-08-10 — Land the audited history cache and request-guard repair

Issue #177 shipped the debugging bundle desktop-material-debug-handoff-31d3fd4.zip, audited against 31d3fd4618fddb9d0941cc9ffdbcba02e5299a14. Its Phase 1 source-safe patch is now applied, tested, and merged; the bundle's own patcher refused to run because its reconstructed anchors differ from this tree in whitespace only, so the changes were applied by hand against the real source and reviewed line by line rather than forced through a fuzzy match.

What landed in GitStore:

Two repairs outside the bundle were required to leave the gates green:

Verification on this Linux container, with Node 22.22.2:

The 22 unit failures and 2 script failures are not caused by this change and are not claimed as fixed. They are Windows contracts executed on a Linux host: WSL distribution discovery, UNC and drive-root probing, packaged Dugite path selection, 7-Zip stash export, \-separated ORAS staging paths, the self-hosted runner manager, and update-coming-soon, whose renderer returns null under __LINUX__. The exact same failing set was recorded on a stashed, unmodified tree and after the patch — an identical list, proving no regression. Windows CI remains the authority for those files.

Not verified here: packaged Electron build, Windows E2E, the screenshot and accessibility matrix, heap soak evidence, and push/pull/commit stage timings. Phases 2 through 7 of the bundle's plan — push, pull, and commit latency instrumentation, the memory soak, the visual contract, and the release proof — remain open and need a packaged Windows runtime. Do not read this checkpoint as completing them.

2026-08-09 — Make self-hosted runner risk choice main-process owned

The Actions runner form still warns before setup and requires the two host-risk acknowledgements plus a third acknowledgement for a completed known unsafe finding. That third checkbox is intentionally not an IPC permission. Setup reruns the current workflow and queue audits in the main process, presents a Windows-owned confirmation containing the repository, complete labels, and finding detail, and keeps a receipt only in memory for matching evidence during that one setup operation. A safe recheck erases the receipt; a changed finding requires a new native decision; Start and scheduled trust monitoring remain strict and never reuse any earlier choice.

The manager now audits the complete runner label set—including self-hosted— before creating the managed root or registration, rejects more than 20 custom labels in the UI before a new preflight or setup request, and strips legacy renderer-provided risk fields from persisted runner state on load.

Focused verification passes 94/94 across the runner contract, runner UI, removal-dialog, automatic commit proof, diff-theme, style-token, and lifecycle suites. The root TypeScript check passes, and the complete desktop test command reports 1,008/1,008 discovered files and 8,494 tests with no failures or React unmounted-state-update warnings. A production build run with the repository-pinned Node 24.15.0 produced dist/GitHubDesktop-win32-x64/GitHubDesktop.exe; the build script now owns a short-lived event-loop handle until asynchronous packaging settles, so Node cannot exit while Electron Packager is still copying the app.

Stop-and-handoff boundary: this local handoff intentionally stops before yarn package, installer verification, remote CI, tag, and Release publication. The unpackaged application directory is real build evidence, not a verified Squirrel installer or a remotely published result.

Preservation note: the detached audit worktree that was present during the initial inventory disappeared from disk and from Git worktree metadata during this handoff. Its base commit d82f1fc1603ad3aa55cabdd016fd6b4adac4cce7 is an ancestor of origin/main, but its staged index had uncommitted deletions and is no longer available to inspect or recover. No cleanup command in this handoff removed that worktree; do not describe its disappearance as a verified safe deletion.

2026-08-09 — Complete School mode and settle command shortcuts

School mode is now a complete Windows Appearance surface. It supports a persisted custom name, local salted credential setup and unlock, immediate English-only presentation, hidden language/playfulness controls and related palette/settings-search rows, hidden scheduled language selection, and dim-sum suppression. The renamed value is used by the visible mode surface, command palette, and settings search; deleting the local profile remains the documented reset route rather than a claim of security.

The command palette is bound to Ctrl+Shift+P. Ctrl+Shift+F remains bound to opening the current repository in its folder, with a focused menu regression test covering both accelerators.

Focused verification is 50/50 for the School mode, command-palette, and settings-search changes, and yarn lint:src passes. The required hidden-desktop capture is not claimed: the Lowlevel MCP server executes basic commands but hangs on its required Git preflight. Remote CI and installer-release evidence must still be read from the actual main runs.

2026-08-08 — Keep standard CI Windows-only and remove the 60-minute cap

The standard CI and automatic installer release gates no longer include the Linux TUI. ci-linux.yml retains only platform-neutral lint and supply-chain checks, ci-windows.yml retains the Windows desktop build and packaged E2E jobs, and the installer publisher listens only to CI Windows and uploads only the Windows installer payload. The manual combined Super Express lane is now Windows-only as well; the separate manual TUI workflow and all TUI source and historical verification records remain intact.

All explicit timeout-minutes: 60 entries were removed from the desktop CI, installer, and Windows emergency-release workflows. This removes the workflow cap; it does not claim a remote run is complete until GitHub reports its actual result.

Focused verification: the CI workflow safety and Super Express contract suite passes 31/31. Remote CI for the integrated commit and the resulting release are pending and must be reported from their actual run and asset records.

2026-08-08 — Repair OAuth, public runner preflight, Actions layout, and release details

The Windows desktop source now follows the upstream GitHub Desktop OAuth request shape: the authorization and token exchange omit an unregistered custom redirect_uri, so GitHub uses the callback registered on the OAuth application. The Actions runner manager now uses the rich searchable GitHub account picker, honours the repository's persisted account binding, and permits public repositories only after the immutable workflow audit proves that an untrusted event cannot reach the managed labels. Unknown visibility and unsafe workflows still fail closed.

The Actions run list fills the available row when no workflow detail is open and returns to the resizable split when a run is selected. Release notes now have a separate collapsible section from release metadata, preventing the notes from appearing inside the Release details dropdown. Focused verification passed 130/130 tests, including the OAuth, public-runner, searchable-account, full-width Actions, and release-details contracts. Lint passed; the exact production build and hidden-desktop capture were still in flight at handoff.

Changed source and tests are on main for the requested integration pass. Remote CI, release publication, and the final cleanup proof must not be described as green until their actual results are observed.

2026-08-07 — Opt-in post-clone runner provisioning

Scope: Single interactive private GitHub/GitHub Enterprise clones can opt in to a Windows or dedicated WSL/Linux self-hosted runner. The clone dialog keeps the feature off by default, requires a workflow-author trust acknowledgement, does not expose it for public repositories, and excludes batch/background clones. Dispatcher.clone triggers provisioning only after the new repository is registered and its canonical GitHub remote matches the original selection.

Changed: Clone options, clone dialog and dispatcher, the trusted runner manager, clone styles, focused tests, and repository-management documentation. The main process now independently verifies that the target repository remains private before allocating a local runner, WSL distribution, download, or registration token.

Verification: focused clone option/UI tests pass 8/8, the root TypeScript check passes, and the documentation catalog check passes 19/19. A real runner needs an authorized private repository plus a Windows/WSL host, so no local test claims live registration.

2026-08-07 — Harden the Windows self-hosted runner manager

The Windows Actions view now treats a managed GitHub Actions runner as one repository-scoped, exact-account operation. Public or unknown-visibility repositories are blocked. For a private repository, setup and every later start prove that private-fork pull-request workflows are disabled, resolve one default-branch commit, audit every workflow from that immutable commit, and scan complete stable pending-run and job inventories for any labels that could claim the runner. The setup-form result is bound to its current account and proposed labels; Start deliberately performs a fresh audit against the runner's live labels.

The main process keeps one-time registration and removal tokens in memory and keeps Windows registration tokens out of command-line arguments. It never uses runner replacement, rejects duplicate or inconsistent paginated inventories, verifies the official runner package digest, and waits for the exact new registration and complete label set to be online before reporting readiness. Process ownership, process-tree termination, stopped-state postconditions, exclusive operation leases, a lifecycle journal, restart reconciliation, and stable GitHub absence checks now cover setup, start, stop, cancellation, scheduled trust rechecks, removal, and shutdown. Ambiguous registration or local metadata retains recoverable state instead of guessing that cleanup succeeded.

The UI exposes contextual setup and start preflights, both security acknowledgements, runner-specific accessible controls, cancellable in-flight operations, and an irreversible removal dialog that keeps exact progress open after submission. Suggested labels stay within 64 characters without losing the platform suffix. Linux-in-WSL management is visibly disabled until the app can prove in-distribution process-group cancellation; WSL is not presented as isolation from the Windows host.

Focused local verification on the current source passes 48/48 tests: app/test/unit/self-hosted-runner-contract-test.ts is 38/38, and app/test/unit/ui/self-hosted-runner-manager-test.tsx is 10/10. The command was:

node script/test.mjs app/test/unit/self-hosted-runner-contract-test.ts app/test/unit/ui/self-hosted-runner-manager-test.tsx

The broader Windows app suite, exact production build, hidden-desktop runtime exercise, live runner registration, and remote CI verdict remain pending. The current source is not yet a published or remotely verified result. Detailed behaviour and recovery guidance are in docs/features/integrations/self-hosted-runner-manager.md.

2026-08-07 — Repair Windows CI, release contracts, and Pages validation

Repair commit fef8e7e5574d88dbd2f5720a2c0d5799a44032bb restores the Windows CI setup and Super Express release contracts, regenerates the documentation catalog and 279-article hub count, gives reruns a unique package version, and replaces the AI merge editor's inaccessible hidden input buffer with one controlled native text area that exposes the complete document and submits one form value. Hardening commit 4954a74529 adds fail-closed coverage for changed, missing, and non-ENOENT unreadable dependency manifests.

Local evidence before publication: the full script gate passed 219 with 0 failures and 2 expected skips; the six originally failing unit files passed 85/85; the final AI editor pair passed 15/15; the release and manifest contract pair passed 11/11; and the lifecycle-accurate nested app install completed in 94.56 seconds without changing either app manifest. Adversarial mutations proved the exact runner labels, token chain, run-attempt version input, active shell programs, native editor, and every manifest failure mode can each turn their own contract red.

The GitHub Actions, Pages, and direct Windows manual-release results remain pending until these commits reach main; this handoff does not claim a remote verdict or a published Release in advance.

2026-08-06 — Repair the blank Windows startup renderer

The packaged Windows renderer failed before React mounted with ReferenceError: __webpack_module__ is not defined. The cause was the Node-oriented @github/copilot-sdk ESM graph being concatenated into the renderer through CopilotStore; the empty root and hidden-until-ready window then presented as a blank white launch. app/webpack.common.ts now externalizes the SDK, and script/build.ts fails before packaging if either renderer bundle contains the undefined binding.

The focused contracts pass 14/14. A production Windows build completed with the external SDK present. The exact dist/GitHubDesktop-win32-x64/GitHubDesktop.exe launched on the hidden desktop, reloaded through CDP with readyState=complete, one populated #desktop-app-container child, and no captured runtime exceptions. The genuine Lowlevel MCP capture is tracked at docs/assets/screenshots/material-blank-startup-fixed-20260806.png, 960x660, SHA-256 00D8BD6FCE0EFA10107523BF92BEA54E80DDA6ED66B8E3700B21297D6CBF2A82, and shows the first-run Desktop Material surface. The detailed behavior, failure modes, security notes, and verification record are in docs/features/quality-and-reliability/renderer-startup-bundle-safety.md and .codex/run-manifests/2026-08-06-blank-startup.md.

The source branch still needs its commit, dew, default-branch integration, and remote CI result before this handoff is complete.

2026-08-06 — Verify Super Express on the self-hosted pool

The pure self-hosted Super Express path now has remote runner evidence. Run 31064587087 <https://github.com/Ding-Ding-Projects/desktop-material/actions/runs/31064587087>_ at 60f32baf76 completed preparation and Linux TUI packaging on linux, then ran the Windows lane on CLAUDE. The Windows lane passed the Git Bash preflight, AllSigned-compatible PowerShell helpers, uv-managed Python 3.11, the pinned Yarn shim, setup-node's Yarn cache probe, dependency installation, and reached Build production app. GitHub's runner control channel cancelled the job at 2026-08-06T02:26:44Z before Package Windows.

Run 31065485291 <https://github.com/Ding-Ding-Projects/desktop-material/actions/runs/31065485291>_ at 3fe381f5f9 repeated the same self-hosted-only path on COMPUTER; Linux TUI passed, the Windows setup and dependency stages passed, and the Windows production build started. The runner control channel cancelled it at 2026-08-06T02:46:25Z, again before Package Windows. Both runs finished cancelled, not success; both used publish=false, so no Release was created. Self-hosted placement and prerequisite repair are verified, while a completed Windows package/artifact and combined Release remain unverified because the external cancellations occurred before packaging.

2026-08-06 — Scope run cancellation to Super Express

Ordinary push-triggered CI, installer, and Pages workflows continue to use unique run-and-attempt concurrency groups with cancel-in-progress: false, so a new push cannot cancel an earlier validation or publication run. The three Super Express workflow files are the only exception: each uses a ref-scoped cancel-in-progress: true group. A newer Super Express dispatch can therefore free the scarce self-hosted runner from an obsolete release, while normal push runs remain independent. The focused workflow safety tests now enforce this allowlist and the group scope.

2026-08-06 — Bootstrap every self-hosted Windows dependency shell

The self-hosted Windows dependency setup now selects the requested Node.js version before the repository-pinned Yarn bootstrap runs. The bootstrap copies vendor/yarn-1.21.1.js beside two small launchers under RUNNER_TEMP: a Windows yarn.cmd launcher and a POSIX yarn launcher for Git Bash. The following Git Bash step converts the temporary directory to an MSYS path, marks the POSIX launcher executable, and fails if bare yarn resolves anywhere else. This covers both PowerShell/cmd actions and the Bash cache/install steps, including Unicode and space-containing temporary paths.

The focused CI contract test passes 2/2. A clean local node vendor/yarn-1.21.1.js install --frozen-lockfile completed in 84.58s, and an isolated probe selected Node v24.15.0, returned Yarn 1.21.1 from both launchers, and resolved Git Bash to the temporary POSIX launcher. The remote Super Express run after this change is still the required final verification; a queued, failed, or cancelled run must not be reported as green.

2026-08-06 — Keep Super Express scheduling self-hosted-only

The latest self-hosted-only release dispatch reached the registered Windows runner, but its first prerequisite failed because that machine had no WSL distribution installed. The exact remote failure was Windows Subsystem for Linux has no installed distributions, so the Windows package never reached dependency setup or compilation even though the Linux package passed.

The explicit release contract keeps every Super Express job on the registered self-hosted pool: linux handles preparation, Linux TUI packaging, and publication, while a registered Windows x64 runner handles the Windows package. The direct reusable Windows and Linux TUI workflows use the same static [self-hosted, Windows, X64] and [self-hosted, Linux, X64] labels. A busy or unavailable local runner queues or fails the release; it never moves to a GitHub-hosted machine. uv python install 3.12 remains responsible for the Linux TUI's pinned interpreter, and self-hosted Windows setup uses uv for Python 3.11 after the Git Bash preflight.

The workflow contract test asserts the static self-hosted labels and rejects hosted targets, runner-selection, and cloud-fallback shapes. Focused workflow tests, YAML parsing, actionlint, Prettier, and git diff --check are the local gates; the next remote Super Express run is the required post-fix evidence.

2026-08-05 — Multi-remote fetch sync

The ordinary Fetch path now uses every configured remote when a repository has more than one. A single-remote repository retains the existing Fetch <remote> copy and focused selection. Multi-remote repositories expose Fetch all remotes in the toolbar and dropdown, with a status description that names the expanded scope. The store keeps current/default/upstream remotes first and then adds the remaining configured remotes once each.

Changed implementation and test files:

Focused verification is 19/19 tests passing. The exact Windows production build completed with packaging skipped. The real hidden-desktop renderer displayed Fetch all remotes and Fetch the latest changes from every configured remote for a two-remote fixture without clipping in the inspected frame. The unmodified development renderer still logs its existing __webpack_module__ is not defined startup error, so the visual probe used a temporary CDP startup shim and does not claim packaged-release proof. A later capture-only DOM-removal attempt triggered the disposable app's crash boundary; that contaminated frame was discarded. Documentation is in docs/features/repository-management/multi-remote-fetch-sync.md with index, README, roadmap, and feature-list references.

On the merged linked checkout, the first focused test invocation found the declared windows-argv-parser native output missing from app/node_modules. Running yarn install --immutable rebuilt that vendor dependency; the same focused command then passed 19/19 without source or lockfile changes.

2026-08-05 — Harden the Windows dependency cache and preserve Team View styling

The CI dependency-cache hit path now validates the actual Electron runtime, targeted Copilot package, and react-confetti ESM entry for the current runner and architecture before reusing an installed-dependency cache. The final dependency verification checks the same react-confetti runtime file, so a cache containing only package manifests cannot skip installation and then fail later in the renderer build.

The Launchpad Team View selectors now live in the shared .launchpad-view scope rather than only inside the max-width: 520px media query. Team View therefore retains its layout and state styling on desktop as well as narrow Windows windows, while the Sass-safe parent-selector structure remains intact.

Local verification is 32/32 focused CI, dependency, workflow, and Launchpad tests, passing ESLint type-checking, and git diff --check. A fresh production renderer compile after this styling and cache follow-up is still pending; remote Windows/Linux runs remain queued.

2026-08-05 — Settings account cards keep one active identity across providers

Settings → Accounts was using the first card in each provider section as its active marker. A GitHub.com account and a GitHub Enterprise account could therefore both appear active, while neither exposed Make active. The surface now compares every account with the single global accounts[0] identity and applies the same predicate to GitHub.com, Enterprise, GitLab, and Bitbucket cards. Clicking Make active updates the controlled account order, so the target row becomes active and the previous row becomes actionable. Explicit repository account bindings remain authoritative.

Source commit 7a757f5b75d627e1b4b7ae5ed47b2181638fefa0 contains the fix and regression test. Focused account/store/routing/UI verification passes 39/39; targeted ESLint, Prettier, and git diff --check pass. The required Lowlevel production build has not yet returned because its shared endpoint is servicing another long-running build. No hidden-desktop capture or runtime success is claimed until that route is healthy.

2026-08-05 — Account-aware repository transfer (verification in progress)

The Windows Electron app now has an account-aware Transfer repository workflow. It can add another GitHub.com or GitHub Enterprise identity through the existing sign-in dialog, choose a personal or organization owner, keep or rename the destination repository, and choose privacy. Full history uses a temporary bare clone to publish every local branch and tag. Clean state creates one root snapshot commit, retains the previous tip under a local refs/desktop-material/transfer-backups/ recovery ref, and publishes only the current files. Both routes verify the destination tip before retargeting origin and preserve the source as upstream when needed.

The entry points are the Repository menu, repository-list context menu, Command Palette, and Repository settings → Remote. The transfer dialog requires two independent confirmations plus a full-range authorization slider, and displays real checking, creation, preparation, publication, retargeting, and completion progress. Focused direct Node contract tests pass 7/7. Targeted ESLint passes, and the changed-path TypeScript check reports no diagnostics in the transfer files although the repository-wide command exits on existing TypeScript 6 findings. The exact Windows production build reached the full renderer/main bundle after the missing local file-package outputs were rebuilt, but remained nonzero on four existing TypeScript 6 errors in dds-converter.ts, two fixture typings, and ui/index.tsx; it did not emit a runnable out/main.js. The repository-wide test harness remains blocked before test discovery by the malformed whatwg-encoding dependency payload, so hidden-desktop runtime evidence is not claimed.

Implementation commit 6c3a4ec8297e79226968a89e3232ba281c539357 contains the feature, tests, and documentation update. Hardening commit 5e96aad79e82bc597b5c1233fccd17c0b37ce7fa preserves known-private defaults and verifies the exact destination tip before retargeting. Verification and changelog commit 8ac2bf5cfce2f4645fa4ead4e7cf05e23cd59478 records the run manifest and current evidence.

2026-08-05 — Make Super Express release self-hosted-only

The Super Express Release path is now deliberately self-hosted-only. The combined dispatcher runs preparation and publication on the registered Linux x64 WSL runner, the Windows package runs on [self-hosted, Windows, X64], and the Linux TUI package runs on [self-hosted, Linux, X64]. The direct Windows and Linux TUI recovery workflows use the same static labels. Hosted selectors, ubuntu-latest, windows-2022, cloud fallback jobs, and runner-inventory branching were removed from all three Super Express workflow files. If a required local runner is offline or busy, the release queues or fails rather than silently consuming a cloud runner.

Because the Linux runner is Debian 13, the dispatcher publisher also installs the pinned uv tool and Python 3.12 through uv python install 3.12; TUI version discovery uses uv run --python 3.12. This keeps the pure self-hosted path independent of the actions/setup-python distribution manifest that previously lacked a Debian 13 Python 3.12 entry.

The focused workflow contract now asserts that all three workflow files contain only the expected static self-hosted labels and no hosted target or fallback selector. Pure self-hosted run 31063281760 <https://github.com/Ding-Ding-Projects/desktop-material/actions/runs/31063281760>_ at eb5a769c51 proved Prepare exact release target and the Linux TUI package on runner linux; the Windows package reached runner COMPUTER but stopped before its build because shell: bash resolved to the Windows WSL launcher, which reported that no WSL distribution was installed. The Windows action and shared setup action now prepend the installed Git Bash directory to GITHUB_PATH, and fail with a direct prerequisite message if Git or Git Bash is absent. That repair is in the next pushed revision; no Release was created because this run used publish=false.

Follow-up pure self-hosted run 31063591401 <https://github.com/Ding-Ding-Projects/desktop-material/actions/runs/31063591401>_ at 4a9afbbbf7 proved preparation and the complete Linux TUI package on linux, and reached the Windows build on CLAUDE with Git Bash selected. It then failed in the shared actions/setup-python@v6 step while installing Python 3.11 into the self-hosted toolcache (Error happened during Python installation). The next repair keeps hosted runners on setup-python, but uses pinned uv, uv python install 3.11, and its discovered interpreter path for npm_config_python on self-hosted Windows. This run also used publish=false, so it created no Release.

2026-08-05 — Fix Super Express workflow startup planning and repair build prerequisites

The Super Express dispatcher keeps preparation and publication on ubuntu-latest, while its combined packaging jobs and its two direct reusable packaging lanes each check the repository runner inventory on a hosted selector. When an online, idle matching runner is available, exactly one static conditional job uses [self-hosted, Windows, X64] or [self-hosted, Linux, X64]; otherwise the lane uses windows-2022 or ubuntu-latest. The earlier dynamic self-hosted fallback tried to build a multi-label runs-on value from job outputs; GitHub marked those dispatches startup_failure before creating a job, so no runner log existed to diagnose. The combined dispatcher now inlines its static selector/build jobs instead of calling the reusable workflows, because the caller itself remained planner-invalid after the lane repair. Static targets retain schedulability while allowing the requested self-hosted-first behavior and keeping the zero-test emergency lane and direct artifact-only lane behavior unchanged.

The workflow contract test now asserts the fixed labels and rejects the dynamic runner-selection shape. The setup action now checks cached React JSX runtime and react-confetti files before use; an incomplete cache automatically returns to the bounded dependency install path. The source Sass error at app/styles/ui/_launchpad.scss:278 was corrected by nesting the team selectors under .launchpad-view inside the media query, so Sass can resolve every &__… selector against its real parent.

Local verification is 9/9 focused CI/dependency/workflow tests, YAML parsing, Prettier, and git diff --check. The full production compile was attempted with the repository-pinned TypeScript and a supported local Node 24 runtime, but the webpack process exceeded the four-minute local bound without returning a client verdict; no production-build success is claimed from that attempt. The earlier cloud Windows fallback run 31060316032 was red at the Sass error and also reported react/jsx-runtime resolution from its incomplete dependency cache. The cache repair and Sass correction address those reported causes.

The matching Windows and Linux self-hosted runners were online and idle during inventory checks. Follow-up combined dispatches 31060759025, 31061020998, and 31061157152 created the selector and static build jobs but were cancelled by an external concurrent-run sweep before any selector or build step ran. Self-hosted execution and a post-fix remote green build therefore remain unverified; no Release was published by these publish=false dispatches.

2026-08-05 — Close remaining Windows TypeScript build gaps

The merged default-branch tree exposed five additional TypeScript diagnostics across three seams after the dependency and stylesheet failures were corrected. The provider triage label switch now handles the self-hosted account provider. The self-hosted OAuth error path now captures and validates the active authentication state before updating it, so a nullable store state cannot be spread into an invalid sign-in state and a callback race cannot overwrite a replacement flow. The SignInStore regression fixture now records callback accounts in a typed list and asserts exactly one authenticated account before checking its provider, endpoint, and login.

Local evidence for this follow-up is 41/41 focused tests across SignInStore, provider triage, and CI workflow safety; passing ESLint type-checking; and an isolated production renderer compile with 0 Webpack errors. The compile also emitted only the existing Sass deprecation warnings and no Koffi, JSX-runtime, Sass parent-selector, or TypeScript errors. Fresh remote Windows and Pages verification for the integrated fix is pending.

2026-08-05 — Restore Windows production build compatibility

The final Windows verification of the retired tooling correction reached the production compiler but failed on three dependency and stylesheet edges. The application now pins @github/copilot-sdk back to 1.0.5, which removes the Koffi native dependency introduced by 1.0.8; the supplied dependency-install trace showed the retrying native failure while Koffi's optional platform packages were being resolved. The version-specific 1.0.8 declaration shim is removed with the rollback.

react-confetti 6.4.0 keeps its React 16 JSX-runtime support, but its ESM entry asks Webpack for react/jsx-runtime without an extension. The common Webpack configuration now aliases that exact request to the installed react/jsx-runtime.js file, preserving strict ESM resolution for other dependencies. The Launchpad Team View styles are also nested under their .launchpad-view parent so Dart Sass no longer rejects a top-level & selector. The CI workflow guard now matches the integrated removal of the retired agent-only submodule instead of requiring a stale .gitmodules block.

Local evidence for this correction is 3/3 dependency compatibility tests, 13/13 Launchpad tests, 12/12 CI workflow-safety tests, passing ESLint type-checking, and an isolated production renderer compile with 0 Webpack errors. The earlier full production compile showed the other five compilers finishing successfully; the renderer's two reported errors are covered by the isolated rerun. Fresh remote Windows and Pages verification for this correction is pending.

2026-08-05 — Keep private tooling out of hosted CI checkout

The first remote Windows verification after the dependency repair reached the runner but failed while recursively cloning vendor/lowlevel-computer-use-mcp: that submodule is agent tooling whose history is not available to the hosted workflow token. The desktop build does not consume it; the three public product submodules remain available. The first correction used update = none to keep recursive checkout from attempting the unavailable agent-only clone. The subsequent integration at 883c1b6c6b01ca1371d590d2971e756ff5ed9039 removed that retired gitlink and its registry entry entirely, leaving only the three public product submodules in .gitmodules. Fresh remote verification of that integrated correction is pending.

2026-08-05 — Preserve dirty work while creating a destination worktree

The dirty branch-switch dialog now offers Leave my changes here. It closes the decision dialog without stashing or checking out the dirty source, opens the existing Add worktree flow with the destination branch and suggested name prefilled, and leaves creation and switching until the user confirms a path.

Verification

GitHub integration and remote CI evidence are recorded after the source and documentation commits land on the default branch.

2026-08-05 — Direct Super Express lane dispatch actions

The Windows and Linux TUI Super Express packaging workflows now each expose a manual workflow_dispatch action in addition to their reusable workflow_call entry point. Direct dispatches are restricted to main, default to the dispatched commit, validate the same packaging payload, and upload an artifact-only recovery result. They never publish independently, preserving the combined dispatcher's one-Release update/bootstrap contract.

2026-08-05 — Restore CI-compatible dependency pins

The Dependabot upgrades to TypeScript 6.0.3 and @types/request 2.48.13 made the Windows setup action fail before the desktop tests could start: TypeScript 6 rejected the repository's legacy project layout, and the newer request declarations introduced an incompatible tough-cookie type graph in the vendored compile. The dependency manifest and lockfile now restore TypeScript 5.8.2 and @types/request 2.0.9, the versions compatible with the current setup action and vendor sources. The same dependency group also carried tsx 4.23.1, which transforms JSON imports incorrectly under the test runner, and @types/react-virtualized 9.22.3, which removed the Grid.propTypes declaration used by the app; those are restored to 4.19.3 and 9.7.14 as well.

The same correction refreshes the Pages Docs hub from 254 to 264 rendered articles using node script/sync-site-doc-counts.mjs; the committed check now agrees with the current docs/ tree. Remote CI verification is pending for the resulting default-branch commit.

2026-08-05 — Cross-provider account switching correction

The rail account switcher was calling the real promoteAccount path, but the account store immediately re-sorted a selected GitHub Enterprise account behind GitHub.com. Because the rail derives its active indicator from accounts[0], the UI appeared to switch and then silently returned to the previous account. The store now preserves the promoted account at accounts[0] across providers, sorts only the remaining accounts, and persists that order for the next launch.

Verification

2026-08-05 — Super Express packaging lanes parallelized

The manual Super Express dispatcher now keeps one combined immutable Release but runs Windows x64 and Linux TUI packaging in separate reusable workflows. The Windows lane owns the desktop dependency cache, build, Squirrel payload, portable ZIP, and installer assets on windows-2022. The TUI lane builds on ubuntu-latest with uv build and locked runtime constraints, and carries the bootstrap and installer scripts as executable assets. A single publisher downloads both lane artifacts so the shared Squirrel latest feed and TUI bootstrap URL cannot land on separate partial Releases.

Local proof for this change is 16/16 application workflow-contract tests, 10/10 TUI installer-contract tests, passing Prettier/YAML parsing, and sh -n success for both checked-in TUI shell scripts. No remote Actions run or Release is claimed by this handoff entry yet.

2026-08-05 — Partial Releases no longer steal the Windows update feed

Commit a4ce485037138f24d7534452a861a1fb7749beeb hardens .github/scripts/promote-current-release.sh: a published Release may own the Windows Latest alias only when it includes both the Squirrel RELEASES manifest and a *-full.nupkg package. This prevents a newer Linux/TUI-only partial Release from making releases/latest/download/RELEASES return 404 to the Windows app.

Verification

Remote state

The fix was merged into main as 6f5cf66c30, with source commit a4ce485037138f24d7534452a861a1fb7749beeb and documentation commit 96fcc0a2d14cd2f791fd51f6b470ae7f225695aa. The integrated tree passes the focused suite with the repository's pinned Node 24.15.0 invocation: 29 passed, 0 failed. The repository wrapper's additional --conditions=import flag is not used for this proof because its current tsx loader path changes the whatwg-encoding JSON import shape before the test can start.

The dewed integrated tip was bc63986119e2c71cc28d98e1465c9c8501c25f58. Its current-SHA remote evidence is recorded precisely: Deploy Pages run 31056983826 passed; CI Windows run 31056982528 failed because the Windows jobs could not clone the configured codingmachineedge/lowlevel-computer-use-mcp submodule (repository not found), and the follow-on production step could not find cross-env. The dependent Build Installers / Express Release run 31057063196 was blocked because its trigger was workflow_dispatch, not this repository's main push CI, so no Release was published. These are external CI/submodule blockers; the updater guard's local tests and live HTTP feed proof remain verified.

The enabled GitHub Wiki recovery note was committed as 34cb7157716cd846117ad9e86fe876dd70c389b2 and is now published on its master branch. An initial publication attempt used a stale Git credential and returned HTTP 403; gh auth setup-git --hostname github.com refreshed the credential path, after which the exact commit landed and the Wiki checkout is clean.

2026-08-05 — Actions job-log transient 404 recovery

This Windows Electron fix was developed in the new linked worktree branch codex/job-log-404-fix at commits 33f54a69825d97083dc8f0b1fb134b353e9686ca and e85cf787e3aea81ac28679f00b3b0201507af133, and the integration checkout carries those commits into the default branch. GitHub can briefly return HTTP 404 while a valid completed-job log archive is being prepared. The main-process transfer now retries only that API response after 250/750/1,500 ms waits, restarts from the original API endpoint for a fresh signed redirect, and keeps the bearer header off cross-origin blob requests. A follow-up audit separates the retry count from the redirect-hop budget, proves cancellation during backoff prevents another fetch, and asserts the blob-404 request has no bearer header. The log viewer explains the provider state and exposes Retry and Open on GitHub; its test checks the link destination and external activation. The unrelated Launchpad Sass brace correction is included because it was the build-blocking syntax error discovered while producing the required renderer artifact.

Verification receipts

The task-branch workflows were cancelled by workflow concurrency, so no remote green result is claimed here. Release publication remains an external follow-up after the default-branch workflow produces its verified installer.

2026-08-04 — Live Material renderer proof and startup cleanup

The design reference is now verified against the real production Electron renderer rather than only the static design/ file. Commit ab8c26d7535c9861f81b761e73798d1363bd78e1 also fixes a startup race in app/src/ui/repository-settings/repository-settings.tsx: asynchronous initial settings reads now begin after mount and stop updating state after unmount. That removes the React warning that appeared when the settings surface closed while its reads were still pending.

Verification

Remote checks and boundaries

Run 30928494987 is still in progress. Its Lint job reports four pre-existing formatting findings (.act-super-express-event.json, .github/workflows/build-installers.yml, app/test/unit/site-accessibility-test.ts, and tui/src/desktop_material_tui/assets/changelog-catalog.json), while TUI jobs have also failed; Windows x64/arm64 and CodeQL are still running. The changed renderer file passes its targeted ESLint check. The TUI scope is explicitly closed, so those unrelated TUI failures are recorded rather than changed in this Windows Electron milestone.

The follow-up run for 0969cbbb76ed18fe4f6d79d33ad95b6ae96a38d9, 30929478484, has the same Lint/TUI failures. Windows arm64 also built and uploaded its artifact, then failed Run script tests because the committed documentation hub catalog and index are stale relative to the already-merged TUI articles. Running yarn generate-docs-hub-catalog followed by yarn test:script passes locally (214 tests, 213 passed, 1 optional skip), but the generated diff is entirely for the closed TUI documentation surface and is intentionally not carried into this Windows Electron task. Windows x64 and E2E remain remote checks in progress at this handoff update.

The local package/signing step was not part of this proof and no signing policy was changed. No release is claimed by this handoff entry.

CI formatting follow-up

Commit a89900dd419e4dd78031516dea10c4edb1df9b38 formats the two installer workflow TUI_CONSTRAINTS_NAME environment assignments reported by the remote Lint job. It is a formatting-only change: installer behavior and the intentional skip-signing contract are unchanged. File-scoped Prettier and the Git whitespace check passed, and the commit is on main.

The remaining TUI catalog formatting and stale TUI documentation output are not changed because the Windows Electron task keeps the TUI scope closed.

Desktop lint correction

Commit a9c69adfde9bb97cd03e48a99783ff6e6a5a87f1 formats only the desktop app/test/unit/site-accessibility-test.ts. Its focused accessibility contract suite passes 11/11, and file-scoped Prettier passes. The commit is on main and is covered by CI 30932145369 and Cheap LFS 30932145377, which were queued behind earlier Windows/TUI work at this handoff update. The remaining formatter finding is the closed-scope TUI catalog.

2026-08-04 — Search registry and changelog catalog correction

Commit 77c7b1ebc6cee54c9e0b1febf5a6b67496477891 registers the repository settings tab surface in the collection search registry, updates its appearance contract test for the descriptor-based UI, and aligns the Pages screenshot gallery contract test with the tracked CSS. The focused suites pass 39/39; Prettier and the Git whitespace check pass.

Commit 0b004744bb3f228651fdc8a2c693d57d9f933da1 restores the 12 newest 3.6.3-material22 records already present in changelog.json and updates the catalog count to 4151. The changelog suite passes 24/24, with one explicit release-tag date skip because this checkout has no matching release-* tags; historical dates were not rewritten from incomplete local metadata.

The full script suite currently reports 214 tests: 210 passed, 3 failed, 1 optional skip. All three failures are the already-closed TUI documentation scope: a stale committed docs-hub catalog and two missing Linux TUI pages. No desktop script contract failed. CI run 30935849771 is queued; no release or installer success is claimed here. The Squirrel Windows packaging job continues to skip signing as required by the current contract.

2026-08-03 — App fixes: repository list, Cheap LFS, local Actions, CI

A session of defect work across the app and the test harness. Everything below is on main and dewed; the one item that is not finished is named at the end rather than left for someone to discover.

The Repositories list rendered nothing while holding repositories. SectionList tested one value and constructed another: the capability guard asked about the global ResizeObserver while the constructor used window.ResizeObserver. Whenever the two disagreed the guard passed and new threw on undefined — and a throw in a component constructor unmounts the subtree rather than degrading it, so the panel came up empty instead of falling back to an unobserved list. Fixed in bcd832d40e; the guard now asks whether the value it is about to construct is callable. A separate change gives the genuinely-empty case real copy and the three creation paths as operable buttons, because the old empty state apologised for failing to find a repository the user had never searched for.

Cheap LFS aborted a large commit on a momentary lock. "Could not canonicalize the repository root" turned out not to be about the root at all: probing that exact repository afterwards canonicalizes cleanly. On Windows realpath must open a handle to ask for the final path, so it queues behind virus scanners, indexers, and Git's own working-tree writes; during an 18,750-file commit that contention is routine and lasts milliseconds. 0612c7c538 retries the transient codes (EACCES, EAGAIN, EBUSY, EIO, EMFILE, ENFILE, EPERM, UNKNOWN) and excludes ENOENT on purpose — a repository that is not there is not busy. It still fails closed, and the reparse-point checks still run on whatever comes back; only the waiting changed.

Local Actions runs work without a manual install. act stops on an arrow-key menu asking for a default image when it has no platform configuration; spawned from the app its stdin is not a terminal, so the console read fails and Windows reports Incorrect function — an error that never mentions images. d023f5ef92 passes the platform mappings up front. act itself is now installed automatically into the app's own data directory (ccad989359), user-scoped, no elevation, and a PATH-resolved copy always wins. Two things worth keeping: the asset spellings are the release's own (x86_64, not x64), and extraction must use the absolute System32 bsdtar — where Git for Windows or MSYS is installed their GNU tar shadows it and reads C:\... as host:path, failing a purely local copy with Cannot connect to C: resolve failed.

Settings tabs are no longer positional. The RepositorySettingsTab enum was defined to equal the TabBar's child indices, with a note asking integrators to keep them contiguous. That holds only while the list is a fixed run of children — the moment a filter removes earlier rows, clicking one opens whichever page sits at that number. eb7fadc805 gives each row a descriptor carrying the tab it selects and resolves clicks through the filtered list, then adds the search field the shared rules require. The open tab stays listed even when it does not match, so the strip can never empty and strand a selection the panel is still rendering.

CI: memory exhaustion was real, and it was not the tests. node --test runs one worker per file and V8 sizes each worker's old-space from the machine's memory, so four workers on a 16 GB runner were entitled to the whole machine before git or Windows asked for anything. Windows charges reserved commit, so it hit the limit long before the tests wanted the memory, and the damage landed as scattered, unrelated-looking failures: "paging file is too small", "Not enough memory resources", spawn UNKNOWN, git "Out of memory", V8 "Array buffer allocation failed". b02a3ff611 bounds per-worker heap and derives concurrency from memory as well as cores. Verified: none of those strings appear in the CI unit log afterwards.

Testing notes worth reusing. Module mocks in a .tsx test must be followed by require, not a static import — the file compiles to CommonJS, so require resolves at call time and picks the mocks up while a static import hoists above them, and top-level await import is a parse error under that output format. Dialogs render inside a <dialog> element that jsdom treats as closed, so role queries against them need { hidden: true }. Stub git per test file rather than in the shared globals: several suites run git against real repositories on purpose and a global stub disarms them silently.

Open: agent-sessions-panel-test.tsx is pathologically slow

Two tests that complete in ~44 ms on an idle machine take 250–500 s, and the file fails. This is not caused by the worker heap cap or by the section-list repair — both were ruled out by substitution (restoring the pre-repair section-list still reproduces it; so does raising the heap back to 4 GB), and it was already taking 127 s in CI before either landed. Do not re-test those two.

DOM accumulation is ruled out too: rendering the panel repeatedly leaves 13 elements and one body child every time, so Testing Library cleanup is working and the queries are not scanning a growing document.

The per-test ceiling cannot help here, and the reason is worth knowing before anyone retries it: node --test can only time a test out between awaits, and these tests are synchronous. Whatever is burning the time is blocking the event loop, which also means the cost is inside a synchronous call — a render or a query — rather than in anything being waited on.

a2c25bf537 added a 120-second per-test ceiling so a wedged test names itself instead of the batch failing at file level with nothing to act on. It has not had the effect hoped for here: the run still ends at file level rather than naming the two tests, so the next step is to establish why --test-timeout is not firing for them before spending more time on the underlying slowness.

Desktop Material — Active parity handoff

2026-08-03 — Integrate-and-clean pass, and the Linux TUI is back on main

The TUI scope was reopened by the user during this session, so the revival branch was integrated rather than kept aside. main now carries it.

What was preserved before anything was touched

The linked worktree at desktop-material-linux-tui-revival was holding 20 modified and 39 new files, all under tui/ — uncommitted, which is the only kind of work a wiped directory takes with it permanently. Committed first as dbbb3431c8, before any merge: multi-account sign-in with keyring-backed secrets, a bounded agent surface (CLI, client, access policy, local server) with its Postman collection, GitLab and Bitbucket provider clients, Build & Run with local AI repair and Ollama, automation, an audio system with bundled melody cues, a gh push fallback, Help and Changelog screens, settings palette search, and the Section 6 advanced Git and workspace surfaces — 309 files, +17,694 lines including roughly 4,000 lines of tests.

That commit is a checkpoint, not a verified release. The TUI suite has not been run against it, so the parity contract is claimed rather than proven until it has. This is the first thing a successor should do.

The one merge conflict, and why it was not resolved by picking a side

tui/contracts/parity.yaml's status_summary is a derived number. The branch claimed 89 rows not_yet_available, main claimed 135, and the merged row set actually holds 91 — so neither side was right, and taking either would have published a total the file itself contradicts. The contract was regenerated from its source of truth (tui/tools/generate-parity-contract.mjs, which reads docs/readme-tabs/complete-feature-list.md plus the overrides). It produced the same counts a hand recount did, and fixed 26 further lines a hand resolution would have left stale. Merge commit 05528e87d1; main then fast-forwarded.

The site's count guard earned its keep

Merging the TUI branch added four docs/**/*.md articles, and script/site-dc-pages-test.mjs immediately failed with "the Docs hub advertises article counts that docs/ no longer matches". One node script/sync-site-doc-counts.mjs and the site went from advertising 249 articles to the real 253. That is exactly the drift this guard exists to catch, on the first merge after it shipped.

Deleted, kept, and left alone

Item Outcome
codex/revive-linux-tui + its worktree Deleted after its tip was proved an ancestor of the dewed origin/main
origin/claude/pensive-visvesvaraya-e86ef2 Deleted — proved already an ancestor of origin/main
Nine dependabot/** branches Kept. Each backs an open pull request (#137–#145). Deleting them closes those PRs, and they are neither agent task branches nor merged
Stashes None existed
app/test/unit/agent-sessions-panel-test.tsx Left uncommitted. Another agent's MARK … timing probes, added to diagnose a wedged test. Debug instrumentation, not work — committing it would ship console.log into the suite, and reverting it would destroy their investigation
.act-*, .codex/repo-list-* Left uncommitted, and now ignored. They kept reappearing as untracked noise in this shared checkout and being swept into unrelated commits; the patterns now cover the family

Concurrency, again

Three separate agents committed into this working tree during the session. One of them swept an earlier task's staged git rm deletions into its own commits (ba452e4017, dbea7be82f) and dewed them, briefly leaving main publishing the old homepage with its stylesheet and both Cheap LFS pages deleted. Stage explicit paths, never git add -A, and re-read git log before committing — the index may not still be yours.

2026-08-03 — The published site is one Material Design 3 component

Commit 80d05e73b881d6b2cd4da4f5a99465be5ad2df98 replaces every hand-built page under site/ with a single Design Component: site/index.html holds the template and its logic class, site/Listbox.dc.html is the searchable select it imports, and site/support.js is the byte-for-byte upstream runtime.

Vendoring. site/support.js hard-codes the unpkg URLs it loads React from. Rather than fork it, script/vendor-site-assets.mjs downloads those builds, re-hashes them against the SRI digests the runtime itself pins, and points it at the local copies through the window.__resources map it already consults — site/vendor/dc-resources.js, which must load before support.js. The same script subsets Material Symbols Outlined by icon_names and Noto Sans HK by text, both derived from the page source on every run. 420 KiB on disk; provenance, digests, and licences in site/vendor/manifest.json.

Verified. A headless Chrome on an off-screen desktop, against an assembled _site served locally: no console errors, performance.getEntriesByType reporting zero third-party hosts, all six pages rendering with content and correct aria-labelledby, all eight overlay panels opening and closing on Escape, the language switch reaching Cantonese with all three Noto Sans HK weights loading, the playfulness slider changing the voice line across levels 1 and 5, the regex builder naming its dialect and reporting a syntax error, the four tab searches and both close modes previewing with counts and protection, and the appearance editor applying and persisting per element.

Five defects found and fixed during that pass.

  1. Every listbox selection was a silent no-op. The page is parsed from the browser's own document, where HTML lowercases attribute names, so the callback arrived as onpick while the component read onPick. It now reads both. This is the failure mode to remember for any Design Component used as a page rather than previewed from source text.
  2. The accent seed replaced --md-sys-color-primary without --md-sys-color-on-primary, leaving the dark theme's #00344f on #006493 — a 2.02:1 primary call to action. onColor() now derives black or white from WCAG relative luminance; all four accents measure 6.4:1 in both themes.
  3. Both tab strips had role="tab" with no tabpanel, no aria-controls, and no roving tabindex.
  4. Three range inputs and the Bold/Italic/Underline toggles had no accessible name or pressed state.
  5. Seven drag-and-drop upload placeholders shipped as empty boxes; they now hold captures this repository already had.

Concurrency note. Two commits made by another agent in this same checkout — ba452e4017 and dbea7be82f — swept this task's staged git rm deletions into themselves and were dewed, leaving main briefly publishing the old homepage with its stylesheet and both Cheap LFS pages deleted. Commit 80d05e73b881d6b2cd4da4f5a99465be5ad2df98 restores a coherent tree. When several agents share one working tree, stage explicit paths and re-check git log before assuming the index is still yours.

Known, not caused here. app/test/unit/wiki-function-gallery-test.ts fails two assertions (88 raw-main images against 86 catalog rows). It fails identically with this work stashed.

2026-08-03 — Stash manager portal runtime correction

The stash manager is now rendered through the shared dialog portal, so its Manage, Export, History, and Appearance and voice tabs paint above the Changes pane instead of being clipped inside it. The accepted hidden-Windows capture material-stash-manager-centered-20260803.png is 1443×992 and has SHA-256 B733BC06C0B3DB455BF634381409D64B898773D6D742A97097F2E9AF130F4A01. Additional inspected captures proved the complete 7z option set, the appearance/funny-level controls, and the History tab. A disposable fixture also created a real Git stash with subject Named headless stash; the manager surface itself did not refresh its inventory before the final capture, so that Git result is recorded as operation proof rather than as a UI-row claim.

Focused manager/export tests passed 17/17, targeted ESLint passed, and the full TypeScript check passed. The exact fix checkout's webpack compilation completed; the later packaging script stopped only because the isolated checkout lacked ignored generated choosealicense.com/_licenses data.

2026-08-05 — Dedicated History Graph repository page

The graph now has a first-class HistoryGraph repository section appended to the persisted RepositorySectionTab enum, so existing saved section values do not move. The repository rail labels the page Graph and routes it directly to the shared compare renderer in full-width page mode: the branch filter, history scope, commit search, filter chips, lane controls, selection, and commit actions are retained, while the narrow History sidebar is not mounted. The page has its own localized title and accessible panel relationship. The responsive surface catalog and repository section-order tests include the page and the previously drifted Launchpad, preference, AI-security, and repository- settings entries now match their source enums again.

Focused verification is 85/85 across graph behavior, repository navigation, section ordering, feature registration, and the responsive surface catalog. npx --no-install tsc --noEmit still stops on two unrelated dirty test fixtures (app/test/unit/ui/merge-choose-branch-dialog-test.tsx, lines 84 and 117), where the existing "Merge" fixture is not a MultiCommitOperationKind; that dirty work was preserved. The required Lowlevel preflight and checkout identity checks passed, but the MCP build receipt did not: the first exact build produced refreshed output and then wedged its client, while a retry returned an unhandled TaskGroup error while another checkout was building through the same service. No built-app capture is claimed from that unverified receipt.

2026-08-03 — History view tabs checkpoint

The History surface now exposes a real, keyboard-accessible List / Graph tab strip rather than hiding the graph mode behind an icon-only toggle. The selected view remains persisted, the tabs use roving focus with arrow/Home/End navigation, and both views share the existing commit actions and filter state. The three-column graph continues to use the virtualized continuous lane renderer. Focused source/style verification passed, and the exact production build was exercised on a hidden Win32 desktop with a disposable Git fixture. The inspected 1443×992 captures are material-history-view-tabs-list.png (List selected) and material-history-view-tabs-graph.png (Graph selected); the CDP receipt also confirmed the tablist/tab/tabpanel relationship. R3 still retains its broader graph-scale and multi-branch acceptance work, but the missing view-tab surface is now runtime-proven.

2026-08-03 — Stash manager export slice

The new isolated checkout codex/stash-manager-20260803 contains a separate tabbed Stash Manager dialog with searchable exact-identity export to directory, ZIP, and configurable 7z, plus History and shared language/funny-level controls. getStashes no longer truncates by entry count. Focused verification currently passes 42/42 (40 existing Git/UI assertions plus 2 7z argument assertions). The production build emitted out/main.js before the final appearance/options edits; rerun the exact build and headless Windows capture after those edits. Do not claim runtime verification until the dialog is opened in the real built artifact and the export surface is exercised.

2026-08-03 — Bug-hunt and Ollama interface checkpoint

This checkpoint is the current source of truth for the active audit. The main checkout started at 79d5d59662dd7639664a878b390706f0c3975f2c with unrelated working-tree material already present. The audit kept that material intact and added the following scoped fixes:

Verification so far: the required production webpack build emitted the current out/main.js bundle; the hidden Win32 desktop launched it with a disposable profile and fixture and produced a nonblank 1443×992 first-paint capture; ollama-model-manager-test.tsx passed 14/14; the focused rejected-creation Agents test passed 1/1; the focused internal-browser contract and UI files pass 32/32; Prettier, tsc --noEmit, and the targeted repository ESLint rules are clean. The new browser slice still needs a fresh exact build and runtime smoke; the prior first-run/checklist overlay prevented a truthful Ollama capture.

The three roadmap audits confirm that R3/R4/R5/R8 have substantial local foundations but still need built-app captures or remaining live wiring, while R1/R2/R6/R7/R9–R18 retain the server, provider, adapter, or integration work listed below. No roadmap item is marked complete merely because source tests passed. Open issues were re-read at the checkpoint: desktop-material remains open on #23 and #118–#135; agent-global-memory has no open issues.

The hidden verification service was reached at the documented loopback MCP endpoint. Its scheduled task could not be enabled because Windows returned Access Denied, so the exact documented server command was run as a hidden, task-owned process for this capture. The disposable fixture, profile, desktop, and Electron process must be removed after final evidence is recorded.

2026-08-02 — Session close: 51 commits, all on main

Start here. Everything below is dewed; origin/main contains all of it and no worktree holds uncommitted work.

What landed

Full suite: 7,670 tests pass across 930 files. tsc --noEmit clean.

The next concrete step: mount the Agents panel

It is built and green but reachable from nothing. app/src/ui/agent-sessions/ exports AgentSessionsPanel with IAgentSessionsPanelProps:

sessions, availability, baseBranches, defaultBaseBranch, existingBranchNames,
selectedPath, onSelectSession, onCreateSession, isCreating,
onConfigureSetupCommands?

plus startAgentSessionRun / cancelAgentSessionRun / detectAgentRunnerAvailability from agent-runner-bridge.

Mounting means adding a List / Agents tab beside the repository list, in renderRepositoryList in app/src/ui/app.tsx, and rendering:

<AgentSessionsPanel
  sessions={this.state.worktrees.map(w => toAgentSession(w))}
  availability={this.state.agentRunnerAvailability}
  baseBranches={allBranches.map(b => b.name)}
  defaultBaseBranch={defaultBranch?.name ?? 'main'}
  existingBranchNames={allBranches.map(b => b.name)}
  selectedPath={currentWorktree?.path ?? null}
  onSelectSession={this.onSelectAgentSession}
  onCreateSession={this.onCreateAgentSession}
  isCreating={this.state.isCreatingAgentSession}
/>

onCreateAgentSession calls the existing dispatcher.addWorktree(repository, path, { createBranch: getAgentSessionBranchName(request.name), commitish: request.baseBranch }), then startAgentSessionRun({ agent, worktreePath, operationId, prompt, autoApprove }), and reports the outcome through dispatcher.postNotification — never a modal. availability comes from detectAgentRunnerAvailability() once on mount, defaulting to UnknownAgentRunnerAvailability.

The one piece nobody has built yet is the live status feed. runState, diffStat and editedFileCount are props; nothing polls git or subscribes to codex-log / opencode-log, so the fleet chips will render whatever the caller passes and no more. That belongs in a store, and until it exists the panel shows a static fleet rather than a live one.

Two design decisions worth knowing before reviewing it. The creator has a Task for the agent field, required once a runnable agent is chosen, because otherwise picking Codex spawns a process with nothing to do. And Start sits below the Options disclosure, not inside it — the screenshot reads as putting it inside, but a primary action hidden behind a collapsed section is a usability defect.

Two things found but deliberately not fixed

Still open from the bug hunt

Three tab surfaces and the Commit & push all dialog are hard-coded English; the profile history page read is unbounded; the version-history timeline is a listbox whose options are not its children; the overflow button sits inside the tablist; the regex block model is dead code emitting constructs RE2 rejects; compact density starts the browser view 14 px low.

2026-08-02 — REQUESTED FEATURES, recorded before they are built

Read this first. These were asked for in one session, from screenshots of GitKraken. They are written down here before implementation because the machine they were requested from was about to lose power. Nothing below is finished unless it says so. Where a screenshot is the only specification, the description is what the screenshot showed, not a guess at what it meant.

The two rules that govern all of it

1. Every screenshotted feature MUST be added. Not should — must. The user's instructions, in their words: "if it doesn't exist, create the feature fully from scratch even if it means creating a web server" and "every single feature i screenshotted should be added, if not possible create them from scratch and host them in docker" — corrected immediately after to "not should be, must be added, and find a way to do so." So "we don't have that", "that needs a service we don't run" and "that is not possible here" are answers to nothing. A missing back end is a back end to write, and a way is found. Nothing on this list is cut for being hard.

2. Anything server-shaped is hosted in Docker, by the user. Every one of these features that needs somewhere for two machines to meet — collaboration, patches, insights, presence, deep links, single sign-on, SAML, the OAuth authorization server — runs in a container the user hosts, stood up by a fully automated, wizard-guided flow inside the app. There is no vendor backend anywhere in this design, and none is to be introduced.

Together those two rules say: write the server, ship it as a container, and make the wizard install it. That, not any individual feature, is the critical path.

1. History: a toggleable graph view — IN PROGRESS

A second view mode for history, alongside the existing list, laid out as three columns: Branch / Tag | Graph | Commit Message.

Existing groundwork: showCommitGraph in compare.tsx (persisted under ShowCommitGraphKey), buildCommitGraphRows in commit-graph-model.ts, and CommitGraph in commit-graph.tsx.

2. Agents panel — IN PROGRESS

A second sidebar tab beside the repository List, called Agents. Three parts, from three screenshots:

Both shipped agents are real: app/src/lib/build-run/codex.ts and opencode.ts, the *-runner.ts files in app/src/main-process/build-run/, and the codex-* / opencode-* IPC channels already exist and work.

3. Command palette: far more commands — AUDITED, NOT YET ADDED

The user's screenshot showed 111 of 111 commands. The catalog is now 246 unique entries, so that screenshot is an older build — but the point stands: whole feature areas have no palette route.

An audit of the settings/app half returned 45 concrete additions: tab management (close/others/left/right, the eight sort orders, favourite, rename, move to group, group collapse/delete), the notification centre inbox (which has no palette route at all — the existing palette:notification-history row is mistitled and actually opens the Git-backed version history), settings undo/redo, sign-in actions, six element appearance editors, and repository-scoped editor and default-branch overrides. 27 need only a palette:* case in onPaletteCommand; 18 need a teleport anchor first. The git/repository half of the audit was still running.

Also found: docs/features/design-system/command-palette-coverage-gaps.md has a stale header claiming 112 catalog entries.

4. Proactive conflict detection — NOT STARTED

A banner: "Potential conflict detected" — «X has changes that could conflict with your changes on branch. Review to avoid future conflicts.» With Other options: send your changes to that person as a Cloud Patch, push your changes so they can fetch them, and ignore conflict warnings for your changes on that branch. Plus a Show N overlapping files disclosure.

Cloud Patch is back in — the user first said "skip cloud patch", then said "even the cloud patch". It is built self-hosted, on the user's own Docker server, never as a vendor service. So the banner keeps all three options: send your changes as a patch, push so they can fetch, and ignore warnings for this branch. Tracked as R18.

5. AI-assisted merge conflict resolution — NOT STARTED

A three-pane conflict editor (ours | result | theirs) with Auto-resolve with AI and Open in external merge tool, plus an AI Merge Summary panel giving, per conflict, a confidence percentage and a plain-language reason for the choice it made.

Existing groundwork: app/src/lib/copilot-conflict-context.ts and copilot-conflict-resolution.ts already exist — start there rather than from nothing.

6. Commit context menu in the graph — NOT STARTED

Right-clicking a commit in the graph view offers: Checkout this commit, Create worktree from this commit, Create branch here, Cherry pick N commits, Reset branch to this commit, Revert commit, Recompose N commits with AI, and Recompose N children of sha with AI.

7. Compose commits with AI — NOT STARTED

Restructure existing history into a cleaner story: take a pile of uncommitted WIP, or a mess of coding-agent commits, and reorganize it into logical, readable, reviewable commits. This is the feature the context menu's "Recompose" entries invoke.

8. Summarize past changes with AI — NOT STARTED

Select N commits and get a plain-language explanation. The screenshot showed a header Explaining 3 commits, the commit rows with author and date, then a prose summary followed by a Changes bullet list naming each modified file and what changed in it.

9. Launchpad — NOT STARTED

A prioritized inbox across issues, pull requests and work in progress, grouped into collapsible status sections with counts: Pinned, Ready to merge, Unassigned, CI failing, Merge conflicts. Each row shows age, status icons, the item title with its #number, and its diff stat (+102 / -0), and rows can be pinned. Stated purpose: start the day here and act on the most important work without juggling apps.

10. In-app pull request review — NOT STARTED

A GitHub Pull Request screen inside the app: the PR number and title, an Open state badge, «author wants to merge head into base», a Description section, a Comments thread, and a right rail carrying N files changed, a Review Code and Suggest Changes button, a Submit a Review button, Reviewers and Assignees.

The requested emphasis is suggesting code changes internally — writing review suggestions from inside the app and posting them as review comments, rather than opening the browser. The comment in the screenshot showed a posted suggestion block ("Code Suggestion for #212").

12. Feature parity checklist — a target list, not a claim

Three more screenshots supplied a competitor's feature checklist. Below is that list with what a quick codebase check found. The "here?" column is a grep-level answer, not a verified parity claim — anything marked partial or ? needs someone to open the app and look before it is called done.

Feature Here? Evidence / what is missing
Git LFS partial Cheap LFS (release-backed) is extensive; ordinary Git LFS is a separate thing — see docs/features/repository-management/cheap-lfs-vs-git-lfs.md
Git Worktrees yes app/src/ui/worktrees/, app/src/lib/git/worktree.ts
File history & blame partial 10 files mention blame; whether there is a blame view needs checking
View & create pull requests partial Creating exists; the in-app PR review screen is item 10 above
Hiding & soloing no zero hits — graph lane hide/solo does not exist
Auto-Gen SSH key no 3 incidental hits only
Git hooks support yes extensive, including a hooks proxy
Submodules yes app/src/ui/repository-settings/submodules.tsx and more
Visual Interactive Rebase no zero hits for interactive rebase
Visual Interactive Cherry Pick partial cherry-pick is everywhere (42 files); the visual interactive form is the gap
One-click undo & redo Git operations partial undo exists; a general redo of Git operations needs checking
Command Palette yes 246 entries — and item 3 above is about growing it
GPG commit signing partial 10 files mention gpg
Keyboard shortcuts yes throughout
Dark, Light & Custom Themes yes full appearance customization system
Local Workspaces partial repository groups exist; "workspace" appears in 45 files, needs checking
Cloud Workspaces no hosted service, and out of step with this app's local-first design
Merge Conflict Tool partial conflict handling exists; the three-pane tool is item 5 above
Merge Conflict Output Editor no the editable result pane of item 5
Code Editor no external editors are supported; there is no in-app editor
Pull or fetch multiple repos yes Pull all, and Commit & push all
Multiple Profiles partial a profile store exists (22 files); a user-facing profile switcher needs checking
Gitflow support no zero hits

And the agent-specific checklist:

Feature Here? Note
Agent Sessions View in progress item 2 above
Launch Agent Sessions in progress item 2 above
Independent Terminal Sessions partial create-terminal-stream.ts and a CLI workbench exist; per-session terminals do not
Worktree Status in progress the fleet status chips in item 2
Claude Code no runner picker entry only
Codex CLI yes real runner and IPC
OpenCode yes real runner and IPC
Copilot CLI no runner picker entry only
Gemini CLI no runner picker entry only

13. Team collaboration — self-hosted, wizard-guided, NOT STARTED

A team-collaboration feature set, from a screenshot: Code Suggest, shared workspaces, Insights, Launchpad with pinning and snoozing, a Team View both in the Launchpad and as live activity status in the left panel, Conflict Prevention, predictive merge-conflict alerts, filtering the commit graph by team, and sharing with deep links.

The user's explicit design decision: there is no vendor cloud. The user hosts their own Docker server, and setting it up must be a fully wizard-guided, automated flow inside the app. That is what makes this set buildable here at all — everything above needs a place for two machines to meet, and the answer is a container the user owns rather than a service they rent.

So the first deliverable is not a feature from that list; it is the wizard: detect or install Docker, generate the server's configuration and credentials, start the container, verify it is reachable, and hand back a join URL — with every step recoverable and nothing asking the user to type a command. The collaboration features are then built against that server.

Constraints that already apply here: secrets never go through chat or a log, the server's credentials are generated rather than typed, and the app must degrade honestly to single-player when no server is configured. Cloud Patches from that screenshot stays out, per the earlier decision. Share Cloud Workspaces becomes "share a workspace through your own server", or it is cut.

13b. Every "cloud" function runs on that Docker server

Said plainly by the user: use the Docker server for the cloud functions. There is no vendor backend anywhere in this design. Anything a competitor calls "cloud" — shared workspaces, patches, insights, team presence, deep links — is served by the container the user owns, or it is not built.

Resolved: the "skip cloud patch" said earlier meant no vendor patch service. The user has since said "even the cloud patch", so patches are in, self-hosted on that server. Private storage and self-hosted storage collapse into the one thing. Tracked as R18.

13c. Admin and security controls — NOT STARTED

From a screenshot: AI security controls, and patch storage that is private and/or self-hosted. With the self-hosted decision above, "private storage" and "self-hosted storage" collapse into one thing: storage on the user's own server.

AI security controls means the administrator deciding what may be sent to a model at all — which repositories, which files, whether diffs leave the machine, and which provider is permitted. Every AI feature in this list (items 5, 7, 8 and Code Suggest) has to be gated by it, so it is a prerequisite for them rather than a companion to them.

13d. Access management — the Docker server is also the identity provider

From a screenshot: Single Sign-On, Multi-Domain SSO, SAML. The user's direction: a custom Docker OAuth server. So the same container the user hosts issues the identities — it is the OAuth authorization server, and SSO and SAML are things it federates, not things a vendor sells.

This makes the wizard in item 13 bigger and more important, not smaller: it now has to provision an OAuth server, which means real key material, correct redirect handling, and token lifetimes — generated by the wizard, never typed by the user and never shown in a log.

Two things this app already knows that apply directly: it has no OAuth loopback HTTP listener — sign-in uses the x-github-desktop-auth protocol deep link (recorded in the peer-closed-stream entry further down this file) — so a self-hosted OAuth flow must decide deliberately between that deep link and a loopback listener rather than assuming one exists. And the internal browser already has a hardened private-session OAuth path with partition rotation and callback correlation, which is the right place to run this flow.

15. Integrated terminal — NOT STARTED

From a screenshot: a Git-enhanced terminal, a commit graph that stays live and synchronized with what the terminal is doing, CLI diff/blame/history views, and auto-suggest plus auto-complete for Git commands.

Existing groundwork: app/src/lib/create-terminal-stream.ts, the CLI workbench (app/src/lib/cli-workbench.ts, cli-workbench-catalog.ts), and the start-cli-command / cli-command-output / cli-command-state IPC channels. The live-synchronized graph is the interesting half: it means the graph view of item 1 has to be able to refresh from an external mutation, not only from the app's own.

14. Issue tracker integrations — NOT STARTED

From a screenshot: Jira Cloud, Jira Data Center, the Git Integration for Jira app, GitHub, GitHub Enterprise, GitLab, GitLab Self-Managed, and Trello.

GitHub and GitHub Enterprise are already first-class in this app, and there is existing GitLab and Bitbucket account plumbing (see the submodule provider sign-in strings). Jira and Trello are entirely absent. Each integration needs its own credential path, and every one of them must obey the rule that a token is never rendered, logged, or pasted into a conversation.

11. Screenshots belong in a gitignored directory

Requested during this session: reference screenshots go to a gitignored folder. design/reference-screenshots/ is created and ignored for exactly this. Note honestly: the agent that recorded these features could not write the image files — the screenshots were pasted into a conversation, not handed over as files on disk, so only the descriptions above exist. Drop the images into that folder and the descriptions become checkable against them.


2026-08-02 — Fleet bug hunt: six readers, ten fixes so far, more in flight

Six read-only agents were pointed at disjoint areas of the desktop app — the internal browser, appearance and tabs, the regex builder and every search surface, localization/changelog/dim-sum, main-process and IPC, and the local version history plus notifications. Between them they reported around thirty candidate defects. Each one below was re-read against the code before it was touched, and each fix carries a test that fails against the old code.

The branch did not typecheck when this started. tsc --noEmit failed on two ipcWebContents.send calls in internal-browser-window.ts, so the previous handoff's claim of a clean typecheck was wrong. That was the first thing fixed.

Landed

Commit What was wrong
2714c53345 internal-browser-find / internal-browser-page-text were sent but never declared in RequestChannels — the branch failed tsc. Both now carry named payload types and appear in the IPC contract test.
1dbeca53ff Pinned tabs went into the overflow dropdown whenever the active tab sat past the leading run. The layout now takes pinnedCount and lays the pinned run out first.
cb29c34dbc Notification dedupe matched on kind/title/body only, so repository A's failure and repository B's collapsed into one row pointing at B. accountKey and repositoryId now take part, and the coalesced entry no longer inherits fields the new notification omitted.
dff4f9c9fb 24 keys existed only in English, so Cantonese mode rendered the submodule Create-remote tab in English and bilingual mode rendered it twice. Both catalogs are now asserted key-for-key and placeholder-for-placeholder. Two mojibake ellipses repaired.
ae4ba15421 safeSimplexListener caught rejections and not synchronous throws, so one malformed update-accounts payload reached uncaughtException and destroyed every window.
19940edffb Filter surfaces trimmed the query and then searched with the trimmed string: the regex + became the uncompilable +, and a substring with a deliberate trailing space matched text without it.
4d9e6216e3 FilterList and AugmentedSectionFilterList computed regexError and rendered only a red border, so an invalid pattern listed every item with nothing announced. They now render the same role="alert" message SectionFilterList already had.
3df847fcfa A profile restore that deletes a state file unlinked only the primary, leaving the git-ignored crash-safe backup; the next read recovered from it and resurrected the file. Now uses clearCrashSafeFile.
abb255cbd8 Silent install judged the release asset's name and spawned whatever was at the supplied path, with nothing requiring them to match. The review now compares the path's base name too.
e4595bc179 normalizeInternalBrowserCommand never learned the three page-search commands, so every find request was dropped at the IPC boundary before reaching its handler. The feature could not have worked.

Landed in the second pass

Commit What was wrong
d324e86952 The quick-action window disabled its summary box at "done" while leaving Commit & push enabled, over a snapshot it never re-read — a second click re-committed the files it had just committed.
470c78ce2c The dim-sum card cancelled its dismissal timer on focusin and never restarted it, so tabbing past it once left it up for the session. Changelog copy had no catch.
7eecf4c227 QuickActionWindow treated any did-fail-load as fatal and reported it twice; notificationWindowOwners grew without bound; the exception reporter logged the crash instead of the submission failure.
e8a16d8ab5 The tab colour picker showed the default over any stored #rgb or #rrggbbaa and silently flattened alpha on the next touch.
953600d6e0 Roving tabIndex with no arrow-key roving: only the active tab was keyboard reachable. role="tablist" also sat on a container holding seven non-tab controls.
754abc062e The date-range picker rewrote the field under the caret and could swap a half-typed value into the other end; the calendar lost its only tab stop once a range was set.
84c3ea0e72 Feature: Commit & push all now selects repositories, with a search bar wired to the regex builder. Bulk select/clear never reach past the filter.
1a8ea1a964 The two bulk tab closes disagreed on mode, casing and match-key scope, so they were not each other's negation. Whitespace-only queries enabled a dead button; the surface defaulted to fuzzy subsequence over the absolute path.
97040068ec Settings search marked no characters in regex mode; version history advertised a file search it could only run against one loaded commit.
318616e127 Notification and log history mutations ran with no profile repository lease, so a debounced commit could land on a half-restored tree and the restore would roll back onto it.
ca3cf95a49 Six internal-browser defects: renderer leak on window close, address bar reverting on Enter, auth tabs never showing an error, a blank external-open button below 840 px, a 21 px dead band above every page, and clipped focus rings.
9c70e73849 The regex builder seeded the user's plain-text query unescaped and then switched the surface to regex — (WIP) silently became a capture group. The palette also had no way to insert a literal at all.
fc8eafbf12 The automation store had the same missing lease as its two siblings.

Still open, verified but not fixed

2026-08-02 — Internal browser: page search renderer completed, three features remain

Read this before touching app/src/internal-browser/. The main-process and renderer halves of page search are now present. Four commits established the browser defects/plumbing, and the current slice makes the feature reachable.

Landed

Commit What
af9b60b787 Four real defects fixed (below)
abee1ad199 Page-search plumbing: commands, main-process handlers, IPC back-channels

The four defects, each found by reading rather than from a report:

  1. An IPC message per keystroke. componentDidUpdate re-measured the content viewport on every state change, and typing in the address bar is one state change per character — each cancelling a frame, rescheduling a 120 ms timer, and sending the native view an identical rectangle. Now gated on chromeLayoutKey, which changes only when the chrome's height can.
  2. A tablist with no panel and non-tabs inside it. Wrapper divs sat between the tablist and its tabs, the new-tab button was a non-tab child, and nothing declared itself the panel. Wrappers are role="presentation", the button moved out, the viewport is the panel, and a sr-only line explains the panel is empty because a separate native view draws the page.
  3. The window was called "Browser" forever — several browser windows were indistinguishable in the taskbar. It now names the active tab.
  4. A null check that missed. tab?.url === null is false when there is no tab (undefined is not null), so it validated an empty string every render.

The security decision, stated plainly

Page search in regular-expression mode runs a script inside the page. This is the first time this browser has ever done so, it was an explicit user decision after the constraint was raised, and it happens on every regex search on every site. It is built as tightly as the platform allows:

A successor changing any of this should treat it as a security boundary, not an implementation detail.

Known limitation, by design

Regex mode cannot highlight or scroll to matches in the page. Doing that means mutating the page's DOM, which is a far larger boundary than reading text. Plain mode gets real in-page highlighting from Chromium's findInPage; regex mode gets a match count and a results list with surrounding context (findMatchContext builds the window). This must be documented in the UI, not left to look like a bug.

Not started

Feature Notes for whoever picks it up
Find bar UI Implemented in app/src/internal-browser/internal-browser-app.tsx. The renderer listens to internal-browser-find and internal-browser-page-text, sends bounded request-token commands, keeps plain text as the default, and offers regex mode plus the shared anchored builder. Focused contract/UI tests pass 32/32; exact Windows build and runtime smoke are still pending for this checkpoint.
Funny-level sliders It reads languageMode and uses t() for 37 strings but never consults readFunnyLevels(), so its copy ignores a setting the rest of the app honours. Pattern to copy: app/src/lib/dim-sum-copy.ts.
Non-blocking notifications It has no toast surface; the error notice is role="alert" aria-live="assertive" in the header, which interrupts and shifts layout.
Dim sum surprise The browser is a separate renderer entry point and takes no part in the 10% draw. Model, copy and card all exist — see app/src/models/dim-sum.ts and app/src/ui/dim-sum/. Needs its own suppression rules (an authentication tab is mid-task and must not be interrupted).

Verification state

tsc --noEmit clean, Prettier and targeted ESLint clean, SCSS compiles. The focused internal-browser contract and chrome suites pass 32/32, including plain and regex query dispatch, request-token matching, regex result navigation, and close behavior. The exact Windows build and runtime smoke are the remaining verification boundary for this checkpoint.

2026-08-01 — The dim sum surprise reaches the app

The website has served a dim sum dish on one visit in ten since 309ad27736; the Windows app served none. It does now.

What shipped

The pictures

Twelve dishes, ~27 MiB, copied byte for byte from the shared catalog by script/generate-dim-sum-assets.ts. Twelve rather than the whole catalog because each is a multi-megabyte lossless PNG the installer pays for; the twelve span steamed, baked, fried, rolled, bakery, dessert and drink. script/build.ts copies app/static/dim-sum to out/static/dim-sum, matching how the narration assets already travel.

Verification

47 unit tests across five files, all passing: dim-sum-surprise-test.ts, dim-sum-copy-test.ts, dim-sum-assets-test.ts, dim-sum-wiring-test.ts, ui/dim-sum-surprise-test.tsx. The asset test hashes every committed PNG against the manifest on every run, so a picture that stops decoding fails CI rather than reaching a user as a broken image. The wiring test walks every settings surface and fails if a dim sum toggle ever appears.

Not done here

No screenshot of the card in the running app: it appears on a 1-in-10 draw at launch, and the capture harness has no hook to force the draw. Adding one would mean a test-only override of the probability, which is a change to the feature rather than to the harness. The rendered markup is asserted instead.

Issue #23 asked for every published screenshot to be replaced. 81 of 92 are refreshed against a build containing the full-app command palette; the 11 that are not are listed with concrete blockers in .codex/run-manifests/2026-08-01-gallery-recapture.md (5 are the Linux TUI, which is out of scope by directive).

The run exposed three real app defects, all fixed here:

  1. window.location.reload() was dead app-wide — the main process denied every will-navigate, including a document reloading itself, so both renderer Reload buttons did nothing. Fixed in app/src/lib/same-document-reload.ts.
  2. The repository logo editor grew a second scrollbar because its override released overflow-y but not overflow-x (CSS computes (hidden, visible) as (hidden, auto)).
  3. The capture fixture seeded its token under the dev-flavoured credential service name only, so a production build could never hydrate an account — the blocker that killed the 2026-07-31 run.

Four harness drifts were also corrected (Shift+right-click appearance editors, two controls that moved into the More menu, the · N visible artifacts clause, and rail buttons whose text now embeds their Material Symbol ligature).

Published: 66d446266e, ancestry proven against the remote main.

2026-07-31 — Full-app command palette: rich controls and teleport

The Ctrl+F command palette was rebuilt as Material 3's full-screen search view. Three behaviours landed together:

  1. Full-app coverage — the palette dialog opts out of the floating-card geometry and covers the window below the title bar (#dialog-layer dialog#command-palette.command-palette-full), with a 1180px content column, a detail pane, and a hint footer.
  2. Rich controls — a catalog command may declare control (toggle | entry | number | choice); the palette renders the matching live control inline. App supplies values via getPaletteControlValues() and writes via onPaletteControlChange, reusing the exact dispatcher setters the Settings panes call. Unknown values render disabled controls; changes never dismiss the palette.
  3. Teleport — every command resolves a home (resolvePaletteHome); click/Enter opens the owning surface and spotlights the exact control (teleportTo in app/src/ui/lib/teleport.ts, selector registry in app/src/lib/teleport-targets.ts, anchors spread with teleportAnchor(...) in the preferences panes). Ctrl+Enter/Run executes. Push/force-push/pull/fetch/discard/remove homes carry no self-opener, so teleporting can never fire them. A missing surface posts a non-blocking notification instead of failing silently.

New i18n keys live under commandPalette.* / palette.* in both languages. Docs: docs/features/design-system/command-palette-full-coverage.md. MD3 audit of the whole UI: docs/verification/md3-ui-audit-2026-07-31.md (84/100; missing --md-sys-shape-corner-extra-small/-full tokens were added).

Verified locally: tsc clean; changed-file eslint/prettier clean; palette suites green (catalog 27, rich 6, filter-mode 4, appearance, i18n 23); _command-palette.scss + _teleport.scss compile standalone under dart-sass.

2026-07-31 — In-app changelog viewer and two context-menu defects

Handoff written mid-stream at the user's request. Three of five requested items are complete and pushed; two were never started. Nothing is left in a broken or half-applied state, and no work is stashed or branch-only.

Done and pushed

4942f2025c — context menu regex builder and keyboard shortcuts.

The regex builder opened from a context menu was unusable, from three separate causes that had to be fixed together:

  1. The builder's overlay sat at z-index: 70 while the menu's own full-viewport backdrop sits at 1000. Both are body-level layers in the same stacking context, so the builder was painted under a transparent sheet: the first click landed on the backdrop, dismissed the menu, and unmounted the builder. Fixed with a named --regex-builder-z-index: 1100 token in app/styles/_variables.scss.
  2. The builder portals to #regex-builder-layer on document.body, so it is not a DOM descendant of .filter-mode-control — only a React-tree one. The menu's onKeyDown guard tested that class alone, so every keystroke typed into the pattern field drove the menu instead: Escape tore the menu down, Enter fired a menu action, arrows moved a highlight nobody could see. Every other host of the builder already tested .regex-builder-overlay; the context menu now does too.
  3. A click landing in the builder overlay's transparent margin still reached the backdrop. The backdrop now stands down while a builder carrying its own search-surface id is open.

Also in that commit: IMenuItem gained an accelerator, rendered as a trailing <kbd> hint and announced through aria-keyshortcuts (never both, so the shortcut is not read twice). Electron's composite editMenu role is now expanded into Cut / Copy / Paste / Select all — it previously rendered as one blank unclickable row, which means every text field in the app (text-box, text-area, the autocompleting input) had an empty context menu. The menu's three hardcoded English strings are now localized.

f89f162d3d — the changelog viewer.

The app had no changelog: only a release-notes dialog for a pending update, plus a link that opened a website. The new Release history dialog covers all 683 recorded releases and 3,694 entries, reachable from Help → Release history, the command palette, and About.

That commit also repairs yarn lint:src, which was already red on main from two test files added earlier in this session's work (docs-site-color-test.ts, docs-site-tabs-test.ts).

CI had been red on main for the previous three pushes, blocking every release, from three independent causes — all of them mine, all now fixed. The lint job above was only one of them. The other two:

Build Installers / Express Release run 30652270161 shows the shape of the damage: it built, packaged, signed and collected the installers successfully, then failed on "Preserve the upstream CI failure result" and skipped publishing. The release machinery is fine; it was being fed a red CI.

Evidence

Check Result
changelog-viewer-test.ts 37/37
changelog-viewer-wiring-test.ts 10/10
ui/context-menu-shortcuts-test.tsx 11/11
docs-site-color-test.ts + docs-site-tabs-test.ts 68/68
material-context-menu-style-test.ts 4/4
i18n-test.ts, filter-mode and diff-search suites 35/35
npx tsc --noEmit clean
yarn lint:src clean (was red before)

The backdrop and keyboard cases in the context-menu test genuinely fail without their fixes — verified by watching them fail first.

Decision: stop supporting arm64

The user has directed that arm64 support ends. The only development machine is amd64 (x64), so nothing arm64 can be built, run, or verified here — an arm64 job can only ever report a result nobody on this project can reproduce or debug.

This is recorded, not yet implemented. Nothing has been removed. Whoever picks it up should drop the arm64 matrix legs and any arm64-only packaging, release assets, and verification steps, then confirm the release still publishes a complete x64 installer set.

Worth knowing before starting: the arm64 leg has already cost real time this session. One of the three CI failures above — the render-mermaid-test.mjs CDN assertion — was reported only by the arm64 runner, because the matrix splits which test batch runs where, not because the failure was architecture-specific. It reproduced on x64 the moment it was run there. So removing arm64 must not be treated as removing coverage: check which test batches the arm64 legs were carrying and make sure the x64 legs still run all of them, or the suite will get quieter without getting greener.

Search starting points: .github/workflows/ci-linux.yml, .github/workflows/ci-windows.yml, .github/workflows/build-installers.yml, and any arch/matrix entries naming arm64.

Not done — pick these up

  1. Drag a tab onto a tab to create a group; drag into a group to add. Requested this session, not started. Nothing was written for it.
  2. Per-repository tabs above the history editor, so history can be read tab by tab. Requested this session, not started.
  3. No webpack build has been run since the changelog landed. tsc and the unit tests pass, but the renderer now statically imports the 552 KB changelog.json (via app/src/lib/changelog/changelog-catalog.ts, path ../../../../changelog.json). There is precedent for importing JSON from outside app/src (github-api-operation-catalog.ts), so this is expected to resolve — but expected is not verified. Run yarn build:prod before trusting it, and consider a dynamic import() so the catalog lands in its own chunk rather than the main bundle.
  4. Documentation is not updated for either commit: no feature article under docs/, no README.md or ROADMAP.md entry, no landing-page or docs-site section, and no screenshots of the new dialog. Anything added under docs/ must be followed by yarn generate-docs-hub-catalog — a missed regeneration is what broke CI earlier in this work.
  5. Issue #23 is unchanged from the previous handoff: 8/86 frames promoted, 38 uninspected frames outside the repository, the per-feature verify_* batch untouched, and the live Cheap LFS batch still needing real multi-gigabyte uploads.
  6. The settings-history capture has still not been re-run under demo mode. out/ was rebuilt at the start of this session (exit 0) and now contains the redaction, so the run is unblocked — it just has not happened.

Notes for whoever picks this up

2026-07-31 — Recurring Git errors auto-repair (local verification)

The Windows app now contains the four failures reported from the repository surface. Its app-owned, hook-free rev-parse --verify HEAD probe retries only the localized Windows launcher denial, twice, with bounded cancellation-aware backoff. Repository-indicator refresh contains each provider failure, clears visible progress in finally, continues with the other repositories, and reschedules without producing the generic background-action toast.

Add Submodule repairs a missing working .gitmodules only from one immutable, Git-validated stage-0 blob OID. The byte buffer is restored exactly (including valid non-UTF-8 comment bytes) through an exclusive create; failure rollback removes only a matching device/inode and preserves any path whose ownership cannot be proven. Cheap LFS pointer inventory omits protected metadata and gitlinks, while oversized protected dot paths remain in commit enforcement and fail before provider discovery, credentials, release anchoring, upload, commit, or push. Normal, mixed automatic/manual, scheduled, and one-click commit paths therefore cannot silently commit those raw bytes.

Local evidence includes 6/6 launcher/updater regressions, 62/62 exact pointer/submodule checks, 101/101 broader focused checks, the exact non-UTF-8 blob and terminal-branch checks, 19/19 generated documentation checks, changed-file ESLint, and TypeScript no-emit. The reproducible production build passed through Lowlevel MCP before rebase, and the exact merged 7b6bed9768 tree passed again in 559.1 seconds (returncode: 0, no timeout). A real off-screen Win32 session opened a deterministic repository with a modified .gitmodules and deleted gitlink; after twelve stable seconds the 960×660 Changes surface showed both entries, notification history was empty, and isolated logs contained none of the four reported errors. The accepted 80,546-byte frame had SHA-256 32f2849dd973c899f4596618f73a498929c137f00402c196a667a1003374cb21. The app, desktop, profile, fixture, screenshots, and incomplete dependency backup were removed. Push, hosted CI, installer Release, and dim-sum asset proof remain pending. Rolling progress is recorded in Discussion #113.

香港粵語:Git 啟動跣腳會有節制咁再試,背景 fetch 自己仆低唔再拉埋全場; .gitmodules 只會由同一粒 index blob 原封不動補返,連奇怪 comment byte 都唔會俾 UTF-8 攪成炒蛋。Cheap LFS 亦識得分清 metadata 同大檔,唔會再 亂報 unsafe path,更加唔會未判死刑就走去開 Release、commit 或 push。

The first hosted CI run (30677422935) found one inherited Windows regression from the changelog commit rebased immediately before this fix: Release history and Show logs in Explorer both claimed H in Help. The release-history mnemonic now uses R; the exhaustive menu combination test passes. The same run's three Linux parity jobs reported 202 desktop feature rows against a frozen 201-row TUI contract. Rather than edit the prohibited TUI surface, this follow-up removes the duplicate summary row while retaining the dedicated feature article, category index, Pages card, and app documentation. The second hosted run (30678663185) cleared those failures and passed 7,472 of 7,473 Windows unit checks; its sole failure found the same incoming context menu's new search input used a constant expression where the registry auditor requires a literal one-to-one surface ID. The input and its regex control now carry the literal material-context-menu ID, and the focused registry contract passes without changing runtime behavior.

2026-07-30 — Publish organization listbox sizing (pushed acceptance)

Publish repository's Organization control is no longer a native select whose options could disappear inside a compact dialog. It is now a searchable, explicit-None listbox with persisted fuzzy, substring, and bounded-regex matching plus direct access to the full Regex Builder. Keyboard operation covers Home, End, Enter, Space, and Escape. The parent ignores a previous account's late organization response. The shared Regex Builder portal now owns Escape and closes itself without closing the Publish dialog.

The list viewport is bounded to 128–176 CSS px, scrolls vertically inside the dialog, and ellipsizes long organization names. Shared select wrappers also gain shrink containment so they cannot force dialog-level horizontal overflow. The owned provider fixture returns exactly three stable organizations, including one deliberately long name and local deterministic avatars.

Local evidence is green:

The accepted final capture, docs/assets/screenshots/material-publish-organization-picker.png, is 1440×960, 133,919 bytes, with SHA-256 7db03d5db789d19e1ad49de66bd79abb62e46c7909eda9de08878aac367033d8. Its narrow acceptance used a 390×844 physical window, 780×1688 logical viewport, and combined DPR/zoom 0.5. The list measured 176 CSS px / 88 physical px with clientHeight=172, scrollHeight=184, and maxScrollTop=12; the harness reached the bottom, kept the final option visible, found no horizontal overflow, proved the long label ellipsis, and restored None as the selection. The owned provider, app processes, headless desktop, fixture, profile, and temporary evidence were cleaned up.

Gallery promotion brings the current Windows plan to 85 scenes: 67 canonical plus 18 specialist. Older dated 84-scene entries below remain point-in-time provenance. Implementation commit 63c1ec08c4f24f85d87f21d98851dcd5784c7800 is proven on origin/main. Its first hosted matrix exposed two provenance-generation omissions rather than an application regression: this retained receipt was not committed even though the generated catalog linked it, and the TUI parity contract had not been regenerated. This follow-up publishes both inputs; final exact-SHA CI, Pages/wiki, and installer Release proof remain open.

2026-07-30 — Conflict/CI agent repair and hideable progress (local state)

2026-07-29 — CURRENT HANDOFF (read this first)

Collapsible filters, searchable publish owners, relative age, and per-repository appearance

The repository side sheet now keeps its account, service, status, search, and regex controls behind one state-preserving Filters disclosure that starts collapsed. Active filters remain applied and are counted on the disclosure. The existing compact Add, Select, and More action strip remains reachable outside the panel. Its three equal-width buttons stay inside the 390 px sheet; bilingual labels stack inside each button instead of overflowing or recreating the old multi-row clutter.

History commit hover/focus cards now pair the exact authored timestamp with an auto-updating relative age. The relative phrase follows the active English, Hong Kong Cantonese, or bilingual mode. The command-palette appearance editor is compact and left-aligned and adds a persisted Random per repository mode. It derives one of six balanced row layouts from the stable local repository ID, so the same repository keeps its look across opens and restarts without storing a path or redrawing randomly.

Publish repository now replaces the organization select with an anchored Material listbox. Its native search field uses the shared fuzzy, substring, and safe-RE2 modes plus the full Regex Builder. Typing never changes ownership, invalid regex remains visibly fail-open, and switching accounts clears a stale organization before the newest request can populate the list.

Focused implementation verification passes 133/133 tests across 11 files, including the ordinary .gitmodules Cheap LFS false-positive regression, state-preserving filter collapse, bilingual relative time, nested listbox/builder focus, fail-closed publishing, and a renderer-level proof that two repository keys resolve to different row structures. The two gallery capture-contract suites pass 73/73. The exact Windows production build and the four final current-build captures remain in progress; no stale renderer or missing organization screenshot is being presented as final evidence.

The earlier candidate files awaiting current-build replacement are:

香港粵語:repo 篩選而家識摺埋又記得狀態,三粒主要掣喺窄版雙語都唔會 衝出門口;Publish owner 由舊式下拉變咗可搜尋 listbox,仲有完整 Regex Builder,打錯 regex 都唔會將選項變魔術消失;History hover 同時講實際日期 同「幾耐之前」;命令面板仲可以每個 repo 穩定抽一款外觀,唔會每次打開都 洗牌洗到暈。133/133 個 focused test 同 73/73 capture contract 已過, .gitmodules 唔再無啦啦畀 Cheap LFS 捉去問話;exact build 同四張最終圖 仲做緊,未綠燈就唔會偷步報喜。

Earlier July 29 reliability close-out

This close-out is limited to two existing reliability changes. The Cheap LFS cloud-compression workflow commit now uses a temporary empty core.hooksPath, closing the post-commit gap left by --no-verify without changing hooks for ordinary user commits. The second change adds the authenticated diagnostic-log service, the best-effort client transport, its deployment runbook, feature documentation, and category/master Postman collections.

The focused desktop gate passes 38/38 tests across 2 files, including a real-Git fixture whose deliberately failing Git LFS-style post-commit hook is not invoked while the exact workflow commit still reaches its bare remote. The service gate passes 4/4 tests for authorization, dashboard isolation, ingest/redaction/persistence/search, and bounded storage metadata. TypeScript, focused Prettier and ESLint, JSON parsing, Docker Compose validation, and git diff --check pass. The deployed ARM64 service at 192.168.50.242:4318 returns HTTP 200 from /health; its earlier authenticated ingest/search/storage acceptance remains recorded below without re-reading or exposing its bearer token.

The exact hidden Lowlevel MCP production build passed before integration in 402.68 seconds. While closing out, origin/main advanced independently to d99c09886001f778f11cbf51db67021e76b4f4ad with the compact repository actions work. Local main was fast-forwarded to that commit and this scope reapplied without conflict. The exact integrated production build then passed in 520.65 seconds with client_ok: true, return code 0, no stderr, and no timeout. The client reported a session-termination transport cleanup failure only after returning the complete successful result; this non-visual run created no headless desktop or app window. The integrated tree again passes 38/38 desktop tests across 2 files, 4/4 service tests, and 19/19 documentation-catalog tests, plus TypeScript, focused Prettier/ESLint, new-file Markdown lint, JSON parsing, Compose validation, catalog parity, and git diff --check. Remote publication evidence is the remaining gate.

Final review caught and corrected the dashboard's default level= request: an empty level now means all levels, while a malformed non-empty client filter returns HTTP 400 instead of falling through to an all-client query. The 4/4 service suite covers both cases, and the service image builds locally. After a fresh host capacity/workload/port preflight, only the existing desktop-material-diagnostic-log-server Compose service was rebuilt and recreated. It is running/healthy; live public health and authenticated default search return HTTP 200, malformed-client search returns HTTP 400, and the deployed server.mjs SHA-256 is 087a3e7b47d71c857dd9ee4b5111249dbf7e382dd3b0e3f44fde5beee37c9270. The host again reported that its kernel does not enforce the configured memory limit; CPU, PID, retention, storage, and application-level bounds remain active.

Immediately before commit, origin/main advanced from d99c098860 to 5a2fb5c228 with one test-only correction in app/test/unit/ui/repository-group-management-test.tsx. The staged close-out was preserved, local main was fast-forwarded, and the index reapplied without conflict. No production source changed after the accepted build; the upstream focused test was rerun as the integration gate.

香港粵語:今次淨係收好兩件已經開咗工嘅可靠性修正——Cheap LFS 背景 commit 唔再畀壞咗嘅 post-commit hook 扮失敗,同埋中央診斷記錄服務/客戶端正式 執齊。38/38 個桌面測試、4/4 個服務測試同靜態檢查都過晒;遠端中途有新 main commit 亦已經穩陣接返,冇用推土機式 push。依家只欠合併後最終 驗證同遠端出貨證明,唔會臨收舖先加新餸。

2026-07-29 — Compact repository actions

The repository side sheet no longer presents five equal-weight pills across three rows. Its top-level action strip is now one 44 px row with Add, Select, and More. The More menu preserves repository-group creation, workspace sync, and commit/push-all; the two menu buttons expose localized accessible names and popup state. New visible and accessibility copy ships in English and playful Hong Kong Cantonese.

Focused repository-action and layout tests pass 6/6. Targeted ESLint and Prettier pass. The exact Lowlevel MCP production build completed successfully, and the built Electron UI was exercised on the isolated WinSta0\DMCompactActions20260729T200345 desktop with a disposable one-repo fixture. The accepted dark 1440×960 capture is docs/assets/screenshots/material-repositories-sheet.png, SHA-256 a4337af0544827860e8c0e9cf540359926f2b79b51c4ae9d1fe4b9571841dd1a. It contains no user repository names, credentials, or private account data.

The first production build correctly failed because an unbundled more_horiz ligature violated the typed Material Symbols allowlist. The action now uses the already bundled category glyph; the repeated build passed. The headless run restored the matching Electron 42.0.1 runtime from its checksum-verified local cache, with no download. Remote and CI publication evidence follows in the rolling progress record, Discussion #98.

2026-07-29 — Diagnostic logging and Cheap LFS hook containment

The current task adds two isolated reliability surfaces. The Cheap LFS cloud-compression workflow commit now uses a temporary empty core.hooksPath, closing the post-commit gap that --no-verify leaves. Its real-Git regression passes with a deliberately failing Git LFS-style hook and proves the exact one-file commit reaches the remote.

The repository now also contains the authenticated diagnostic log service, client remote transport, deployment runbook, feature documentation, and category/master Postman routes. The ARM64 service is running healthy at 192.168.50.242:4318 from /home/docker/services/desktop-material-diagnostic-log-server, with data at /home/docker/data/desktop-material-diagnostic-logs. Its bearer token exists only in the host-side mode-0600 secret file. Live ingest, redaction, search, and storage-status acceptance passed. Docker warned that this host does not enforce memory cgroup limits; CPU, PID, storage, retention, and application-level bounds remain active.

The issue-closeout, Cheap LFS helper, GitLab, and Windows bug-hunt lineages are now reconciled in the local main merge, and all six textual conflicts are resolved. The shutdown/profile persistence checkpoint is present at ac0e50fc2d; its focused tests and task-branch push passed before reconciliation. The merged tree then received four additional P1 repairs:

The post-reconciliation focused gate passes 194/194 tests across 17 files. TypeScript, targeted ESLint with the repository rules, targeted Prettier, the 231-entry documentation catalog, the generated hub parity gate, and the line-ending contract also pass. This is a source checkpoint, not the final acceptance claim. Completion still requires the full-tree gates, an exact Windows production build through the off-screen Lowlevel MCP workflow, runtime and updater-exit acceptance, a pushed default-branch proof, cleanup of every merged task worktree/branch, and the applicable issue receipts.

香港粵語:四條工作線已經喺本機 main 完整對齊,六個文字衝突亦已解決。 今輪再修正單一 clone 揀檔時序、clone helper 清單遺漏、重試關閉等候長時間 clone,同埋 reload 跨文件設定檔鎖/關閉確認競態;相關 194/194 個重點測試 已通過。未完成完整 Windows build、離屏實機驗證、推送同清理之前,唔會當成 最終完成。

Desktop Material is Windows-only. The five linux-tui-*.png files, the TUI source/package notes, and the July 27 Debian/Xvfb manifests are preserved historical records, not supported product/release targets and not blockers for this Windows close-out. Any later heading that says “read this first” is an archived point-in-time handoff and is explicitly superseded by this section.

Current-source updater capture accepted and published

The packaged development x64 application at runtime source b069384ad7d8a65d1192ee06859a705fe484c9c8 passed the real updater-ready gate. Screenshot promotion commit e3967f1b81ec039624500797dca40a1ab6d98598 publishes docs/assets/screenshots/auto-updater-current-source-ready.png: 960×660, 47,086 bytes, SHA-256 0fc9caf5b13eb5b914121090f403c394545e02ea4303b11dd4598afcb3a2dfca. The 12,299-byte receipt has SHA-256 50fe3ed0bcb5287786933a6ae1523021bd1417b1462a3fe5bb48d644d7527f3c.

The accepted package contains 6,210 files and 385 directories totalling 904,084,592 bytes, with SHA-256 1b728afc5c53c9a37b63b57af528a71356a726a1115458a458b6284fb05a7cdc. Its 226,677,760-byte GitHubDesktop.exe has SHA-256 7930378e3675b12f337784dd29018c5110b4b789ec5bb79be2cec6c83a8a0c40.

The verifier exercised real Electron/Squirrel events over loopback using a disclosed inert, no-executable 9000.0.1 full nupkg. It proved the exact current development x64 source, frontmost About, onboarding absent, and the ready state. Protected install and external state stayed unchanged. File Exit was requested before the graceful direct-quit fallback; Quit and Install was never clicked. Owned processes, registry state, install tree, profile, temporary state, and ready tree were removed, then the desktop listed zero windows and closed.

Original-resolution inspection rejected an earlier formally successful frame because Welcome covered About. The verifier was fixed to require the first-run checklist to be absent and to use elementFromPoint for a frontmost About attestation. That rejected candidate and the dated pending notes below remain historical facts; they are superseded as the current updater acceptance state. The immutable July 22 legacy migration frame remains a separate historical artifact.

香港粵語:今次用真 build 同真 Electron/Squirrel event,Welcome 遮住 About 嗰張舊候選圖已經打回頭;修正 gate 要 onboarding checklist 消失兼驗明 About 喺最前,先收貨 960×660 圖、receipt 同完整清理證明。Quit and Install 冇撳過,保護中嘅 install/外部狀態亦冇郁過。

Main consolidation and task-worktree cleanup

Every task tip was rechecked as clean and as an ancestor of both main and origin/main before cleanup:

Their six linked worktrees and local branches were removed. The merged remote origin/codex/bug-hunt-20260728 tip ac0e50fc2d4571ffe0ec8c6d72f929988daf35cb was also deleted. The one initialized submodule set was at its recorded commits with no modified or untracked content; the other five sets were uninitialized. Git left four dependency junction shells after unregistering the worktrees, so each exact junction was resolved and removed without traversal; the main checkout's root and app node_modules targets remained intact. The now-empty worktree parent was removed. Final cleanup proof must continue to show one registered main worktree, no local or origin task branches, and no stashes. The unrelated desktop-plus and upstream remotes were deliberately preserved.

香港粵語:六個 task tip 全部先驗明已經入咗本地同遠端 main、worktree 乾淨、submodule 冇改動,先刪 worktree、分支同已合併嘅遠端 task 分支; 共用 dependency junction 只刪連結本身,主 checkout 嘅 dependencies 冇郁。desktop-plusupstream 係無關 remote,所以保留。

Final regression and security sweep

The complete post-merge test run used application source d0be4827e0bb636132006d2c361ce845dc579f15 plus the documentation-only publication edits in this handoff. It accounted for all 873 discovered files across four batches: 7,112 tests reported, 7,111 passed, one intentional skip, zero failures, and exit code 0 in 457.47 seconds. The script suite separately reported 190 passes, two intentional skips, and zero failures.

yarn lint, yarn tsc, yarn test:eslint, the 27 updater/Pages verifier contracts, and the 17 screenshot/wiki contracts all passed. The documentation catalog regenerated 231 entries without a tracked generated-file change.

The full run exposed and then verified two late high-zoom regressions. The GitHub Releases controls now retain their normal 40 CSS-pixel target while the dedicated 125%–200% zoom layout uses 32 CSS pixels so a complete release row stays above the fold. The formerly contradictory tests now assert both scopes, and the verifier sources that had failed CI formatting are formatted.

The dependency sweep now resolves every brace-expansion consumer through the callable compatibility adapter backed by patched 5.0.8. The adapter is covered across minimatch 3/10, glob 7/13, bounded expansion, and Electron ASAR unpack globs. markdownlint-cli 0.49.1 now brings markdown-it 14.3.0 and linkify-it 5.0.2. The dev-dependency audit reports zero vulnerabilities, and GitHub reports zero open Dependabot alerts.

Nine CodeQL false positives were removed without exclusions or suppressions: fixed error strings are asserted exactly, the GHES host is checked as the exact --hostname argument, Git config uses JSON string serialization, and credential tests use length-checked constant-time equality without printing secrets. The subsequent CodeQL run closed all nine. One high alert remains: the production OAuth client secret is intentionally compiled into the native public client. Moving it to another shipped bundle would not secure it. GitHub's device flow is disabled for the bundled app registration, and changing to device flow or a confidential exchange broker requires external app-owner authority, a credential rotation/migration plan, and a product decision. Alert 45 therefore remains open rather than being dismissed inaccurately.

香港粵語:最終 full suite 873/873 個檔案都有結果,7,112 個 test 係 7,111 pass、1 個有意 skip、0 fail;lint、TypeScript、驗證器同文件合約 亦全綠。三個 Dependabot 漏洞已清零,九個 CodeQL 誤報用更精準斷言收妥。 OAuth secret 嗰個真實架構警報冇扮作解決:要 app owner 開 device flow 或者提供 confidential broker,同時要做憑證輪換先可以真正移除。

Security, packaging, and toolchain hardening checkpoint

The merged tree at d273ae95d7 received a second bug-hunt pass before packaged runtime acceptance:

Current local gates pass: a frozen root install (including the app/native post-install), repo-wide lint, TypeScript, 93/93 focused app tests, 186/188 script tests with only the absent ARM64 toolchain and optional Mermaid browser skipped, 4/4 custom ESLint-rule tests, and the TUI's 250 tests with its one platform-only skip plus Ruff and Mypy. The dependency audit is reduced to one unique brace-expansion advisory through four repository build/lint paths; no compatible 1.x patch exists, those paths do not ship in the app, and forcing the incompatible 5.x API into Minimatch 3 was rejected.

This is still a source checkpoint. The exact committed tip needs its own production build, packaged-tree proof, off-screen updater receipt and inspected 960×660 screenshot, full 7,100-test gate after screenshot promotion, final documentation push, remote CI/Pages proof, and merged branch/worktree cleanup.

香港粵語:第二輪已加固封裝 symlink/reparse point、原生編譯器參數、OCI 驗證、加密長度、文件 HTML 解析、OAuth bundle 邊界、ESLint AST 相容性同 依賴鎖檔;fresh install、lint、TypeScript、重點 app/script/TUI 測試已 通過。未完成同一個 commit 嘅 Windows 封裝、離屏 updater receipt、完整 7,100 個測試、遠端 CI/Pages 同分支/worktree 清理之前,仍然唔會當成 最終完成。

Superseded stop-now checkpoint

The last exact source-and-verifier checkpoint is ddfbec8302cd4ac4f5f4fb4313f36505dd34750c, and the stop-now handoff recording its final boundary is pushed at d107b0aeb8be2db6f3bd1baf152548249bcd562b. Local and remote main matched that latter commit before this final cleanup note. The completed Cheap LFS and close-out source tips are ancestors of pushed main; their two remote task branches were deleted after that proof.

The exact-tip updater run built ddfbec8302 successfully and reached the real Electron/Squirrel Update ready UI. Chromium wrote a 960×660, 46,232-byte candidate PNG, but the verifier deliberately rejected the run because its normal File → Exit request left the owned app process alive beyond the 45-second cleanup bound. The candidate was therefore not promoted to the gallery and no complete verifier receipt exists. Cleanup was then performed through the real app dispatcher with quitApp(true) on the same off-screen desktop. The app process count and headless window count both reached zero, and DesktopMaterialMainUpdater-20260728-441a0f01ca54 was released. A successor should repair the verifier's normal-exit boundary, rerun it from a clean owned root, require the complete receipt, inspect the image at original pixels, and only then promote the screenshot.

The focused updater source gates completed before this stop: updater behavior 31/31, release-note behavior 6/6, and verifier contract 18/18, with TypeScript and targeted formatting/lint clean. Full final-tree tests and the exact pushed CI/release verdict remain remote or outstanding and must be reported as such.

Eight sibling directories that were no longer registered Git worktrees were revalidated as empty shells containing only two junctions back to this checkout's dependency directories. The junctions were unlinked first and all eight empty shells were removed. The failed updater run root contained no live owned process or reparse point; its read-only Git objects were normalized and the exact temporary root was then removed. No stash or additional registered worktree remains.

origin/codex/bug-hunt-20260728 is intentionally preserved at bd0041d33989ded70ba1b6424b538312d502b455. It is an unfinished lineage, not cleanup debris: 25 commits diverge from main, a trial merge has six content conflicts, and exact-tip CI run 30420344514 failed current docs/gallery gates. Its own handoff still requires a build, full tests, visual acceptance, and issue receipts. Do not delete or wholesale-merge it until those changes are reconciled and verified.

For d107b0aeb8, Cheap LFS cloud compression run 30423623373 passed, while CI 30423623412 and Code scanning 30423623414 were still running at handoff. No release targeted that SHA yet. The continuous issue scan remained #23, #80, #81, #82, #85, #87, #94, #95, and #96.

Cheap LFS long Windows filenames and materialized-pull boundary

The integrated tree now keeps every Cheap LFS recovery/materialization component independent of the tracked basename. A valid 200-unit Windows filename previously grew to 256–267 units when the tracked store, GHCR/OCI restore, or generated clone hydrator appended its suffix; a 255-unit filename grew to 311–322. Those per-component overflows are not repaired by core.longpaths, \\?\, a short checkout root, or 8.3 aliases. The new bounded process/UUID names cover tracked recovery, consumed sources, GHCR staging, OCI materialization, and generated hydration. Current and historical crash-orphan shapes are also recognized by the owned-artifact scanner and private info/exclude block.

The focused Windows regression gate passes 82/82 tests across seven files: 255-unit tracked publish/replace, 200-unit Release helper hydration, 200-unit GHCR and OCI materialization, all bounded sidecar kinds, and current/legacy owned-artifact shapes. That is a source-level checkpoint only. The earlier successful exact-67d475fd5e production compile/package is now superseded by this later source change; the bounded-sidecar final tip still needs its own full build, headless acceptance, commit, push, CI, and installer release.

The reported Pull dialog is a separate boundary. Desktop projects an exact-hash Materialized payload as clean, while Git still sees raw bytes where its index carries a pointer and correctly refuses an incoming overwrite. Do not use Stash changes and continue for multi-gigabyte materialized payloads. On the current build, first copy those verified payloads outside the repository, restore only paths explicitly marked Materialized from HEAD, pull, run Materialize all, and retain the backup until hydration verifies. An edited or Modified path must never be restored this way.

Standalone Cheap LFS versus Git LFS comparison atlas

The Pages lineage based on remote 823f7fa0e5 added site/cheap-lfs-vs-git-lfs.html as a genuinely separate route rather than stretching the existing product guide again. The route controller defines exactly 72 bilingual, row-level sourced criteria in 12 categories and renders desktop table plus narrow card views. Its fit signals are contextual: cheap, git, tie, or depends; there is no aggregated product winner.

Six browser-style tabs separate the verdict, matrix, exact git push handoff, workflow diagrams, fit finder, and source library. Tab order, pins, active hash, and per-tab font/size/color/radius appearance persist. Comparison category and outcome persist under route-specific keys, while the page shares the established EN/粵/EN+粵, independent funny-level, and theme keys. Text search remains plain by default. Explicit regex mode delegates both search and builder work to the documentation site's shared same-origin worker, which the page terminates at 750 ms; patterns never compile on the page thread and are not persisted.

The dedicated push tab preserves the product boundary: provider bytes and provider proof precede a Cheap pointer commit on an established branch; a first Release-backed publication may need the app's create-only anchor; OCI does not. Plain git push publishes the already-created pointer commit. The proof inspects git show HEAD:path/to/large-file.bin, pushes, fetches, and requires git rev-parse HEAD to equal git rev-parse '@{upstream}'. It warns that materialized raw bytes may appear modified and must not be added over the pointer, and that ordinary git push --set-upstream origin HEAD is not the app's hook-skipping anchor. The parallel Git LFS lane documents tracking, .gitattributes, the clean filter, and the pre-push hook.

The two marketing graphics are code-native site/assets/cheap-lfs/comparison-orbit.svg and site/assets/cheap-lfs/pointer-paths.svg; they are conceptual diagrams with accessible titles/descriptions, not fabricated app evidence. The full feature contract is docs/features/repository-management/cheap-lfs-vs-git-lfs.md.

Verification state: local Pages acceptance completed before integration. The new 72-row contract and original 30-row guide pass; documentation catalog/hub/regex/search suites pass 59/59; and the exact Lowlevel MCP run passed 35/35 installed-Chrome checks in six phases with 33/33 HTTP 200 responses, zero runtime errors, zero document overflow at 1440×960 and 390×844, and verified browser/server cleanup. The accepted captures and hashes live in docs/verification/cheap-lfs-vs-git-lfs-pages-2026-07-28/.

That branch base predates renderer multi-compiler correction 6903c9ae1e. Its skill-required production-build attempt entered that known pre-fix webpack path, so only the validated task-owned ten-process tree was stopped. The captured boundary is returncode=4294967295, empty stderr, and timed_out=false; no app-build success is claimed. The route is now present on remote main at 80e0209a12f41df8a6a80ef52925b52ab9ecb1b0, and Pages run 30391300142 deployed that source successfully. Final exact application build proof still belongs to the integrated tree.

Cheap LFS Pages comparison and push guide

site/cheap-lfs.html now presents a filterable 30-decision Cheap LFS versus Git LFS comparison and a six-stage push handoff. The copy is deliberately marketing-forward without hiding the boundaries: an established branch uploads and verifies provider bytes before the compact pointer commit is pushed; a first Release-backed publication may require the app's create-only, hook-skipping branch anchor first. The CLI proof uses git show for the committed pointer, warns against adding the materialized raw file, fetches the remote, and requires HEAD to equal @{upstream}.

The dedicated verifier served the assembled site on loopback and drove installed Chrome headlessly through Lowlevel MCP. Its 46/46 checks across eight phases covered all three language modes, both themes, independent funny-level persistence, every comparison filter and reload persistence, desktop and 390 px overflow, compact-nav keyboard reachability, image/network health, and browser/server cleanup. Accepted captures are docs/verification/cheap-lfs-pages-revamp-2026-07-28/cheap-lfs-comparison-wide.png (1440×960) and cheap-lfs-push-narrow.png (390×844); exact hashes and the Pages-only evidence boundary are in the dated receipt.

The skill-required full Electron production build was started through the exact Lowlevel MCP endpoint but remained silent for more than 34 minutes. It was interrupted when the user prioritized publishing the site update, so this milestone makes no full-app build claim and changes no app screenshot.

Close-all-open-issues verification provenance

Integrated close-out gate

The close-all-open-issues wave is merged locally but remains unpushed. Source and contract work is present, but completion still requires the exact Windows production build, the declared focused and full test gates, fresh acceptance for all 86 Windows gallery targets, default-branch integration and push proof, and separate finished/closing receipts for each issue. None of those remaining gates is inferred from an older screenshot or test run.

Desktop Material is Windows-only. The five linux-tui-*.png files, the TUI source/package notes, and the July 27 Debian/Xvfb manifests are preserved historical records, not supported product/release targets and not blockers for this Windows close-out. Any later heading that says “read this first” is an archived point-in-time handoff and is explicitly superseded by this section.

Immutable provenance for historical screenshot hashes

Every dated screenshot byte count/SHA table below refers to the exact commit-addressed blob in this table. The pathname is a display label, not a claim that mutable main still contains the same bytes after a gallery refresh.

Historical frame Immutable source blob
Tab groups material-tab-groups.png at 58be6fe5953477b015a134c414a8cf82363ecc75
Command palette material-command-palette-appearance.png at 58be6fe5953477b015a134c414a8cf82363ecc75
Cheap LFS UI cheap-lfs-ui-acceptance.png at 342a1548009a3e1591c27f7a4af82cf6cf02c96e
Cheap LFS cloud cheap-lfs-cloud-compression.png at f7b4760a13894f0320f7b361f055f6fba40d913f
Cheap LFS commit progress cheap-lfs-commit-progress.png at c3db37ea5524b91f9603151ae5d1107205f16a59
Compact Releases material-github-releases-compact.png at 513c5cc96aee045a218837530a11951e8466b618
Legacy updater migration auto-updater-update-ready.png at 923dbb51acad8f01f01f1c100c6945c7a2e08e23
Safe regex builder regex-builder.png at f8eca3ac844e8eaec2dc2dce635f57874b4e92bc

Superseded pre-final-review TypeScript gate

The logged root npx tsc --noEmit run completed with exit 0 after its foreground wait had timed out. The authoritative files are %TEMP%\DesktopMaterial-close-all-open-issues-20260728-1581a0ec8c65\logs\tsc-noemit-source-freeze.log and %TEMP%\DesktopMaterial-close-all-open-issues-20260728-1581a0ec8c65\logs\tsc-noemit-source-freeze.exit; an empty log is expected for this clean compiler pass. Wrapper PID 14588 and compiler PID 19300 were both rechecked and proved absent, so the gate left no owned compiler process running. Later adversarial review changed progressive error normalization and its tests, so this earlier pass is retained only as a scoped historical checkpoint and is not the final-tree TypeScript proof. A second run begun before that review finished was deliberately marked superseded; its exact wrapper/command/compiler/console-host process tree (3148, 6168, 16148, 16340) was stopped and proved absent. Final closure requires a fresh post-review compiler run. Neither checkpoint stands in for the production build, full test suite, visual acceptance, publication, or issue closure.

Reviewed-source checkpoint before main reconciliation

After the adversarial code and documentation reviews completed, a fresh npx tsc --noEmit run passed with exit 0, and yarn lint passed the repository-wide Prettier check, the ESLint/Prettier compatibility check, and source ESLint with exit 0 in 319.30 seconds. The authoritative files are %TEMP%\DesktopMaterial-close-all-open-issues-20260728-1581a0ec8c65\logs\tsc-noemit-reviewed-source-freeze.{log,exit} and %TEMP%\DesktopMaterial-close-all-open-issues-20260728-1581a0ec8c65\logs\yarn-lint-reviewed-source.{log,exit}. Their wrapper/compiler process trees were rechecked and proved absent.

All 16 verifier contract files then ran. 206/207 assertions passed; the only failure was the intended fail-closed Pages import because the distinct current-source updater frame, auto-updater-current-source-ready.png, does not exist yet. The complete log is %TEMP%\DesktopMaterial-close-all-open-issues-20260728-1581a0ec8c65\logs\verifier-contracts-reviewed-source.log. This checkpoint predates reconciliation with the newer remote main fixes, including #96, so the same gates must run again on the merged source before the exact build.

Post-checkpoint acceptance and CI reconciliation

The pushed close-out checkpoint is 2fedf140e394fa2fea3e380203e716b6f7aa8628. Remote CI run 30370044526 completed with successful lint, Windows TUI core, and packaged Windows x64 E2E smoke. Its 845-file/6,957-test Windows x64 unit run had exactly seven leaf failures: the two deliberate missing-updater gallery gates plus five stale source/copy assertions described below. Three Linux TUI jobs stopped only at the generated parity-contract hash, and Windows arm64 script tests stopped only at the generated documentation catalog. The parity contract has therefore been regenerated from the current 201-row source. The documentation catalog repair already exists on newer main and will be regenerated again only after the final documentation tree is reconciled.

The preceding branch run also exposed three stale source-shape tests. Their assertions now follow the current lazy repository-tools JSX wiring, the shared context-menu appearance helper, and the localized “Subtrees could not be loaded” copy. These are test-contract repairs, not product-behavior changes. The updater/wiki failures remain deliberately unresolved until the distinct current-source updater frame is produced by the packaged-build verifier.

A separate read-only acceptance audit proved that every required verifier implementation exists, but found two printed command templates that their own containment checks would reject. The internal-browser receipt is now a direct child of its owned run root, and the Ollama receipt now shares the owned P0 captures directory with its PNG. A cross-contract assertion pins both rules. After the shared renderer profiler became quiescent, the three repaired app test files passed 46/46 across 3/3 files, the regenerated 201-row parity contract passed its checked-generation gate, and the gallery plus live Cheap LFS contracts passed 75/75. Prettier, application-test ESLint, the repository-ignored verifier lint with its intentional CommonJS/synchronous rules disabled, syntax checks, and git diff --check are green. The authoritative logs are %TEMP%\DesktopMaterial-close-all-open-issues-20260728-1581a0ec8c65\logs\post-ci-repair-{targeted-tests,contracts,format-lint}.log. Those reviewed repairs and provenance fences are pushed at 107bd91a003f490fa3d91cc642a7beaa350d2c35; branch CI run 30376865471 is queued. The matching rolling checkpoint is Discussion #54 comment 17815363, and the private-gallery authority boundary is recorded on #23 comment 5106684118. Those two earlier receipts printed a nonexistent source-gate SHA; the correction is explicit in Discussion comment 17815648 and #23 comment 5107001088. Only 107bd91a003f490fa3d91cc642a7beaa350d2c35 is authoritative.

The open-issue scan after that audit remains exactly #23, #80, #81, #82, #85, #87, #94, #95, and #96. Two #23 specialist frames still require read access to DingDingChae/desktop-material-cheap-lfs-private-20260722-153308. Both GitHub API and non-prompting HTTPS checks under the active codingmachineedge identity return not-found. No substitute repository, historical frame, or mocked provenance will be represented as that private live acceptance.

The read-only audit also found that the cloud specialist's current pin is internally inconsistent with the retained history. Its verifier requires e56519d4742c63bb2c9f5f1e917de3fca7379fdd, the pre-compression UI-acceptance commit, while simultaneously requiring the compressed pointer first documented at 6259b0fa0dc6c65cdb5a90af8e1da9358b45b0ac and today's no-private-workflow encrypted-builder routing. Read access is required first to inspect authentic later history. If no retained commit contains the compressed pointer with the legacy private workflow removed, producing that current-state evidence will require separate owner authorization for one narrowly scoped fixture commit; it will not be inferred from the request to capture screenshots.

The live Cheap LFS specialist now fails closed around that boundary. Before attaching to Chromium, after the settled production surface proves the current builder-routing state, and immediately after original-pixel capture, it bookends read-only Git snapshots and requires a clean main checkout at the exact origin/main SHA. Every fence revalidates the repository root and .git directory as the same real directories, checks Git's reported top-level and absolute Git directory, and rebinds the reviewed GitHub origin. The cloud scene additionally requires .github/workflows/cheap-lfs-cloud-compression.yml to be absent from HEAD, the index, and the real working tree; link/junction parents, ignored occupants, and any other non-absence fail. A version-2 receipt binds the exact reviewed commit, hashed origin, and stable filesystem identity to its canonical SHA-256 fingerprints. Capture creation uses an exclusive descriptor, full write, fsync, and identity-aware cleanup; the fully written receipt is published atomically without overwriting through a same-directory hard link. The focused contract passes 20/20, including real dangling-link and atomic-publication probes plus injected write failures. This closes the verifier's mount-time rewrite and orphan-output gaps without pretending that the inaccessible, internally inconsistent fixture pin is resolved. A mutation that begins and fully reverts between samples remains the unavoidable read-only TOCTOU limit; the owned fresh clone and three double-fenced samples are the strongest non-mutating mitigation.

2026-07-28 — Bounded Cheap LFS inventory joins the close-out (Refs #96)

Issue #96 was filed while this campaign was active. The initial fix landed on remote main and is now present through this merge. Adversarial review showed that its size preflight still sent a pointer-looking oversized file to git grep -I --untracked, so a hostile 50+ GiB sparse file could exhaust Git before Desktop Material's bounded format validator ran.

The close-out branch now removes working-tree content from Git grep entirely. Unscoped inventory asks Git only for NUL-delimited changed/untracked names; explicit path selections are validated before any asynchronous Git work. Each candidate is then proven as an in-repository regular single-link file and only its first 512 bytes are read through the tracked-path store. The prefix read requires a settled identity, rechecks the opened handle and visible path after the read, revalidates every parent, refuses symlinks/reparse points, gitlinks, linked files, and identity drift, and rejects unsafe or non-safe-integer bounds. Clean committed pointers remain classified from their bounded working-tree text. Pointer-looking oversized files are carried to the existing bounded format rejection; raw oversized files never enter content grep.

The regression uses real NTFS sparse files with the issue's exact logical size, 55,581,030,080 bytes, for both raw and pointer-looking cases. Git Trace2 proves the vulnerable grep --untracked command is absent while the bounded name inventory still runs. It also covers scoped and unscoped calls, traversal prevalidation, clean committed pointers, modified gitlinks, selected symlinks, the exact pointer-format boundary, future-mtime/unsettled identity proofs, and invalid prefix bounds. The final focused pair passes 82/82; the complete Cheap LFS directory passes 673/673 across 48 files and 89 suites in 187.55 seconds. Two independent adversarial reviewers found no remaining actionable blocker in #96's reported working-tree scope. Index/HEAD Git-object inventory still uses bounded-result Git plumbing and is recorded as a separate hardening opportunity, not part of #96's explicit --untracked reproduction.

The source fix is closure-ready locally, but the issue remains open. Final closure still requires a fresh final-tree typecheck/lint pass after all reconciliation, the exact MCP production build, pushed main ancestry, applicable remote checks, and a timestamped finished receipt.

The current guided-gallery contract, capture plan, and Pages manifest declare exactly 84 Windows targets: 67 canonical outputs and 17 specialist outputs. That declaration does not become a published 84-image acceptance until every target exists and passes the current-build capture, privacy, and promotion gates. The five original linux-tui-*.png files and their dated Debian/Xvfb manifests remain byte-for-byte historical evidence, but are explicitly outside the current gallery rows, raw-main image set, Pages figures, and promotion plan. README/wiki/site screenshot surfaces describe that boundary without relabeling the old pixels as Windows evidence.

Issue #23's older public body and comments contain superseded 77- and 89-image counts. Its final evidence comment must explicitly correct that history to the current contract: 84 blocking Windows scenes, plus five preserved historical Linux/Xvfb frames outside the current set.

The July 22 legacy updater-migration frame is also retained outside the current set at immutable commit 923dbb51acad8f01f01f1c100c6945c7a2e08e23. Current-source updater acceptance owns a distinct filename, so its promotion cannot overwrite or relabel those 49,195 historical bytes.

Static documentation generation and the non-image-dependent documentation, tab-count, tooltip-lifetime, and localization checks pass. The fail-closed gallery validity checks correctly remain red because the distinct auto-updater-current-source-ready.png target has not yet been captured; the legacy updater blob is historical evidence and cannot satisfy that current slot. No UI was launched and no screenshot was recaptured or deleted in this documentation checkpoint. Issue closure still requires current-build acceptance for all 84 Windows targets.

2026-07-28 — Measured Changes/History renderer update suppression (main checkpoint)

The exact baseline v3.6.3-beta3-zadughkqcv Windows x64 portable build at 9bdfdb8b25e458e4834bdaa26473d44a5602621d was driven on an isolated Lowlevel MCP Win32 desktop. Idle rendering was already smooth (122/122 frames at 16.51 ms average, 16.80 ms max, zero over 25 ms), but twelve warmed Changes/History switches measured 56–104 ms and six 59–67 ms long tasks. A single Changes click measured 104 ms, one 62 ms long task, and 166 mutation records.

RepositoryView.onTabClicked always dispatched updateCompareForm({ showBranchList: false }) after the real section mutation. AppStore._updateCompareForm then merged and emitted even when the value was already false, producing a second root render for one user click. Navigation now dispatches only when the list is open, and a store-level equality gate protects every caller. Focused responsiveness, lifecycle, progressive-loading, and navigation coverage passed 42/42. In that source checkout, changed-file ESLint could not load five repository-specific rules; it reported only missing rule definitions, not source findings.

That source checkout's mandated production build and direct compile diagnostic both reached bounded webpack timeouts, and its reused incomplete dependency tree left repository-wide TypeScript red without naming the new helper or test. No post-fix binary or timing was claimed by that checkpoint. The merged close-out tree still owes the final gates listed in the current handoff above.

2026-07-28 — Tab-group dialogs move onto the dialog layer (Refs #92)

CreateTabGroupDialog/EditTabGroupDialog rendered inline in repository-tab-strip.tsx. Dialog carries tooltip-host, whose position: relative overrides the UA position: absolute on <dialog>, so they laid out as in-flow flex items of the strip at z-index: auto and the app bar's positioned pills painted over the Group color swatches. Both now portal into #dialog-layer via the new app/src/ui/dialog/dialog-layer.tsx. Second defect in the same frame: Tooltip anchors mouse-placed tips to mouseRect, which stays (0,0,0,0) when a tip is shown by focus, and getDirection falls back to an unclamped SOUTH — so the tip landed half outside the window. getTargetRect now falls back to the target's box and clampTooltipRectToWindow bounds every tooltip. Verified: 17/17 across the three touched test files (5 new, each confirmed failing before the fix), tsc exits 0, eslint and repo-wide prettier clean. Not visually verified — no build or capture was run on this worktree.

2026-07-28 — Disconnected tooltip owners clean up immediately (Refs #94)

A tooltip could outlive a transient button or row when React removed its owner without dispatching mouseout or blur. Tooltip now observes target connectivity only while a tip is pending or visible. If the target disconnects, it cancels pending show/hide timers, stops its observer and viewport listeners, removes the portal, and clears the old target's tooltip marker and aria-describedby; unmount performs the same cleanup. Focused regressions cover both removal before the delay expires and removal after the tooltip is visible. Final built-app acceptance remains part of the current Windows gate and is not claimed here.

2026-07-28 — Tab counts use truthful singular and many copy (Refs #95)

Count selection now lives in tab-count-copy.ts instead of being scattered through individual controls. English uses singular copy for exactly one and the many form for zero or two-plus across the group chip, edit-dialog intro, member-menu button/status, and overflow-button accessible name. Cantonese keeps its natural count wording while using the same one/many selection contract. Unit coverage exercises 0, 1, and 2 in English and Cantonese and checks the real collapsed-group and overflow-button accessible names. The fresh source-freeze #95/i18n run covered 4/4 declared files and passed 64/64 tests with exit 0; its authoritative files are %TEMP%\DesktopMaterial-close-all-open-issues-20260728-1581a0ec8c65\logs\focused-tab-copy-source-freeze.log and the matching .exit file. Wrapper PID 3252 was rechecked and proved absent. This is exact focused proof, not built-app acceptance, which remains pending with the current Windows gate.

2026-07-28 — Encrypted restore names the decrypting phase (Refs #85)

Encrypted-and-compressed Release restores now report the real transform order: Downloading → Decrypting → Decompressing → Verifying → Materializing. The plain bilingual label is Decrypting · 解密緊; funny-level voice may vary without changing the phase, path, byte counts, or order. The focused operation, progress, localization, and real-operation verifier contracts cover the distinct phase. Exact current-build UI acceptance remains pending and is not borrowed from the July 22 Cheap LFS screenshots.

2026-07-28 — Unattended encrypted Cheap LFS pin skips instead of prompting (Refs #87)

isBackgroundTask now reaches autoPinLargeFilesBeforeCommit. A scheduled commit whose repository has Release payload encryption on and no saved password skips the pin via app/src/lib/cheap-lfs/unattended-encryption.ts — nothing encrypted, nothing uploaded, no anchor published, the large files left in the working tree and out of that commit, and one non-blocking notice per repository. The interactive modal is unchanged. Verified: 638/638 Cheap LFS tests green (22 new), npx tsc --noEmit exits 0, yarn lint clean. Not visually verified — no build was run.

2026-07-28 — Shift+Right-click opens appearance editors (Refs #89)

The appearance editor no longer claims a plain right-click anywhere. The gesture is now Shift+Right-click, decided once by isAppearanceEditorPointerGesture in app/src/ui/appearance/; the shell-wide document listener in app.tsx uses isAppearanceEditorFallbackContextMenu, which also accepts a keyboard-originated context menu so those owners never become mouse-only. Surfaces with a real menu (tab strip, tab overflow rows, repository list) keep it and their Customize entries. Settings → Appearance advertises the gesture in both languages at every playfulness level. Verified: 100 unit tests across 15 files green, eslint and prettier clean. Not visually verified — no build was run.

The two pre-existing tsc errors that branch recorded against its base (operations.ts and app.tsx) were the merge-collision damage fixed in ff53cd2155; after merging, npx tsc --noEmit exits 0 on this tree.

2026-07-28 — Root renderer resource lifetime audit (historical predecessor checkout snapshot)

The root App created telemetry and update-check intervals without retaining their handles, while componentWillUnmount cleared only an unrelated interval. A queued idle callback could therefore start permanent polling after unmount. The same root instance was retained by undisposed app/build/updater/drag subscriptions, three IPC listeners, document drag/drop/focus handlers, and application-menu key listeners.

The fix collects subscriptions in one CompositeDisposable, makes typed IPC on() registrations disposable, retains and clears both deferred timer handles, releases every global handler, and guards queued idle/animation-frame work with the mounted state. Focused lifecycle tests pass 4/4 and ESLint is clean on all three changed files.

In that predecessor checkout, the exact Lowlevel MCP headless build preflight passed against server checkout f2edfe442555cfe35a519dd0b058986cb09d6ee3, but the mandated production build stopped before compilation because that predecessor checkout had no dependency tree and npx --no-install correctly refused to download missing cross-env. Repository-wide TypeScript was also red from missing baseline dependencies (dugite, registry-js, Copilot SDK, Dexie, and others); no reported diagnostic targeted the changed files. That checkout-specific environment is superseded by the current handoff and is not a current blocker or current test verdict.

2026-07-27 — Progressive asynchronous lazy loading (locally verified, Refs #82)

App.render() returns null until AppStore.loadInitialState() resolves, so every await in that method was a blank window. Two of them were slow and optional: enumerating installed external editors (a filesystem walk plus, on Windows, a registry read) and recovering the interrupted clone-queue journal. Both now run in loadDeferredInitialState(), which loadInitialState() starts without awaiting. The selected editor is adopted from localStorage so the shell paints with the user's real choice; the availability scan corrects it afterwards and drops its own answer when externalEditorSelectionGeneration shows the user picked an editor while it was running. Each deferred step is isolated and reports failures through sendNonFatalException('deferredStartup') rather than swallowing them. No timers were introduced anywhere in that path.

repository.tsx previously imported seven substantial section modules statically (Actions, Releases, Cheap LFS, Issues, GitHub API explorer, provider triage, repository tools), so all seven were evaluated at launch even in a session that only looked at Changes. They are now type-only imports plus direct named asynchronous imports, rendered through a new LazyView. The production renderer emits the exact seven repository-*.js chunks; no webpackMode: "eager" or barrel import remains. Changes and History stay static. A failing section shows a local role="alert" surface naming the real error with a working retry, plus a persistent corner notification — never a modal, never a focus move. Webpack chunk failures retain the actionable chunk name while redacting only a private file:///C:/…/out/ installation prefix before the message reaches either surface.

app/src/lib/progressive-load.ts holds the ordering rules once: LatestLoadGate refuses a token that is not strictly newer than the last accepted one, and ProgressiveLoad.run() never rejects, turning a rejection into a failed state carrying the real Error. It is used by LazyView and by the submodule/subtree count loaders in repository.tsx, which also stop discarding their failure reason in a bare catch {}.

Current focused evidence is 37/37 across progressive-load-test.ts, ui/lazy-view-test.tsx, and progressive-startup-test.ts; the new packaged verifier contract is 8/8. That verifier inventories the exact seven chunks, withholds only repository-tools.js, observes the real accessible loading→local-failure transition without focus or modal theft, restores the identical SHA-256, uses the physical Try again control, and requires a spinner-free cached revisit. The final exact MCP build and off-screen original-pixel execution remain the publication gate and are not claimed by this source checkpoint.

2026-07-27 — Funny-level sliders: superseded by the owner's own integration (Refs #83)

A parallel implementation of #83 was written on this branch and then discarded during the merge with origin/main, because the repository owner had independently implemented and pushed the same feature in a550dc1ea8 ("Integrate safer pushes, encrypted payloads, and funny controls"). Their version is the one that ships; FunnyLevelControls (app/src/ui/preferences/funny-level-controls.tsx) and its 14-test suite were deleted rather than merged, because two implementations of one settings control is strictly worse than either alone.

The same happened to the #78 encryption work merged earlier from this branch: a550dc1ea8 deleted app/src/lib/cheap-lfs/encrypted-payload.ts, app/src/ui/repository-settings/cheap-lfs-encryption-gate.tsx and their three test files, replacing them with payload-encryption-credentials.ts and cheap-lfs-payload-password.tsx. That deletion is the owner's call and stands.

What survived from this branch, because the owner's commits did not cover it: the decrypting restore phase (#85), progressive lazy loading (#82), the repository/tab group management merged in a2ad99e218 (#81), the capture fixture's menu: step, and the two CI test repairs below.

2026-07-27 — Observed user-initiated push/pull/fetch promises (locally verified, Refs #80)

Pressing Push origin could surface the generic "A background action stopped unexpectedly" notice instead of the real failure. The toolbar handler started dispatcher.push(...) and dropped the returned promise, so when the push preflight's hosted-repository lookup 404s and repositoryWithCanonicalRemoteForNetwork rejects, the renderer's global unhandledrejection containment in app/src/ui/index.tsx — which is deliberately generic so an arbitrary rejection cannot copy a credential onto the screen — was the only thing left to report it.

The rejection was never double-reported by the store: performFailableOperation catches a Git-level push failure, calls emitError, and resolves, so a rejection escaping _push is by construction a failure nothing has presented. The fix is therefore observe-and-report at the call site, not observe-and-swallow. New helpers live in app/src/ui/lib/observed-operations.ts; the toolbar push/force-push/pull/fetch, the menu push and force push, the force-push confirmation dialog, and the workflow-push-rejection retry now route their promise through observeUserInitiatedOperation, while the previously void-ed provider triage refresh is contained as a background diagnostic via containBackgroundOperation. A failed canonical-remote preflight still runs no Git command at all — withCanonicalRemoteForNetwork never invokes performPush when the destination cannot be proven.

Local evidence: app/test/unit/push-rejection-observation-test.tsx passes 17/17, including a rendered PushPullButton click on a rejecting push (asserted to post the real error once and leave nothing for Node's unhandledRejection), and the same suite fails 2/17 when the observation is reverted. Adjacent suites pass — provider triage and canonical-remote preflight 52/52, source-regex/style neighbours 100/100, docs-hub catalog 33/33. npx tsc --noEmit, ESLint, and Prettier are all clean. Remote CI, installer, and built-app screenshot evidence for #80 remain outstanding.

2026-07-27 — Historical encryption/network/tone checkpoint (superseded status)

The current local implementation covers three open issues. #78 provides optional AES-256-GCM encryption for GitHub Release-backed Cheap LFS payloads: the app asks once per operation unless the user explicitly opts into the Windows credential vault, reads legacy pointer formats, restores plaintext legacy payloads without prompting, and fails closed when authentication and cleanup both fail. #80 observes asynchronous push, fetch, and pull actions and shows an invalid canonical remote as a persistent yellow notification whose Change remote URL action opens the repair surface. #83 restores separate, persisted 1–5 funny-level sliders for English and Cantonese. #81 and #82 are deliberately deferred to a later continuation.

Current local evidence is 194/194 focused tests and 6768/6768 full tests across 831 files, with tsc and yarn lint clean. This checkpoint does not claim packaged visual evidence or remote CI. #78, #80, and #83 remain open pending screenshots captured from the real built application.

2026-07-27 — Historical TUI path browser and Cheap LFS Git wrapper (archived, non-blocking)

The Linux-first Textual edition now has a folder-only browser in its Open and Create repository dialogs. Browse/Hide, Home, and Up remain reachable by mouse and keyboard while the repository path stays a real editable field. Matching outer single or double quotes are removed from pasted paths immediately where the terminal exposes bracketed paste, with the same normalization at submission. The input is treated only as a path: it is never evaluated by a shell.

The literal github launcher now also provides bounded native-Git routing:

The README and installation guide include one-line Linux shell and Windows PowerShell installs. Both install the github, dmt, and desktop-material-tui launchers through uv and run uv tool update-shell so uv's tool directory is added to future shell PATH values.

Current automated evidence is green:

Gate Result
full Windows-hosted TUI suite 250 passed, 1 Linux-only skip in 182.76 s
focused path normalization/browser/Pilot suite 29 passed
focused Cheap LFS Git-wrapper suite 47 passed
Ruff lint and format clean
strict mypy, normal and explicit Linux platform clean
package build wheel and source distribution built successfully

The final handoff accepted the source and package with one bounded visual gap. A disposable Debian/Xvfb/xterm run launched the packaged TUI and captured the real Open repository dialog. Its deterministic bare-remote fixture advanced through safe-push and pointer; the consumer restored 23 bytes whose SHA-256 exactly matched both the pointer and cache object. The Windows uv tool install puts all three 0.1.0 launchers in C:\Users\cntow\.local\bin, which was already on PATH, and the Linux wheel smoke reported the same aliases. The owned distro, displays, fixtures, and virtual environments were destroyed and proved absent. Immediate bracketed-paste normalization, the expanded-tree click path, narrow live resize, and Ctrl+Q exit remain automated rather than accepted visual evidence, as recorded without inference in the run manifest and cleanup ledger.

The preceding TUI compatibility correction commit f555d374a6 is contained in origin/main. In CI run 30317262582, the Linux TUI Python matrix and Windows TUI core job passed, but the workflow overall failed in the unrelated Windows x64 unit job. Installer run 30318769692 failed and published no Release. Feature commit 62420efaf6 is integrated and pushed through merge f5f6f04c7e, which remains an ancestor of current remote main. For that exact merge, Pages run 30323259671 and Cheap LFS cloud run 30323259650 passed; CI run 30323259648 and code-scanning run 30323259706 were still running at handoff and are not claimed green.

2026-07-27 — Historical TUI compatibility correction (archived, non-blocking)

The first CI run for merged source 2abccae8fd exposed two real portability defects after the earlier local matrix:

The Git porcelain, reflog, and profile-history parsers now normalize only a terminal uppercase Z to +00:00; numeric offsets and malformed-date failure behavior remain unchanged. The Windows lock branch now imports msvcrt dynamically as Any, matching the existing fcntl runtime boundary. The installer workflow also skips TUI package work when prepare has already marked an upstream failed-CI target as non-publishable. That prevents a newly loaded workflow from assuming a historical pre-TUI target contains tui/, while successful current-source release runs still require the wheel and source distribution.

Local correction evidence is green: the isolated CPython 3.10.20 full suite passed 193 tests with one Windows-host Linux-PTY skip, the affected post-format set passed 35/35, Ruff lint/format passed, strict mypy passed all 47 source files for both Linux and Windows platforms, 32 focused persistence/CLI tests passed, and the release workflow safety suite passed 8/8. Packaged Windows E2E passed in job 90140843987. Correction commit f555d374a6 is contained in origin/main. CI run 30317262582 passed the Linux TUI Python matrix and Windows TUI core job, but the overall workflow failed in the unrelated Windows x64 unit job. Installer run 30318769692 failed and produced no Release. The earlier failed jobs that motivated the correction were Python 3.10, Python 3.12 mypy, and the historical-target TUI package job.

2026-07-27 — Historical Linux-first interactive TUI preview (archived, non-blocking)

A new tui/ Python project is a terminal-native sibling to the Windows-only Electron application. Its Textual shell is designed for both mouse and keyboard operation: repository/workspace tabs, buttons, lists, tables, checkboxes, and selectors are clickable, while repository paths, URLs, commit messages, provider bodies, API payloads, regex patterns, and sample text use real Input/TextArea controls.

Status: implementation commit eee005c7f4, integration merge ba45dcfbaf, and verification commit fcb86eca4d are integrated and pushed through merge 2abccae8fd. Local evidence is complete: 193 Windows-hosted TUI/core tests passed with one Linux-only PTY skip, that PTY test passed on real Debian, all 164 focused Windows Cheap LFS tests passed, the wheel/sdist and fresh install were inspected, and a non-root remote Docker build ran successfully. Five original Lowlevel/Xvfb screenshots prove mouse clicks, editable Inputs/TextAreas, regex matches, bilingual narrow layout, and Cheap LFS preview; every disposable process, display, filesystem root, Docker image, and WSL distribution was removed and proven absent. Pages/wiki publication is live; the first CI defects and locally verified correction are recorded immediately above. Packaged Windows E2E is verified. The correction is contained in origin/main, and its Linux TUI matrix and Windows TUI core jobs passed in run 30317262582; that workflow still failed in the unrelated Windows x64 unit job, while installer run 30318769692 failed and published no Release. The run manifest records the exact local evidence and hashes.

2026-07-27 — HISTORICAL SESSION HANDOFF (superseded; do not read as current)

main is at 949dc81e6d, pushed, with zero divergence from the remote. The working tree is clean; no stashes; every agent branch is merged and deleted except the one still running (below).

Verification state on this tree

Gate Result
node script/test.mjs 6,508 tests / 808 files / 0 failures
node script/test.mjs script 163 pass / 0 fail / 2 skipped
npx tsc --noEmit (root) clean
npx eslint --rulesdir ./eslint-rules clean
npx prettier --check (repo-wide) clean
CI runs were still in flight at handoff time — not green, not claimed green

Nothing in this session was closed on a CI badge. Every closing comment says so explicitly and commits to reopening rather than burying a later CI failure. If CI on 96eeb54c17 or its ancestors reports a failure, that is real and the affected issues should be reopened.

Issues: 23 open → 6 open

Closed with a real capture from a built app: #22, #73 (tab overflow with its search field, Regex builder and per-row customize control), #74 (repository groups expanded and collapsed, count pill and accessible name visible), #70 (sync summary line).

Closed as fixed, merged, pushed, locally verified: #55, #56, #58, #59, #65, #67, #69, #72. Each carries its own regression tests, and each was proven to fail without its fix.

Closed as shipped: #63, #64, #71, #75.

Still open, with the honest reason:

Issue State
#35 Closed. Stream-hash shipped in 949dc81e6d: OCI drops from 7 full payload reads to 3, with the registry authoritative for layer digests. The Release path was already single-pass from tranche 1 — 2 → 2, no saving, and that is stated rather than dressed up as a win.
#66 Fixed and pushed (registration now targets the update-stable Squirrel root, stale registrations detected and repaired). Not closed because no real re-registration was exercised — verifying the post-update repair needs an installed build carrying the change to be updated over.
#68 Fixed and pushed. Not closed because the private route deliberately ends at a builder-unavailable blocker: creating the public builder repo and writing its Actions secrets needs a token this feature never holds. Until that external setup exists, private-repo compression does not run at all — which is the safe outcome, not a silent fallback.
#34 Feature shipped and merged. Wants a framed capture of the branch picker.
#23 79-capture campaign. Now unblocked — script/capture-app.js exists and works.
#62 Blocked on the user. All 21 desktop-plus features referenced anywhere in this tree are already implemented; no unadapted one could be found. Needs a name or screenshot of the feature believed missing. Upstream delta measured: 78 commits since fork point d9080117b1, versus 1,345 here (2,438 files, +902k lines). Do not bulk-merge upstream.
#78 Blocked on the user. Needs the scope decision: encrypt Cheap LFS payloads before upload (fits this app), or encrypt working-tree files in place (fights Git's diffing).

Things a successor should know

Open risk worth carrying forward

The racily-clean fix (#72) makes publishing pay one filesystem timestamp tick. Measured: ordinary revalidation is unchanged (3.95 ms → 3.68 ms, still skipping the re-hash, so #35's win survives), but publishTextBatch pays roughly 17 ms × N in its staging loop. Settling members in parallel is the obvious follow-up if that shows up on a large batch.

2026-07-27 — Ignored files to a local submodule (local phase, on a branch)

Built on the isolated worktree branch worktree-agent-a1c6b6311afbc2837; not merged and not pushed. It implements only the local half of the roadmap entry: candidates come from git status --porcelain=1 -z --untracked-files=all --ignored=traditional and each is proven by git check-ignore -v -z --stdin run without --no-index, so a tracked path — including one force-added against an ignore pattern — can never be proven ignored and can never be selected. Eleven per-file rejection reasons and nine destination reasons are all fail-closed. Every staged copy is verified by size and SHA-256 while the parent repository is still strictly read-only; the first index mutation anywhere is the new repository's own commit, and the single git submodule add follows it. Originals are only ever read and are re-hashed at their exact original paths afterwards. Independent recovery copies under <git-dir>/desktop-material/ignored-submodule-recovery/<run>/ are deleted only after that final verification and are named in every failure.

Local evidence: 36/36 focused tests (9 pure planning, 22 against real temporary Git repositories, 5 dialog), and 732/732 across the cheap-lfs, submodule, repository-settings, collection-surface-registry, search-surface-filters, and i18n suites (61 files). Root npx tsc --noEmit is clean and npx eslint --rulesdir ./eslint-rules is clean on every touched file. Two mutation checks confirm the safety tests are load-bearing: adding --no-index to check-ignore fails exactly the two tracked-file tests, and disabling the staged-copy hash comparison fails exactly the copy-proof abort test.

Still open: merge to main, push, CI, and headless screenshot acceptance. The publish phase — Release/OCI storage selection, Cheap LFS upload, pointer conversion, provider repository creation, remote creation, and push — is deliberately not built; the module imports none of that code and a source test asserts it. Detail in docs/features/repository-management/ignored-files-to-local-submodule.md.

2026-07-27 — Session summary: fifteen pushes, and what is still open

Pushed to main through 821ab93d57. Full local gate on that tree: node script/test.mjs reports 6,508 tests across 808 files with 0 failures, root npx tsc --noEmit is clean, eslint is clean, and repository-wide prettier --check passes.

Shipped and pushed this session, each verified before its own push:

Open, with the honest blocker recorded on each issue:

Two self-inflicted CI breaks were fixed in the same session: a screenshot added without its wiki-manifest row, and then the same screenshot missing from the Pages gallery, which is a second pinned count cross-referencing the first.

2026-07-27 — GitHub Pages renders Mermaid diagrams instead of their source (#71)

Ten ```mermaid fences — three in docs/learn-more/unreachable-commits.md, five in docs/readme-tabs/features.md, two in docs/readme-tabs/complete-feature-list.md — rendered as diagrams on github.com and as raw fence source on the published site, because pandoc --from gfm turns a Mermaid fence into <pre class="mermaid"> and site/docs-template.html loads no JavaScript at all.

Local evidence: node script/test.mjs script passed 148/150 with 0 failures and 2 environment-gated skips (pre-existing ARM64 cross-tools; the new browser-gated end-to-end render, which passed when run with DESKTOP_MERMAID_TOOLCHAIN set). The full Pages build was reproduced locally with real pandoc 3.10 and a real headless Chromium 151: all ten diagrams rendered, zero colour-audit warnings, and Chromium reported 0 non-file: requests for the published pages in both colour schemes. npx prettier --check passes on every touched non-Markdown file. Not yet verified against the deployed Pages site.

2026-07-27 — Exact-90% restore, app-hosted browser, and private badge (pre-publication local receipt)

At this pre-publication checkpoint, three user-facing continuations were locally accepted and integrated into local main. The source and captures were later pushed through 2abccae8fd, and Pages/wiki publication is now verified live. Packaged Windows E2E is verified. At that checkpoint, a TUI compatibility rerun and installer/Release evidence were still pending; the TUI item is now historical and non-blocking under the Windows-only product boundary. Do not attach an older installer badge to these changes.

Cheap LFS restore scheduling and progress

App-hosted browser

Private-repository lock badge

Local acceptance

Accepted local capture Dimensions Bytes SHA-256
docs/assets/screenshots/cheap-lfs-restore-lookahead.png 1440×960 106,724 001e9d09e95cf81c981f4b97a33c2aab958a93fce8eca064a8d0cea9df1e3a96
docs/assets/screenshots/app-hosted-browser-authentication.png 1144×741 65,346 257960b35797e2f7e5f2a8e442c353e656d98af5ef4a088fe30113b641293f69
docs/assets/screenshots/private-repository-lock-badge.png 960×660 87,517 7cf7e27565bceb3d584c24752c2e066b29abdbcafe066b25250fa65d3284de9a

Publication update

The source and accepted captures are pushed through 2abccae8fd, and Pages/wiki publication and packaged Windows E2E are verified. At that historical checkpoint, installer/Release evidence remained pending; the separate TUI correction no longer defines or blocks the supported Windows product. This pre-publication local receipt does not claim the missing installer evidence.

Feature contracts: Release-backed Cheap LFS, App-hosted browser, and Private-repository lock badge.

2026-07-27 — Documentation search no longer compiles reader regex on the UI thread (#69)

site/docs-search.html, published as /docs/search.html, built and compiled reader-supplied patterns with a bare new RegExp(...) on the page thread. A catastrophically backtracking pattern such as ^(a+)+$ against a long non-matching page hung the tab with no recovery. This was pre-existing debt, not a regression from #63.

Local evidence: node script/test.mjs script passed 121/122 with 1 pre-existing skip and 0 failures, including 12 new worker/controller assertions and the new 12-test docs-search-page-test.mjs, whose adversarial case measured ^(a+)+$ against a 20,000-character non-matching page terminating at ~815 ms wall clock (deadline 750 ms) with the page still answering a plain-text search afterwards. npx prettier --check passes on every touched non-Markdown file. No TypeScript was touched. Not yet verified in a real browser against the deployed Pages site.

2026-07-27 — Tabbed GitHub Pages hub with a site-wide search dock (#63)

The published documentation hub (docs/index.html) is no longer one long scroll. Six top-level tabs — Overview, Install, Features, Reference, Search and Project links — each open a panel of their own, and Features and Reference carry generated sub-tabs so a category or a documentation folder is a page rather than a section to scroll past.

Local evidence: node script/test.mjs script passed 104/105 with 1 pre-existing skip and 0 failures, including the new script/docs-hub-page-test.mjs (14/14 — tab state, deep links, arrow-key movement, no-JS readability, plain-text default versus regex opt-in, builder⇄search synchronisation, the empty state, a real ^(a+)+$ termination measured at ~750 ms through the real worker on a real thread, and appearance persistence) and the extended script/generate-docs-hub-catalog-test.mjs (22/22, including a coverage assertion that every feature page is linked from the hub and a staleness assertion for the committed page). npx prettier --check passes on every touched file. Rendered checks in a real browser at 375×812, dark, bilingual, compact: no horizontal page overflow on any tab, no overflowing element outside the pre-existing overflow-x: auto code blocks, tab targets 48 px tall, and text contrast between 7.2:1 and 13.2:1 for tab, sub-tab, body, note and link roles. The Pages workflow is unchanged and its docs-hub-catalog.js assertion still holds.

2026-07-26 — Dedicated Cheap LFS tab in Repository Settings

The Cheap LFS preferences moved out of the combined "Build, run & large files" tab into their own Cheap LFS tab in the Repository Settings dialog, inserted immediately after Build & run (enum value = TabBar position invariant preserved; the conditional ForkSettings tab stays last).

Verification: build-run-cheap-lfs-settings-test.tsx now exercises the new component plus new tab-wiring/i18n/negative cases; with cheap-lfs-test.tsx and responsive-surface-catalog-test.ts the three files pass 43/43, and the nine adjacent suites (repository-settings management/appearance, settings search/surfaces, build-run opencode/auto-pull, i18n, tab-session style, command-palette catalog) pass 80/80. npx tsc --noEmit is clean. Feature docs, the User Guide, and this handoff were updated to the new path Repository settings → Cheap LFS.

2026-07-26 — Add Submodule dialog searchable branch picker (issue #34)

The Add Submodule dialog's URL route now lists the remote's branches instead of relying on free-text alone. A "Load branches" action beside the URL field (also fired automatically on first blur with a valid URL) runs git ls-remote --symref -- <url> HEAD refs/heads/*--heads alone was verified to suppress the HEAD symref line, so the ref patterns are explicit — through the new pure parser in app/src/lib/git/ls-remote-heads.ts and the spawning helper listSubmoduleSourceBranches in app/src/lib/git/submodule.ts (source revalidated before spawn, remote-operation env, credential trampoline, AbortSignal process kill, 5,000-branch cap with truncation reported, malformed lines skipped, empty repo yields an empty listing).

The loaded list renders as the registered standalone search surface add-submodule-branches (literal IDs in JSX for the static audit): a type="search" input plus FilterModeControl on the shared fuzzy/substring/RE2 matchGroup stack with the invalid-regex role="alert" contract, then a select whose pre-selected first option is the visibly marked remote default. Picking writes the free-text branch field, typing free text deselects the list, and the remote-default option maps to an empty branch argument (no -b), preserving the existing addSubmodule call contract and Create remote behavior. All new copy is keyed in English and Cantonese (submodule.addLoadBranches*/addBranch* keys); loading is announced through a polite live region and failures are inline and non-blocking.

Verification (local, this worktree): collection-surface-registry-test.ts 4/4, search-surface-filters-test.ts 15/15, new ls-remote-heads-test.ts 6/6, ui/add-submodule-dialog-test.tsx 16/16 (5 new picker tests), the eight existing submodule suites 55/55, i18n-test.ts 20/20, and root npx tsc --noEmit clean. Feature doc updated in docs/features/repository-management/submodule-subtree-and-remote-creation.md. Refs #34; remote CI has not run on this branch yet.

2026-07-26 — Unit-test repair after the remote-automation hardening

The f8eca3ac84 hardening moved scheduled commit/push, pull preview, and commit-batch flows onto repositoryWithCanonicalRemoteForNetwork before network I/O but did not update the test suite, so the Windows x64 unit job failed in CI (and in the dependent Express/Super Express release runs). Commit 6d6bda8a79 repairs the suite without touching the hardened runtime behavior:

Verification: the seven previously failing files pass 54/54 locally, and the full unit suite reports 793/793 files with 6306 tests — the only local failure is get-shell-env-test.ts (pwsh), which fails identically on clean f8eca3ac84 and is a pre-existing local-shell environment issue, not a regression. Remote CI on the push is tracked from the run list; no remote success is inferred before it lands.

2026-07-26 — Remote repair, unattended Git, and distribution surfaces

Final-tree local evidence: canonical yarn lint and root TypeScript --noEmit passed; the final cross-feature regression matrix passed 104/104 across seven files; and yarn test:script passed 84/84 across twelve files, including x64/ARM64 shell-extension and documentation-catalog checks. The exact Lowlevel-MCP-routed unpackaged production build passed in 287.9 seconds. The fresh off-screen Win32 build then completed the dark-English regex-builder scene at 1280 x 800; its adversarial safe-RE2 near miss completed in 16 ms. The accepted capture is docs/assets/screenshots/regex-builder.png (SHA-256 BEFBFA90491120195884F7424AAB551B81CB3174068077E466A8020C335A28B1). A separate issue-#39 capture proves the one-ahead fixture renders Push origin rather than Publish branch (SHA-256 568C2B927F555586CDBFA62BD1AC79B6E4A7C8B7CC17D4F98178CCF6441D4AC6). Remote CI and publication are pending until this commit is pushed; no remote success is inferred from the local receipts.

Remaining audit risks: automatic Cheap LFS OCI materialization still invokes the external Docker credential helper without a direct unattended/no-window proof. Also, direct Cheap LFS remote operations in publication-state reads, first-publish anchor pushes, and workflow-commit pushes still need either the canonical-remote preflight or explicit stale-URL coverage. Treat both as open until verified or repaired.

Product follow-up requested by the user: every cancellation action must use a slide-to-confirm interaction. This is a handoff requirement only in the current push; the existing cancellation controls have not yet been migrated or claimed as verified. The eventual control must remain keyboard- and screen-reader-operable, expose clear pending/confirmed/canceled states, respect reduced motion, and avoid turning ordinary non-cancellation navigation into a confirmation gate.

2026-07-26 — Pull-and-bug-hunt reliability pass

Fast-forwarded clean main from a6d5841b05 to 78dc8d0bc5, scanned every open issue and three touched repositories, then split the bug hunt across Git, renderer/security, static Pages, and native Windows packaging. The resulting repair set is deliberately broader than issue #39 because adversarial review found additional release-blocking defects in the first implementations:

Local evidence so far: root TypeScript no-emit passed; canonical yarn lint passed; the changed renderer/real-Git matrix passed 179/179; the tightened RE2 stress rerun passed 14/14 and reduced the 500-group case from roughly 875 ms to roughly 100 ms; the Pages worker/controller passed 9/9 including real hard termination and capture amplification; and the script gate passed all 83 non-catalog tests, including real x64 DLL activation and ARM64 cross-compilation. Its one catalog assertion correctly reported the two new verification pages as unindexed before regeneration. The final production build, off-screen Win32 UI capture, regenerated catalog/full gates, and remote receipts are recorded below in this section before publication; do not infer remote success from this local implementation paragraph alone.

2026-07-26 — Multi-account token-invalidation fix re-verified; worktree sweep

A reported bug — AppStore.onTokenInvalidated resolving the affected account by endpoint position, so a second same-host account's invalidated token signed nobody out — was investigated and found already fixed and on main. Commit 3e692befb2 ("Sign out the account whose token actually failed") is an ancestor of origin/main: getAccountForEndpointAndToken (api.ts:5975) matches endpoint plus the exact token the failing request used, and onTokenInvalidated (app-store.ts:2013) uses it, so exactly the affected account is signed out and other accounts on the host stay signed in. A token no signed-in account holds signs nobody out and logs a warning. Coverage already exists at accounts-store-test.ts:186 — five tests including the two-dotcom-accounts / second-token case, the first-account case, the unheld-token case, and same-token-different-endpoint. Re-verified this session: node script/test.mjs app/test/unit/accounts-store-test.ts with TEMP=C:\dm-temp21/21 pass, 0 fail. No source change was needed, so nothing new was written to app/.

Worktree/branch sweep completed in the same pass. git worktree list now shows only the main checkout; branch claude/determined-heyrovsky-eca6d2 was merged (identical tip 12d3ed4600) and deleted; no stashes exist. 43 stale directories under .claude/worktrees/ were left behind by earlier sessions. Before deleting anything, every file in the two non-empty ones was hashed and checked against git's object store: agent-a55be6fd4ca9e9180 — 103/103 blobs already known; material-design-ui-audit-763c44 — 3572/3576 known, and the four outliers were two test files byte-identical to main (CRLF-vs-LF hashing artifact) and the two icon-logo.icon/icon.json assets, which are semantically equal to main and differ only by a stray reformatting. Conclusion: no unique, uncommitted, or unpushed work in either. All 74 node_modules junctions were deleted as links (never followed) and the real node_modules trees were verified intact afterwards, then all 42 removable directories were deleted — including agent-a55be6fd4ca9e9180 (206M) and material-design-ui-audit-763c44 (629M, whose WORKTREE-IN-USE.md marker was a stale 2026-07-20 note whose branch no longer exists). Roughly 835M reclaimed.

NEXT AGENT: nothing is pending here. One empty directory, .claude/worktrees/determined-heyrovsky-eca6d2, could not be unlinked only because it is the running session's shell cwd; it holds no files, is not a registered worktree, and disappears when that session exits.

2026-07-26 — Windows 11 context menu LIVE; packaging gap fixed

The packaged handler is registered and verified on this host (DesktopMaterial.ShellExtension_1.0.0.0_x64__6yspk5eyn48ge, from the CI-built v3.6.3-beta3-zadttgmugx payload). No security setting was changed — Developer Mode was already enabled. Verified: manifest wires Directory + Directory\Background to the compiled class; DllGetClassObject S_OK; root command ECS_ENABLED (app-beside-DLL check passes); right-clicking a folder in Explorer opens the Win11 modern menu (PopupHost windows on demand) — exercised on an off-screen desktop via Lowlevel MCP, where DWM does not compose XAML popups, so the one outstanding capture is an interactive-session screenshot of the open menu (registration + activation + menu-opens are proven; the entry rendering inside it is not pixel-proven yet).

Found and fixed in the same pass: packaged builds ship shell-extension/ under resources\app, but registration needs it beside GitHubDesktop.exe — no shipped build could register at all. Registration now self-heals by copying the shipped folder into place (decideShellExtensionPackageSource, three new tests), and the settings pane counts either location as package-present. Gates: both tsc projects, 110/110 extension tests, yarn test:script 68/68, prettier clean. NEXT AGENT: an interactive-session screenshot of the top-level menu entry (right-click any folder on the real desktop) completes the evidence; the registered package on this host already serves it.

2026-07-26 — Integration cycle complete: CI verified green, two releases shipped

Remote main = 6d3b2f0834; CI run 30192722432 on b7146213fd is fully green (Lint, Windows x64/arm64, E2E smoke, script tests). Everything below in this file dated 2026-07-26 is now merged, pushed, and CI-verified; issues #40 #41 #42 #43 #45 closed on that run. Releases v3.6.3-beta3-zadtsszkum (target 7608c04200) and v3.6.3-beta3-zadttgmugx (target b7146213fd, the green tip) were published manually from the lanes' own verified artifacts because the Actions token currently cannot create ANY release (fallback run proved prerelease creation 403s too — #44, needs an org admin: the change window is 2026-07-25T20:55Z → 2026-07-26T02:50Z; tag pushes still work, repo rulesets empty, workflow grants unchanged).

Local push gate, now mandatory and memory-recorded: app tsc and yarn tsc -P script/tsconfig.json, node script/test.mjs (all-batch fail-0 + accounting), TEMP=C:/dm-temp yarn test:script, yarn lint, and yarn generate-docs-hub-catalog whenever docs pages change (the staleness guard fails CI otherwise — it caught three un-catalogued docs on its first CI pass). The compression-workflow caller is pinned to a Prettier fixed point (byte-equality test vs the rendered template) after an automation reflow broke main's lint; CodeQL is pinned to javascript-typescript after the COM stub woke the cpp autobuilder.

Open user-action items: promote v3.6.3-beta3-zadttgmugx to Latest (gh release edit v3.6.3-beta3-zadttgmugx --repo Ding-Ding-Projects/desktop-material --latest); investigate #44 in org settings; restore read:project/project token scopes for board updates. Open work: #22 closing capture, #23 screenshot tranche, #25 decision, #34 submodule branch picker, #35 perf tranche 2, #39 publish-label remote read.

2026-07-26 — Windows Explorer context menu + quick-action window

Branch feat/windows-context-menu (worktree), three commits, not yet merged or pushed: 48e1f02b45 (classic verbs), 807a6f5267 (quick-action window + packaged Windows 11 handler), plus an unrelated pre-existing prettier fix to .github/workflows/cheap-lfs-cloud-compression.yml that was blocking yarn lint.

Shipped: per-user (HKCU-only, never elevated) Explorer verbs on folders and folder backgrounds — "Open with OpenCode here" and "Open in Desktop Material"; a small always-on-top MD3 quick-action window (own webpack entry quick-action) doing status → commit → push for one folder; and a real IExplorerCommand COM server in a sparse MSIX for top-level Windows 11 placement. Settings → Integrations reports which implementation is actually serving the menu. Full detail: docs/features/integrations/windows-explorer-context-menu.md.

Verified: tsc clean; yarn lint green; targeted suites green (151 tests across the three new files plus the ipc/i18n/settings-search/settings-surfaces contract tests). The COM DLL compiles with MSVC and exports DllGetClassObject/DllCanUnloadNow undecorated; the generated manifest passes real MSIX schema validation via makeappx pack — which is what caught the X.500 quoted-publisher and bare-GUID requirements, and that Directory item types come from the desktop5 schema, not desktop4.

Bug found and fixed by actually launching the app, not by tests: handleCommandLineArguments runs at module scope before app.on('ready'), so the quick-action branch tried to create a BrowserWindow too early and died as an unhandled rejection. Now guarded on app.isReady(); the initial command line is handled from the ready handler and that branch serves second-instance only.

NOT verified, needs a human or a differently-configured host: live Add-AppxPackage -Register and the resulting top-level menu entry — it needs sideloading enabled in Windows Settings, which is a system security setting the agent will not change. No certificate is ever installed by design (trusting a self-signed cert is a machine-wide change); the classic verbs are the documented automatic fallback. A cold-open millisecond figure from a packaged build is also still outstanding — the instrumentation is in and logs Quick action window interactive in <n>ms; the dev bundle is 11.4 MB vs the main renderer's 25.8 MB, which is a size proxy, not a timing.

2026-07-25 HISTORICAL SESSION HANDOFF — superseded / 舊交接紀錄

Seven cycles pushed today (tips: f9e07c9c4272876526d47c588cb224a49757e88151fcf503f4/645657f470/be5784f7daee591a3278896497dba0/4698458a84a71cbd4a747921cceb97), each gated on tsc + lint + the accounted full suite and receipted in Discussions (#37 and the rolling thread #3). Test-releases-only mode is ON: both lanes publish prereleases (--prerelease), the promote step skips prereleases cleanly, and releases/latest stays frozen at zadtorqoxa so installed apps do not auto-roll; revert the two --prerelease flags to resume production releases. Latest green prerelease: v3.6.3-beta3-zadtqgahmd (all fixes below).

Cheap LFS 200k end-to-end (issues #24/#38), state after round 3 on the test repo bambustudio-deps-cheaplfs-test (local f3a768470 "pin 10 large deps", 3 pointer files committed, 7 files pending; remote has main @ 611b665e9 and three one-asset prereleases — verified read-only): verified WORKING live — first-publish bootstrap (branch published to an empty remote through a stock LFS pre-push hook), hook stdin spool + --no-verify anchor, per-file failure reasons, 600k path ceiling (212k paths; scoped scan 3.5s vs 161s), loud aborts; EBUSY never recurred. ONE OPEN DEFECT (the only #38 remainder): GitHub's releases API returns [] for a commit-less repository, so the pre-commit release review cannot see pre-existing releases; the anchor push then un-hides them mid-flight and the review-fingerprint guard correctly aborts the in-flight uploads ("The reviewed release, asset, repository, or account changed."). FIX IMPLEMENTED, NOT YET PUSHED OR RE-VERIFIED LIVE — see "Anchor before the release review" below; it is committed only on branch fix/bootstrap-before-review in a linked worktree and still needs a merge, a push, and a fourth headless E2E pass. Then re-run the E2E pass 2 (app is parked headless at "Commit 7 files to main", desktop CheapLfsRun3, CDP 9223) and close #38/#24 on captures.

Environment lessons that cost real time (also in agent memory): MSIX Temp virtualization on this host diverges the container %TEMP% from real Temp — junction fixtures then fail realpath with ENOENT; run gates with TEMP/TMP=C:\dm-temp. The Lowlevel MCP server sees REAL paths (container %LOCALAPPDATA% = ...\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Local). Headless app driving that works: extract the portable release zip, launch via Lowlevel MCP launch_on_headless_desktop with --remote-debugging-port, and drive by CDP DOM clicks (scripts under the session scratchpad run2/run3; omit the Origin header against Chrome 148). A gate is green ONLY if every batch's ℹ fail line is 0 AND the exit code is 0 — never trust the tail. Worktree junctions must use full Windows paths; worktree build:prod needs the gemoji/choosealicense/gitignore submodule content.

Open issues: #22 (tab overflow — fixed + released, needs a live capture to close), #23 (screenshots: 36/77 regenerated, tranche 2 pending), #24/#38 (above), #25 (needs the user's A/B/C decision on six external-UI screenshots), #34 (submodule branch picker feature), #35 (Cheap LFS perf tranche 2 / stream-hash uploads). The stale July-1 GitHubDesktopSetup-x64.exe should be deleted by the user (Squirrel --install performs no version comparison; guard shipped but cannot stop a re-run installer).

2026-07-25 Repository list bulk actions

Branch feat/repo-list-bulk-actions (worktree only; not merged, not pushed — push was explicitly out of scope for this task).

2026-07-25 Cloud compression installs its own workflow (background)

Branch feat/auto-install-compression-workflow (worktree only; not merged, not pushed — this session was explicitly forbidden from pushing).

Defect. A repository could use Cheap LFS cloud compression and compress nothing. ensureCheapLfsCloudCompressionWorkflow wrote .github/workflows/cheap-lfs-cloud-compression.yml into the working tree and deliberately stopped there ("never stages, commits, or pushes"), leaving a Changes entry the user had to notice, review, commit, and push. GitHub Actions never sees an uncommitted file, so until they did, compression was off in fact while the UI said it was on.

Fix. New pure module app/src/lib/cheap-lfs/workflow-auto-install.ts holds the decisions; AppStore.maybeAutoInstallCheapLfsCloudCompressionWorkflow (fire-and-forget, in-flight-guarded per repository) runs them.

Entry points. _ensureCheapLfsCloudCompressionWorkflow (covers the settings toggle and the Cheap LFS panel sync) and maybeAutoMaterializeCheapLfs (a checkout demonstrably carrying Release pointers).

Gates (all green, TEMP=C:\dm-temp). npx tsc --noEmit exit 0; yarn lint green (prettier check + eslint); node script/test.mjs app/test/unit/cheap-lfs → 417/417, accounting 32/32 discovered file(s) produced results across 1 batch(es); 417 test(s) reported, ℹ fail 0; workflow-auto-install-test.ts alone → 30/30, ℹ fail 0, accounting 1/1; i18n + error-notice + notice-stack + auto-fix + notification-centre → 68/68, accounting 6/6, ℹ fail 0; local-commit-batching-git-test.ts + pending-commit-push-safety-test.ts exit 0.

Not done here. No push (forbidden this session), no merge to main, no live headless verification of the background install against a real GitHub remote, and no screenshot of the new notices. Account selection uses the repository's current association only — the fallback resolver work lives on another branch.

2026-07-25 Anchor before the release review (#38 last defect)

Branch fix/bootstrap-before-review (worktree only; not merged, not pushed). Addresses the round-3 defect above plus the toolbar state it left behind.

Root cause, exact pre-fix lines. app/src/lib/stores/app-store.ts:14771 called ensureCheapLfsReleaseAnchor and then went straight to autoPinLargeFilesForCommit (:14799) — the release inventory was only ever read inside the per-file pin (allocateCheapLfsReleaseBucket, app/src/lib/cheap-lfs/operations.ts:2075), so nothing in the flow re-read or re-fingerprinted it once the anchor had changed what GitHub was willing to show. Compounding it, decideCheapLfsFirstPublish (app/src/lib/cheap-lfs/first-publish.ts:84) returned blocked-unborn-branch for an empty local repository, which is the one case that can never escape the hidden-inventory state on its own.

Implemented sequence (release provider, anchored path only): ensureCheapLfsReleaseAnchor → bootstrap commit if the branch is unborn → create-only push → prove from ls-remote → record tracking ref + upstream and reload remotes/branches/status → GitHubReleasesStore.listAlltakeCheapLfsReleaseReview → pin/upload. An already-published repository returns anchored: false, takes no review, and behaves exactly as before.

Docs: docs/features/repository-management/release-backed-cheap-lfs.md. Gates: prettier clean, tsc --noEmit clean, yarn lint green, targeted node script/test.mjs app/test/unit/cheap-lfs app/test/unit/github-releases-store-test.ts = 415/415, 32/32 files, fail 0, exit 0 (run with TEMP=C:\dm-temp). Still unverified: no live E2E re-run against a build containing this fix.

2026-07-25 Bundled-Git hook stdin, swallowed abort, 100k path cap

Branch fix/push-hooks-and-caps. Closes the three defects the live #38 re-verification found against v3.6.3-beta3-zadtpwiotl after the first-publish bootstrap started working.

1. Bundled-Git /dev/stdin hook failure. Root cause proved locally against the bundled Git 2.53.0.windows.3: app/src/lib/hooks/hooks-proxy.ts:188 ran git hook run <hook> --to-stdin=/dev/stdin. Git for Windows is a native Win32 program whose open() special-cases only /dev/null, so /dev/stdin was resolved as an ordinary filesystem path and xopen() in Git's pick_next_hook died before the hook was spawned — fatal: could not open '/dev/stdin' for reading: No such file or directory, exit 128, on every intercepted hook run in a repository with stock Git LFS hooks. The companion MSYS symptom (sh: /dev/stdin: No such file or directory) has the same shape: /dev/stdin is a symlink to /proc/self/fd/0, and the MSYS runtime cannot re-open an anonymous Windows pipe inherited from a non-MSYS parent (measured: it can re-open a disk-file handle).

Fixed at the layer that fixes all hook users: app/src/lib/hooks/ hook-stdin-spool.ts streams the proxied payload into a real file (bounded at 64 MiB, mkdtemp-private, removed in a finally) and --to-stdin=<that path> is passed instead. Additionally, the Cheap LFS first-publish anchor push now carries --no-verify (ILocalCommitBatchingGitOptions.skipPushHooksbuildLocalCommitBatchingExactPushArgv(..., skipHooks)), with hook interception dropped in lockstep. That is scoped strictly to the app-generated create-only publication; the user's reviewed push and every batch push still run hooks.

2. Silently swallowed abort. AppStore.ensureCheapLfsReleaseAnchor returned only a TranslationKey and logged the real Git failure to log.warn, and the notification it produced went to the notification-centre history — the app's on-screen surface is the ErrorNoticeStack, fed only by _pushError. Net effect: the commit aborted with no toast and no reason anywhere. It now returns ICheapLfsFirstPublishFailure { reasonKey, detail }, and buildCheapLfsFirstPublishAbort derives all three surfaces from that one failure — per-file rows (reasonKey + reasonDetail), a terminal progress snapshot stating failed = n / succeeded = 0 with the reason on every row, and a persistent notice enqueued straight onto the notice stack (not emitError, which can become a modal). reasonDetail is scrubbed by sanitizeCheapLfsFailureReason on every surface. New EN + 粵語 keys cheapLfs.firstPublish.reasonWithDetail and .abortTitle.

3. 100k path cap. MaximumLocalCommitBatchingPaths was 100,000, refusing a real 212,569-path first publish outright. The bound is a memory bound only — paths reach Git through NUL-delimited stdin, and the per-batch 10,000-path / 1.4 GB ceilings are what bound a commit and a push. Raised to 600,000 from measured cost (400k paths = 58 MiB raw-diff stdout + 159 MiB parsed entries + 106 MiB tree map; 600k = 87/239/158 MiB), which keeps the worst-case transient parse footprint near 400 MiB and clears the required 400,000 by 50%; 1,000,000 was rejected at ~700 MiB. The 64 MiB raw-diff and path-inventory stdout budgets were raised to 160 MiB in lockstep — at 400k paths a raw diff already measures 58 MiB, so the byte budget would otherwise have become the real, less legible cap. The proof capture's whole-tree git add -A ceiling matches.

Gates: npx tsc --noEmit clean; Prettier written; targeted node script/test.mjs green with intact accounting lines (hooks/ hook-stdin-spool-test.ts new, cheap-lfs/first-publish-test.ts and git/local-commit-batching-git-test.ts extended). cheap-lfs/ oci-registry-runtime-test.ts "accepts a pinned winget link…" fails both with and without this change (Windows symlink/realpath privilege in the fixture) — pre-existing, verified by re-running it on a stashed clean tree. Not yet re-verified against a live installed build.

2026-07-25 Cheap LFS first publish, EBUSY push race, silent failures

Branch fix/cheap-lfs-first-publish. Closes the three defects proved by the headless 200k end-to-end in issue #38, plus the launch-time Actions metadata error observed in the same session.

1. Release-route first publish (422 × 10). pinFileToReleaseallocateCheapLfsReleaseBucketreleases.create passes targetCommitish: await releaseTargetCommitish(...) (cheap-lfs/operations.ts:1493), which resolves to the local branch name via resolveReleaseTargetCommitish (:927). On an unpublished repository that branch does not exist on the remote, so GitHub answers 422 Validation Failed for every file, unrecoverably.

Design chosen: publish the branch tip before uploading, then prove it from the remote, consistent with the existing "each batch pushed and proven" contract. app/src/lib/cheap-lfs/first-publish.ts holds the pure decision; AppStore.ensureCheapLfsReleaseAnchor runs it once per commit before any hashing or upload and, for publish-branch, pushes with expectedRemoteSha: null (create-only, can never overwrite) and re-reads the remote ref via isCheapLfsFirstPublishProven. Blocking decisions refuse with a localized per-file reason instead of retrying into another 422. Deferring uploads to the push phase was rejected: it would commit pointers whose bytes exist nowhere remote, so a clone taken between commit and push would resolve to a dangling pointer. No silent provider fallback was added.

2. EBUSY push race. readWorkingTreeFingerprint (git/local-commit-batching-git.ts) built a scratch index under desktop-material-commit-batch-* and cleaned it with an unconditional rm(dir, { recursive: true, force: true }) in a finally. At 200k files the git add -A holds index.lock ~14 s, so the unlink hit EBUSY — and because it threw from a finally it replaced the real error and aborted the push before any network I/O. Replaced with git/temporary-index-cleanup.ts, which consults decideTemporaryIndexLockCleanup (fail-closed: never touches a symlink or non-regular lock; awaits a live or indeterminate owner on a bounded 60 s / 250 ms budget; treats EBUSY/EPERM/EACCES from the unlink as proof of a live owner) and never throws. The same pattern in git/commit-push-batch-proof.ts (desktop-material-commit-intent-*) was fixed identically. The trigger was also removed: the whole-tree git add -A ran with a 256 KiB (8 KiB in the proof capture) stdout ceiling, so Node killed Git part-way through a large tree's line-ending warnings — which is what stranded the lock. Both now use the 64 MiB path-inventory ceiling.

3. Silent failures. ICheapLfsAutoPinFailure now carries statusCode (read from responseStatus on GitHubReleasesError/APIError) and an optional self-diagnosed reasonKey; ICheapLfsAutoPinProgress.failedFileDetails republishes every settled failure with its sanitized reason on each progress snapshot. The Cheap LFS mini terminal renders per-file failure rows and folds the reasons into the summary's aria-valuetext; the failure notification appends Reason: HTTP 422 — …. sanitizeCheapLfsFailureReason bounds the text to 240 characters, collapses control characters, and strips URLs, gh*_ tokens, and Authorization: Bearer values before display. New EN + Cantonese keys; error copy stays plain and factual.

4. ActionsMetadataJSONError on launch. The only producer of that message outside api.ts is the update-build probe (desktop-material-update-build.ts), whose 256 KiB bound is far below a real compare or workflow_runs page. One oversized response aborted the whole probe, and onUpdateNotAvailable is registered directly as an IPC listener, so its floating promise turned any rejection into the generic "background action stopped unexpectedly" toast. The bound now matches the shared 2 MiB Actions limit; each leg degrades independently through updateBuildProbeDegradation (unproven is never reported as "ahead"); UpdateStore logs every skipped response and emits onActionsMetadataSkipped at most once per session, which app.tsx turns into one informative non-blocking notification; and onUpdateNotAvailable can no longer reject.

Gates: npx tsc --noEmit clean, yarn lint green, yarn prettier --check green, targeted node script/test.mjs green (new suites cheap-lfs/ first-publish-test.ts, cheap-lfs/failure-reason-test.ts, git/temporary-index-cleanup-test.ts, plus honest contract extensions to cheap-lfs/automation-test.ts and update-coming-soon-test.tsx). Not yet verified against a live installed build — the 200k end-to-end that produced the evidence has not been re-run.

2026-07-24 trampoline token lifecycle fix

Production build zadtjbevjx logged repeated Unhandled renderer promise rejection — Error: Tried to use invalid trampoline token from trampoline-server.ts processCommand, immediately after a 5 s updateRemoteHEAD timeout overlapping a git fetch --recurse-submodules. User-visible symptoms were "A background action stopped unexpectedly" toasts and Cheap LFS randomly failing a 10 GB commit.

Root cause: a trampoline token was revoked when the promise that requested it settled, not when the Git process it was issued for exited. Timed-out, aborted, and max-buffer operations — and spawnGit, which resolves the moment the process starts — all leave Git running past that point, so a live process asked for credentials with an already-deleted token. processCommand then threw from a socket data handler: an unhandled renderer rejection and a reply that never arrived, wedging that Git process on an unclosed socket while it still held its lock files.

Fix (fix/trampoline-token-lifecycle): tokens are now lease-counted and disposed only once revoked and every child process holding them has exited (keepTrampolineTokenAliveUntilExit, wired into git(), spawnGit, and the bounded SSH working-copy runner). Per-operation trampoline context moved from the promise's finally to token disposal so a late request keeps the right repository and forced account. The invalid-token path now replies on the socket and logs one warn naming the command identifier, credential-helper verb, and parameter count — never the token, stdin, or askpass prompt — and distinguishes an expired token from one this session never issued. No new user-facing copy, so no new translation keys.

Verification: trampoline-token-lifecycle-test.ts (11 new tests, including a real server driven over a loopback socket); trampoline suites 39/39 and the related Git/SSH suites 49/49 green with the accounting line intact; tsc --noEmit clean; yarn lint (Prettier + ESLint) green.

2026-07-25 updater downgrade investigation and guard

fix/updater-downgrade, branch-only. The reported "auto-update downgraded the install to 3.6.2" did not come from the update feed, and no comparer ranked 3.6.2 above 3.6.3-beta3-*:

Fixes landed as defence-in-depth for the same failure class, since Squirrel installs the highest feed entry without comparing it to the running version:

Verification: prettier --check clean, tsc -P tsconfig.json and tsc -P script/tsconfig.json clean, yarn lint green, node script/test.mjs script/release-version-test.ts app/test/unit/update-version-order-test.ts app/test/unit/super-express-release-workflow-test.ts app/test/unit/ci-workflow-safety-test.ts → 34/34 pass, accounting 4/4. Not pushed; no CI run exists yet.

2026-07-24 feature discoverability pass

Two Opus audits (entry-point matrix + user-journey burial hunt, 11 raw reports) drove feat/feature-discoverability, integrated with one review blocker fixed. All changes are additive or relabel-only; no entry point was moved or removed:

Verification: lint fully green after removing a stale workflow worktree Prettier was sweeping; tsc clean; complete suite run exit 0, 0 failures, coverage of the palette/search/tab suites confirmed in the log.

Seven more branches were merged into main after the morning feature wave, each built by an isolated Opus agent and adversarially reviewed before integration:

Integration notes: audio-cue-store.ts needed a real three-way resolution (narration queue × SFX routing × theme player — operation cues route through the merged playForEvent gate with null event ids so recorded narration stays attached to notifications); i18n-resources.ts resolved keep-both three times. One regression was found by the first complete full-suite run and fixed at the root: a hidden or unrealized tab strip measures every tab width as zero and the overflow split collapsed all but one tab — the strip now never splits on unmeasurable widths. Earlier "full" runs had silently skipped the tab UI suite; the final gate below is a complete run.

2026-07-24 feature-wave integration into main

The five July 24 feature branches and the narration-asset branch were merged into main sequentially: feat/settings-search, feat/tab-overflow-dropdown, feat/audio-system, feat/audio-narration-assets (243 MP3/WAV files + manifest.json under app/static/audio/), feat/local-actions-runner, and feat/batching-filecount-progress-wip (#14). Per the handoff plan, the batching WIP branch's stray concurrent-agent copies of the settings-search and preferences files were resolved in favor of the already-merged feature branches; its batching-only changes (dual caps, commit progress, gc isolation) merged cleanly. Three integration commits follow the merges: the Sound pane (which merged in parallel with settings search) is indexed by the settings-search catalog — tab name key in English and Cantonese plus five entries reusing the pane's own labels; four pinned source-contract tests were updated to the post-merge source shapes (command allowlist gains run-actions-locally, renderRailTab feature-marker gating, tab-control registration, and gc suppression followed through AutomaticCommitPushBatchGitMaintenanceArgs); and the responsive surface smoke catalog registers the Sound settings tab, moving its pinned gate count from 87 to 88.

Known follow-up: the bundled narration/melody assets are not yet played by the audio runtime — the narrator currently uses live TTS and SFX are synthesized; wiring the pre-generated files (and per-event melodies) remains task #9's second half. Remaining backlog after this integration: #10 sound effects mapping, #11 repo-themed music tracks, #15 auto-fix errors, #16 native large-repo handling, and the Cheap LFS end-to-end app test (push as codingmachineedge, big-file auto-pin, fresh-clone verify).

Added a search box to the Settings (Preferences) dialog rail so a setting can be found by title, description, or keyword across every tab and jumped to directly. Because the rail renders on every tab, the box is present on every settings page.

2026-07-24 tab-strip overflow dropdown (branch feat/tab-overflow-dropdown)

When the repository tab strip overflows its width, the tabs that no longer fit move into a keyboard-accessible "more tabs" dropdown instead of clipping or scrolling horizontally. The split keeps a contiguous, in-order run of tabs visible, guarantees the active tab stays on screen by sliding the run, pins collapsed-group chips, and preserves every per-tab appearance customization for both visible tabs and dropdown rows.

MVP-vs-complete: the split, active-tab guarantee, chip pinning, appearance preservation, a11y, i18n, and tests are complete. Overflow rows do not carry the live repository logo/icon (they show label + path + status chips); adding the async logo loader to dropdown rows is a possible follow-up.

2026-07-24 optional audio system (branch feat/audio-system)

Added an optional, off-by-default audio layer with three parts: a spoken TTS narrator (English + zh-HK Cantonese, rate-limited), Web Audio synthesized sound effects (no bundled assets), and per-repository looped music. New pure modules under app/src/lib/audio/ (audio-settings, audio-throttle, narrator-lines, tone-synth) plus the renderer audio-cue-store; a new Settings → Sound pane (app/src/ui/preferences/sound.tsx) wired through the PreferencesTab.Sound tab; and event routing added to App via the in-app notification centre (syncAudioSystem). Anti-annoyance is enforced by the pure decideAudioActions (master gate, global SFX debounce + per-category cooldown, narrator cooldown, quiet hours, reduced-sound, screen-reader coexistence); errors always bypass suppression and stay clear at every funny-level. All copy localized (English / Cantonese / bilingual) via settings.sound*. Funny-level (1–5, per language) scales only narrator tone.

Verification: npx tsc --noEmit clean; app/test/unit/audio-throttle-test.ts (16) and app/test/unit/audio-settings-test.ts (15) pass — 31 total. Feature doc: docs/features/design-system/audio-system.md. MVP scope: throttling, settings serialization, TTS/SFX/music, and the Settings UI are complete and working; build-run phase SFX and a distinct push/fetch cue mapping are noted follow-ups (push currently narrates via the auto-commit notification). Per-repo music persists in localStorage rather than the git-backed dedicated-setting store — a possible future upgrade.

2026-07-24 Local GitHub Actions runner (branch feat/local-actions-runner)

Added a local GitHub Actions runner: Repository ▸ Run actions locally… (and the "Run Actions locally" command-palette entry) opens a dialog that discovers and parses .github/workflows, feature-detects act+Docker (clear localized install guidance when either is missing), and streams a chosen workflow/event/ job run — with workflow_dispatch inputs, secrets (written to a 0600 temp --secret-file, deleted after the run, never logged, never on the argv), and a dry-run (-n) mode. Cancel tears down the container tree via Build & Run's kill-tree. Renderer↔︎main is wired over new IPC channels (detect-actions-local-tools, list-actions-workflows, start-/cancel-actions-local-run, and the actions-local-run-log/-state pushes).

2026-07-24 batching dual caps, detailed commit progress, and gc isolation

Extended the automatic local commit batching and commit progress.

Files changed: app/src/lib/commit-push-batching.ts, app/src/lib/git/local-commit-batching.ts, app/src/lib/git/local-commit-batching-git.ts, app/src/lib/git/commit.ts, app/src/lib/app-state.ts, app/src/lib/stores/app-store.ts, app/src/ui/changes/commit-message.tsx, plus the commit-push-batching, git/local-commit-batching, git/local-commit-batching-git, and legacy local commit batching entry points unit suites, and docs/features/repository-management/automatic-commit-push-batching.md.

Local verification: npx tsc --noEmit is clean for the changed files (the only tree-wide tsc errors belong to an unrelated in-progress settings-search/actions-local-run feature being edited concurrently in the same checkout, not to this change). Prettier is clean on every changed file. node:test suites green: commit-push-batching 19/19, mock git/local-commit-batching 24/24, legacy local commit batching entry points 8/8, and the real-Git git/local-commit-batching-git integration suite.

2026-07-24 final integration and clean Git topology receipt

The requested merge-and-cleanup pass found no separate work left to integrate. After git fetch origin --prune --tags, both local main and live origin/main were exactly 727496025775c1015492beb936b79e0b4f019b04 with 0/0 divergence. The live remote exposed only refs/heads/main, GitHub had no open pull requests, the checkout had no local non-default branch, .git/worktrees did not exist, the sole registered worktree was the clean primary checkout, and the stash list was empty. Accordingly, branch merges, branch deletion, linked-worktree removal, stale-metadata pruning, and stash deletion were all deliberate no-ops: every available repository tip was already contained in main.

Exact-source local acceptance ran before this documentation-only receipt. The fixed Lowlevel MCP service reported healthy at 127.0.0.1:8765; its scheduled task pointed to the required checkout and Python, whose source tip was 547a102a49169d41da876de217856229ab7c03a1. The prescribed unpackaged production build returned 0, did not time out, and completed in 527.53 seconds. Its binding hashes were out/main.js c0573314a9e3fcda894e41cf545e5c2e876c1324317a3b7b5da7bbfcc3a1c625, out/index.html d44d3b8f637b17fc75c9f3ea14bc08166a7fa931de46b6ea41971ccd6131f553, out/keytar.node 391976ea3af33d6697a9df2e007a8a00d5c7e0aa6f08c7eceeb21fb483591c09, and Electron 082d352efc6a9f5882354ee4096ae0b40b78bc6c8e52fc5084f3df9254c613ff.

That bundle launched only on the uniquely named off-screen Win32 desktop DM-Merge-20260724-a82f, using isolated profile and disposable Git fixture paths. The runtime-resolved Desktop Material window (PID 18216, HWND 1056160) produced a stable, nonblank, unclipped, private-data-free 960×660 client capture: 90,059 bytes, SHA-256 f6d8bcf136f3a993eafbfeaba5a18ef1b55298ec9923173641984357b5a0c80f. The generic background close helper could not resolve that alternate-desktop HWND, so the already revalidated saved PID was terminated as the declared fallback. The desktop then reported zero windows and closed successfully. The exact owned Temp root and the two ignored trampoline bootstrap directories were moved to the Recycle Bin after path validation; all remain recoverable until the bin is emptied.

Local validation passed Electron-version and changelog checks, TypeScript, full source lint/Prettier, and all 39/39 script tests. The optional local desktop-trampoline bootstrap could not compile because this host lacks the ClangCL Visual Studio toolset (and uses Node 26/Python 3.9 rather than CI's pinned Node 24.15/Python 3.11); it changed no tracked source, and its generated directories were removed as described above. The authoritative fresh Windows x64/arm64, packaged x64 E2E, CodeQL, Cheap LFS, and downstream installer/release results for this receipt are therefore verified after its single main push and recorded in the GitHub Discussion plus the final external handoff, avoiding an endless documentation-release loop.

This receipt changes no product behavior or UI. / 今次純粹係合併同清場驗收:啲分支 一早已經乖乖地入晒 main,冇偷走、冇亂刪,亦冇整花個介面。

2026-07-23 materialize cancel/summary correction from verified bug audit

A multi-agent bug audit of the last fifteen commits (nine finder lenses, every finding adversarially verified by three independent reviewers) confirmed seven defects. The three user-facing materialize-flow defects are fixed in this change:

Verification: tsc --noEmit clean; ESLint and Prettier clean on every touched file; focused suites pass — app/test/unit/cheap-lfs 298/298, ui/cheap-lfs-test.tsx 20/20 (three new behavioral tests plus the rewritten repo-wide-cancel test), submodule-mutation-guard-test.ts 7/7 and submodule-repository-navigation-test.ts 21/21. The latter two were already failing at the previous HEAD (the dispose assertions matched an outdated map shape and a line-wrapped source pattern) and were repaired with the field rename.

Remaining verified findings, not yet fixed: committing a selected non-deleted .git*-prefixed path whose parent directory is a symlink/junction, or whose leaf is a symlink or multi-link file, still throws an unhandled CheapLfsTrackedPathError that fails the whole commit (app/src/lib/cheap-lfs/commit-key.ts, a regression of "Allow ordinary .github commit files"; the merged legacy-deletion guard from 9a0be385a1 already bypasses the more common deleted-path case); maybeAutoMaterializeCheapLfs awaiting the whole per-checkout queue can stall awaited _selectRepository chains behind long downloads (app-store.ts, medium); the cloud-compression action rejects documented-valid exactly-2-GiB legacy parts and lacks a stdin error listener in readPointerBlobs (.github/actions/cheap-lfs-cloud-compression/cloud-compress.mjs, medium/low).

2026-07-23 Cheap LFS settings, scrolling, and legacy-deletion key guard

The Large files manager now makes its configuration route explicit: Open Cheap LFS settings opens Repository settings → Build & run, where storage, automatic pinning, transfer concurrency, clone/open materialization, and cloud compression are configured. The manager is also the repository page's vertical scroll owner, so long pinned-file inventories remain reachable instead of being clipped by the repository shell.

Private-registry commit-key validation keeps its pointer/key proof fail-closed. Its only compatibility exception is an otherwise Windows-hostile selected path whose exact repository-relative identity is proven deleted by a fresh live Git status. A current nondeleted unsafe path, a missing or mismatched status proof, or a real OCI pointer stored under a control-plane path is still rejected. This allows a legacy deletion to commit without turning path validation into a key bypass.

UI note / 介面提示:Open Cheap LFS settings / 開啟 Cheap LFS 設定 會直接帶你去 Repository settings → Build & run;長檔案清單都可以一路碌到底,唔使周圍搵 設定。

Exact-source verification passed 58/58 focused key, commit-entry, UI, localization, navigation, and temporary-workspace regressions; TypeScript and the full source lint passed. The fixed Lowlevel MCP production build returned 0. An isolated 960×660 app then rendered 60 canonical pointers with computed overflow-y: auto (518 px client height, 9,942 px scroll height), reached assets/large-file-60.bin, and opened #repository-settings with Build & run as the sole selected tab. The complete bundle/capture hashes and recoverable cleanup receipt are in .codex/run-manifests/2026-07-23-cheap-lfs-settings-scroll-key.md.

The first concurrent publication at 9a0be385a1 passed lint, ARM64 packaging, packaged x64 E2E, Pages, CodeQL, and Cheap LFS cloud automation. Its x64 unit job found two pre-existing source-contract regexes that still expected the old three-item scroll-owner exception list. The follow-up makes both contracts expect the new Cheap LFS exception and also preserves the earlier Prettier-tolerant controller assertion. / 首次 push 功能本身過關,但 CI 捉到兩條舊 regex 仲認住舊 scroll-owner 清單;今次一齊更新,唔畀測試字蝨再扮大佬。

2026-07-23 responsive Releases publication and live Bambu checkpoint

The integrated Cheap LFS, ordinary-Git batching, responsive Repository Releases, and richer commit-progress source is now published through corrective source c22e29a03ac14b01e35ab7b1434fa288bc794307. Exact-source Cheap LFS cloud-compression run 30055965804, CI 30055965807, CodeQL 30055965809, and Pages 30055965817 passed. Installer run 30057456712 then published immutable, non-draft, non-prerelease, six-asset exact-target Release v3.6.3-beta3-zadthusbjk.

The corrected unpackaged production build returned 0 after 390 seconds wall (Yarn 387.64 seconds) through the fixed Lowlevel MCP endpoint. Its 1,179,200-byte out/renderer.css has SHA-256 6fba1434112ea5c02256a12e6ce8af42f5c870f0db5835155acb8075708d9d28.

The current public-safe UI receipts are:

Surface Dimensions Bytes SHA-256 Acceptance
Cheap LFS progress, English 1440×960 113,869 3d6358567126e3ce0504b04c4489abbfd473b77546bd82dac834553d50fe9333 All 36 named assertions passed, including noBlockingDialog; one real pointer selection settled the diff and all three worker rows are contained.
Cheap LFS progress, bilingual 640×960 85,175 1b99c827d1b5b2cf05298fb1255873acdf0502f72a40437c378c0be7bb989e50 All 36 named assertions passed after one real pointer attempt; progress bottom y=942 remains inside panel bottom y=944, with no injected diagnostic style.
Repository Releases, 200% zoom 960×660 89,856 8e29ac666a0832d353126d8dd759200ba7e853016a940501e5c7cbdbb1cf992a The 480×330 CSS viewport contains one complete 53.5 px release row, HH:mm timestamps, a wrapping bilingual disclosure, and zero horizontal overflow.
Bambu Cheap LFS, live ten-object inventory 960×660 98,404 55a6519a81edef49cb7b6f6f02606a75485b34a1fed21beafa21b67fd758d142 The inspected public-safe frame shows the real Bambu repository with ten tracked raw pointers, their immutable public Release tag, local pointer state, sizes, and Materialize actions. The separate fresh-clone hash receipt below proves the later 10/10 restore.

The historical initial-integration changed suite passed 151/151. For the corrected source, the focused Releases style/localization/UI plus Pages contracts pass 55/55. A final 152-test integrated rerun was still progressing after 693 seconds with no observed failure when the user explicitly requested the immediate push; it was stopped cleanly during the disposable-Git batching suite and therefore has no aggregate pass claim. A complete rerun is handed off instead of being misreported.

For the compact Releases scene, native Enter expanded and collapsed the tools disclosure. Search, status, selection, and release-row actions remained keyboard-focusable; the no-next-page pagination action remained present with its correct disabled state. Constant-physical-size probes passed at 100%, 125%, 150%, and 200%, with one complete row and zero horizontal overflow at every scale. The gallery source now contains 77 inspected images.

The public codingmachineedge/bambu-build exercise copied exactly 8,305 payload files and 14,809,588,162 bytes. Desktop Material created four ordered UI batches (639d566b, 8efaa6f9, 93d72d61, and f58fd4c0) and proved each remote tip. The first normally packed push received HTTP 408 while leaving its exact pending commit durable; the real UI retry pushed that same immutable SHA with process-local fast-pack options, then completed the remaining three batches.

Managed public cloud run 30048474438 processed the 13 Release objects one by one and reported 13 compressed, 0 kept raw, and 0 failed. The Release still retains all 13 raw originals beside the 13 verified compressed assets, for 26 assets and historical raw fallback. The real Changes UI then pushed manifest/workflow commit 712ad85f92f9002474f0f13b6bb6991153d586af. Verifier run 30054805137 passed all 8,305 files, ten pointers, and 26 assets and published immutable Release bambu-build-verify-30054805137 with its 5,489-byte manifest asset (SHA-256 234e88a446073d59c293e40966b6cbcfa080e21467fe14df840452d0c04694b3).

A fresh real-UI clone at exact 712ad85 restored all ten working files to the manifest SHA-256 values (10/10) while their committed Git objects remained 370–514-byte pointer blobs. The first explicit Materialize all overlapped clone/open automatic materialization and reached two hash-identical compare-and-swap recovery copies. Integrity remained correct, but that overlap was not accepted; it prompted repository-scoped serialization of automatic and manual materialization.

The repository-scoped correction passed 29/29 focused queue and UI tests; the wider four-suite Cheap LFS pass immediately before the final progress plumbing was 108/108. Coverage includes a real disposable-Git concurrency regression in which automatic, individual, and Materialize-all requests target the same checkout. The test proves one download, FIFO queue release, exact-request cancellation ownership, fresh pointer re-listing under the lock, and no rejected-tail poisoning. The initial real-UI clone remains the GUI receipt; a second multi-gigabyte overlap rerun was not claimed because the user requested immediate publication and worktree cleanup.

Cleanup followed remote proof of exact handoff commit a64c1cb54c. All six completed Desktop Material task tips were ancestors of origin/main; their clean linked worktrees and merged local branches were removed, the default checkout was fast-forwarded, and the repository finished with only clean main, no stash, and zero divergence. The older unstaged run-manifest draft contained no exact receipt token absent from the pushed final manifest and was therefore dropped as superseded. In codingmachineedge/bambu-build, both sets of locally materialized payloads were size- and SHA-256-proven against all ten committed pointers before restoration; its default checkout now equals 712ad85, and its merged manifest worktree/branch were removed. The empty headless desktop was closed, and the two owned temporary evidence directories were moved to the Windows Recycle Bin, so they remain recoverable. The unrelated BambuStudio/.claude/worktrees/recursing-kepler-58a6c3 checkout was preserved.

Historical initial integration commit c3db37ea5524b91f9603151ae5d1107205f16a59 and responsive source 513c5cc96a are both ancestors of corrective c22e29a03a. That correction replaces the 7–8 px/22 px compact overrides with readable 9–16 px text, 30–34 px controls, a 52 px row, a wrapping localized disclosure, and three-column metrics. Its widened 800×560 combined gate covers the exact 125% case (768×528 CSS) that the earlier 760×520 gate missed. Exact-source build, four-scale geometry/keyboard proof, original-pixel review, capture promotion, cloud compression, CI, CodeQL, Pages, and installer Release publication are complete. The newer repository-scoped Cheap LFS serialization fix is covered by the deterministic concurrency regression above. The promoted live inventory frame documents the real ten-pointer UI, while the separate fresh-clone manifest proof documents the 10/10 restored bytes.

2026-07-23 cross-lane automatic updater recovery

Commits 241cc90ce90f240bad075edac7ebe43eea515df8 and 04246fdf12c09446b88d2f40130581d603131c8e moved automatic and Super Express packages into one Squirrel-monotonic z<9-letter-base-26-run-ID> namespace. The alphabetic payload retains GitHub run ordering without triggering the installed NuGet comparer's 32-bit overflow on modern decimal run IDs.

Exact-source CI 29977738533 and downstream Build Installers 29978844761 succeeded for 04246fdf12c09446b88d2f40130581d603131c8e. The latter published six-asset Release v3.6.3-beta3-zadtberjmv. A live installed 3.6.3-beta3-s000000000201 build automatically selected, downloaded, and applied its 311,110,425-byte full package; the installed packages/RELEASES and the following check both reported zadtberjmv.

For a visible UI receipt, successful Super Express run 29980281736 published and promoted the greater same-SHA Release v3.6.3-beta3-zadtbhvdfc. On the isolated off-screen legacy process, Check for Updates changed from the reproduced stale latest version state to Downloading update…, then to An update has been downloaded and is ready to be installed with Quit and Install Update. Squirrel independently recorded localVersion=3.6.3-beta3-zadtberjmv, downloaded the zadtbhvdfc full package, wrote its app directory, repointed the execution stub, and finished. The accepted 960×660 capture is 49,195 bytes with SHA-256 a02cffa612114be3af5e0fffcd5b602a4ba4dfd3226298e48d143a6bed76bd4d.

Historical legacy Super Express installation with a newer alphabetic-z update ready at immutable source commit 923dbb51acad8f01f01f1c100c6945c7a2e08e23

The detailed fail-closed, remote, package, log, headless-desktop, and cleanup receipt is in docs/verification/auto-updater-version-order-2026-07-22.md.

2026-07-23 Cheap LFS registry storage and automatic push batching

This continuation is integrated, locally build/UI accepted, and remotely published through corrective source c22e29a03a. Its exact-source cloud, CI, CodeQL, Pages, and six-asset installer Release receipts are recorded above. The subsequent repository-scoped materialization serialization correction remains inside this overall task but does not borrow those earlier remote receipts.

Cheap LFS commit preparation now keeps a compact terminal-style panel directly below Commit. It reports sanitized active paths, hashing/preparation/upload/ verification phases, per-file and aggregate bytes, and completed/failed counts. The persisted Upload up to three large files at once toggle defaults on and limits Release or OCI transfers to three; disabling it restores sequential work. The Changes filter can isolate files strictly over 100 MiB. A per-file upload failure removes that raw path from the current commit but leaves it selected for retry; successful pointers and unrelated safe changes may commit, and an all-failed selection creates no empty commit.

Repository settings → Build & Run → Large-file storage now selects a published GitHub prerelease, GHCR, or Docker Hub. New Release buckets are real published prereleases, not drafts, and exact older Desktop Material drafts are published in place after revalidation. The progress panel also computes a byte/capability recommendation without changing the saved provider: ordinary Git at or below 100 MiB, Releases for one transfer totaling at most 1.5 GiB, private-source GHCR for a larger eligible GitHub.com batch, Docker Hub when it is locally configured, and Releases when no registry setup is detected. These signals do not prove live quota, billing, organization policy, or service health.

The concrete user report in codingmachineedge/lowlevel-computer-use-mcp was repaired without rewriting Git. Remote main f2edfe442555cfe35a519dd0b058986cb09d6ee3 contains the 166-byte pointer for software/docker.exe. After revalidating tag assets, release ID 357437469, its one uploaded asset ID 486745803, exact size 638124464, and provider digest sha256:a5b5837542f2f57fadbb09db90a60c84f8efc0a65f8d6dcd2e5b9fca3a2b87e6, that exact legacy draft was published in place as a non-draft prerelease. The four unrelated empty same-tag drafts were left untouched. The stable public asset is now available from the assets prerelease. The source repository currently contains only .github/workflows/pages.yml and has no Cheap LFS compression run, which proves why cloud compression never started. The updated app will create the managed .github/workflows/cheap-lfs-cloud-compression.yml caller in Changes when that public repository is opened; by design it is not silently committed or pushed, so the user must review and commit that one workflow before compression can run.

GHCR and Docker Hub each use one logical <source-name>-cheap-lfs OCI package with stable tag desktop-material-cheap-lfs-v1. A complete current snapshot is bounded to 4,096 objects, 8,192 layers, and 8 MiB each for canonical config and manifest JSON. Add or remove inside those proof bounds uploads only new content- addressed chunks, verifies a new immutable manifest, creates and verifies its deterministic retention tag, moves the stable tag, and rewrites current pointer- form files to that digest while preserving verified materialized raws and their valid older pointer metadata. Historical retention tags are not deleted. It cannot mutate or append to an existing manifest or timed-out layer; unchanged and already accepted blobs are reused, while a timed-out object is reprepared at half the prior layer bound down to an 8 MiB floor. New chunks start at 1.5 GiB, safely below GHCR's documented 10 GB layer limit, and each GHCR ORAS process times out below the provider's ten-minute boundary. Docker Hub has no hard layer-size or upload- time limit encoded; current plan, pull, storage, abuse, and fair-use rules remain external provider policy.

Same-provider updates retain the exact package coordinate already named by the committed/index-aware pointer inventory, including Docker Hub organization or collaborator namespaces. Only a first Docker publish defaults to the current credential username. GHCR-to-Docker or Docker-to-GHCR migration refuses unless every old pointer is an exact unedited materialized raw; it re-hashes those bytes, performs no old-provider pull or delete, publishes a fresh full snapshot, then rewrites the pointer-form paths. Mixed logical targets, same-provider relocation, pointer-form migration inputs, and edited raws fail before publish.

Verified-private repositories encrypt every OCI chunk with AES-256-GCM. The shared key is intentionally committed at .desktop-material/cheap-lfs-registry-key-v1 so authorized private-repository collaborators can restore it. This protects payloads from a registry-only leak; it does not protect them from anyone who can read the private repository, an old clone, fork, backup, or Git history. Key removal or rotation must retain old bytes for historical immutable pointers. New private pointers bind the exact key with key-id sha256:...; both canonical and legacy key paths are reserved from pin/remove operations. Required-key staging overrides ignore and selection state, proves the final commit-tree bytes, and safely rolls back a hook-damaged commit. Credentials remain operation-scoped: GHCR uses the selected GitHub.com account and Docker Hub uses the trusted Docker Desktop credential helper, passing a token to ORAS through standard input and clearing it afterward. A first public GHCR package is refused before upload because GitHub creates it private and exposes no supported visibility-change API; use Releases, Docker Hub, or an existing exact-linked public package. GitHub browser sign-in now requests write:packages; the account-scope audit offers reauthorization for older tokens, while destructive delete:packages remains excluded. GitHub's OAuth scope page describes write:packages as granting package upload/download, but its Container registry page separately says Packages supports PAT classic only. The selected OAuth token passed a non- mutating GHCR challenge; no live package mutation was performed, so PAT-classic compliance is not claimed and any provider rejection fails closed before the stable tag or Git pointers move.

Windows builds download and verify the official ORAS 1.3.2 AMD64 archive, executable, and license before packaging. The installer ships the Apache-2.0 text as static/cheap-lfs/oras/LICENSE.ORAS.txt. Both package architectures use that audited x64 executable, so the ARM64 package depends on Windows 11 x64 emulation and fails closed if it cannot start.

The default-on clone/open detector now scans Release and OCI pointers before it requires a selected Releases account. Explicitly public GitHub.com Release and public OCI pointers can materialize while signed out. Anonymous Release reads omit Authorization; Release mutations and private/unknown reads stay account- gated. Private OCI pointers fail closed without matching credentials and the tracked key. Updated Desktop Material repairs an old pointer-only clone by reopening it or by choosing Large files → Materialize all. Original bytes remain in Release assets or immutable OCI layers, and verified temporary bytes replace the working-tree pointer atomically only after size, digest, source identity, visibility, and (when applicable) GCM checks pass.

Ordinary Git commits now stay below a decimal 1.5 GB (1,500,000,000-byte) push ceiling by using a 1.4 GB changed-blob budget and bounded path/proof overhead. The app forms stable path batches, creates one commit, records a durable branch/remote/path intent and pending-commit ref, pushes it with ordinary fast-forward rules, proves that exact commit as the same remote tip, and only then creates the next commit. Intent-to-pending and final cleanup are atomic two- ref transactions. No later commit exists after a failed or ambiguous push; retry reconciles the exact intent and resumes the pending push before new commit work. A required tracked private-registry key is promoted into batch 1 and included in the byte/path/proof budget exactly once. Push also inspects local- only commits made by older app versions. Existing individually safe commits are pushed and proven one at a time without changing their SHA, author, timestamps, message, or signature before any new working-tree batch is created; a currently pending batch bypasses that legacy rewriter. An individually oversized commit can be rebuilt only on a clean, linear local-only branch with an exact configured or resolved destination and no Git operation. A compare-and-swap ref below refs/desktop-material/commit-batch-backup/ protects the original tip. Before the first proven push, a safe failure restores it; after a proven push, the app never rolls the branch backward and retains the recovery ref when needed. Every replacement batch must reproduce the expected path modes and object IDs, and a candidate already reachable from any configured remote is never rewritten. Rebuilding preserves the reviewed message and final tree but creates new commit IDs, does not preserve cryptographic commit signatures, and does not promise the original author timestamp on each replacement batch. Final tree equality and every replacement path's exact mode/object ID are proven before success.

Every app-owned commit entry point supplies process-local -c gc.auto=0; no repository/global setting is changed. The commit flow records HEAD and verifies the new commit's object, tree, parent transition, and message. If Git exits nonzero only after creating that exact commit (for example an unrelated post-commit maintenance failure), Desktop Material accepts it once and shows a maintenance warning. An unchanged, unreachable, or unexpected HEAD remains a real failure and is never retried into a duplicate commit.

Local acceptance is recorded in the dated Cheap LFS commit-progress receipt. The initial c3db37ea55 worktree's unpackaged production build returned 0 after 400.46 seconds (404.3 seconds wall) through Lowlevel MCP and produced out/renderer.css SHA-256 6381556b36c295ba47ad90e8080f4079cbc61951bd7811ab9cb9fc3520638cb1. That is retained as historical first-publication evidence; the responsive correction's current build receipt is the 390-second 6fba1434… build above. The current promoted accepted frame is:

Frame Dimensions Bytes SHA-256
docs/assets/screenshots/cheap-lfs-commit-progress.png 1440×960 113,869 3d6358567126e3ce0504b04c4489abbfd473b77546bd82dac834553d50fe9333

The wide English receipt passed all 36/36 named assertions, including noBlockingDialog, plus its deterministic one-pointer selection receipt and contains all three worker rows. The final 640×960 bilingual receipt also passed all 36/36 named assertions after one real pointer attempt. Its 85,175-byte capture has SHA-256 1b99c827d1b5b2cf05298fb1255873acdf0502f72a40437c378c0be7bb989e50, keeps the progress surface at y=942 inside the y=944 panel, and contains no injected diagnostic style. The earlier 1,466.27-second build, 107,411-byte wide frame, and visibility-hidden narrow failure remain in the dated receipt only as superseded interim evidence.

The corrected companion material-github-releases-compact.png proof passed at 100%, 125%, 150%, and 200% in one 960×660 physical viewport. The promoted 200% frame is 89,856 bytes with SHA-256 8e29ac666a0832d353126d8dd759200ba7e853016a940501e5c7cbdbb1cf992a. Its 480×330 CSS viewport shows one complete 53.5 px row, 24-hour timestamps, a wrapping bilingual disclosure, and zero horizontal overflow. All compact scales measured the 176 px panel, 30 px target floors, 9 px text floor, and the three-column metrics layout. Native Enter expands/collapses the tools; available actions retain focus semantics and the no-next-page pagination control remains correctly disabled. The gallery source now contains 77 images, including the dedicated live Bambu Cheap LFS frame.

Release/OCI operations pass 80/80, registry transport/runtime policy 77/77, disposable-Git batching 117/117, UI/settings/localization 157/157, ORAS scripts 8/8, the headless verifier contract 19/19, and the compact commit-shell style contract 7/7. The full Cheap LFS folder aggregate is deliberately reported as 261/262 because one wall-clock policy case exceeded its 2.5-second harness budget during concurrent heavy Git work; the isolated policy rerun passed 8/8, including that same behavior.

These UI/build receipts are local evidence for the initial integration and its isolated responsive correction. The final acceptance app PID 20836, HWND 1905774, provider PID 16700, hidden desktop, provider credential, ports 52613/53748, and exact owned temporary root were stopped, deleted, or proved absent. The separately retained installed-app Bambu environment remained untouched during that earlier checkpoint. Corrective source c22e29a03a later completed exact-source cloud, CI, CodeQL, Pages, and immutable six-asset installer publication. Bambu commit 712ad85, cloud run 30048474438, verifier run 30054805137, its immutable manifest Release, and the initial 10/10 fresh- clone hash proof are now complete. Only the newer serialized materialization rerun and its final promoted image remain explicitly pending above.

2026-07-22 Cheap LFS cloud compression implementation

Cheap LFS now has repository-local cloud compression without cloud decompression. A generated caller pins actions/checkout and Desktop Material's composite compressor to immutable SHAs, grants only contents: write, and runs on pushes to the repository's default branch or by manual dispatch. Public repositories receive automatic setup in the Large files UI. Private repositories remain off until the user explicitly enables a persisted setting; unknown visibility fails closed, and the workflow repeats a live event-visibility guard.

The Action downloads Release objects directly, raw-DEFLATEs one object at a time at level 9, and uploads a verified side asset without Actions artifacts or caches. A strictly smaller success changes only that pointer object to the existing v1 part-deflate form and pushes a [skip ci] commit. Mixed raw and compressed multipart pointers are valid. Original raw assets are never deleted because historical commits can still name them. Failed or non-beneficial objects retain their exact raw pointer and remain cloneable; independent later objects still run.

Desktop Material alone downloads and decompresses. Its existing bounded local inflate path checks the recorded output cap, original per-object size/SHA-256, and assembled whole-file size/SHA-256 before replacing a pointer. The UI labels raw, compressed, and mixed pointers, explains the local-only boundary, and offers English, playful Hong Kong-style Cantonese, and bilingual copy.

Focused tests exercise the real composite Action against a temporary Git remote and fake Release API, workflow/policy ownership, public/private UI controls, settings persistence, pointer state, failure and non-beneficial fallback, ambiguous-push recovery, build-output-style pointer paths, bounded draft lookup, atomic workflow replacement and link rejection, repository-switch races, and local compressed-object materialization failures. The final combined gate passed 134/134 tests across 25 suites; all 27 script tests, repository-wide Prettier and ESLint, the ESLint/Prettier compatibility check, TypeScript, and git diff --check also passed.

Live cloud-compression acceptance is complete in the retained repositories:

The first public run, 29967844734, also provides the live safe-failure proof. GitHub's tag endpoint returned 404 for the draft release; the Action reported 0 compressed, 0 kept raw, 1 failed safely, did not rewrite the pointer or remove the raw asset, and exited failed. The production UI then materialized that still-raw pointer successfully with the exact 1 MiB digest above. After the bounded draft lookup correction, the public and private compressed pointers were each materialized manually through the UI and again produced that exact size and digest on the local PC.

Draft lookup is deliberately bounded to 100 API pages of 100 releases, or 10,000 releases. If the exact draft tag is outside that window, the object fails safely and remains raw. A GitHub Release also holds at most 1,000 assets; because the historical raw asset is retained, a full Release cannot accept the compressed side asset and likewise stays safely raw until capacity is available.

The production bundle and all interaction ran through the fixed Lowlevel MCP HTTP endpoint on the isolated DesktopMaterialCheapLfsCloud-20260722-190000 headless desktop. The accepted bilingual private-opt-in/compressed-row frame is:

Accepted local capture Dimensions Bytes SHA-256
docs/assets/screenshots/cheap-lfs-cloud-compression.png 960×660 105,577 9449e50f60cd298e9cc261e9044fc0cd93706a8e9f243dcceb88d63b6df9ab8d

The canonical yarn build:prod wrapper could not start because this fixed environment has no yarn executable. No dependency was downloaded; the equivalent existing-dependency production Webpack command compiled all five targets through MCP in 420.6 seconds with ok: true, client_ok: true, and returncode: 0. The one-time development alias and GitHub credentials were deleted and verified absent, the production credential was restored with no backup left behind, the exact Electron process and zero-window headless desktop were closed, and the owned synchronized test-clone run root was removed.

Publication is complete for source checkpoint f7b4760a13894f0320f7b361f055f6fba40d913f, which is pushed on main with a clean zero-divergence checkout. Exact-source CI 29972351158, CodeQL 29972351173, and Pages 29972351147 all succeeded. Wiki commit 407cbf260c229e9f8e7fd86062afad83e5080f63 publishes the synchronized seven-page source, and the live Pages gallery serves all 73 figures including the byte-identical 105,577-byte cloud-compression capture. Downstream installer run 29973527338 published non-draft, non-prerelease latest Release v3.6.3-beta3-b0000040887 from that exact tag and commit with all six required Windows x64 assets. The final source audit found only local/remote main, one root worktree, and no stashes.

2026-07-22 live Cheap LFS public/private GitHub and UI acceptance

Live Cheap LFS protocol, history, and Desktop Material UI acceptance completed through the configured DingDingChae account. Both purpose-built repositories are retained on pushed main commits:

Both releases remain draft prereleases tagged assets-test-20260722-153308. The original backend assets and the two UI-created assets are all uploaded at 1,048,576 bytes with digest sha256:30e14955ebf1352266dc2ff8067e68104607e750abb9d3b36582b8af909fcb58. The public UI explicitly materialized and re-pinned its payload; the private UI materialized on open in a fresh profile and passed the same native-picker, review, upload, and pointer-replacement sequence.

The first live UI attempt exposed two defects: GitHub's exact draft-tag route can return 404, and an absent asset label can arrive as either null or "". The store now performs a bounded release-inventory fallback, while the provider model normalizes both no-label spellings. The focused Release-store and transfer/model gates pass 17/17 and 41/41, TypeScript passes, and all five production Webpack targets plus staging completed in 296.8 seconds.

Fresh public/private clones resolved to the exact UI commits above, retained their earlier deterministic-pointer commits as parents, and were clean. Their canonical five-line Git blobs are 201 and 202 bytes; Windows CRLF copies are 206 and 207 bytes. git lfs ls-files returned no entries, proving the test is real Cheap LFS history rather than Git LFS metadata.

The user explicitly authorized a temporary bridge from the logged-in GitHub CLI account to Desktop Material's development secure store. The token was not printed, logged, placed in an argument/URL, written to source, captured, or committed. After both isolated UI runs, the exact credential entry was deleted and re-read as absent; the app PIDs, CDP ports, and off-screen desktops were also closed.

Both repositories include the generated Cheap LFS logo. The canonical documentation copy at docs/assets/cheap-lfs-logo.png is 1254×1254, 1,091,778 bytes, SHA-256 34b2e68ad1e95f45cac08e3c2ee5d9981a35611d30b0deb7282a5c7fe0682a2f. The accepted UI capture at docs/assets/screenshots/cheap-lfs-ui-acceptance.png is 1200×752, 79,404 bytes, SHA-256 8f53ed803dc7415ca86e4399040201afbbd627718a48e4a453e637099fa03684. Full evidence is in the dated verification record.

2026-07-22 command palette rows, tab groups, Alt reliability, and release gates

The published baseline at 7edca120c5 introduced rich command-palette rows, appearance controls, the first tab-group data/actions, and its accessibility follow-up. That exact SHA is on origin/main; CI 29895625564 and code scanning 29895625583 passed. Build Installers 29896993449 published the non-draft, exact-target Windows release v3.6.3-beta3-b0000040881 with all six required non-empty installer/feed/portable assets. Those receipts prove only that baseline; they do not verify the continuation below.

The current continuation makes tab groups real, visible strip controls. One named/color-coded chip appears before each group's first member with a count, chevron, accessible expanded state, and active-group marker. Clicking the chip or pressing Enter/Space hides or restores the member tabs; focus and a localized status announcement return to the chip when a mutation removes the focused tab from view. Group creation, context actions, color names, chip descriptions, success/failure announcements, and accessible names now follow English, playful Hong Kong-style Cantonese, or bilingual mode.

Persistence now retains groups through open, single-close, bulk-close, session-import, per-window serialization, legacy-primary mirroring, reload, and unknown-field round trips. Malformed/duplicate group records are repaired at the profile boundary. A group can contain pinned tabs or unpinned tabs, never both: a cross-boundary move is a no-op, preserving the invariant that every pinned tab precedes every unpinned tab. Portable version-1 tab-session exports deliberately strip groupId and do not export profile-local group definitions; import preserves the destination profile's groups rather than creating dangling memberships.

Group ordering is normalized as one contiguous block at load and after every structural mutation. Manual movement within the block keeps membership; moving a member outside the block ungroups only that tab. Label, opened-time, repository-status, and favorite arrangements sort whole blocks by their first member, and malformed cross-pin input degrades incompatible later members to ungrouped tabs rather than splitting one group across the boundary.

The command palette keeps its 760px shell, 520px result area, leading icon, title, optional keyword line, and group chip. The title/search/empty state, stable group labels, row search-term prefix, anchored appearance editor, and the Ollama/Copilot/background-queue discoverability entries now follow all three language modes. Search retains English and localized keys. Escape closes only the appearance editor and restores its toggle focus; density and row-part choices remain persisted and safely repaired.

Windows bare-Alt handling is now an isolated state machine: one uninterrupted bare press toggles once, held repeats remain part of that press, and Alt plus another key, Shift/Ctrl/Meta, prevented events, modal transitions, orphaned repeats, or out-of-order key-up events cannot leave stale state for a later toggle. Every Alt release consumes its pending sequence and clears the menu highlight path. This is covered as a deterministic keyboard-state contract; current end-to-end headless interaction evidence has not yet been recorded.

At this July checkpoint, the manual Super Express Release lane ran the complete unit and script suites before its production build/package. That test-before-build contract was explicitly superseded on August 2 by the owner-directed zero-test emergency lane recorded later in this handoff. Release pull requests continue to target the Windows product's main default branch.

Local continuation acceptance is complete; publication is pending. The exact unpackaged production build passed through the fixed Lowlevel MCP endpoint in 394.1 seconds with client_ok: true. An isolated off-screen run restored the named group after relaunch, collapsed it to a selected role="tab" chip, expanded it again, and confirmed the member was visible. The same run opened the fully contained command-palette appearance editor, kept Reset visible, and returned five Ollama matches.

Accepted local capture Dimensions Bytes SHA-256
docs/assets/screenshots/material-tab-groups.png 1000×687 94,467 fd857137f71b79fbef65225e4469f2d2e3d95ecb6701e4847b84da11ad2875b8
docs/assets/screenshots/material-command-palette-appearance.png 1000×687 99,234 ac4db2aa3696d2e1987c0c93573ccf48f86c61111e42fcabf0cec54db3b87a7d

README, Pages, the User Guide, and the 73-scene Guided Feature Gallery now reference the two inspected synthetic-only captures plus the separately accepted raw and cloud-compression Cheap LFS UI frames. Implementation checkpoint 58be6fe5953477b015a134c414a8cf82363ecc75 is pushed on main; exact final CI/code scanning, Pages/wiki publication, and installer Release receipts remain required.

The published Pages site is now usable on a phone. The top app bar previously hid every navigation link below 760px, leaving Install/Features/Screenshots/ Docs unreachable; a hamburger control now discloses the same links as a stacked sheet with 48px targets, and a 480px breakpoint collapses the feature, footer, and principle grids to one column without page-level sideways scrolling. The rendered documentation template gained a sticky, wrapping header, a search field, and a compact type scale.

site/docs-search.html publishes as docs/search.html and searches every rendered page from a search-index.json built by site/build-search-index.js during the Pages workflow (137 pages locally). Search accepts plain text or a regular expression with match-case and whole-word options, highlights up to three excerpts per page, guards zero-length matches, reports invalid patterns instead of throwing, and mirrors state into the URL. A regex builder composes contains/starts/ends/exact/any-of/all-of patterns with an optional quantifier plus six ready-made snippets, previews the pattern, and applies it to the query. The builder was exercised in a browser: (?:cheap lfs|pull request) and \b(?:timeout)+\b both compile.

Screenshot regeneration ran against a fresh production build on an isolated profile with the deterministic loopback GitHub provider and Ollama fixtures. 52 distinct canonical captures were promoted (50 replacements plus the new material-repository-folder-detection and material-repository-submodule-management, both added to the Feature-Gallery catalog, the Pages gallery, and their two count assertions, now 69). Two captures were withheld because they were byte-identical to another surface (material-api-app-functions matched the API explorer; material-notification-bulk-actions matched the notification centre), so the previously published images for those two remain in place rather than publishing a duplicate as a distinct feature. Thirteen further canonical scenes could not be made deterministic in this run and their existing images are unchanged: error-notice, app-identity, history-power-tools, remote-manager, logo-studio, submodule-context, rebase-review, pull-request-compose, pull-request-open, pull-all, history-deepen, history-deepening, merge-all, and cheap-lfs-preparing. They need the additional submodule/shallow-clone/remote fixtures rather than the base P0 fixture, and material-pull-preview and material-ollama-model-manager are outside the canonical set. No scene is reported as renewed unless its file actually changed.

2026-07-22 Cheap LFS 1.5 GiB parts, no upload timeouts, Pages-hosted docs

Cheap LFS release uploads kept failing near the 2 GiB asset ceiling, so CHEAP_LFS_PART_SIZE_BYTES now plans new parts at 1.5 GiB while the pointer parser still accepts legacy parts up to exactly 2 GiB. Release-asset uploads no longer apply any stall or total-runtime timeout by default on either the GitHub CLI or Electron compatibility transport: a transfer ends only on completion, transport failure, or user cancellation. Tests keep injecting explicit stallTimeoutMs/maximumRuntimeMs values to exercise the watchdog paths, and the pointer contract test now pins the legacy 2 GiB parse bound independently of the upload cap. Feature and User Guide documentation were updated to match.

The GitHub Pages site now hosts the complete rendered documentation set. The Pages workflow installs pandoc, renders every docs/**/*.md (README files as folder indexes) plus the root project documents through site/docs-template.html with site/md-links.lua rewriting .md and wiki-style links, and the site's Docs/Read-the-docs/Documentation links point at the hosted docs/ index instead of redirecting to the GitHub wiki. The render loop was executed locally with pandoc 3.10 (137 docs pages plus root documents) and one page was visually verified. Local verification: 142 passing tests across site accessibility, CI workflow safety, release transfer, cheap-lfs, and pull-preview contract suites, plus repository-wide TypeScript no-emit and Prettier on changed files. Remote CI, the Pages deploy, and the express release are post-push verification items.

2026-07-21 pull preview moved to right click on the toolbar Pull button

A plain left click on the toolbar Pull remote button now performs the pull directly via the dispatcher; the reviewed pull-preview dialog opens only from a right click on that button (wired solely to the pull-state button) or from the application-menu Pull action, which is unchanged. The pull-preview contract test was updated to pin the new routing, and the feature doc, docs index, wiki User Guide, and Feature Gallery now describe the click/right-click split. Verified locally with the pull-preview contract suite (5 passing tests), repository-wide TypeScript no-emit, and Prettier on changed files. Remote CI and release publication occur after push.

2026-07-21 reviewed pull previews

Ordinary pulls now open a reviewed Material dialog before mutating the current repository. The implementation freezes the local/upstream refs and full OIDs, ahead/behind counts, effective pull.rebase/branch rebase/pull.ff plan, and bounded incoming commit/file summaries. Confirmation revalidates that identity, strategy, and a freshly read clean worktree, then integrates the exact reviewed OID. Unsafe, stale, detached, conflicted, dirty, failed-fetch, busy, and fast-forward-only-blocked states fail closed. The dialog is globally modal and non-dismissible while Git runs, with persisted English, playful Hong Kong-style Cantonese, and bilingual copy.

Local verification on implementation source b86b4618d3 passed 92 focused tests across 24 suites, TypeScript no-emit, changed-source ESLint/Prettier, git diff --check, and the exact production command npx --no-install cross-env RELEASE_CHANNEL=development DESKTOP_SKIP_PACKAGE=1 yarn build:prod through Lowlevel MCP (exit 0; 625.37 seconds). The fixed MCP checkout was ed1427f69b20dcd66df1de2ae3c6ba6591e2e640.

The app was exercised on the uniquely named off-screen Win32 desktop DesktopMaterialPullPreview-b86b4618 against a synthetic clean repository. The review showed local 6692f0306cb38b794ed44d910f32f554134aeff0, upstream c5543728717b5029acc9b80c901dd22f6fcdc343, 0 ahead, 2 behind, a fast-forward plan, two incoming commits, and three changed paths. Confirming the dialog advanced HEAD to the exact upstream OID with +0/-0 and no worktree changes. The inspected client-only screenshot is 960×660, 62,882 bytes, SHA-256 cbbfc9876ded7366aca8532a7d685fed4a959453c1ccfd1845f4dc7fc408895, at docs/assets/screenshots/material-pull-preview.png; it is nonblank, unclipped, and contains synthetic data only. The validated Electron PID, hidden desktop, and containment-checked fixture root were removed and confirmed absent.

The feature was replayed onto the latest remote baseline in an isolated publish worktree because another active task had unrelated edits in the shared checkout. Those edits were left untouched. Remote CI, Pages, installer/release, and live wiki synchronization are post-push verification items.

2026-07-21 CI lint newline repair

GitHub CI run 29879526652, Lint job 88797062810, failed only during the repository-wide Prettier check: opencode.json had no final newline. The configuration values and permissions were already valid, so the repair adds only the missing newline and does not change OpenCode behavior. On the exact failing source plus this repair, the full CI-equivalent yarn lint command passes Prettier, the ESLint/Prettier-compatibility check, and repository-wide ESLint. Remote CI and installer publication remain pending until this commit reaches main.

2026-07-21 final pull-preview, Cheap LFS, and stale-overlap CI checkpoint

Reviewed pull previews now gate execution on fresh repository status, retain an atomic raw strategy/configuration snapshot, and parse changed-file output as a bounded stream. A busy sentinel and phase-locked modal prevent refresh, close, or footer actions from racing an active pull; accessible state and the footer remain synchronized with the exact phase. The privacy-safe reviewed pull-preview screenshot was accepted at 960×660.

Cheap LFS cancellation now opens an explicit confirmation instead of stopping the operation immediately. The GitHub CLI fallback streams the exact source, uses 1 MiB chunks to reduce renderer progress traffic, verifies the streamed digest, bounds retry, and reconciles the Release inventory before retrying so an ambiguous prior upload is never duplicated or deleted. Authentication, proxy authentication, cookies, and Basic credentials are redacted from bounded CLI diagnostics.

The manual browser handoff now stages only regular, nonempty files. It uses a verified same-volume hardlink when possible and otherwise a bounded copy; it never exposes a symlink that Explorer or GitHub can interpret as an empty .symlink file. Multipart files remain actual regular parts. Existing uploads with the exact expected size and digest count toward progress and capacity, so a partial manual upload can resume with only missing objects. Digestless legacy assets receive bounded download/hash verification before reuse. Every reuse is revalidated against a fresh complete Release inventory, followed by a final inventory fence before any pointer is published.

The pre-integration Cheap LFS gate passed 189/189, with the manual staging and partial-resume subset passing 23/23. After rebasing onto the final remote baseline, the expanded Cheap LFS/Release selection passed 207/207 and the pull-preview selection passed 81/81. Root TypeScript, configured targeted ESLint, targeted Prettier, feature-document markdownlint, and git diff --check are green on the merged tree.

Express Installer hotfixes 98bd712f2f and 484ebc0210 separate stale overlap from genuine CI failure without dropping a successful Release. Every successful exact target publishes its own immutable Release even after newer commits overtake it. Creation is always non-latest; only a freshly revalidated current main target is promoted, and a mid-promotion branch advance triggers verified demotion. The flow deliberately avoids GitHub's lossy shared concurrency queue. A real failed upstream CI still preserves the artifact while the workflow remains failed. The focused workflow contract passes 8/8.

Release v3.6.3-beta3-s000000000201 was already published from fa4806971c with all six required assets. That is the verified installer-release baseline, not a claim that the later hardening batch has published. The user explicitly requested that completion not wait on future CI, and explicitly skipped the GitHub Projects board; neither is a remaining acceptance gate for this batch.

2026-07-21 final Git topology cleanup

Feature tip 5c0fec2381 was verified byte-for-byte as the remote main tip before cleanup. Every remaining local and remote topic-branch tip was proven an ancestor of that pushed default branch. Eight merged local topic branches and four merged remote topic branches were then deleted without force; the two temporary CI worktrees had already been removed after their own remote proofs. git worktree prune leaves only the clean main checkout, the stash list is empty, all initialized submodules are at their recorded commits, and local main has zero divergence from origin/main at this checkpoint.

2026-07-21 printenvz Windows install-stage repair

The install stage failed building vendor/printenvz with LINK : fatal error LNK1117: syntax error in option 'opt:lldltojobs=2'. Node >= 24 Windows headers ship enable_thin_lto=true and lto_jobs=2 in config.gypi, so the bundled common.gypi Release config injects clang/lld-only flags (-flto=thin, /opt:lldltojobs=N) into every gyp target; MSVC link.exe rejects them. vendor/printenvz/binding.gyp now forces enable_lto=false, enable_thin_lto=false, and lto_jobs="" on Windows through gyp's conditions-inside-variables pattern, the only scope that survives config.gypi include merging and still applies to target_defaults Release conditions (target-level variables are evaluated too late, and plain top-level variables are overwritten by includes). Verified with the exact failing step (node-gyp rebuild in vendor/printenvz): build/Release/printenvz.exe links and runs, and the generated printenvz.vcxproj no longer contains any -flto/lldltojobs options. No cleanup of branches, worktrees, or stashes was needed; the untracked opencode.json predates this task and is intentionally left uncommitted.

2026-07-21 Settings clone queue and mobile connection checkpoint

The durable automatic-clone policy now has a first-class Settings → Clone queue destination. One card per signed-in hosted account hydrates the saved base directory, parallel/sequential mode, and enabled state. A folder is required before enabling; changing the directory or mode while enabled updates the same policy immediately. Discovery still establishes a baseline and checks every five minutes, queues only newly discovered repositories, uses the existing three-wide/one-at-a-time modes and durable batch journal, and never opens an unsolicited progress dialog. The page does not expose the Agent API's fixed eight-running/64-waiting request bounds as user settings.

Settings → Agent access now keeps a localized Mobile connection card visible in every mode. Local or stopped states explain the required recovery; when Paired LAN mode is running, Open mobile connection page first replaces any existing pairing code, then hands the fresh five-minute one-use /connect URL to the default browser. Its secret stays in the fragment, is not logged or sent to the site server, and a browser-open failure reports only a generic localized error.

Focused Queue, Agent access, and Settings registration coverage exercises policy hydration, directory choice/validation, enable/disable and clone-mode dispatch, fresh-link generation, unavailable states, browser failure, and all three language modes. The responsive inventory includes the new Settings page. Exact-source TypeScript/lint/format gates, production build, Lowlevel MCP off-screen interaction and screenshot acceptance, remote CI, Pages/wiki sync, Release verification, and final topology cleanup remain separate acceptance steps and are not claimed by this checkpoint.

2026-07-21 manual multipart Cheap LFS and express release checkpoint

The browser-assisted Cheap LFS fallback no longer rejects a file merely because it exceeds GitHub's per-asset size limit. Planning first stats the complete batch, fails before expensive hashing when projected parts exceed one Release's 1,000-asset cap, streams whole/part SHA-256 values, allocates one bucket with room for the complete batch, and reserves collision-safe names. A large source becomes ordered .partNNN files in the private handoff folder using 1 MiB bounded range copies. Small sources retain symlink, hardlink, then bounded-copy fallbacks. Hash and copy callbacks are time-throttled before they reach the renderer, the preflight reserves the worst-case copy fallback plus verification space, and Unicode/Win32 case variants cannot collide in the flat folder.

The existing single action opens the exact Release editor and the prepared Explorer folder. Polling remains cancelable for roughly six hours, backs off to 30 seconds, scans the bounded paginated inventory once per attempt, accepts only new uploaded IDs with exact names and sizes, downloads and hashes every part sequentially, then rehashes every source before writing any pointer. A version-2 handoff manifest records original nested paths and all flat asset ranges. Materialization uses the bounded preview when sufficient and otherwise caches the complete paginated Release inventory before resolving pointer parts, so assets beyond the preview page are not reported missing. Subfolders remain encoded in each tracked pointer; they do not need matching Release folders.

Build Installers / Express Release keeps the automatic successful-main-CI path and adds a manual main-only fast path whose Linux lint, Windows x64 trampoline/unit/script tests, and Windows x64 build/package jobs run in parallel. A failed or cancelled main CI still runs the package lane for a recoverable Actions artifact but cannot publish. The package job uploads the exact ZIP/EXE/MSI/Squirrel payload as a three-day uncompressed artifact before release-note generation and publication. The publisher revalidates current main and tag absence, then uses one create-only gh release create --notes-file call. A deterministic package-version-plus-commit-count tag prevents reruns from inventing a second release for the same source commit.

The shared CI setup action restores only an exact installed-dependency cache keyed by platform, target architecture, toolchain, manifests, lockfiles, install configuration, post-install logic, and local vendor inputs. It includes Playwright's external FFmpeg payload; Python setup remains unconditional. Cache hits and cold installs validate package sentinels before use or cache save; misses retain bounded install retries. Build output, installers, Release payloads, credentials, and runtime configuration are not cached. Focused Cheap LFS, UI, workflow-safety, setup-action, and release-note tests currently pass 72/72. Remote CI, cache-hit timing, live multi-gigabyte browser upload, and Release publication remain external verification rather than claims in this checkpoint.

2026-07-21 responsiveness, resource lifecycle, and CI handoff

The lag, hang, and retained-resource implementation is integrated through 2a2742796bdf65fc8562b317dcb73423bff9aa30. The final task branch is rebased onto the concurrent clone-queue/mobile-settings work at fa4806971c; its two task commits update the temporary-submodule build-fix guard contract and make wide anchored appearance editors use their intended 780 px shell without changing the compact 390 px fallback.

The focused Git/process gate passes 30/30, the changed-test/Pages/wiki gate passes 84/84, the complete UI directory passes 815/815, and the full all-files run passes 1,491/1,492 with one intentional skip and zero failures. After the later release, CI, and settings integrations, the combined Cheap LFS/release/workflow/guard/responsive-editor gate passes 83/83.

The fixed Lowlevel MCP checkout remained clean at ed1427f69b20dcd66df1de2ae3c6ba6591e2e640. App-source candidate aabb111d2c01f38e7535ab077048816a5ad16893 completed the required no-download production build; all five Webpack configurations compiled successfully and the build finished with Done in 1178.13s. The later fa4806971c app feature arrived while that build was running, so the pushed-SHA Windows CI result is the required final integrated build proof.

The first off-screen screenshot candidate was rejected during final visual audit because the 780 px repository-toolbar editor was clipped by its 390 px anchored shell. The shell-width defect is now fixed and covered by a responsive style contract. The rejected PNG is not published; the tracked gallery image remains unchanged, and a fresh final-source recapture is follow-up evidence. All owned Electron processes, loopback listeners, and headless desktops from the rejected run were closed.

Remote CI proved the Playwright cache validator fix on Windows x64, packaged E2E, and arm64. The remaining x64 failure was exactly the stale runOpencodeFix source assertion corrected by this branch. A concurrent opencode.json merge then added a missing-final-newline lint failure; this handoff formats that file as well. Exact pushed-SHA CI, installer, and Release verification remain pending.

2026-07-21 remote discovery hard-total-bound follow-up

The responsiveness correction is rebased additively onto 910f7de5be3b577e4492d65c1162fcea962d7652. Remote default-branch discovery still receives five seconds, including proxy environment preparation. If that deadline aborts an owned Git process, process-tree termination receives one final five-second grace window. The advisory post-fetch lookup therefore has a ten-second hard settlement bound even when taskkill/SIGKILL completes without an observable child close. Its termination promise receives a rejection observer as soon as abort starts, including after the caller's bounded wait has ended. Clone cancellation continues to use the unbounded strict-close barrier.

Repeated environment preparations for the same exact URL and resolver now share one in-flight system proxy promise. A timed-out caller can stop awaiting without starting duplicate unresolved operating-system work; success or failure evicts the entry and authentication environment assembly remains per operation. Electron exposes no abort signal for proxy resolution, so one permanently stalled entry can remain for each distinct URL until resolution or restart.

The Windows helper audit found only the existing environment-derived SystemRoot pattern (and equivalent WINDIR guesses) in this Node/Electron codebase, not an authoritative GetSystemDirectoryW binding. The correction therefore preserves the existing realpath/type/basename/containment validation and C:\Windows fallback instead of substituting a different guess. Independent Windows-installation-directory authentication remains a defense-in-depth item.

Deterministic focused coverage passes 30/30: injected never-settling and late-rejecting terminators, the normal cleanup barrier, same-URL proxy coalescing and eviction, and clone's unchanged strict termination barrier join the existing remote-HEAD/account/clone tests. The exact rebased changed-test, Pages, and wiki set passes 84/84. Root and script TypeScript, changed-source ESLint and Prettier, categorized feature Markdown, and diff integrity pass on the same tree. This local checkpoint claims no push, CI, package, wiki deployment, or Release.

2026-07-21 temporary submodule viewer and dialog-wheel checkpoint

The changed/new submodule commit card no longer calls the permanent openOrAddRepository path. It resolves the clicked absolute checkout back to a currently declared submodule, rejects relative or unrelated paths, and enters the existing validated SubmoduleRepository path. That model remains absent from the repository database, Recent, tabs, and last-selection persistence and keeps the established read-only mutation/process boundary.

The manager and diff card now say Open temporary viewer instead of promising normal repository management or commits. English, playful Hong Kong Cantonese, and compact bilingual resources explain the read-only/no-import boundary. The temporary context bar adds a visible, accessible, responsive Close viewer action beside the customizable Back control. Both use the same guarded return path, which disposes temporary caches and restores the persisted parent.

The shared dialog shell now routes wheel and trackpad gestures from any descendant to the nearest vertical owner with remaining range. Nested lists and editors consume their own range, an owner at its edge lets the outer body take the next gesture, preventing controls and Ctrl+wheel retain ownership, and a background floating dialog still requests front through the existing stack.

Local verification passed 103/103 checks: 67 temporary-viewer, localization, and Pages contracts plus 36 existing dialog/responsive/style regressions. Root TypeScript no-emit, targeted ESLint, targeted Prettier, and git diff --check passed. The fixed Lowlevel MCP endpoint at http://127.0.0.1:8765/mcp timed out during startup_status; the visible desktop was not used as a fallback. Therefore this checkpoint claims no exact production build, off-screen screenshot, remote CI, or release. After rebasing onto d6dd74b9d761f3b384788af8b2a8889213017d4b, all six changed test files pass 46/46; root TypeScript and exact changed-file ESLint, Prettier, Markdown, and diff gates also pass.

2026-07-21 Cheap-LFS CLI-first crash containment and direct manager

Production Release-asset uploads now try the trusted, exact-length GitHub CLI transport before Electron. This prevents the reported fatal mojo result not ok: 9 path when a validated gh.exe is available: Electron's native chunked upload data pipe is never opened for that attempt. GitHub CLI credentials remain isolated, progress stays bounded, and cancellation/quit still tears down the owned child process. The memory-bounded Electron uploader remains only as the compatibility path when the trusted CLI cannot be resolved.

The repository rail now has a direct, localized Large files destination. Its Cheap LFS manager lists committed pointers from nested folders, searches by path, pins reviewed files, materializes one or all objects, and owns a stable vertical scroll region. Users no longer need to locate or decode assets in the GitHub Releases catalog. The existing Release editor plus flat temporary-folder handoff remains available for explicit browser recovery; its manifest still maps every asset back to the original repository-relative path.

The manager, repository-section mapping, scroll contract, and all three language modes pass 48/48 focused tests across six suites. This checkpoint does not claim a live multi-gigabyte upload or final packaged-app visual receipt.

2026-07-21 CI update-coming-soon and exact-SHA Release notes checkpoint

The updater now distinguishes “no release yet” from “GitHub Actions is actively building or packaging a newer commit.” After Squirrel reports no update, a bounded unauthenticated provider probe derives only the configured HTTPS GitHub release feed and reads exact ci.yml plus build-installers.yml run data. It accepts only an in-progress main push CI run or workflow-run/manual-dispatch installer run under the expected workflow path. Bounded job data must also prove that run's exact Windows x64 build/packaging job is in progress for the same run ID and SHA. GitHub's compare endpoint must then prove that exact SHA is ahead of the installed exact __SHA__; equality, behind/diverged state, malformed data, a non-GitHub feed, network failure, and rate limiting all retain the ordinary no-update state.

The accepted state is the new in-memory UpdateComingSoon enum and is never stored. About renders New update coming soon, 新版本就快焗好出爐, or the compact bilingual composition from the existing persisted language preference. The ordinary last-check timestamp remains compatible. An update-transition generation prevents a delayed Actions/compare result from overwriting a real Squirrel available/downloaded event, and the check button plus existing four-hour schedule continue to use the normal release feed after publication.

Build Installers now checks out full history at the same exact RELEASE_TARGET_SHA already protected by the initial and pre-publication main checks. A new TypeScript generator reads the latest published Release through a 256 KiB authenticated response, resolves its tag, requires ancestry and exact HEAD, collects at most 50 newest exact commit IDs/subjects in the range, and caps the final body at 24,000 characters. Subjects are whitespace/control normalized, limited to 180 characters, and neutralized for Markdown, HTML, and mentions. The notes expose the exact range and commit links, report omitted history, preserve the update-feed explanation, and reach the single release action through body_path; mismatches fail before publication.

CI, installer, and Pages now make the overlap contract explicit: each invocation has a unique run_id/run_attempt concurrency group and cancel-in-progress: false. A newer run therefore cannot cancel active work or replace GitHub's single older pending slot. The workflow source contract scans every YAML workflow to reject cancel-in-progress: true and any declared group that omits either uniqueness component. Release notes are generated before the final main/tag revalidation, keeping that fail-closed check immediately adjacent to the single publish action.

Focused updater, persisted-state, race, English/Cantonese/bilingual, non-cancelling workflow concurrency, exact Git range, sanitization, bound, and first-release checks pass 35/35. Root app TypeScript and script TypeScript pass. The implementation has not been pushed or exercised by remote Actions, so no CI run or sample published Release is claimed. The fixed low-level MCP preflight passed after its stalled scheduled task was restarted, but the mandated no-download production-build command could not start because this host has no yarn executable; no headless GUI capture is claimed. Integration must preserve the exact workflow filename and include the generator, workflow, runtime, tests, feature docs, wiki, Pages, roadmap, and this handoff together.

2026-07-21 Codex CLI support for Build & Run repair

Build & Run's existing OpenCode repair path now also supports the Codex CLI. The failed-build and free-form send dialogs expose the same provider selector, persist it per repository, and retain a separately gated per-run auto-approve choice. Settings exposes both preferences. New labels and guidance use English, playful Hong Kong Cantonese, and compact bilingual resources.

The installed codex-cli 0.144.0 help was inspected directly before the runner was written. Detection uses shell-free codex --version and codex login status. Execution uses the supported stdin form:

codex --ask-for-approval <on-request|never> exec --sandbox workspace-write \
  --disable hooks --ephemeral --ignore-user-config --ignore-rules \
  --color never -

A local parser dry run of that complete option prefix with --help exited 0; putting --ask-for-approval after exec exited 2. A second installed-CLI probe confirmed that --disable hooks disables the stable hooks feature and --ignore-rules is accepted. The exact root-option order and flags are locked into the pure and runner tests.

The child cwd is the repository root. Neither the repository path nor prompt enters argv. A selected nested profile directory is lexically validated to stay inside the repository, capped at 1,024 characters, and included in stdin only. Failed-build output is capped at 4,000 characters, free-form input at 8,000 characters, captured detection output at 8,000 characters, and each streamed line at 16,000 characters. Both providers retain the existing bounded dialog/panel buffers and application-owned shutdown barrier. Operations are owned by the exact renderer WebContents; duplicate IDs are rejected, foreign cancellation is ignored, owner navigation/destruction aborts and awaits the process tree, and panel Stop fences the verification rerun. Codex never receives the dangerous sandbox-bypass flag.

--ignore-user-config skips the user's base config, --disable hooks disables lifecycle hooks, and --ignore-rules skips user/project execution-policy rules. An inert installed-CLI probe also established that mcp_servers={} does not clear MCP servers contributed by trusted project .codex/config.toml, and Codex CLI 0.144 exposes no verified blanket MCP-disable switch. Project Codex configuration therefore remains an explicit repository trust boundary; the integration does not claim MCP isolation.

Missing Codex installs show npm install --global @openai/codex behind explicit consent. Missing authentication points to codex login in a terminal and states that Desktop Material does not request or store secrets. Agent completion never establishes success: the dispatcher still runs the selected Build & Run profile again unless the operation was cancelled.

Verification from the isolated codex/codex-build-fix worktree based on 2a2742796bdf65fc8562b317dcb73423bff9aa30:

The README, categorized feature documentation, roadmap, local wiki sources, Developer Guide, User Guide, and Pages source now describe the feature and its safety/failure contract. A packaged production UI run, screenshot acceptance, default-branch integration, remote CI, wiki/Pages publication, and release proof remain pending. This branch is intentionally committed without push or merge so the coordinating agent can integrate it with the other July 21 worktrees.

2026-07-21 Cheap-LFS recovery, output controls, and portable-ZIP checkpoint

This earlier checkpoint removed two misleading Cheap-LFS progress states from the compatibility Electron path. A two-minute no-forward-progress watchdog aborts its owned request, and the transfer reserves 100% until an exact provider response or reconciled asset proves GitHub accepted the object. The later CLI-first checkpoint above prevents that native data pipe from opening whenever the trusted GitHub CLI is available.

A stalled request now retries automatically through a fixed gh api transport. HTTP 411 also selects that exact-length path because GitHub requires Content-Length while Electron needs chunked mode for memory-bounded multi-gigabyte requests; HTTP 502 selects it because the failed native request may have left an asset in starter. Each reconciliation scans at most the ten 100-object Release pages once, then polls only the discovered asset ID. An exact uploaded name, label, size, and digest is reused, while a persistent incomplete object fails closed without clobbering or deleting it. A failed CLI process gets one post-failure reconciliation in case GitHub committed the upload before the transport error.

The fallback resolves only the real Program Files\GitHub CLI\gh.exe, uses no shell, and supplies the selected account token only through a scrubbed child environment and one temporary empty GH_CONFIG_DIR. Inherited GitHub credentials/debug state, prompts, update checks, telemetry, spinner, and color are disabled. The exact validated source range streams through stdin while its SHA-256 and progress are calculated; stdout/stderr, no-activity time, and total runtime are bounded. Cancellation terminates and awaits the owned process, and the temporary configuration root is removed. Application quit now stops accepting Release transfers, aborts all active native/CLI work, and waits for their completion through the existing owned-process shutdown barrier. Missing CLI, failed CLI, and incomplete-asset results have localized English and playful Hong Kong Cantonese recovery text; bilingual mode composes both. The explicit browser/Explorer drag-and-drop handoff remains available when the user chooses manual recovery.

The Build & Run panel now exposes a one-shot Scroll to bottom action, persisted Auto-scroll output, and persisted Truncate long lines. Reading older output automatically pauses auto-scroll; enabling it again jumps to the tail. Truncation is display-only: the full line remains in the DOM and Copy all output retains the original text. Both toggles expose pressed state and all three names use the English, Cantonese, or shared bilingual translation path.

Windows packaging now creates dist/GitHub Desktop-x64.zip from the complete packaged application tree before building the Squirrel outputs. Native Windows tar.exe streams a ZIP64-capable archive to .partial.zip, lists it to reject a truncated/corrupt result, requires non-zero size, then promotes it atomically. The release workflow collects that ZIP beside the EXE, MSI, update manifest, and NuGet packages and treats a missing or empty ZIP as a publication failure. This also makes the same portable output available from a local Windows production build and yarn package if remote CI is unavailable.

Verification is deliberately recorded by subset rather than as one unrun total:

The combined Cheap-LFS, transfer, output-control, style, localization, workflow, and portable-ZIP gate passed 165/165 across 18 suites. A complete local production package has not yet run. Therefore this checkpoint does not yet claim a full-size local ZIP/installer, an exact production-build receipt, remote CI, or a published release containing the ZIP. Those receipts must be appended after they exist.

2026-07-21 Cheap-LFS 0% transport repair and manual Release handoff

The automatic Release-asset upload's 0% deadlock was traced to Electron's ClientRequest.write() contract: it returns void, while the old pump treated that value as Node backpressure, paused the source, and waited for a drain event Electron never emits. Commit c4403f2a0faf6e96fb53be3c5a9f4587f4a219c7 now advances the stream from Electron's write callback and reports accepted-byte progress. It was fast-forwarded to origin/main; CI 29853767664, CodeQL 29853768026, and Build Installers 29855717704 all passed. The exact commit is published as non-draft release v3.6.3-beta3-b0000000266 with the canonical/full x64 NuGet packages, x64 EXE, x64 MSI, and RELEASES.

The follow-up manual fallback is implementation-complete. Manual upload is available beside Cancel only during an automatic upload. It stops that attempt, plans every remaining file as one collision-safe batch, splits sources above the Release limit into ordered .partNNN assets, and creates a random upload-these-files handoff. Whole files use symlink, hardlink, then a bounded streamed-copy fallback; multipart ranges use bounded 1 MiB streamed copies. It opens the validated exact GitHub Release editor before bringing Explorer to the front, and polls for the user's drag/drop upload. GitHub Release assets are flat, but the manifest and pointers preserve every original repository-relative subfolder; duplicate basenames receive hash-suffixed asset names. Only newly created exact-name/exact-size asset IDs are accepted. Every asset is downloaded and SHA-256 verified, every source is rehashed before any pointer is written, and the original commit resumes automatically. Explicit cancel is distinct from account/repository aborts. Every multipart part counts toward the 1,000-asset bucket cap and remains in one release with its logical file.

A later live multi-gigabyte attempt exposed a separate 1%/out-of-memory failure: Electron buffers a ClientRequest body internally when chunked encoding is not enabled. The upload adapter now removes the conflicting Content-Length only at the Electron boundary and enables chunkedEncoding before the first write. The validated byte range still bounds every read and progress value, while Electron can release streamed chunks instead of retaining the complete asset in process memory. The focused transfer suite proves the flag is already active on the first write, the length header is absent, authentication/type headers survive, only one source chunk is in flight, and the exact range reaches the request. Commit e90f1765017892a857cc6d4ecad791b122c03412 is on origin/main; its CI run 29858326644 passed lint, Windows x64 tests/package, Windows arm64 package, and packaged x64 E2E.

The same repair now enforces GitHub's 1,000-asset Release capacity as a complete repository-local bucket family: assets, assets-2, assets-3, and later exact tags. All ten 100-item pages are inventoried. An automatic multipart file or complete manual batch is allocated as one group, so a group that would cross the remaining slots moves intact to the next Release and every pointer, refresh, rollback, handoff, and verification uses that selected tag. A group above 1,000 is rejected before hashing or per-file I/O. Provider objects still in the starter state count toward capacity and name collision checks but are shown as processing and cannot satisfy manual detection, upload success, download, or materialization. Exact single-release JSON remains bounded at 8 MiB so a legitimate 1,000-record response fits; list responses keep their smaller 2 MiB boundary.

Rollover acceptance covers 998 existing objects plus a two-part file staying in the base bucket, 999 plus two parts moving together to assets-2, the matching two-file manual case, exactly 1,000 objects across ten capped pages, pre-I/O 1,001 rejection, and starter-to-uploaded polling. The expanded related suite passed 165/165; after the final audit added rejected-asset cleanup and wrong-tag refresh guards, its focused transfer/operations rerun passed 34/34. TypeScript no-emit, scoped formatting, and diff validation also pass.

Local acceptance passed 104/104 focused tests across the transfer pump, cheap-LFS operations/automation/manual flow, GitHub Release parsing/API/store, asset download, and commit UI. TypeScript no-emit, scoped ESLint, scoped Prettier, and git diff --check passed. The exact low-level-MCP production build (RELEASE_CHANNEL=development, DESKTOP_SKIP_PACKAGE=1) returned client_ok: true after 840.62 seconds. The resulting app launched on the uniquely owned DesktopMaterialCheapLfsManual20260721 off-screen desktop with only a synthetic Git fixture and isolated user data. Its 960×660 client capture was nonblank, unclipped, light-themed, private-data-free, and SHA-256 4267b4e51261c170ee994b70696080207f4df1f47f13488d55f025f525e537b3. The server's generic resize/close helpers could not resolve their own headless HWND; the exact saved Electron PID was therefore terminated as the documented fallback. The window list reached zero, the desktop closed, and the validated Temp run root was removed. No public screenshot was promoted.

No live browser drag/drop was performed; direct draft/GHES editor routes, pagination, pre-existing-ID exclusion, basename collision handling, remote and source corruption, cancel cleanup, and link/copy fallbacks are deterministic unit coverage. During final verification the user's still-running visible app was read-only inspected and found to be build b0000000256, started before the repair was published. It therefore cannot contain either the b0000000266 transport correction or this follow-up manual fallback; the visible process was not closed or replaced by the verifier.

2026-07-21 — lag, hang, and resource lifecycle hardening

This milestone is implemented in the isolated codex/fix-lag-hangs-20260721 worktree. It started from c4403f2a0faf6e96fb53be3c5a9f4587f4a219c7; the primary checkout's unrelated dirty feature set remains preserved and untouched. Concurrent upstream work advanced through 41ce24d6b8, e90f176501, and 09b3a0ee89; this task is rebased onto 09b3a0ee89f520621f0db6be077f0ab70b2b4221 without overwriting it.

Proven defects and fixes

Current local evidence

2026-07-21 Screenshot renewal — 58 of 66 delivered

58 of 66 gallery screenshots were recaptured from the shipped Material UI and promoted (commits dc40ffb316 renewing 57 and bf86e6c6a3 renewing the welcome screen). Every promoted image passed the driver's per-capture privacy and dimension gate (synthetic fixture only; no home/profile/Temp/credential or user repository content) and shows the full Material Design 3 UI with Material Symbols iconography.

Getting there required reconciling the codex capture driver (.codex/verification/capture_gallery_cdp.js, committed in dc40ffb316) with the migrated UI: a vt helper injected into every renderer evaluation to read visible text with aria-hidden Material Symbol ligatures excluded; rail navigation and the functions-first API surface; and a --resilient mode that banks every scene that renders and reports any it cannot. A real product privacy fix also landed (7b319f92d8): the settings history diff no longer exposes local paths.

Not renewed this pass (existing Material-era images kept, low marginal value): material-ollama-model-manager (its scene needs a Copilot-enabled provider plus a separate Ollama server via --ollama-run-root); material-app-identity-workspace (React-fiber appearance reload times out); material-repository-logo-studio (logo-studio portal timing); material-create-pull-request and material-native-pull-request (pull-request-open deepens and removes the shallow boundary, which also cascades to the clone/pull scenes); material-pull-all-account-fallback, material-shallow-clone, material-shallow-clone-safe, and material-clone-account-fallback (clone-dialog / batch-sync state after that shallow-boundary mutation). These need targeted per-scene fixture/state work or the extra Ollama+Copilot fixture stack; they were left rather than shipping a broken or non-deterministic capture.

Earlier attempt notes retained below for provenance.

The full gallery renewal against the shipped Material UI was attempted end to end. Everything except the driver's assertions works: fresh production build (out/main.js/renderer.js at main tip 148b297f2b, 231s), deterministic fixture + loopback provider (53 runs, 31 artifacts, releases/issues/branch rules), disposable keychain credential, hidden Win32 desktop, Electron launch with CDP, and canonical capture. Five images captured cleanly at 1440×960 — material-welcome, material-workspace-changes, material-history, material-history-context-actions, material-branches-sheet — with all four Material fonts (Roboto/Roboto Mono/Roboto Serif/Material Symbols Rounded) reporting loaded and light/english state verified. A diagnostic capture of the Repositories sheet confirms the shipped UI is correct (Sync repositories, Commit & push all, Add all present and unclipped, Material Symbols rendering).

Blocker (well specified): .codex/verification/capture_gallery_cdp.js matches UI elements by raw element.textContent.trim() in ~20 spots across 85 scenes (e.g. the repositories-sheet assertion at ~line 2769). The Material Symbol migration renders glyphs as aria-hidden font ligatures, so a button's textContent is now e.g. "syncSync repositories" instead of "Sync repositories" — the driver's label match fails and the strict canonical run aborts (CAPTURE_EXIT:1) even though the UI is correct.

Fix spec: add a visible-text helper the driver can inject into its CDP evaluations — clone the node, remove [aria-hidden="true"] descendants (this excludes .material-symbol), then read textContent.trim() — and use it in place of raw textContent.trim() at the 20 label-matching sites (leave content-reading sites, e.g. diff text, on raw textContent). Then re-run the canonical, audit-design, and responsive passes and promote byte-for-byte with the privacy/dimension gate. This is best fanned out (helper + per-site edits + re-run) once subagent capacity is available. Per policy no partial gallery was promoted; the existing docs/assets/screenshots set is unchanged.

Capture teardown is complete: app and provider processes stopped, keychain credential deleted, disposable Temp run root removed. One empty headless desktop (DesktopMaterialShots20260721) could not be removed via the MCP remove_headless_desktop tool (returns a TaskGroup error); it holds no windows or processes and clears on MCP server restart.

2026-07-21 Backend handoff for Codex

Division of labor (user-directed 2026-07-21): Claude owns the frontend (app/src/ui/**, app/styles/**); Codex (GPT 5.6 Terra Ultra) owns the backend (app/src/lib/**, app/src/main-process/**). The items below were found by an adversarially-verified bug hunt over the pushed main tip (each confirmed by a 3-lens majority). They are backend and are left for Codex — not fixed by Claude.

  1. wip-title-nondraft-parse-throws (high)gitlab-merge-request-json.ts:355 with DraftTitlePrefix at gitlab-merge-request.ts:338. draftState() throws invalid-response when a title carries the legacy wip: prefix but the provider reports draft=false/work_in_progress=false. On GitLab ≥14 WIP: is ordinary title text, so a non-draft MR titled WIP: … deterministically breaks the whole MR list/dialog. Fix: trust the declared draft/work_in_progress booleans as authoritative; never throw because a legacy title prefix disagrees (drop wip: from the draft-prefix regex, or treat the prefix as non-authoritative when a boolean is present).

  2. scheduled-automation-survives-repository-switch (medium)app-store.ts:3156. runScheduledCommitPush/ runScheduledPull check selectedRepository === repository once, then await _refreshRepository (and isMergeHeadSet) and proceed without re-checking. A repo switch during that await lets an auto commit+push (or pull) run against the deselected repo — a durable remote side effect. Fix: re-validate selection after each await (and before commit/push/pull), or thread a cancellation token from AutomationScheduler.stop() into the in-flight callback.

  3. gitlab-mr-mutation-success-reported-as-canceled (low)gitlab-merge-request-store.ts:364. run() calls assertContextCurrent() after the mutation already resolved server-side; an accounts-update mid-flight makes a completed create/update report as canceled. Fix: a server-confirmed mutation should report success (or "succeeded, refresh") rather than a spurious cancel.

  4. hardlink-publish-fails-on-exfat-fat-network-share (medium)github-release-asset-download.ts:147. publishWithoutOverwrite() installs assets via fs.link and only tolerates EEXIST; exFAT/FAT/network-share targets (the cheap-LFS large-binary case) don't support hard links, so publish fails fatally. Fix: fall back to copy+rename on EXDEV/EPERM/ENOTSUP/etc.

  5. stale-guard-readopts-superseded-live-run (medium)build-run-store.ts:231. onState()'s stale guard only drops events from a superseded run once that run is terminal, so late non-terminal events from a still-live superseded run (e.g. an opencode fix running after a new run started) are re-adopted. Fix: reject events whose runId !== activeRunId regardless of the old run's phase.

  6. replace-import-duplicate-tabs-same-repository (medium)repository-tabs-store.ts:790. parseTabSession()/comparablePath() don't canonicalize paths (no .././dup-separator collapsing), so an imported session with two spellings of the same repo path creates duplicate tabs. Fix: Path.normalize before deduping.

Refuted (not real, do not action): two candidates were dropped by the verification panel. One frontend bug from the same hunt — anchored-editor-capture-escape-preempts-nested-overlays (anchored-appearance-editor.tsx:207) — is owned by Claude (frontend) and tracked separately.

2026-07-20 ultracode audit and completion wave

This section records the July 20 audit of the outstanding codex/report-gitlab-* work and the completion wave that followed. No production build, screenshot, release, or remote CI/Pages success is claimed here. Those are delivery receipts and are recorded only once the exact pushed commit and its green remote runs exist.

Branch audit outcome

Environment-blocked items left honestly pending

Two items cannot complete in this checkout because the LowLevelComputerUseMCP server and its off-screen Win32 desktop are not available here. Both remain open rather than being reported done.

Completion wave contents

This handoff records the wave's scope. Per-item build, screenshot, release, and remote-CI receipts are added only when the exact pushed commit and its green remote runs exist.

Graphical edition platform support decision

Desktop Material's Electron application is Windows-only. Windows x64 is the published installer target; Windows x64/arm64 builds, the Windows x64 full-unit lane, and Windows x64 packaged E2E are the supported graphical product gates. macOS and Linux Electron runtimes, packages, and E2E lanes are intentionally unsupported. Non-Windows runners may still host platform-neutral repository automation. On July 27 the user explicitly authorized a separate Linux-first Python/Textual TUI; its wheel, tests, and headless terminal acceptance do not change this Electron boundary.

The policy change has a tracked CI contract and a fresh combined-tree Windows gate: 592 unit files ran in three batches, with 4,161 passes, zero failures, and one intentional skip across 4,162 tests in 386.4 seconds. The 8/8 CI-policy checks, 16/16 script tests, root/script TypeScript, formatting, ESLint, feature Markdownlint, YAML parsing, and 13/13 wiki/catalog checks also pass.

The first Windows-only remote run, CI 29710664098, correctly withheld a release because the concurrently added script/generate-wiki-diagrams.js was not Prettier-clean. Pages 29710664112 passed and installer run 29710722904 skipped. The correction formats that generator without changing any generated SVG content; the repository-wide Prettier gate and a fresh generator run pass.

2026-07-20 — toolbar typography and readable Releases catalog

The repository-toolbar appearance owner now includes a complete, responsive typography surface alongside label and density controls. It supports a curated font family, 10–20 px title size, safe hex text color, bold, italic, underline, strikethrough, small caps, letter case, character spacing, text effect, and left/center/right alignment with a live toolbar preview. All new copy follows English, playful Hong Kong Cantonese, and bilingual presentation.

2026-07-20 — tab-title appearance startup/profile-switch containment

An installed 3.6.3-beta3-b0000000240 session reached the root crash boundary after the user right-clicked a tab title. The sanitized production log recorded Tab title appearance is not initialized from the tab-history lookup while an account/profile transition was rebuilding owner-scoped appearance stores.

2026-07-20 M25 — repository-bound API functions in buttons

This worktree implements the user-requested functions-first GitHub API workflow. Eligible GitHub repositories seed five safe read functions on first use: repository details, issues, pull requests, releases, and Actions workflows. They are stored through the existing profile-backed named-function registry, remain bound to the exact repository/account/provider, and run from buttons in both the API surface and Repository tools → API functions.

2026-07-20 — organization repository Git authentication routing

2026-07-20 M24 — guided sparse checkout accepted locally

This is the implementation and local-acceptance receipt for the user-directed guided sparse-checkout dialog. Final pushed-SHA CI, Pages, release, wiki, and topology checks are delivery receipts and are not claimed by this pre-publication section.

M24 promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-sparse-checkout.png 1452×1001 112,506 8ee7149da7eb045bcda347067dcf2d88c32a626829402c97a52df2d60b2a3576
docs/assets/screenshots/material-sparse-checkout-safe.png 1452×1001 125,413 d536c936e1888c5ea7712bb746ec6eac302ae204edd170ab55379455aeda6a5d

2026-07-20 M23 — complete and published

This is the live handoff for the user-directed full Ollama model manager wave. Its scope is Ollama model lifecycle management only; the separate submodule-manager and general regex-builder requests are not part of M23.

2026-07-20 M22 handoff — implementation pushed; visual refresh paused

This section is the live handoff for the current user-directed wave. Do not interpret the historical completion receipts below as proof that this wave is finished.

Outcome

The July 19 documentation pass adds a repo-wide visual-learning layer: eight reproducible labeled SVG workflow diagrams (one on every canonical wiki page) and seven generated conceptual PNG illustrations for Git, branching, conflict resolution, rebase, stash recovery, automation, and provider-account isolation. The SVG sources are regenerated by node script/generate-wiki-diagrams.js, and all wiki image references use raw main URLs so the separate GitHub Wiki can render them after publication.

The complete M0 through M21 Material and guided Git/GitHub roadmap is shipped on main; it turns audited capabilities into named, interactive app functions. The separately guarded expert GitHub API Explorer is contextualized by the selected repository and bound to its selected account and provider host. It reviews mutations and bounds and redacts responses rather than acting as an unrestricted command console.

The first four-function P0 wave is implemented, pushed, and production-UI verified at exact source SHA 9e946fd527e5843b2fdba5de675a5476b0c80445: guided history deepening, native pull-request creation, Actions artifact download/digest context, and effective branch-rules inspection. The typed operation registry is also complete. Actions workflow-run and artifact pagination then passed its exact production UI gate at 0aca4420df88a0865a0223530b956209e131431d. Attempt-aware job pagination, exact job logs/re-runs, pending deployment reviews, and fork-run approval now pass their production UI gate at 2f40d8949aaa7ae4ce5418cd949c28c643da0a37. Cryptographic artifact attestation review/result UI, Actions cache manager, bounded Pull Request Center, Release Manager, Issue Hub, and the named Git functions are all shipped as the accepted M19 parity wave.

The current Pages source, README, and in-repository wiki sources are on main. Pages deployment remains subject to the protected reviewed main promotion path; historical branch-only publication receipts below are retained as provenance rather than current status.

The July 18–19 temporary-submodule navigation and CI/release-hardening changes have completed ten-pass off-screen local acceptance. Initialized children remain temporary and return to their persisted root through the profile-customizable Back control. The final post-build child/read-only/Back regression, later fresh-bundle duplicate Open/Back race regression, and owned runtime cleanup are also complete.

2026-07-19 advanced workflow completeness (M21)

The supplied GitHub Desktop demand brief is closed item by item in the 30-item feature ledger. The wave extends the existing Desktop/store/dispatcher boundaries rather than adding a generic command console or application HTTP endpoint:

Mutation paths use typed fixed arguments rather than a shell, bind confirmation to repository/account/ref identities, re-read live state before acting, cap provider pagination and cached content, and keep credentials, raw provider responses, and disposable paths out of renderer-visible receipts. Every new surface listens to the persisted English, playful Hong Kong Cantonese, and compact bilingual mode contract with English fallback.

Integrated verification and off-screen acceptance

2026-07-19 owner-scoped appearance, large-file, and repository-management release

2026-07-19 cheap-LFS commit routing fix

2026-07-19 adaptive cheap-LFS compression (superseded for new uploads)

This intermediate implementation is retained as history. The later raw-upload changeset disables compression for every new asset while preserving reads of the compressed pointer records described below.

2026-07-19 stale repository lock recovery and CI hardening

2026-07-18 repository-page CI status

Internationalization follow-up

2026-07-18 complete inbox, Docker-over-SSH, and Releases dashboard

2026-07-18 multi-account push owner routing

2026-07-18 Build terminal OpenCode handoff and add-instead recovery

2026-07-18 direct public release creation

2026-07-18 Build & Run OSS-fleet stress test

A 21-repository open-source corpus (express, vite, fresh, ripgrep, gin, Newtonsoft.Json, flask, junit5, commons-lang, guzzle, sinatra, Alamofire, dart args, elixir plug, scalatra, aeson, zls, jq, nlohmann/json, awesome-compose, traefik) was cloned and driven through probeRepository/detectProfiles. Findings and fixes:

The sync pill also gained its missing state: diverged (ahead and behind at once) now renders the pull shape in the amber family (--dm-sync-diverged-bg/on over new --dm-amber-on-container tokens in both themes) instead of borrowing the pull tone, so the pill signals that a push will follow the offered pull. The post-shell style contract covers the new state alongside the original five.

2026-07-18 UI fixes: submodule diff, subtree access, oversized→cheap-LFS

2026-07-18 Cheap-LFS automation and Commit & push all

2026-07-18 Account, clone, and Releases fixes

2026-07-18 Cheap LFS — 2 GiB streamed uploads and auto-split larger files

2026-07-18 Clone progress — stage, %, speed, ETA, submodule phase

The clone progress experience was enriched from a bare bar into a Material readout: the git stage (Receiving objects / Resolving deltas / Checking out) with a numeric percentage, transfer speed and a derived ETA (rolling-window rate in the store), and a distinct Fetching submodules phase (indeterminate) that was previously an opaque pin near 100%. The git progress parser now captures the throughput segment it used to discard; multi-clone rows surface each repo's stage/description/percent, not just a bar.

2026-07-18 Notification automations (context-menu-only, safety-gated)

A right-click Automations… entry on any notification row (the only entry point) opens a builder for rules that fire a webhook or a local command when a matching notification arrives. Non-negotiable safety, all verified: every rule is disabled by default and its enabled flag is re-clamped to false on load, so a rule restored/synced/imported through its Git-backed store can never fire until deliberately armed in the current session; webhooks run main-process-only on an isolated session with the full SSRF guard set (manual redirects, https-only, credentials omit, bounded response, content templated into the body never the URL); commands run shell:false with every substituted argument re-validated against the argv allowlist (refused, never escaped); and a receipt loop-guard stops an automation firing on its own follow-up notification.

2026-07-18 Build & Run — fix errors with opencode

When a Build & Run stage fails, the panel now offers Fix with opencode: launch the opencode AI coding agent to diagnose and fix the errors, auto-installing it if missing, and running it in repo-scoped auto-approve ("yolo") mode.

2026-07-18 GitHub API Explorer — functions-first

The Explorer was reorganized from a browse-first catalog into a functions-first surface (presentation only — no execution, review, redaction, scoping, or persistence machinery changed):

2026-07-18 Release-backed "cheap LFS"

A new Large files & storage tools-hub category hosts a cheap-LFS panel: instead of real Git LFS, a chosen large file is uploaded to a GitHub Release asset and a small text pointer file is committed in its place; materialize downloads the asset and restores the real bytes.

2026-07-18 Repository Tools catalog reorganization

The tools hub's taxonomy was rebuilt for scanability: seven plain-language categories ordered by everyday frequency — Status & branches, Search & inspect, Commits & history, Nested repositories (gated, submodules + subtrees), Cleanup & maintenance, Share & transfer, Repair & recovery — with entries alphabetical within each (enforced by a shared comparator, rule documented on HubCategoryOrder). All 24 entry ids and titles are unchanged; ~15 vague descriptions were rewritten as one-line "what you'd use this for" sentences. Category headers gained one-line subtitles, filter chips derive from the categories actually present, and a latent invalid-HTML-id bug in the detail-pane header was fixed with a slugifier. Contract, responsive, and RTL suites extended additively.

2026-07-18 Git subtree manager

A full subtree vertical slice mirroring the submodule manager (the bundled dugite git 2.53 ships contrib git-subtree, verified by a memoized capability probe that still gates the UI defensively):

2026-07-18 Submodule config manager

Every submodule row in the Submodule Manager (and the Repository Settings Submodules tab) gained a Configure action opening a per-submodule config dialog:

2026-07-18 In-app log viewer, verbose logging, Git-backed log history

Logging is now a first-class, inspectable surface:

2026-07-18 Regex builder on every filter bar

Every persistent search/filter surface in the app now carries the shared FilterModeControl cluster (fuzzy/substring/regex mode cycle, match-case toggle, and the regex-builder launcher) with its mode persisted per surface. The wave covered the 23 surfaces that lacked it: the three SectionFilterList consumers that only needed a filterListId (worktrees, account picker, Copilot model picker); the five Actions surfaces (runs filter, workflow manager, workflow catalog, cache manager, and the find-in-job-log search with mode-aware match navigation); the six shell/tab surfaces (command palette, Material context-menu filter, tab search, arrange tabs, close-tabs-containing — its inverse "keep" variant deliberately stays a documented literal substring for destructive-action safety — and the tab-style-editor font search); the five repository surfaces (in-diff search with mode-aware occurrence navigation, submodule manager, gitignore templates, tools catalog, provider triage); and the four GitHub views (issues search, REST + GraphQL API-explorer catalogs, notification centre). Bespoke one-off regex toggles were replaced by the shared control everywhere they existed. All FilterModeControl and regex-builder buttons now declare type="button" so dialog-form hosts (the command palette) cannot implicitly submit. A completeness sweep confirmed no remaining filter bar lacks the affordance; compact popovers hide the launcher label via their own SCSS while keeping the aria-label.

2026-07-17 Docker builds, sync-pill vibes, auto-build-on-pull, and list typography

The three urgent goals previously recorded at the top of this handoff are implemented on claude/handoff-md-implementation-3b529c:

A three-dimension adversarial review (correctness, security/invariants, and UI/style consistency, with every finding independently re-verified against the code) confirmed nine defects, all fixed before commit: the stale-preference equality hash, agent-surface auto-build exposure, the light-theme accent freeze of :root-declared aliases, the 32px-size versus 29px-row mismatch, publish description contrast, the force-push badge color mismatch, the misleading typography preview baseline, the stale post-pull tip read after a mid-pull repository refresh, and docker suppressing make.

Local verification in this checkout: 105 focused tests across the build-run, appearance, and style-contract suites pass, including 11 Docker detection cases, 9 auto-build decision cases, the new typography validation cases, and a new sync-pill style contract; repository-wide tsc --noEmit introduces zero new errors against the pre-change baseline; changed-file Prettier and repository-rule ESLint are clean. The loader, list-row, and Git-config round-trip suites were extended for the new appearance payload but cannot execute in this checkout because it lacks the dugite/@testing-library dependencies; they run in CI. No production build or headless UI gate was run for this wave.

A parallel implementation of the same three goals on claude/ui-clipping-material-design-g5g3n9 was superseded by this reviewed wave when the branches were merged to main; that branch's distinct clipping/token/accessibility polish pass (next section) was kept in full.

2026-07-17 clipping, Material-token, and accessibility polish pass

A dedicated audit swept all 219 stylesheets and the Material shell components for text clipping, pre-Material styling leftovers, and keyboard accessibility. Dialogs now use the MD3 extra-large radius and level-3 elevation instead of the legacy 6px Primer card; the title bar, window controls, CI status popover, avatar stack, tab bar, tooltips, toast/repository kbd chips, and commit drag badge all route through --md-sys-*/--dm-* tokens (with a new --dm-on-green on-color for dark-mode contrast). Fixed pixel heights on app-bar chips, repository tabs, menu rows, dialog headers, and buttons became min-heights so larger user-selected interface fonts grow controls instead of clipping, the CI check-run description lost its hard 250×12px clip box, and the branch list description gained the ellipsis treatment. Keyboard users can now see the tab close button on focus, the tab rename input has an accessible name and focus ring, the tab-strip search fields have focus-within indicators, split-button dropdown options highlight tonally on focus-visible, and notification unread state is exposed to screen readers rather than being color-only. Validated with a full Sass compile, TypeScript, ESLint (custom rules), Prettier, all 31 style-contract suites (110 tests), and the affected component suites (258 tests), all passing.

2026-07-17 Build & Run auto-build hardening

The one-click Build & Run auto-build now works across every detected ecosystem, on every supported host, including complex builds whose dependencies must be installed automatically:

The runner threads install commands into the auto-fix planner and executes multi-command remediations sequentially with the existing cancellation checks; the Repository settings auto-install copy and the plan/type docs now describe the cross-platform behaviour. Focused verification in this environment: the rewritten auto-fix/toolchain-install suites plus the existing detect/gitignore suites pass (128 tests), the IPC-contract, toolbar-overflow-layout, and post-shell style suites pass (32 tests), and repository-wide tsc --noEmit --skipLibCheck, changed-file ESLint with the repository rule directory, and Prettier are clean. No production UI gate was run in this Linux container.

2026-07-17 recovery, custom logos, app functions, and responsive completion

Clone account changes now invalidate stale provider selections and reload the new account before a repository can be chosen. Automatic clone work is owned by an app-lifetime background store instead of a blocking dialog. Its versioned journal preserves queued, running, paused, interrupted, failed, and review-required items across renderer or process restarts, with explicit pause/resume/retry/dismiss controls. Clone recovery rejects credential-bearing URLs, unsafe canonical paths, origin mismatches, non-owned worktrees, symlink escapes, and time-of-check/time-of-use path changes; displayed failures redact credential material. Recovery finalizes only repositories which were actually added to the app: a temporarily unavailable completed clone remains journaled, visibly needs attention, exposes Retry adding repositories, and cannot emit or suppress its completion summary prematurely.

Repository appearance now includes a code-native vector logo studio rather than another set of dropdowns. Profiles can define a default and individual repositories can inherit or override it. The bounded model supports presets, text and mark layers, transforms, colors, live preview, undo/redo, and guarded JSON import/export without accepting raw SVG. The selected logo propagates to the repository list and open tabs through the shared bounded loader.

The API surface now exposes saved, versioned app functions with stable names, exact repository/provider/account bindings, reviewed mutation behavior, bounded redacted output, SHA-256 fingerprints, and the same catalog through the app, local Agent API, MCP, and REST adapters. Malformed persisted state fails closed and never stores credentials. The GitHub API Explorer can create, inspect, execute, update, reload, and remove these functions.

The final review also replaced three regex-based GraphQL token strippers with one shared lexical scanner. Comments are recognized only outside strings, ordinary escapes and escaped triple quotes in block strings remain contained, and malformed strings fail closed. Exact lexical-decoy regressions prove that a retained mutation cannot be classified or invoked as a noninteractive read.

The responsive smoke catalog accounts for every registered repository page, preferences page, repository-settings page, clone and notification tab, File History surface, and safely orchestrated dialog/menu surface. All 76 applicable rows passed all eight viewport/zoom scenarios; the three unavailable fixture integrations are explicit N/A rows, with zero failures, blockers, missing rows, document-width overflows, unreachable scroll bottoms, or unnamed buttons. The scenarios include the 320×240 CSS viewport produced by 200% zoom as well as short, portrait, standard, and wide layouts. The complete 79-row evidence is in docs/verification/responsive-surface-matrix-2026-07-17.json (SHA-256 108c4c444feda61bb890d341cc83fb5bc27c008695fe9f384114d6499ed9532b).

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-repository-logo-studio.png 960×660 110,716 791c67e611a87c9e7e716616c1031c3bf696cd8acdb7f98aa1fbdffb36858777
docs/assets/screenshots/material-api-app-functions.png 944×1000 126,774 10d635a3e884902d4e791258e9cb470c83be0b268aa4e88aaab537601bb6a3f5

The exact required unpackaged production build completed through the fixed MCP endpoint in 365.14 seconds under concurrent verification load, without a timeout or dependency download. Full TypeScript, repository-aware ESLint over 77 changed source files, Prettier over 113 supported files, and diff-integrity checks passed. The final sequential unit run covered 457 files in two batches: 3,139 tests across 863 suites, with 3,138 passing, zero failures, and one intentional skip. The focused script harness also passed all 15 tests; the post-review clone/API audit passed all 59 tests.

The first remote CI attempt (29571690398) then caught two existing account-binding tests whose clone destination was hard-coded as a Windows path; the strengthened absolute-path contract correctly rejected that fixture on macOS. The tests now derive the same parent/name destination with the host platform's path.resolve instead of weakening production validation. The account-binding, batch model/journal/recovery, and auto-clone retest passed all 48 tests locally before the corrective push.

The hidden run used only DesktopMaterialP0_20260717_0139, saved app PID 8700, provider PIDs 14392/6460, provider port 61130, and CDP port 61241. The generic alternate-desktop close route failed closed, after which the exact revalidated app PID was terminated gracefully. The disposable credential was deleted and read back absent; all recorded PIDs and both ports reached zero; the named desktop closed exactly once; and the containment-checked owned Temp root was removed and verified absent.

Publication checkpoint

2026-07-16 navigation, context actions, and scroll containment

Repository tabs now have a runtime search/switcher across labels, aliases, paths, and clone URLs. Arrange Tabs has its own literal multi-key filter while one-shot sorts continue to apply to all open tabs. The repositories side sheet adds independent exact-account and provider-service scopes, including explicit local-only, unavailable-account, and unknown/signed-out states.

Every button receives a discoverable shared hover and keyboard-focus hint. History commit rows own their specialized context path: right-click, Context Menu, Shift+F10, and the named More button all build the same action set from the effective selection, so an unselected clicked row cannot accidentally act on an unrelated multi-selection.

Repository Tools now wins the real compiled Material-card cascade with an owned vertical scroll region. The production gate reached its exact bottom at regular, 640×480, 960×420, and 150% zoom layouts with the final named control inside both the surface and viewport.

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-tab-search.png 1000×687 91,055 1a18b970c9aaffe4716be61cbbc84afa34cad6395a9e2e35bdfe48472396abc5
docs/assets/screenshots/material-history-context-actions.png 1000×687 92,197 c5c2b722a4c79979ce3973ed8ce921fb1eac661caa1c03ace2317d4f81ef0ec0
docs/assets/screenshots/material-repository-tools-scroll.png 960×420 29,840 d39dad61015ca333fbb95d388a8d75d7484a662d85f068e99a4b5fefa80f8b45

The exact hidden-desktop verifier and safety/build/geometry receipts live in .codex/run-manifests/2026-07-16-navigation-context-scroll.md. The app process, desktop, CDP listener, and disposable fixture were removed after promotion.

The July 16 adaptive customization maintenance release also passed its exact production build and off-screen interaction gate at tested code source c5205838dfc5ee2b7ce80ce488215a2cd903bb26. It adds profile/repository/tab appearance, measured app-bar overflow, pure Material entry surfaces, guarded tab close/arrangement, workflow-run cancellation, reviewed rebase, repository-account propagation, bounded OAuth scopes, and compact-surface corrections. Its detailed acceptance receipt and seven inspected captures are recorded below.

The final feature-completeness audit closes every current roadmap maintenance item. Detailed Pull All progress passed its production/headless/a11y gate at 1bc8a226de; exact shipped commit 36197bf6dd then passed CI run 29490902486 and installer run 29490902407. Pages run 29489043545 deployed the then-current 51-image gallery, and the public seven-page wiki carries the same inspected release documentation. A final focused checkout pass added 37/37 green registration, Pull All, checkbox, compact-style, and Pages-gallery tests to those repository-wide and off-screen receipts.

2026-07-16 notification triage and error notices

The notification centre now supports explicit Local/GitHub sources, text search, source-appropriate filters, select-all-visible, and bounded bulk triage. Local rows can be marked read or unread and deleted together in one history-backed mutation; GitHub rows can be marked read or done only within the loaded account/filter context. The former trash-only affordance is now an explicit Clear all action with a visible non-modal confirmation and a notification-history recovery explanation.

Generic errors that previously opened a blocking acknowledgement-only dialog now appear as bounded, dismissible red notices in the bottom-right corner by default. Preferences → Notifications → Application errors can restore the legacy blocking-dialog style. Authentication, retry, file-size, Copilot, and other flows that require a decision or remediation remain dialogs regardless of that preference. Safe error summaries continue to be written to the local notification history independently of the transient notice stack.

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-error-notice.png 1000×687 101,359 953467ac7846bf01ec3090b01b15938c35e7be2ee73bd0638e1df3bfeaf3fe0b
docs/assets/screenshots/material-notification-bulk-actions.png 1029×600 101,445 b3ca2875c1080733e832df49bc0680e7711ad650809c33149382f96fe8cf7c32

Focused notification, error-routing, preference, profile-history, responsive-style, and React interaction coverage first passed 68/68 tests across 21 suites. The final combined source, Pages, and 58-item wiki-gallery gate passed 84/84 tests across 24 suites. Full TypeScript, repository-aware ESLint, targeted Prettier, diff integrity, and the exact unpackaged production build also passed; the final MCP build emitted every webpack target in 131.72 seconds without a timeout or dependency download.

The accepted app-native geometry had equal document/body client and scroll widths. The normal error notice stayed fixed entirely inside a 1000×687 CSS viewport with no card overflow. In the short-height notification gate, the panel stayed inside a 1029×600 CSS viewport; its source surface measured 374/374 pixels client/scroll width and 473/486 pixels client/scroll height with overflow-y:auto. Exactly three filtered rows were selected, all named bulk controls were reachable, and the Clear-all recovery confirmation remained visible. Both promoted PNGs were reopened at original resolution and contain only the deterministic git-source fixture and synthetic error copy.

The fixed low-level MCP ran only on the uniquely named off-screen desktop. The final saved launch PID 12760, runtime HWND 7406868, and CDP port 57931 were revalidated. The alternate-desktop generic close path failed closed, so only the exact owned Electron process set was terminated; the listener reached zero, the desktop listed zero windows and closed, and the containment-checked Temp root was removed. A stale post-interaction HWND frame was rejected because its hash matched the pre-interaction frame; only current app-native pixels were promoted.

Publication checkpoint

2026-07-16 GitHub API Explorer release

The repository rail now includes a GitHub API Explorer contextualized by the exact selected repository and bound to its selected saved account and provider host. Its complete searchable catalog contains all 1,206 current REST operations and identifies exactly 10 operations added since the prior pinned 2026-03-10 catalog. The request builder supports REST and GraphQL, requires exact-request review before a mutation can run, and keeps displayed response headers and bodies bounded and credential-redacted.

The accepted evidence uses the deterministic synthetic material-fixture-owner/material-fixture repository and provider identity. The catalog's New operations scope shows 10 of 10 operations; the selected repository custom-pattern read completed with a synthetic 200 response. No personal account, credential, or private repository identifier appears in the capture.

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-github-api-explorer.png 944×1000 129,807 0115fb552e5212d7d326eb36197e4499f03dd99707b0ebb18c5c3fddf6082228

README, Pages, User Guide, and Feature Gallery sources now reference this evidence. The machine-checked guided gallery therefore contains 56 distinct named functions or states, each backed by one distinct tracked PNG.

The exact unpackaged production build passed twice through the off-screen MCP runner; the final rebuilt-source run exited 0 without a timeout in 126.5 seconds. The accepted app-native client was 944×1000 physical pixels (983×1041 CSS pixels at DPR 0.9599999785), with equal document/body client and scroll widths and no element outside the horizontal viewport. The verifier confirmed 10 rows and 10 New badges, the expanded synthetic repository path, the 200 response, and both deterministic custom-pattern names. The disposable credential was deleted and read back absent; the saved Electron and provider PIDs, their two loopback ports, the uniquely named desktop, and the containment-checked fixture root were all confirmed gone after capture.

2026-07-16 function screenshot catalog

The wiki now treats the Guided Feature Gallery as a machine-checked visual catalog: 56 named, user-facing workflows or states each own one distinct PNG. Core History browsing, local Agent access, and the repository-contextual GitHub API Explorer are included in the manifest and its rendered image body. Eight unused legacy captures with obsolete or clipped UI were removed, leaving no tracked PNG unassigned and no screenshot reused for a second catalog row. Home, User Guide, and Developer Guide link or describe the same canonical catalog, and a focused unit contract rejects missing, duplicate, unrendered, or unassigned assets.

The exact MCP endpoint and scheduled task passed preflight against low-level checkout 806d9ba85e4afbc2af58d7499496babfa7c68891. The service PATH no longer contained a global Yarn command, so the first build stopped before compilation. A temporary owned shim then invoked the already-cached Yarn Classic package in offline mode; the required npx --no-install cross-env RELEASE_CHANNEL=development DESKTOP_SKIP_PACKAGE=1 yarn build:prod command completed with code 0, no timeout, and no dependency download.

The compact visual check used only hidden desktop DesktopMaterialFunctionCatalog2026071601 (creation handle 972), launch PID 7624, runtime HWND 4392554, CDP port 9347, and the synthetic material-fixture@example.invalid identity. The first 960×660 MCP frame was clean and the Configure Git renderer measured 1000/1000 document and body widths with seven named controls and no horizontal clipping. Native hidden-HWND resize was unavailable. A later post-CDP PrintWindow frame retained stale compositor regions, so it was rejected and no replacement image was promoted; the catalog uses only previously inspected current assets. The exact PID, listener, hidden desktop, disposable fixture/profile/captures, and owned Temp root were all verified absent after cleanup. The unrelated OAuth manifest and detached foreign worktree remained untouched.

2026-07-16 clone-style Add Submodule release

Repository settings → Submodules → Add submodule… now opens a dedicated Material popup with the same GitHub.com, GitHub Enterprise, URL, and GitLab & Bitbucket source model as Clone. Hosted tabs preserve exact-account affinity and repository browsing; URL mode accepts validated HTTPS, SSH, and local Git sources. The review binds the source to a safe repository-relative checkout path plus an optional tracked branch before Git starts.

The Git boundary revalidates duplicate and occupied destinations against the live superproject immediately before spawn, forwards the selected credential account only to the remote operation, reports bounded clone progress, and owns an abort signal plus exact process callback. While Git runs, inputs freeze but Cancel operation remains active; success refreshes the underlying managed submodule list.

Verification is green: 53 focused model/UI/Git/popup/style/Pages tests, TypeScript, changed-file ESLint and Prettier, the complete 1,190-test suite, and the exact unpackaged production build. The build and UI gate ran through low-level MCP checkout 806d9ba85e4afbc2af58d7499496babfa7c68891 on the single hidden desktop DesktopMaterialAddSubmodule2026071601. The visible desktop was never shown, focused, resized, or used for input.

Chromium accepted the initial HWND-targeted onboarding click but its next PrintWindow frame became a stale black compositor surface, so the isolated loopback CDP endpoint was used for renderer interaction and capture. At the app's minimum logical 1000×688 renderer, the popup measured (129,59) to (919,677), document/body widths were 1000=1000, the internal scroll region was 790=790, every required control was named and keyboard-reachable, and the review retained the synthetic source/path/branch. Native off-screen resize was unavailable; a requested 700×650 CDP emulation was clamped to the app's supported logical minimum/auto-fit behavior and is recorded as a limitation, not as a native-size claim.

The accepted 1500×1032 screenshot is docs/assets/screenshots/add-submodule-dialog.png (109,198 bytes, SHA-256 9ebfe5d94f7f624736c6fada706ee15279754102735d01d63d201b322ad10834). It contains only the synthetic superproject and .invalid URL. README, Pages, Home, User Guide, and Feature Gallery sources reference it, bringing the guided gallery to 52 inspected images. The exact launch PID 13704, its windows, CDP listener 59317, hidden desktop, ephemeral tooling, profile, fixture, and owned Temp root were revalidated and removed; the desktop reached zero windows before closing.

The assembled Pages source also passed the isolated browser gate at desktop 960×660 and mobile 390×844 viewports: all 54 image instances loaded, all 53 gallery cards rendered, document/body widths matched their scroll widths, and no control or content crossed the viewport. Its exact HTTP/browser PIDs, loopback ports, profile, hidden desktop, and containment-checked Temp root were then removed and verified absent.

2026-07-13 P0 production UI gate

The exact unpackaged production build passed with:

npx --no-install cross-env RELEASE_CHANNEL=development DESKTOP_SKIP_PACKAGE=1 yarn build:prod

The build took 108.72 seconds. It ran at 9e946fd527 through the exact low-level MCP checkout 806d9ba85e4afbc2af58d7499496babfa7c68891 on one off-screen Win32 desktop. The visible user desktop was never shown, focused, or used for input. A loopback-only synthetic provider, disposable profile, true shallow Git fixture, and reserved .invalid repository identity kept all mutations and credentials out of public GitHub and the normal Desktop profile.

Functional receipts

Responsive, focus, and clipping receipts

Win32 background input and the native Save dialog were exercised through the low-level server. Chromium ignored background-posted clicks and PrintWindow occasionally returned stale/black compositor pixels, so the allowlisted app-native CDP fallback drove renderer controls and captured the stable original surface. Every promoted candidate was reopened at original resolution.

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-history-deepening.png 944×660 70,047 a03f313b604ade9eb4458aaccffe2807c7580e53651215d52b75d9ddbfc181e2
docs/assets/screenshots/material-create-pull-request.png 944×660 76,575 93c8ec71c65e73414419d46214dd5849a128908e7336b08786ab677cd9f48022
docs/assets/screenshots/material-actions-artifacts.png 944×1000 106,252 326a27a927fa668444487f0dff3ef71c8b81eaf53e5d300b554d07a62541ae42
docs/assets/screenshots/material-effective-branch-rules.png 944×1000 107,573 7a4533aa0e9b40644ac2fb55ceb3fe0788ccb502137e370fd1762925a685bfd6

The two 944×1000 captures intentionally preserve tall original viewports of the dense Actions and Branch Rules states, including their visible internal scroll positions. They are original screenshots, not stitched or resized images.

2026-07-14 post-merge production launch

The post-merge source at b6e78eecf3638fcdb1a81d27e7275c84e641a5f6 was rebuilt with the exact unpackaged production command and launched on one uniquely named off-screen Win32 desktop. The disposable HTTPS fixture and isolated profile were removed after capture. Chromium ignored the permitted background-posted welcome events, so this receipt intentionally records the stable launch surface rather than claiming a deeper renderer state that was not exercised.

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-post-merge-welcome.png 960×660 150,763 c0e5cd5e56fe0cc839446256a8439789229627bc932b91421b418377fcf68d5a

Provenance note (2026-07-17): this capture was later retired in the "one screenshot per visual function" catalog dedup and is no longer tracked or referenced. The row is retained as a historical receipt; the byte length and SHA-256 describe the file as it existed at this checkpoint.

The Pages publish layout was also assembled exactly under the owned run root. All 21 images loaded with nonzero natural dimensions. At 944×660 the document width was 929 with matching scroll/client widths and zero visible overflows. At 390×844 mobile emulation the document width was 375 with matching widths; the four P0 cards collapsed into one 259-pixel-wide column with wrapped captions. Desktop, P0-gallery, and mobile-P0 captures were visually inspected before cleanup. All 33 formerly parent-relative screenshot URLs in the Pages source were corrected to publish-root-relative paths.

Cleanup completed: the exact disposable development-channel credential was deleted and read back absent; the app, provider, CDP endpoint, provider port, and off-screen desktop were gone; and the containment-checked owned Temp root was removed. No normal Desktop profile or public provider state was changed.

Publication checkpoint

2026-07-13 Actions pagination production UI gate

The exact unpackaged production build at 0aca4420df88a0865a0223530b956209e131431d passed on the isolated desktop DesktopMaterialActions-20260713-29de6ec7. The build used the same exact production command and completed in 112.3 seconds.

Pagination and responsive receipts

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-actions-pagination.png 960×660 95,213 3250eaee8b6fc69b06dceb6439f04ee45e68351229ac87db003d04c27c4dd7a2
docs/assets/screenshots/material-actions-artifact-page-two.png 960×660 83,960 5310197657763fc1269639d5b3c8c3998393ae36e6077e71e274877e51dbdb8b

The Pages layout was also assembled under the owned run root with all 33 tracked PNGs. Its 23 referenced images and 22 gallery cards loaded at nonzero natural dimensions. At 960×660 and 390×844, document/body widths matched the viewport and measured overflow/outside arrays were empty; original desktop and mobile captures showed both new cards and wrapped captions.

Publication and cleanup receipt

See .codex/run-manifests/2026-07-13-actions-pagination-ui-gate.md for the complete fixture, request, interaction, geometry, publication, and cleanup record.

Legacy M0-M18 milestone summary

Milestone Status Shipped result
M0 COMPLETE CI, Pages, Windows installer/release workflow, README, wiki sources, and screenshot pipeline.
M1 COMPLETE Token-safe per-account settings repositories with serialized Git history and recovery.
M2 COMPLETE Persistent browser-style repository tabs with range/regex close controls and rich per-tab styling.
M3 COMPLETE Reusable Git-backed settings history, diffs, undo/redo, and restore-to-point.
M4 COMPLETE Draggable non-modal dialogs and Material side sheets that preserve background interaction.
M5 COMPLETE Notification centre with unread controls, Git-backed event log, and notification history.
M6 COMPLETE Shared fuzzy/substring/regex search modes, filters, and full regex builder.
M7 COMPLETE Parallel/sequential multi-clone, URL-only repository export/import, and secure exact-origin clone account fallback with persisted affinity.
M8 COMPLETE 50–200% UI scaling, auto-fit, and full GitHub organization repository browsing.
M9 COMPLETE One-click commit/push, schedulers, safe auto-pull, and merge-all branches/worktrees.
M10 COMPLETE GitHub Actions runs, reruns, workflow dispatch, job detail, and searchable logs.
M11 COMPLETE Secure localhost MCP/REST agent server, renderer bridge, stdio proxy, CLI, and Preferences UI.
M12 COMPLETE Desktop Plus quick-win parity: telemetry off, status/sort controls, Material actions, identity, permanent discard, hide-recent, and accessibility tooltips.
M13 COMPLETE Repository metadata/defaults, pinning/grouping, branch pills, bounded Pull All with exact-origin account fallback, remotes, and submodules.
M14 COMPLETE History metadata/regex search, commit graph, guarded deletion, SVG preview, and branch presets.
M15 COMPLETE Multiple stashes per branch and the rebranded Desktop Material CLI.
M16 COMPLETE Tab-aware multi-window lifecycle, routing, scoping, and serialized profile mutation.
M17 COMPLETE GitLab/Bitbucket providers, self-hosted GitLab PAT flow, clone browsing, and cross-host PR/status routing.
M18 COMPLETE Full Material shell and final post-shell polish, including layout, clipping, and accessibility regression coverage.

Additional shipped work includes the .gitignore manager, Build & Run with toolchain/project handling, multi-remote and submodule managers, fork-owned updating, and the merge-wave integration fixes listed in Git history.

Build & Run detection gate

Build & Run now walks bounded nested project roots and presents the project folder beside every profile name. The detector covers Node package-manager metadata (including modern bun.lock and packageManager), Deno, Rust, Go, .NET, Python entrypoints and packaging files, Java/Kotlin build files, PHP, Ruby, Swift packages, Dart/Flutter, Elixir/Phoenix, Scala/SBT, Haskell, Zig, Make, and CMake. Settings and the toolbar use the same stable <profile> — <project folder> display name; long labels wrap in settings and ellipsize only in the compact toolbar/panel header.

Focused evidence for this gate is in app/test/unit/lib/build-run/detect-test.ts and app/test/unit/post-shell-style-test.ts. The exact production webpack bundles compile, but this checkout still lacks the packaged Electron runtime and the native printenvz package binary, so an interactive Electron headless capture cannot be claimed until those dependencies are restored.

Merged implementation ledger

These are the first paths to inspect when maintaining each subsystem:

Prior integrated validation evidence

The exhaustive run on the earlier application/test tree shipped by b2699faccb07728fe9aa2838aa13355d71e172b0 recorded:

Secure clone account fallback validation

Screenshot Bytes SHA-256
docs/assets/screenshots/material-agent-access.png 110,128 644891eaa37c878cb577065822681ee8fd33a018a92e0b89822b43e67393ef93
docs/assets/screenshots/material-automation.png 87,304 efe45408a390301294d5e23193b619eec858fcef4abb147d82709513c5bb3843
docs/assets/screenshots/material-branch-merge-all.png 116,134 c5cb41e17d67c627758ef43620c255c8272f85ed182a741c086a80d735c8719e
docs/assets/screenshots/material-history-power-tools.png 122,930 fe8b6323d77663467b2a6ae887d5e277e31b8dc84f0e35cec2332537ec7fd28a
docs/assets/screenshots/material-multi-window-menu.png 115,719 9a6cbcbb4c257eac3312b76f8ed0077a6a123901a6bee9b7793b926a61310c66
docs/assets/screenshots/material-notification-center.png 111,723 f8d0cf33723b1c9793d165ab39fd0cec2ccd41b50136d36f6be9c3d34b7d4709
docs/assets/screenshots/material-provider-accounts.png 117,558 91ab46ec566676f0c87534f5e72795e31a62adeecf6bf2597e533920ff428cff
docs/assets/screenshots/material-workspace-changes.png 123,162 3155b321f9aabb73ee6a40000c69f8931f1915920216818a362ec974cc3a4621

Earlier verified captures, including docs/assets/screenshots/settings-history-manager.png, remain tracked; that M3 image is also 1443×992 and has SHA-256 abbcc34aa02949d2144f008c9ed10b4414f721843890643d65d8e0b9360c3da1.

2026-07-13 guided Git and GitHub evidence

A subsequent exact off-screen run verified three named, task-specific app functions at 1000×687. The app presents focused controls and state for these tasks; it does not expose a searchable list of raw Git/gh commands or API endpoints.

Screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-github-notifications.png 1000×687 81,465 53f40a94a6ead19b73c6c3302d0eb60b0effd050c7b018b43dd76d4b2072a354
docs/assets/screenshots/material-sparse-checkout.png (historical M19 version) 1000×687 60,070 49a7182f5fd9eb7e0a86d6c20a1ed5b5f388b9063c87d033bfef63d42b7b37e7
docs/assets/screenshots/material-shallow-clone.png 1000×687 67,271 337e7a967b538de22bdd560ff9393ff35619fd1ea76e6ff8aea7827793befd59

Each promoted PNG was reopened at original resolution and matched the source capture's SHA-256. No bundle-import or issue-creation screenshot is included in this evidence set. Task forms follow a no-page-level-sideways-scroll policy: labels wrap and action groups stack when practical, while horizontal scrolling is reserved for spatial code, diff, or log content.

The M19 table is a historical receipt. M24 later replaced the tracked material-sparse-checkout.png with the 1452×1001, 112,506-byte guided Choose capture whose SHA-256 is 8ee7149da7eb045bcda347067dcf2d88c32a626829402c97a52df2d60b2a3576.

Headless verification environment

The safety contract is mandatory:

  1. Write a run manifest and record the initial dirty-state baseline.
  2. Preflight the scheduled MCP task and exact MCP source SHA.
  3. Build without downloading dependencies.
  4. Create one uniquely named off-screen desktop and one owned Temp run root.
  5. Launch the absolute Electron binary with isolated --user-data-dir and disposable --cli-open; save the returned PID and discover the live HWND.
  6. Use only HWND-bound background input and client_only screenshots. Never call show_headless_desktop, focus a normal window, or send global input.
  7. Treat rendered_ok as transport success only; inspect pixels at original resolution for blank frames, theme, clipping, private data, and dimensions.
  8. Revalidate HWND/PID before close; use exact saved-PID termination only as a fallback; close the desktop exactly once; delete only the owned Temp root.

The proof cleanup completed after screenshot promotion. The exact saved app process was terminated only after its background close request was ignored; the fixture then stopped through its owned stop marker, both loopback listeners were absent, the hidden desktop listed zero remaining windows and was closed exactly once, and both synthetic credential entries were verified absent. The owned path alias, safe working root, and Temp run root were each resolved to their recorded exact target before removal and are all verified absent. All completed agent worktrees were subsequently verified clean and merged before removal; local main was synchronized with origin/main.

M19 final publication and repository evidence

The complete function-first parity roadmap is now shipped: the P0 four-function slice, typed operation boundary, Actions run/artifact pagination, attempt/job/log/re-run, deployment review, fork approval, cryptographic artifact attestation review/result UI, Actions cache management, bounded PR/Release and Issue waves, and the named Git functions are all accepted. The complete M19 ledger remains the source of truth for that acceptance.

2026-07-13 Actions run inspector production UI gate

The exact unpackaged production build at 2f40d8949aaa7ae4ce5418cd949c28c643da0a37 passed on the isolated off-screen desktop. The build used the required no-download production command and completed in 115 seconds. The visible user desktop was never shown, focused, resized, or used for input.

This roadmap slice exists as named app functions rather than a command or API catalogue. The run detail pane selects the latest or a historical attempt, loads strict 50-job pages, retains page one through a later-page retry, and sends an exact loaded job to the bounded log transfer or re-run mutation. Run-level pending deployments and review history load independently; selected approvable environments use a dedicated required 1–1024-character decision dialog, while an eligible first-time fork run has a separate confirmation.

Every new API/store surface stays on the repository-selected same-endpoint account. Current jobs use the fixed latest-attempt path, historical jobs use the fixed attempt path, deployment reviews send only normalized environment ids/state/comment, and fork approval is bodyless. Same-run attempt changes abort and generation-guard stale jobs; repository/account/run changes also cancel child work. Artifacts are now correctly labelled as run-level outputs across all attempts.

Focused implementation evidence is green: TypeScript --noEmit, targeted ESLint with the repository rule directory, responsive style contracts, and 124/124 Actions checks across 22 suites. Those checks cover strict bounded parsing (including single-byte response streams), fixed paths and bodies, permission-aware bounded errors, exact-account routing, current→historical stale-request cancellation, latest-attempt page revalidation, shortened-page stopping, 50→51 retained retry, exact recovered-job log/re-run targeting, 101-attempt bounded navigation, locked deployment selection, required bounded comments, approval submission, separate fork confirmation, consuming modal scrims, and contained/restored focus.

The deterministic provider checkpoint is also green. Eleven provider tests plus the live probe cover inspector run 84152 at attempt 2, 51 current and 51 historical jobs, current sentinel 85101, historical sentinel 85050, a one-time current page-two 503, exact bodyless re-run/fork mutations, exact bounded deployment-review bodies, redirected log content without credentials, two eligibility-distinct environments, stateful history, unchanged artifact integrity, and blocked Git receive-pack.

Interaction, request, and responsive receipts

Promoted screenshot Dimensions Bytes SHA-256
docs/assets/screenshots/material-actions-jobs-pagination.png 960×660 111,675 0e61eb4e66c20bffbeac76c79eebb9508d44160cb104feb8fc47f2617dc94b90
docs/assets/screenshots/material-actions-pending-deployments.png 944×808 98,249 6eea1333755d5edad469c8d0d06b8a3d62e43c991e6bc9de5e98080dee75c1bc

Both promoted PNGs were reopened at original resolution after copying and matched their accepted run captures. README, in-repository wiki, and Pages sources now reference them. The assembled local Pages layout loaded 25 nonzero images across 24 gallery cards. At 960×660, document/body client and scroll widths were all 945; at 390×844 they were all 375. Overflow and outside-control arrays were empty, and original desktop/mobile captures showed the two new cards with wrapped captions and no sideways scrolling.

Publication and cleanup receipt

2026-07-14 Actions cache and screenshot refresh

The Actions provenance/result UI and cache-manager slice is complete at exact source SHA e282eb2fce on main. The cache manager now starts after the repository's selected-account subscription, survives late Fetch-origin association, and keeps cache state when a concurrent workflow refresh completes. The page uses a scrollable vertical layout so long cache keys, refs, usage, and destructive controls remain visible without page-level sideways scrolling.

The synthetic loopback provider adds three bounded cache records and usage, single-delete, and delete-by-key routes. Exact headless verification ran on DesktopMaterialActionsCache-20260714-8c4f with the cached Electron 42.0.1 runtime, provider http://localhost:51008/api/v3, and renderer CDP port 51111. The pagination gate loaded 51 successful workflow runs and 31 artifacts with both page-two sentinels and empty overflow/clipping/outside/overlap receipts. The cache gate displayed 3 caches using 836.8 MiB, all cache cards, and all delete controls in an inspected original-resolution 960×660 PNG.

Promoted evidence is referenced by README, the three in-repo wiki pages, and the Pages gallery:

Focused formatting, TypeScript, Actions cache/store/UI tests (30/30), fake provider tests (12/12), and scoped ESLint passed. Webpack completed in the exact build:prod command, but packaging remains environment-blocked because node_modules\printenvz\build\Release\printenvz.exe is absent; no dependency was downloaded or synthesized.

2026-07-14 accessibility and clipping gate

The Pages source was exercised in system Edge headless mode at 960×660 and 390×844. Both viewports passed with zero axe accessibility violations, matching document/body client and scroll widths, and zero visible elements extending past the horizontal viewport. The existing page gallery remained fully contained at both widths.

The audit found and fixed two real accessibility defects: the footer skipped from page-level h2 sections to h4 headings, and the in-text roadmap link had insufficient contrast without a non-color distinction. Footer headings now use the correct h3 level, and section links are underlined with a visible offset.

Focused source/style coverage passed 27/27 tests, including the new Pages accessibility contracts and existing compact-shell, post-shell, Actions, and responsive style contracts. The exact production webpack bundles also compiled successfully. The Electron interaction portion could not launch in this checkout because the installed Electron package has no runtime binary and Playwright's bundled browser is absent; the build's packaging step remains blocked by the known missing node_modules\printenvz\build\Release\printenvz.exe. No runtime or dependency was downloaded.

2026-07-16 adaptive customization production gate

The exact tested code source, fixed verification checkout, production build, launched renderer, and captured UI all matched c5205838dfc5ee2b7ce80ce488215a2cd903bb26. The unpackaged production build completed successfully in 147.1 seconds through the repository's exact low-level computer-use service. All input, resize, capture, and inspection work stayed on an off-screen Win32 desktop; the visible user desktop was never shown, focused, or used for input.

The interaction gate verified:

Focused model/store/UI/migration/stale-state/accessibility coverage, TypeScript, lint, formatting, diff checks, and the exact production build passed for the tested code source. Documentation and screenshot publication are committed only after that fixed source gate; direct fast-forward main, CI/Pages, and wiki receipts therefore belong to the later publication commit rather than being retroactively claimed for the captured code SHA.

Seven privacy-safe captures were inspected at original resolution:

Capture Dimensions Bytes SHA-256
docs/assets/screenshots/material-welcome.png 1440×960 146,428 28f0b56ef43347fad0bbe7e0bcb824d7c3df2c39e444a022fb7145c51b6991ca
docs/assets/screenshots/material-customization.png 1440×960 109,343 a9b1493641c69840df6467612dc6f32fa5603404ac5e9b34ac776e7399dc79db
docs/assets/screenshots/material-toolbar-overflow.png 1440×960 167,132 67d64944736d37dd521028d55557a2bb7a9d42d8940aa8051d2ef875c5f021c5
docs/assets/screenshots/material-tab-appearance-word.png 1440×960 167,878 4df433b6bf3b58993299032d6d19e0ded5da3acb0a37f53e6b7109686df7a569
docs/assets/screenshots/material-tab-arrange.png 1440×960 160,546 ce6a43a088b650d14bca158d12776d8dd4dcca5bf89d3f1d52720ddefda85470
docs/assets/screenshots/material-actions-cancel.png 1440×960 133,083 6dceb918e322b2f30ee574a51e815e32f5d4b272f250811b20202a409bec731c
docs/assets/screenshots/material-rebase-review.png 1440×960 153,207 145c5b54320116ce41bdc0b17eb9e726a8cb0dbaf0988886011a862d8cc189de

2026-07-16 profile identity and portable tab workspace

The exact implementation commit is 4e797f52b9ecb4d77f40bfa1e11629fb2f8e3b95. It adds a persistent, profile-backed App identity editor with a shared live/title-bar brand, validated built-in or custom logos, geometry, borders, shadows, colors, and Word-style name typography. Font, width, weight, case, size, spacing, opacity, bold, italic, underline, strikethrough, small caps, highlight, and fixed text effects restore across restart without changing the signed executable or operating-system icon. Migration retains unknown newer identity and tab-style keys while validating every known field before persistence or CSS use.

Repository tabs now support favorites, favorites-first/last stable one-shot sorting inside pin groups, local repository-folder drop to add/open/switch, and bounded JSON export/import of the current order, active tab, aliases, pins, favorites, and appearance. Runtime ids and credentials are excluded; malformed, oversized, relative-only, duplicate, and missing-path entries fail or skip safely, and a replace import never destroys a usable session when no repository can be resolved. Appropriate shell, title, tab, and repository surfaces expose right-click customization plus the exact profile-history or repository Git ownership path; editable and specialized context menus retain priority.

The complete runner passed 1,218/1,218 tests across 420 files and 306 suites. TypeScript, scoped ESLint/Prettier, staged diff and secret scans, focused accessibility/context/session tests, and the exact MCP production build passed. The build used the fixed low-level service and returned successfully in 170.5 seconds without downloading dependencies.

All interaction stayed on off-screen desktop DesktopMaterialScreenshotRefresh2026071601. Because native hidden-HWND resize was unavailable, the approved CDP viewport fallback verified all 38 unique identity controls at a 645×645 renderer viewport. Document, body, preference pane, and identity surfaces had matching client/scroll widths; no required control clipped horizontally. Restart restoration, the eight arrange actions, favorite state, export/import dialogs, and folder-drop overlay passed their bounded geometry gates. This native-width limitation is explicit; the renderer gate did not claim a second native resize mechanism.

The freshly rebuilt MCP screenshot docs/assets/screenshots/material-app-identity-workspace.png is 1443×992, 166,398 bytes, SHA-256 45504266edf337f36a5a6bde0932e1b7ab740d33009e7d8c04a866979e506533. README, Pages, and wiki sources share the asset. Fifty-five distinct published screenshot references resolve locally with none missing; Pages presents 54 unique gallery images and the guided wiki table catalogs 53. The screenshot was inspected at original resolution and contains synthetic state only.

Exact owned PID/HWND pairs 11388/315884768 and 2148/54920934 were gracefully stopped, the hidden desktop reached zero windows and closed once, and the containment-checked Temp root was removed. The visible desktop and unrelated Electron processes were untouched. The foreign OAuth-scope manifest remained untracked and byte-identical; the detached release worktree was not modified.

2026-07-16 final repository integration and cleanup

The integration baseline immediately before this memory-only update is ea76808dca482d2ce6f78c1fb5de27a6dc6f2462. Both previously untracked run manifests are committed. Detached worktree commit 991b57bc1b098e78e4ae43b1ac0b1b76fb74ebe3 is merged into main, and the superseded Pull All stash commit 183ee8648e77be6b43b3899d3b81c4361099504a is retained as merged history without replacing the newer published implementation. Both integration merges preserved tree 28e5840b55d989cc8ef0514f1f3c2ca5673a41b8 exactly.

The stash was dropped after its commit became reachable from main. The clean detached worktree at %USERPROFILE%\.codex\worktrees\3e3c\desktop-material, its empty parent directory, and stale worktree metadata were removed. The final audit at that baseline reported zero dirty files, zero stashes, no unmerged local or remote branches, one local branch (main), one remote branch (origin/main), one canonical worktree, and 0/0 divergence between main and origin/main.

2026-07-18 optional Desktop Material feature highlighting

The current publication changeset adds a thirteenth profile-backed Appearance default: Highlight Desktop Material features. It is off by default and uses the existing version-1 appearance object, profile persistence, local Git-backed Settings History, live preview, and Cancel rollback. No parallel store, schema version, storage key, or repository-local override was added. The normalizer accepts only a real boolean and old version-1 profiles migrate naturally to false.

When enabled, AppTheme installs one data-dm-highlight-features body gate. Only explicit data-dm-feature entry points receive the non-animated accent edge plus compact M or full Material badge. The reviewed inventory covers repository Actions, Releases, Issues, API, Triage, and Tools; Settings Agent access and Automation; repository-tab search, arrange, new-tab, notification, and settings-history controls; the Commit & Push, Build & Run, and theme toolbar controls (including overflow); and a centralized allowlist shared by the app menu and command palette. Changes, History, Branches, Accounts, Git, Appearance, and other upstream/mixed surfaces remain deliberately neutral.

Focused persistence, UI, theme-side-effect, responsive-marker, shell, Settings-toggle, and allowlist coverage passed 28/28 tests across seven files. All 554 repository unit-test files passed in three batches in 516.9s; script tests passed 16/16; deterministic provider tests passed 14/14; root and script TypeScript, repository-wide no-cache ESLint, and repository-wide Prettier passed. The configured Markdownlint command is not a clean Windows repository gate: its recursive glob includes nested dependencies and reported 54,084 baseline diagnostics, so this milestone does not claim a Markdownlint pass.

The fixed MCP preflight was healthy at 127.0.0.1:8765; its scheduled task points to checkout 8d6940be6a5f6e7c37de3f73acd2259fa7651efe. A temporary Yarn shim came strictly from the existing local npm cache, delegated to pinned Yarn 1.21.1, and the exact required final production build passed in 229.1s (yarn reported 227.46s). The shim was removed and where yarn was absent.

The final rebuilt UI run stayed on Win32 desktop DesktopMaterialHighlightFinal-20260718-2015 (handle 1044). Provider and launcher PIDs 32220/20420 used loopback port 52821; exact launch PID 7260 resolved to HWND 20251006, with CDP on 9347. The accepted light Appearance capture is 1440×960, 137,390 bytes, SHA-256 3e7cfc236741dc9873e4e3dace1d25e58b57c73464ed026a45e56c44eda53b08. A final 1440×960 dark capture, a 600×240 compact shell capture, and a true 300×400 narrow Settings capture were inspected for contrast, compact M replacement, hidden-label behavior, scroll reachability, and clipping. The native off-screen helper could not close the revalidated HWND, so only saved launch PID 7260 was terminated as the documented fallback. The desktop then reported zero windows and closed; both loopback ports reached zero listeners; both provider processes stopped; and containment-checked cleanup removed the exact owned Temp root. The visible desktop and unrelated Electron processes were untouched.

The tracked material-customization.png, README, Pages, and wiki sources now describe the default-off discovery treatment.

Publication and cleanup checkpoint

2026-07-18–19 CI recovery and temporary submodule navigation

Local outcome

The July 18–19 changeset repairs the Windows packaged-E2E updater-port failure and adds Open as repository for initialized Submodule Manager rows. The opened child is a temporary negative-ID repository: it is absent from the saved repository database, repository list, Recent group, persisted last selection, and persisted tab collection. A context bar returns directly to the persisted root repository, including from nested temporary navigation. Appearance now stores exactly English, playful Hong Kong Cantonese, or bilingual presentation, plus Tonal/Filled accent/Outlined and Back to parent/Parent name/Icon only presentation for the Back action.

That explicit profile selection supersedes the earlier locale-derived behavior recorded in the historical internationalization receipt above. The older text remains provenance for its original source rather than a description of the current language contract.

The CI action selects one exact loopback /update URL for both the production bundle and runtime mock server. Installer publication is now downstream of successful CI for the exact same-repository main SHA; manual dispatch runs the same reusable CI gate; existing tags and missing or empty required assets fail; and one successful eligible run contains one release-publication action. This local receipt does not claim the still-pending remote result.

Exact build and headless environment

Runtime stage PID HWND
Diagnostic launch 20380 67830826
Accepted passes 1–4 6048 19464818
Pass 5 and initial pass 6 17732 48956738
Persistence-build verification 13272 19661426
Tokenized passes 6–9 before localization correction 8624 73991674
Final localized pass 9 and pass 10 32600 83101264
Log-loop-fixed provider launch 16460 90637818
Fixture published-remote relaunch 23188 56230330
Final branch-rules environment launch wrapper 24136; Electron main 5116 86050108
Final post-build regression wrapper 28356; Electron main 25584 62588622

The retained verifier state finished at pass 10 with one persistent repository, one persisted repository tab, checked-out child modules/material-widget, and uninitialized control modules/dormant-addon. Each pass reset known state before interaction, rejected blank/error frames, and advanced the durable pass ledger only after all assertions and the final direct CDP capture succeeded.

Ten accepted passes

Pass Accepted capture Dimensions Bytes SHA-256
1 pass-01-launch-final.png 1440×960 110,384 21f098f11388e1b57028dbcf9288e51272932b9a8a14cd150d6a2e04766a981e
2 pass-02-manager-final.png 1440×960 140,353 2e883f275f7c888404a959d51be5dac0c88cf46fa39a343d4795315efd53c40d
3 pass-03-child-context.png 1440×960 103,250 25de28cb43ea3031f20788a52638095b0272b73424f4e36d7e43657ab7f381b0
4 pass-04-back-parent.png 1440×960 122,228 bec6bf8e2ae957ab8544df68babf12e6fffe88be179e0e88e996878619119ff5
5 pass-05-restart-policy.png 1440×960 140,116 a5402d2eb7b2a545c965eb0ce3a217a12a4fa634c7e85695ae050a3205b6e28e
6 pass-06-appearance-tokenized.png 1440×960 136,786 4e511ff542907575633335ffdd8d8eb379b13b3a2f5c08e32ca6cf51b4298169
7 pass-07-compact-keyboard.png 700×650 63,406 6cbbf7a893dbb0b5d111057364d040e1a57a6c42d30f2b392cb022fee6c2415d
8 pass-08-dark-200.png 640×480 61,722 2f79c502ce72fd4cfafe44b12ffd35e58d23ff703d507e6441e4ef846c3f37cf
9 pass-09-languages-localized.png 700×650 77,064 62c02c1040ecae78bfed9f7f24841b546719815994a772eaa1cd524c4ff9b4f9
10 pass-10-regression.png 1440×960 164,471 f86886bae8848f73bd35015cc9b87ba0dc3f2438c09791439347f2f697e71f0c

The passes proved fresh launch and identity; initialized/uninitialized manager gating; child Git scope and persistent-database invariants; exact Back focus and parent restoration after child changes; restart fallback without repository or tab pollution; Appearance live preview, Save, Cancel, and legacy fallback; keyboard-only compact operation; dark and 200%-requested auto-fit behavior; all three language modes and localized stale recovery; and final Changes, History, Actions, Notifications, Releases, Repository Tools, and Settings regressions.

The additional inspected stale bilingual frame was 1443×993 and 163,335 bytes at SHA-256 33a595e1faf1b7ade1b523c254ef826c0a9e5239c84a184a84e7cfe6f6b50a6b. The provider regression captures were Actions at 1440×960 and 109,546 bytes (bd682b6f465012f0737fd6e47eb054bdb58333c13d2eaaffdf092523b0529325) and Releases at 1440×960 and 146,415 bytes (8dea0b61a0da101c730cb93e3534b5281d9aa3392c75acef8a1944cc36fbc1fb). The same sweep accepted the effective-branch-rules state at 1440×960, 162,231 bytes (6a391269c74dd638687100651f023d727667b47960ab2353a1717fde96037ba8).

Two 2160×1440 pass-1 candidates were rejected because Playwright inherited the Windows 150% device scale rather than the requested renderer pixels. Direct Page.captureScreenshot produced the accepted exact-size frames. Other intermediate frames were retained only for debugging when stale tooltip CSS, incomplete async waits, or pre-fix localization made them unsuitable for public evidence.

Bugs found and corrected

Final local code and runtime gates

The final built bundle then reopened the child and confirmed its context bar, unchanged persistent repository count, customizable Back control, and read-only Repository Tools boundary. The inspected 1440×960 child frame was 134,223 bytes, SHA-256 53bae0c04eccedbafa4dbb749151b00df4d95fadce701758259ffd049fdc89ad. Back restored the root in a second inspected 1440×960 frame, 159,924 bytes, SHA-256 e11956f58a18216bd90b65276890f86579e0bdd1b559268a139861fe2f94dcf0. Both were nonblank, unclipped, and private-data-free at original pixels.

The log-history repository remained at HEAD af8c8e91c8d99f0bf99f05dd46c7903d2ef9baf1, count 22682, and clean status across eight idle seconds. Before its owned run root was deleted, the fixture root was at 5f4cc173 with only the expected modified submodule pointer; child modules/material-widget was clean at de377c26.

The exact app/wrapper and provider/launcher processes were stopped. Listeners 62241 and 50158, the owned credential entry, the headless desktop, and the entire containment-checked run root were independently confirmed absent. The visible desktop and unrelated Electron processes were never touched.

The final privacy audit rejected the first Repository Tools pair because its introductory path exposed the verifier account's Temp directory. The pair was recaptured from the same production bundle against the synthetic C:\DesktopMaterialEvidence-20260719\fixture checkout; the compact scene now also proves an actual scroll of the function list. Both replacements passed original-pixel inspection. Exact PID 5608, listener 62243, DesktopMaterialPublicTools-20260719, and the neutral evidence root were closed or removed and confirmed absent.

All six frames were inspected at original resolution for exact dimensions, nonblank pixels, clipping, theme, synthetic-only data, and private-data absence before promotion.

Asset Dimensions Bytes SHA-256
docs/assets/screenshots/material-repository-tools.png 1440×960 124,544 670295d148df32c1796951363a1cde5ddb4aa7b31ce3142e2a50949b7e56c398
docs/assets/screenshots/material-repository-tools-scroll.png 960×420 68,162 4b47645776429875394280f0e5584aacf28988d2dcf2ccc79793e929a68f46f3
docs/assets/screenshots/material-effective-branch-rules.png 1440×960 162,231 6a391269c74dd638687100651f023d727667b47960ab2353a1717fde96037ba8
docs/assets/screenshots/add-submodule-dialog.png 1440×960 145,009 4c441e7d9757b6627e930bb9d43a39c86e38d408cc568b1c1ca874484b808a2a
docs/assets/screenshots/material-customization.png 1440×960 165,740 478009bd887a067d007627a531206750bdb9e95508ec9860c609e8c090db2f15
docs/assets/screenshots/material-submodule-context.png 1440×960 103,250 25de28cb43ea3031f20788a52638095b0272b73424f4e36d7e43657ab7f381b0

Publication checkpoint — implementation and correction

The repair baseline remains CI run 29671087941 at source 19c1e2a06d0746f4c371d37a1c102ae961011f90: only Windows x64 packaged E2E failed, while both macOS packaged-E2E jobs, both Windows build jobs, both macOS build jobs, and lint succeeded. The failed-SHA release is immutable historical state: installer run 29671087924 and release v3.6.3-beta3-b0000000163 are not reused, deleted, or rewritten.

Maintenance constraints

2026-07-21 CI FFmpeg recovery and Super Express Release

2026-07-25 Standalone Ollama settings tab

2026-07-31 recurring background Git and indicator errors

2026-07-31 automatic submodule add recovery

2026-07-26 write EOF crash — peer-closed stream writes

Branch fix/write-eof-crash (not pushed; push was explicitly out of scope). Fixes the user-reported unrecoverable dialog from build zadtrqvojl: Error: write EOF at WriteWrap.onWriteComplete (node:internal/stream_base_commons:87:19).

2026-08-02 closeout publication, CI recovery, and roadmap foundations

The closeout range from b637f07e0e through 55ecff5946 is published on origin/main. It includes the completed bug/UI checkpoints, the bounded roadmap foundations listed below, and the release/installer corrections the owner requested. The exact run record is docs/verification/handoff-closeout-2026-08-02/run-manifest.md.

Release and CI behavior

Roadmap foundation receipts

These commits are foundations, not declarations that the corresponding open roadmap issue is finished:

Roadmap Published foundation
R1 server trust boundary, restart-safe provisioning, Windows provisioning driver, and Docker build context (6839db9256, e014b3676c, a229ddabca, 1547cb97f3)
R2 fail-closed OAuth authority core (74d8ee7eb8)
R3/R8 continuous graph actions and truthful lane visibility (f3e386edbc, 22a44bceed)
R4 operational Agents/signing surfaces and secure setup commands (7373ba0afa, 4613d62db8)
R6 immutable, native-Windows-accurate conflict forecast (55ecff5946)
R7 guarded editable three-pane merge editor (f52d815b2a)
R9 immutable commit-composition plan (482fd3bb3b)
R10 safe reviewed change-summary contract (d6ccccaa14)
R11 Launchpad model, bounded preferences, and accessible view (e19ccbc7c9, cd00c6c152)
R12 pull-request review workspace (a1a5e87e11)
R14 fail-closed AI policy boundary (f0fa06da2a)
R15 repository refresh coordinator and integrated-terminal renderer (0a78b569d5, c8abe88858)
R16 provider sign-in redaction and strict issue-tracker identity/config (8f94d5617c, 229978e75f)
R17 interactive-rebase plan/editor plus history lane controls (cb4c38a5f4, a12756271d, 22a44bceed)
R18 canonical Cloud Patch artifact and encrypted self-hosted store (e8cc4a1314, f895bf7aad, 8abed0ce7e)

Repository TypeScript is green at the last product commit. The R6 gate passes 15/15, and an independent native CompareStringOrdinal(ignoreCase=TRUE) sweep covered all 1,112,064 Unicode scalar values with 1,946 aliases and zero mapper mismatches. R10 passes 24/24 and R16 passes 21/21.

Deliberately open acceptance work

Issues #118–#135 stay open wherever the roadmap table says an adapter, server route, live UI, or capture is pending. A foundation test is not a substitute for a reachable feature. In particular, the requested README/docs/wiki image for each new roadmap feature is not claimed: those images must come from the real built Windows surface through the off-screen Lowlevel capture harness after each feature is wired. No mockup, design image, or unrelated screenshot was substituted.

A separate linked worktree at C:\Users\cntow\Documents\GitHub\desktop-material-linux-tui-revival contains uncommitted TUI work on codex/revive-linux-tui. Its recorded branch tip is an ancestor of origin/main, but its working files are not clean or proven complete. They were preserved exactly and were neither staged, committed, merged, nor deleted by this Windows closeout.

2026-08-04 command-palette routes and shortcut contract

The command-palette coverage work now keeps the live notification centre and the Git-backed notification-history dialog as separate commands. The former opens the live side sheet; the latter opens the local history surface. The desktop menu now names the command palette directly and binds it to CmdOrCtrl+Shift+F, matching the app-wide shortcut contract. The old Ctrl+F binding was removed from that menu; Ctrl+F remains reserved for find-in-page where that surface owns it.

Verification for this checkpoint:

The release/installer path was intentionally not exercised in this checkpoint; the user's skip-signing contract remains in force.

2026-08-04 screenshot catalog and Windows unit-test contract correction

The Windows desktop job in CI run 30940885403 packaged the application and uploaded its Squirrel.Windows files, but its unit test step was red. The failure combined a stale screenshot-docs contract with three assertions that queried the parent New Agent Session dialog after the nested setup editor had closed. The setup editor itself already handled Escape through its native key listener; the test needed to identify the nested dialog by its accessible name rather than treating both dialog layers as one node.

This checkpoint refreshes the committed gallery plan and generated screenshot pages to 91 published gallery outputs, retains the historical notification frame separately, and scopes the setup-editor close assertions to Setup commands. The generated docs now contain 98 screenshot pages plus the index, with 7 retained historical frames.

Verification for this correction:

2026-08-12 surface locks wired, narrator voice, personal vocabulary

What changed

Surface locks did nothing. setMd3LockCredentialVault was never called at renderer start-up — a gap the feature's own documentation had recorded months earlier under a heading called Not yet wired. Every attempt to lock an element wrote a lock record, was refused the credential, rolled the record back, and left a button that appeared to be made of paint. The vault is now installed in app/src/ui/index.tsx.

A recorded lock also gated nothing: the row appeared in the manager and the element carried on working. app/src/ui/appearance/appearance-lock-gate.ts adds one capture-phase gate over mousedown, click and Enter/Space, keyed on a data-md3-lock-target attribute an element carries via appearanceLockTargetProps. AppearanceLockPromptHost, mounted once in the shell, opens the existing unlock prompt anchored to the blocked control.

Narrator voice is selectable, per language, with rate and pitch — app/src/lib/audio/narrator-voices.ts plus pickers in Sound preferences.

Personal vocabularyapp/src/lib/personal-vocabulary.ts and the control on Settings → Appearance. Applied at translate, which is the single user-facing text boundary.

Two Material 3 corrections. --button-height 25px → 40px and --button-border-radius 6px → 20px, which were the last values in the app reading as Material 2 and were under the minimum touch target besides.

Verification

What a successor needs to know

One guard could not be made to fail, and that is recorded rather than hidden. A lastIndex reset was added to the vocabulary's cached regex with a confident comment about why it was necessary; String.replace with a global pattern manages lastIndex itself, so the test written to prove the reset was needed passed with the reset removed. The line was deleted and the comment now says so. Anyone reviewing a module-level /g regex will want to add it back.

Seven commits in this session are missing the Co-Authored-By trailer. Author and committer are correct throughout, so git blame attribution is intact, but the trailer is what the release line-count attribution reads. Correcting them needs a history rewrite and therefore explicit authorization; they were left alone. commit.template does not apply to git commit -F, which is how the gap opened.

Still open

2026-08-12 capture harness — three distinct failures, two fixed

Worth separating, because they arrived one behind the other and the temptation was to treat them as one problem with one cause.

1. ERR_CONNECTION_REFUSED — fixed. A development compile sets webpack's publicPath to http://localhost:3000/build/, so the renderer fetches its own bundle from a dev server no capture run has any reason to be running. Run yarn compile:prod before capturing. The harness now names this outright when it sees a refused connection, because the bare error sends a reader looking at the network rather than at which webpack config produced the bundle.

This was found only because the harness was changed to report the console errors it had been collecting all along. It reported them only on the success path, so the one failure where they are decisive was the one failure that discarded them — leaving locator timed out waiting for #desktop-app-contents, which reads identically whether the app is broken, the machine is slow, or this.

2. Silent process abort on --tabs=N — fixed. With no dialog handler registered, Playwright auto-dismisses every dialog, and that auto-dismiss races Electron's teardown: it calls Page.handleJavaScriptDialog after the dialog has gone, rejects with No dialog is showing, and Node turns the unhandled rejection into a process abort. No failure line, no console errors, no indication of which step was in flight — indistinguishable from the application crashing. The harness now accepts dialogs deliberately, tolerates one that has already closed, and reports a driver-level rejection as an ordinary non-zero exit.

3. --tabs=N still fails, but now legibly — NOT fixed. page.reload: Timeout 30000ms exceeded, waiting for navigation until "load".

The cause is understood and neither half is misbehaving. profile-git.ts installs a beforeunload guard while a profile write is in flight (profileRepositoryNavigationGuards), and the tab-seeding path writes repositories into IndexedDB and then reloads the renderer straight into it. Electron cancels the navigation rather than prompting, so page.reload waits for a navigation that will never happen. Accepting the dialog does not help, because there is no dialog to accept.

Candidate fixes for whoever picks this up: reload with waitUntil: 'domcontentloaded'; or wait for the profile write to settle before reloading; or have the seeding path avoid the reload entirely. Not attempted here — the settings captures this session needed did not use --tabs, and guessing at a fix for a path that is not exercised would have shipped an unverified change.

Captures taken this session: docs/assets/screenshots/personal-vocabulary.png and docs/assets/screenshots/narrator-voice-pickers.png, both from the built app at the commits named in their feature articles. Both caught defects no test was looking at — a label that repeated its own heading, and a disabled text button that rendered as stray grey text because a Material text button has no container until it is interacted with.

2026-08-12 the trailer question, settled by checking rather than by rewriting

Ten commits in this session carry no Co-Authored-By trailer, because commit.template does not apply to git commit -F. The obvious remedy is a history rewrite and a force-push, which needs explicit authorization and is worth not asking for, because the premise turns out to be wrong.

script/count-lines.mjs attributes a commit to an agent when either the author matches AgentAuthorPattern (/^(claude|codex|opencode|…)/i) or a Co-Authored-By trailer matches. Every commit in this repository is authored by Claude Fable 5, so the first branch is satisfied and the trailer is redundant.

Verified rather than reasoned: running agentCommits() over the real history and checking all ten SHAs returns 10/10 attributed to an agent.

So there is nothing to fix, and rewriting ten pushed commits would have changed no number anywhere. The trailer still goes on every new commit — it is the rule, and it is the branch that carries the attribution in any repository where an agent commits under a person's identity. It simply is not load-bearing here.

2026-08-12 undeclared imports — one fixed, three named, guard added

app/test/unit/declared-dependencies-test.ts reads the two manifests and fails on any package app/src imports that neither declares. It reads the manifests rather than the module graph on purpose: the graph is exactly what lied.

It found three pre-existing direct imports of transitive packages:

Imported Reaches the build through
winston-transport winston
@floating-ui/core @floating-ui/react-dom
focus-trap focus-trap-react

They are the same latent shape as the fs-extra failure — resolving only because something else pulls them in — but they differ in two ways that make them lower risk: each ships its own types, so they cannot produce TS7016, and each parent is a direct dependency that reliably installs them.

They are listed as exceptions anchored to their parent, and a second assertion fails if a parent ever stops being declared, so the list cannot become somewhere new undeclared imports are parked.

Follow-up, deliberately not done here: declare all three at the versions already installed (winston-transport@4.5.0, @floating-ui/core@1.8.0, focus-trap@6.1.0). That is a manifest and lockfile change and had no business riding along in a commit whose job was turning a red build green.

2026-08-18 personal vocabulary schemaVersion and Material control

What changed

The personal vocabulary contract now treats schemaVersion as the canonical top-level field for user-supplied files. Existing local cache/data that still uses version is kept compatible on read so older installs continue to load, but new cached data is written with schemaVersion and new files are validated against that shape only.

The settings surface was moved onto the app's existing Material Design 3 primitives instead of the raw file input: a read-only summary field, a choose button that opens the local file dialog, and a clear button that restores the original wording. The change stays inside the existing preference surface and keeps the fail-closed behavior intact.

Files changed

Verification

No tests or captures were run in this lane, per the Yum Leung Cha boundary for this task.

Notes for the next person

The compatibility policy is deliberate: user-facing files must use schemaVersion, while legacy cache entries using version are still read so existing data does not disappear. The UI change uses only the repository's existing Material primitives and does not introduce a new style file.