R76 keyed its inventory on the target filename, so a daemon import of a root module that
imports the platform-runtime family itself was invisible: the daemon could gain or widen an
edge to a root hub without any gate noticing. Dynamic edges were invisible in the same way,
and the ranked spine (R4, R5, R6) cannot see a dynamic import's direction at all.
The target predicate is now computed from the tree: the platform-runtime family plus every
module outside the daemon zone that reaches it, over static and dynamic edges alike. That
made exactly three real edges visible, and all three are classified rather than allowlisted:
the two provider-runtime hubs the daemon runtime composes, and the dynamic interactor lookup
in the snapshot capture, which is a leak and now carries the rationale and the deepening
issue (#2555) that a filename pattern never would have asked for.
Part of #2542
* refactor(daemon): separate open-target policy from Android mechanics
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
* refactor: address adversarial review findings on open-target seam
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
* fix(platform-android): keep the mechanics facade lazy for the new open-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
* fix(android-tools): keep inferOpenedAppBundleId best-effort on a mechanics 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
* perf(android-tools): skip loading Android mechanics when app-bundle identity 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
---------
Co-authored-by: Claude <noreply@anthropic.com>
* refactor(daemon): typed lifecycle participation for platform resource owners
daemon-runtime.ts no longer imports the Apple runner owner, the Android
snapshot-helper/Web orphan cleanups, or the app-log legacy marker recovery
directly. Those are now behind PlatformOwnerLifecycle, a typed
startup/shutdown surface owned by the daemon; the root composition module
platform-runtime-daemon-lifecycle.ts is the sole place that wires the
concrete platform owners into it.
Reclassifies the R76 daemon-platform-runtime-inventory edges accordingly:
the leaked apple-runner-owner and operation-host edges are removed, and
resource-cleanup/daemon-lifecycle stay as composition-essential.
Closes#2333
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017oNQ8THHYFcK7NX1s78kW5
* style: apply oxfmt formatting to R76 inventory test fixtures
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017oNQ8THHYFcK7NX1s78kW5
* test(daemon): update source-ordering assertion for the renamed call site
daemon-runtime.ts now calls platformDaemonLifecycleOwners.recoverLegacyAppLogMarkers
instead of the old recoverLegacyAppLogMarkersAfterDaemonLock dynamic import; the
text-based ordering guard needs to look for the new call site.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017oNQ8THHYFcK7NX1s78kW5
* docs(adr): record #2333 as landed in ADR 0022
The registry (DAEMON_PLATFORM_RUNTIME_EDGES) already reflects the
retired apple-runner-owner/operation-host edges; update the ADR prose
to match instead of leaving #2333 listed as outstanding work.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017oNQ8THHYFcK7NX1s78kW5
* fix(daemon): configure the Apple runner owner only after the daemon lock is held
configureForDaemonLock ran before acquireDaemonLock, which meant a
process that lost the lock race briefly published a global runner-owner
state dir and claim-authority probe it didn't own. Move the call inside
the post-lock try block (verified nothing reads the runner-owner state
before request time — runner-host.ts only captures getter closures) and
drop the now-unreachable clear call on the lock-failure branch. Adds a
source-order regression test pinning the new sequence.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017oNQ8THHYFcK7NX1s78kW5
---------
Co-authored-by: Claude <noreply@anthropic.com>
* refactor(daemon): consume a semantic Apple session observation port
* chore(gates): retire direct daemon observation imports
---------
Co-authored-by: PLASMA-FR <173463847+PLASMA-FR@users.noreply.github.com>