* feat: start remote sessions without a repository
Offer a fresh isolated workspace for cloud and paired-device sessions while preserving explicit and saved repository choices. Use a private empty backing repository per session through the existing managed-worktree lifecycle, retaining reclaim, snapshot restore, and cleanup without copying the agent workspace.
* fix: preserve workspace intent and independent snapshot cleanup
Retain legacy source selections before Git discovery updates availability, keep ordinary snapshot expiry independent of allocation contention, and update the complete source-selection browser flow. Keep request mapping and validation at their existing owners while satisfying import-cycle and export checks.
* fix: retain allocation and cleanup error causes
* test: expect normalized workspace source preferences
* feat(macos): collapse completed chat work above replies
Keep final answers and attachments visible while completed commentary and tool activity fold into a reversible disclosure. Preserve phase and turn metadata, retain split native transcript projections across history refreshes, and keep active or unresolved work exposed.
* fix(macos): preserve commentary segment identity through replay
Use the Gateway segment marker to distinguish commentary from canonical messages, preserve it through native cache copies, and keep it out of answer settlement. Retain canonical identity across reasoning framing changes so cached and live finals converge.
Promote canonical task titles in native and web subagent activity rows while keeping status and progress separate. Gateway summaries already prefer the configured task label, with a bounded task-text fallback. Preserve generic labels when no title is supplied.
* feat(dashboard): save shared fullscreen and split defaults
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(dashboard): preserve transient and legacy presentation intent
Keep command-driven route activation and cross-tab personal choices separate from shared defaults. Restore offline layouts, keep ordinary renders storage-free, refresh generated protocol models, and cover the affected Gateway and UI boundaries.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(dashboard): preserve cross-tab choices and keyboard defaults
Keep personal override writes with the persistence owner, share the opening decision across keyboard and rail controls, and preserve prepared sidebar content during initial reconnect observation.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
---------
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* feat: give every plugin a compact chat activity icon
Separate package-owned activity SVGs from plugin identity artwork. Ship 154 defaults and seven exact tool overrides, preserving Echo and the progress claw. Include authenticated bounded delivery, safe mask rendering, packaging, and authoring guidance.
* test: declare Vite types for the activity asset browser test
* refactor: keep plugin artwork selection with catalog presentation facts
* test: scope activity browser types and simplify fixture copies
* feat: load CDN libraries and fonts in widgets
Share public static-resource origins across document, sandbox, and channel policies while keeping API access and native Gateway pins separate. Add visualization guidance for inline code explanations and persistent dashboards.
* fix: preserve local widget renderers in direct hosting
Keep document-approved same-origin renderer scripts available in the intersecting HTTP CSP. Cover stored and newly wrapped registered documents without granting API connections.
* fix: hide subagent sessions from Activity
Filter subagent sessions before search, facets, counts, and pagination so Activity stays focused on conversations. Preserve normal nested sessions and existing diagnostic listings.
* test: use the stored session label in Activity regression
* style: group session key predicates by their owning module
* fix: high Gateway CPU while viewing diagnostics
* test: match agent selection observer contract
* test: exercise diagnostics replacement through initial load
* feat(ui): keep open files in shared sidebar tabs
Give chat files named tabs in the existing shared strip and retain their view and editor state. Keep workspace browsing and original downloads, honor explicit line links in reused tabs, and isolate split-pane focus.
Closes#146655
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* feat(ui): render HTML in file tabs
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix: synchronize HTML preview protocol and CI fixtures
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
---------
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* feat(voice): unify Live sessions across calls and meetings
Resolve provider capabilities and interruption policy through the shared realtime voice owner. Keep meeting input isolated from virtual-microphone output, reuse native delegation for meetings and Voice Call, and preserve explicit Stop across browser and Apple relay clients.\n\nValidated with real Live API and synthetic Chromium/WebRTC proof, focused regressions, changed-file checks, and independent review. Related to #146289.
* test(voice): align capture fixtures and validation gates
Model browser audio capture in the shared meeting RPC fixtures so startup
failure tests reach the provider and verify capture cleanup. Preserve the
same relay startup behavior while simplifying duplicate lifecycle branches.
Rebalance the pre-existing 702-root platform test graph by moving security
tests beside sandbox/tool tests; keep coverage, graph counts, and limits.
* fix(meetings): preserve configured input commands
Keep explicitly configured capture/filter/mixer output as provider input on
local Chrome and paired nodes, preserving the v2026.9.4 contract. Generated
input and output-only overrides continue to use managed browser capture.
Retain Live's isolation guard and explain how to remove an input override
when selecting Live. Prove the actual PCM paths through both meeting engines
and transports, and document the preserved configuration behavior.
## What Problem This Solves
The first web model picker open could wait seven seconds for a catalog reply. A late initial snapshot could also restore an old saved account after the user changed it.
## Why This Change Was Made
Publish the existing catalog during connection setup through the authenticated request dispatcher. Initial and ordinary replies use the same cache publication checks, so delayed work cannot replace a newer session selection.
## User Impact
Published choices appear on first open and reconnect while discovery continues. Warm reopen stays fast, without an extra catalog request from opening the picker.
## Evidence
With catalog replies held for seven seconds, the original picker had no usable choices until the reply. The corrected New Session and active-chat pickers showed rows within 100 ms; warm reopen took 8–12 ms. Neither open added a request.
Real browser/Gateway tests cover reconnect and a saved-account change before snapshot completion. Sixteen valid configuration fixtures start; an invalid legacy fixture rejects as expected. Previous-version source builds connect in both directions; installed-release upgrades were not tested. Full consumer analysis: `consumers.md`.
## Compatibility
The new connect field is sent only after server advertisement. Clients without opt-in receive no snapshot. No protocol-version bump, configuration key, database change, or migration.
## Consumers
- New Session picker: uses published rows before its ordinary catalog reply.
- Active-chat picker: receives the saved session's model/account projection and retains newer selections.
- Mounted browser shell: preserves initial publication across reconnect.
## Invalidation
Connection, identity, configuration, session metadata, session mutations, and explicit refresh retire stale reads. Expiry and eviction retain publication ordering; delayed results cannot refill invalidated state.
## Contention
Snapshot publication adds no lock, transaction, or await. The existing dispatcher owns catalog reads; the common cache owner admits results synchronously.
## Tests
Browser picker tests exercise fresh, saved-session, refresh, and reconnect flows. Gateway tests enter connect, `models.list`, and `sessions.patch`. Handshake, cache, metadata, and sibling checks pass. The shared test partition guard passes with the server grouping from #146212. Full automated validation is still required.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Publish static model choices after sign-in, then let the existing provider-scoped catalog owner acquire and publish account models, including late results. Keep ordinary model menus and picker opens passive, retain rows during renewal, and fence results after account changes.
Validated with registered Gateway tests, Telegram and browser flows, previous-release state and SDK contract checks, and successful CI.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
A divergent database copy for one agent no longer refuses the whole Gateway at startup. That agent is refused with a typed reason visible in status and Doctor while healthy agents keep running. Repairing the files and restarting clears the refusal; the default and configured system agents stay fatal.
Startup owns the process-local admission decision. Routing, cron, session scans, status, and Doctor consume it while preserving divergent files. The protocol projection adds optional response metadata without a version bump; no durable admission state or config option is added.
Regression evidence includes failing-before/passing-after admission and consumer-boundary tests, isolated Gateway service/refusal/recovery proof, and successful exact-head pull_request CI. Published-updater-to-candidate and native Windows proof remain unverified; the maintainer accepted that bounded gap for this landing.
Fixes#144689. Refs #145252.
Reported by @steipete in #144689.
* feat(openai): support public GPT-Live-1 voice sessions
Adapt public Live sessions, startup events, delegation, audio, captions, and
Platform authentication through the existing OpenAI voice plugin. Keep the
Codex subscription transport separate.
Persist public WebRTC transcripts through the Gateway and drain provider
finalization before releasing voice session owners across relay, Discord,
Voice Call, and MeetingBot. Preserve synchronous bridge disposal.
Validate targeted protocol and lifecycle regressions, authenticated synthetic
voice and WebRTC flows, and the iOS Simulator app build.
Closes#145071
* fix(voice): preserve cleanup and package boundaries
Keep the OpenAI capability catalog cold, remove the delegation type cycle, and expose portable Google mock declarations. Route failed call startup through the existing binding cleanup owner and stop failed local audio processes while provider finalization drains.
* fix(ui): preserve public Live caption fragments
Carry explicit verbatim semantics through the browser transcript pipeline so split words, repeated fragments, whitespace, and overlapping speakers bypass legacy ASR heuristics. Keep Gateway-only persistence and avoid synthetic final or item events.
* test(openai): expose portable delegation mock types
Use public logger and gateway callback contracts in test helpers so declaration-enabled plugin package compilation does not reference private Vitest types. Verified declaration compilation for all six affected plugins and test callers.
* fix(openai): wait for delayed GPT-Live delegation transcripts
Retain metadata-only public delegation notices while user captions are empty, resume through the existing admission owners when text arrives, and claim notice IDs before callbacks to prevent duplicate work. Bound pending notices and missing-input waits; revoke them during close, cancellation, and transcript drain. Preserve subscription prompt fallback behavior.
Validation: 103 focused tests pass; new regressions failed against the original behavior. Independent P0-P2 autoreview is scoped-clean. Combined type/lint gates are owned by the landing checkout because declaration boundaries reject this worker worktree borrowed compiler install.
* feat(openai): select GPT-Live Talk defaults by account
Resolve unpinned Talk models with the selected agent account and session requirements. Platform credentials select public GPT-Live; ChatGPT-only accounts select the subscription voice model. Preserve explicit model pins, manual responses, video, Azure, and direct tool bridge defaults. Keep catalog discovery aligned with session creation without rewriting saved config.
Validation: 177 focused tests pass; scope and account regressions fail on the prior owners. Authenticated microphone-to-delegation-to-spoken-answer proof passes with 211200 audio bytes and awaited completed shutdown. Core and plugin production/test typechecks pass; independent review through P2 is scoped-clean. Full changed-file guards continue in the landing workflow.
* test(openai): isolate Talk account default coverage
Keep the routing suite below its existing line limit by reusing its fixtures in a focused defaults suite with injected host auth. Use explicit blocks in the live audio fixture. Production behavior is unchanged.
Validation: all 61 routing/default tests, extension test typecheck and typed lint pass; independent P0-P2 review is scoped-clean.
* refactor(openai): split realtime delegation dispatch and tests
Keep direct bridge admission and dispatch in a focused local owner, reuse the existing bridge fixture across a dedicated delayed-delegation suite, and apply the required block style. Preserve lifecycle checks, callback binding, transcript publication and subscription behavior without relaxing file budgets.
Validation: 103 focused tests pass across five files; independent P0-P2 autoreview is scoped-clean. The landing lane owns canonical typed validation of the combined candidate with physical dependencies.
* test(openai): expose portable bridge mock callback types
Use public Mock annotations tied to the realtime callback and logger contracts so exported bridge fixtures emit declarations without Vitest private Procedure types.
Validation: actual OpenAI declaration emission and extension-test typecheck pass after reproducing TS2883 before the fix; 40 helper-consumer tests pass; independent P0-P2 autoreview scoped-clean.
* fix(openai): preserve camera-capable Talk defaults
* fix(talk): align browser capabilities with launch models
Resolve optional provider and model overrides through the existing Talk catalog before browser camera negotiation. Preserve other provider rows and explicit model choices, while unpinned OpenAI Talk follows the requested GPT Live account defaults.
* fix(ui): avoid shadowing Talk provider selections
* fix(ui): clarify model authentication and prevent overlapping controls
Show available credential methods and account identity in Models settings,
including the global Auto utility model resolved by the Gateway. Keep
provider connection separate from model setup, use a compact discovery
spinner, and keep tablet labels and controls side by side.
* test(ui): align Models catalog expectations with utility previews
Preserve the accepted client type in presence and restore it with the connection mode after cache eviction. Display Terminal for TUI connections while retaining App for native clients.
* feat(desktop): match virtual worker displays to the viewport
Keep Fit as the default and gate Match on provider-owned resize permission and authenticated controller ownership. Preserve sizing choices during reconnects and retire resize authority with input control.
Pass resolved SSH VNC credentials through optional auth metadata and reconcile lost physical modifier releases after native popups. Add instrumented production Gateway/XFCE resize proof and native selection regressions.
* fix(desktop): align renderer exports and suppression inventory
* test(desktop): cover real node carrier resize qualification
* test(workers): align repository access provider fixture
* fix(ci): run real desktop resize proof with an upstream fixture
* fix(ci): bind desktop proof to raw merge identity
* fix(ci): retain safe desktop proof failure diagnostics
* fix(ci): expose safe desktop SSH setup diagnostics
* fix(ci): keep desktop proof phase tuple private
* fix(ci): retain desktop proof phase after timeout
* fix(ci): observe Gateway startup at desktop proof timeout
* fix(ci): run desktop proof against built Gateway
* fix(ci): assert visible desktop recovery state
* fix(ci): remove retired desktop spy allowance
* test(ui): model targeted desktop status in sizing fixtures
* feat(sessions): automatically archive inactive transcripts
Add opt-in worker maintenance, live storage settings, and exact restoration from compressed JSONL archives. Advance the agent schema to 20 and embed verified cold payloads in supported backups.
* fix(sessions): preserve cold history across reads and lifecycle actions
Restore archived history before channel context, latest-text reads, reset and fork operations. Preserve legacy schema migration preflight and steering transcript order; regenerate native protocol bindings and repair the Windows cleanup fault fixture.
* fix(ci): regenerate plugin assets and rebalance cold storage tests
* fix: harden updater validation and account selection
* fix: keep Mac desktops available and resolve session views directly
Keep authorized Computer executions awake with bounded native assertions, report locked/unknown desktop state, and offer explicit unattended hosting. Manual lock and route retirement revoke old executions without disturbing a successor or unrelated held input.
Resolve session desktops through exact session and environment status before unrelated inventory. Preserve retry for transient errors, recover missing sources to the picker, and refresh availability when the presenter reconnects.
* test: keep node host alive for inventory assertions
* refactor: remove unused Mac service protocol requirement
* fix(macos): preserve desktop parameter errors
Preserve command-specific malformed snapshot and computer.act errors at the execution-envelope guard, using the existing decoder and a shared response formatter. Include unattended hosting in the existing consent and setting-coercion coverage tables.
Verified the four original CI failures and eight lifecycle siblings with a signed Intel payload in an isolated native test run. Swift lint, formatting, schema guard, and independent review passed.
* fix(macos): preserve literal desktop error responses
Keep the two complete diagnostic strings at the response boundary so native translation discovery does not interpret a temporary command label as UI copy. The selection predicate, error code, and response messages are unchanged.
Verified unchanged native i18n inventory and generated artifacts, strict Swift lint and formatting, an isolated Intel compile, and independent review. Existing signed native regression proof remains applicable to the identical output contract.
* fix(macos): read console state from the registry root
The IOService plane root can be the hardware entry and omit IOConsoleUsers,
leaving an unlocked desktop unavailable to Computer work. Use the registry
root accessor while preserving CFBoolean, UID, lock, and release validation.
Live signed Swift proof calls the actual platform method before and
after the accessor repair on macOS 15.7.9.
* fix: refill prepared workers after session worktree cleanup
Retain the canonical Git donor while keeping the admitted session commit.
Reuse repository identity for immutable replays and preserve managed archive
snapshot retention. Cover archive removal, immediate Git pruning, store
reopen, pinned refill, bare donors, and idempotency rejection with real Git.
Validation: 130 focused and sibling tests passed, scoped changed checks,
and managed review with the retention finding resolved against the existing
archive owner and forced-pruning regression.
* test(android): await approval reconciliation before reconnect
Wait for the original resolution coroutine to finish its immediate readback
before replacing the test backend. The published unknown-outcome message
precedes that read and was not a completion barrier. Preserve the exact
reconnect request-order assertions and existing timeout.
Validation: causal reproduction of the extra leading get, all 26 approval
runtime tests, app ktlint, and independent review.
* test(android): await complete gateway deadline admission
Read operation readiness through the existing lifecycle owner lock before
advancing virtual time. The operation field is published before its deadline
is registered, so an unlocked read could observe half-completed admission.
Preserve the deadline, cleanup, and replacement-admission assertions.
Validation: causal RED/GREEN, all 53 foreground-service tests, Android
ktlint, and independent review.
* fix(macos): propagate native worker task cancellation
Route Swift task cancellation through the existing worker owner and settle
cancelled calls without waiting for a suppressed child result. Bind queued
cancellation to its exact request reservation and consume that request's
buffered controls when admission is already cancelled.
Clarify that Screen Sharing can explicitly lock a Mac on viewer disconnect;
unattended hosting respects that operating-system boundary.
Signed isolated native proof passed six functions/eight cases, including
active and pre-dispatch cancellation, scoped buffered controls, worker
replacement, and process cleanup. Swift and documentation checks passed.
* test(browser): report tab creation errors before polling
* perf(ui): reuse native embed shape validation
* test(ui): await plugin mutation reconnect before assertions
* test(codex): control native relay retention clock
* fix(workers): cancel reserves and finalize confirmed cleanup
Let environments.destroy cancel an unused automatic reserve through the existing guarded preparation owner before waiting for provider settlement. Preserve claimed workers and admitted capture expiry behavior.
Carry confirmed allocation cleanup through WorkerProviderError.cleanupComplete and the existing teardown finalizer. Retire pending or bound node enrollment before terminal failure and preserve the original provider error. Uncertain allocation and cleanup retain their existing recovery ownership.
Validate with producer/consumer RED-GREEN cases, 53 combined service regressions, provider and ownership siblings, changed checks, and scoped P2 review. Keep separate checkpoint/image recovery obligations with the provider.
* fix(memory): reject views in FTS schema checks
Restore the existing unavailable-FTS fallback when a view occupies the derived index name. Preserve the colliding view and the existing savepoint boundary; table lookup must include views while excluding the independent trigger namespace. The unchanged temporal-ranking regression fails before this repair and passes afterward, with 64 focused cases, changed checks, and independent review passing.
* fix(cua): launch observed Mac apps by native identity
Use the observed bundle ID or name accepted by the pinned Mac driver instead of its unsupported launch_path field. Preserve discovered launch-path precedence on Linux and Windows and the rejection of model-supplied paths. Both Mac regressions failed before the guard; all 21 provider cases, selected changed checks and independent review pass. A fresh signed artifact and native launch proof remain required.
* fix(nodes): republish runner inventory after reapproval
* test(memory): preserve equal-count view collision coverage
* test(ui): wait for chat readiness before submitting controls
* fix(ci): recover stranded hosted tooling capacity
Rebalance one eligible file within its existing tooling family after bounded tail packing overflows. Preserve the 80-job cap, timing floors, complete inventories, process isolation, and ordinary plans.
* test(android): observe promotion before crossing discovery deadline
Use the existing retirement callback to observe reservation before exercising bounded cleanup. Preserve discovery and assertion deadlines and release the held callback during cleanup.
Related: #136257
Projection owner: #144762
## What Problem This Solves
Quick Chat could keep stale model choices after a catalog update and did not expose the published Fast setting. Its picker must preserve the Gateway's availability and thinking decisions, including refusal guidance and selectable rows whose availability is unknown.
## Why This Change Was Made
Quick Chat consumes the shared OpenClawKit catalog projection introduced in #144762. Both chat surfaces now use one Fast-state projection. Model and speed changes use the existing session-settings route lease and target queue, then reload canonical catalog/session state. This removes the partial patch-response model/thinking derivation.
Catalog publications refresh the open picker without losing its draft; late reads cannot replace a reopened presentation. The nonactivating panel preserves Attach text and Paste reply targeting. Native tests exercise the registered shortcut callback and require the panel/editor to present even while the application does not own foreground.
## User Impact
- Refused model rows are disabled with the published guidance; unknown availability remains selectable.
- Effort labels come from the catalog, and speed offers Session default, Fast, and Normal when applicable.
- Settings changes settle before sending. Rejected speed changes preserve the retry key for an unchanged draft.
- Reopening Quick Chat retains the correct catalog and presentation state.
## Evidence
- [Connected native candidate](https://github.com/openclaw/openclaw/actions/runs/34584437164) passes at this exact PR head using the real Gateway fixture from #144762/run 34571594676. A real catalog publication refreshes the same Quick Chat presentation without losing its draft. Clearing a saved speed override and choosing the unknown-availability model both reload canonical session state. No inference server or transport mock was added.
- [Connected baseline](https://github.com/openclaw/openclaw/actions/runs/34585094303) reproduces the missing refresh on main `68b7893b`: the Gateway publishes the new model name, but Quick Chat retains the old name. Build, connection, and publication pass before the stale-name assertion fails. The baseline's existing test guard suppresses its panel, so this is publication-state red, not a visual baseline.
- [Exact-head CI](https://github.com/openclaw/openclaw/actions/runs/34583201846) passed.
- [Final targeted macOS run](https://github.com/openclaw/openclaw/actions/runs/34581841571): app/native builds, 2 XCTest UI cases, 83 Swift Testing cases, and 11 shared projection tests passed. Includes rendered model selection, effort, Fast/default, refused/unknown rows, publication, stale reads, and send retry behavior.
- [Earlier resumed run](https://github.com/openclaw/openclaw/actions/runs/34581142507): the same picker and lifecycle proof passed; its first attempt failed before compilation on an HTTP 500 while downloading SwiftLint.
- [Baseline picker red](https://github.com/openclaw/openclaw/actions/runs/34566007763): refused row enabled, guidance missing, and inferred effort options. The candidate's native menu records show the corrected states.
- The final rebase was followed by 67 passing config/state/recovery tests and real Gateway startup/list/create/command transport checks for all 17 sanitized config fixtures, with fake credentials and external networking disabled. Legacy roster used Doctor repair before startup.
- Focused catalog/auth protocol tests passed. Retained Telegram Test Server `/models` proof returned the provider selector with zero inference requests.
Original and connected native captures were inspected locally and by an independent validator. Artifacts retain native menu JSON, real Gateway/session records, and panel images. Panel captures have clipping/transition limits; they do not establish expanded-menu visual quality. The shortcut proof invokes the registered callback and observes a visible editor with application-active/key-window state false; it does not claim a physical key event, foreground ownership, signing, or permission grants.
The corpus also exposed an unchanged base issue: the generic-token `/models` command advertises an OpenAI fallback while the published catalog is empty. Startup and command transport succeed; complete command/catalog semantic parity is not claimed. This PR changes only native app code and its tests.
No protocol version or schema change. The temporary proof workflow is removed from this PR; its task staging branch is retired and artifacts are retained. No shipped test behavior is deleted; existing fixtures are adapted to the typed settings provider, and the new speed tests cover accepted and rejected writes.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Related: #136257
## What Problem This Solves
Fixes an issue where users of iOS chat and macOS shared chat or Quick Chat could see Fast and thinking choices that did not match the selected model's published capabilities. Model availability and provider sign-in also need to follow the session's Gateway state.
## Why This Change Was Made
The Apple clients now request the direct session catalog and consume its availability, Fast, thinking, input, and route fields. A saved Fast override takes precedence, and thinking choices, labels, and defaults come from one published profile. Unknown availability stays selectable; explicitly unavailable rows show the published refusal guidance and use disabled menu buttons in both shared composer layouts.
Native sign-in shows the owner's code and link, waits for the wizard result, and then reads published authentication state. Connection changes and cancellation retire the captured operation. Older Gateways keep slash commands with update guidance. This removes app-side capability inference and duplicate metadata decoding without a protocol or storage change.
## User Impact
Model controls reflect the selected session and model. Users can complete supported sign-in methods from shared chat without treating a displayed code or browser navigation as successful authentication.
## Evidence
- Baseline projection tests reproduce three regressions in [run 34564827772](https://github.com/openclaw/openclaw/actions/runs/34564827772).
- [The macOS CI job](https://github.com/openclaw/openclaw/actions/runs/34574028270/job/103182622412) passes 1,693 OpenClawKit tests and 2,146 macOS tests on the PR merge. This includes cancellation/failure messages, older-Gateway command fallback, and stale model-catalog responses across session or connection changes.
- [Run 34571594676](https://github.com/openclaw/openclaw/actions/runs/34571594676) passes 11 projection tests, 13 Quick Chat tests, and one iOS simulator test with zero skips or failures. The simulator shows unknown rows selectable, refused rows disabled, Fast absent where unsupported, published thinking labels, the device code and link, and connected auth state after wizard completion. CLI model inventory and session details come from the same fixture Gateway.
- 33 Gateway session-catalog and native-auth tests pass. Swift protocol regeneration check leaves generated source unchanged.
- Config, state, and startup-recovery suites: 56 tests pass. Real Gateway startup passes all 15 sanitized config fixtures with fake credentials and no inference.
- Telegram Test Server `/models` returns the provider selector with no inference; this covers the command sibling.
- Max-lines, assertion-safety, workflow, and native string inventory checks pass.
The task-owned proof workflow is removed from this PR; its run artifacts retain the screenshots, catalog, auth-state output, and test results. The CLI inventory omits Fast/thinking fields, so those controls are compared to the direct session catalog for the same model.
Simulator proof uses an isolated synthetic sign-in provider and ad-hoc signing. It does not claim external OAuth, release signing, or device permission proof.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* feat(gateway): reject stale session reset requests
Add an optional expectedSessionId precondition to sessions.reset so stale automation is rejected before interrupting a replacement generation.
Refs #123862
* test: bind setup credential checks to fixture provider
* perf(ui): keep environment shuffle icon out of startup
---------
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
Related: #136257
Supersedes #142851. Builds on #144181.
## What Problem This Solves
Fixes an issue where API keys saved on the Models page followed a different persistence path from CLI keys, and CLI logout refused to remove profiles referenced by provider configuration.
## Why This Change Was Made
Models and CLI key operations now share credential selection, persistence, and removal. Removal clears references for the same captured credential plan that the store deletes; concurrent replacements are preserved. Both paths use the Gateway auth-refresh owner and retain recovery guidance after a committed write.
If another client changes the provider binding while the CLI key prompt is open, the saved key does not replace the newer binding. The CLI reports the committed key and tells the user to reopen Models. Internal write controls stay outside the public plugin interface.
Reference-backed profiles cannot be converted to inline keys by replacement. If a concurrent credential generation rejects removal after config cleanup, the remover restores only cleanup-owned config values that no later writer changed.
If removal throws or commits only some owner stores, the removal owner reads the targeted stores again. It restores references only for credentials that still exist and keeps successful deletions removed.
Recovery replays only the captured config delta for targeted survivors. A retained token or external-secret profile keeps its provider binding.
## User Impact
- Edit or remove saved API keys through Models or the CLI with the same stored result.
- Keep model defaults, connection settings, account metadata, credential copy restrictions, tokens, and reference-backed keys intact.
- Explicit CLI profile selection still supports named backups without changing the active connection.
- Agent-local overrides remain intact; a conflicting shared-key replacement reports how to resolve the override.
## Evidence
- Baseline CLI: removing a configured profile failed with the provider-reference refusal.
- Baseline browser: Models reported “Secret saved,” while the key remained inline in provider configuration and the profile store stayed empty.
- Real Gateway/browser and CLI proof: save and removal produce identical credential/configuration state; both refresh auth successfully and preserve the selected model.
- Targeted owner, CLI, Gateway, UI, portability, and plugin-interface tests cover persistence, reference cleanup, concurrent credential replacement, retained credential kinds, explicit backups, administrator scope, and committed-write warnings.
- Independent real-browser acceptance passed UI/CLI state parity, metadata and credential-kind preservation, administrator-scope enforcement, config-write failure recovery, and active-run preservation during targeted removal. Full-provider logout closed the matching real local-provider streams.
- Final rebased candidate: 230 targeted owner, CLI, and Gateway tests passed. The rebuilt Gateway/UI passed the real-browser and CLI save/remove parity test. UI and portability checks passed on the integrated candidate, whose Auth B production files match the final candidate.
- Corrective focused checks: 80 tests passed for the binding race, public plugin boundary, CLI test types, and UI end-to-end inventory. Protocol generation passed.
- Real CLI race proof: a second CLI changed the provider from `fixture:manual` to `fixture:secondary` while key entry waited. The first CLI then preserved `fixture:secondary`, returned the saved-key recovery message, and exited 1.
- Final review-fix checks: 151 owner and Gateway tests passed. They cover configured and default reference-backed profiles plus API-key-only and full-provider removal races that preserve credential, profile metadata, order, and provider binding.
- Final public CLI proof: reference-backed replacement rejected without state change, then logout and save succeeded. A same-ID concurrent replacement completed while logout waited on the config lock; the rejected logout preserved credential and config, then retry and save succeeded.
- Rebased-head checks: 291 focused owner, CLI, Gateway, SDK, and UI-inventory tests plus 50 Models-page tests passed. Protocol generation, full build, the public CLI campaign, and real Models-page UI/CLI parity passed again after the Models login work landed.
- Incomplete-removal checks: 154 owner and Gateway tests passed. They cover thrown store errors, incomplete removal, partial multi-store deletion, surviving-reference restoration, and successful retry.
- Untargeted-binding checks: 155 owner and Gateway tests passed. Failed API-key-only removal preserves the retained token binding, and retry removes only the targeted key.
- Proof limit: the running Gateway's internal refresh exception was not live-injected. Gateway tests cover the failure branches and UI tests cover the resulting warning; remote-target and absent-local-Gateway CLI outcomes were observed separately.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
## Problem
Models sign-in also runs model setup, which can activate a provider's starter model. Bare `/login` starts OpenAI device authentication before the user chooses a provider.
## Solution
Add credential-only provider login in Models and one shared provider menu for chat. Plugins declare optional login choices in their manifests. Core resolves provider and method choices and produces existing command buttons or copyable commands. Bare `/login` always asks for a provider, even when only one is available. API-key and local setup methods remain available through explicit provider commands. `/login codex` retains its device-code flow.
The credential-only flow uses the shared persistence and auth-refresh owner from merged #144181. It preserves the selected model, restrictions, concurrent settings and existing account pins. Models publishes the saved credential through the current Gateway context. Cancellation locks at the real persistent-effect boundary; confirmed saves remain visible through later errors. Caller authority is checked at credential and session commits, and disconnected clients cannot finish pending login. Qualified choices reject stale or ambiguous plugin owners. Leaving Models closes its wizard input through the existing close operation and waits for admission to settle. This uses optional `closeInput` on `wizard.cancel`; ordinary cancellation still refuses to interrupt a protected save. Separate pending requests keep page disposal independent of an outstanding Cancel response.
The final conflict resolution also preserves the shared refresh outcomes from merged #144436: rejected or unreachable refresh reports saved credentials with recovery guidance. One shared error module carries saved-credential and settings-write failure facts, and the provider-neutral runtime owns completion/failure wording for both chat paths.
Channels render core-owned command actions. Provider-neutral recovery replaces the old OpenAI-specific recovery path. OpenAI, MiniMax and xAI declare their supported credential-only choices; methods requiring starter discovery retain setup.
## Impact
- No new configuration keys or database schema.
- Optional metadata preserves setup for plugins that omit it.
- Connecting a provider does not activate its default model.
- Chat selection rechecks current owner permission and availability.
## Evidence
Original baseline: `d35cefd9b7`. Integrated base after #144181: `7d2296e333`. The later required conflict resolution integrates #144436 at `39b671dc74`.
- Real Telegram Test Server baseline: bare `/login` issued a device code before selection. Candidate: provider buttons, second method menu, synthetic device code, saved result and rejection of a stale qualified selection. Telegram transport and user actions are real; provider credentials are synthetic.
- Real Gateway baseline: `models.authLogin` was unknown. Candidate: saved fixture credential with the same default model and restrictions.
- Independent public-client checks cover singleton webchat selection, wrong-connection denial, unavailable choices, disconnect rejection and positive connected-owner completion. An existing CLI setup flow with omitted metadata still saves credentials and honors explicit `--set-default`.
- Integrated public-client cancellation proof: cancelling before save leaves no credential; cancelling after profile visibility while a provider note is pending returns running, and acknowledging the note produces the saved terminal result. A public settings edit during login survives; the saved profile appears without restarting the Gateway.
- Browser captures show Connect, explicit provider selection, the sign-in URL/code and saved result with the selected model unchanged. Captures were inspected.
- Current integrated focused Vitest: 243 passing tests across the auth producer and choice resolution, shared login runtime, core chat, native Telegram, Gateway wizard ownership, Models UI and the CLI sibling. Earlier retained checks cover method ordering, setup, MiniMax/xAI and provider recovery. The Telegram fixture cleanup preserves all test names, parameter rows and assertions; its 25 cases pass after cleanup.
- Page-disposal regression: the original Gateway kept waiting after a saved note, and the original Models page left the wizard unsettled on removal. The correction passes 33 Gateway and 49 UI tests, including disposal during a pending Cancel and a second login on the same connection. Fresh real-Gateway proof rejects a peer disposal, preserves the saved credential, returns truthful closure status, and immediately admits the same owner’s next login.
- Focused lint, assertion safety, runtime build and whitespace checks pass. Full typechecking and full CI run on GitHub.
This extracts Auth C+E from #136257 and replaces closed#142943. Auth A was merged before integration; its implementation was not copied into this branch.
## Deletion and rewrite ledger
`src/auto-reply/codex-login-recovery.ts` moved to `src/auto-reply/provider-login-recovery.ts`. Its `buildCodexLoginRecovery`, `CodexLoginRecoveryEvidence`, and `CodexLoginRecovery` symbols moved to `buildProviderLoginRecovery` (`:23`), `ProviderLoginRecoveryEvidence` (`:5`), and `ProviderLoginRecovery` (`:11`). The fixed OpenAI/Codex recovery action is replaced by the shared provider menu. No recovery test definition was deleted; the nine renamed or parameterized definitions are mapped below against head `73cfa4b319b9640a6711b2dc8e871d9ff4aea035`.
| Removed test name | Disposition | New test name and location |
| --- | --- | --- |
| `adds Codex login recovery to raw forwarded refresh failures` | **behavior moved** | `adds provider login recovery to raw forwarded refresh failures` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:51` |
| `keeps Codex login recovery actionable on Control UI turns` | **behavior moved** | `keeps provider login recovery actionable on Control UI turns` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:72` |
| `preserves Codex login recovery in known failure payloads` | **behavior moved** | `preserves provider login recovery in known failure payloads` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:118` |
| `keeps disabled OpenAI OAuth profiles actionable on later turns` | **behavior moved**; original OpenAI row retained, xAI and MiniMax rows added | `keeps disabled %s OAuth profiles actionable on later turns` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:228` |
| `does not offer Codex login for $label` | **behavior moved**; API-key and transient OAuth negative rows retained, provider-name-only negative row added | `does not offer provider login for $label` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:277` |
| `keeps non-OpenAI OAuth refresh failures on provider-specific terminal guidance` | **behavior moved and expanded**; terminal guidance retained, shared login action added | `adds provider login while retaining non-OpenAI terminal guidance` — `src/auto-reply/reply/agent-runner-execution-auth-failures.test.ts:289` |
| `turns returned OpenAI refresh failures into Codex login recovery` | **behavior moved**; original OpenAI row retained, xAI and MiniMax rows added | `turns returned %s refresh failures into provider login recovery` — `src/agents/embedded-agent-runner/run/payloads.errors.test.ts:121` |
| `adds Codex login recovery to OpenAI OAuth refresh failures` | **behavior moved** | `adds provider login recovery to OpenAI OAuth refresh failures` — `src/cron/service.failure-alert.test.ts:845` |
| `does not offer Codex login for non-OAuth authentication failures` | **behavior moved** | `does not offer provider login for non-OAuth authentication failures` — `src/cron/service.failure-alert.test.ts:884` |
The obsolete provider restriction in `buildCodexLoginRecovery` is intentionally removed: typed non-OpenAI OAuth failures now receive the shared action while keeping their provider-specific terminal repair command. The old `/login codex` recovery presentation becomes `/login`; explicit `/login codex` remains supported. Typed OAuth evidence, negative authentication cases, private profile handling, and complete recovery-presentation assertions remain covered.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Related: #136257
## Problem
Provider login could overwrite settings changed during sign-in and could hide that credentials were already saved when settings application failed. CLI auth changes used a read-only status refresh that did not acknowledge publication to the Gateway's prepared auth state.
## Solution
Login saves credentials through the existing owner and replays only its configuration changes against the writer's current source. Independent additions also merge when their parent object was absent at login start; overlapping edits still report a conflict. Model identities are normalized through the existing config owner. ID-keyed model rows merge as upserts: unchanged fields and concurrent entries survive, while overlapping changes report a settings conflict separately from the saved credential.
The administrator-only `models.authRefresh` method uses the existing Gateway publication owner and waits for prepared auth state. It reloads shared-store ownership after external writes and rekeys configured owners before queuing publication. Login, logout, profile order, and local-store notifications share that owner. Generated protocol artifacts and the dependent Workboard manifest are updated without a protocol version bump.
When an older Gateway returns `INVALID_REQUEST` with `unknown method: models.authRefresh`, the CLI makes one guarded legacy `models.authStatus { refresh: true }` request and still prints restart guidance. Legacy status refresh is not reported as acknowledged publication.
## Impact
- Full-provider logout cancels matching active runs immediately after credential removal, even when later auth refresh fails. Targeted logout and unrelated runs remain unchanged.
- Unset and existing defaults are preserved unless `--set-default` is requested.
- Concurrent model IDs and independent fields survive sign-in; partial rows retain existing settings.
- Read-only status access stays unchanged. The read-to-admin scope narrowing is intentional for the new mutation; permission errors do not trigger the compatibility path.
- Order acknowledgement includes auth publication. A committed order still returns a warning if refresh fails.
- Omitted workspace is supported by configured-owner lookup; refresh uses current configuration rather than stale request facts.
## Evidence
- 398 current-owner targeted tests pass across retained and refreshed owner/sibling proof, including CLI login/logout/order, config replay, ID normalization, partial model rows, fallback classification, runtime notifications, scoped/overlapping publication, and public method admission.
- Baseline real CLI proof shows a concurrent logging edit being overwritten before the repair. Credential readback confirms persistence even when settings are rejected.
- Fresh eight-scenario CLI acceptance on `f6044cbdd60a` passes default controls, ordinary ID upserts, concurrent new IDs, independent field edits, and saved-credential reporting for genuine conflicts. The prior failed partial-row run is retained in the evidence history.
- Real Gateway proof shows acknowledged publication, visible credentials/model availability, overlapping agent refreshes, read-only denial with status access retained, local-agent logout, and remote-store separation.
- Fresh real-Gateway proof with older-method response controls on `f6044cbdd60a` passes login, order, and local logout: exactly one legacy status request follows the typed unknown-method response, restart guidance remains, and no publication success is claimed. Wrong method/code, permission failures, and mismatched state do not use the fallback. The same pass verifies the updated prepared-catalog behavior from main.
- Live logout fault proof on `117f47d41b4a` starts two real provider HTTP requests through `chat.send`, then makes provider auth preparation fail during publication. Full-provider logout still closes the matching request and emits `auth-revoked`; the unrelated request stays active and completes. The response remains `UNAVAILABLE`. The registered-handler regression is red before the fix and green afterward.
- The absent-parent regression fails on `117f47d41b4a` and passes after the one-condition conflict-check correction. The existing registered-provider login test verifies both provider entries, credentials, and the original default; 52 selected login/config tests pass. No further live fixture experiments were run.
- Formatting, syntax lint, assertion safety, max-lines limits, protocol generation/validation, and relevant generated-output checks pass. Full CI runs on GitHub. Fixtures use synthetic credentials; no live vendor OAuth or model inference is claimed.
Existing limitation: shared-main CLI logout reports an auth-store lock failure on both the pinned baseline and candidate before refresh. Agent-local logout and its refresh are verified; this PR does not change the shared-profile remover.
An additional targeted-profile fault attempt stopped at credential removal before reaching publication; it is retained as a limitation. Existing targeted-logout preservation tests pass.
The separate setup lifecycle is owned by #144195. Shared login results and chat/Telegram completion presentation follow in the next extraction PR.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* refactor(protocol): simplify generated schema registration
* fix(protocol): handle Windows paths in registry type checks
Normalize diagnostic filenames using the same path rule as the compiler host, so expected readonly diagnostics are recognized on Windows. The actual package guard and both optional-mode compiler probes pass; the native Windows execution is separate evidence.
## What Problem This Solves
Cloud worker snapshots could be inspected and recovered in Settings, but operators could not start a build, rebuild a project image, or cancel an active build from that view.
## Why This Change Was Made
Add Build snapshot with eligible-profile and Gateway-local repository selection, Rebuild using a recorded local project root, and confirmed cancellation through the existing environment methods. Group build environments with their snapshots, refresh worker inventory before image inventory, and poll every 10 seconds while a worker build or capture remains active. Preserve the observed worker state when image listing fails.
Failed and orphaned builds remain visible with their existing worker error and count toward Needs attention; they do not keep polling or offer cancellation. Capture counts are deduplicated by lease ID. Pending build dialogs retain their errors, and profile-save notices direct operators to Snapshots after restart.
Carry optional local project-root metadata through preparation and Crabbox allocation/listing, and include profile identity in the existing worker summary. Preserve main's computed project label for repository-backed sources; only local snapshots expose Gateway-local root metadata. No new RPCs, configuration options, database schema, or image reuse policy. The rebase retains #143893's pin, previous-generation, rollback, delete, and retention controls.
## User Impact
Operators can prepare committed project snapshots without starting a session. Inline errors explain invalid selections and prepared-pool capacity. Rebuild uses ordinary preparation/reuse policy and does not force a capture when the existing image remains reusable. Images without a recorded local root omit Rebuild; the repository picker remains available for local checkouts.
Cancellation explicitly asks to destroy the selected worker, including an unused ready reserve. It uses non-force destruction: the existing lifecycle owner checks attachment under the environment lock and retains failed/orphaned records. The earlier stale-cancellation review concern was rejected on that source evidence, and the review accepted the rejection.
## Evidence
- Rebased onto #144002, which repairs the unrelated docs-navigation CI expectation. The previously failing navigation test now passes locally.
- Expanded focused tests passed: 50 project-preparation/provider tests, 117 cloud-worker UI tests, four snapshot browser flows, and 23 Crabbox Gateway tests (194 total).
- Changed-file `pnpm exec oxlint` passed. Core typechecking passed after narrowing the existing local/repository project union without casts or suppressions.
- Independent review of the complete feature was scoped-clean at P0–P2. The new one-line project-variant integration repair also received a clean scoped review.
- Asynchronous failure, capture polling, inventory ordering, and image-list failure regressions were each demonstrated failing before their repair and passing afterward.
- Full `node scripts/check-changed.mjs` passed before the patch-identical rebase onto #144037. Post-rebase changed-file oxlint and all four focused snapshot test shards passed; both previously failing navigation assertions also passed. Exact-head CI [34480832658](https://github.com/openclaw/openclaw/actions/runs/34480832658) passed for `31306f3861d4ec0aee8b5de1bf2c2a0c89fa2d53`.
Earlier CI exposed two settings E2E assertions expecting the old restart notice; those assertions now require the complete intended notice. The integrated pin/delete browser fixture supplies the valid empty worker inventory it consumes. A cancelled security workflow passed on its single retry; the later navigation failures were repaired upstream in #144002 and #144037. No checks or baselines were weakened.
The additive optional provider-metadata compatibility risk is accepted within this reviewed change. Required fields, allocation identity, and preparation policy remain unchanged. Bundled-provider tests and core/plugin typechecks cover the changed boundary; arbitrary third-party providers were not exhaustively exercised.
[Maintainer-provided live UI proof](https://github.com/openclaw/openclaw/pull/143929#issuecomment-5619200603) covers Build snapshot through available-image publication and surplus retirement. The Snapshots UI and project-preparation modules are byte-identical to that proof revision across this rebase. The cancelled Labeler automation passed on its single retry.
## Screenshots
Mock Gateway fixture (synthetic profiles, one build in progress).
| Before: Snapshots view (read-only) | After: Build snapshot, Rebuild, Cancel, and a build row |
| --- | --- |
|  |  |
| After: build dialog |
| --- |
|  |
The underlying `environments.prepare` path was proven live against Crabbox AWS in #143838 (build → capture → available → surplus retirement); this PR wires that method into the view.
The rebase onto #144037 preserved both source commits unchanged by range-diff. No duplicate navigation/catalog repair was included in this PR.
* feat(control-ui): show cloud session machine specs
Expose optional OS, machine class, vCPU, and memory metadata on correlated
worker placements. Resolve provider defaults through lifecycle-owned catalogs
without changing persisted profile snapshots.
Show known machine facts in sidebar hovercards and placement tooltips. Refresh
session subscribers when discovery completes, and fence catalog warmups
against profile changes.
* test(gateway): account for machine catalog preflight discovery
Model the read-only providers catalog query in Crabbox preflight fixtures. Assert exact command sequences so failed preflight still cannot allocate or clean up a worker.
* refactor(gateway): centralize machine catalog lifecycle
Keep machine metadata subscriptions, cleanup, and warmup warnings with the catalog owner. Delegate its async listing operations directly so the environment service stays within its line limit after concurrent preparation changes.
## Problem
Operators cannot prepare a cloud worker for a profile and local repository without first dispatching a session. Ready-worker demand currently comes from session activity.
## Solution
Add the admin-only `environments.prepare({ profileId, projectPath })` RPC. It validates the local Git checkout and pins HEAD, authorizes the committed setup recipe, atomically reuses matching inventory or admits a build, and schedules the existing preparation pool. List and status summaries expose preparation purpose and key; `environments.destroy` cancels an in-flight build while retaining provider settlement and cleanup ownership.
Persist purpose through nullable `worker_environments.preparation_purpose TEXT`, using the existing compatible additive migration. Legacy rows remain reserves. Unfinished builds bypass the per-project ready target, including reused reserves promoted to builds, while retaining their original expiry and obeying the global cap. Ready builds return to ordinary reserve retention. A zero global cap rejects admission before reuse.
Pool retention uses the inventory behind each pass's source snapshot while rereading existing rows live. A build admitted during an awaited retention operation is handled by the already-requested next pass, so stale eligibility cannot cancel successful admission. Current store queries still enforce capacity; expiry, cancellation, and provider settlement remain live.
## Impact
An operator can build an eligible project's prepared worker without creating a session. Admission returns its environment ID, preparation key, and whether it reused inventory. Validation and capacity errors remain typed. Existing reserve targets, idle timeouts, provider capture behavior, and global capacity accounting remain intact.
This adds no UI, CLI command, provider changes, version bump, or changelog edit. Build admission has a separate module to keep lifecycle ownership and file-size limits clear; the existing profile validator is shared, with its obsolete assertion-baseline allowance removed.
## Evidence
The [initial exact-head CI attempt](https://github.com/openclaw/openclaw/actions/runs/34455365820/job/102800854096) hit the pre-existing Doctor/plugin-index SQLite lock flake in `channel-plugin-blockers.test.ts`. The failing path is unchanged by this PR and is recorded for separate repair. The first authorized failed-job rerun passed. [Exact-head CI attempt 2](https://github.com/openclaw/openclaw/actions/runs/34455365820/attempts/2) completed successfully on `8ceaeb8f9e60a241badc1c283503c7783d68bc15`, including the required CI gate. No test or locking behavior was changed to bypass the failure.
- Reproduced the admission-versus-retention race before the fix: a newly admitted build was durably marked for destruction. All **50 tests across four pool suites** pass after the snapshot/liveness repair, including new-admission and reserve-promotion interleavings with zero ready target, global capacity, and preserved expiry. Fresh combined autoreview is scoped-clean through P2, and the full `check-changed` lane passed for the pool and schema-test repair.
- Schema-maintenance and prepared-environment-store suites pass **46 tests**, including bare nullable-column repair, legacy-row reopening, purpose persistence, and integrity checks. The schema contract list now includes the already-declared `preparation_purpose TEXT` column.
- The existing public method-order tests reproduced two failures because their appended suffix omitted `environments.prepare`. Added the new method to the exact suffix expectations and existing mutation-policy table; all **32 tests** in `server-methods-list.test.ts` pass with legacy prefix/index assertions preserved.
- Landing CI found missing generated native protocol models and a stale Workboard asset hash. Regenerated Swift/Kotlin outputs and the manifest using the repository commands; `pnpm protocol:check` and `pnpm plugins:assets:check` pass. Both repair diffs passed autoreview through P2. The initial Docker packaging failure followed generated assets dirtying the tracked tree; the replacement exact-head run passed Docker packaging as well as protocol and build-artifact checks.
- Post-rebase validation: changed-file `pnpm exec oxlint` passed; descriptor registry, release-train, and prepare RPC tests passed (**22 tests across 3 files**). The rebase retained both adjacent RPC descriptor additions and otherwise preserved the reviewed patch.
- `pnpm install` — passed.
- Broad worker, environment RPC, protocol, and state migration run — **3,088 passed**, two Windows-only tests skipped on macOS. This preceded the final mechanical admission extraction and zero-cap correction.
- Final focused run, including the corrected boundary tests and SDK E2E — **153 passed across 12 files**. The E2E runner also completed its runtime build.
- `node scripts/check-changed.mjs` — passed, including production/test typechecks, core/scripts lint, database guards, and zero runtime import cycles. Earlier type, lint, fixture, and shrink-only baseline findings were fixed.
- `pnpm db:kysely:check` — passed.
- `pnpm docs:check-links` — passed: 13,092 links checked, zero broken links.
- `git diff --check` — passed.
- Autoreview — scoped-clean through P2. Reserve promotion and zero-cap findings were fixed. Regression cases demonstrated the reserve-reuse, stale-expiry, cancellation, and zero-cap failures before their fixes.
Live provider build verification was not run; validation uses the boundary tests listed above.
The [initial CI test shard](https://github.com/openclaw/openclaw/actions/runs/34451706681/job/102788886784) also reported `StateDatabaseCoordinatorContentionError: another OpenClaw process owns state-lifecycle` while the update-run-ledger process fixture closed its database. The PR does not modify that fixture, test, coordinator, or database-cache lifecycle owner. No lifecycle-lock behavior was changed for this landing; the replacement shard passed, including the update-run-ledger tests.
<details>
<summary>Exact test and review commands</summary>
```sh
node scripts/run-vitest.mjs src/gateway/worker-environments/ src/gateway/server-methods/environments packages/gateway-protocol src/state/openclaw-state-db-prepared-workers.test.ts
node scripts/run-vitest.mjs src/gateway/worker-environments/service-prepare.test.ts src/gateway/worker-environments/prepared-pool-build.test.ts src/gateway/worker-environments/prepared-environment-store.test.ts src/gateway/worker-environments/prepared-pool.test.ts src/gateway/worker-environments/prepared-pool-expiry.test.ts src/gateway/worker-environments/prepared-pool-maintenance.test.ts src/gateway/worker-environments/provider-project-preparation.test.ts src/gateway/worker-environments/provider-intent.test.ts src/gateway/worker-environments/service-validation.test.ts src/gateway/server-methods/environments.prepare.test.ts packages/gateway-protocol/src/schema/environments.test.ts packages/sdk/src/app-sdk-composed-resources.e2e.test.ts
.agents/skills/autoreview/scripts/autoreview --mode local --max-priority P2 --dataset src/gateway/worker-environments/provider-intent.ts --prompt 'Review final environments.prepare change. Prior actionable findings are fixed: unfinished reserve reuse promotes to build without renewing expiry, and maxTotal zero rejects before reuse; both have before-fix failing regression proof. The capability concern was disproved by supplied unchanged provider-intent.ts: current provider support is rechecked before constructing preparation identity, and missing preparationKey rejects admission. Admission moved from service.ts into build-preparation.ts for max-lines; validated profile helper moved unchanged into service-validation.ts. Build-specific cancellation still retains provider settlement and cleanup ownership. Broad suite passed 3088 tests; latest focused final helper/store/pool/RPC/schema plus SDK E2E passed 153 tests. SDK build is finished and its unrelated generated manifest hash restored; sources are now stable.'
```
</details>
* fix: show full subagent transcripts in the task sidebar
* fix(codex): keep task history dependencies lazy
Preserve the registration-only import boundary and regenerate the dependent Workboard manifest.
* fix(codex): preserve native task history across refreshes
Expose stable shared message identities from native history projections and verify them across paging and content updates.
* test(ui): use task history in file intent fixture