Skip to content

[Feature]: Harden Control UI Lit lifecycle boundaries #102423

Description

@steipete-oai

Summary

Harden the Control UI's Lit lifecycle boundaries around external subscriptions, post-render work, routing, localization, and chat persistence.

Problem to solve

The Control UI already uses Lit 3, but many elements still manage store subscriptions with paired fields and connectedCallback/updated/disconnectedCallback bookkeeping. The repeated lifecycle code has produced concrete ordering gaps: late context requires retrying subscription setup from updated(), locale changes do not invalidate every mounted element, router pending/not-found work can survive a disconnect, and chat commit/scroll/persistence effects can run after their owning pane is gone or before state is actually rendered.

Proposed solution

  • Introduce application Lit base elements that own locale invalidation and the shared light-DOM policy.
  • Introduce a reconnect-safe ReactiveController for lazy external-source subscriptions, including late source arrival and source replacement.
  • Move router pending and not-found lifecycle state behind a dedicated controller with a thin Lit host.
  • Give chat a renderer-neutral invalidate/after-commit seam, deterministic teardown, and disconnect-safe scroll and draft persistence.
  • Keep the current production decorator configuration; Lit's current guidance still recommends experimental decorators for compact production output.

Alternatives considered

  • Migrating to standard decorators: newer syntax, but currently larger emitted output and no lifecycle correctness benefit.
  • Adopting Lit Labs signals/compiler packages: unnecessary and not stable enough for this boundary.
  • Leaving each element's manual cleanup in place: preserves the repetition and the existing lifecycle races.
  • Replacing Lit with another framework: much higher migration cost without addressing these local ownership problems first.

Impact

Affected: Control UI users and maintainers.

Severity: medium. Most failures are edge cases around reconnects, route changes, locale changes, final chat updates, or immediate navigation after typing.

Frequency: lifecycle-dependent and intermittent.

Consequence: stale UI, missed post-render updates, incorrect pending navigation behavior, or a draft not being flushed when a chat pane disconnects. The shared controller boundaries also remove substantial repeated cleanup code and make future UI changes safer.

Evidence/examples

  • ui/src/app/app-host.ts retries an eight-subscription setup from updated() because context/runtime may arrive late.
  • ui/src/components/app-sidebar.ts, ui/src/pages/sessions/sessions-page.ts, and ui/src/pages/workboard/workboard-page.ts repeat the same pattern.
  • Only the Overview page currently owns the locale invalidation controller, while shell/sidebar/page elements independently render translated strings.
  • ui/src/app/router-outlet.ts retains pending state across AsyncDirective disconnect/reconnect and queues an unguarded not-found microtask.
  • ui/src/pages/chat/chat-state.ts registers composer persistence after the outer controller but clears the shared state first during disconnect.
  • ui/src/pages/chat/scroll.ts mutates rendered indicator state after commit without invalidating and does not cancel every frame/retry on teardown.

Additional information

This is a maintainer-requested modernization slice. It intentionally preserves public behavior, the current ApplicationContext capability contracts, and the existing Lit decorator mode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.enhancementNew feature or requestimpact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.maintainerMaintainer-authored PR

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions