Machine providers: durable lifecycle and shared plugin APIs - #3274
Merged
Conversation
This was referenced Sep 8, 2026
ymichael
force-pushed
the
bb/machine-provider-apis
branch
7 times, most recently
from
September 11, 2026 17:26
ca79006 to
a440dec
Compare
Squash of bb/machine-provider-apis on top of 12e6e97. Machine creation is now the environment's first provisioning step, the machine migration is 0117 on top of the consolidation's 0116, and machine-phase progress and failures are reported into the thread transcript. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
focusPromptBox was a plain function declaration, so it got a new identity on every render. RootComposeView schedules it through requestAnimationFrame in an effect that lists it as a dependency, so calling it bumped focus-request state, re-rendered, produced a new identity, re-ran the effect, and called it again. The loop ran at frame cadence for as long as the composer was mounted. That effect early-returns unless startedComposing is true, which is why a cold load looked fine and returning to the new thread page from a thread did not: the loop only starts once composing has begun. Every frame it called focusEnd() on the prompt editor. Opening any menu put focus inside that menu, the next frame pulled focus back out, and Radix dismissed the layer -- the environment picker appeared to open and close instantly. Traced from an open-to-dismiss window of five milliseconds, with the dismissal stack running through our focusEnd into DismissableLayer's onDismiss. Memoize the callback so its identity is stable, and list it in the plugin composer host memo that reads it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
selectHosts silently returned every host, so ephemeral provider sandboxes leaked into machine pickers, the projectless machine chip, usage limits and the counts that gate multi-machine UI. It now takes a required scope and callers state whether they want persistent machines or all of them. The projectless chip keeps a selected ephemeral host in its list so filtering the choices never hides the current selection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bb machine list, bb updates, and bb skill install-cli-skills enumerated every host, so disposable provider sandboxes appeared as ordinary machines and collected CLI installs and update runs they discard on recreation. The server default for CLI-skill status did the same. Each enumeration now selects persistent machines, matching the app's Show all machines reveal; bb machine list --all opts back in and the table gained a Type column so sandboxes are distinguishable. Lookups by id or name still resolve sandboxes, so --machine can still target one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ymichael
force-pushed
the
bb/machine-provider-apis
branch
from
September 11, 2026 20:12
2bd1ed9 to
92d25be
Compare
ymichael
added a commit
that referenced
this pull request
Sep 11, 2026
## Human comments ## What was wrong Connect machine cleanup could become permanently stuck after the remote revocation had already succeeded but its response was lost, or after local grant cleanup failed. On retry, the owned machine row was already revoked and no longer held a label claim, so `revokeMachine` returned `not-found` instead of acknowledging the completed revocation. The provider retained its local grant and every later retry failed the same way. ## What changed - Make revocation idempotent for an already-revoked machine owned by the authenticated account. - Preserve existing authentication and account-ownership checks: missing devices, foreign devices, bogus credentials, and revoked server credentials still fail. - Preserve label-claim tunnel closure and its retry behavior; a completed retry does not close the tunnel twice. - No UI, public API shape, CLI, configuration, or server/daemon wire contract changed. No protocol-version bump is needed. ## How you verified - Added a regression that fails with the previous 404 behavior and passes when a completed owned revocation is retried through both dashboard and server-credential paths. - `pnpm exec turbo run test --filter=@bb/web --force -- src/server/api.test.ts`: 31/31 passed. - `pnpm exec turbo run test --filter=bb-plugin-connect --force -- src/server-access.test.ts src/tunnel-lifecycle.test.ts`: 20/20 passed. - `pnpm exec turbo run typecheck build --filter=@bb/web --force`: passed. - `bb plugin build plugins/connect`: passed. - Targeted formatting and `git diff --check` passed. - Independently exercised response-loss, real SQLite deletion-failure, pending reconciliation, authorization, and socket-cleanup recovery cases with owned local fixtures; no cloud credentials or vendor resources were used. Follow-up to #3274. > AGENT GENERATED
This was referenced Sep 12, 2026
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong Repository setup and teardown scripts were launched with piped stdin, but the host daemon never wrote to or closed that pipe. Any noninteractive hook that read stdin—for example, `cat >/dev/null` before doing its work—waited until the lifecycle timeout. Setup could prevent an environment from becoming ready, while teardown could skip cleanup commands after the read. ## What changed - Launch repository lifecycle scripts with the existing output-only process helper, which supplies immediate stdin EOF while preserving piped stdout and stderr. - Apply the same behavior to setup and teardown through their shared runner. - Preserve contributed environment variables, streamed UTF-8 output, timeouts, cancellation, and process-group cleanup. - No public API, CLI, configuration, or server/daemon wire contract changed. No protocol-version bump is needed. ## How you verified - Added setup and teardown regressions that read stdin before writing a marker, emit split UTF-8 output, and write stderr. Both fail before the fix and pass after it. - `pnpm exec turbo run test --filter=@bb/host-daemon --force -- src/environment-lifecycle-script.test.ts src/operation-environment.test.ts test/command/environment-hook.test.ts`: 20/20 passed. - `pnpm exec turbo run build typecheck --filter=@bb/host-daemon --force`: passed. - Targeted formatting and `git diff --check` passed. - On a real Modal sandbox, repository setup received EOF, a real Codex agent completed its turn, and a separate disposable worktree's teardown received EOF and wrote its cleanup marker. The sandbox was suspended after verification. Follow-up to #3274. > AGENT GENERATED
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong Variables saved in Machine environment were omitted from ordinary repository setup. A script needing a configured token could fail even though BB had saved the value correctly. The machine-environment support in [PR #3274](#3274) supplied explicit hooks, but normal setup ran through `environment.attach` without those values. ## What changed Resolve fresh machine variables on the server when dispatching setup, then pass them transiently through `environment.attach` into the existing setup runner. The retained provisioning request stays free of plaintext values. Existing encryption, precedence, cancellation and recovery behavior remain; unmanaged attached paths still skip setup. Adds the validated attach contribution field and bumps host-daemon protocol **204 → 205**, requiring older daemons to update. Updates the configuration documentation, machine CLI guide and bb-cli reference. No new user-facing setting or CLI command. ## How you verified - Server-delivery and setup-shell regressions failed before the fix and pass afterward. - **146 tests pass**: 57 server, 30 daemon, 56 contract and 3 integration tests. Coverage includes fresh values on repeated dispatch, local-host exclusion, encrypted storage, retained request/state privacy, missing-key failure, cancellation with duplicate attaches, explicit hooks, cloning and old-protocol rejection. - Turbo builds and typechecks passed for `@bb/server`, `@bb/host-daemon` and `@bb/host-daemon-contract`; formatting and diff checks passed. - Started `pnpm start:worktree`, configured Modal, and created a test thread through the BB CLI. A real Modal sandbox installed this server’s daemon, cloned a disposable repository, and ran ordinary setup. Setup required a configured test variable and wrote a receipt; the live Codex thread read the receipt and returned **PASS**. The initial byte comparison omitted the receipt’s trailing newline; the corrected check passed without changing the file. Focused commands: ```sh pnpm exec turbo run test --filter=@bb/server -- test/hosts/live-command.test.ts test/internal/internal-session-protocol-version.test.ts test/services/environments/provider-orchestration.test.ts src/services/hosts/host-environment.test.ts pnpm exec turbo run test --filter=@bb/host-daemon -- test/command/environment-dispatch.test.ts test/command/environment-hook.test.ts test/command/command-router.test.ts test/command/project-clone-private-env.test.ts src/operation-environment.test.ts pnpm exec turbo run test --filter=@bb/host-daemon-contract pnpm exec turbo run test --filter=@bb/integration-tests -- fake/environments/environment-attach-recovery.test.ts pnpm exec turbo run build typecheck --filter=@bb/server --filter=@bb/host-daemon --filter=@bb/host-daemon-contract pnpm exec turbo run build typecheck lint --cache-dir=.turbo/cache --output-logs=new-only --concurrency=4 ``` > AGENT GENERATED
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong The machine-environment CLI decoded every stdin chunk separately. A multibyte UTF-8 character split across pipe chunks was therefore replaced with invalid-character markers before the value was saved, even though the command reported success. This follows up on the machine-environment support added in [PR #3274](#3274). ## What changed Collect stdin as bounded byte buffers and decode UTF-8 once after EOF. The existing 65,536-byte limit is still enforced on raw bytes before removing one trailing newline. Empty input, CRLF handling, secret masking, validation, and preservation of unrelated variables are unchanged. ## How you verified - Added regressions for deliberately split UTF-8, empty input, CRLF, repeated newlines, exact ASCII and multibyte byte limits, and over-limit rejection. The split-character and multibyte-boundary cases fail before the fix and pass afterward. - `pnpm exec turbo run test typecheck build --filter=@bb/cli --force`: 59 files and 607 tests passed; build and typecheck passed. - Exact two-file formatting and `git diff --check origin/main...HEAD` passed. - Ran the built CLI against the worktree test server and its encrypted disk SQLite database. Split `café`, `€`, and `🌍` values were stored exactly; byte limits, masking, and unrelated-value preservation passed. Temporary variables were removed. > AGENT GENERATED
This was referenced Sep 12, 2026
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong The shared new-thread composer treated checkout-capable providers as eligible on every connected machine, even when a machine had no source for the selected project. That exposed Project checkout and Worktree on an unconfigured machine; if that explicit choice later became invalid, resolution could silently fall back to the primary machine. This regressed in [b3c5434](b3c5434) ([#3274](#3274)). ## What changed - Derive existing-machine checkout eligibility from the project's sources and the existing project-scoped provider query. - Hide Project checkout and Worktree when that project is not set up on a machine, while preserving valid local, remote, and hostless choices. - Retain an explicit selected machine and block submission if its checkout disappears or becomes unavailable instead of redirecting the thread elsewhere. - Add focused composer regressions for per-machine eligibility, invalidation, availability, keyboard behavior, and valid fallback-free selections. | Before | After | | --- | --- | |  |  | The paired 390×844 dark-theme captures use the actual source components with synthetic SDK and machine data. The before image is from base `1ebdc56a50`; the after image is from pushed head `63920f8faa`. No server/daemon wire contract, CLI, public SDK, generated file, or lockfile changes. ## How you verified - New eligibility regressions failed before the fix and passed after it. - `pnpm exec turbo run build typecheck test --filter=@bb/app --force` — build and typecheck passed; 4,469 tests passed and 3 were intentionally skipped. - Extra templates validation — 44 tests passed. - Browser target matrix — 20 submission/control cases plus four rejection, keyboard, focus, root, and overflow cases passed at 1280×900 and 390×844 in light and dark themes. - `git diff --check origin/main...HEAD` passed, and Git reports a conflict-free merge with current `main`. > AGENT GENERATED
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong Plugin host calls share a process and its environment. After #3274, a call needing changed machine variables waited for all active calls to finish. That could block a stop/close call behind the long-running work it was meant to stop. Cancelling a waiting call could also trigger the manager's five-second force-kill timer and interrupt unrelated calls in the same worker. ## What changed Remove the environment wait queue. While any calls are active, incoming calls run immediately using the worker's current environment, even if they supply different values. Once all calls finish, the next incoming call supplies fresh values. Values from overlapping calls are not saved as pending updates. Continuous overlapping work can intentionally retain old settings until the worker becomes idle. The environment is restored when the last active call finishes. Existing cancellation and force-kill protection for unresponsive handlers remain intact. Acquisition stays inside the call's error cleanup. Bump `HOST_DAEMON_PROTOCOL_VERSION` from 205 to 206 so enrolled machines update for the changed environment semantics. Document when plugin calls adopt settings in the machine CLI guide, configuration docs, and bb-cli skill reference. No new CLI flags or public SDK members. This PR does not touch UI code. ## How you verified - Updated real-worker regression coverage for immediate admission with different values, retaining the first values until every overlapping call finishes, adopting the next idle call's values, variable removal, cancellation/deadlines, disposal, and hung-handler termination. Four tests failed with the previous waiting implementation; all 32 plugin host manager tests pass after the change. - Post-rebase `pnpm exec turbo run test build typecheck --filter=@bb/host-daemon --filter=@bb/host-daemon-contract --force` — 617 daemon tests and 56 contract tests passed; all 11 Turbo tasks passed. - Actual browser-plugin host handlers running through the real manager, worker process, and IPC, with an injected cooperative runtime: previously close waited behind a two-second run after a variable change; now it interrupts the run and returns in 1 ms with either unchanged or changed values. - Verified through the actual built `bb` CLI, isolated source server, enrolled built daemon, and a diagnostic plugin installed with `bb plugin install`. Two 20-second calls overlapped across a machine-variable update and retained the old values in one worker PID; stop commands returned in 268 ms and 259 ms; the first idle call adopted the new values and later reflected removal. - Targeted formatting and `git diff --check origin/main...HEAD` passed. > AGENT GENERATED
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong Automatic shared-machine cleanup counted live thread executions but missed pending and starting threads whose workspace was still being prepared or whose scheduled start had not dispatched. Archiving the previous last owner could therefore remove an ephemeral machine underneath new work already assigned to it. The gap came from [b3c5434](b3c5434) ([#3274](#3274)). ## What changed - Include persisted pending/starting environment intents and preparing workspace ownership in the automatic-removal guard. - Use targeted SQLite queries so retention survives database reopening without adding a manager, timer, or schema migration. - Recheck that a machine is still available before saving a startup placement and before reserving a provider workspace, so removal winning the race fails cleanly. - Preserve cleanup for failed, cancelled, archived, deleted, and orphaned work, as well as existing explicit machine-removal behavior. No UI, host-daemon wire contract, CLI, public SDK, generated file, or lockfile changes. ## How you verified - Five new regressions failed before the fix and passed afterward: archive/project deletion during workspace preparation or a scheduled start, plus removal winning admission. - 105 relevant tests passed: 99 server tests covering environment providers, machine cleanup, and startup recovery; 6 database tests covering persistence, terminal owners, orphan rows, and reuse. - Post-rebase `pnpm exec turbo run test build typecheck --filter=@bb/server --filter=@bb/db --force` passed all 13 Turbo tasks: 2,606 server tests and the full database suite passed, with one intentional server skip. - Isolated HTTP + migrated SQLite verification covered preparation and scheduled-start cleanup through archive and project deletion. - Real Modal verification retained a machine through preparing and scheduled work, executed both surviving threads on that same machine, and removed it after the final owner was archived. - `git diff --check origin/main...HEAD` passed, and Git reports a conflict-free merge with current `main`. > AGENT GENERATED
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong After Modal creates a sandbox but saving its resource checkpoint fails, cleanup has only the allocation key. Reconciliation looked in the currently configured app, so changing App Name could make cleanup report success while leaving the original sandbox running. This affects the cleanup path introduced in #3274. ## What changed Find sandboxes across apps in the current Modal environment using the existing `bbMachineKey` tag, terminate every match, and verify removal by sandbox ID. Enumeration and termination failures remain retryable. The change stays inside the Modal plugin and requires no new stored fields, migration, core changes, or protocol changes. ## How you verified - The cross-app regression failed before the fix and passes afterward. Tests cover duplicate matching allocations, unrelated sandboxes, repeated cleanup, and enumeration/termination failures followed by retry. - `pnpm exec turbo run test typecheck prepare:bundled lint --filter=bb-plugin-environment-modal-sandbox` passed, including 52 tests. - A local probe exercised the actual cleanup route with migrated SQLite and an injected checkpoint failure. An installed-SDK probe verified tag filtering without an app filter and pagination. Both used simulated external compute; no live Modal API calls were made. > AGENT GENERATED
ymichael
added a commit
that referenced
this pull request
Sep 12, 2026
## Human comments ## What was wrong #3274 replaced plain machine names in the environment picker headers with `MachineLabel`, adding a tiny laptop icon beside every machine name, including servers and desktop machines. ## What changed Restore the previous status-dot-and-name header markup. Preserve name truncation and the conditional “this machine” badge. Update the existing picker test to assert that headers contain no laptop icon. ## How you verified - `pnpm exec turbo run test --filter=@bb/app -- EnvironmentPicker.test.tsx` — all 31 tests passed, including the “this machine” badge assertion. - Captured and visually inspected the actual picker in Ladle with fixture machines, both with and without local-daemon detection. Headers have no laptop icons; the local fixture shows the badge. Screenshot animations were disabled for stable captures. - `git diff --check` passed. > AGENT GENERATED
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human comments
What was wrong
Cloud-backed workspaces need coordinated machine allocation, enrollment, server access, and durable lifecycle ownership. Without it, interrupted setup, pause/follow-up cycles, and project deletion can strand resources or interrupt other threads sharing a machine. Manual enrollment also read its command before preparation finished, and access readiness treated a registered provider as working access.
What changed
Adds experimental machine-provider and server-access APIs with UI, SDK, CLI, and Plugin Guide support. Core owns durable machine identity, encrypted bootstrap, enrollment, allocation checkpoints, checkout ownership, and coordinated lifecycle transitions. Plugins own vendor allocation, snapshots, and idle timing. Standalone machines have independent lifetimes; environment compositions pair machine and workspace providers through
register().Includes Manual enrollment, Connect server access, and Modal sandboxes. Modal supports configurable images and size presets, filesystem snapshots, same-host resume, and diagnostics. Its vendor implementation now lives under
providers/modal/, with a shared adapter for machine lifecycle registration. Idle policy, settings, diagnostics, and UI remain Modal-specific.Ephemeral machines account for live threads and launches across projects and environments, retiring after their final owner releases them. Durable
resumingstate holds queued follow-ups until restoration completes and drives settings, environment selection, and thread banners. Interrupted allocation, suspension, resume, and cleanup recover through persisted checkpoints. Checkout recovery retries when an earlier thread-start RPC settles, so a follow-up accepted after turn completion cannot remain stuck behind that RPC.Plugin bootstrap requires an executor and uses the selected access provider; Manual setup uses internal enrollment operations. Cancellation reaches enrollment and access acquisition. Cleanup uses the creation key before a checkpoint and the resource afterward. Both UI and CLI wait for manual command readiness. Access settings and composer banners consume validated availability and refresh on recheck and plugin enable/disable; errors and timeouts become unavailable without exposing private diagnostics.
Provider-icon registrations require an agent, machine, or environment kind in the SDK. Environment providers and compositions require a description and icon. Existing untyped plugins can omit these fields at runtime; omitted icon kinds apply across kinds, while a specific kind takes precedence. Cross-plugin icon overrides remain allowed. Older compositions that omit an icon use FolderUnknownIcon, without inheriting the machine provider logo. Mobile includes the same icon and its native SF Symbol mapping.
Default machine choices, CLI enumeration, updates, and CLI-skill installation exclude ephemeral sandboxes;
bb machine list --alland explicit machine targeting retain access to them. Active sandbox threads keep their current machine identity even with only one persistent machine. Project summaries count configured and total machines within the same scope; checkout counts follow the Show all machines toggle, and hidden online sandboxes do not mask offline persistent checkouts.Plugin Guide, API map, audit entries, and CLI guides describe the implemented contracts. Removed obsolete wording/feature assertions and added compiled examples and boundary regressions. Artifact tests copy nested plugin source directories so the Modal refactor is covered while retaining SDK bundling and Dockerfile assertions.
Migration
0117_machine_providers.sqlfollows main's0116. Host daemon protocol is 203, combining main's protocol changes with this branch's machine/bootstrap/shutdown changes. Plugin SDK version is 0.4.83. Modal participates in the bundled-plugin preparation graph.How you verified
Rebased onto
bc75f9dde7and rebuilt the source app, server, daemon, bundled plugins, and matching CLI. Local checks passed 9,732 tests, with five skips, across app, server, daemon, CLI, database, domain, Plugin SDK, API map, server/daemon contracts, scripts, Connect, Modal, and plugin-build. Relevant typechecks and lint passed.The artifact regression reproduced locally before the fixture fix and passes afterward. The previous Linux package-smoke failure occurred during Ubuntu mirror installation; the rebase includes main's mirror fix.
Fresh live QA uses this worktree's isolated source server and built CLI, real Modal compute/snapshots, Connect access, and Pi agent turns executing shell tools:
The natural idle sweep suspended a third sandbox after 76 seconds with a temporary one-minute threshold. A follow-up restored its files and ran once; archive while paused automatically destroyed it in one attempt. The original ten-minute setting was restored. Independent Modal API checks confirm all three allocations have no compute and all seven captured snapshots were deleted. All six pre-existing machine phases and general/access/Modal settings match before and after.
All applicable CI checks passed on
30bf86c10b, including workspace build/typecheck/lint, every test shard, Linux/macOS package smoke, bundle budgets, and SDK/version guards. iOS and optional Node compatibility smoke are skipped by workflow conditions. The subsequent picker-description removal passes all 31 picker tests. Direct folder-browser loading is restored; omitted composition icons use FolderUnknownIcon. The affected app/server tests (18 tests), typechecks, lint, and bundle budget pass. The measured boot payload is 1,610.0 KB raw / 394.6 KB brotli, and the thread-route closure is 2,142.9 KB raw / 571.3 KB brotli. The latest CI fixes pass all 82 integration tests, all 334 mobile tests, 18 server provisioning tests, and relevant typechecks/lint. A controlled delayed start acknowledgment reproduces the checkout recovery failure before the fix and verifies successful follow-up output afterward. Integration tests ran locally with two workers after a fully parallel run encountered startup timeouts during concurrent builds. All applicable CI checks pass on5c38bd6fb4, including the integration and packages shards, workspace checks, all app/server tests, and Linux/macOS package smoke; GitHub reports the PR mergeable.Earlier passes covered stopped/interrupted setup, scheduled work and suspension recovery across server restart, access-provider errors/timeouts, and live access banner refresh. This pass does not claim desktop/mobile QA or installation of a separately managed Manual daemon. Removal of an independently managed unreachable machine can still require workspace cleanup; automatic abandonment is not implemented.
Pre-merge CLI/server rerun on
5c38bd6fb4passed with real Modal, Connect, Pi and Codex: two projects/eight environments/ten threads across one and two sandboxes; ten simultaneous offline follow-ups with exact single writes; stop/follow-up; cross-project deletion; shared-owner cleanup while the other host runs; active-turn suspension; and separate Codex and natural-idle resume checks. Manual command readiness and idempotent creation also passed. Auxiliary fixture collisions were corrected and rerun. All five allocations created during the run were automatically destroyed in one attempt, and independent Modal queries confirmed no compute and all eight captured snapshots deleted. Settings and all seven pre-existing machine phases match the baseline. Cleanup emitted non-blocking Keep Awake/offline and Codex archive/machine-removing warnings; final archive and cleanup succeeded. No code changes were needed for that QA pass.The display fixes in
2bd1ed9f36add three regression tests for current sandbox identity, scoped project counts/offline status, and checkout counts across the Show all machines toggle. All three fail before the fixes and pass afterward. All 66 focused app tests pass; app typecheck passes and lint reports no errors. The real-provider QA above ran on5c38bd6fb4, before the subsequent machine-enumeration and display changes; That push exposed the upstream Codex parity fixture failure described below.Rebased onto
18b71d810cto include #3526's fix for Codex warning parity. The earlier CI packages failure came from #3478 changing warning classification while the recorded expected event still used the unhandled-event fallback. #3526 refreshes that single fixture and pins its unhandled count to zero; it also adds provider source files to the parity test's Turbo inputs. All 21 branch commits replayed without conflicts. On rebased head92d25beb50, all 56 provider-parity tests, 281 Codex provider tests, and 66 focused app tests pass, along with app/parity/Codex typechecks. All applicable checks pass on rebased head92d25beb50in CI run 34643021790, including packages, server, all app shards, integration, workspace build/typecheck/lint, and Linux/macOS package smoke. iOS and optional Node compatibility jobs are skipped by workflow conditions.