Skip to content

refactor(platforms): break the four upward edges out of src/platforms - #2090

Merged
thymikee merged 5 commits into
refactor/platform-substrate-wavefrom
refactor/platform-upward-edges
Aug 28, 2026
Merged

refactor(platforms): break the four upward edges out of src/platforms#2090
thymikee merged 5 commits into
refactor/platform-substrate-wavefrom
refactor/platform-upward-edges

Conversation

@thymikee

@thymikee thymikee commented Aug 27, 2026

Copy link
Copy Markdown
Member

Summary

No behavior changes for operators or clients; getAndroidAppStateWithAdb(adb) keeps a byte-identical signature. This is #2082 W2: the four upward edges out of src/platforms are removed by giving each piece of behavior its real owner, so the family trees can move later.

  • The Android foreground read stays with its family. packages/platform-android owns the complete adb read/parse loop — readAndroidAppStateWithExecutor beside its host-based twin, sharing the same command tables and parser. The façade exposes it lazily, the composition root wraps it, and src/sdk/android-adb.ts reaches it through that root in one dynamic hop. No injected parser, and no root → SDK → platform → legacy round trip.
  • Desktop snapshot projection goes to its capture owner. shapeDesktopSurfaceSnapshot and scopeSnapshotNodes live in @agent-device/capture-kit/snapshot-desktop-projection, beside the occlusion and quality behavior. Contracts exports only the snapshot-scope vocabulary they consume.
  • Contracts additions in this PR are vocabulary and plan models only; no parser or runtime mechanic sinks into contracts.

The platforms → root edge count is zero: the dynamic import sits on the SDK side of the seam, not inside the family tree.

Scope: 25 files, one command family (Android app state) plus the desktop snapshot path.

Validation

Exact head 55d3cfe has 17 substantive SUCCESS checks plus one expected build-cache matrix SKIP: Coverage, Repo Guards, Integration Tests, Typecheck & Package, Lint & Format, Compatibility & Provenance, Bundle Size, Resolve native fingerprint, all four native Smoke Tests jobs, and every CodeQL analysis. The skip is matrix.name, which drops out when the native fingerprint is unchanged.

The previous head 50b9ac6 had the same 17 SUCCESS plus one SKIP; the delta between them is 11 files / 26 lines of comment-only citation repair carried up from #2088, where the W1 move had orphaned references to the src/utils/*.ts paths it deleted. Conflict-free rebase, no production behavior, closure, or budget change.

The SDK route is proven where it ships: src/sdk/android-adb.test.ts drives the public getAndroidAppStateWithAdb through the full fallback ladder and its failure-stdout path, so a broken composition seam fails rather than being mocked away. The family test keeps the list coverage, and the moved projection keeps its golden fixture.

An earlier head hit the smoke:automation-system native-alert step on the Android lane. It has since passed here on two consecutive heads with no change to the alert path — that step also failed byte-identically on unrelated PRs while main was green, and the full account is on #2088.

Stacked on #2088 at f87c0fe, which has 32 substantive SUCCESS checks plus the same one expected build-cache matrix SKIP, the full mutation lane included (ten shards plus aggregate).

🤖 Generated with Claude Code

https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 2.48 MB 2.48 MB +213 B
JS gzip 834.0 kB 834.2 kB +251 B
npm tarball 957.3 kB 957.4 kB +129 B
npm unpacked 3.32 MB 3.32 MB +261 B

npm unpacked components

Component Base Current Diff
JS / dist source 2.64 MB 2.64 MB +261 B
Apple runner source/project 581.1 kB 581.1 kB 0 B
macOS helper source 54.8 kB 54.8 kB 0 B
Android helper artifacts 0 B 0 B 0 B
Other package files 45.3 kB 45.3 kB 0 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 31.8 ms 32.1 ms +0.3 ms
CLI --help 88.4 ms 88.6 ms +0.3 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/platform-runtime-operation-host.js +386 B +115 B

Top changed packed files

Packed file Base Current Diff
dist/src/snapshot-desktop-surface.js 1.8 kB 0 B -1.8 kB
dist/src/snapshot-desktop-projection.js 0 B 1.0 kB +1.0 kB
dist/src/app-helpers.js 1.7 kB 1.2 kB -445 B
dist/src/surface-snapshot2.js 0 B 405 B +405 B
dist/src/platform-runtime-operation-host.js 27.7 kB 28.1 kB +386 B
dist/src/surface-snapshot.js 0 B 291 B +291 B
dist/src/app-state.js 867 B 1.1 kB +184 B
dist/src/android-adb.js 1.7 kB 1.8 kB +120 B
dist/src/android-adb.d.ts 2.6 kB 2.6 kB +48 B
dist/src/interactor.js 13.3 kB 13.3 kB +19 B

@thymikee

thymikee commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

Code review is clean at 5e3e3459, but this is not ready yet. It is stacked exactly on open #2088 (39af1410), which currently has blocking mutation failures, so #2090 must wait for that base to merge/rebase. Its exact-head iOS smoke also failed: gesture-pan-duration.ad timed out after 60s. The changed seams do not obviously own that path, so this is not a code finding yet, but it needs a successful rerun or a same-load base comparison before readiness. All other substantive checks are green; no separate device-evidence debt found for the behavior-preserving moves.

@thymikee
thymikee force-pushed the refactor/platform-upward-edges branch from 8d7cf6f to 1ce404e Compare August 27, 2026 14:30

Copy link
Copy Markdown
Member Author

The stack is rebased onto main (now including #2089's capability-matrix retirement): #2088 sits directly on ea1d6b8 and this branch is one commit on top of it (1ce404e), so the exact-head iOS smoke — including gesture-pan-duration.ad — reruns fresh on the new head. Nothing in this diff touches the pan/gesture path (the desktop-surface split is macOS/Linux snapshot capture; the parser and type moves are Android/web), so if the timeout reproduces on this head it warrants the same-load base comparison you suggested rather than a code change here. I'm watching both PRs and will act on the results.


Generated by Claude Code

Copy link
Copy Markdown
Member Author

Coverage on 841caa1 failed on one test of 8,800: provider-scenarios/android-lifecycle.test.ts ("Android Settings flow uses scripted ADB provider") with Android test IME recovery records could not be persisted for Pixel 8 — the activate-path fail-closed fence in platform-runtime-android-application-tools.ts, meaning a recovery-record write failed inside the scenario harness. Evidence this is load-borne, not this PR's: this diff only relocates the foreground parser and backend types (the IME lifecycle path is untouched beyond W1's import swaps), the same test passes 12/12 locally on this exact head, and the same Coverage job passed on #2100's head (5d30acb), which contains this PR's content as a strict subset and ran minutes apart alongside two sibling coverage runs. I don't have permission to re-run the job from this session; the next push or a maintainer re-run should clear it, and I'm keeping the PR watched until it's green.


Generated by Claude Code

@thymikee

Copy link
Copy Markdown
Member Author

[P1] Don’t satisfy R13 by moving implementation into contracts. ADR-0019 keeps contracts vocabulary/plan-model thin and explicitly excludes capture parsers/runtime mechanics, but this head puts the Android dumpsys foreground parser and the desktop snapshot projection algorithm there. Issue #2082 called for composition inversion: keep platform parsing with the Android owner and expose the narrow behavior to the legacy caller through composition; put genuinely cross-family snapshot shaping behind an honest owning domain seam. Otherwise W2 removes upward edges by creating the wrong downward ownership before the family moves.

[P2] Remove the four-line #1832/history narrative moved into snapshot-desktop-projection.test.ts; the test name, fixture, and assertions already encode the invariant under current main’s comment rule.

Exact-head Coverage is also red on the unrelated IME recovery persistence scenario, iOS is pending, and stacked base #2088 is not ready.

@thymikee
thymikee force-pushed the refactor/platform-upward-edges branch from 841caa1 to a15d335 Compare August 27, 2026 15:41

Copy link
Copy Markdown
Member Author

Addressed on a15d335 (rebased on #2088's d6442d7, which carries the ADR-0019 substrate amendment):

P1 — both relocations invert instead of sinking into contracts:

  • The Android dumpsys foreground parser is back in @agent-device/platform-android with its owning test, and contracts/android-observation returns to observation vocabulary only. The legacy caller now composes: app-helpers exposes createAndroidAppStateReader(parseForegroundApp) and imports nothing upward; the composition seam in src/sdk/android-adb.ts injects the root-composed parser (the R13-privileged wrapper platform-runtime.ts already had), and the published getAndroidAppStateWithAdb(adb) signature is byte-identical. The platforms → root edge count stays zero — the dyn-import now lives on the SDK side of the seam, not inside the family tree.
  • The desktop snapshot projection moves to @agent-device/capture-kit/snapshot-desktop-projection, beside the occlusion/semantics/quality behavior W1 now sends there — capture-kit is the owning domain for cross-family snapshot shaping under the amendment. Contracts exports the snapshot-scope vocabulary it consumes (pinned, budgeted).

P2 — the #1832 narration in the projection test is gone; the test name and the golden fixture carry the invariant.

On the exact-head failures: Coverage's IME-persistence scenario has the standing-down comment above (single flake, passes locally on the head, passed in the superset run); the failed iOS settings smoke was a daemon-metadata startup failure on the macOS runner after 76/76 XCUITests and a successful runner prepare — daemon startup isn't in this diff and the same lane was green on #2088's head minutes earlier. Both rerun on this push.


Generated by Claude Code

@thymikee

Copy link
Copy Markdown
Member Author

Not ready. The parser now lives in the platform package, but the new composition is still an R13 workaround: root app-helpers accepts an injected parser, the SDK dynamically imports root platform-runtime to retrieve the platform-android parser, then feeds it back into the legacy reader. The paragraph-long comment exists to justify that indirection. Move the complete read/parse behavior behind platform-android's existing host seam (or narrowly amend R13 for an honest SDK-facade import) instead of preserving this root -> SDK -> platform -> legacy loop. Also move the SDK route test into SDK topology and remove implementation-history narration. Android and iOS smoke are red on this exact head and need a rerun or same-load base comparison; base PR #2088 is still open.

Copy link
Copy Markdown
Member Author

Fixed on e61846a — the loop is gone, not justified: packages/platform-android/src/app-state.ts owns the complete adb-executor read/parse (readAndroidAppStateWithExecutor, beside its host-based twin, sharing the same command tables and parser), the façade exposes it lazily, the composition root wraps it, and src/sdk/android-adb.ts reaches it through that root in one dynamic hop — no injected parser, no root→SDK→platform→legacy round trip, and the paragraph comment is reduced to a single R13 directive. app-helpers keeps only the app-list helpers. The SDK-route tests now live in SDK topology (src/sdk/android-adb.test.ts, exercising the full fallback ladder through the public function); the family test keeps only the list coverage.

On the exact-head smokes, the same-load base comparison you asked for now exists: #2088's head d6442d7 — which carries every shared snapshot/utility move under this PR — ran the identical iOS lane green end-to-end (Settings replay and the gesture-pan-duration replay included) at 15:58, minutes after this PR's heads failed those lanes under a triple-stack CI load. The Android alert-accept timeout's only W2-side delta was the parser plumbing this push has now replaced wholesale. Both lanes rerun on e61846a.


Generated by Claude Code

@thymikee

thymikee commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

The prior ownership blocker is resolved: platform-android now owns the complete ADB read/parse behavior, SDK reaches the composition root once, and the moved SDK test proves the public failure-stdout and fallback route. Remove the new explanatory comment at packages/platform-android/src/app-state.ts:36. Exact-head CI is green, but this stack remains blocked on open/red base #2088; rebase and re-establish evidence after that base is resolved. Not ready yet.

@thymikee
thymikee force-pushed the refactor/platform-upward-edges branch from e61846a to c350a07 Compare August 27, 2026 18:03
@thymikee

Copy link
Copy Markdown
Member Author

Code review is clean at c350a07e: platform-android owns the complete read/parse behavior, SDK crosses the composition seam once, the public-route regression is valid, and the prior narration is removed. Not merge-ready: base #2088 remains open/conflicting with checks running, so rebase/revalidate after it resolves. Exact-head Android E2E is red on the native-alert scenario and iOS/Coverage/Repo Guards were still in progress; require green rerun or same-load base evidence.

Copy link
Copy Markdown
Member Author

Done on c350a07: the explanatory comment at packages/platform-android/src/app-state.ts:36 is deleted, along with the matching one-liner in src/sdk/android-adb.ts — the ownership is visible in the module layout, so neither line was carrying anything.

The branch is rebased onto #2088's new head fccf8c1, which replaces the capture-kit host-mechanics ownership with the @agent-device/host-kit package you asked for; one import in agent-browser-network.ts resolved to the host-kit values seam, and capture-kit's manifest keeps snapshot-desktop-projection while shell-quote is now a host-kit seam export rather than a capture-kit subpath.

Green on this head: typecheck, lint, check:layering, fallow, and the boundary/policy/budget gates plus both android app-state suites.


Generated by Claude Code

@thymikee

Copy link
Copy Markdown
Member Author

Code review is clean on the ownership/routing change: Android keeps the full state read/parse loop, contracts additions are vocabulary only, and desktop capture/projection sits with capture-kit and platform-family owners with structural/runtime proof. Not ready yet: remove the two new history/implementation docblocks in packages/capture-kit/src/snapshot-desktop-projection.ts ('legacy desktop-surface...' and 'shared scope specification...'); names and the golden test already carry the invariant. This exact head is stacked on blocked #2088, and coverage/package/integration/native-smoke evidence is still incomplete. Once the base is corrected, comments removed, and exact-head checks finish green, I see no remaining #2090 code blocker.

Copy link
Copy Markdown
Member Author

Rebased onto #2088's restructured head; this branch is now 37f146f and the merge conflict is gone.

#2088 replaced host-kit's four category barrels with eight narrow capability ports (command, process, diagnostics, retry, archive, file, request, version) and moved the pure helpers into kernel, so this PR's one conflict — stripUndefined in agent-browser-network.ts — now resolves to @agent-device/kernel/record. Nothing else in the W2 diff moved.

Green on this head: typecheck, lint, check:layering (1505 files), fallow, and the boundary/policy/budget/ratchet gates.

The Android Smoke lane is red here for the same reason as on the base — the smoke:automation-system native-alert step, which reproduces identically on unrelated PRs while main is green. The evidence is written up on #2088; it is not this diff's and there is no fix to port yet.


Generated by Claude Code

@thymikee
thymikee force-pushed the refactor/platform-upward-edges branch from 37f146f to dbbe26b Compare August 27, 2026 19:18
@thymikee

Copy link
Copy Markdown
Member Author

Re-reviewed dbbe26baeb: the two projection docblocks are removed and the branch-owned ownership/routing code remains clean. No new semantic #2090 code blocker.

Not ready yet. The PR body is materially stale: it still says the Android foreground parser and desktop projection live in contracts, while the reviewed implementation keeps the complete read/parse operation in platform-android and projection in capture-kit. Rewrite Summary/Validation to describe the final ownership and current evidence. Base #2088 remains open with substantive checks pending, and #2090 Coverage, Repo Guards, integration, native smokes, and JS CodeQL are still incomplete. Re-establish exact-head readiness after the base resolves and CI completes.

Copy link
Copy Markdown
Member Author

Both docblocks removed on dbbe26b, and the branch is rebased onto #2088's current head (bc8ae93) so the compare validates the narrow host-kit stack rather than the superseded chain.

shapeDesktopSurfaceSnapshot and scopeSnapshotNodes now carry no prose; the function names, the golden fixture, and the assertions state the invariant.

Green on this head: typecheck, lint, check:layering (1505 files), and the capture-kit suite.


Generated by Claude Code

@thymikee
thymikee force-pushed the refactor/platform-upward-edges branch from dbbe26b to dc23f7d Compare August 27, 2026 19:39

Copy link
Copy Markdown
Member Author

PR body rewritten on dc23f7d (rebased onto #2088's c8b6eb1).

You were right that it was materially stale — it described the superseded shape where the foreground parser and the projection sank into contracts. It now states the shipped ownership: platform-android owns the complete adb read/parse loop behind its façade, capture-kit owns the desktop projection, and contracts carries the snapshot-scope vocabulary only. ## Summary / ## Validation per docs/agents/pull-requests.md, with the SDK-route regression named as the evidence that the composition seam is proven where it ships rather than mocked away.


Generated by Claude Code

@thymikee

Copy link
Copy Markdown
Member Author

Re-reviewed dc23f7d292: branch-owned code is clean. The Summary now truthfully describes platform-android owning the complete read/parse operation, capture-kit owning desktop projection, and contracts remaining vocabulary-only; prior narration is removed. All substantive exact-head checks are green, including Coverage, Repo Guards, integration and every native smoke.

Not independently merge-ready only because base #2088 remains open and the Validation section still says Android smoke is red even though current #2088 and #2090 Android lanes are green. Correct that stale evidence paragraph, land/rebase the base, and re-establish exact-head stack evidence. No remaining code blocker.

Copy link
Copy Markdown
Member Author

Stale evidence paragraph corrected. The Validation section now states what is true on dc23f7d — typecheck, lint, layering, fallow, the boundary/policy/budget/ratchet gates, Coverage, Repo Guards, Integration and every native smoke lane green — and the Android native-alert step is described as an earlier head's failure that cleared with no change to the alert path, rather than as a current red.

No code change, so the head is unmoved at dc23f7d.

On the base: #2088 is now green on c8b6eb1, mutation lane included — all ten shards completed and the aggregate passed. It is open pending your review rather than pending CI.


Generated by Claude Code

@thymikee
thymikee force-pushed the refactor/platform-upward-edges branch from dc23f7d to 0fb6b4b Compare August 27, 2026 20:17
claude added 5 commits August 27, 2026 20:52
…#2082 W2)

src/platforms carried four imports that point up into root src, each of
which would become an R11 violation the moment its family moves into a
platform package:

- android/app-helpers.ts reached the composition root for the foreground
  parser. The parser is pure dumpsys vocabulary, so it moves to
  @agent-device/contracts/android-observation; the platform-android
  app-state module and app-helpers both consume it from there, and the
  composition wrapper plus the package facade's lazy re-export retire
  (R13 allows only the composition root to import platform packages, so
  vocabulary relocation is the inversion that stays legal).
- web/provider.ts and web/agent-browser-network.ts type-imported the
  backend diagnostics/network-dump vocabulary from src/backend.ts. Those
  six types move to @agent-device/contracts/backend-diagnostics;
  backend.ts re-exports them for its SDK consumers.
- snapshot/snapshot-desktop-surface.ts split three ways: the pure
  projection (scope/interactive/depth) moves to
  @agent-device/contracts/snapshot-desktop-projection, the per-family
  captures move to platforms/linux/surface-snapshot.ts and
  platforms/apple/os/macos/surface-snapshot.ts beside the code they
  dispatch to, and the root file keeps only the device-dispatching
  runtime host behind R3-tolerated dynamic imports. apple/interactor
  now reaches macOS surface capture family-internally instead of
  through root.

src/platforms -> root src is now zero edges. Contracts grows two entries
(pinned, budgeted); the android foreground-parser tests move beside the
parser. Left for a later pass: app-parsers.ts shares the marker-walk loop
shape with the contracts parser but parameterizes it for blocking-dialog
parsing - generalizing that is a design change, not a move.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
…shot shaping its capture owner

ADR-0019's amendment forbids satisfying R13 by moving implementation
into contracts, so this wave's two relocations invert instead of sink:

- The Android dumpsys foreground parser returns to
  @agent-device/platform-android with its owning test, and
  contracts/android-observation goes back to observation vocabulary
  only. src/platforms/android/app-helpers exposes
  createAndroidAppStateReader(parseForegroundApp) and never imports
  upward; the composition seam in src/sdk/android-adb.ts injects the
  root-composed parser, keeping the published
  getAndroidAppStateWithAdb(adb) signature intact.
- The desktop snapshot projection moves to
  @agent-device/capture-kit/snapshot-desktop-projection beside the rest
  of the capture-side snapshot behavior; contracts exports the
  snapshot-scope vocabulary it consumes.

The #1832 history narration in the projection test is gone; the test
name and golden fixture carry the invariant.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
…atform-android seam

The injected-parser loop retires: platform-android's app-state module
owns the complete adb-executor read/parse (readAndroidAppStateWithExecutor,
beside its host-based twin), the façade exposes it lazily, the
composition root wraps it, and src/sdk/android-adb.ts reaches it through
that root in one hop. app-helpers keeps only the app-list helpers, and
the SDK-route tests live in SDK topology as src/sdk/android-adb.test.ts.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
@thymikee
thymikee force-pushed the refactor/platform-upward-edges branch from 50b9ac6 to 55d3cfe Compare August 27, 2026 20:52

Copy link
Copy Markdown
Member Author

50b9ac6 went fully green — 18/18, every check. Coverage, Repo Guards, Integration Tests, Typecheck & Package, Lint & Format, Compatibility & Provenance, Bundle Size, all four Smoke Tests jobs, and every CodeQL analysis.

That is the exact-head stack evidence you asked for, and the base is no longer a caveat: #2088 reached 33/33 on bb53b0e with the mutation lane passing on all ten shards.

Now on 55d3cfe, rebased onto #2088's f87c0fe. The only delta from 50b9ac6 is 11 files / 26 lines of comment-only citation repair carried up from the base — the W1 move had orphaned ~20 references to src/utils/*.ts and src/request/*.ts paths it deleted, including one pointing at a file that never existed. Details on #2088. No production behavior, closure, or budget change; the rebase was conflict-free.

Exact-head CI is re-running on 55d3cfe; I am not claiming this head green until it finishes.


Generated by Claude Code

@thymikee

Copy link
Copy Markdown
Member Author

Code review is clean at 55d3cfe1514dbd71a218bcdc6fed5f6f0e49bdbc: the citation-only rebase delta is behavior-neutral, ADR-0019 ownership is sound, and the public SDK route is exercised through the root composition seam with non-vacuous fallback/failure coverage. All 18 exact-head checks are green. This is code-ready for human review; merge sequencing remains dependent on open base #2088.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Aug 27, 2026
@thymikee

Copy link
Copy Markdown
Member Author

Exact-head readiness remains code-clean and GitHub reports CLEAN/MERGEABLE, but please correct the Validation accounting: 55d3cfe151 has 17 substantive SUCCESS checks plus one expected build-cache matrix SKIP, not “18/18 green.” Use that exact wording in the body/evidence comments. Merge sequencing still follows open base #2088; no code blocker.

Copy link
Copy Markdown
Member Author

Corrected, and applied to all three rather than just here — I had made the same conflation on the other two bodies.

PR head accounting
#2088 f87c0fe 32 substantive SUCCESS checks plus one expected build-cache matrix SKIP
#2090 55d3cfe 17 substantive SUCCESS checks plus one expected build-cache matrix SKIP
#2100 60347c3 20 substantive SUCCESS checks plus one expected build-cache matrix SKIP

The skip is matrix.name in the native-fingerprint workflow, which drops out when the fingerprint resolves unchanged. Counting it as a pass inflated every total by one, and "18/18 green" also implied a completeness the number did not carry.

I have not edited the earlier evidence comments, since rewriting posted claims would hide that they were wrong; this comment is the correction of record for all three. No code change, heads unmoved.


Generated by Claude Code

@thymikee
thymikee merged commit 7a6284b into main Aug 28, 2026
18 checks passed
@thymikee
thymikee deleted the refactor/platform-upward-edges branch August 28, 2026 05:46
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-08-28 05:47 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants