Promote develop → main: overnight UI/demo polish + money-gate + deploy fixes - #11918
Conversation
…t 'Active' copy for coding-plan subscriptions Two app-demo blockers in @elizaos/ui: 1) Sign-in first-click dead-end: with a stored-but-expired Steward JWT and no mounted Steward launcher (registerStewardLoginLauncher has zero production callers), handleCloudLogin entered the Steward branch, launchStewardLogin drained the stale token and threw 'the Steward login surface is not mounted' — first click errored, second click worked. Now the branch is only taken when it can complete on this click (usable stored token or mounted launcher); otherwise the stale token is drained and the same click falls through to the working device-code flow. New seam helper: hasUsableStoredStewardToken(). Launcher registration API untouched. 2) Misleading model-switch UI: selecting 'Claude Subscription' under Settings -> AI Model does NOT move main chat inference (by design: applySubscriptionProviderConfig only records it for the task-agent orchestrator; model.primary is set only for openai-codex), but the Intelligence summary row showed a bare 'Active'. Coding-plan subscription entries now read 'Active for coding agents' with a clarifier that chat replies keep using the Intelligence provider; the Codex plan (which can drive runtime inference) and Cloud/local keep the plain 'Active'. Tests: useCloudState.steward-stale-login.test.tsx (fall-through, short-circuit and launcher paths), cloud-steward-login.test.ts (usable-token rules), ProviderSwitcher.active-summary.test.tsx (copy per entry category). All mutation-checked (reverting each fix reds its test).
… + WS split/tile layout fields dropped
1. Help deep-links to a Settings section always landed on the generic hub.
HelpView.navigate wrote the section into window.location.hash and then
called setTab("settings"), whose pushState replaces the URL with the bare
/settings path — clearing the fragment BEFORE SettingsView mounts and reads
it (hash-nav mode clobbered it the same way with "#/settings"). Route the
section through the sanctioned eliza:navigate:view `subview` channel
instead (App.tsx maps it into SettingsView's initialSection — the same path
the agent + slash-command flows use). "Open AI Model settings" now opens
the ai-model section, not the hub.
2. The WS shell:navigate:view → DOM eliza:navigate:view bridge
(startup-phase-hydrate) dropped the server's `views`/`layout`/`placement`
fields, so an agent-driven split-view/tile-views action degraded to a
single view: createNavigateViewHandler saw only viewId and laid out one
pane. Forward the three fields with the same untrusted-input sanitization
as the rest of the frame.
Tests: HelpView.test.tsx (4) pins the subview dispatch, the untouched
plain-tab + tutorial paths, and that the fragment stays clean;
startup-phase-hydrate.navigate-frame.test.ts (+3) pins layout-field
forwarding, sanitization, and single-view omission. Both mutation-checked
(reverting each fix reds its tests).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… salvaged from rate-limited lane (#11866) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
[codex] fix cloud api core stub duplicate export
Releases only carried GitHub's auto-generated source archives: release.yaml created them with no `files:`, the npm tarballs it already builds were discarded, and desktop installers only build for stable tags. - Compile standalone `elizaos` CLI executables for macOS/Linux/Windows × arch via `bun build --compile` (packages/elizaos/build-standalone.ts). - Make the CLI compiled-aware: inside a bun binary `import.meta.url` points into the unreadable `/$bunfs` root, so getPackageRoot() now resolves templates/manifest/package.json next to the executable (isStandaloneBinary). - Emit the real npm `.tgz` tarballs for the headline packages + checksums (packages/scripts/pack-release-artifacts.mjs), matching what npm publishes. - release.yaml stages both + a combined SHA256SUMS and attaches them to beta releases and to stable production releases. - Regression coverage: src/package-info.test.ts (unit) and scripts/standalone-smoke.mjs (compiles the host binary and drives version/info/create end-to-end). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(release): attach downloadable binaries to GitHub releases
feat: add elizaos-plugin-true402 to registry
…unctuation ebd5203 (#11573) fixed the dead e.g/i.e entries by matching [\w.]+ but anchored the match with (?:^|\s), which rejects abbreviations preceded by quotes/parens/asterisks ('"Dr' / '(Mr') that the original \b handled — the tts first-sentence early-emit path chopped mid-name ('He cited "Dr.'). drop the anchor: leftmost matching already captures the maximal trailing [\w.] run and any other char or start-of-string delimits it.
…background (#11874) AppBackground mounts at the shell root and is statically imported by App.tsx, so its static import of ProgrammableShaderBackground pulled the whole vendor-three chunk (~1.5 MB raw / ~320 KB brotli) onto the first-paint eager graph — even though three is only needed for the opt-in GLSL programmable-background mode that most sessions never use. Lazy-load ProgrammableShaderBackground so three is code-split off the boot path; the plain ShaderBackground (same color) paints as the Suspense fallback, so the swap is seamless when a user does select a GLSL shader. Verified: ProgrammableShaderBackground is the sole three consumer and AppBackground was its only eager production importer (other importers are stories/tests, not in the app bundle), so the chunk genuinely leaves the first-paint graph. Background suite 54/54 green; biome + typecheck clean. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…fuse the next promote deleting BOTH copies (#11875) #11845/#11847 raced the same missing-export fix into two spots, duplicating the export. The dedup then ALSO raced: develop's #11857 deleted the first copy while main's #11865 hotfix deleted the second. Relative to the promote merge-base both sides now carry a different single deletion, so the next develop->main promote auto-merges BOTH deletions cleanly and ships a stub with ZERO runWithTrajectoryPurpose exports — re-breaking every Worker deploy with the original "No matching export" build failure (verified by simulating the merge: surviving export count = 0). Fix: make develop's file byte-identical to main's (keep the first copy). Identical content on both sides makes the promote merge trivially correct. `bun run --cwd packages/cloud/api typecheck` passes with this tree. Co-authored-by: NubsCarson <carson@nubs.site>
fix(core): extractFirstSentence abbreviation check when preceded by punctuation
…transcript follow-up to 35e6a66 (#11712): looksLikeRawFieldTranscript fired on any replyText: line anywhere in a reply, so a legitimate diagnosis that QUOTES a leaked shouldRespond:/replyText: transcript (this repo's own daily debugging workflow) was silently replaced at the send boundary by the QUOTED replyText tail — the whole answer dropped with only a logger.warn. same hijack on the text-mode path: parseMessageHandlerFieldTranscript claimed any prose with a replyText: line and discarded every preamble line. structural rule instead of contains-check: a raw envelope echo IS the message — its first substantive line outside code fences is a known field line, with a shouldRespond:/replyText: hallmark at top level. prose preamble or fenced field lines mean the reply QUOTES a transcript and ships intact. parseFieldTranscript now treats fenced field lines as value content, so a real leak whose replyText quotes an envelope in a fence is no longer split at the quoted lines. the text-mode claim is gated on the same detector, and the comment/code mismatch (comment said routing AND reply field, code was OR) is resolved in favor of the documented-correct OR (a lone shouldRespond: IGNORE echo must stay claimable). genuine leak shape from #11712 (leading skeleton) is still detected, blocked, and recovered — existing regression tests unchanged and green.
fix(core): stop transcript guard from rewriting replies that quote a transcript
The shell rendered a floating circular back-arrow button pinned to the top-left corner of every routed and full-bleed view (ShellBackButton in App.tsx). Because it was `fixed` at z-60 it floated over page content and overlapped it: it covered the "GAMES & ENTERTAINMENT" heading on the Apps gallery and sat on top of the "Character / Knowledge" breadcrumb — which is itself the in-context back control. Remove the global button and the now-dead code it required: - delete ShellBackButton and its two mount sites (RoutedShellContent, FullBleedShellContent) plus the onNavigateBack prop and handleShellBack handler; - drop the --shell-backnav-clearance CSS-var seam (set-side in App.tsx, consume-side padding in spatial/dom.tsx) that only existed to reserve top space for the fixed button; - remove the now-orphaned ArrowLeft, CSSProperties, and goHome imports. Pages that need a back affordance already render their own in-context control (the preferred pattern, e.g. the Character subpages' "Back to Character hub" button); everyone can also use browser/OS back. No page relied solely on the global button for an in-app back path. Tests: App.navigate-view-wiring asserts no global corner button mounts on app routes; a new CharacterHubView.back-button test proves the Knowledge subpage still renders its own back control. The obsolete clearance-seam guard is deleted and the app-shell tap-target/occlusion specs are updated. Closes #11876 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
the manual redirect loop rebuilt each hop init from params.init, re-sending method+body on every hop. 624325a (#11693) stripped credential headers cross-origin but left the body: a POST with a secret body that a compromised server 302s to an attacker origin re-POSTed the full body there. it also deviated from standard fetch, which the header fix cites: 301/302-POST and any 303 rewrite to a bodyless GET. reproduce that rewrite (whatwg http-redirect fetch): 301/302 on POST and 303 on any non-GET/HEAD method switch to GET, drop the body, and delete the body-describing headers (content-type/length/...); 307/308 still preserve method+body. fixes both the cross-origin body exfil and the GET-after-303 functional deviation.
fix(core): rewrite POST redirects to bodyless GET in ssrf fetch-guard
…nt files the unborn-HEAD change-set scoop (3781312, #11605) unions 'ls-files --others --exclude-standard' into changedFiles, but a fresh scaffold that runs npm install BEFORE writing .gitignore has thousands of untracked node_modules paths (--exclude-standard has nothing to honor yet). those flooded the 60-file cap, and because agent-written tool paths were spread LAST (Set dedupe keeps first occurrence), the flood evicted the agent's real files: 'what did you change' answered with node_modules noise and diffs rendered junk. - filter vendor/build dirs (node_modules, .venv, dist, ...) from the unborn-HEAD untracked scoop only; born-HEAD never scoops untracked and explicit tool-written paths are always kept - spread agentWritten first so explicit edit/write tool calls survive the MAX_CHANGED_FILES cap - drop the truncated garbage tail line when the ls-files listing was cut at maxBuffer (ENOBUFS)
fix(orchestrator): keep unborn-HEAD untracked scoop from evicting agent files
…successful retry as origin best result 35a9e81 (#11514) records completions on the task_complete early returns so the spawn cap can relay them instead of re-spawning. but the verify-retry handoff records a completion the router itself just judged a failed build: the dead-url verification annotation makes that text systematically longer than a clean success, so longest-wins recordOriginResult keeps the failure and the successful retry's shorter deliverable can never displace it. at the per-origin spawn cap tasks.ts then relays the dead-url completion — planner-only verification directive included — verbatim to the user as the final answer. gate verify-failed completions (deadUrls > 0) out of origin-result capture at every site: a known-failed build is not a relayable deliverable, and the cap's honest "attempted N times" fallback covers the nothing-clean case. the main-path record now routes through the same helper so the key contract (#8875) and the gate live in one place.
… configured
When the user sends a message with no model provider configured, the chat
showed a forever "Waking Eliza…" spinner (and "Ask Eliza — waking up…"
placeholder) that never resolved.
Root cause: the server's computeCanRespond requires a registered TEXT handler,
so with no provider wired it reports canRespond:false FOREVER (not a transient
warm-up). The shell's readiness keys off canRespond, so phase stays "booting"
indefinitely — the boot spinner never clears even though the send came back
with the actionable no_provider gate.
Fix (client, packages/ui): derive an authoritative noProviderConfigured signal
from the latest assistant turn's failureKind === "no_provider" (server truth).
When set, useShellController auto-navigates to Settings once (setTab), and the
ContinuousChatOverlay suppresses the boot banner and swaps the "waking up…"
placeholder for a Settings hint — reusing the EXISTING in-transcript no_provider
error gate ("Connect a provider → Open Settings") as the error surface. Clears
automatically once a real reply lands (provider wired) and re-arms on a fresh
miss.
Tests: co-located vitest (jsdom) cover detection, single navigation,
idempotency, clear-on-recovery, re-arm, boot-banner suppression, and placeholder
swap — plus a Playwright before/after evidence capture over the real overlay.
Closes #11879
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(orchestrator): stop verify-failed completions from shadowing the successful retry as origin best result
…ub-agents via OPENCODE_CONFIG_CONTENT gateway mode (86bc107, #11651) promised a child env dump contains no raw provider key, but an opencode spawn broke the invariant twice over: buildOpencodeSpawnConfig embedded the raw cerebras/opencode/cloud key as provider options.apiKey inside the JSON assigned to env.OPENCODE_CONFIG_CONTENT, and applyModelGatewayEnv — which runs after and deletes only the seven named env keys — never touched it. the child env carried the raw key AND the opencode child pointed its baseURL straight at api.cerebras.ai / eliza cloud, bypassing the gateway. - buildOpencodeSpawnConfig checks resolveModelGatewayConfig() first, before any credential read (env, runtime settings, or config-env — setting() falls back to all three, so env-key deletion alone could never fix this). in gateway mode it returns a gateway-pointed openai-compatible provider config: nothing raw to leak, and the child routes through the gateway instead of bypassing it. - applyModelGatewayEnv enforces the stated invariant literally: raw values captured from the named keys are swept out of every remaining env value, so a composite carrier (a JSON blob like OPENCODE_CONFIG_CONTENT) that still embeds a raw key is dropped whole. fail-closed backstop for future merge steps. off-mode behavior is byte-identical; a new off-mode test pins the legacy direct-cerebras wiring. model-gateway-env.test.ts now exercises agentType opencode — the untested gap that hid this.
fix(orchestrator): gateway mode leaked raw provider key to opencode sub-agents via OPENCODE_CONFIG_CONTENT
…pps earning inference markup (#11870) A re-review BAN set review_status='rejected' but left monetization_enabled true, and the creator-earnings path (deductCredits/reconcileCredits/ processPurchase) gates on that flag alone — only NEW paid charges checked isAppMonetizationApproved. A rejected (prohibited-category) app therefore kept collecting inference markup on every chat/generate-image/messages call and stayed publicly usable, contradicting the invariant documented at api/v1/apps/[id]/route.ts ("a rejected re-review DOES cut everything off"). - runAppReview: a rejection now flips monetization_enabled=false in the same transaction (pricing preserved; re-enable requires fresh approval via PUT /apps/:id/monetization). Composes with the create-time gate (#11828) and the restore gate (#11834/#11843). - Earnings math derives its effective flag from isAppMonetizationActive (enabled AND not rejected) so rows persisted rejected+enabled before this fix earn nothing either; the draft re-gate deliberately keeps accruing per the documented grandfather DECISION. - Real-PGlite ledger proof: approved+enabled earns 25% markup; a re-review ban (real runAppReview, deterministic pre-filter) revokes the flag and later calls earn ZERO; legacy rejected+enabled rows earn nothing (markup + purchase share). Red against pre-fix source, green with the fix. Refs #11834 #11843. Closes #11870. [cloud-security]
…ched boots On a warm/cached load the app boots almost instantly, so the view transitions loading -> none within a few milliseconds. StartupShell returned the full-screen orange StartupLoading splash immediately for the "loading" kind, so those few ms painted the splash and then ripped it away — a jarring flash. Gate the loading splash behind STARTUP_SPLASH_DELAY_MS (220ms): render it only once the loading state has persisted past the threshold. A boot that becomes ready first never paints it. Error / pairing / bootstrap views stay immediate. The delay uses an effect-based timer (useState + useEffect + setTimeout, cleared on unmount / view-kind change) so no render-time clock/timer is introduced and the audit:ui-determinism gate stays green. The startup-shell:first-paint mark now fires only when visible startup UI actually paints (immediate views, or the splash once its gate opens) — never on a null-rendering mount — preserving the dedupe-by-name behavior. StartupLoading markup/roles/test ids are unchanged. Closes #11883 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-reject fix(cloud): review rejection revokes app monetization — stop banned apps earning inference markup (#11870)
…r gate, 5 coverage-ratchet drifts, deterministic #11030 deadlock guard (#11898) packages/ui no-backdrop-blur-gate (#9141 battery): #11829's new NotificationCenter reintroduced backdrop-blur-2xl/backdrop-saturate-150 on the sheet/panel shell. Drop the GPU backdrop filter and carry readability with a near-opaque base (bg-neutral-950/[0.87]) instead; refresh the committed home-screen e2e artifacts (sheet + panel verified readable over the live launcher in headless chromium, 10 screenshots + walkthrough video). packages/app coverage/ratchet gates (5 reds, all real drift, no baselines loosened): - core-view-action-surface + view-switching matrices: track the automations core view (added by b07f3d9 without a surface owner) and the background settings subsection (#10994 registered it in SETTINGS_SECTION_META only) — AutomationsFeed + BackgroundSettings* are real agent-surface owners. - route-coverage: plugin-birdclaw (#11385) declares a production collapsed gui/xr/tui view that was never added to the manifest ratchet. Wire it fully: manifest list, XR ratchet, runtime-plugin boot classification, gui+tui visual-matrix cases, tracked visual-review rows, manager-visible tile case, HMR lockstep probe, GUI interaction owners (its real plugin.test.ts + BirdclawView.test.tsx), and the ui-smoke stub (view registration + honest zero-key /api/birdclaw/status "not installed" state). Both birdclaw Playwright visual cases pass live (real BirdclawView bundle renders the setup card; audit JSON + screenshots reviewed). - ui-smoke-coverage: scenario-pr.yml still hand-named the 10 pre-#11442 voice-workbench spec filenames; point the slice at the renamed specs. - view-interaction-coverage: the launcher owner declaration still claimed edit-mode/drag-to-reorder coverage that #11523's read-only launcher removed; declare what run-launcher-e2e.mjs actually proves now (no-edit long-press, tap-launch telemetry). ios-local-agent-transport #11030 deadlock guard (both ui + app-core copies, ~1-in-4 flaky under a loaded suite): the 10s wall-clock Promise.race lost to a CPU-starved event loop. Replace it with a deterministic detector — promise assimilation invoking the hostile proxy's fabricated `then` proves the raw Capacitor proxy crossed an await (the exact #11030 regression) and rejects instantly with the descriptive error. Verified: reintroducing the raw-proxy bug fails the test immediately with the #11030 message; fixed transport never touches `then` (asserted). Suites: packages/ui 544 files / 5532 pass; packages/app 37 files / 316 pass; app-core transport suite 30 pass; typecheck green (ui, app, app-core); biome clean on touched files.
…ch-action (#11853 sibling) (#11904) The existing *-gate.test.ts files are all STYLE gates. Two production UI bugs slipped past every one of them plus manual QA because they were MECHANICS bugs (the pixels looked right, the interaction was dead): (a) drawer-not-scrollable: a clamped-height (max-h-[..vh]) + flex-col + overflow-hidden shell with no inner overflow-y-auto scroll body — taller content is dead-clipped and unreachable. (b) broken-swipe: a useHorizontalPager surface with no explicit touch-action — the browser default (auto) steals the horizontal pan and fires pointercancel, so the flick never commits on touch. Adds a static (no-browser) vitest gate scoped to the real drawer/pager surfaces (McpDetailDrawer, Launcher, HomeLauncherSurface). Comments are stripped before scanning and the drawer scroll-body triad is checked per-element (not per-file) so a comment mention or a decoy scroller can't mask a regression. Self-tests plant each bug shape (incl. the exact false-negatives codex flagged) and assert the detector fires. Green against develop; fails on both planted real-bug shapes. This is the MECHANICS gap not covered by #11868 (44px tap-target), #11877 (focus order), or #11898 (test-red clearing). Enforcement is #11853's job. — [sol-orch] Co-authored-by: wakesync <shadow@shad0w.xyz>
fix(ui): dynamic view/overlay load failures show the recoverable card, never a blank screen
…a finish error
The in-chat first-run wizard could loop forever with no escape. On any
finish/provision error, `seedError` re-appended the runtime CHOICE
(`${message}\n\n${RUNTIME_CHOICE}`), so a persistent failure — e.g. the
"Not found" 404 from `POST /api/first-run` — re-offered the same runtime
question indefinitely with no distinct error surface and no way out. The
"Other / configure in Settings" provider pick made it worse: it ran a local
finish that hit the same 404 and re-looped instead of ever opening Settings.
This is the UX/navigation fix (the underlying 404 is a separate backend/env
issue, out of scope):
- Finish errors now seed a DISTINCT, non-looping recovery turn
(`first-run:error:*`) with a human message and a dedicated
`[CHOICE:first-run id=error]`: Try again (`error:retry`, re-runs the last
runtime's finish), Choose a different way to run (`error:restart`, re-offers a
fresh unlocked runtime CHOICE), and Configure in Settings (`error:settings`).
- "Other / configure in Settings" (`provider:other`) now opens the Settings tab
(`setTab("settings")`) and exits first-run (`completeFirstRun("settings")`)
via a shared `exitToSettings` helper, latched by `completedRef` so a
double-tap can't flip the gate twice.
- Raw terse errors ("Not found", "Failed to fetch", …) are wrapped in a clear,
human sentence via `finishErrorMessage`.
Local-success, cloud, and needs-cloud-login paths are unchanged.
Tests: updated the affected conductor tests and added coverage for the
persistent-404 no-loop + retry + Settings escape, the cloud `error:retry`
re-run, and `provider:other` -> Settings exit. Also hardened `beforeEach` to
restore default mock implementations (clearAllMocks keeps implementations, so a
leaked mockRejectedValue would poison later tests). Full src/first-run suite:
191 passed.
Closes #11882
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ebased fix(ui): recover first-run finish errors without looping
…calibration-ceiling fix (#11373) (#11905) * feat(voice): expose AEC delivery counters in window.__jniVoice.status() (#11373) The JNI ambient pipeline (#11562) counts far-end playbackFrame deliveries and tracks the last echo-cancelled batch ERLE, but the on-device harness status() did not surface them — so on-device verification could not read the truthful delivery counters the same way /api/voice/audio-frames/status exposes them for the WebView pump path. Add playbackFramesReceived + lastEchoErleDb to JniVoiceStatus. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(voice): raise echo-delay self-calibration ceiling to 500ms + reject cap-edge locks (#11373) The Pixel 6a physical-device AEC capture (#11373 evidence) measured the real WebView pump-path playback->mic delay at ~380-410 ms — beyond the previous 300 ms ECHO_CAL_MAX_LAG_SAMPLES search ceiling. The one-shot self-calibration therefore locked a cap-edge lag (4765/4782 = ~298 ms at confidence ~0.32, barely over the 0.3 gate) and pinned an ~85 ms misalignment forever; with 256 filter taps (16 ms) the NLMS then diverges instead of cancelling (echo-only replay at the locked delay: converged-half -12 dB vs +3.3...+5.5 dB at the true delay). - ECHO_CAL_MAX_LAG_SAMPLES 4800 -> 8000 (300 ms -> 500 ms) - reject locks within one frame of the ceiling (a cap-edge peak means the true delay is likely beyond the searched range; keep observing instead) - calibration window 12000 -> 16000 samples for enough correlated overlap at large lags - annotate the android platform seed with the measured device evidence - tests: calibrates a 400 ms delay; refuses a cap-edge lock Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(voice): near-end (double-talk) seam in the AEC loop harness + physical-Android driver/analysis tools (#11373) - aec-loop-harness: nearEndAudioUrl option (+ nearUrl deep-link param) — the double-talk near-end plays through the SAME AudioContext connected straight to destination, never through the playback tap: acoustically present at the mic, absent from the far-end reference. On-device findings that forced this shape: Android WebView HTMLMediaElement rejects data: URLs (NotSupportedError) and a second CDP-created AudioContext renders silently while the harness context holds the output stream (verified on Pixel 6a — near-end corr 0.014 in the mic, i.e. inaudible). - android-physical-driver.mjs: physical-device variant of the emulator driver (wake/keyguard/pm-grant prep; volume via KEYCODE_VOLUME_* with read-verify because 'cmd media_session volume --set' silently does not apply on Pixel/Android 16; near-end via the harness seam instead of macOS 'say'). - measure-device-erle.ts: optional --delay override so a capture can be replayed at a sweep-found optimum, not only the device lock. - sweep-delay-erle.ts / lag-trajectory.ts / near-end-preservation.ts: ERLE-vs- delay sweep, windowed lag-drift trajectory, and matched-filter near-end preservation over a device capture — all through the production classes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evidence): Pixel 6a physical-device AEC acoustic-loop bundle (#11373) Android target-device leg of #11373, captured autonomously over adb/CDP (no human at the device — pm grant + volume keys + CDP cover every gate iOS could not clear). Real speaker->air->mic loop through the production /api/voice/* transport on a physical Pixel 6a (Android 16): - transport: echoReferenceWired=true, playbackSamplesReceived=354880, lastPlaybackFrameAt advancing; mic capture is genuinely acoustic (0.021 RMS room floor -> 0.074 during playback) - measured playback->mic delay: ~380-410 ms across five runs, wandering ~21 ms within a run (lag trajectory) — the finding that exposed the 300 ms calibration ceiling bug fixed in this branch - echo-only ERLE: 0 dB AEC-off baseline; +3.3...+5.5 dB converged-half at the true delay (sweep), -12 dB at the pre-fix cap-edge lock (bug evidence kept as *-cal300ms-bug-*) - double-talk: real overlapping second talker; near-end preservation +7.2 dB mean (not crushed; DTD holds) with the misalignment noise documented - synthetic control at the measured delay converges to its noise-floor ceiling (+9.9 dB) — the measurement chain is sound - screen recording, screenshot, logcat, mic characterization, full READMEs with honest limitations (WAV far-end because the fused lib fails to relocate on this build; same-loudspeaker near-end; uncontrolled room) Refs #11373 (iOS rows remain open). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Evidence hygiene cleanup for #11905.
…11734, refs #11760) (#11908) Hardware-lab acceptance row for the inference memory policy merged in PR #11822, on real Pixel 6a hardware (serial 27051JEGR10034, MemTotal 5589MB -> CONSTRAINED, nCtx=4096, idleUnloadMs=300000, no debug overrides), build 35f61d1 md5-verified on device after evicting a foreign APK a sibling session had installed. - 12.1 min foregrounded soak, 10/10 real local-inference turns (mobile-local-direct-reply, 52-58s warm, 95s cold first load) - 4 pressure releases observed: PSS 2.16->0.28GB, GL mtrack 1.60->0.05GB per release, MemAvailable ~0.7->2.0GB; released state held for the entire 7-min idle leg - transparent reload after each release: 58s turn (~+4s vs warm) - lmkd killed 48 processes across 27 other packages in the window; ai.elizaos.app killed 0 times, pid stable, exit-info before/after byte-identical (no new LOW_MEMORY of the main process) - key device-exact finding: the CONSTRAINED pressure lever (availMem < lmkThreshold+512MB = 728MB) structurally preempts the 300s idle lever on this device profile; idle firing remains covered by the emulator soak + JVM unit tests Verdict: PASS. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Exclude the global chat overlay from per-view occupancy metrics and compact the Character overview Experience summary.
Supersedes #11867. Closes #11864.\n\nValidation:\n- bun run --cwd packages/core prebuild\n- bun run --cwd packages/ui test src/components/shell/ConnectionFailedBanner.test.tsx\n- bun run --cwd packages/ui typecheck\n- bunx @biomejs/biome check changed files\n- git diff --check origin/develop...HEAD && git diff --check\n- node packages/ui/scripts/reconnecting-shift-proof.mjs\n- bun run --cwd packages/app audit:app
…#11912) Captures the four adb-measurable rows of #11734 on real Pixel 6a hardware (policy build 35f61d1, eliza-1-2b Q4 via the bionic Vulkan host), leaving only battery/power-meter + iOS rows genuinely lab-gated: - TTFT distribution: 12 identical-length turns — p50 54.3 s / p90 57.7 s (warm-only p50 54.3 / p90 54.5; 3/12 transparent post-release reloads at 57.3-58.8 s). Client TTFT == full-turn latency: the fast path emits the whole reply as one SSE chunk and the native stream decodes the full 256-token buffer per turn regardless of maxTokens. - Isolated prefill: 8-rung exact-token ladder regressed on the device-logged in-lock window — marginal ~5.1 tok/s, batch-quantized by ELIZA_LLM_N_BATCH=128 (flat <=127 tok, +~23 s per extra batch); effective decode <= 7.9 tok/s. Cross-check llama-bench pp128 3.88 / pp512 8.86 / tg128 6.78 tok/s. The historical "4.8 warm decode" is a combined-window rate. - Thermal timeline: 91.4 min at 15 s cadence — Thermal Status 0 throughout (no OS throttling), peak skin 42.9 C / TPU 68 C; battery fell 76->70% while USB-powered (bounds, does not replace, the power-meter row). - eliza-1-4b tier: the predicted finding — lowmemorykiller kills the foreground app DURING the 2.95 GB Q4_K_M load (ApplicationExitInfo reason=3 LOW_MEMORY, RSS 3.4 GB, GL mtrack 3.22 GB, MemAvailable 1670->206 MB in 22 s). The pressure-release policy cannot fire mid-load; minRamGb: 6 is confirmed real on this 5.59 GB device. 2b restored and verified afterward. Also documented: the shipped device-tier eliza-1 GGUFs (2b/4b "-256k") are Qwen3.5-architecture, not Gemma-4 (only the 8 GB "-128k" artifacts carry the cutover), and an autonomous background agent job can hold the resident-model lock longer than its own period, starving chat turns. budgets.json measuredBaselines + BASELINE.md updated (non-gating; gate budgets stay null pending multi-run stability). Refs #11734 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Supersedes #11887. Closes #11886.\n\nValidation:\n- bun run --cwd packages/core prebuild\n- bun run --cwd packages/ui test src/styles/overscroll-behavior.test.ts\n- bun run --cwd packages/ui typecheck\n- bunx @biomejs/biome check changed files\n- git diff --check origin/develop...HEAD && git diff --check\n- bun run --cwd packages/app audit:app\n\nNote: physical macOS two-finger trackpad verification requires a rebuilt macOS Electrobun app and could not be exercised from this Linux/headless environment.
|
Too many files changed for review. ( Bypass the limit by tagging |
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
LifeOps Benchmark —
|
|
❌ PR title does not match the required pattern. Please use one of these formats:
|
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
LifeOps Benchmark —
|
Promote develop → main (overnight UI/demo polish + fixes)
develop is 69 commits ahead of main (
a544b23037). Promoting to get the overnight UI/demo polish and fixes to prod.Notable payload
UI / demo polish
d6aedf88dd)3f4d0ef76f)7dfd450fbc)a747ced409)6a22c0491d)ec10626875)Money / security
e9ac8125c2)073f4d99ca)OPENCODE_CONFIG_CONTENT(b49fb99018)fc868c0439)Deploy / promote safety
6bffde9b78); verified at tip: exactly ONErunWithTrajectoryPurposeexport inpackages/cloud/api/src/stubs/elizaos-core.ts, zero diff vs main3b51a0be36)Other
Pre-promote verification
bun run typecheckclean inpackages/cloud/sharedandpackages/cloud/apiat develop tipa747ced409(own-source, tsgo --noEmit, exit 0)Merge as a merge commit (promote convention). [cloud-frontdoor] approves the migrate gate + monitors the prod deploy (churn-proof via #11653).
[cloud-frontdoor]