Conversation
The type-safety ratchet was retired repo-wide in #16930 (script and baseline deleted on develop). Deleting the branch's copy resolves the modify/delete conflict so the branch can merge cleanly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves the type-safety-ratchet-baseline.json modify/delete conflict (the ratchet was retired in #16930; the branch dropped its copy in the previous commit). All four code files merge cleanly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…resh branches The develop-pr-gate per-file changed-coverage floor (50%) reports packages/agent/src/api/accounts-routes.ts at 49.00% on this PR. Extend the changed test file with real-branch cases: ensureSubscriptionCli install/cooldown/not-on-PATH via its injected deps, the OAuth unsupported-provider + status/submit/cancel session guards, the coding-plan probe on test and refresh-usage (401 -> needs-reauth), and the pool-driven + inline-fallback usage refresh paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(accounts): remove broker fallback regressions
* feat(os): typed intent vocabulary for chat/voice/transcription routing The one structural intent contract (eliza.os-intent/v1) unifying how chat, voice, and transcription are launched across iOS/Android/desktop entry points. Discriminated-union intents with declared prerequisites, targets, auto-start gating, and typed outcomes. Behavior derives from structural fields only, never prompt/transcript text. Refs #16441 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(os): routing authority, dedupe store, decoder, executor - router.ts: structural routing authority (stale/duplicate/degraded/blocked/ consent-required/routed), consent-gated auto-start, prerequisite checks. - dedupe.ts: clock-injected stable-id idempotency store with TTL + snapshot/seed for restored-session/crash recovery. - decode.ts: J3 boundary decoder + deep-link and legacy-launch adapters mapping the free-form native action string to typed intents once. - apply-command.ts: exhaustive executor over the narrowed one-controller surface. Refs #16441 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(os): full intent-routing case matrix + biome formatting 76 deterministic vitest cases across contract/dedupe/decode/router/apply-command: invalid/stale intents, locked device, missing permissions, auth expiry, background/foreground, consent gating + reversibility, concurrency over a shared store, duplicate-start prevention across redelivery paths, and crash recovery via snapshot rehydrate. Exhaustive command executor now fail-fast throws on an unhandled kind. Refs #16441 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(os): end-to-end pipeline test + ./os-intent subpath export Proves a real native elizaos:// launch link flows decode → route → drive the ONE controller, and a redelivered link drives it exactly once. Exposes the module via the ./os-intent package subpath (mirroring sibling #16440's ./native-transcript). Refs #16441 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
fix(release): include simple views in npm cohort
…top new unpriced positions swallowing deltas (#17039) Two P1s in the balance-delta producer merged via #16956 (issue #16943): 1. The sample fingerprint folded per-position price coverage into a single opaque list, so ANY new unpriced position (spam airdrop) changed the fingerprint and silently re-baselined — permanently swallowing a concurrent material move in priced holdings. Coverage is now tracked per position and only priced<->unpriced flips on positions BOTH samples hold re-baseline; positions unique to one side fall through to the normal delta comparison. 2. The baseline carried no wallet address, so importing a different wallet cross-compared the old wallet's total against the new one's and fabricated a material-delta notification. The baseline now records a wallet identity key (sorted per-family addresses, EVM lowercased) and an address change on a retained family resets the baseline cleanly. Legacy baseline rows (pre-walletKey schema) fail the shape check and are discarded — one designed silent re-baseline on upgrade, never a comparison against a row whose wallet identity is unknown. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(ui): resolve view-id navigation from registry paths * chore: refresh PR checks * chore: refresh evidence rows --------- Co-authored-by: shadow <shadow@shad0w.xyz>
* ci: per-SHA staging concurrency groups so a gate-parked run cannot squat newer develop deploys Since the 2026-07-16 required-reviewers rule on the staging environment, push-event staging runs park in status=waiting at the env gate and a waiting run holds the shared cloud-cf-deploy-v4-staging group. One unapproved run wedged every newer develop push into pending/zero-jobs (Jul 22 R10/R11, Jul 23 recurrence; misdiagnosed as runner starvation). Fix: group staging push runs per head SHA. Waiting runs can no longer block group admission for newer pushes; nothing in-flight is ever cancelled (cancel-in-progress remains PR-only). Deploy-step serialization is unchanged via the job-level per-env groups (cancel-in-progress: false) and the #14083 freshness guard still skips stale-SHA clobbers. Production keeps the shared queue-never-cancel group untouched. needs-human-review [sol-orch] * ci: factor staging admission and Pages artifacts --------- Co-authored-by: Shaw <shawgotbags@gmail.com>
…17041) Native function-calling envelopes carry no top-level completed field, so tryGateEvaluator's "planner declared the turn incomplete" veto was structurally inert on the native lane — a sequential multi-op request could be truncated after its first turnComplete-returning action (#17034). Every native tool schema now accepts a reserved optional eliza_turn_scope enum ("final" | "more_work_pending"). parsePlannerOutput folds the declarations into a first-class completed signal (JSON-lane top-level completed still outranks it), strips the argument before dispatch so no action handler ever sees it, and the loop consumes the folded signal. Absence preserves pre-#17034 behavior exactly; only an explicit more_work_pending vetoes the gate, mirroring the JSON lane. Fixes #17034 Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Shaw <shawgotbags@gmail.com>
Co-authored-by: Shaw <shawgotbags@gmail.com>
…te WS echo duplicates The active web chat received the same assistant reply twice: once streamed into the optimistic temp-resp-* bubble via /messages/stream, then again as a proactive-message WS broadcast of the persisted memory under a different server UUID, which the id-only dedupe in the proactive handler appended as a second bubble. Protocol fix (root cause, replaces the rejected text-match suppression from #17009): - server: the terminal SSE done frame now carries messageId, the durable persisted assistant memory id. The streaming route pre-mints the id before emitting done and hands it to the deferred persist; action-callback turns that already persisted mid-turn reuse that memory's id. - client: on done, the streamed temp-resp-* bubble is swapped to the persisted id in place (useStreamingText complete mod), collapsing any already-appended echo bubble with the same id. - proactive-message handler now reconciles by id (update in place or no-op) instead of append-unless-same-id; genuinely new proactive messages (different id) still append. No text matching anywhere; identity flows through the protocol.
…16970 #16951) (#17047) * docs(evidence): retire remaining live .github/issue-evidence instructions (#16948 residuals) plugin-meetings README gets the inline-PR artifact wording plus the managed evidence-and-e2e-mandate markers (mirroring PR #16948's plugin-trajectory-logger fix); the accounts-ui e2e README now documents the path the harness actually writes (test-results/evidence/10722-accounts-ui-e2e/). The repo-wide sweep also repoints the remaining live run instructions (voice matrix, startup trace, mobile-resource lab normalization, voice workbench PR bundle, benchmark review-package, device lifecycle matrix) at their real gitignored output dirs, and stamps the coding-capability MASTER_PLAN with an evidence-location note so its pre-retirement work items cannot re-instruct committed evidence. Fixture paths in check-pr-evidence.test.mjs and history/research docs describing the retirement are intentionally untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(shared): never let ELIZA_TTS_DEBUG go silently dead under strict LOG_LEVEL (#16958) The server ttsDebug sink emitted at a fixed info level, so LOG_LEVEL=warn or error filtered the diagnostic out even though the operator explicitly opted in via ELIZA_TTS_DEBUG — the exact silently-dead-diagnostic defect #16347 existed to kill. The sink now emits at info normally and escalates to the logger's active threshold (warn/error/fatal) when LOG_LEVEL is stricter, so emission is guaranteed at any level. New suite pins LOG_LEVEL=error at logger init and asserts delivery through the real listener stream (which only fires for entries that passed the level gate). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(scenario-runner): pin the deterministic twin's non-owner tier to ADMIN (#16963) The catalog README described the mutation-wall refusal fixture as a USER-granted non-owner, but the twin actually whitelists the guest as a connector-admin (ADMIN) — and nothing pinned that resolution, so a silently broken whitelist stamp would degrade the guest to GUEST and the refusal would still pass for the wrong reason (any non-owner is refused). The scenario now probes the real roles.ts resolution (checkSenderRole) both at seed time and in a finalCheck that runs before cleanup clears the whitelist, failing hard on any tier other than ADMIN; the README states the real tier. Negative-tested: emptying the whitelist fails the seed with 'expected the whitelisted guest to resolve as ADMIN, saw GUEST'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): per-cell FFI skip accounting; drop stale ABI v12 JSDoc (#16970) bootFusedFfi's one-line JSDoc still said '(ABI v12)' while the function pins the loaded library to ELIZA_INFERENCE_ABI_VERSION (currently 14) — the comment now names the constant instead of a hardcoded version that drifts. The fused FFI-lane guard in voice-live-e2e only tripped on '0 pass' or '12 skip', so a partial skip (some matrix cells skipped, the rest passing) sailed through the 'nothing skipped' claim; it now fails on ANY nonzero skip count. Guard grep verified against all four bun-test summary shapes (all-pass, partial-skip, full-skip, explicit '0 skip' line). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): fail the builtin-view ratchet when observed sites drop below the pin (#16951) maxMutationSites only ratcheted upward: when a refactor removed local mutation sites the freed headroom silently accrued, worst on multi-file aggregates like automations (71), where one slimmed file could absorb dozens of future local-only mutations unnoticed. The validator now emits a stale-baseline finding whenever observed < maxMutationSites (suppressed while a source file is unreadable — the partial count is meaningless next to the missing-source finding already emitted), so every drop force-pins the count down. All 25 current baseline entries already sit at their exact observed counts, verified by recount. #17016's my-apps entry arrived via rebase onto develop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Shaw <shawgotbags@gmail.com>
Follow-up to #17019, which covered agent-switch, model-switch, view uninstall, and rollback re-register. A caller sweep of plugin-app-control found four more Node-side loopback fetches that still crossed the token-protected local API boundary with only Content-Type: - settings defaultRouteFetch: only /api/views/* paths got the bearer; /api/config, /api/permissions/*, /api/wallet/*, /api/backups, /api/update/*, /api/training/* did not. Attach it unconditionally. - background defaultGenerateImage (/api/background/generate-image). - client/api.ts AppControlClient (/api/apps/installed, runs, launch, stop). - verification-room-bridge live-load POSTs (/api/plugins/load-from-directory, /api/apps/load-from-directory). All reuse the same createViewsRequestHeaders() seam from #16836: canonical ELIZA_API_TOKEN with the legacy ELIZA_API_AUTH_TOKEN fallback, header omitted entirely when no token is configured, so open local dev is unchanged. Integration coverage extends the real-TCP bearer-protected test to the non-views settings route, generate-image, and the app-control client, and keeps the no-token-in-URL/body leak assertions over every captured request. Co-authored-by: 0xSolace <shadow@shad0w.xyz>
…nts fetch a stage-1 compose fans providers out concurrently and pays the same db round-trips several times over: getRoom 4x (recent_messages / character / platform_* / world) and 3 overlapping newest-first room messages-scans (recent_messages at conversationLength, facts at 10, attachments at <=50). on a single-threaded store (pglite wasm) those duplicates serialize — their latencies sum instead of overlapping — and set the composeState wall. three structural changes, no prompt-content change: - runtime.getRoom now goes through a short-ttl (1s), in-flight-shared promise memo (same shipped pattern as identity-clusters.ts); every room mutation wrapper invalidates the key, so correctness never leans on the ttl in-process. - runtime.getMemories coalesces the exact compose-shape messages-scan (newest-first, room-scoped, no filters) into one superset fetch sliced per caller; slicing is provably identical to a direct limit/start-bounded query because a start bound is a pure suffix predicate on the newest-first order. createMemory/createMemories bust the room key, making the intake-then-compose sequence self-enforcing: a stale window can never drop the message being answered. any other query shape passes through untouched. - the attachments provider evaluates the message-side half of its render gate before fetching conversation history; a text-only turn with no attachment reference skips the history scan + access-context resolution entirely (it was the largest single provider wall on simple dms). measured on a repeatable harness (real AgentRuntime + in-memory adapter mirroring plugin-sql ordering, real recent_messages/attachments/facts providers, serialized 20ms per db query modeling pglite): simple-dm compose drops from 7-8 serialized round-trips / ~165ms to 3-4 / ~71ms.
- ensureConnection writes rooms via adapter.upsertRooms directly, bypassing the room-read memo invalidation; invalidate params.roomId after the standalone call so a just-created/updated room is never served as a memoized null or stale Room. - coalesceRoomMessagesScan now bypasses the memo whenever includeEmbedding is set (previously only rejected === false), since the coalesced superset fetch omits the flag and would return embedding-less/embedding-bearing rows to a caller that pinned it either way. - test: ensureConnection invalidates the room memo (exercises the upsertRooms wrapper-bypass path the review flagged).
Fixes #16997. Validates and reconstructs provider tool-call SSE incrementally, rejects divergent consolidated payloads, preserves protocol-valid usage frames, and adds exact-head live Cerebras evidence.
gpt-oss-120b remains an available option everywhere it is served (model catalogs, Groq-hosted defaults, id-handling tests, pricing tables, quirk branches) but no longer poses as the go-to default on lanes where the product already standardized on gemma-4-31b: - plugin-elizacloud package.json pluginParameters metadata claimed 'Default: gpt-oss-120b' for nano/small/medium while the runtime resolvers (getSmallModel/getNanoModel/getMediumModel) actually default to DEFAULT_ELIZA_CLOUD_TEXT_MODEL = gemma-4-31b; align the declarations. - Cerebras-lane defaults still pinning gpt-oss: proactive-greeting live script, SETTINGS live-e2e acceptance model, multitask-bench openclaw factory fallback, app-eval cerebras fixtures, openclaw-adapter cerebras config primary. - Stale docs/workflow comments claiming gpt-oss is the Cerebras default (lifeops bench workflows, HyperliquidBench docs) — the lifeops large tier and HyperliquidBench cerebras path have resolved to gemma-4-31b since the tier registry landed. Groq lanes keep openai/gpt-oss-120b: no gemma-4 is served on Groq, so it is the available option there, not a stale default. Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…7055) * fix(ui): designed not-found state for unknown /apps/<slug> routes Navigating to /apps/<slug> for a slug nothing serves used to fall through every router layer (registered pages, remote views, app runs) and silently render the healthy launcher grid — a UI three-state violation (a failure rendered as healthy) that is exactly how #17020 shipped invisible: the dead deep link looked like a working page. AppsPageView now receives the routed slug and, once the view registry has settled with no claimant (no routable view at /apps/<slug>, no app run whose slug matches), renders a designed AppRouteNotFound state: the literal dead path in monospace, a plain statement that nothing is mounted there, a "Browse apps" recovery action, and — when a routable view's id matches the slug but lives at another canonical path (stale bookmark) — an "Open <label>" action to that path. While the registry fetch is in flight the grid still renders, so a cold deep link never flashes not-found before the upstream registry claim can land. A structured logger.warn fires once per unknown slug as the observable signal. Ratchet baseline covers the two navigation-only controls (no domain mutation to twin); tests cover the claim-resolution matrix, the component's real history-seam navigation, and the mounted-App navigate-view path. Closes #17033 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): harden /apps/<slug> not-found gate — error state, claim grace, broken entries, i18n, hash nav Review fixes on the #17033 not-found state: - a failed registry load renders the grid and never warns (asserting "nothing mounted here" requires a settled successful registry read) - a ~1.5s grace window absorbs the idle-deferred registerAppShellPage / async plugin-claim race before a settled-unclaimed slug is asserted dead - available:false registry entries never claim the slug and are never offered as the recovery CTA, so broken installs surface as not-found - appRouteNotFound.* strings translated across all eight locale catalogs - recovery buttons follow the hash-navigation idiom on file:/appWindow surfaces where pushState is never observed by the router - test headers converted to the prose-block doctrine Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Shaw <shawgotbags@gmail.com>
…nt (#17054) * fix(cloud): emit client-resolvable view ids from shared-tier nav intent The Tier-0 shared-runtime nav fast path kept its own matcher-id -> label table and emitted the raw matcher id as values.viewId in the VIEWS handoff. Two ids drifted from the client's routable registry: "wallet" (the builtin tab is "inventory"; TAB_PATHS inventory -> /wallet) and "help" (no Help surface exists anywhere). The client resolves viewId against its registry (PR #17021) and an unresolvable id lands in the not-found fallback, so "open my wallet" produced a confident "Opening Wallet for you." reply followed by a silent launcher grid. The vocabulary now lives in @elizaos/shared/views/shared-nav-targets as matcher id -> { viewId, label }, translating wallet -> inventory and omitting help entirely so that utterance falls through to the normal LLM turn. shared-nav-intent consumes the table (pure data, worker bundle stays lean), and a cross-package contract test in packages/ui pins every emitted id to either a builtin shell view at its canonical path or a known plugin-declared view, failing by name on any future drift. Closes #17032 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(shared-nav): drop AOSP-only camera target, fs-pin plugin views, correct #17021/#17033 claims Adversarial-review fixes for the shared-tier nav vocabulary: - Remove "camera" from SHARED_NAV_TARGETS: the camera view is an AOSP-fork-only native surface; on the clients a Tier-0 shared agent serves (web/desktop/iOS) /camera renders the ViewUnavailableFallback launcher grid. Camera utterances now fall through to the LLM turn (AOSP devices run dedicated local runtimes whose real VIEWS action handles camera). Tests updated on both sides. - Correct overclaiming comments: PR #17021 resolves emitted ids against the client registry, but its unresolved fallback is still a blind /apps/<id> navigation; the designed not-found render for unclaimed /apps/<slug> routes is #17033. - Replace the self-referential PLUGIN_VIEW_TARGETS map with an fs-backed pin: the contract test reads each declaring plugin source from the monorepo and asserts it still declares both the literal view id and canonical path, so a plugin rename fails the test instead of silently reintroducing the drift class. - Rename the unroutable-id sweep to what it actually asserts and extend it to "camera". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
fix(ci): restore develop merge protections removed by #17077
#17084) 86400s — far above any plausible leg runtime, per no-artificial-budgets campaign policy; liveness detection stays with the orchestrator. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…t-resort guard Follow-up to #17084, which merged with two stacked, contradictory comment paragraphs on TIMEOUT_BENCHMARK_RUN_S (the retained text still justified the old 900s bound under the new 86400 value) and a cap 97x the slowest observed leg. State the current design once: hang detection is owned by the orchestrator's ProcessDeadlinePolicy one layer below, and this constant only bounds a child that wedges before that machinery arms — 4h (~16x the slowest observed sanity leg) is far above any plausible runtime without letting a dead process hold the gate for a day. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
x402-paid buyer-side yield signal action. Follows up #16685, closed with guidance to add as a third-party plugin. Co-authored-by: Stakemate369 <299733642+Stakemate369@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Classify model output once through a shared typed boundary before Stage 1, planner, or failure-reply text reaches a user channel. Preserve ordinary JSON, recursively unwrap reply scaffolds, and reject action, planner, evaluator, spawn, malformed, and nested control records with observable errors at runtime boundaries. Add deterministic adversarial coverage for extra keys, nesting, malformed records, fenced output, genuine domain JSON, and the Stage-1 direct-reply path. Co-authored-by: wakesync <shadow@shad0w.xyz>
…herence chore(benchmarks): coherent 4h last-resort acceptance-gate leg cap
…ivery fix(agent): give dashboard replies one transport owner
…ct (#17063) * fix(views): 'open knowledge' resolves the Knowledge (documents) view The documents view's user-facing label is 'Knowledge' (tab name, view manager card, tags), but the deterministic view-command matcher had no 'knowledge' noun — only documents/docs/files. So the on-screen name is the one phrase that did NOT deterministically navigate: 'open knowledge' fell through the rigid matcher, missed the narrow NL shortcut, and rode the full planner path (where it is at the mercy of provider availability; live QA surfaced it as a 'something glitched' fallback when the planner call failed). Add knowledge / knowledge base / knowledge hub to the documents nouns. The view already carries the 'knowledge' tag, scoreView matches it for fuzzy search, and DOCUMENT_SURFACE_WORDS in views-show already treats 'knowledge' as a documents-surface word — the matcher was the only place the label was missing. Tests: view-command-matcher explicit cases gain the three phrasings (199 pass); full view-matrix suite 600 pass. Co-authored-by: wakesync <shadow@shad0w.xyz> * fix: unify localized Knowledge navigation --------- Co-authored-by: wakesync <shadow@shad0w.xyz> Co-authored-by: Shaw <shawgotbags@gmail.com>
…ks vi.mock across files The vmForks pool shares one worker process whose VM-context module interception races across test files: vi.mock factories nondeterministically leak into (or vanish from) a neighboring file's module graph when several conversation-route suites run in one invocation. Observed both directions on pristine develop (~3/5 group runs): conversation-failurekind-roundtrip loses its chat-routes mock (real readChatRequestPayload rejects with "text is required"), and conversation-greeting-idempotency inherits a foreign no-op persist mock (zero greeting rows, regenerated divergent greetings). packages/agent was the only vmForks user; the root suite already runs forks. 8/8 grouped runs green under forks vs 3/5 failing under vmForks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
perf(core): coalesce turn-scoped room + message reads on the compose hot path
…leak fix(test): move packages/agent vitest to the forks pool — vmForks leaks vi.mock across files
…registry fix(registry): remove unsafe YieldSignal listing
…tivity capture (#17056) * fix(app): lifecycle-safe renderer services + self-starting LifeOps activity capture Adds a renderer-service lifecycle registry (@elizaos/ui/platform/ renderer-services): plugin appRegister entries declare scoped services (registerRendererService) instead of starting work at import time; the app shell installs a per-window host that starts only shell-eligible services, retains every returned disposer, and tears down on pagehide, host replacement, and same-id re-registration (HMR). Side-effect loader identities are role-qualified (<name>#<mode>) so a register entry can never share a cached import promise with the package-root facade. Personal Assistant's LifeOps activity capture moves from the never-reliable React mount to an imperative controller registered as a main-shell-only service: idempotent starts, stop() racing any awaited native operation removes late handles/monitors/intervals, native monitoring never starts without granted permission (no capture before consent, re-checked on resume), and unexpected failures surface as capture_error + console.error instead of collapsing into runtime-not-ready. Closes #16504 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): survive bfcache round trips in the renderer-service host A pagehide with persisted=true (iOS Safari back-nav entering the back/forward cache) used to dispose the host outright, permanently killing every renderer service until a hard reload. Only a real page teardown (persisted=false) disposes now; bfcache freezes and resumes running instances safely. Adds the bfcache round-trip test and the requested rationale comment for the Symbol.for globalThis store (#12091 doctrine). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(lifeops): close the client-lifeops prototype race; leaf ui subpaths; surface 5xx status-probe failures Ported from the adjudicated #17053 branch (fix/lifeops-connector-deps): - The register-path import graph never evaluated client-lifeops.js, so client.captureLifeOpsActivitySignal existed only if the PA root facade happened to load first (lost boot-batch signals + spurious capture_error until the idle load landed). The capture module now side-effect-imports the extension itself and re-types its /api-subpath client view via the exported LifeOpsElizaClientMethods interface. A new test imports the capture module with the real client-lifeops module (no vi.mock of any @elizaos/ui specifier) and fails if the side-effect import is removed. - Leaf @elizaos/ui subpath imports (/api, /bridge, /events, components/ui/button, components/ui/input) replace root-barrel imports in the capture path and blocker settings cards, keeping the router/component tree out of the register chunk. - The status probe previously quieted every ApiError (persistent 500s included) as "not ready" forever, contradicting its own header comment; only network/timeout/503 count as the designed stand-down now, anything else surfaces as capture_error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(lifeops): real-PGlite activity-signals route e2e; de-larp PA agent test stubs Ported from the adjudicated #17053 branch: an HTTP-shaped POST through the real route dispatcher -> LifeOpsService -> repository insert against a real PGlite-backed AgentRuntime, read back via GET and raw SQL (telemetry mirror included), plus the 400-with-no-row and runtime-unavailable error paths. The PA agent test stub now re-exports the real createIntegrationTelemetrySpan and checkRateLimit instead of shape-drifted fakes, so route tests run the genuine dispatch path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Shaw <shawgotbags@gmail.com>
…tion fix(agent): preserve authoritative streamed text
|
Merged to main; prod rollout is now waiting on production environment approval (prevent-self-review blocks lalalune, who triggered the push). @standujar @NubsCarson @0xSolace — pending approvals:
Rollback anchor: |
LifeOps Multi-Tier BenchmarkSuite:
|
|
Status: the main-push Cloud CF Deploy run was manually cancelled at 21:17Z (no rejection recorded; prod groups are queue-never-cancel, so it wasn't automation). Re-queued it — it is back in |
Promotion: staging-verified a3b14c9 → prod
Authorization: Shaw directed this promotion on 2026-07-23 (session goal): "make a PR from develop to main, merge, fix any issues and make sure prod is updated with latest."
Commit:
a3b14c9433eb4d542b5a9343240ae09f339e6884(exactdeveloptip at PR creation; staging deploys track every develop push).Content: 101 commits / 299 changed files on top of the prior promote anchor
9f4dbdb(#17042, promoted to prod earlier today). Carries: the chat duplicate-delivery cluster (#17037, #17049, #17057), warm-pool key-push hardening lineage (#17066 → #17078 → #17083 → #17086), nav/not-found/loopback set (#17021, #17038, #17054, #17055, #17062), lifecycle-safe renderer services + LifeOps activity capture (#17056), unsafe YieldSignal registry removal (#17103), agent vmForks mock-leak fix (#17099), adm-zip lockfile/audit fixes (#17085, #17087, #17089), account-pool ratchet fix (#16514), and the develop-green lockstep fixes (#17069).Migrations: none — zero migration/drizzle files in the promotion diff; schema-safe revert.
Rollback anchor:
main@c97a73bfe84b0c191249e9397f87432812d091f5(current prod tip; no cloud-DB migrations ride along).Merge method: MERGE COMMIT per promotion pattern (not squash).
Guardrail: no
wrangler.tomlchanges in the diff — prod billing/financial vars untouched; platform-only promotion.Evidence
Promotion PR: each constituent PR carried its own reviewed evidence at merge time (per Definition of Done). Rows below link representative real artifacts from the promoted content.
main@c97a73b(= staging9f4dbdb, promoted this morning in promote: verified staging 9f4dbdb → prod #17042). Representative pre-change control captures from constituent PR evidence (fix(ui): designed not-found state for unknown /apps/<slug> routes #17055 develop-head control run, desktop + mobile):17055-after-walkthrough.mp4 · 17055-before-walkthrough.mp4
a3b14c9): Windows CI · Dev Smoke · gitleaks — and this PR's own required lanes (test / build / dev-startup / lint-and-format) execute the full backend suite on the merge ref.[AppsPageView]warn + recovery navigation assertion):17055-after-console-network.log · 17055-before-console-network.log
17055-ocr-after-desktop.txt · 17055-vitest-suites.log