mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
perf/1961-cli-compile-cache
18 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
03c3984066 |
perf(contracts): granularize entry surfaces so hub importers stop evaluating the facade clump (#1969)
* perf(contracts): granularize entry surfaces so hub importers stop evaluating the facade clump
`@agent-device/contracts/platform` unions 32 vocabulary modules and
`/interaction` another 18. A file that value-imports either evaluates the whole
union to reach one function, and because permanent hubs sat behind them —
`command-descriptor/registry.ts`, `core/capabilities.ts`,
`interactors/register-builtins.ts`, `command-descriptor/platform-execution-entry.ts` —
that union rode into roughly half the unit suite's test graphs.
Give every vocabulary module its own entry subpath and move all value-importers
onto the module that owns the symbol. Type-only importers are left alone: `import
type` is erased, so it already evaluated nothing.
Measured with the #1950 eager-import-closure walker over all 974 unit-core test
files, against base
|
||
|
|
81409f1a7c |
refactor: migrate type to the request-bound device runtime (#1935)
* refactor: migrate type to the request-bound device runtime
Wave 5 unit 2 for #1739 (ADR 0019), find's last blocker. `type "text"` and
`find <q> type "text"` now reach the device through one admitted, request-bound
`typeText` operation instead of the `handleTypeCommand` interactor leaf and its
dispatch-table arm.
- New `TypeTextRuntimeOperations` contract riding the same `Interactor` seam as
focus/screenshot/element-text; the operation returns the interactor's own
closed `TypeTextBackendResult`, so Apple route evidence passes through and
every other owner types blind, exactly as before. The iOS synthesized-type
commit wait (#1676) is Apple-interactor-internal and moves nowhere.
- The interaction backend's `typeText` member exists only when the `type`
handler admitted and bound a runtime — no caller can fall back to legacy
dispatch, so the command keeps exactly one execution path (R41).
- `executeBoundTypeText` reproduces the retired leaf byte-for-byte: leading-ref
rejection with the same hint, space-joined positionals, the 0-10000 delay
bound, and only textEntryRoute surviving from the owner's result. Its parse
pins moved from the dispatch-level tests into the daemon runtime test.
- Exact-owner facts replace the capability bucket (apple sim+device, android
all-but-simulator-row, harmonyos emulator+device, linux device, web device,
vega unavailable, providers wherever their interactor is reachable) and
`type` leaves HARMONYOS_SUPPORTED_COMMANDS / WEB_INTERACTION_COMMANDS.
- The Linux desktop replay types a digit on real hardware; the coverage
manifest promotes `type` contract -> live with the two-sided count pins.
- Android/webdriver facts helpers extracted (androidTouchFact, interactorCell)
to keep inspectFacts under the complexity gate.
`find` stays legacy: both of its direct execution legs now share bound
runtimes, so the atomic R35 cutover is next.
* refactor(type): single-pass daemon routing, shared binder source, owner cell tests
Review follow-ups on #1935.
- The type handler now calls the bound executor directly: the interaction-
runtime hop validated and formatted what executeBoundTypeText validates and
formats again, so it is gone — no boundTypeText backend member, no second
result rebuild. The ADR 0014 frame expiry moves to the handler.
- New contracts/interactor-operation-binding.ts: one local resolver and one
fail-closed provider resolver shared by the screenshot, focus, and type
binders — three private copies retired, provider error text preserved.
- provider-limrun/interaction-operations.ts: the interactor-backed interaction
cells move out of the app-log owner (586 -> 563 lines, below its pre-unit
size); text interaction is composed by that owner, not defined in it.
- Every owner runtime test now pins the focusPoint/typeText fact cells and
bound-operation presence for its exact kinds: apple, android (incl. the
synthetic-simulator refusal), harmonyos, linux, web, vega (refusal + hint),
webdriver (reachability-gated, incl. inactive session), limrun (live +
recovery). The webdriver unsupported-capability row documents that
interaction gates on interactor reachability, not capture declarations.
- The Linux replay assertion is now change-sensitive: type "555" then wait for
a 555 node — no calculator button carries that label, so the wait passes only
if the keystrokes landed in the display; deleting the type step turns it red.
* fix(replay): give the calculator focus before the Linux type assertion
The change-sensitive wait exposed what the review predicted: the typed digits
never landed, because `focus 100 100` clicks the DESKTOP and takes keyboard
focus away from the calculator. The old broad assertion masked exactly this.
The retries then wedged on a latent quirk: attempt-1 leaves the pointer at
(100,100), and the next attempt's `xdotool mousemove --sync` to the same point
waits for a motion event that never comes, so every retry dies at the focus
step with a 10s timeout — which is why the lane reported step 7, not the
failing wait.
New tail: `focus 100 100` (R40 evidence + survival assert), then
`click "label=1"` — a resolved press inside the window that restores keyboard
focus, proves pointer input lands in the app, and moves the pointer off
(100,100) so retries cannot trip the mousemove no-op hang — then `type "55"`
and `wait "label=155 || text=155 || value=155"`. No button is labelled 155, so
the wait passes only if the typed keystrokes reached the display.
* refactor(type): delete the fallow SDK typeText surface, drop dead surface fields
Thermo-nuclear review follow-ups (reviewed at 82fb8c2dc; the three-hop relay
it names was already deleted in
|
||
|
|
46eff36f85 |
refactor: migrate focus to the request-bound device runtime (#1925)
* refactor: migrate focus to the request-bound device runtime Wave 5's first unit (#1739, ADR 0019). `focus x y` and `find <q> focus` now reach the device through one admitted, request-bound `focusPoint` operation instead of the `handleFocusCommand` interactor leaf and its dispatch-table arm. - New `FocusRuntimeOperations` contract with local and provider interactor binders, mirroring the screenshot/element-text seam rather than inventing a second way for one operation class to reach its mechanics. - Exact-owner facts replace the capability bucket: apple simulator/device, android emulator/device/unknown, harmonyos emulator/device, linux device, web device, vega none, providers wherever their interactor is reachable. That is the retired bucket's cell table, restated as facts. - `focus` leaves BASE_COMMAND_CAPABILITY_MATRIX and both hand-maintained overlays (HARMONYOS_SUPPORTED_COMMANDS, WEB_INTERACTION_COMMANDS). - R40 is the new parametrized cutover row; `focusPoint` has exactly one owner. - The `x y` positional parse moves to utils and is shared with the still-legacy touch siblings, so a migrated command cannot drift from them. `find` stays legacy: this unit owns its focus leg only, its `type` leg still dispatches, and R35 waits on the Wave 5 `type` unit. * test(focus): cover the owning interactor binders, lower the find ratchet Review follow-ups on #1925. P1: focus-runtime.test.ts bound a fake focusPoint, so deleting the interactor call inside bindLocalFocusInteractor left focus a successful no-op with every test green. Adds packages/contracts/src/focus-runtime.test.ts, which executes both binders and asserts resolver context, positional (x, y) forwarding, the structured missing-provider failure, and that an already-cancelled request never resolves an interactor at all. Two planted mutants confirm it bites: removing `await interactor.focus(input.point.x, input.point.y)` and transposing its two arguments each fail exactly the two forwarding tests, while the daemon-level focus and find suites stay green — which is the gap the reviewer named. Coverage: find.test.ts shrank to 1204 lines when its focus assertion moved off the dispatch mock; the ratchet pin follows it down. * test(focus): add live Linux focus coverage to the desktop replay The Linux `focus` claim rested on the provider scenario at command-contract level. The desktop replay runs on real Linux hardware in the Smoke lane, so it now runs a coordinate focus and re-asserts the session survived it. Coordinate, not selector: the step exists to prove the migrated `focusPoint` path executes on real hardware, so it must not be able to fail on match ambiguity or CI layout drift. Reclassifies focus contract -> live in the Linux coverage manifest and updates the two pinned counts. The manifest gate is two-sided — a live claim must name a command the replay actually invokes — so the claim cannot drift from the file. |
||
|
|
17bdca76cc |
refactor: migrate wait to request-bound runtime (#1875)
* refactor: migrate wait to request-bound runtime * fix: preserve native selector wait observation * fix: classify wait observations as conditional * refactor: compact conditional runtime declarations * fix: isolate selector runtime intents |
||
|
|
494eb52f66 |
refactor: migrate get to the request-bound device runtime (#1877)
* refactor: migrate get to the request-bound device runtime `get` declares `elementReadRuntimeUse` (required `captureSnapshot`, preferred `readTextAtPoint`), admits once from exact owner facts, refuses before binding, and binds exactly once. Its capability bucket, the static HarmonyOS/Web command sets that augmented it, and `requireCommandSupported` admission for `get` are gone; `'get'` leaves the `createSelectorRuntime` capability union. The neutral `readTextAtPoint` operation replaces the branch-per-family legacy `read` dispatch on the `get` path. Every local family and both providers now classify it exhaustively — Web, HarmonyOS, Vega and every provider row report it unavailable, which is behaviour-preserving because the legacy dispatch had no arm for them and threw on every call before falling back. R36 is the new parametrized cutover row. * fix(get): admit before the direct-iOS fast path; close the element-read outcome Review blockers on #1877. 1. `dispatchGetViaRuntime` could complete the direct-iOS selector query before `resolveBoundGetRuntime`. Once `get` declares `device-runtime`, ADR 0019 requires resolve -> admit -> bind before anything in the request path operates, so admission now runs first for every target shape and the fast path is a fast path *within* an admitted request. Regression: an eligible direct selector cannot operate when facts refuse admission. 2. `readTextAtPoint` returned `Promise<string>` and `readTextForNode` caught any throw and fell back, assigning a typed diagnostic after an untyped failure. It now returns a closed `ElementTextReadOutcome`; fallback happens only for the contract's classified reasons; unexpected errors propagate. The reason union is derived from its runtime list so the two cannot drift, and an unhandled reason is a compile error at the consumer. This retires the generic catch the start record promised. * feat(daemon): land the selector capture seam with get as its first consumer Takes ownership of the request-bound selector capture seam from #1876, which cannot ship standalone: with find's cutover deferred it had no consuming command (ADR 0019 §10) and was not dead-code clean (check:production-exports 19 -> 20). `get` is its first consumer, so it lands here. Adopts find's handoff as given. The one shape change, approved by the coordinator: the selector family gets its own capture uses carrying a PREFERRED `readTextAtPoint`, declared ALONGSIDE the snapshot uses so `snapshot`/`diff` keep binding exactly what they bind today. The read is surfaced through the existing arms of `bindSnapshotCaptureRuntime`, reusing the same selectActiveAppSnapshot / selectSnapshotWithoutActiveApp selectors — no second plan-to-operation dispatch. `get` now runs through `createBoundSelectorRuntime`; `resolveBoundGetRuntime` and its test are deleted as superseded, and `'get'` leaves the `createSelectorRuntime` capability union. The legacy read adapter survives for `find <q> get text` and is selected by which command constructed the runtime — never by failure, family, environment, or flag — so `get` cannot reach it. It retires in find's cutover, where the last consumer moves. * refactor: retire the read dispatch alias across both selector consumers Read-only `find` now constructs a BOUND selector backend, so `get text` and `find <q> get text` execute the same bound `readTextAtPoint` instead of one binding it and the other dispatching the legacy `read`. This moves find's READ LEG only: find's descriptor stays LEGACY_PLATFORM_EXECUTION and it claims no cutover row. With no consumer left, the whole chain goes: the `read` registry entry and its `dispatch: {}` projection, `DISPATCH_HANDLERS.read`, `handleReadCommand`, `interaction-read-legacy-dispatch.ts`, and the duplicate platform reader branches it carried. `read` was the only `dispatch-alias` descriptor, so that catalog group goes too. Deleting the registry entry drops 'read' from DescriptorDispatchCommandName, which makes a surviving DISPATCH_HANDLERS.read a compile error rather than something R36 has to police. R36 now claims the retirement it can prove. `find.test.ts` is over the size tripwire, so its handler invocation is extracted to find-handler-fixture.ts and the pin lowered 1237 -> 1221. * refactor(daemon): apply the seam addendum after #1876 was re-scoped Two edits, per find's ADDENDUM.md: 1. `includeRects` returns to `buildRuntimeCaptureInput`. It was removed from #1876 as unconsumed; the selector capture path is genuinely its first consumer (a Web rect capture requests bounds explicitly), so it lands here under the same rule that moved the seam. `snapshot`/`diff` pass nothing. 2. The per-capture `signal` is dropped, not restored. `CaptureSnapshotInput` has no such field on this stack — it moved to `wait` (#1875) with the regression that proves per-poll abort and quiescence. `get` captures once per resolution and never polls, so nothing here needs it. The seam test and fixture coverage for it moves with the contract rather than being kept against a field that no longer exists. * refactor(get): retire the direct-iOS selector shortcut `get` declares device-runtime, so its request path must reach the platform only through operations R36 declares. `dispatchDirectIosSelectorGet` reached `runAppleRunnerCommand` through a path the row declares no operation for; admitting before a bypass is not executing through the seam, so the bypass is removed rather than ordered after admission. Every target shape — including the simple iOS `id=` selector — now resolves through the bound capture. `queryDirectIosSelector` itself stays: `offscreen-target-probe.ts` still consumes it and it remains single-copy. `dispatchDirectIosSelectorIs` belongs to `is` (#1883). Two get-only helpers (`readDirectIosGetSelector`, `buildDirectIosGetResult`) became unreachable and are deleted with the caller. Declaring `querySelector` as a fact-admitted preferred operation was rejected on duplication, not correctness: the offscreen probe takes a plain session and cannot consume a bound operation, so it would ship the query twice until Wave 5 moves the probe — the deferred-duplication shape this PR was already overruled for on the `read` alias. It returns as a declared, §9-measured operation in a later unit that also moves the probe. Cost, stated plainly: `get text id=…` loses its tree-capture skip on iOS. No fallback was added and the latency is not recovered elsewhere. R36's singularExecution claim is now what the code does rather than aspirational. * refactor: ride the Interactor seam for the element read; drop the bespoke host Two operations of the same class were reaching their mechanics two different ways: `findText` rides `Interactor` via `localInteractors.resolve`, while `readTextAtPoint` had its own host port. That is duplication of MECHANISM, so the read now rides the same seam. `Interactor` gains `readTextAtPoint?`, implemented on the Apple, Android and Linux interactors where those mechanics already live. `src/platform-runtime-element-text-host.ts` and its `elementText` host wiring are deleted; the contract binds through the resolver exactly as the snapshot runtime does. Size honesty: this removes an 89-line module but the four readers still have to exist, so they moved into the interactors rather than vanishing. Net production change is ~4 lines, not ~89. The duplication of mechanism is what is actually fixed; Wave 5/6 retires the seam for both operations together. Also from the size investigation: - `ElementTextRuntimeExecution` was byte-identical to `SnapshotRuntimeExecution`; removed and reused, as `find-text-runtime.ts` does. - Removed a stranded, stale comment in `selector-capture-binding.ts` that still claimed a duplication this branch had already retired. - `FrozenUnavailablePlatformRuntimeFacts` is derived from its input type rather than restated, removing a 14-line clone group my new cell had pushed over the detector threshold. * refactor: migrate is to the request-bound device runtime (#1883) * refactor: migrate is to the request-bound device runtime `is` declares the shared selector capture use, admits once from exact owner facts, refuses before binding, and binds exactly once. Its capability bucket, the static HarmonyOS/Web command sets that augmented it, and `requireCommandSupported` admission for `is` are gone; `'is'` leaves the `createSelectorRuntime` capability union. Admission now runs BEFORE the direct-iOS selector fast path. ADR 0019 requires resolve -> admit -> bind before anything in a `device-runtime` command's request path reaches the device, so that query becomes a fast path *within* an admitted request rather than a way around exact-owner facts. The rule is documented once, on `createBoundSelectorRuntime`, replacing the two duplicated call-site comments `get` and `is` were each carrying. Declared behaviour change: `is` takes the active-app plan split, so the facts decide per family. On iOS `appBundleId` is the XCUITest attach target — with no tracked app the runner's own process comes to the foreground, displaces the app under test, and the capture then answers confidently about the runner's own blank screen. An iOS `is` on a session with no tracked app is now a typed SESSION_NOT_FOUND refusal carrying the `open` hint. Refusing beats displacing-and-lying. Android captures the real launcher in that state and is unchanged, which is what the platform facts already encoded. The two Apple watchOS cells move from capability-admitted-then-runner-failure to a typed unavailable refusal, the same classification snapshot, diff, and get already landed. R37 is the new parametrized cutover row. `find` keeps `createSelectorRuntime` and its `requireCommandSupported` call, so `captureData` stays optional and `captureSnapshotWithInteractor` stays: this unit is not the last selector unit. * fix(is): a failing iOS assertion fails instead of exiting zero Reverses part of #557, on thymikee's explicit instruction. `is` is an assertion: the docs state it "exits non-zero on failure". The direct-iOS fast path broke that contract — it reported a failed predicate as a completed command, so on device $ agent-device is text id=… "Wrong Expected Text" Passed: is text (exit 0) because `{ok: true, pass: false}` reaches `isCliOutput`, which renders "Passed: is <predicate>" without reading `pass`. A failing assertion reported as success lets a replay run on past a broken state. Now: Error (COMMAND_FAILED): is text failed for selector id=…: expected="Wrong Expected Text" actual="Apple Account, …" (exit 1) The renderer needed no patch: a negative can no longer produce a success envelope, so it is correct by construction. Direction chosen deliberately. Making the two paths agree could have gone either way, and "an agent asked a question and got an answer" is a real argument for the other one. This follows the DOCUMENTED contract rather than merely the incumbent behaviour, and the alternative is a far larger change: a zero-exit `is` would alter every platform and path, break scripts that rely on it failing the shell, and needs its own PR, docs, and probably a major version. It is also already how `is hidden` and `is exists` behave end to end. PASSING assertion, and that arm still answers with zero captures (pinned). Only the negative falls through — what #557's own summary asked for, "preserving snapshot fallback for misses", refusing fallback only for hard failures like ambiguity. The fall-through was #557's own design, never armed: the `| null` return and the caller's `if (!payload) return null;` guard were unreachable. This makes that dead guard live. Measured on iPhone 17 (median of 9, warm daemon): predicate holds 0.14s / 0 snapshots, unchanged; predicate fails 0.25s / 1 snapshot. ~+0.11s on failing assertions only. Correctness gain beyond the envelope: the fast path evaluates a ONE-NODE tree, so `visible` cannot see the ancestor geometry a list row inherits and its negative can be wrong. Falling through re-asks the real tree and can turn a spurious negative into a pass. The #557 pin moved with its reasoning at the pin site. * fix(layering): let a cutover row state a data-only admission retirement Review blocker on #1883: R37 claimed `legacyRetirement.routeNames: ['WEB_QUERY_COMMANDS_WITH_IS', 'HARMONYOS_IS_SUPPORT']`. Neither identifier has ever existed. They satisfied the non-empty shape check while proving nothing — the vacuous registry claim AGENTS.md warns about, and a green gate that would stay green if the deletion were reverted. The cause was the model, not the row. Every `LegacyRetirementClaim` form names something that must NOT exist, which a row can always satisfy by inventing a name. `is` retired no module, route, or dispatch projection because it had none: its legacy admission was a capability bucket plus membership in two static platform command sets, so its real retirement is a DATA deletion the model could not express. Rather than patch around that with sentinels or a per-command policy file — both forbidden by the playbook — this generalizes the model. `staticCommandSets` names the sets themselves and is proven from both sides: each must still be DECLARED in production source, and must no longer list the command. A fictional set fails the first half; a skipped deletion fails the second. That is what an identifier-shaped claim cannot state. R37 now claims HARMONYOS_SUPPORTED_COMMANDS and WEB_QUERY_COMMANDS, which is the deletion it actually performed. Planted red, both halves, against the real gate: [R37 is-runtime-cutover] 2 violation(s): (is cutover row):1 — claims retired static command set 'WEB_QUERY_COMMANDS_WITH_IS', which no production source declares (is cutover row):1 — claims retired static command set 'HARMONYOS_IS_SUPPORT', which no production source declares [R37 is-runtime-cutover] 2 violation(s): src/core/capabilities.ts:59 — static command set WEB_QUERY_COMMANDS still admits is so the exact claim that shipped is now rejected by name, and so is restoring the membership it claims to have removed. Mechanism cases live with the other planted-row tests; layering goes 177 -> 181. * test(is): pin the exit-code guarantee independently of what answers the predicate Prep for the Blocker 1 retirement, which deletes `buildDirectIosIsResult` — the function the #557 reversal fixed. The reversal's guarantee must not evaporate with it, so it gets a case that does not know how the daemon decided. `is` is documented to "exit non-zero on failure". The reversal proved that at the JSON envelope; nothing pinned it at the CLI boundary, which is where the defect was actually visible (`Passed: is text`, exit 0). This asserts the CLI contract directly: a `predicate_failed` response exits 1 and never renders as passed. It survives the retirement untouched, because it asserts the outcome rather than the path. Planted red with the exact pre-#1739 envelope the shortcut produced (`{ok: true, data: {pass: false}}`): `exitSpy.calls` is `[]` — no exit call at all — so the case fails, which is the regression it exists to catch. Unpushed on purpose: the restack will carry it into the retirement cycle. * refactor(is): retire the direct-iOS selector shortcut thymikee's ruling (option b). `is` declares `device-runtime`, so its request path must reach the device only through the operations R37 declares. It did not: a simple iOS `id=`/`label=` target was answered by a direct XCUITest querySelector without any capture, ordered after admission but not executing through the seam. This is not retired because it was wrong. `wait` hypothesized that the degenerate one-node evaluation mis-answers `is visible` for off-viewport nodes, traced it through the code convincingly, then tested it on device and it did not reproduce — XCUITest's own query is conservative about visibility, so the degenerate evaluation never gets the chance. It is retired because it was an undeclared, unmeasured bypass that made R37's singularExecution claim false: the same class of untruth as the sentinel retirement names fixed in the previous commit. Declaring querySelector as a real operation instead was rejected for a concrete reason: offscreen-target-probe.ts consumes queryDirectIosSelector with a plain session and cannot take a bound operation, so declaring it now would ship it twice until Wave 5 moves the probe — the deferred-duplication shape that got get's read deferral overruled. It returns as a declared, fact-admitted, section 9-measured operation in the unit that also moves the probe. Retired: dispatchDirectIosSelectorIs, its call site, buildDirectIosIsResult, and resolveDirectIosSelectorQuery — each had exactly one caller, all on this path — plus the ResolvedDirectIosSelectorQuery type they orphaned and two imports. queryDirectIosSelector itself stays: the offscreen probe still consumes it and it remains single-copy. Latency cost, stated plainly and not softened: a held predicate on a simple iOS selector goes from ~0.14s with no capture to ~0.25s with one, measured as the median of 9 warm runs on iPhone 17. There is no fallback and no fast path. R37's comment finally describes the code: "every predicate answers from the resolved tree" was written while the shortcut existed. Its scope is now stated too, so it is not read as absolute — the Android foreground-blocker diagnostic still reaches adb on the failure path, where it cannot produce or change a verdict; that edge is pre-existing, co-owned with wait, and recorded as Wave 6 denominator work with R22's appState as its declared replacement. Seven tests lost their subject. Those whose only content was the shortcut's own mechanics are deleted; the outcome-level ones are retargeted and keep asserting what survives. --------- Co-authored-by: agent <agent@local> * fix(contracts): a falsely advertised element read fails as a contract bug An owner whose facts advertised `readTextAtPoint` but whose interactor cannot perform it was reported as `{ status: 'unreadable', reason: 'surface-not-readable' }`. That put a contract violation inside the closed reason set that licenses falling back to the captured tree, so `get text` answered from potentially stale snapshot text precisely because the runtime lied about itself. ADR 0019 §2 requires the mismatch to fail as `runtime-contract-invalid`; it now throws. Removing the only producer of `surface-not-readable` made that reason dead: no path can reach it, since an interactor that HAS the read maps a blank or absent answer to `no-text-at-point` via `elementTextRead`. Dropped from the union, its consumer switch arm, and both test lists. `classifiedFallbackReason`'s `never` arm stays — it is what makes adding a reason a compile error rather than a silent untyped fallback. Deduplication found while auditing the change: - `invalidRuntimeContract` was module-private in `platform-runtime.ts`. It now owns its own module so both runtime modules share one construction. It is deliberately not exported through the platform facade: that facade must stay exhaustive over its sources, which would make this a public symbol with no external consumer. - The 8-field runner execution projection was written out three times (`snapshot-runtime-capture-input.ts`, `interaction-read.ts`, `screenshot-runtime.ts`). One `runtimeExecutionFromContext` now serves all three; `screenshotExecutionFromContext` keeps its name and delegates, since `ScreenshotRuntimeExecution` and `SnapshotRuntimeExecution` are the same type. Dropping a field here silently strips request id, log/trace paths, XCUITest overrides, or runner lease context — an operation that still answers but runs unconfigured, which is exactly the defect the wait unit hit as a P1. Red before green: with the old guard restored the new regression fails with "Missing expected rejection" — the call resolves instead of throwing, which is the silent degradation it exists to forbid. --------- Co-authored-by: agent <agent@local> |
||
|
|
d8e03aea9b |
refactor: migrate screenshot to request-bound runtime (#1878)
Retires the last dispatchCommand edges for screen capture: the generic-route command, the sparse-snapshot fallback, and the Android snapshot-timeout evidence capture all admit exact owner facts and bind once (ADR 0019, cutover rule R39). --overlay-refs becomes part of the declared use, so a target that can capture pixels but not a tree is refused before anything is written to disk. |
||
|
|
79dddaf781 | refactor: tighten viewport runtime facts (#1873) | ||
|
|
37b1bc8cbd |
refactor: migrate viewport to request runtime (#1864)
* refactor: migrate viewport to request runtime * fix: preserve viewport cutover evidence |
||
|
|
d76e0f94e9 |
refactor: migrate snapshot to device runtime (#1779)
* refactor: migrate snapshot to device runtime * refactor: complete snapshot runtime policy cutover * test: enforce snapshot owner-facts admission * refactor: consolidate desktop snapshot capture * fix: scroll to visible iOS smoke targets * fix: close snapshot cutover alias bypasses * fix: constrain snapshot admission identity flow * fix: enforce snapshot admission through owner facts * fix: adapt replay source tests to snapshot runtime |
||
|
|
d8a7d03faf |
refactor: route application lifecycle through runtime facts (#1759)
* refactor: route application lifecycle through runtime facts Moves the canonical `open`, `prepare`, `close` and internal `runtime` descriptors behind package-owned lifecycle bindings admitted from device runtime facts, while daemon request/session policy and public response construction stay put. Based on main, which already carries the boot unit, the parametrized cutover gate and the apps unit. Readiness is package-owned there, so the Apple and Android bindings call ensureAppleReady/ensureAndroidReady rather than a root readiness bag; ensureAppleReady gained an onColdBootStart hook so open keeps warming the runner cache in parallel with a cold boot, and a narrow markBooted port publishes readiness' fresh observation so a flow still makes one simctl listing. Cutover rows take R24-R27, clear of the accepted catalog and the sibling install stack, and cutoverTableDefects rejects a duplicate rule id. Two defects this unit introduced are fixed here rather than shipped: `open <app> <url>` dropped the URL on a first open, and test-IME activation was first fatal on an unobtainable helper and then over-caught. Helper unavailability is a typed non-activation outcome now; fence, lock and post-record failures propagate. The duplication the unit had accumulated is gone: one runtime-admission module instead of five per-command copies, one direct-lifecycle binding factory instead of six hand-rolled packages, one transport-hint predicate, one session finalization path, and no identity-wrapper module. * fix: allocate lifecycle cutover rows after deployment * chore: preserve lifecycle union reconstruction * fix: reconcile lifecycle runtime stack * refactor: tighten lifecycle runtime topology * refactor: remove superseded runtime adapters * fix: preserve stacked runtime cutovers * test: preserve migrated runtime ownership * test: move Android deployment retry ownership * test: extract runtime hint fixtures * fix: preserve lifecycle stack invariants * fix: complete lifecycle runtime cutover * fix: remove lifecycle cutover residue |
||
|
|
66cca1a5b8 |
refactor: route install commands through platform runtime (#1758)
* refactor: route install commands through platform runtime * fix: preserve stacked runtime facts * fix: align deployment facts with shutdown runtime * refactor: simplify capability facts projection * style: format capability facts projection * fix: preserve migrated capability ownership * fix: propagate deployment artifact cancellation * refactor: move Harmony deployment mechanics into package * refactor: move Apple deployment tools into package * refactor: move Android deployment tools into package * refactor: inject deployment temporary storage * refactor: remove superseded deployment helpers * fix: preserve provider deployment transport |
||
|
|
5855dfc2e0 |
refactor: route shutdown through device runtime (#1757)
* refactor: route shutdown through device runtime * fix: cover shutdown cutover review gaps * fix: propagate shutdown cancellation * fix: move shutdown mechanics to platform owners * fix: pass device to shutdown fact fixture * test: cover shutdown facts in session state fixtures * test: simplify Android shutdown assertions * fix: preserve Apple shutdown cancellation |
||
|
|
39cd4d346a |
refactor: route appstate through platform runtime (#1755)
* refactor: route appstate through platform runtime * test: keep appstate capability fixture below complexity limit * test: cover appstate required readiness fact * fix: align appstate facts with boot readiness * fix: keep appstate use declaration minimal * fix: close appstate parity and ownership gaps * docs: record final appstate size accounting * fix: merge neutral runtime imports * docs: align final appstate size totals * fix: remove stale runtime dependency edges * docs: correct appstate size accounting * refactor: keep runtime-use factory internal * docs: itemize runtime-use relocation * fix: move appstate queries into runtime packages * refactor: retire root foreground query paths * refactor: share Android foreground parser ownership * fix: preserve Android appstate parser precedence * docs: keep appstate evidence in review artifacts * fix: keep appstate runtime loading lazy * fix: fail closed for stale limrun appstate * fix: preserve limrun recovery and abort appstate * fix: narrow limrun exact-owner recovery * fix: allocate appstate cutover rule * fix: reconcile appstate with merged main * style: format harmony runtime test * fix: allocate appstate rule id * fix: allocate appstate layering rule * fix: remove stale app command admissions * fix: close appstate layering regressions * fix: align Harmony capability parity with runtime facts * test: cover limrun recovery-only readiness * fix: keep Limrun recovery binding app-log only * fix: parse Android app state in linear time |
||
|
|
eabc936a0f |
refactor: route apps through request runtime (#1756)
* refactor: route apps through request runtime * test: remove stale apps adapter mock * fix: clean apps runtime replay artifacts * fix: remove stale runtime test exports * refactor: simplify apps runtime admission * test: exercise runtime use through facade * fix: close apps runtime admission gaps * fix: disambiguate doctor app inventory callback * fix: keep capability fixture below complexity limit * fix: keep HarmonyOS app inventory fail-closed * test: type HarmonyOS app admission fixture * fix: restore HarmonyOS app inventory parity * test: align HarmonyOS readiness fixture * fix: preserve HarmonyOS doctor app parity * test: type HarmonyOS doctor fixture * fix: isolate HarmonyOS doctor policy * fix: align apps cutover with shared rule catalog |
||
|
|
b13c06338e |
refactor: route boot through readiness runtime (#1747)
* refactor: route boot through readiness runtime * fix: separate boot admission from readiness * fix: register boot cutover policy * refactor(runtime): move readiness into platform owners * fix(test): tolerate provider temp cleanup races |
||
|
|
b15c502318 |
refactor: extract platform network runtime (#1702)
* refactor: extract platform network runtime * fix: preserve platform network recovery routes * test: guard network parser placement |
||
|
|
b1ed5353d1 |
refactor: extract platform log runtime (#1701)
* refactor: extract platform log runtime * fix: clear terminal app log recovery markers * fix: preserve scoped app log tooling * fix: preserve app log cancellation * fix: handle large changed coverage diffs * fix: harden Limrun runtime identity * refactor: tighten platform log runtime * fix: close app log trust gaps * fix: accept canonical session path aliases * refactor: extract durable capture kit * fix: refresh retained log marker admission * fix: rotate app logs after process relaunch |
||
|
|
c06bed9f77 |
refactor: extract platform device inventory runtime (#1699)
* refactor: extract platform inventory runtime * fix: preserve scoped Apple inventory tooling * fix: preserve Apple tool cancellation * refactor: tighten platform inventory boundaries |