callstack / callstack/agent-device

refactor: cut the daemon's commands-closure leak and its last root hubs (successor to #2278 and #2335)

Geschlossen
#2,545 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

refactor
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:

  1. 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.
  2. 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.

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 where daemon-request lives.

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 #2540).
  • Daemon → src/ outside src/daemon/ is 0 file pairs except the edges classified composition-essential or daemon-policy-essential by the R76 inventory.
  • 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. #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.
  • 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

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Ö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

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.