Skip to content

chore(gates): classify root hubs, dynamic edges, and the root-to-daemon entry #2542

Description

@thymikee

Purpose

Three blind spots let daemon/root coupling reappear without failing a gate. Each is a measured hole, not a hypothetical.

  1. Root hubs are not classifiable. R76 (scripts/layering/daemon-platform-runtime-inventory.ts) matches src/daemon/** importing src/platform-runtime(?:\.ts|-[a-z0-9-]+\.ts). A daemon file importing a differently-named root hub that itself reaches platform mechanics is invisible: src/provider-device-runtime.ts accounts for 12 daemon file pairs and imports src/platform-runtime.ts and src/platform-runtime-screen-recording-apple-runner-transport.ts on its own behalf, neither of which is under any inventory. ADR 0022's "one leaked edge remains" is true only for direct edges to gated names.
  2. Dynamic imports are unwatched. R4/R5/R6 see static edges. Today's one instance: src/daemon/snapshot-interactor-capture.tssrc/core/interactors.ts (dynamic; src/core/interactors.ts imports src/provider-device-runtime.ts). docs/dependency-graph-findings.md already records dynamic direction as "outside every rule".
  3. Nothing owns root → daemon. 37 file pairs reach into daemon internals from outside. src/daemon-client/** — which wave 3's refactor(daemon): relocate the daemon client out of src/daemon #2360 moved out of src/daemon/ — still holds 13 pairs / 8 value edges into daemon-request.ts, config.ts, daemon-process.ts, session-repair-tombstone.ts, request-progress-protocol.ts. The move changed the client's location, not its imports.

Umbrella: #2545.

Required behavior

  1. Extend the R76 inventory so a daemon edge to a root module that reaches platform mechanics is classified even when the module name is not platform-runtime-*. Keep the existing three categories and the same no-drift/no-stale rules; widen the target predicate rather than adding a second table.
  2. Make dynamic import direction observable in the same pass: a dynamic daemon edge into a root or lower zone must be classifiable or reported. Do not add a separate gate job.
  3. Add one declared entry surface through which non-daemon code may import the daemon, and ratchet the rest. src/daemon-client/** and src/cli/** are the named importers today; a file outside the declared entry gaining a daemon import fails. Repair the residue rather than allowlisting it: the daemon-client edges into session-repair-tombstone.ts, daemon-process.ts, and request-progress-protocol.ts are the real work.
  4. Ratchet, don't reset: the R75 handler-owned session-authority ratchet and the R6 type-inversion ratchet keep their current references. Current inversions are commands -> client (2), commands -> daemon-server (1), mcp -> client (1).

Completion conditions

  • A planted daemon import of an unclassified root hub turns the layering check red. Verify the same for a planted dynamic edge and a planted out-of-entry daemon import, before acceptance.
  • Stale-entry and symbol-drift failures still fire (existing R76 behavior must not weaken).
  • src/daemon-client/**src/daemon/** value edges reach 0, and the shrink-only rule holds the set there.
  • One gate run, no new CI job.

Out of scope

Dependencies

  • None for the gate work. Wave A. The provider-device port child and the extraction child both want to touch the inventory; sequence the inventory edit into this branch where the branches meet.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions