callstack / callstack/agent-device
refactor: cut the daemon's commands-closure leak and its last root hubs (successor to #2278 and #2335)
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- TypeScript
- Sterne
- 4.7k
- Forks
- 303
- Ø Merge
- 10 Std. 42 Min.
- Gemergte PRs (30 T.)
- 493
Beschreibung
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 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 importsrc/runtime.ts. - Daemon →
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.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.
Children
Wave A (independent):
- #2540 —
refactor(daemon): stop importing the commands barrel through src/runtime.ts. The closure leak; the only child that changes what the daemon loads. - #2541 —
refactor(runtime): own provider-device admission behind a typed capability. 12 pairs → 0. - #2542 —
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):
- #2543 —
refactor(cli-schema): orient the schema layer below commands. 5 value back-edges, 7 type-only. - #2544 —
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) 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/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 #2540). - Daemon →
src/outsidesrc/daemon/is 0 file pairs except the edges classified composition-essential or daemon-policy-essential by the R76 inventory. pnpm depgraphreports 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 importssrc/**, but packaging it before the closure cut and the hub ports just relocates the eager-closure problem. #2469 must also land first: the eager-closure budget cannot currently tolerate a module split. - Moving
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. - Growing
@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. - Collocation-only file moves, generic hook bags, and new gate detectors that do not name a measured edge. Per #2531's rules: fix-shaped, not detector-shaped.
Reproduction
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.
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne mit pnpm depgraph --out /tmp/depgraph.json und den Messungen in scripts/layering/model.ts; sieh dir die untergeordneten Wave A-Issues #2540–#2542 an, bevor du etwas änderst. Verfolge die Wertabschlussmenge des Daemons und die ausgehenden Paare aus src/daemon/**, und betrachte die aufgeführten Abschlussbedingungen sowie die Gate-Ergebnisse von R4/R5/R6 als erledigt.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- backend, build-system, devtools
- Issue-Typ
- Refactoring
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 25/100