chore(promote): develop → main — 36 commits (money fail-closed pricing, MCP debit refund, credential-pool + agent-api hardening, #11640 deploy-concurrency fix) - #11673
Conversation
…11627) Fresh de-larp audit of scripts/ + packages/scripts/ + packages/*/scripts + plugins/*/scripts. The larp catch-verifier axis (main().catch(console.error)) is already 0 (fixed in #11548); the 42 `|| true` occurrences are all legitimate best-effort probes/idempotent cleanup; the check-i18n / check-secret-hygiene "dupes" have intentionally diverged for fork vs in-repo invocation. Removed the airtight completed-throwaway subset (each proven 0-reference tree-wide via `git grep -l <basename>`, none test-glob files, none imported): - plugins/plugin-training/scripts/gepa-view-switching.ts - plugins/plugin-training/scripts/multishot-view-switching.ts - packages/app/scripts/android-webview-attach-probe.mjs - packages/benchmarks/social-alpha/trenches-chat-dataset/scripts/monitor_progress.sh - packages/benchmarks/social-alpha/trenches-chat-dataset/scripts/calculate_success_metrics.ts - packages/benchmarks/social-alpha/trenches-chat-dataset/scripts/calculate_realistic_success_metrics.ts Evidence: .github/issue-evidence/10200-scripts-delarp-slice/README.md Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ent nested-list detection (#11633) - keys.ts: parseKeyId() returned null for any keyId whose base key is the literal "+" symbol ("+", "ctrl++", ...) because split("+") yields a trailing empty part, so those bindings could never match despite being valid KeyIds. Resolve a trailing "+" separator to the "+" key. - utils.ts: couldBeEmoji() treated every grapheme longer than 2 code units as an emoji (width 2), so decomposed (NFD) characters with two combining marks (e.g. Vietnamese ế as e+U+0302+U+0301) measured width 2 while their NFC form measured 1, breaking truncation/padding/wrap alignment for NFD text. Detect multi-codepoint emoji via ZWJ instead; skin tones, flags, keycaps and ZWJ families are still caught by the existing range/VS16 checks. - markdown/list-renderer.ts: nested-list detection sniffed rendered lines for a hardcoded cyan SGR prefix (\x1b[36m). With colors disabled (NO_COLOR, piped output) or any non-cyan listBullet theme, nested lists got double indentation and items starting with a nested list grew an extra bullet ("- - b"). Tag nested-list lines structurally instead of sniffing ANSI codes.
* fix(local-inference): point at Metal nil-pipeline guard * test(local-inference): #11612 Apple Metal regression proof for the nil-pipeline guard Build the guarded llama.cpp submodule commit 299d5b78b with the Apple Metal toolchain (macOS 26.2, M4 Max) and run a real eliza-1 0.8B GGUF fully offloaded to the Metal GPU (every layer -> device MTL0). Generation completes correctly ("... is **Paris**.", 430/174 tok/s) with no nil-pipeline abort, proving the two new nil-checks are inert on the healthy Metal path and only fire on a genuinely nil pipeline. Verifies the regression risk of the submodule bump on the one platform the original Linux capture host could not. Refs #11612. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… keyless readiness (#11346) (#11630) * fix(benchmarks): swe_bench pyproject readme points at deleted RESEARCH.md RESEARCH.md was removed in the repo-wide unreferenced-markdown cleanup, so `pip install -e packages/benchmarks/swe_bench` failed at metadata build. Point readme at the README.md that exists. Audited every other packages/benchmarks/*/pyproject.toml readme reference; swe_bench was the only dead one (webshop and vending-bench still have their RESEARCH.md). Refs #11346 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(benchmarks): fix stale code_agent_matrix flags in orchestrator runbook --require-publishable-live, --trend, --require-non-code-regression-evidence, and --non-code-regression-summary do not exist in code_agent_matrix.py (argparse exit 2). Replace them with the real CLI: the --enforce-* gate stack, --summarize + --compare-summary for longitudinal trend deltas, --enforce-no-regression, --quality-guardrail-summary + --enforce-quality-guardrail, and --write-run-index. Drop --no-docker from the seven-benchmark commands: osworld requires Docker and preflight rejects --no-docker for it unless OSWORLD_PROVIDER_NAME is configured. Every command was executed on this host: preflights exit 2 with missing CEREBRAS_API_KEY as the only blocking issue, run commands exit 0 under --dry-run (21 cells for the 7x3 matrix), the trend command exits 0, and the guardrail gate exits 10 as designed when the guardrail report is not clean. Refs #11346 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evidence): #11346 keyless readiness evidence — oracle smoke, TS build proof, verified operator commands Adds the evidence bundle for the code-agent matrix readiness pass: - terminal-bench oracle smoke run to completion on the real vendored corpus (analyze-access-logs): real per-task Docker image build, real container, reference solution through the default tmux-session environment, real grader, exit 0, 1/1 passed (log + JSON/MD reports). - TS build proof: bunx turbo build scoped to @elizaos/plugin-agent-orchestrator and @elizaos/app-core, 96/96 tasks successful, exit 0. - README operator commands rewritten to flags code_agent_matrix.py actually accepts, each executed on this host to confirm it parses and runs. - Existing dry-run / mock / pip-install artifacts from the readiness pass. No model run happened; every artifact is dry-run, mock, oracle, or build proof, and the README says so. The only remaining live-run blocker is CEREBRAS_API_KEY. Refs #11346 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…bundle the whole tree (#11628) The pre-#11271 ui-fixture-e2e.yml triggered on all of packages/ui/src/**; ui-e2e-gate.yml (which carries all 14 fixture-runner legs since 19b40d1) only triggered on an enumerated subset. Changes under e.g. packages/ui/src/cloud/**, components/settings/**, bridge/**, or components/composites/** skipped the gate entirely, even though the runners esbuild-bundle from the full source tree — a regression in a shared component reachable from any runner could land unguarded. Replace the enumerated packages/ui/src/* entries with packages/ui/src/** in both the pull_request and push paths lists. The packages/ui package.json line, the packages/agent server-module lines, and the workflow self-path are unchanged. Refs #11419 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…specs (#10832) (#11623) * feat(plugin-pty): gated interactive claude/codex vendor-CLI spawn specs (#10832) Phase 2 of the interactive PTY tier: `POST /api/pty/sessions` now accepts kind "claude" | "codex", spawning the real interactive vendor CLI (plain TUI, no --print / codex exec one-shot args) via new pure spec builders in lib/vendor-cli-spec.ts, mirroring buildElizaCodeCerebrasSpec. Gate: PTY_VENDOR_CLI_ENABLED — separate from PTY_INTERACTIVE_ENABLED, default OFF, exact truthy allowlist (true/1/on/yes) so near-miss values fail closed, and always rejected on ELIZA_BUILD_VARIANT=store. Credentials reuse the existing subscription-plugin conventions and are opaque passthroughs: CLAUDE_CODE_OAUTH_TOKEN (plugin-anthropic-proxy's env credential path; else the CLI reads ~/.claude/.credentials.json via the inherited HOME) and CODEX_HOME (the per-account convention; else ~/.codex/auth.json). Both keys are added to the store's spec-env allowlist. Bin resolution: PTY_CLAUDE_BIN / PTY_CODEX_BIN overrides, else PATH, with actionable install guidance when missing. Refs #10832 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(cockpit): drive the vendor-CLI tier through CockpitInteractiveTerminal (#10832) Adds an optional kind prop ("eliza-code" default | "claude" | "codex") to the existing terminal surface: vendor kinds spawn without a cerebras tier, the header/status name the vendor CLI, and the server's PTY_VENDOR_CLI_ENABLED gate rejection surfaces in the existing error state. Widens spawnPtySession's kind typing in the ui client accordingly. Refs #10832 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evidence): live vendor-CLI smoke + vitest logs for #10832 Real route handler + real PtyService + real installed claude/codex binaries: gate-off 403, store-build 403, and live interactive TUI bytes from both CLIs, plus the plugin-pty (88) and cockpit-terminal (11) vitest summaries. Refs #10832 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evidence): make pty vendor smoke portable --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Shaw <shawgotbags@gmail.com>
…f misreporting it (#11643) devicectl `launch --console` runs the target under a debug session (ptrace + exception ports) that SIGTRAPs (signal 5) the full-Bun no-JIT engine host the moment it loads — the app dies before engine start, while icon-tap/unattended launches boot healthily. devicectl relays that crash as a nonzero exit code (signal null), which ios-device-logs.mjs previously misreported as a generic 'phone locked / not paired' failure. - Add pure classifyConsoleExit() + CONSOLE_SIGTRAP_SIGNATURE to ios-device-lib.mjs: recognize the SIGTRAP from the child signal OR the captured log (EXC_BREAKPOINT / SIGTRAP / 'signal 5' / Trace/BPT trap), word-boundary anchored so our own 'signal 15' bounded detach is never confused for it. Reported non-fatally so the boot-trace pull still runs; genuine locked/unpaired early-exits stay fatal. - ios-device-logs.mjs uses the classifier, names #11515 in the pre-capture warning + header, and prints the exact '--no-console --pull-boot-trace' re-run when a SIGTRAP is seen without a boot-trace pull. - 7 new unit tests (40 total pass); AGENTS.md/CLAUDE.md + evidence README codify the decision: engine observability uses the boot-trace pull, never --console. Closes #11515. Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… allowlist extension (#11638) * fix(app-deploy): forward registry push cred + per-org image-namespace allowlist extension (#11636) the code-fixable half of the normie app-deploy 403: forward the dedicated registry-scoped GHCR_USERNAME/GHCR_TOKEN pair to coding sub-agents (broad GITHUB_TOKEN/GH_TOKEN/CR_PAT stay denied), add the docker-login line + missing-credential reporting to the eliza cloud deploy contract, and let an operator grant an org its own image namespace via organizations.settings.allowed_image_namespaces — additive, fail-closed, shape-validated, consulted at all three image-gate call sites only after the platform env allowlist denies. refs #8434 * fix(orchestrator): deny broad github tokens for sub-agent credentials --------- Co-authored-by: Shaw <shawgotbags@gmail.com>
* docs(local-inference): document device setting policy * docs(local-inference): clarify device policy gates * docs(local-inference): note the chat-path stream-step default (8) vs runner default (32) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(cloud): sweep stranded credit reservations * fix(cloud): settle reservations from stored estimate * fix(cloud): sweep stranded app chat reservations --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Shaw <shawgotbags@gmail.com>
Co-authored-by: Shaw <shawgotbags@gmail.com>
…per-window rate-limit sweep (#11642) * fix(agent-api): NaN-safe rows pagination, RFC 2397 data-URL parsing, per-window rate-limit sweep Three unit-proven fixes in the agent HTTP API: - database.ts: GET /api/database/tables/:table/rows parsed offset/limit with Math.max(0, Number(raw)), which propagates NaN (?offset=abc -> 'OFFSET NaN' in the SQL text -> query throws -> 500) and let floats/Infinity through to the interpolated LIMIT/OFFSET clause. Extracted parseRowsPagination() built on @elizaos/shared parseClampedInteger: non-numeric input falls back to defaults, out-of-range clamps, output is always a SQL-safe integer. - media-store.ts: DATA_URL_RE only accepted 'data:<mime>(;base64),' so any RFC 2397 data URL with media-type parameters (data:text/plain;charset=utf-8; base64,...) failed to parse; persistDataUrl returned null and the raw base64 stayed inline in the message record/context - the exact thing the content-addressed store exists to prevent. Header is now split at the first comma and parsed token-wise (mime = first token, base64 = any ';base64' token), preserving the markup-sniff/attachment-download path for parameterized SVG. - rate-limiter.ts: the periodic cleanup swept EVERY bucket with the calling endpoint's windowMs, so a check with a short window erased still-valid history from keys tracked with longer windows, silently resetting their limits. Buckets now remember their own windowMs and the sweep prunes each by its own window; resetRateLimits() also resets the sweep clock so tests are deterministic. All three verified by mutation testing (fix reverted -> new tests fail). * test(agent): keep swarm synthesis fixture typed --------- Co-authored-by: Shaw <shawgotbags@gmail.com>
…ork (#11376) (#11629) The #11271 failure mode: a 304-file squash titled as a small cloud-refund refactor carried a stale checkout's file contents over work already merged on develop — no conflicts, merge-base only 8 minutes old, so no base-age check could have caught it. This lands the final #11376 acceptance criterion: a fast required PR check that makes that impossible to repeat silently. - .github/workflows/stale-base-guard.yml — runs on every PR in seconds: blobless --depth=1500 fetch, guard script snapshotted from the BASE branch (a PR cannot neuter the gate that judges it), GIT_NO_LAZY_FETCH=1 so any accidental content read fails loudly. `stale-base-ack` label = loud override for deliberate reverts; labeled/unlabeled events re-trigger. - packages/scripts/stale-base-guard.mjs — plumbing-only (oid compares, no blob reads): flags a PR when it sets a file byte-identically back to an older blob from the target's first-parent history, discarding newer merged work. Heal/re-land PRs (restoring work a clobber reverted) pass by construction; deletion-only findings are non-blocking notices unless a modification-revert corroborates the stale-tree signature. Staleness backstop: merge-base > 200 first-parent commits or > 72 h behind the tip. - packages/scripts/stale-base-guard.self-test.mjs — 9 fixture-repo scenarios (clobber shape, heal, deletions, re-adds, backstops, --window, --ack, missing merge-base); the workflow runs it before the guard on every PR. Proven on real history (evidence in .github/issue-evidence/11376-stale-base-guard/): the actual #11271 topology FAILS with 297 silent-revert findings in ~8 s; the five #11271-restore merges (#11427 #11430 #11433 #11490 #11522) and ten live open PRs all PASS with 0 findings; the exact CI clone shape verified against github.com (fetch 2.4 s, guard sub-second). Refs #11376 Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Shaw <shawgotbags@gmail.com>
Co-authored-by: lalalune <shaw.nicola.walters@gmail.com>
…te (#11579) Port the six finer-grained regression tests from the closed PR #11553 atop the merged #11555 fix: bare unfenced code-body verbatim, fenced code with a prose lead-in, pretty-printed JSON, prose containing separator/emphasis runs, still-defers empty/whitespace/refusal-stub/degenerate-run, and refusal-that-continues-into-content + bare social apology. Running the ported suite against the merged implementation exposed two real coverage gaps in isUnusableStage1Reply: - Bare refusal stubs ("I am not sure.", "I don't know.", "I'm sorry, I can't help with that.") were delivered verbatim instead of deferring — #11504's ask was to tighten the unusable signal to actual refusals/empties. Port #11553's whole-reply-anchored isBareRefusalStage1Reply (apology-prefix stripped; refusal-plus-content and bare social apologies are kept). - Multi-token degenerate spam ("aaaaa bbbbb") slipped the merged whole-reply single-code-point check. Add #11553's per-token check (every whitespace-separated token is one character repeated 5+ times) alongside the existing set-based check, so nothing the merged heuristic already caught is weakened. Refs #11504 Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…model can never bill $0 (#11635) (#11647) * fix(cloud): fail-closed last-resort inference pricing so an uncatalogued model can never bill $0 (#11635) The pricing fallback ladder is provider-max → env-default → last-resort. The last-resort tier was `?? 0`: a servable model with no catalog row AND no AI_PRICING_FALLBACK_* env default billed $0 for both reserve and settle = free inference / silently uncollected revenue. Make tier-3 non-zero and fail-closed (lookup.ts): a per-product-family `lastResortTokenUnitPrice` returning a conservative frontier-max rate (language $5/M in, $25/M out; embedding $0.2/M), keyed off the same `productFamily` used for the catalog lookup. The request still serves — it just can never bill $0; a real catalog entry (cheaper) supersedes it next lookup, and the existing loud log still flags the catalog gap. Matches the function's own stated intent ("must not be under-billed at $0 either"). Tests (red-before/green-after proven by stashing lookup.ts): the two suites that codified the $0 behavior now assert a non-zero, sane (< $0.10) charge, and the embedding case asserts the cheaper family rate was chosen. Typecheck clean, biome clean. Note: the 2 pre-existing `fetchEntriesForSource provider-outage` failures in this dir fail identically on develop tip (a gateway mock-leak across sibling test files) — orthogonal to this change, not introduced here. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cloud): log last-resort pricing fallback --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Shaw <shawgotbags@gmail.com>
Co-authored-by: lalalune <shaw.nicola.walters@gmail.com>
…sk lifecycle evidence (2026-07 campaign) (#11650) * docs(evidence): orchestrator surfaces — rendered + recorded + live task lifecycle evidence (2026-07 campaign) Evidence bundle for the #11028 orchestrator campaign: - desktop/ + mobile/ screenshots of springboard, orchestrator, task-coordinator, and coding-cockpit surfaces (1440x900 and 390x844) - flow/ series: a real task driven through the cockpit in Claude subscription mode — starting -> open -> active (sub-agent Kira executing "Write hello.txt") -> validating - video/orchestrator-walkthrough.webm: 9m03s recording of the full walk (losslessly remuxed to finalize the container) - logs/: structured backend logs correlating to the original flow and the mobile re-capture, plus the mobile browser console - capture.mjs: the Playwright tooling that produced everything - README.md: per-artifact manifest, honest about the duplicated flow frames, the missing terminal-status frame, and the lost desktop console log Mobile shots were taken after a stack reboot and show the same task persisted (validating, 1.9K tokens) — cross-restart persistence proof. Refs #11028 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evidence): force-add gitignored *.log evidence files for #11028 bundle The logs/ correlating artifacts (backend structured logs + browser console) were silently excluded by the repo *.log ignore rule; they are part of the evidence manifest and must ship with it. Refs #11028 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ing sub-agents (#11536 E2) (#11651) Opt-in via ELIZA_MODEL_GATEWAY_URL + ELIZA_MODEL_GATEWAY_TOKEN (config-env conventions: config env section first, process.env fallback). Mode is ON only when BOTH are set non-empty. In gateway mode, AcpService.buildEnv — the single choke point where the child env is assembled for both the native and cli ACP transports — runs a final rewrite: OPENAI_BASE_URL + ANTHROPIC_BASE_URL point at the gateway, the gateway token is injected as OPENAI_API_KEY + ANTHROPIC_API_KEY, and every raw provider credential the merge paths can carry (OPENAI_API_KEY, ANTHROPIC_API_KEY, CODEX_API_KEY, CEREBRAS_API_KEY, ELIZA_OPENCODE_API_KEY, ELIZA_E2E_CEREBRAS_API_KEY, CLAUDE_CODE_OAUTH_TOKEN) is deleted first — excluded, not shadowed — so a child env dump contains no raw provider key. Runs LAST in buildEnv so host forwarding, customCredentials, spawn extras, and account selection cannot reintroduce a raw key. Mode off (either var missing) leaves the child env byte-identical to previous behavior; a structured [AcpService] log line records engagement per spawn without ever logging the token. Refs #11536 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(benchmarks): point swe-bench metadata at README * docs(swe-bench): remove stale research readme reference --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com>
Fail closed when a non-zero token side has no exact catalog row, no provider-max fallback, and no positive AI_PRICING_FALLBACK_* env default. This removes the hardcoded floor approach: we should not sell inference we do not know how to price. Zero-token sides still cost zero without requiring a price, provider-max fallback still covers priced providers, and explicit positive env defaults still work. Env fallback values <= 0 are treated as invalid.
…e, not just non-ok HTTP (#11637) (#11652) * fix(cloud): refund the MCP proxy upfront debit on every post-debit failure, not just non-ok HTTP (#11637) mcp/proxy/[mcpId] debits the caller upfront (reserveAndDeductCredits) but only refunded when the upstream returned a non-ok HTTP status. Every other post-debit failure kept the money = a silent over-charge: - unsafe/blocked external endpoint → 400 - container has no load balancer → 503 - endpoint misconfigured → 500 - upstream unreachable/DNS/refused → 502 Add a `refundPrecharge(reason, status?)` helper right after the debit and call it on all four early-return failure branches; the non-ok HTTP branch now routes through the same helper. Refund amount = the exact upfront debit. Test (__tests__/mcp-proxy-refund.test.ts): drives the real route with mocked deps and asserts refundCredits fires on unreachable(502)/unsafe(400)/ container(503)/non-ok, and NOT on success. Red-before/green-after proven by stashing the route: the three new failure-path cases fail (refund never called) without the fix. typecheck + biome clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cloud): refund MCP proxy invalid JSON precharge --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
#11509) (#11656) PR #11509 removed the third runtime chip (`runtime:other` = "Bring your own keys") from the in-chat onboarding conductor — it conflated the inference- provider axis with the runtime-location axis. Four ui-smoke specs still asserted that deleted chip is VISIBLE, so they are guaranteed-red on develop: - runtime-configurability.spec.ts - first-run-startup.spec.ts - walkthrough/walkthrough-capture-smoke.spec.ts - walkthrough/journey.ts (step 02) Each now asserts the chip is absent (`toHaveCount(0)`) instead of visible, and the stale header/expectation comments + the IN_CHAT_ONBOARDING_DESIGN.md option list are corrected to the shipped Cloud/Local chooser. The conductor seeds only runtime:cloud + runtime:local (use-first-run-conductor.ts:108-113); BYOK remains reachable as provider:other one step later. The unit tests that assert a stale runtime:other pick is consumed as a no-op are correct and left unchanged. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…t be cancelled mid-flight (#11640) (#11653) * ci(cloud-deploy): give the deploy jobs per-env concurrency so a prod deploy can't be cancelled mid-flight (#11640) migrate-db already has a job-level `cloud-db-migrate-<env>` concurrency group with cancel-in-progress:false, but the deploy-api / deploy-console / deploy-app jobs had none — they inherited only the workflow-level group, which did not protect the in-flight job. With the fleet's rapid develop→main promote cadence, every newer main run preempted the running Worker deploy, so NO Worker deploy completed since 19:13Z and prod ran stale code while only Pages/console updated. Add a per-job, per-env concurrency group (job-level groups are repo-wide, so they serialize the same job ACROSS runs — queue, never cancel): - deploy-api → cloud-cf-deploy-api-<production|staging>, cancel-in-progress:false - deploy-console→ cloud-cf-deploy-console-<pr-N|production|staging> - deploy-app → cloud-cf-deploy-app-<pr-N|production|staging> PR previews keep a per-PR group that DOES dedupe (cancel-in-progress:true); main/dispatch-prod and develop/staging never cancel. Distinct group per job so the three still run in parallel within a run. YAML validated (parses; 4/4 jobs carry concurrency). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evidence): record cloud deploy concurrency validation --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(cloud): harden credential pool followups * fix(cloud): prevent pooled affiliate markup * fix(app-core): remove coding account empty fallbacks * fix(cloud): preserve app billing with pooled credentials * docs(evidence): refresh credential pool verify proof --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…of always CPU (#10727) (#11654) * fix(local-inference): image-gen honors the probed GPU vendor instead of always CPU (#10727) The image-gen loader hardcoded `gpu: undefined` in the ImageGenRuntimeProfile, so selectImageGenBackends fell through to sd-cpp CPU on every Linux/Windows box — even NVIDIA, whose backend probeHardware reliably detects via nvidia-smi. A silent CPU fallback with an accelerated path available (the #10727 rule). - Add pure imageGenGpuVendorFromProbeBackend (cuda->nvidia, metal->apple, vulkan->amd, null->undefined) and thread the real probe vendor into the profile; NVIDIA Linux/Windows now reaches the CUDA/TensorRT path. Probe failure degrades gracefully to the platform default with a logged reason (no silent swallow). - SEV-4: the embedding handler's swallowed `probeHardware().catch(() => undefined)` now logs why, so a broken probe on an accelerated box is visible. - SEV-3: correct two false hardware.ts comments (claimed the probe uses capacitor-llama and reports AMD as vulkan — it does neither; it uses nvidia-smi + Apple-Silicon detection and leaves AMD/Intel null at probe). - Tests exercise the REAL mapper the caller uses (not synthetic gpu profiles), asserting NVIDIA reaches CUDA and macOS/AMD paths are unchanged. Known, deliberately deferred: embeddings/image-gen on AMD/Intel still run CPU because probeHardware leaves them null at probe time (no cheap pre-load VRAM query; guessing vulkan risks a hard GPU-open throw with no CPU retry). Routed to a real-GPU-host follow-up rather than shipped blind from a macOS host. Refs #10727. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(local-inference): record imagegen GPU probe evidence --------- Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(scenarios): effect proofs for 8 keyless connector scenarios (#11381) — WIP Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(scenarios): effect proofs — vision, suno, goals, health, convo (#11381) WIP Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(scenarios): effect proofs — orchestrator, facewear, relationships, task-coordinator (#11381) WIP Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(scenarios): lower action-effect ratchet * WIP: fleet round-3 salvage (credit wall) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(scenarios): tighten action-effect ratchet baseline --------- Co-authored-by: lalalune <shaw.nicola.walters@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Shaw <shawgotbags@gmail.com>
) (#11657) * refactor(cloud-ui): collapse 6 use-session-auth + 3 auth-query + 2 auth-gate clones into cloud/lib (#11341) ~1,000 lines of cloned Steward session/auth-gate glue existed across billing, api-explorer, instances, public-pages, account-security, monetization, api-keys, and analytics. No production consumer used the divergent extended fields (authSource/stewardAuthenticated/stewardUser) — only a test mock did. One canonical hook now lives in cloud/lib: use-session-auth (with the Playwright test-auth bypass the browser suites rely on) + auth-query. Refs #11341 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(cloud-ui): delete dead cloud barrels, settings-section adapters, and the unreachable connectors route (#11341) Dead code with zero importers, verified by import-graph scan + repo-wide grep: - account-security {Account,Security,Permissions}Section.tsx adapters — the registered settings sections use the *Surface exports directly. - api-keys/ApiKeysSection.tsx + api-keys/index.ts (same pattern). - billing/index.ts, organization/index.ts, cloud/index.ts barrels — register-all and settings/sections.tsx import concrete files; the '@elizaos/ui/cloud' bare subpath and the 'export * as cloud' namespace had no consumers anywhere in the repo. - connectors' dashboard/settings/connections route: nothing navigates to it — every backend OAuth callback and in-app link targets /dashboard/settings?tab=connections (a different, unregistered path). The cloud-connectors settings section is the real mount. - connectors per-connection barrel re-exports (internal-only components). Refs #11341 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(cloud-ui): one canonical home per account-management surface — Settings sections + compat redirects (#11341) The plan doc (packages/cloud/AGENT_FIRST_EXPERIENCE.md, #11340) calls for ONE billing/settings entry for credits, checkout, developer keys, connections, and account management. Before this change most of those concepts had TWO registered homes: a standalone /dashboard/* route AND a Settings section rendering the same body — and the shell's own dashboard/billing → settings redirect was DEAD code, shadowed by the identically-pathed registered route. Collapsed to the Settings section as the single mount, with compat redirects carrying every legacy deep link: - dashboard/billing → settings#cloud-billing (redirect un-shadowed; the Stripe ?canceled=true banner moved into BillingSectionBody so it renders at the canonical home; dashboard/billing/success + invoices stay) - dashboard/monetization, /earnings, /affiliates → settings#cloud-monetization (3 standalone wrappers deleted; the tabbed MonetizationView is the home) - dashboard/account, /security, /security/permissions → settings sections (route wrappers deleted; *Route.tsx files renamed to *Surface.tsx) - dashboard/api-keys → settings#cloud-api-keys (was already redirect-only; ApiKeysRoute.tsx renamed to ApiKeysSurface.tsx) - dashboard/settings?tab=<x> → the backend OAuth/Stripe return URLs that used this legacy shape 404'd on the dashboard/* catch-all; a tab-aware redirect now maps them onto the settings sections Bug fixes surfaced by the audit: - /settings#billing and /settings#api-keys (the declared-canonical URLs, incl. the apex authenticated home) resolved to NO section — section ids are cloud-*. readSettingsHashSection now has a legacy alias map, and all in-repo links point at the canonical #cloud-* hashes. - ParamRedirect appended the query string AFTER the target hash, producing /settings#billing?x=y; it now orders path + search + hash. - BillingSuccessPage had a vacuous fromSettings ternary with two identical branches. register-all.test.ts now pins the invariant both ways: flow routes stay registered; account-management paths must NOT be (they'd shadow their redirects). Refs #11341 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(cloud-ui): strip migration narration, stale claims, and dead props from the cloud surfaces (#11341) Comment slop only — no behavior change except one dead-code removal: - Removed ~120 'Ported/Lifted from @elizaos/cloud-frontend/...' provenance sentences and 'Rewired:/Changes vs the original/Migration notes' diff blocks. The package they narrate against was deleted; the comments described the port, not the code. - Removed Wave-3 / re-IA Step 2 / REVISION-2 / PLAN §, DECISIONS.md citations (in-motion migration phasing, not architecture). - Fixed stale factual claims (billing-tab 'standalone billing entry', connectors-upsell 'standalone cloud route', instances 'mirroring the api-keys domain', analytics 'Wave-3 settings section'). - billing/components/success-client.tsx: CreditBalanceDisplay accepted a {sessionId, creditsAdded} props interface and discarded it — props removed at the definition and the only call site. - cli-login-page.test.tsx: trimmed the mock's authSource/stewardUser/ stewardAuthenticated fields (a contract no production code ever read). Kept: durable rationale (why wallet sign-in is absent, why titles are set imperatively, why the copy-key action can't exist, MFA-enroll-not-wired note, backend endpoint maps). Refs #11341 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(cloud-ui,cloud-e2e): rendered evidence + spec update for the unified account-management surfaces (#11341) - New real-browser harness packages/ui/src/cloud/__e2e__/run-slop-removal-e2e.mjs (mock cloud stack + PGlite + SIWE key + real Tailwind + esbuild fixture + Playwright): proves all 11 legacy /dashboard/* deep links + the 2 legacy hash aliases land on their canonical /settings#<section> homes, and screenshots the canonical sections (billing incl. relocated ?canceled banner, monetization tabs, security anchors, api-keys, account) at desktop + mobile with real mock-stack data. 26/26 checks green; output (22 screenshots + walkthrough.webm + RESULT.json) committed. - cloud-e2e frontend-monetization.spec.ts: earnings/billing no longer have standalone routes; the spec now asserts the compat redirects against the REAL packages/app frontend (passed locally in 45.5s: apps + analytics fetch assertions green, all 5 redirect URL assertions green). Refs #11341 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(cloud-ui): port the #11558 gate regression test onto the consolidated cloud/lib/auth-query (#11341) develop's #11558 fixed the analytics/api-keys gates by rewiring them onto useSessionAuth and added analytics/lib/auth-query.test.tsx. This branch deletes those per-domain gate clones entirely — every domain now shares cloud/lib/auth-query, which already gates on the canonical useSessionAuth (localStorage-JWT fallback included), so the fix holds structurally. The regression test moves to cloud/lib/auth-query.test.tsx against the shared gate (+ a caller-enabled=false case). 4/4 green. Refs #11341 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>
…s + frontend-hosting (#11646) The ui-e2e-runner-coverage ratchet was red on develop: run-credentials-e2e.mjs (#11488 org credentials tab) and run-frontend-hosting-e2e.mjs (#10690/#11425 hosting work) landed with no packages/ui package.json script and no CI leg, so they could only run by hand. Add test:credentials-e2e and test:frontend-hosting-e2e scripts and matching ui-e2e-gate.yml legs. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…g rendered evidence (#11342) (#11659) * test(app): cloud-surface aesthetic audit harness (audit:cloud) + launcher cloud-gating rendered evidence spec (#11342) - new audit-cloud Playwright project + audit:cloud script: walks every registered cloud route (register-all.ts) at desktop+mobile, captures rest+hover screenshots, scans #10725 brand rules, writes manual-review stubs + report.json + contact-sheet.html, with a coverage guard against the live cloud-route registry - launcher-cloud-gating.spec.ts: renders the REAL launcher with a cloud-apps catalog entry and proves the LAUNCHER_CLOUD_IDS gate — tile absent while /api/cloud/status is disconnected, present when connected (desktop 1280x800 + mobile 390x844), plus a recorded cloud setup walkthrough (launcher -> Settings -> Connect Cloud -> tile appears) - extract shared brand-color scans (collectBlueColors/ collectHoverViolations) out of all-views-aesthetic-audit into helpers/brand-color-scans.ts so both audits enforce one rule set Refs #11342, #10725 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): analytics auth gate falls back to the persisted Steward token; audit stubs + coverage guard hardening (#11342) - analytics used a context-only auth gate (no persisted-token fallback), so /dashboard/analytics hung on its loading skeleton whenever the Steward runtime was not mounted; it now shares the canonical cloud/lib/auth-query gate like applications/approvals/documents - cloud audit: shape-accurate billing settings stub (autoTopUp/limits/ payAsYouGoFromEarnings — the {} stub crashed BillingPage), analytics successRate as a fraction, coverage guard reads the route registry from the RUNNING bundle (node import of the domain tree breaks on extensionless ESM subpaths), walkthrough video via recordVideo context - launcher-gating evidence committed: desktop+mobile cloud active/inactive launcher screenshots, setup walkthrough webm + stills, README with repro commands Refs #11342, #10725 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): no-blue palette rule on the cloud connections page (#11342) dashboard/settings/connections rendered Discord blurple (#5865F2) and Telegram blue (#0088cc) on icons, avatar chips, doc links, and the two primary connect buttons — the only blue the cloud-surface audit's DOM scan found across all 42 routes. Third-party brand blues already have an in-repo no-blue precedent (EarningsPageClient's network dots). Icons go neutral (text-txt), avatar chips + links go accent, and the connect buttons drop to the default accent button (orange -> darker-orange hover). Also: app-charge audit stub now carries the full AppChargeDetails shape (expiresAt/paidAt/amountUsd/providers/paymentUrl) — the page formats expiresAt with Intl and crashed on the earlier minimal fixture. Refs #11342, #10725 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(evidence): cloud-surface visual audit — 42 pages × 2 viewports, hand-filled verdicts (#11342) audit:cloud run 3, 85/85 green. Committed per PR_EVIDENCE.md: desktop/ + mobile/ screenshots (rest + hover), manual-review/<slug>.md hand verdicts for every registered cloud route, report.json (machine scan: zero blue, zero orange-hover violations, zero console errors except the documented app-auth test-auth harness limitation), and contact-sheet.html. Verdicts: 25 good · 16 needs-work · 1 needs-eyeball (harness-gated). The needs-work set shares one systemic root cause documented in the README: the dark-only cloud-frontend port hardcodes ~895 text-white usages across 93 files while the app-hosted shell renders the light theme, so headings/copy land white-on-cream — a #10725 theme-token sweep, not per-page patches. Refs #11342, #10725 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>
…URL/TOKEN) with fail-closed strict mode (#11536 E1) (#11660) * feat(core): vendor-neutral model-gateway config (ELIZA_MODEL_GATEWAY_URL/TOKEN) with fail-closed strict mode (#11536 E1) Add a vendor-neutral credential-broker gateway layer so a single OpenAI-compatible gateway can front all model traffic without raw provider keys ever reaching the model client. - New packages/core/src/model-gateway.ts: resolveModelGateway() / applyModelGateway(). ELIZA_MODEL_GATEWAY_URL takes precedence as the effective base URL and ELIZA_MODEL_GATEWAY_TOKEN as the effective api key at the same resolution layer that consumes OPENAI_BASE_URL / OPENAI_API_KEY, so every OpenAI-compatible client inherits gateway mode. Vendor-neutral: the gateway only needs to be OpenAI-compatible. - Scrubber: when gateway mode is on, the raw provider key is dropped from the resolved OpenAI-compatible config so it never travels with the gateway request. - Fail-closed strict mode (ELIZA_MODEL_GATEWAY_STRICT=1): if a raw provider key is present while gateway mode is on, throw ModelGatewayStrictError naming the offending var. Non-strict: gateway silently wins. - Wire choke points: features/documents/config.ts (feeds llm.ts embed + text createOpenAI baseURL/apiKey) and testing/inference-provider.ts openai endpoint detection. - Export from both node + browser barrels (pure string logic, no Node deps). - Tests next to the module: URL/token precedence, strict fail-closed names the offending var, resolved config carries no raw key material when gateway mode on, canonical env-var-name contract. Sibling layer: PR #11651 (E2, merged) covers the spawned sub-agent env path in plugins/plugin-agent-orchestrator. It defines the canonical env-var-name contract (ELIZA_MODEL_GATEWAY_URL / _TOKEN). This module mirrors those constant names (MODEL_GATEWAY_URL_KEY / _TOKEN_KEY) for cross-layer greppability but DUPLICATES rather than imports them, since packages/core must not depend on a plugin. Core runtime only; does not touch packages/cloud. Co-authored-by: wakesync <shadow@shad0w.xyz> * chore(core): sort model gateway barrel export --------- Co-authored-by: wakesync <shadow@shad0w.xyz> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…te + decouple spawn success from event-recording (#11641) (#11667) * fix(orchestrator): portable orchestrator_tasks session lookup on pglite + decouple spawn success from event-recording (#11641) The runtime-db task store resolved a sessionId->task by `SELECT document FROM orchestrator_tasks WHERE document LIKE ?`. On pglite/postgres the drizzle driver does not treat that JSON-bearing column comparison as a plain-text LIKE the way sqlite does, so the query throws on every session event. Two live symptoms on self-hosted pglite nodes: 1. OrchestratorTaskService.onSessionEvent -> resolveTaskId -> findSession threw on every `ready`/`tool_running`/... event, logging a failed-query warn per event, forever. 2. POST /tasks/{id}/agents returned 500 even though acp.spawnSession succeeded and the agent was doing work, so API consumers saw a false failure and could double-spawn. Fixes: - findSession now prefilters on the indexed `search_text` column (a plain TEXT column listTasks already LIKE-matches on every backend) instead of the JSON `document` column. buildSearchText folds each session id into search_text so the DB narrows to candidate rows; the JS sessions.find stays the authoritative match (no substring false-positive can resolve to the wrong session). A full-scan fallback runs only when the targeted prefilter misses (legacy rows persisted before this change), keeping the hot event path cheap. Portable on sqlite, pglite, and postgres. - spawnAgentForTask decouples the API response from durable recording: once acp.spawnSession succeeds the in-memory index is seeded and the session write is best-effort. If recording degrades, it returns a coherent 2xx detail carrying the just-spawned session instead of a 500. - The failed-record warn is rate-limited to once per sessionId via a Set on the service (cleared on task delete), ending the per-event spam. Tests: findSession portability against a pglite-LIKE-rejecting adapter, false-positive isolation across tasks, the indexed-prefilter (no full-table scan) guard, spawn-success-despite-recording-failure -> 2xx, and warn-once-per-session. Full plugin suite: 1270 passed, 15 pre-existing env failures (drizzle-orm/opencode/smithers/provision resolution), zero new failures. Co-authored-by: wakesync <shadow@shad0w.xyz> * test(orchestrator): record pglite session lookup evidence --------- Co-authored-by: wakesync <shadow@shad0w.xyz> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… loader's capability gate (#10727) (#11671) Follow-up to the merged #10727 image-gen vendor-threading fix (#11654), which only genuinely helped Windows NVIDIA. A 5-lens adversarial review caught that on Linux+NVIDIA the fix was still a no-op: selectImageGenBackends gated the CUDA head on `profile.sdCpp?.cudaCapable`, positive evidence the real caller never populates, so a Linux NVIDIA box still returned [{sd-cpp, cpu}] — byte-identical to the pre-fix output — and silently ran image-gen on CPU (the primary #10727 target). - Linux+NVIDIA now proposes CUDA first and lets loadSdCppImageGenBackend be the single source of capability truth (it probes the binary and throws ImageGenBackendUnavailableError → clean CPU fall-through when CUDA is unproven). Only demote to CPU-only on explicit evidence the binary CANNOT do CUDA. Same trust-the-loader contract win32 and the AMD/Intel branch already use. - Log each accelerated→next image-gen fall-through so a GPU box degrading to CPU is visible, not silent — the #10727 failure mode one layer below selection. - Correct the SEV-4 embedding probe-failure warn: the fallback is the performance preset (gpuLayers auto), not a 'conservative default'. - Tests: assert CUDA-first on the EXACT real-caller profile shape (no synthetic sdCpp — the shape the merged test masked with an injected cudaCapable flag), add a mocked-probe service seam guarding the wiring, and prove macOS is unaffected. Refs #10727. Co-authored-by: Shaw <shawgotbags@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Too many files changed for review. ( |
|
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 —
|
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Promote develop (261b5b4) → main (1fb1c53), 36 commits.
Money / security fixes shipping
Deploy reliability (this promote benefits directly)
Gates
Residual risk: robot-fleet disk saturation (#11640 second half) can still 900s-timeout checkout under load — deploy runs being monitored; migrate gate needs approval as usual.
— nubs-cloud [cloud-frontdoor]