refactor: PlatformPlugin registry foundation (step a) — Phase 3#956
Conversation
Size Report
Startup median (7 runs, lower is better):
Top changed chunks:
|
|
Careful draft review against |
Remove the speculative daemon-owned facets (providers/recording/appLog/perf) from the PlatformPlugin type. The earlier 'recording' facet baked the iOS-simulator provider seam (IosSimulatorRecordingRequest) into the contract and could not represent the Android/web/macOS-runner/iOS-device-runner/stop-path recording contracts, which need the daemon recording context. The step-a contract now carries only what this slice implements and parity-tests: id, platforms, familySelector?, createInteractor, discoverDevices, capability. The facets are introduced in step (b) as platform-neutral, daemon-owned wrappers, pinned by table-equivalence parity tests (plan updated).
|
Addressed the foundation-shape blocker (commit fce3c12) — applied option A: trimmed the step-a contract to only what this slice genuinely implements and parity-tests. Removed the iOS-shaped Audited the other speculative facets ( Verified the deletion was clean: Plan updated ( All gates green after the change: |
|
Re-reviewed fce3c12 after the contract-scope fix and CI completion. The previous blocker is addressed: PlatformPlugin no longer declares the speculative daemon facets or imports daemon-owned recording/provider/log/perf types, and the follow-up plan now introduces those later as platform-neutral daemon-owned wrappers with parity gates. The live getInteractor route remains behavior-preserving, checks are green, and the PR is no longer draft. No remaining blockers; marking ready-for-human. |
|
Phase 3 — PlatformPlugin: the behaviorless foundation (step a only)
This is the safe, behaviorless scaffold for the platform-plugin axis of
plans/perfect-shape.md§5.1/§6 and ADR-0009. It adds aPlatformPluginregistry that WRAPS today's existing interactor factories and device-discovery branches —no leaf code is rewritten, default behavior is byte-identical. The risky remainder (steps b/c) is a
plan only below.
What this PR adds (scaffolding)
src/core/platform-plugin/plugin.ts— thePlatformPlugintype (type-only imports; lazycreateInteractor/discoverDevices;capability.bucket). Per review, the contract is trimmed to only thefacets this slice actually implements and parity-tests — the speculative
providers/recording/appLog/perfdaemon facets are NOT declared here (they are introduced in step b with platform-neutral,daemon-owned types, so the foundation never bakes in the old iOS-simulator recording shape). Plus the
registry:
registerPlatformPlugin,getPlugin(throws the sameUNSUPPORTED_PLATFORMAppError as theold switch default),
tryGetPlugin,registeredPlatforms.src/core/platform-plugin/register-builtins.ts—apple(ownsios+macos),android,linux,webplugins wrapping the existingcore/interactors/*factories andplatform-inventory.tsbranches viathe same lazy dynamic
import()s. Includes the compile-time exhaustiveness assertion(
BuiltinPluginsCoverAllPlatforms): a newPlatformliteral without a plugin fails the build.src/core/interactors.ts—getInteractornowreturn getPlugin(device.platform).createInteractor(...)after the unchanged provider-device check. Verified byte-identical: same lazy imports, same factory calls,
same throw code+message. This makes the registry production-live (not dead scaffold).
src/core/platform-inventory.ts— exportsWEB_DESKTOP_DEVICE+shouldUseHostMacFastPathso theweb/apple plugins reuse the same instance/predicate (no divergent copy).
src/core/platform-plugin/__tests__/parity.test.ts— the parity suite.Placement note: the registry lives in
src/core/platform-plugin/(mirroring the existingcore/platform-descriptor/andcore/command-descriptor/foundations), not §5.1'ssrc/platforms/,because everything it wraps today lives in
core/and that keeps every import in the allowedcore→core/core→platformsdirection. Relocating it tosrc/platforms/apple/is part of step (c).Allow-lists: derived vs. left hand-authored
PLATFORMS(kernel/device.ts) andparsePlatform(
utils/parsing.ts) stay the source of truth — per the roadmap's "err toward leaving hand lists." Nothing isderived FROM the registry yet; the parity test only PROVES equivalence.
--platformenum readsPLATFORM_SELECTORS(cli-flags.ts).Parity tests
registeredPlatforms()is byte-for-byte equal to the canonicalPLATFORMStuple, in order.parsePlatformaccept-set (verbatimreference copy in-test, incl. the
appleselector correctly excluded as a non-leaf).capability.bucketmatches the existingplatformDescriptorsregistry (no drift between thetwo foundations).
ios/macos→ one Apple plugin).getPluginthrowsUNSUPPORTED_PLATFORM(verbatim code+message) for an unregistered platform; duplicateregistration is a hard error.
Local verification (all green)
tsc -p tsconfig.json✅ ·oxlint . --deny-warnings✅ ·oxfmt --check✅ ·rslib build✅fallow audit --base origin/main→ No issues ✅vitest run --project unitover the new tests +core/+platforms/__tests__/→ 183 passed (incl. theexisting
getInteractorrouting tests, unchanged through the registry).Plan for the risky remainder — review the plan before starting steps b/c (do not auto-merge those)
Full file:line-grounded plan in
plans/phase3-platform-plugin-progress.md.Step (b) — capability + daemon columns onto plugin grants: route
isCommandSupportedOnDevicethroughgetPlugin(...).capability.bucket(pure swap); port everysupports()/unsupportedHint()device closureverbatim (
command-descriptor/registry.ts:41-54— these encode macOS-coordinate-pinch, tvOS-no-touch,two-finger synthesis nuance — never flatten to data); introduce the
providers/recording/appLog/perffacets typed against platform-neutral, daemon-owned wrappers of the existing start+stop contexts (de-iOS-
naming
startIosSimulatorRecording) by wrapping the daemon branches (request-platform-providers.ts:117-233,record-trace-recording-backends.ts:73-101,app-log.ts:179-185/344-375,session-perf.ts:109-131). Eachtable pinned by a table-equivalence parity test BEFORE any hand table is deleted.
Step (c) — unwind macOS out of
platforms/ios: relocate the ~797 LOC macOS leaf + the OS-agnostic engine(6,136-LOC runner stack) into
src/platforms/apple/{os/macos, core}, byte-identical, gated behind thesim-validation request-counting harness (runner request count unchanged before/after each commit), per
apple-platform-consolidation.md. The XCTest two-finger synthesis and adb/idb leaves stay untouched. Theios+macos→applePlatformcollapse is the last, highest-diff step.