Repository navigation
Extract src/platforms into the platform packages (umbrella: substrate wave → per-family moves → seam retirement) #2082
Description
Goal
Finish the extraction that #1490 started: src/platforms (181 production files, ~28.4k lines) moves behind the six packages/platform-* exports maps, and the platforms src zone retires from the spine. After this, every platform implementation lives in a workspace package held by R11/R13 instead of the R3 zone seam.
Numbers below come from the repo's own gate model (scripts/layering + scripts/depgraph, extended with a workspace/exports-usage scan) at c794c11.
Why it is close
src/platforms already gets almost everything from packages — kernel (184 import sites), contracts (108), and it imports @agent-device/platform-apple/-android directly. The daemon no longer imports it at all (#2072). What still pins it to root src/ is small and concrete.
Blockers, measured
1. Shared substrate: 47 root-src files (~5.6k lines) that platforms imports at 136 sites. A package cannot import root src/ (R11, no edge kind tolerated), so these must sink below the boundary first. The set is transitively closed over root src — it depends only on itself plus existing packages — so it can move wholesale:
- 40 files in
src/utils— led byexec.ts(37 sites),diagnostics.ts(21),timeouts.ts(10),parsing.ts,retry.ts, the owned-process/archive families src/request/cancel.ts,src/request/progress.tssrc/snapshot-quality/verdict.ts,src/snapshot-quality/backend-capabilities.tssrc/snapshot/snapshot-occlusion.ts,mobile-snapshot-semantics.ts(snapshot-desktop-surface.tsturned out to be an upward edge itself — it dynamically imports platform implementations, so it belongs to W2, not the substrate)
Destinations follow the repo's own signals: host/process mechanics into capture-kit (R18's violation hint names it as the mechanics home), pure kernel-typed geometry into kernel, snapshot semantics/vocabulary into contracts.
2. Four upward edges. Left in place they drag the whole host layer (the naive closure balloons from 47 files to 286):
src/platforms/android/app-helpers.ts→ dynamic import ofsrc/platform-runtime.ts(composition back-reference; invert to injection)src/platforms/web/agent-browser-network.tsandsrc/platforms/web/provider.ts→ type-only imports ofsrc/backend.ts(types move to contracts; R11 grants no type-only exemption)src/snapshot/snapshot-desktop-surface.ts→ dynamic imports ofplatforms/linux/snapshot.tsandplatforms/apple/os/macos/helper.ts(desktop dispatch; invert or relocate with its family)
3. Shared cross-family files need an owner — and family dirs import them (20 import pairs), so this must land before the family moves. ~20 files at src/platforms/ root (install-source*, toolchain-probe, boot-diagnostics, perf-utils, appearance, command-attempts, setting-state, …) serve several families; a family package cannot import them while they stay in root src. They need a substrate home (capture-kit or a dedicated package) first.
4. Policy follows the files. R3 (platforms-seam) is keyed to the src zone, which disappears; the CLI cold-start guarantee must be re-expressed at package level (extend the R13/composition policy: platform packages statically importable only from the composition files and interactor seam, dynamic/type-only elsewhere). TARGET_DAG_RANK drops platforms; the UNRANKED_ZONES comment already documents this retirement pattern from the kernel/contracts extractions.
Waves (one PR each, deletion of the old location included)
- W1 substrate: move the platforms-blocking closure into capture-kit (38 utils mechanics modules + png-worker +
request-cancel/request-progress), kernel (rect-center,scroll-indicator), and contracts (snapshot-occlusion,mobile-snapshot-semantics,snapshot-quality-verdict,snapshot-quality-backend-capabilities); full consumer re-point, no shims; thekeyed-lockshim retires — branchrefactor/platform-substrate-wave - W2 upward edges: the composition inversion in
android/app-helpers.ts; web backend types → contracts; desktop-surface dispatch inversion - W3 shared platform files → their substrate home (prerequisite for every family move)
- W4 apple (largest: ~81 files incl.
core/) →packages/platform-apple - W5 android (~60 files) →
packages/platform-android - W6 harmonyos / linux / vega / web (small; parallelizable per family)
- W7 seam retirement: retire R3, extend the package-level seam policy, drop
platformsfrom the spine, update ADR/docs
After W1–W3, the family waves (W4–W6) are mutually independent — different source dirs, different target packages — and can run in parallel, with two serialization rules: a handful of shared platform-runtime-* host files get one-line specifier swaps from several family PRs (merge order is arbitrary, conflicts are trivial), and any wave touching the same package as the operation-catalog work (see coordination below) finishes before the other starts on that package.
Each family wave: files move behind the package's exports map (named-export façades per the R11 facade gate), colocated tests move along, and the ~110 external import sites (≈35 platform-runtime-* host files with dynamic imports, core/interactors/*, sdk/*) re-point to @agent-device/platform-* specifiers.
Coordination with the post-#1739 cleanup lane (#2081 and successors)
The two efforts are file-disjoint almost everywhere; the contract to keep it that way:
- Sequencing: the
platform-runtime-*host-surface deepening (item 6 of that plan) starts after W4–W6 land — the family moves shrink its inbound/local import counts and sink the root utilities it still leans on, so deepening gets easier, and running both concurrently on the same ~35 host files is the main conflict generator. - Per-package serialization: the operation-catalog work rewrites
packages/platform-*/src/runtime.tsand contracts' operations vocabulary; the waves here add mechanics files and exports entries to the same packages. Whoever starts on a given package finishes before the other touches it. - Shared-file watchlist (small, trivial conflicts, but worth knowing):
packages/contracts/package.jsonexports map,packages/platform-*/package.json,scripts/layering/check.tswiring + rule ids,src/platform-runtime.ts/platform-runtime/request-providers.ts.
Verification per wave
pnpm check:layering (R11 package boundaries, facade exports, R13), pnpm typecheck, pnpm lint, pnpm test:unit, pnpm build + scripts/check-package.ts (published-tarball soundness), cold-start budget (src/__tests__/eager-closure-budgets.ts) since the R3 seam exists to protect CLI startup, and the depgraph report to confirm the platforms zone shrinks to zero by W6.
Activity
thymikee commentedon Aug 27, 2026
Triage: keep this as the coordination umbrella, not a single ready-for-agent unit. The W1-W7 ordering and package-colocation goal are the right durable direction, including retiring substrate seams only after each platform family owns its runtime. Each wave should become a separately executable child issue once its destination package, dependency boundary, and planted-red enforcement are explicit; only those child units should receive ready-for-agent. Leaving the umbrella unlabeled avoids one worker spanning coupled package moves and ADR-0019 cleanup.
refactor(substrate): sink the platform-blocking utils/request/snapsho…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor: split generic host mechanics into @agent-device/host-kit (#…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…
refactor(substrate): split host mechanics into @agent-device/host-kit…
refactor(platforms): break the four upward edges out of src/platforms (…
refactor(platforms): sink the shared src/platforms root files into th…