The startup JS gzip gate was a fixed ceiling that main drifted to within
1-3 KiB of, forcing repeated hand-bumps (315->317 KiB) and failing
feature PRs on drift they did not cause (#112649 burned two CI rounds).
check-control-ui-performance.mjs now also enforces a committed baseline
(config/control-ui-startup-budget-baseline.json) with a 512 B tolerance:
regressions beyond baseline+tolerance fail with an actionable message,
intentional increases become a reviewed one-line diff via
--update-baseline --reason, meaningfully lighter builds print a
lower-the-baseline hint, and a malformed/missing baseline fails closed.
The fixed ceiling stays as the cumulative-creep backstop.
Closes#112743.
* feat(scripts): add watch-pr-ci CI watcher with mergeable and attach prechecks
* fix(scripts): require successful attached PR CI run
* fix(scripts): harden watch-pr-ci verdicts against foreign runs and truncated rollups
* fix(scripts): add fresh-run gating to watch-pr-ci attachment
* fix(scripts): guard stale-cancelled verdict against truncated context pages
* fix(scripts): declare rollup context total count
* fix(scripts): sanitize check names and close the final polling interval
* test(scripts): type deadline wait samples
The core-runtime-media-ui shard runs its ui config non-isolated for speed, but the
full chat-pane lifecycle tests instantiate the pane component, which relies on
chat-thread/chat-message module-level singletons (thread-state map, confirmation
dismisser WeakMap, module-scoped document context-menu listeners) and spies on those
modules. Under the shared non-isolated graph a stateful predecessor file can leave
those modules duplicated, so the pane binds to a different instance than the test's
spy/registry -- producing order-dependent flakes: `removeEventListener`-not-called
teardown assertions or 120s session-lifecycle hangs. Reproduced deterministically on
a Linux Node 24 Testbox (MAX_WORKERS=1); isolating a single file only shifted the
failure to a sibling pane test, so the whole full-pane family shares the fragility.
Route the 7 full-pane lifecycle test files through a new isolated jsdom lane
(vitest.ui-isolated.config.ts, isolate: true) for a fresh module graph; the other
~370 ui tests stay fast and non-isolated. Registered in both shard registries
(ci-node-test-plan.mjs, vitest.test-shards.mjs) and excluded from vitest.ui.config.ts.
Verified on Testbox: the deterministic single-worker media-ui shard goes from failing
to 5182 passed / 0 failed. Test-infrastructure only; no product code changes.
* chore(scripts): end failing oxlint runs with a stable status line
A crashed run-oxlint wrapper printed only a stack trace, and a lint
invocation whose output was truncated (cmd | tail -N) read as success —
which recently let a wrapper crash (stale node_modules after a dep-adding
merge) masquerade as a clean lint. Route the CLI entry through a small
wrapper that converts crashes into exit 1 and ends every failing run
with '[oxlint] FAILED (exit N)' as the final line.
* chore(scripts): declare runOxlintCliEntry in the script declaration contract
check-guards verifies .d.mts contracts against .mjs exports and
check-test-types consumes them; the new entry export needed both the
declaration and explicit log-parameter annotations in the test.
* feat(mobile): session dashboard screens on iOS and Android via authenticated Control UI webview
* fix(android): keep configured Control UI base path in session dashboard URL
* docs(android): note system-trust boundary of the shared Control UI webview
* fix(android): origin-only document-start rule for Control UI auth script
* chore(i18n): refresh native inventory on rebased head
* fix(ios): swiftlint closure form in session dashboard toolbar
* fix(i18n): tolerate workflow-owned pending native rows in PR alignment checks
* fix(android): KTX toUri per lint and refresh native inventory
* fix(android): ktlint import order incl. main-inherited fleet test, refresh inventory
Follow-up to c5254f13ee (#112074): delete the legacy string-match timeout
classifier (the CLI path only sees typed GatewayTransportError from
callGateway's wrapper timer), the duplicate JSON/blank-message validation
in the private gateway command, the now-pointless getGatewayDispatchConfig
wrapper, the single-use embedded-loader alias, and the cross-os release
guard for the EMBEDDED FALLBACK marker no build can emit anymore.
* refactor(ai): invert plugin coupling behind the transport host port
* fix(ai): queue custom transport registrations until the host is configured
* refactor(ai): remove relocated transport sources from src/agents
* fix(ai): source core stream types from canonical packages and fix tarball fixtures
* fix(ai): invert plugin transport host wiring
* fix(ai): harden managed transport projection
* test(ai): register synchronous stream in transport mock
* fix(ai): lazily install transport runtime host
* fix(ai): preserve completion compat detection