Background-only Bridge and Mac-node launches keep GUI onboarding and saved Gateway-profile Keychain state cold while preserving environment/config-owned Gateway connectivity.
Bound Telegram extension tests to five files per Vitest process across explicit config, directory, and full-suite routes while preserving serial isolated execution.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(test): keep shared jsdom window in step with the per-file module reset
The non-isolated runner already resets the module graph after every test file,
so each file evaluates its own component classes. The jsdom window it shares
across the whole worker was never reset with it: every Control UI component
registers with `if (!customElements.get(tag))`, so the first file to import a
component owned that tag for the rest of the run and `document.createElement`
kept building elements closed over that file's module instances. Later files'
singletons, module mocks, and spies were never the ones production reached, so
assertions failed as "expected ... to be called once, but got 0 times" in
whichever files the size-based sequencer happened to place after a warming one.
Drop repo-owned tags with the graph they came from. Dependency packages are
externalized and register once per worker through native ESM, so their
definitions are attributed by define call site and kept.
The same window also carried mounted DOM forward, so helpers reading
`document.body.querySelector(...)` answered an earlier file's leaked dialog and
focus assertions read its stale activeElement. Clear the body with it;
`document.head` stays, since dependency styles cannot be replayed either.
* fix(test): keep the jsdom definition shape local to its module
* test(cua-computer): freeze provider parity fixtures
* test(cua-computer): keep parity fixture type aliases file-local until a consumer exists
* test(cua-computer): split parity fixtures under the line cap and fix strict test types
The diagnostics change only reordered the large shard; it exposed a pre-existing one-second timeout around lazy Responses transport initialization. Fail from the stream's terminal result instead, and pre-abort egress so payload serialization stays a strict offline contract.
The node launch adapter armed a per-RPC abort timer for every invocation, even
when the RPC budget was clamped to the remaining deadline. Both timers then
expired at the same instant, so which one fired first decided whether the
adapter saw a terminal deadline or a retryable RPC timeout. On the retryable
branch the cancellation loop funded another cancel dispatch out of a
sub-millisecond residue, producing a second doomed RPC and a flaky
"reports unknown cancellation outcome after a hard cancellation deadline"
failure under CI load.
The per-RPC timer now arms only when its budget genuinely binds before the
deadline; otherwise the deadline signal alone governs the RPC. RPC-timeout
retries are unchanged where the RPC budget is the shorter bound.
The non-isolated |ui| lane resets the module graph per test file while the
jsdom document and customElements registry persist for the whole worker.
Three producers leaked across that lifetime mismatch:
- github-link-hovercard-registration.ts: each file's module instance adds
document-level bootstrap listeners; on the first real focusin every stale
instance raced customElements.define -> unhandled NotSupportedError.
Guard the define inside the single-flight loader.
- app-host.test.ts locale retry asserted through createElement, which serves
a sibling graph's shell class bound to a different i18n singleton; construct
ShellGatewayOwner directly so spy and callee share one graph.
- route-transition.test.ts assigned updateComplete over the real Lit outlet's
getter-only accessor when a sibling had registered it; define an own data
property instead (byte-identical to the hunk in PR #123347).
Adds a boundary regression test reproducing the duplicate-module-instance
order; it failed pre-fix with 2 registry defines and the NotSupportedError.
sessions.patch resolves null without sending a request when the
connection scope cannot be captured, but the read-marker guard only
unlatched on promise rejection — so the once-per-episode latch stayed
set with no request in flight, and the unread badge stayed lit on the
open session until navigating away and back. Treat a null resolution
like a failure.
* fix(ui): automations model picker shows raw "common.default" key instead of Default
t("common.default") never existed in the catalog, so the picker's
inherit option rendered the literal key string in every locale
(introduced in #122964 when cron's free-text model input became the
shared model picker). Use the existing quickSettings.model.default key.
Same-sweep i18n call-site drift fixes:
- sessions view Reasoning override now routes through
buildSessionLevelOptions like its Fast/Verbose siblings (adds the
missing sessionsView.stream key; deletes the unlabeled duplicate
withCurrentOption helper)
- activity entry summary collapses the placeholder-only
activity.entrySummary pass-through (two silently dropped params) to
the direct label call; orphan key removed
- group-delete confirm drops its dead {group} param (string has no
placeholder since the reword)
* test(ui): compact multi-line expects in cron view test to stay under max-lines
The file sits at the 1000 counted-line cap on main; extracting named
intermediates keeps the new inherit-option regression net-neutral.
* fix(ui): typing a decimal point into numeric config fields no longer deletes the stored value
For <input type=number>, partial numeric text ("0.", "-", "1e")
reports value === "" with validity.badInput. The input handlers
treated that as an intentional clear: they committed undefined, the
800ms autosave persisted the removal, and the identity resync wiped the
user's in-progress text from the DOM. Typing 0.5 into sampleRate stored
5.
Resolve numeric input state (badInput/empty/value) once in a shared
helper used by both renderTextInput's number branch and
renderNumberInput, absorbing their duplicated parse/commit/revalidate
logic. badInput now surfaces the invalid-number validity message
without committing; genuine clears keep removing optional overrides.
* test(ui): use plain validity objects instead of spreading ValidityState
Spreading a class instance drops its prototype (no-misused-spread); prod
only reads validity.badInput, so a plain object is the honest stub.
* feat(gateway): transfer node worker workspaces
* fix(gateway): harden node workspace transfer
* fix(gateway): isolate transfer HTTP contract
* fix(gateway): trim transfer HTTP exports
* feat(secrets): add authenticated egress substitution proxy
* feat(secrets): bind egress substitution to hosts
* ci(codeql): classify egress proxy bypass tunnel in network boundary query
* refactor(proxy-capture): use the canonical IP parser instead of node:net
* fix(secrets): compare proxy tokens with a process-keyed MAC