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
Remove the last structural coupling that makes the daemon expensive to change and impossible to package, and stop it paying for the whole command pipeline it never calls. Successor to #2278 (residual semantic coupling, closed) and #2335 (decoupling wave 3, closed). Those waves moved code into packages and classified what remained; this one cuts the two things measurement shows are still load-bearing.
Measured at 9aa6465768 with the gate's own model (pnpm depgraph plus a throwaway probe against scripts/layering/model.ts): 1,684 production files, 8,689 edges, 38 zones, R4 = 0, R5 = 0, R6 = 4.
Two findings drive the sequence:
The daemon's eager value closure contains 121 src/commands/** files (717 files total in the closure). One value edge is responsible for 48 of them: src/runtime.ts → ./commands/index.ts. Five daemon files import src/runtime.ts.
Daemon → src/ outside the daemon is 51 file pairs (42 root flat files, 7 src/core/**, 2 src/cli-schema/**), down from 154 edges into 67 files at the wave-3 baseline. Twelve of those pairs are one file, src/provider-device-runtime.ts, and ten of its twelve importers need exactly one symbol, isActiveProviderDevice.
Fan-in is not cost. Churn over the last 400 commits: src/backend.ts 53, src/provider-device-runtime.ts 19, src/runtime.ts 6, src/runtime-contract.ts 5, src/io.ts 4. runtime-contract.ts has 27 importers and is nearly frozen; it is not a target.
Wave B is not scheduled while a Wave A branch is open on the same files; src/commands/index.ts (#2540) and cli-schema/command-schema.ts (#2543) overlap, and #2542 owns the R76 inventory both #2541 and #2544 want to edit.
Completion conditions
This umbrella closes when every child is closed and:
The daemon's value closure reaches src/commands only through src/runtime-command-surface.ts, contains only the capture, selectors, and interactions runtime families (src/commands/*/runtime/**) plus their shared runtime helpers, and includes no command facet, CLI reader, output formatter, or the all-family barrel. Measured at 775163bb35: 34 files, 6,368 LOC, down from 121 files, 19,659 LOC. Zero was the original wording; it is unreachable while the daemon executes those three families in-process, and relocating the runtime directories would only change the count, not what loads (decided 2026-09-14 on refactor(daemon): stop importing the commands barrel through src/runtime.ts #2540).
Daemon → src/ outside src/daemon/ carries only (a) edges classified composition-essential or daemon-policy-essential by the R76 inventory, (b) the shared runtime contracts and command surface (backend.ts, runtime-contract.ts, runtime-factory.ts, runtime-command-surface.ts, io.ts, src/core/**), and (c) process-root contracts that refactor(daemon): stop the client value-importing daemon internals (#2559) #2594 moved out of the daemon so the client could share them without importing daemon internals (daemon-resolution.ts, daemon-process.ts, request-progress-protocol.ts, session-repair-tombstone.ts). No daemon file imports a root hub that reaches platform mechanics outside the inventory. The raw pair count is not the target: it was 51 at 9aa6465768, 42 after Wave A, and 52 after refactor(daemon): stop the client value-importing daemon internals (#2559) #2594 by design, because the client-side repair added daemon → root leaves rather than removing them (reworded 2026-09-16).
pnpm depgraph reports the same R4/R5 = 0 and R6 does not grow past its ratchet.
Explicitly not scheduled
Packaging the daemon. Inbound is already only ~20 non-daemon files and no packages/** file imports src/**, but packaging it before the closure cut and the hub ports just relocates the eager-closure problem. gates: let the eager-closure budget tolerate a module split without admitting new eager work #2469 must also land first: the eager-closure budget cannot currently tolerate a module split.
Moving src/backend.ts or src/runtime-contract.ts. Both are type-only surfaces (value closure of backend.ts is one file) with churn of 53 and 5 commits per 400. Relocating a near-frozen type surface is a rename, not decoupling.
Growing @agent-device/contracts as a destination for src/core/** without a separate measurement of its own churn. At 18k LOC and 185 files it is the second hub in the repo.
pnpm depgraph --out /tmp/depgraph.json, or a throwaway scripts/layering/.probe.ts over listSourceFiles() + resolveImportEdges() restricted to isProductionSourceFile, computing per-bucket outbound pairs, edge kinds (typeOnly/dynamic), and value-only transitive closure from src/daemon/**. Delete the probe after.
Purpose
Remove the last structural coupling that makes the daemon expensive to change and impossible to package, and stop it paying for the whole command pipeline it never calls. Successor to #2278 (residual semantic coupling, closed) and #2335 (decoupling wave 3, closed). Those waves moved code into packages and classified what remained; this one cuts the two things measurement shows are still load-bearing.
Measured at
9aa6465768with the gate's own model (pnpm depgraphplus a throwaway probe againstscripts/layering/model.ts): 1,684 production files, 8,689 edges, 38 zones, R4 = 0, R5 = 0, R6 = 4.Two findings drive the sequence:
src/commands/**files (717 files total in the closure). One value edge is responsible for 48 of them:src/runtime.ts→./commands/index.ts. Five daemon files importsrc/runtime.ts.src/outside the daemon is 51 file pairs (42 root flat files, 7src/core/**, 2src/cli-schema/**), down from 154 edges into 67 files at the wave-3 baseline. Twelve of those pairs are one file,src/provider-device-runtime.ts, and ten of its twelve importers need exactly one symbol,isActiveProviderDevice.Fan-in is not cost. Churn over the last 400 commits:
src/backend.ts53,src/provider-device-runtime.ts19,src/runtime.ts6,src/runtime-contract.ts5,src/io.ts4.runtime-contract.tshas 27 importers and is nearly frozen; it is not a target.Children
Wave A (independent):
refactor(daemon): stop importing the commands barrel through src/runtime.ts. The closure leak; the only child that changes what the daemon loads.refactor(runtime): own provider-device admission behind a typed capability. 12 pairs → 0.chore(gates): classify root hubs, dynamic edges, and the root-to-daemon entry. Makes the residue in this issue visible and non-regrowing.Wave B (after Wave A):
refactor(cli-schema): orient the schema layer below commands. 5 value back-edges, 7 type-only.refactor(daemon): extract the maestro adapter and durable-capture admission subtrees. Blocked on wheredaemon-requestlives.Wave B is not scheduled while a Wave A branch is open on the same files;
src/commands/index.ts(#2540) andcli-schema/command-schema.ts(#2543) overlap, and #2542 owns the R76 inventory both #2541 and #2544 want to edit.Completion conditions
This umbrella closes when every child is closed and:
src/commandsonly throughsrc/runtime-command-surface.ts, contains only thecapture,selectors, andinteractionsruntime families (src/commands/*/runtime/**) plus their shared runtime helpers, and includes no command facet, CLI reader, output formatter, or the all-family barrel. Measured at775163bb35: 34 files, 6,368 LOC, down from 121 files, 19,659 LOC. Zero was the original wording; it is unreachable while the daemon executes those three families in-process, and relocating the runtime directories would only change the count, not what loads (decided 2026-09-14 on refactor(daemon): stop importing the commands barrel through src/runtime.ts #2540).src/outsidesrc/daemon/carries only (a) edges classified composition-essential or daemon-policy-essential by the R76 inventory, (b) the shared runtime contracts and command surface (backend.ts,runtime-contract.ts,runtime-factory.ts,runtime-command-surface.ts,io.ts,src/core/**), and (c) process-root contracts that refactor(daemon): stop the client value-importing daemon internals (#2559) #2594 moved out of the daemon so the client could share them without importing daemon internals (daemon-resolution.ts,daemon-process.ts,request-progress-protocol.ts,session-repair-tombstone.ts). No daemon file imports a root hub that reaches platform mechanics outside the inventory. The raw pair count is not the target: it was 51 at9aa6465768, 42 after Wave A, and 52 after refactor(daemon): stop the client value-importing daemon internals (#2559) #2594 by design, because the client-side repair added daemon → root leaves rather than removing them (reworded 2026-09-16).pnpm depgraphreports the same R4/R5 = 0 and R6 does not grow past its ratchet.Explicitly not scheduled
packages/**file importssrc/**, but packaging it before the closure cut and the hub ports just relocates the eager-closure problem. gates: let the eager-closure budget tolerate a module split without admitting new eager work #2469 must also land first: the eager-closure budget cannot currently tolerate a module split.src/backend.tsorsrc/runtime-contract.ts. Both are type-only surfaces (value closure ofbackend.tsis one file) with churn of 53 and 5 commits per 400. Relocating a near-frozen type surface is a rename, not decoupling.@agent-device/contractsas a destination forsrc/core/**without a separate measurement of its own churn. At 18k LOC and 185 files it is the second hub in the repo.Reproduction
pnpm depgraph --out /tmp/depgraph.json, or a throwawayscripts/layering/.probe.tsoverlistSourceFiles()+resolveImportEdges()restricted toisProductionSourceFile, computing per-bucket outbound pairs, edge kinds (typeOnly/dynamic), and value-only transitive closure fromsrc/daemon/**. Delete the probe after.