Skip to content

refactor(app): isolate composition and presentation / 完成 App 装配与展示层拆分 - #9897

Merged
SivanCola merged 33 commits into
esengine:main-v2from
SivanCola:codex/9777-5-app-shell
Sep 7, 2026
Merged

refactor(app): isolate composition and presentation / 完成 App 装配与展示层拆分#9897
SivanCola merged 33 commits into
esengine:main-v2from
SivanCola:codex/9777-5-app-shell

Conversation

@SivanCola

@SivanCola SivanCola commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Behavior and scope

Slice 5 of #9777 completes App composition and presentation after source-bound ownership #9896. It depends on #9896; renderer #9895, independent prerequisite #9903, settings #9894 and pure kernel #9893 are already merged.

App.tsx becomes a small bridge-free facade. AppRuntime preserves hook order and command owners; AppRuntimeView renders shared regions without another active-session authority. Pure context helpers and lazy subagent outcome/preview cards leave eager consumers. Live wire outcomes preserve ref/status/error/retryable together, while historical output parsing belongs to the rendered card. An AST gate checks runtime imports, re-exports, aliases and dynamic imports with negative fixtures.

This adopts @SivanCola's repaired #9777 presentation structure and includes the shared renderer repairs qualified through the preceding slices.

The inherited session-ownership slice also fixes a confirmed remote resume rejection race: restoring the previous identity and publishing the error now share one revision-checked completion and lifecycle publication fence. The deterministic regression, sibling rejection paths, repeated race cases, full desktop tests and full desktop race tests pass. The same owner slice handles the remote bootstrap lock release/acquire observation race with bounded structured-error recompetition. The obsolete frontend source-contract check now follows the current async handoff; Go regressions verify the actual error-time identity. These backend/test repairs do not change this slice’s production frontend assets.

The shared renderer now distinguishes first materialization from changes to already painted content. New DOM receives real measurements before first paint; a generation-bound window origin preserves existing visible coordinates while the prefix is refined. Geometry acknowledgements follow the complete measurement commit. Ordinary content growth preserves the input-captured Kernel anchor; only origin removal converts an anchor from the previously committed prefix. Changed DOM bounds cannot let a growing offscreen predecessor replace the reader anchor. Bounded windowed Markdown answers render formatted content immediately, while larger worker results automatically commit after active input ends. The single native scroll writer, mount cap and displacement thresholds are unchanged.

This fixes a GTK regression where publishing initial size debt at input release moved later visible rows. Fixed-height regressions cover both larger and smaller actual sizes, reverse travel, mid-history and leading-edge release, and offscreen predecessor growth into the viewport. The predecessor-growth test fails before the anchor-ownership fix and passes after it. A diagnostic GTK run passed 1,951 rows / 967 frames with zero reverse displacement, blank frames, reader writes and final tail distance. Each PR must still pass official CI on its final head.

Current mainline integration

The final source includes mainline tool cancellation/liveness (#9901) and provider settings (#9907). The extracted startup lifecycle now routes directly to provider setup, preserving cancellation and navigation-generation fences; a late probe cannot override a newer page or publish after unmount. The obsolete key overlay is removed. Generation-renewed viewport subscriptions and batched prepend settlement are integrated with the first-materialization/origin model. Deterministic tests cover retired ResizeObserver delivery, origin removal while prepend owns the transaction, and startup navigation/teardown. Provider behavior remains the current mainline implementation.

Validation and delivery

The final source da6e8f0237590ba44608dcc8dd467d712ac38b3a passes all 320 discovered frontend suites, dedicated test groups and long-history performance contracts. Production TypeScript, hook/AST/style checks, repository lint, full build and measured resource budgets pass. Chromium/WebKit App replay covers navigation, three layouts, source-bound send and Stop without page errors. Independent source review found no new blocking security or concurrency issue.

Final-head CI completed successfully with all 17 jobs. Desktop ordinary and race tests, Windows replay/WebView2 selection and scrolling, and Wails native startup pass. The 1,951-row native fixture passes GTK (984 frames) and WKWebView (4,521 frames), with zero reverse displacement, zero final tail distance and 64 additional rows followed at the tail.

The remote rejection regression fails deterministically before the owner repair; focused lifecycle races, full desktop tests and race sweep pass. The real-SFTP bootstrap release-handoff regression and repeated race cases pass. Current mainline Stop, sessioncatalog, recovery, tool cancellation/liveness and provider behavior are preserved. Origin/prepend settlement and viewport generation replacement have deterministic combination coverage; startup setup probes cannot override newer navigation or publish after disposal.

Final-head memory screening passed its complete three-process aggregate on this exact source: three distinct processes, 896 round trips each (2,688 total), one build/configuration/browser/attempt identity. Each distinct process must complete 128 full + 128 windowed + 128 safety + 512 mixed round trips. Aggregation rejects incomplete or duplicate shards, different source/build/configuration/browser/attempt identities, page errors and persistent screening drift. Automated screening does not establish offline heap-retainer or mainline-control attribution; those remain explicitly outside the automated verdict. The complete same-attempt aggregate is verified. Refs #9777.

Documentation-impact: updated - English and Chinese architecture, acceptance and ownership contracts describe the final boundaries and evidence limits.
Cache-impact: low - inherited development AGENTS.md architecture instructions change; application provider-visible prompt, request and history bytes remain unchanged.
Cache-guard: geometry, input, source-bound command and lifecycle regressions preserve ownership; the independent backend prerequisite tests unchanged canonical history and provider projections for rejected cancelled requests.
System-prompt-review: Codex reviewed the development-instruction update; application system-prompt construction and serialization are unchanged.

…sources

Problem: asynchronous App actions and cleanup can outlive the session or
controller that initiated them, especially across background cancellation
and A-to-B-to-A navigation.

Root cause: mutable active-view state and independent effect cleanup were
used as authority for pending operations and shared subscriptions.

Fix: wire committed source-bound command owners, canonical controller
cancellation, generation fences, navigation receipts, and subscription leases
into App composition. Keep the runtime root and page tree together for this
slice. Add a separate three-runner memory screening workflow that verifies
one clean build, complete protocols, and unique same-attempt shard evidence.
Document the remaining offline heap-retainer and control attribution duty.

Verification: 302 frontend discovery suites; App lifecycle and real browser
replay; production/test typechecks; production build and measured bundle
budgets; repository lint; 21 memory protocol/path negative tests; actionlint;
focused independent security review of workflow permissions and aggregation.
Carry the final settings fixture migration and merged pure-kernel base into the ownership slice. The production tree is unchanged, preserving the independently reviewed ownership boundary.
Include the linked bilingual acceptance contract from the renderer parent. The frontend source and build inputs are unchanged.
Problem: the migrated command owners still share a large App entry with the
entire page tree, obscuring the source-authority and presentation boundary.

Root cause: runtime composition and JSX assembly remained in one module;
context and subagent presentation code also remained in eager consumers.

Fix: retain the original hook and command order in AppRuntime, render the
same stable regions through AppRuntimeView, and make App.tsx a small facade.
Extract pure context helpers and lazy subagent presentation with preserved
live outcome tuples and historical output parsing. Enforce the entry and
transitive AST layer contracts, remove the obsolete App size allowance,
reduce remaining ContextPanel debt, and ratchet measured raw assets to
2381.3 KiB for the 2381.2 KiB result. Keep independent memory screening.

Verification: all 302 discovered suites plus the remaining test:all groups;
App lifecycle and actual browser replay; typechecks; production build and
bundle budgets; AST negative fixtures and repository lint; independent
read-only review of hook order, command provenance and outcome compatibility.
Include the updated settings and renderer parents and their bilingual acceptance documentation. Preserve the final shell extraction and memory protocol unchanged.
@github-actions github-actions Bot added the v2 Go rewrite (1.x) — main-v2 branch, active development label Sep 7, 2026
@github-actions github-actions Bot added desktop Wails desktop app (desktop/**) config Configuration & setup (internal/config) labels Sep 7, 2026
Record the renderer parent integration of the final legacy fixture ownership test. This merge leaves the ownership implementation and memory build inputs unchanged.
Keep the final shell and presentation source unchanged while recording the current settings, renderer and ownership parent commits for independent CI qualification.
Carry the reviewed renderer batch-to-geometry fix into the session ownership slice. Preserve the session command and lifecycle boundary while qualifying the updated renderer with this slice.
Carry the approved measurement transaction through the final App composition. Keep shell extraction behavior unchanged and run the complete native and App memory qualification on the resulting head.
Problem: Layout scroll observations and stale pointer releases could detach tail following without current user input. Root cause: scroll geometry and input-release callbacks lacked distinct intent ownership. Fix: Integrate the kernel input lease and release identity correction from the renderer slice. Verification: Renderer transcript, Chromium/WebKit suites and type checks passed; this slice production build passes at 2408.2 KiB raw with an attributable 0.2 KiB increase.
Problem: Tail following and newer gestures could be displaced by layout observations or stale releases. Root cause: Intent ownership was not distinct from geometry and queued callbacks. Fix: Integrate the reviewed renderer correction through the ownership slice. Verification: Production build and bundle gates pass at 2381.4 KiB raw; the measured 0.2 KiB increase preserves the deferred shell boundary.
Fix: Incorporate the renderer branch ancestry update after both prerequisite slices merged. Verification: The merge changes no production files and retains the validated ownership and input-intent tree.
Fix: Carry the merged prerequisite ancestry through the ownership stack so pull-request validation can run on the current base. Verification: The merge preserves the previously validated app-shell tree without production file changes.
Carry the shared measurement publication and native input contracts into the session ownership slice, including its independent cancellation prerequisite.
Keep the App shell slice on the same measured geometry publication and input ownership implementation as the preceding session ownership slice.
@github-actions github-actions Bot added the agent Core agent loop (internal/agent, internal/control) label Sep 7, 2026
Problem: rejected remote session opens could publish an error while observers still saw the rejected session identity.

Root cause: failure state publication and restoration of the previous selection had separate owners, allowing reconnect or later selection work to interleave.

Fix: commit restoration and failure state through one revision-checked completion owner. Order route metadata, terminal state, close and generation replacement with the existing publication fence; cover HTTP, busy, listing, missing-target and reconciled transport failures.

Verification: deterministic regression failed before the repair. Remote tests, five race repetitions of rejection and lifecycle cases, full desktop tests, full desktop race tests, golangci-lint and repository lint pass. No public API, persisted format or provider prompt bytes change.
Keep the presentation slice on the reviewed session-ownership implementation. The remote failure owner restores identity before publishing errors and fences competing lifecycle transitions. Full desktop tests and race tests pass on the shared implementation.
Problem: concurrent clients could fail to open a remote workspace when the serve owner released its lock between a failed mkdir and Stat.

Root cause: lock acquisition treated a missing observation as a permanent creation failure. A frontend wiring check also still referenced the replaced post-publication rollback helper.

Fix: recontend through exclusive mkdir once per missing observation for structured contention-capable errors. Bound consecutive ambiguous failures and preserve cancellation, permission and transport errors. Test real SFTP release ordering and update the async handoff contract; leave stale-lock reclamation unchanged.

Verification: deterministic regression fails before the repair. Bootstrap race tests, bounded-error cases, root lint and repolint pass. The root suite passed except an unchanged control timeout; its full package passed on one isolated rerun. All 302 frontend suites and remaining test:all groups pass. No API, persisted-format or provider-byte change.
Inherit the bounded bootstrap lock-release handoff repair and current async wiring check from the ownership slice. Its deterministic SFTP regression, race tests, lint and full frontend test:all pass; presentation assets remain unchanged.
Problem: native GTK scrolling could reverse visible rows after input paused,
even when the scroll writer accepted no reader writes.

Root cause: newly mounted rows inherited estimates until the reader lease
expired. Releasing their accumulated size debt then moved later visible rows.
Short Markdown parsing added another asynchronous first-paint handoff.

Fix: measure new DOM before paint, preserve existing visible coordinates with
a generation-bound window origin, and acknowledge only the complete prefix.
Preload the history renderer and synchronously format bounded windowed answers;
large worker results still format automatically after active input ends.
Keep the native single-writer and existing safety thresholds. Normalize the
small attributable raw bundle delta from 2408.2 to 2408.5 KiB with a 2408.7
KiB ceiling. Model native extent clamping in the deterministic DOM harness.

Verification: fixed-height regressions cover both estimate directions,
reverse travel, input release and the leading edge. Markdown tests, viewport
tests, production build, repository lint and isolated GTK diagnostic replay
pass. Final-head browser and CI qualification are tracked in the PR.
Problem: the App presentation slice inherited estimated first-paint geometry
that could move visible rows when native input ended.

Root cause: the shared renderer deferred measurements for newly mounted DOM.

Fix: integrate the ownership slice repair without changing App composition,
source-bound commands or hook order. Resolve only the independent raw asset
budget: the shell measures 2381.6 KiB, with a 2381.8 KiB ceiling.

Verification: the integrated shell passes the production build, TypeScript,
hook and AST layer gates, CSS contracts and all bundle budgets. Shared repair
passes 303 frontend suites, performance, Chromium/WebKit reader replay and
App browser lifecycle checks. Latest-head native and memory gates remain
required before merge.
Problem: the safety browser gate could fail with no selection before the
fault transition, instead of testing whether a real selection survives.

Root cause: its text walker included the Compress toolbar label, which is
visible but not a native text-selection target.

Fix: select only the existing transcript-selectable surface and exclude
interactive controls. Require a real native selection and selection ownership
before injecting the geometry fault. Retain every post-transition identity,
selection, displacement, zero-write and memory assertion unchanged.

Verification: the original replay captured Compress as its drag target and
no selected text before the fault. The corrected full browser replay covers
24 safety cycles with real drag selection, pointer holds and tail ownership.
Problem: a toolbar label could satisfy the old visible-text fixture while
never establishing the selection the safety transition was meant to retain.

Fix: integrate the shared browser fixture correction and its pre-fault
selection assertion. Production files and bundle contents are unchanged.

Verification: all 24 browser safety cycles pass, including real native drag
selection, reader holds, tail ownership and zero page errors. The inherited
production build and Chromium/WebKit reader replay remain unchanged.
Problem: enlarging an offscreen predecessor could move the held reader by
its full growth (371px in the Windows browser replay).

Root cause: measurement selected the first visible block from already changed
DOM bounds. The enlarged predecessor became visible and replaced the real
input-captured anchor before the new prefix was committed.

Fix: ordinary size publication retains the Kernel anchor. Only window-origin
removal supplies a coordinate-conversion anchor, selected from the previously
committed prefix and its old sizes. An untrusted new DOM rectangle cannot
claim reading ownership. Preserve existing transaction priorities and fallback
to the Kernel anchor when no cold prefix candidate is available.

Verification: deterministic predecessor-growth regressions fail before the
repair and pass after it for both estimate directions. The model also covers
mid-history origin release, leading-edge continuity and input write exclusion.
Production build and repository lint pass; affected transcript and browser
gates are rerun before publication. Architecture contracts document the owner.
Problem: a growing offscreen predecessor could replace the input-captured
reading anchor during shared renderer measurement.

Fix: integrate the verified Kernel-anchor publication repair and committed
prefix origin conversion. App runtime composition and action owners are
unchanged, as are the independent shell asset budgets.

Verification: the shared repair passes deterministic red/green regressions,
complete transcript tests, TypeScript, production build, repository lint,
Chromium/WebKit reader replay and all 24 safety browser cycles. The integrated
shell build and latest-head official gates are checked before merge.
Problem: main-v2 advanced while the split renderer was being qualified,
leaving an asset-budget conflict and stale integration coverage.

Fix: merge main-v2 4947013, preserving session-level Stop, its original-tab
reconciliation, the stale sessioncatalog repair and the source-bound App
owners. Retain the mainline locale ceiling. The integrated raw payload is
2408.7 KiB; set the smallest rounded 2408.9 KiB ceiling with 0.2 KiB headroom.

Verification: production build and bundle gates pass. Frontend Stop
reconciliation passes 31 checks; focused desktop Stop race tests pass.
Independent read-only review confirms same-tab cancellation, controller
identity and remote rejection publication ownership remain compatible.
Complete App lifecycle and control/sessioncatalog race gates are tracked
before latest-head CI qualification and merge.
Problem: mainline Stop and catalog fixes advanced while the split was being
qualified, and the raw bundle ceilings conflicted across the two layouts.

Fix: retain the mainline behavior with the split runtime composition and
same-tab cancellation owner. The integrated shell measures 2381.8 KiB raw;
its narrow ceiling is 2382.0 KiB, with the inherited locale limit unchanged.

Verification: production type, hook, AST, CSS and build checks pass; the raw
asset gate passes with measured headroom. The shared merged base passes
Stop frontend/desktop race, control and catalog race, App lifecycle and
actual App browser checks. Later mainline updates remain to be integrated.
Problem: mainline recovery-wait and rejection-containment fixes advanced
while App effects were extracted, conflicting with the old App subscription.

Fix: merge main-v2 17a81d7 and preserve the recoverable-error toast through
the shared App effect owner. A committed callback prevents layout-teardown
delivery while effect cleanup removes the one global subscription. Keep the
mainline rejection classification, warning severity and six-second duration.
Raw startup assets measure 2411.3 KiB after the inherited UI changes; retain
a narrow 2411.5 KiB ceiling rather than the obsolete pre-recovery budget.

Verification: lifecycle regression covers StrictMode, 32 callback replacements,
latest-sink delivery and layout teardown. Recovery crash classification,
lineage-dialog and wait-banner tests pass. Production build/type/hook/CSS and
asset checks pass. Independent read-only review found no lost feature or
new subscription ownership defect. Owning Go and App browser checks complete
the integrated-base qualification before final-head CI and merge.
Problem: mainline recovery notifications lived in the old App effect while
the presentation slice had moved runtime ownership to shared composition.

Fix: integrate the shared App effect owner, latest committed toast delivery,
recovery wait UI and error containment. Preserve the bridge-free App facade,
AST layer boundaries and deferred presentation assets. The integrated raw
payload is 2384.5 KiB; its narrow ceiling is 2384.7 KiB.

Verification: production type/hook/AST/CSS/build and measured asset gates
pass. The shared subscription lifecycle test passes on this composition.
Owning recovery frontend and Go race checks, independent source review and
App browser integration pass in the parent slice. Latest-head official CI,
native smoke and complete memory screening remain merge gates.
…ship

Problem: Mainline advanced with the separately reviewed tool cancellation and liveness fixes while the split PR was qualifying.

Root cause: The pending ownership slice shared controller and tool presentation paths with the new mainline revision.

Fix: Integrate main-v2 without changing source-bound command or cleanup ownership. Normalize the measured initial raw bundle ceiling from 2411.5 to 2411.9 KiB for the inherited UI growth (2411.7 KiB actual).

Verification: Agent and control package race suites pass, all 26 tool elapsed/liveness frontend tests pass, production type/build gates and bundle check pass, repository lint is clean, and the production App browser lifecycle gate passes. Independent integration review found no new blocking issue. Final-head remote CI and full memory protocol remain required before merge.
Problem: The final presentation slice must include the qualified current-mainline ownership integration.

Root cause: Mainline added tool elapsed UI, bounded cancellation and controller liveness while the split was qualifying.

Fix: Carry the source-owner integration into the extracted shell and preserve its separately measured bundle ceiling (2384.9 KiB actual, 2385.1 KiB limit).

Verification: Production type/layer/hook/build checks and the exact build budget pass; the shared agent/control race suites, 26 elapsed/liveness frontend tests, repository lint and App browser lifecycle passed in the owning slice. This intermediate local merge is followed by the newly arrived provider settings integration before final qualification.
Problem: Mainline provider settings integration changed App startup navigation and transcript lifecycle while the ownership slice was qualifying.

Root cause: The new mainline implementation retained the pre-extraction App and renderer boundaries, overlapping the split owners.

Fix: Keep the source-bound App composition and first-materialization/origin geometry model. Integrate generation-renewed native viewport subscriptions and batched prepend settlement. Route first-run setup through the existing startup lifecycle with cancellation and navigation-generation guards; remove the obsolete onboarding overlay and retain the provider setup banner until configuration succeeds. Carry mainline provider behavior and normalize only measured integrated bundle/locale ceilings.

Verification: Full transcript suite, native viewport generation tests, origin/prepend combination tests, startup navigation and unmount tests, 54 provider picker checks, onboarding commands, startup contract, production types/build checks, exact bundle checks and App browser lifecycle pass. Repository lint is clean. Full frontend discovery and final-head remote CI/memory protocol remain required before merge.
Problem: Mainline provider settings and viewport fixes must coexist with the final extracted App shell before delivery.

Root cause: The mainline startup and rendering changes overlapped the split lifecycle and presentation boundaries.

Fix: Carry the ownership slice integration without restoring App-local async effects or the obsolete onboarding overlay. Preserve lazy shell boundaries and use the measured 2398.2 KiB raw bundle with a 2398.4 KiB ceiling.

Verification: Production build, TypeScript, AST layer contracts, hooks, CSS and bundle gates pass. The final shell App browser lifecycle passes navigation, three layouts, source-bound send and Stop. Shared transcript, native subscription, origin/prepend, provider picker and startup lifecycle tests pass in the ownership slice. Final-head CI and complete memory screening remain required before merge.
@SivanCola
SivanCola marked this pull request as ready for review September 7, 2026 17:16
@SivanCola
SivanCola requested a review from esengine as a code owner September 7, 2026 17:16
@SivanCola
SivanCola merged commit 401fca4 into esengine:main-v2 Sep 7, 2026
38 of 40 checks passed
SivanCola added a commit that referenced this pull request Sep 8, 2026
Problem: The generated draft referenced 30 of the 38 pull requests merged since
v1.38.1, and no entry mentioned the transcript renderer replacement, the
Standard/Deep session display setting, or the provider connection and model
preference redesign, even though each pull request describes user-visible
behavior.

Fix: Add three bilingual entries with their pull-request references to both the
highlights and the categorized changes lists - transcript renderer replacement
(#9893, #9895, #9896, #9897), Standard and Deep session display (#9894), and
independent model connections and model preferences (#9907).

Verification: node scripts/release-notes.mjs validate (61 releases);
node --test scripts/release-notes.test.mjs (10 pass); the rendered v1.38.2 notes
inspected in both languages; git diff is additions only.
SivanCola added a commit that referenced this pull request Sep 8, 2026
Problem: The generated draft referenced 30 of the 38 pull requests merged since
v1.38.1, and no entry mentioned the transcript renderer replacement, the
Standard/Deep session display setting, or the provider connection and model
preference redesign, even though each pull request describes user-visible
behavior.

Fix: Add three bilingual entries with their pull-request references to both the
highlights and the categorized changes lists - transcript renderer replacement
(#9893, #9895, #9896, #9897), Standard and Deep session display (#9894), and
independent model connections and model preferences (#9907).

Verification: node scripts/release-notes.mjs validate (61 releases);
node --test scripts/release-notes.test.mjs (10 pass); the rendered v1.38.2 notes
inspected in both languages; git diff is additions only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Core agent loop (internal/agent, internal/control) config Configuration & setup (internal/config) desktop Wails desktop app (desktop/**) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant