refactor(desktop): close R2 M5 at the AppShell root - #5952
Conversation
…g authority AppShellContent kept one useEffect, marked for removal in M5, that seeded the default Host's connection projection from the onboarding snapshot, or refreshed it when onboarding could not be read. OnboardingConnectionSeed, a render-null watch in the onboarding authority's contract, now does that from the authority itself, with the shell supplying only the projection's seed and refresh commands. AppShellContent loses its last useEffect (gate 25/30 → 24/29) and the retained-root row for it. Refs apache#4582 Generated-by: Claude Opus 5.5
useAppShellProjectContext still returned the default Host's project list, the Local Host's projects and the raw selected project id, and kept a Local Host project subscription (projects.getLocalSnapshot and subscribeLocalChanges) for them, although no reader remained after project mutations moved to Task Entry (apache#5937). Drop those outputs and the subscription. The hook stays at the root: it is the per-Host project projection the shell composes into the titlebar, Workbar, Module Hub, command palette and mentions, in the same class as the per-Host connection projections. Its retained-root row now records that as an application lifecycle with its actual consumers instead of an M5 removal. Refs apache#4582 Generated-by: Claude Opus 5.5
After the R2 merges, AppShell still threaded several values nothing read: - seven ChatView props (activeConnectionLabel, activeModel, activeModelLabel, activeProviderType, renderProviderMark, modelChoices, onModelChange) that ChatView declares but never reads. The transcript region passed all but activeModel, and the WorkHub conversation passed activeModel. They are removed from ChatView's props, with the ProviderLogo import and the chat-model values AppShell computed only for them. - uiLocaleOverride on AppShellContent; only AppShell's LocaleProvider reads it. - SessionNavigationPorts.activateSession, which no rail action calls. - the WorkHub rail entry object: its `active` repeated workHubActive and its label was a constant. The rail now takes onOpenWorkHub and builds the entry itself. A type-level test pins the trimmed contracts. Refs apache#4582 Generated-by: Claude Opus 5.5
…ect ownership labels AppShellDetailPanel is a stateless frame with no hooks and no dependencies beyond React, which is what the shell zone holds and what the ledger's shell-root-and-frame entry targets. It moves to shell/detail-panel.tsx, so the AppShell family loses one legacy file. Two ownership entries no longer described their files: - mixed-bootstrap-and-conversation-effects is now root-lifecycle-effects, since app-shell-effects.ts holds only root lifecycle hooks. - app-shell-copy.ts, which is command-palette error copy used by app-shell-command-actions.ts, moves to commands-and-overlays. Refs apache#4582 Generated-by: Claude Opus 5.5
…owners The retained-root table is the residual inventory R2 closes on, so every row should match the code. An audit of the rows that stay at the root found wrong consumers (the memory indicator is the transcript's session-context chip, not the titlebar; the rail reads go to the transcript and titlebar, not the command palette), wrong owners (useSystemUiLocale, useAppShellNavRefSync, useStableActions and useToast live in legacy files or @maka/ui) and stale capabilities (useShellAppearance writes no settings; ConversationLifecycle, not the transcript, bumps the pet counter). Those rows now name what the code does. The M3 rows are left to the M3 owner, which retires them. Refs apache#4582 Generated-by: Claude Opus 5.5
…ined The "Transitional feature exports outside Conversation" table scheduled OverlaysConsumer and ManualDiagnosticReportConsumer for M5, with the legacy command actions. Neither can leave the root within R2. app-shell-overlays.tsx composes the legacy Settings surface, which it imports lazily, and the palette command list that apache#4997 deliberately kept as a shell injection point; feature zones may not import legacy code. The manual report is the diagnostics owner's command handed to the shell-built palette options. Both rows now record why they stay. Refs apache#4582 Generated-by: Claude Opus 5.5
Astro-Han
left a comment
There was a problem hiding this comment.
Reviewed 03c30db74e757b434f1e78b960624c38b6d45b26 (21 files, +158/−168).
No P0–P3 findings.
Shape: this is a shrink, which is what closing an R2 slice at the AppShell root should look like. Of the 21 files, 17 are production and they net −75 (+79/−154). The two largest movements are both reductions — app-shell.tsx +7/−35 and use-project-context.ts +5/−33 — workhub-root.tsx and session-navigation/ports.ts each lose a line, and app-shell-detail-panel.tsx moves to shell/detail-panel.tsx as a pure rename (0/0), which is literally the "close it at the root" shape. The one file that grows meaningfully is onboarding-authority.ts (+29/−1), the authority taking over what the root was doing — the same pattern the earlier slices in this series used.
Both ledgers only tighten, which is the criterion this series is held to: renderer-architecture.json +10/−28 (net −18) and scripts/check-app-shell-hooks.mjs 0/−1. Nothing is loosened.
Gate on this head: test is not finished (null when I looked), so I make no CI claim. Note that the previous head of this PR (d084b62d) had already passed test and label; this revision is the drifted one I declined to review earlier and which has now been re-frozen, so it needs its own verdict. mergeable is true and the base is current main.
What I could not judge
- The internal correctness of what moved into
onboarding-authority.tsand out of the two shrinking files; this pass verified the shape, the ledger direction and the run's state. - No Electron run.
I did not approve, request changes, or merge.
Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.
…osure # Conflicts: # apps/desktop/renderer-architecture.json
Astro-Han
left a comment
There was a problem hiding this comment.
Automated review (Claude lineage). This was not written by a human, and it does not approve the PR. Please verify before acting.
Incremental review of 3c9bf72e against 03c30db7. The only new commit is a merge of main at f7633c3d (#5826). There are no new code commits.
Verdict: no P0–P3.
- Ledger conflict. I compared the merge tree with
git merge-tree's automatic result. The only manual resolution is inrenderer-architecture.json: theapp-shell.tsxmetrics, set to 57 import specifiers and 7852 tokens. CI's strict-base check accepts the regenerated values. app-shell.tsx. Main's two changes merged in automatically:executorSessionPendingandConversation.createExecutorSessionActivator(...). Typecheck passes in CI.
CI and status: test passes on 3c9bf72e. The PR is mergeable and is blocked only on review.
#5954 at 1e8cc72b: the two still conflict only in renderer-architecture.json, renderer/README.md and scripts/check-app-shell-hooks.mjs. app-shell.tsx merges automatically. No order is required. Whichever PR lands second should merge main again, keep both sides' rows, and regenerate the ledger.
Astro-Han
left a comment
There was a problem hiding this comment.
Approved at @Astro-Han's explicit request: no blocking findings in our automated reviews of this head, and CI is green.
…composer-read-side apache#5952 (R2 M5 closure) and this branch both cut the AppShell hook gate and rewrote retained-root rows: - Hook gate: both removals apply. `useEffect` (apache#5952) and `useAppShellTurnPresentation` (this branch) are gone: 19 hooks / 24 call sites, matching the merged tree. - Retained-root table: apache#5952's rewritten rows are the base. This branch's removed hooks drop out, and its three cross-region rows replace apache#5952's M3 rows. Those rows no longer list the transcript's model labels and model picker, which apache#5952 removed from ChatView. The Session-workspace row names the Composer edits instead of the ref, and the bootstrap row drops the pending-ref cleanup this branch retired. No row is scheduled for removal. - Exports table: apache#5952's two "stays" rows (OverlaysConsumer, ManualDiagnosticReportConsumer) and this branch's three are kept. - Ledger: main's copy minus this branch's retired legacy paths and emptied ownership entry, regenerated. Generated-by: Claude Opus 5.5
Summary
After #5934–#5937,
npm run check:renderer-architecture -- --reportstill listed two retained-root rows scheduled for M5. M5's fourth item, "remove migrated legacy exceptions, public raw-state exports and redundant props/helpers", and its fifth, "document every retained root projection/lifecycle with its actual consumer, owner and allowed capability", were also open. This PR closes all three, in five commits:61cad0bccOnboardingConnectionSeed, a render-null watch beside the onboarding authority, seeds the default Host's connection projection from each accepted snapshot, or asks it to refresh when onboarding cannot be read.AppShellContentloses its lastuseEffectand the M5 row for it.e485fa592useAppShellProjectContextstops returning the default Host's project list, the Local Host's projects and the raw selected id. It also drops the Local Host project subscription (projects.getLocalSnapshot,subscribeLocalChanges), which nothing has read since #5937 moved project mutations to Task Entry. Its row moves from "M5" to "application lifecycle" (see below).use-project-context.tsloses 2 bridge paths and 1 effect.eae997042ProviderLogo.3681d31d3AppShellDetailPanel(stateless, React-only) moves toshell/detail-panel.tsx, the target the ledger'sshell-root-and-frameentry already named. Two ownership labels are corrected.d084b62d003c30db74OverlaysConsumerandManualDiagnosticReportConsumeras retained rather than "M5". The overlay layer composes the legacy Settings surface and the palette command list, which a feature cannot import; the manual report is a cross-region command. Documentation only.The props removed in
eae997042:activeConnectionLabel,activeModel,activeModelLabel,activeProviderType,renderProviderMark,modelChoicesandonModelChangebut never reads them. They are removed from its props. The transcript region passed all butactiveModel; the WorkHub conversation passedactiveModel.uiLocaleOverrideonAppShellContent. Only AppShell'sLocaleProviderreads it.SessionNavigationPorts.activateSession. No rail action calls it.activerepeatedworkHubActiveand its label was a constant. The rail now takesonOpenWorkHuband builds the entry itself.Why the project context stays at the root
useAppShellProjectContextreads the owner Session's project (path, Git state, current project, capabilities) or, with no Session, the default Host's. The root composes that into:It writes nothing; #5937 moved the mutations and open-folder commands to Task Entry. Every reader is a root-composition input that depends on the owner Session, which AppShellContent derives. That makes it the same class as the three per-Host
useShellConnectionsprojections, which #5934's table already records as "application lifecycle". The row now says so, instead of scheduling a move that would only rename the projection. Consolidating it with Task Entry's own per-Host project reads would be a separate change.Inventory (main
229e1b466→ this branch)--report)app-shell.tsxlines /nonTriviaTokensNot in this PR
useAppShellSessionUiReadsand its one-lineuse-app-shell-session-ui-reads.tsre-export, the Composer region props, anduseShellChatModel. Their table rows are left for A to retire rather than edited here.onNew. It is also never read, but it is required and passed by about 20 tests and stories. Removing it would be churn outside the root.SessionNavigationProvider,SessionTurnRequestInboxProvider,SessionSettingsProvider, the command list) still receive the Session catalog as a prop althoughSessionCatalogContextis above them. That is explicit injection rather than dead threading, so I left it.Refs #4582
Review focus
app-shell.tsxagainst each hook. Main corrections:useSystemUiLocale,useAppShellNavRefSync,useStableActionsanduseToastlive in legacy files or@maka/ui;useShellAppearancewrites no settings;ConversationLifecycle, not the transcript, bumps the pet counter.targetZonevalues, so the effects entry keepssplit-by-capabilityunder its new name,root-lifecycle-effects. No rule changed.app-shell.tsx. Whichever lands second merges main and regenerates.Verification
Run locally on Node 24.19.0 at
d084b62d0(on229e1b466):npm --workspace @maka/desktop run clean:main && … build:test && … test:dist: 3,208 / 3,208 pass. New or changed tests:onboarding-authority.test.ts: the seed maps a snapshot once, skips an unchanged one, and refreshes on a failed read.use-project-context.test.ts: the Desktop stub no longer offers the Local Host snapshot, so a leftover call would throw.app-shell-retired-props.test.ts: type-level. Re-adding any of the seven ChatView props, the rail'sworkHubEntryor the port'sactivateSessionfails the build; checked by re-addingmodelChoices→ TS2322.session-navigation-controller.test.ts: the WorkHub entry test now goes throughonOpenWorkHub.npm --workspace @maka/ui run clean && … build && … test:dist: 699 / 699 pass.npm --workspace @maka/desktop run build:with-deps && npx playwright test --config e2e/playwright.config.ts: 33 / 34. The failure issession-workbar.spec.ts:179, the post-reloadtoBeVisibleat line 224. That spec is flaky on main itself: 4 of 8 runs failed at255ae23aeand 2 of 8 at8ad836ce1(measured for refactor(desktop): retire AppShell's direct Desktop bridge (R2 M5) #5936).npm run check:renderer-architecture -- --base 229e1b4665a06a77ac6afb93ce47b3eaa78e0103 --strict-base: pass.npm run check:app-shell-hooks: 24 / 29.npm run typecheck(preload, main, renderer, storybook),npm run lint,npm run format:check,npx knip --workspace apps/desktop,npx knip --workspace packages/ui: pass.npm run windows:inventory(current),npm run astryx:surface-inventory(regenerated for the moved panel; ok),npm run check:asf-headers: pass.Each commit was typechecked and architecture-checked on its own, with
@maka/uirebuilt per commit.AI use
Select exactly one:
Tool(s) and scope: Claude Opus 5.5 in Claude Code wrote the implementation, tests and PR text. Two read-only Claude Code subagents audited the retained-root rows and AppShell's props; their findings were verified against the code before use. The author reviewed the change and decided to submit it. Every commit carries
Generated-by: Claude Opus 5.5.Checklist
Does this PR entail a change in behavior?