Skip to content

refactor(daemon): stop the client value-importing daemon internals (#2559) - #2594

Merged
thymikee merged 4 commits into
mainfrom
t3code/implement-issue-2559
Sep 14, 2026
Merged

thymikee merged 4 commits into
mainfrom
t3code/implement-issue-2559

Conversation

@thymikee

@thymikee thymikee commented Sep 14, 2026

Copy link
Copy Markdown
Member

Summary

src/daemon-client/** composed the daemon over the network but still value-imported its module graph — config.ts (state-dir), daemon-process.ts (pidfile liveness), session-repair-tombstone.ts, and request-progress-protocol.ts. This moves those process-root contracts out from under src/daemon/ so both sides reach them at the composition root and repoints the client at the relocated modules. The client keeps reading the canonical DaemonRequest/DaemonResponse vocabulary from daemon-request.ts as a type-only import.

Adds gate R78 daemon-client-entry: a runtime (value/dynamic) import of a daemon module by the client is red, an unrecorded type import is red, and a recorded edge the tree no longer imports is stale — so the residue (five type-only daemon-request.ts reads) can only shrink. daemon-modularity now skips src/daemon-client/ so the two gates never own one edge.

Review follow-ups: src/daemon/config.ts no longer re-exports the shared leaf and every importer reads src/daemon-resolution.ts directly (the re-export grew src/cli.ts's eager closure 295→296 against ADR 0019), and the mutation lane's subprocess exclusion follows daemon-process-takeover.test.ts to src/__tests__/.

62 files touched. Production sources (src + scripts, excluding tests and fixtures, rename-aware): +194 / −389, net −195. No behavior change; renames are content-preserving. Part of #2542. Closes #2559.

Validation

Head 3e7bd6f15a, merge-base 730b20149e. Green: eager-closure-budgets (610, src/cli.ts back to 295), check:layering (incl. R78 planted + stale proofs), check:fallow (0 issues in changed files, 0 stale), check:daemon-wire-compat + wire-compat vitest (protocol unchanged, 8 moved, 0 changed — digests identical), full test:unit (1299 files / 10033 tests), typecheck, lint, build. The CI Size report shows +320 B unpacked and slightly faster startup.

pnpm check:affected --run fails on two steps, both external to this change: lint emits no findings and aborts under the parallel fan-out (pnpm lint is exit 0), and mutation-model ("a kernel is owned by tests that reach it indirectly") is already red at merge-base main — a capture-kit scroll-edge-state reachability issue unrelated here. No rebase: the only file upstream also touched is check.ts, in a comment block. A serialized CI run is authoritative.

thymikee and others added 2 commits September 14, 2026 15:53
…2559)

src/daemon-client composed the daemon over the network yet still value-imported
its module graph: state-dir resolution (config.ts), pidfile liveness
(daemon-process.ts), the repair tombstone, and the request-progress framing. Move
those process-root contracts out from under src/daemon/ so both sides reach them
at the composition root, narrow src/daemon/config.ts to re-export only the state
helpers its own importers read (it keeps the daemon-only request-scoping rules),
and repoint the client's remaining imports at the relocated modules. The client
keeps reading the canonical DaemonRequest/DaemonResponse vocabulary from
daemon-request.ts, which is a type-only read. Repoint scripts/clean-daemon.ts and
the ios-snapshot-benchmark cell-admission at the relocated daemon-process.

No behavior change: renames are content-preserving and the wire protocol is
unchanged (wire-compat reports 8 moved, 0 changed, digests identical).

Co-Authored-By: Apex <noreply@callstack.com>
…ient rows from daemon-modularity (#2559)

Declare the daemon-entry surface the client is allowed to see. R78 names every
measured src/daemon-client -> src/daemon edge: a runtime (value or dynamic) import
of daemon internals is always red, an unrecorded type import is red, and a recorded
edge the tree no longer imports is red, so the set can only shrink and a repair
cannot leave a stale entry that lets an edge back in. The only residue is the five
type-only reads of daemon-request.ts: the canonical DaemonRequest/DaemonResponse
vocabulary that anchors the ADR 0006 wire surface, recorded with that rationale.

daemon-modularity now skips src/daemon-client/ so the two gates never own one edge:
its externalDaemonTypesImporters list drops the five client rows it used to cover,
leaving the two importers R78 does not reach. Move the two fallow health baseline
keys off the relocated daemon-process/request-progress-protocol paths (the move did
not carry their high-impact finding, so they are dead, not relocated).

Co-Authored-By: Apex <noreply@callstack.com>
@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.53 MB 4.53 MB +50 B
Package (unpacked) 4.53 MB 4.53 MB +50 B
Package (download) 1.34 MB 1.34 MB -37 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 22.1 ms 21.5 ms -0.5 ms
CLI --help 63.5 ms 59.9 ms -3.6 ms

@thymikee

Copy link
Copy Markdown
Member Author

The moves at 5a350b4 keep content and wire digests the same, and R78 covers every client-to-daemon edge that daemon-modularity used to check. Two things need a fix before merge.

Coverage fails because of this change. src/daemon/config.ts now re-exports from the new src/daemon-resolution.ts, and src/cli.ts:41 still imports resolveDaemonPaths from daemon/config.ts, so CLI startup loads one more module (296 vs 295, see eager-closure-budgets.test.ts in the Coverage job). Point the importers at daemon-resolution.ts directly and drop the re-export, so config.ts keeps only the daemon's own rules.

vitest.config.ts:14 still lists src/daemon/__tests__/daemon-process-takeover.test.ts in MUTATION_EXCLUDED_SUBPROCESS_TESTS. The test moved to src/__tests__/, so the mutation lane runs its real per-case daemon spawn again (#1545). Please update the path.

Also, the body says net −336 production lines, but the diff is about +294/−129 without tests and docs. Please correct it after the fix.

thymikee and others added 2 commits September 14, 2026 16:57
Re-exporting the shared leaf through src/daemon/config.ts cost every importer that
only needs a state dir one extra evaluated module, and src/cli.ts crossed the ADR
0019 eager-closure ratchet (296 against the merge-base's 295). Point the CLI, client,
daemon, scripts, and test importers of resolveDaemonPaths/DaemonPaths/
resolveDaemonServerMode straight at src/daemon-resolution.ts and drop the re-export,
so src/daemon/config.ts keeps only the request-scoping rules the daemon applies.

Co-Authored-By: Apex <noreply@callstack.com>
…tion lane (#2559)

daemon-process-takeover.test.ts moved to src/__tests__/ with the module it covers, but
the mutation lane's subprocess exclusion still named the old path, so thousands of
mutant reruns would have paid its real per-case daemon spawn again (#1545).

Co-Authored-By: Apex <noreply@callstack.com>
@thymikee

Copy link
Copy Markdown
Member Author

All three addressed at 3e7bd6f15a.

  • Eager closureebb1ea0ac6 drops the re-export and points the CLI, client, daemon, scripts, and test importers at src/daemon-resolution.ts directly, so src/daemon/config.ts keeps only resolveSessionIsolationMode/normalizeTenantId. eager-closure-budgets is green again (610 passed; the src/cli.ts case is back at 295 against the merge-base).
  • Mutation lane3e7bd6f15a moves the MUTATION_EXCLUDED_SUBPROCESS_TESTS entry to src/__tests__/daemon-process-takeover.test.ts, so its per-case daemon spawn stays excluded (Per-worktree dev state-dir spawns a fresh daemon per CLI invocation #1545).
  • Size figure — body corrected. Production sources (src + scripts, excluding tests and fixtures, rename-aware) are +194 / −389, net −195 across 28 files; 62 files touched overall.

Full test:unit (1299 files / 10033 tests), check:layering, check:fallow, wire-compat (protocol unchanged, 8 moved, digests identical), typecheck, lint, and build are green on the new head. Not rebased: the only file upstream also changed is scripts/layering/check.ts, in a comment block that does not overlap these hunks.

@thymikee

Copy link
Copy Markdown
Member Author

All three points are fixed at 3e7bd6f. src/daemon/config.ts no longer re-exports anything, no importer reaches resolveDaemonPaths or resolveDaemonServerMode through it, and the mutation exclusion now names src/__tests__/daemon-process-takeover.test.ts.

One small thing: the production figure in the body still does not match the diff. git diff -M --numstat 730b201 3e7bd6f without tests, fixtures and docs gives +303/−144 (net +159), not −195. Please correct the number. Smoke Tests were still running, and there are no conflicts.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 14, 2026
@thymikee
thymikee merged commit 4cfca7b into main Sep 14, 2026
18 checks passed
@thymikee
thymikee deleted the t3code/implement-issue-2559 branch September 14, 2026 15:36
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-14 15:37 UTC

thymikee added a commit that referenced this pull request Sep 14, 2026
…tle-on-exit-2522

* origin/main:
  perf(scroll-until): answer every candidate from one visibility index (#2596)
  refactor(daemon): resolve device interactors through a composed capability (#2593)
  refactor(daemon): stop the client value-importing daemon internals (#2559) (#2594)
  refactor(shell-quote): one implementation, reached through the runner host port (#2595)
  docs(agents): delete the file-size tiers nobody enforces (#2597)
  fix(daemon): key the implicit session by workspace and platform (#2587)
  refactor(cli-schema): orient the schema layer above commands (#2543 step 3) (#2590)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Declare the daemon entry surface and stop daemon-client importing daemon internals

1 participant