You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 by exec.ts (37 sites), diagnostics.ts (21), timeouts.ts (10), parsing.ts, retry.ts, the owned-process/archive families
src/snapshot/snapshot-occlusion.ts, mobile-snapshot-semantics.ts (snapshot-desktop-surface.ts turned 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 of src/platform-runtime.ts (composition back-reference; invert to injection)
src/platforms/web/agent-browser-network.ts and src/platforms/web/provider.ts → type-only imports of src/backend.ts (types move to contracts; R11 grants no type-only exemption)
src/snapshot/snapshot-desktop-surface.ts → dynamic imports of platforms/linux/snapshot.ts and platforms/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; the keyed-lock shim retires — branch refactor/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
W6 harmonyos / linux / vega / web (small; parallelizable per family)
W7 seam retirement: retire R3, extend the package-level seam policy, drop platforms from 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.ts and 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.
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.
Goal
Finish the extraction that #1490 started:
src/platforms(181 production files, ~28.4k lines) moves behind the sixpackages/platform-*exports maps, and theplatformssrc 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) atc794c11.Why it is close
src/platformsalready gets almost everything from packages — kernel (184 import sites), contracts (108), and it imports@agent-device/platform-apple/-androiddirectly. The daemon no longer imports it at all (#2072). What still pins it to rootsrc/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:src/utils— led byexec.ts(37 sites),diagnostics.ts(21),timeouts.ts(10),parsing.ts,retry.ts, the owned-process/archive familiessrc/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_RANKdropsplatforms; theUNRANKED_ZONEScomment already documents this retirement pattern from the kernel/contracts extractions.Waves (one PR each, deletion of the old location included)
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-waveandroid/app-helpers.ts; web backend types → contracts; desktop-surface dispatch inversioncore/) →packages/platform-applepackages/platform-androidplatformsfrom the spine, update ADR/docsAfter 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:
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.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.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 theplatformszone shrinks to zero by W6.