refactor(substrate): split host mechanics into @agent-device/host-kit capability ports - #2088
Conversation
|
Size Report
npm unpacked components
Startup median (7 runs, lower is better):
Top changed chunks:
Top changed packed files
|
|
[P1] Keep moved decision kernels owned by the mutation lane. This head deletes/moves [P2] Prove the new project-root behavior, not only memoization. The W1 package boundary itself is directionally sound and the 1311+/909- change is move-dominated with itemized growth, but this head is not ready while the owning structural gate is red and the behavior change lacks planted-red proof. |
|
Re-reviewed |
|
Both points addressed on the current head ( P1 landed in P2 in Generated by Claude Code |
|
Re-reviewed |
47da869 to
39af141
Compare
|
Addressed on
Generated by Claude Code |
|
Still not ready at |
|
Fixed on
Verified: the shard runs end-to-end locally — dry run executes 2,265 tests, 287 mutants tested, report written — and the mutation model suite (39/39), layering, typecheck, and the moved test all pass. Remaining explanatory comments trimmed to bare directives per the new AGENTS rule. Generated by Claude Code |
6be4299 to
10009d5
Compare
|
Not ready. [P1] This wave contradicts ADR-0019 on both sides: it turns capture-kit from the durable-capture domain into generic platform-common, and moves ~900 lines of snapshot presentation/occlusion/codec behavior into contracts despite the ADR limiting contracts to vocabulary/plans. Split behind cohesive owners or explicitly amend and enforce the architecture before later family waves depend on it. [P2] The Stryker disk-manifest fallback infers sandbox mode from an empty tracked result and has no regression that exercises that branch; make the manifest source explicit and add planted-red sandbox proof. Remove the remaining touched implementation/history narration per current AGENTS policy. Exact-head kernel-errors mutation also times out before producing a report; selectors-2 is pending. |
|
Addressed on P1 — the ~1,000 lines of snapshot behavior ( P2 — kernel-errors timeout — root-caused, not flake: the alias fix made the dry run genuinely transform the mutated tree in-sandbox (before, specifier imports escaped to the real unmutated tree, which is what the default five-minute dry-run budget was calibrated against). Remaining resolver/version narration trimmed to bare constraint statements. Generated by Claude Code |
|
Not ready. The snapshot-behavior move and explicit mutation-source fix are sound, but the architecture blocker remains. The ADR amendment relabels capture-kit as owner of process execution, archives, PNG, atomic files/locks, request plumbing, retry/path/env/version utilities, and other unrelated mechanics, exposing dozens of shallow subpaths. That is the generic platform-common grab bag ADR-0019 was intended to remove; pinning exports freezes the surface but does not create a cohesive owning domain. Keep capture and snapshot behavior here, but move generic host/process/request utilities behind a focused deep interface rather than using ADR prose to bless the workaround. Remove the added implementation/history narration, and require the kernel-errors mutation shard to finish green. |
|
Two of the three asks are done on On the capture-kit P1, before a third relocation of the same ~38 modules I want to agree the target shape, because "focused deep interface" fixes two different things and the blast radius differs by an order of magnitude:
I read your comment as asking for (1). Confirm — or pick (2) or another cut — and I'll implement it across the stack; the matching ADR text then describes whichever layout actually ships rather than blessing the current one. Generated by Claude Code |
|
The exact-head iOS smoke failure on Generated by Claude Code |
|
The snapshot behavior and mutation-source work are sound, but the broader capture-kit ownership blocker remains unchanged on this comment-only head. Confirming the full remedy you outlined: use option 1, a focused host-mechanics owner with a small deep surface ( |
|
Capture-kit is narrower, but the requested host owner is still a generic platform-common utility package hidden behind four technical barrels. |
|
Option 1 is implemented on
The seams are pinned rather than open-ended — The ADR-0019 amendment is rewritten to describe this layout instead of blessing capture-kit as the host owner, and the remaining alias-source and Stryker narration is gone. Two things the seam merge surfaced and this push fixes, both real bugs rather than mechanics: eight test files had per-module Green locally on Generated by Claude Code |
…2082 W1) The shared src/utils closure that blocked the platform-family moves lands on declared owners: generic host mechanics form a new private @agent-device/host-kit package between kernel and capture-kit, and capture-kit keeps capture, snapshot, and recording behavior, depending on host-kit for the mechanics it needs. tar-stream and yauzl move with the archive code. Every seam's exported subpaths are pinned in package-boundaries.test.ts, the layering model ranks the new zone, R13's allow-list names it, and each seam carries an exact eager-closure row. ADR-0019's substrate amendment describes the layout. Tests that mocked two of the moved modules separately became duplicate same-seam vi.mock factories, where the second silently replaced the first; those are merged, and the mocks that production code reaches past are pinned at their injection points instead. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
fccf8c1 to
56039fe
Compare
|
Rebase reconciliation did not change the host-kit blocker: four technical barrels still combine unrelated generic mechanics, eager budgets remain CLI 386/session teardown 79, and fresh CLI-help median worsened 71.8→98.6ms. Split around cohesive owners/narrow capability ports and enforce semantic dependency shape; remove moved narration. Update the stale PR body, which still describes the superseded capture-kit layout. Android smoke is red and most CI/mutation lanes are pending. Not ready. |
The four technical barrels (exec/fs/values/request) grouped by category rather than by capability, so a consumer needing one mechanic evaluated unrelated ones. Each export is now a single capability over the host machine: command, process, diagnostics, retry, archive, file, request, version. A port re-exports only what a consumer of that capability uses, and every port carries its own eager-closure row. Most of the old values barrel was never host mechanics. Pure record readers, config-source values, result text, memoization, async scoping, coordinate validation, and device-scope parsing touch no process, file, or environment, so they join kernel's other primitives instead. Closures fall accordingly: capture-kit's png-worker-client from 20 to 10, png-resize from 28 to 18, session-teardown from 79 to 68, and the CLI from 386 to 380. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
|
The eight capability ports materially resolve the prior generic host-kit blocker: archive/command/diagnostics/file/process/request/retry/version are cohesive, per-port closure is 3–12 files, eager closure improves, and packed size is neutral. Not ready: remove the unused root scratch-exports.json and scratch-symbol-map.json migration inventories (346 unexplained lines; no consumers); update the stale PR body to describe the current eight-port ownership, itemize current growth, and record why the rejected four-barrel/smaller façade did not preserve capability boundaries; trim touched implementation/enforcement narration including packages/kernel/src/scoped-provider.ts and the package-boundary/eager-budget comments. Coverage, native smoke, and affected mutation evidence must also finish. |
|
Rebased onto The barrels are gone. You were right that
Most of The closure numbers you cited move the right way. Every port carries its own eager-closure row, so a port that grows unrelated mechanics fails the gate:
The ports themselves measure 3–12 ( The ADR amendment now states the rule the ports have to keep passing, rather than describing the layout: a port may only hold mechanics a consumer of that capability needs, and a helper that touches no process, file, or environment does not belong in host-kit. The resolver/Stryker narration is gone. Green on On the red Android lane, see the investigation below — it reproduces identically on unrelated PRs while Generated by Claude Code |
|
Android Smoke Tests: not this PR's, and not this stack's. The failure is the same on every red run: the Evidence it is load-borne rather than caused by any diff:
Nothing in this stack touches gesture handling, alert dismissal, or the wait loop; W1 is a mechanics move, W2 is Android app-state ownership, W3 is provisioning and settings placement. No fix exists to port: #2105 addresses device-claim supersession on a retried open, which is a different failure. The scenario's own 10s budget after an alert dismissal is what is too tight under load; a fix belongs in Generated by Claude Code |
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
|
Re-reviewed Not ready yet. Remove the remaining touched implementation/history narration under current AGENTS policy: |
|
All four addressed on Scratch inventories gone. PR body rewritten to the eight-port ownership: what each port owns with its measured closure, the itemized growth against Narration trimmed: the consumer roster on On "Affected decision-kernel mutants": that failure is an artifact of my own push, not a mutation regression. Two shard jobs — Coverage, native smoke, and the mutation lane all re-run on Generated by Claude Code |
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
|
Both addressed on Narration trimmed at all four sites: PR body rewritten to On the mutation lane — I can now name the mechanism, and it is mine. Both failures have the identical shape: the So this is not a lane defect and not a mutation regression; it is my push cadence against a ~19-minute lane. Generated by Claude Code |
|
Correction to my Android write-up above: I said "I have no job-rerun permission from this session, so the lane re-runs on the next push." That was wrong. I had assumed it rather than testing it. I can re-run failed jobs, and I have just used that on #2100's Android smoke (run 33110065044), which hit the same That is the one re-run the standing-down comment entitles the failure to; if it comes back red on the re-run I will treat it as this stack's problem rather than as load, and root-cause the alert-dismissal path instead of comparing runs. Nothing else in that write-up changes: the failure still reproduces byte-identically on unrelated PRs while Generated by Claude Code |
|
CI is green on The mutation lane passed with all ten shards present (aggregate at 20:00:09). That closes the thread I have commented on three times, and the timings confirm the mechanism rather than just being consistent with it:
Those two run two to four times longer than everything else, so any push landing ~17 minutes into a run kills exactly that pair and nothing else — which is what happened on One correction to my earlier account, since I stated it as fact without checking: I described those two as "the last shards to start". They are not — they start first (19:41:31 and 19:42:11, ahead of the other eight). They are simply the longest-running. The conclusion is unaffected, but the detail was wrong. Also green on this head: Coverage, Repo Guards, Integration Tests, Typecheck & Package, Lint & Format, Compatibility & Provenance, Bundle Size, every CodeQL analysis, and all five Smoke Tests jobs — the Android native-alert step included, with no change to the alert path. Generated by Claude Code |
|
Re-reviewed Not ready under current AGENTS comment policy. The cleanup shortened but retained explanatory narration in |
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
|
Both addressed on Comments are tool directives only in the touched tree. Removed: the memo/catch rationale in One judgement call worth flagging rather than burying: in A near-miss from this cleanup, for the record. Stripping the comment out of Body corrected: the file count now reads 598, and the Validation section states both lanes as green with the failures described as historical. The mutation paragraph now carries the shard timings that explain the three cancellations ( Generated by Claude Code |
|
Re-reviewed Not ready yet. The full touched tree still contains implementation/test-tour narration at |
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
|
All four sites cleared on Removed: the header and both docblocks in Body corrected on the green claim. The Validation section now says exact-head CI is still running and does not assert this head is green; it separates local evidence at this head from what completed on On the Android smoke failure at An empty block reformatted onto one line. Identical executable behavior, one run green and the next red, which is as clean a demonstration as this lane will produce that the failure is not caused by the change. Worth recording from that same edit: stripping the comment out of that catch left it empty, and my first attempt to "tidy" it wrote Generated by Claude Code |
The W1 move rewrote this citation to packages/contracts/src/mobile-snapshot-semantics.ts, which does not exist: the module went to capture-kit while isTapPointInsideViewport itself went to packages/contracts/src/snapshot-visibility.ts. The TS test line was left pointing at the pre-move path. Both now resolve. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
The W1 move left ~20 comment citations pointing at src/utils/*.ts and
src/request/*.ts paths that no longer exist. Each now names the capability
port that owns the symbol, which survives further file moves:
exec -> host-kit/command host-process, owner-identity -> host-kit/process
diagnostics -> host-kit/diagnostics atomic-file, process-lock -> host-kit/file
retry -> host-kit/retry request progress/cancel -> host-kit/request
version -> host-kit/version ttl-memo, source-value, parsing, device-isolation,
keyed-lock, success-text -> kernel subpaths
Comment-only; no closure, budget, or behavior change. ADR citations are left
as written, being dated records of the decision rather than live references.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
|
Also green on that head: Coverage, Repo Guards, Integration Tests, Typecheck & Package, Lint & Format, Compatibility & Provenance, Bundle Size, every CodeQL analysis, and all five Smoke Tests jobs. New head is A broken reference this PR introducedFollowing up the iOS lane led me to something I had wrong. There is no That prompted a repo-wide sweep, and the problem is systemic rather than isolated: ~20 comment citations across 11 files point at Verified at Two corrections to my Android write-upBoth were wrong, and I am flagging them rather than quietly dropping them. "The surface still reported a "Take the budget from the same scaling the other live steps use." There is no such scaling anywhere in the repo — no CI factor, no env override. The failing step already uses the same shared The actual defect: One thing that weakens my iOS argumentI said this stack does not touch the iOS runner path. The TS side holds — nothing under If that lane goes red again, the Generated by Claude Code |
|
Re-reviewed exact head Code-clean and ready for human review, but not yet merge-ready: exact-head iOS smoke and the mutation shards/aggregate are still pending. Reconfirm once those finish green. |
|
Reconfirming as you asked: the exact head
The iOS smoke and mutation shards you were waiting on both finished green. All five native Smoke Tests jobs passed here, alongside Coverage, Repo Guards, Integration Tests, Typecheck & Package, Lint & Format, Compatibility & Provenance, Bundle Size, command-docs-gate, Ownership and context budgets, and every CodeQL analysis. The mutation timings held to the pattern on a second independent run — All three Validation sections now state the completed exact-head evidence rather than saying CI is running. One item deliberately left out of this stack, recorded so it is not lost: Generated by Claude Code |
Summary
Nothing changes for operators, clients, or command authors: no CLI surface, wire shape, or platform behavior moves. This is the substrate step of #2082 that unblocks the platform-family moves, and its reviewable claim is where shared code is allowed to live.
@agent-device/host-kitis a new private package between kernel and capture-kit holding only mechanics that act on the host machine. Each export is one narrow capability, not a technical category:commandprocessdiagnosticsretryarchivefilerequestversioncapture-kit keeps capture, snapshot and recording behavior and depends on host-kit;
tar-streamandyauzlmove with the archive code. Helpers that touch no process, file, or environment are not host mechanics and went to kernel instead (record,source-value,success-text,ttl-memo,scoped-provider,location-coordinates,device-isolation) — the same shape as #2106 sinkingscreenshot-geometrythere. Enforced direction:kernel < contracts < host-kit < capture-kit < platform/provider/daemon.Three earlier shapes were rejected: four category barrels (
exec/fs/values, which put unrelated concerns behind one specifier and measurably grew closures), deep façades over the modules in place (hides the surface without moving ownership), and one file per subpath (dozens of shallow generic subpaths with no capability boundary).Tradeoff: consumers now evaluate a port file where they used to import a module directly.
src/cli.tsgoes 369 → 380 andsrc/daemon/session-teardown.ts60 → 68; for the CLI the +11 is exactly the 11 façade files it reaches. Packed size is neutral (JS gzip −270 B).Scope: 604 files, nearly all mechanical specifier rewrites; no command family was touched.
Validation
Exact head
f87c0fehas 32 substantive SUCCESS checks plus one expected build-cache matrix SKIP: Coverage, Repo Guards, Integration Tests, Typecheck & Package, Lint & Format, Compatibility & Provenance, Bundle Size, command-docs-gate, Ownership and context budgets, Resolve native fingerprint, every CodeQL analysis, all five native Smoke Tests jobs, and the full mutation lane — ten shards plus the aggregate, which passed at 21:19:43 with every shard present and green. The skip ismatrix.name, which drops out when the native fingerprint is unchanged.The previous head
bb53b0ehad the same 32 SUCCESS plus one SKIP. The delta between them is one comment-only commit (11 files, 26 lines) repairing references this PR broke: the move orphaned ~20 comment citations pointing atsrc/utils/*.tsandsrc/request/*.tspaths it deleted — all of which resolved at merge-base77b5be8— including one rewritten topackages/contracts/src/mobile-snapshot-semantics.ts, a file that has never existed. Each now names the owning capability port instead of a path.package-boundaries.test.tspins the eight subpath keys and the dependency set, the layering model ranks the new zone, and R13's allow-list names host-kit. Every port and every sunk kernel module carries an exact eager-closure row, so a port that grows unrelated mechanics fails the gate.Two lanes were red on earlier heads; both are resolved and neither was caused by this diff:
kernel-errorsandselectors-2cancelled. Those two run ~19½ minutes against the other eight's 5½–10, so a push landing ~17 minutes into a run kills exactly that pair, and the aggregate then correctly refuses to publish a pass over an incomplete shard set. Left undisturbed the lane takes ~27 minutes and passes, as it now has on two consecutive heads. No shard ever failed on its own.smoke:automation-systemnative-alert step. It reproduced byte-identically on unrelated PRs whilemainwas green, and it passed onc8b6eb1then failed ona7c8df6, whose only non-comment difference is} catch {\n}reformatted to} catch {}. It has since passed onbb53b0eandf87c0feand on both stacked PRs. Investigating it did surface a real scenario-side bug —alert dismissreturns without confirming the dialog closed, and falls back to Back, which cannot produceAlert result: cancelled— but the fix lives outside this refactor and is proposed in the comments rather than pushed.Follow-up: the size report's CLI-help median swings widely between runs on identical content (71.8→98.6ms on one, 81.0→83.3ms on the next, −2.4ms later), so that figure looks noisier than the effect it would measure.
🤖 Generated with Claude Code
https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH