refactor(daemon): separate open-target policy from platform mechanics - #2416
Conversation
Size Report
Startup median (7 runs, lower is better):
|
|
Please preserve the no-target fast return in inferOpenedAppBundleId. It now loads Android mechanics before the helper can return for an absent target, so a loader failure can turn a fresh targetless Android open into an error instead of leaving the optional package identity unset. Keep loading inside the best-effort operation and add a targetless regression with the loader rejecting. This also overlaps #2408 on #2334; these are alternative implementations, not two changes to merge. Checks are green on a0ad24c. |
|
Good catch, fixed in 8cd9a0f. The move from Noted on the #2408 overlap — that's a separate implementation of the same issue, not something to merge alongside this one. Generated by Claude Code |
|
The "Smoke Tests" (iOS) check failed on 8cd9a0f: Generated by Claude Code |
|
Re-run confirms it was a flake — Smoke Tests passed on the second attempt. All checks are green and the PR is mergeable. Generated by Claude Code |
|
The loader failure is handled correctly at 8cd9a0f, and CI is green. I found no remaining correctness blocker; skipping the unnecessary import when identity is already known would be a small optimization, not a required fix. This and #2408 are alternatives for #2334, so choose one before marking it ready to merge. |
Move resolveAndroidPackageForOpen/inferAndroidPackageAfterOpen behind the Android owning seam in packages/platform-android. resolveSessionAppBundleIdForTarget now lazily reaches Android mechanics itself instead of taking an injected resolver function, so open-prepare and selector-dispatch import only the neutral open plan/result surface from platform-runtime-open-target.ts. Reclassifies the two R74 inventory edges to daemon-policy-essential and updates ADR 0022. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0167UVzrdzVMCZqXgxtzWoTD
Restore try/catch around the Android-mechanics lazy load so a module load failure still resolves to undefined instead of throwing. Rename the unrelated private resolveAndroidPackageForOpen in app-lifecycle.ts to requireAndroidPackageForOpen to remove the naming collision with the new exported function. Add a planted-violation regression test for reintroducing Android mechanics on the selector-dispatch edge. Tighten ADR/inventory wording that overstated which files consume the neutral resolver. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0167UVzrdzVMCZqXgxtzWoTD
…n-target exports resolveAndroidPackageForOpen/inferAndroidPackageAfterOpen were re-exported statically from mechanics.ts, which eagerly evaluates open-target-resolution.ts on import and tripped the eager-closure-budgets gate (177 -> 178 modules). Wrap them as lazy async functions, matching the existing pattern used for listAndroidAppsWithAdb/captureAndroidLogcatWithAdb in the same file. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0167UVzrdzVMCZqXgxtzWoTD
…anics load failure Loading Android mechanics moved from the near-infallible root platform-runtime-open-target.ts to the real adb-backed mechanics module, but the wrapper call stayed unguarded. A loader failure now throws instead of leaving the app-bundle identity unset, even for a targetless open that never needed the loaded module. Wrap the load and delegate in try/catch so it degrades to the current bundle id, matching the pre-refactor behavior, and add a regression test with the loader rejecting on a targetless open. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0167UVzrdzVMCZqXgxtzWoTD
…dentity is known inferOpenedAppBundleId always loaded Android mechanics before delegating, even when currentAppBundleId already made the delegate's own fast-return a no-op. Check it first so the load is skipped entirely once the identity is already known, and add a regression test asserting the loader is never called in that case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0167UVzrdzVMCZqXgxtzWoTD
8cd9a0f to
696df77
Compare
|
Rebased onto main at 9d7d60c (696df77). The ADR conflict was in §2.2/§4: merged #2333's "done" writeup (from the landed lifecycle-participation change) with this PR's open-target-planning writeup rather than picking one side. No code conflicts. Also applied the optional optimization you mentioned: CI is re-running on 696df77. Generated by Claude Code |
|
"Smoke Tests" (Linux) failed on 696df77: the "Install Linux desktop dependencies" step ( Generated by Claude Code |
|
Re-run confirms it was infra flake — all checks green on 696df77, rebased onto latest main, mergeable. Generated by Claude Code |
|
The conflict resolution at 696df77 preserves the lazy Android boundary and the targetless/current-identity behavior. The regressions exercise those paths and all checks are green. This is the version I would choose for #2334; it overlaps with #2408, so choose this one and supersede the other before merging both accidentally. |
|
Closed #2408 as superseded by this PR. This one is ready to merge — head 696df77, all checks green, mergeable, rebased onto latest main. Generated by Claude Code |
|
Summary
Closes #2334.
src/platform-runtime-open-target.tsmixed neutral open-plan policy with Androidplatform mechanics (real adb-backed package resolution). This moves
resolveAndroidPackageForOpen/inferAndroidPackageAfterOpenbehind the Androidowning seam in
packages/platform-android, and simplifiesresolveSessionAppBundleIdForTargetto lazily reach Android mechanics itselfinstead of taking an injected resolver callback — removing a dead-code stub
(
async () => undefined) at the Apple/macOS call site and keeping exactly oneconstruction path for the open plan.
session-open-prepare.tsandsession-selector-dispatch.tsnow import only theneutral plan/policy surface from
platform-runtime-open-target.ts. The two R76inventory edges are reclassified from
leaked-platform-mechanicstodaemon-policy-essential, dropping the daemon-to-root platform-runtime edge countfrom 14 to 13. ADR 0022 is updated to record the outcome.
Changes
packages/platform-android/src/open-target-resolution.ts(+ colocated test)owns
resolveAndroidPackageForOpen/inferAndroidPackageAfterOpen, exported viamechanics.ts.platform-runtime-open-target.ts: Android mechanics removed;resolveSessionAppBundleIdForTargetdrops its injected-callback parameter andlazily loads Android mechanics itself (still swallows a load/resolution failure,
matching prior behavior).
platform-runtime-android-application-tools.ts/platform-runtime-apple-application-tools.ts/
session-selector-dispatch.tsupdated to the simplified call signature.scripts/layering/daemon-platform-runtime-inventory.ts(+ test): reclassifiedboth edges, added a planted-violation regression test proving a reintroduced
Android-mechanics import on the selector-dispatch edge stays red.
resolveAndroidPackageForOpenmock fromplatform-runtime-open-target.tsto@agent-device/platform-android/mechanics.packages/platform-android/src/app-lifecycle.ts(
resolveAndroidPackageForOpen→requireAndroidPackageForOpen) to remove asame-name/different-contract collision with the newly exported function.
Validation
pnpm check:layering— green (13 daemon-to-root edges, R76 holds; new plantedAndroid-mechanics-reintroduction test passes).
pnpm check:di-seams— green.pnpm lint,pnpm typecheck,pnpm format:check— green.pnpm check:affected --run— unit project: 2118/2118 tests pass;replay-compatfails only because this sandbox is a shallow clone with no tags (pre-existing
environment limitation, unrelated to this change).
unit-coresweep ofsrc/daemon/**+packages/platform-android/**:3298/3300 pass; the 2 failures (
app-log-session-resource.test.ts,durable-capture-resource.test.ts) reproduce identically on unmodifiedmain.low-severity findings (exception-swallowing parity, the naming collision above,
and the planted-violation test).
🤖 Generated with Claude Code
https://claude.ai/code/session_0167UVzrdzVMCZqXgxtzWoTD
Generated by Claude Code