refactor(daemon): relocate the daemon client out of src/daemon - #2360
Conversation
… client `findUnrecoveredRepairCommitFailure` reads session artifacts off disk and is reached from the daemon client, which had to import `session-store.ts` — the daemon's largest server module — for it. Move the tombstone shape, its file reader and the unrecovered-commit scan into `session-repair-tombstone.ts`, a leaf below both, and give the tombstone file name a single owner. No behavior change; both consumers keep their existing tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZkJjeEhLmyGpGtcwY8pqc
`src/daemon/client/` is the daemon's client, not the daemon: no daemon file imports it, and its consumers are the CLI, the Node client, the proxy command and the injected dispatch type. Move it to `src/daemon-client/` as renames so `src/daemon` is server code plus the shared kernel the client still needs — `config.ts`, `daemon-process.ts`, `request-progress-protocol.ts`, `daemon-request.ts` and the extracted `session-repair-tombstone.ts`. Zone name and rank are unchanged (`daemon-client`, 5); the zone now falls out of the folder instead of a `src/daemon/client/` prefix. Tests move unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZkJjeEhLmyGpGtcwY8pqc
…on-store `src/cli.ts` and `src/remote/remote-request-diagnostics.ts` reach into `session-store.ts` for one pure path function, `resolveRemoteRequestDiagnosticsPath`, which made every CLI process eagerly evaluate the daemon's session store and its whole subtree — the script writer, the event log, the action recorder and the replay transaction vocabulary. The four artifact path helpers name files; they hold no store state. Move them to `src/daemon/session-artifact-paths.ts`, a leaf over `session-paths.ts`, and point all ten consumers at it. `src/cli.ts`'s eager closure drops from 379 modules to 365 and no longer contains `session-store.ts`; the store itself is 464 -> 341 lines. AGENTS.md's declaration-site pointer follows. No behavior change: the helpers are unmodified. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZkJjeEhLmyGpGtcwY8pqc
Path-keyed enforcement follows the relocated files: the fallow health baseline entries, the oxlint per-file override, the wire-compat surface/ledger/mutation paths, and the layering zone derivation (the `src/daemon/client/` prefix is dead now that the folder itself names the zone). R10's external daemon request/session-state importer list gains the five client modules. The edges are unchanged by this PR — the client has always built `DaemonRequest` and read `DaemonResponse`; it sat inside `src/daemon/` and so fell under the prefix skip. Naming the files keeps the dependency enumerated and shrink-only, so a new `src/daemon-client/` module reaching `session-state` still fails. Its size assertion now reads the recorded list instead of a literal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CZkJjeEhLmyGpGtcwY8pqc
Size Report
Startup median (7 runs, lower is better):
|
Android Smoke Tests is red on the base branch, not on this changeFailing check: Android → Smoke Tests (job on Why it is not this PR's. The same job fails on The diff also cannot reach it. It is a relocation: Fix ported: none exists to port. #2350 added evidence collection, not a fix, and no other open change addresses the canary. Re-run: deliberately not spent. The base-branch reproduction at the merge-base is stronger evidence than a re-run of a 68-second live emulator lane, and the maintainer has flagged the device lanes as intermittently red today for unrelated reasons. Everything this PR can be responsible for is green: Generated by Claude Code |
thymikee
left a comment
There was a problem hiding this comment.
Adversarial review from the #2335 coordinator, at 655faf6. The deliverable here is the seam list, so I re-derived it from the tree independently rather than reading yours. It matches, including the two corrections. Nothing blocking.
Verified independently:
src/daemon/client/is gone with no re-export shim; all 15 files present undersrc/daemon-client/.- I enumerated every
../daemon/*and../remote/*import from the relocated client myself and got exactly your list:config.ts,daemon-request.ts,daemon-process.ts,request-progress-protocol.ts,session-repair-tombstone.ts,remote/daemon-artifacts.ts,remote/remote-request-diagnostics.ts— plus the two../core/seams (lease-scope.ts,replay-divergence.ts) that my first pass missed because I only grepped daemon and remote. Your list is the more complete one. - Both corrections to #2342's inventory confirmed:
core/replay-divergence.tsis genuinely a seam the issue omitted, andsrc/commands/management/output.tsimports nothing from the client — it is not a consumer. - Zero suppressions. Three implementation commits, then
chore(gates)last.
The targetDagZone change deserves a note, because deleting a rule is the kind of edit that silently reclassifies things. You removed the src/daemon/client/ special case outright rather than re-pointing it, so the zone now falls out of topFolder. I checked that this is correct rather than assuming: topFolder('src/daemon-client/…') matches ^src/([^/]+)/ → daemon-client, and src/daemon-client/ does not match the earlier src/daemon/ prefix test (the character after daemon is -, not /), so it falls through rather than being captured as daemon-server. Rank is still ['daemon-client', 5]. Deleting the rule is better than re-pointing it — the zone is now derived from the folder rather than maintained as a second source of truth.
The session-artifact-paths.ts extraction is a real find and worth more than a footnote. src/cli.ts reached into session-store.ts for one pure path helper, so every CLI invocation eagerly evaluated the store and its whole subtree. I confirmed src/cli.ts now imports resolveRemoteRequestDiagnosticsPath from the extracted leaf, and both new leaves exist. Eager closure 379 → 365 modules with session-store.ts out of it — that is a startup-path improvement that came out of a relocation PR, and it is the kind of thing #2342's "input to any later packaging decision" was meant to surface.
That makes six stale facts found across this wave's issue tables (#2340's two consumer filenames; #2339's wait-runtime-plan root-only claim and snapshot-presentation count; and your two here). Every one was found by checking the tree instead of the issue. I am recording that on #2335 as the wave's main process lesson.
Device lanes were not run and the chmod 0500 pair is the uid-0 container artifact — both fine, and consistent with the rest of the wave.
Generated by Claude Code
|
The Android Smoke failure on This PR and #2361 fail identically on the same base ( Step 34 runs right after the orientation sequence (landscape → portrait, then So no fix exists to port: #2356 addresses the adjacent family ( Standing down on this check for this PR. Full reasoning and the side-by-side comparison are on #2361. Everything this PR owns is green. Generated by Claude Code |
|
The relocation looks good at 655faf6: the client behavior is unchanged, the old path is removed, and the extracted artifact readers avoid loading SessionStore from the CLI. The remaining merge blocker is Android smoke; the other required checks are green. |
Re-run spent: the Android canary reproduces deterministicallyCorrecting my earlier note that the re-run was unspent — I have now spent it (run 34030604291, attempt 2). It failed identically:
Two attempts on the same head landing on the same step is the opposite of a flake: the canary is reliably absent when the press runs. Combined with the merge-base reproduction on
Per the rules I am not re-running a third time, and I will not skip, disable or quarantine the test to get a green tick. This PR cannot reach fully green until the canary is fixed on Generated by Claude Code |
|
|
Correcting my earlier "still no fix to port": one exists now — #2370. I had attributed step 34 to the post-alert canary family #2356 scopes out. That was wrong. #2356's own Android run fails at the identical line, The defect is in the scenario: it reveals the canary with one blind Keeping it separate from this relocation rather than porting it in. Once #2370 lands I will merge Generated by Claude Code |
Summary
src/daemon/client/was the daemon's client, not the daemon — no daemon file imports it. Moved tosrc/daemon-client/as git renames, tests carried unchanged, no re-export shim. Zonedaemon-clientand rank 5 are unchanged; the zone now falls out of the folder, retiringtargetDagZone'ssrc/daemon/client/prefix.Two leaves come out of
session-store.ts(464 → 341 lines):session-repair-tombstone.ts, the client's disk reader, andsession-artifact-paths.ts—src/cli.tsreached into the store for one pure path helper, so every CLI eagerly evaluated the store and its subtree.src/cli.ts's eager closure: 379 → 365 modules,session-store.tsno longer in it. No behavior change.Every remaining seam from the relocated client, re-derived from the tree:
daemon/config.ts← lifecycle:25, metadata:6, timeout:8, transport:7daemon/daemon-request.ts← lifecycle:7, progress:7, rpc:9, transport:5, client:5daemon/daemon-process.ts← metadata:4, timeout:5daemon/request-progress-protocol.ts← progress:13daemon/session-repair-tombstone.ts← lifecycle:17remote/daemon-artifacts.ts← rpc:10, client:16remote/remote-request-diagnostics.ts← rpc:11core/replay-divergence.ts← lifecycle:6core/lease-scope.ts← rpc:17#2342's inventory was stale; corrections posted there —
core/replay-divergence.tswas missing from it, andsrc/commands/management/output.tsis not a consumer.Closes #2342.
Validation
Tested at
655faf641withpnpm check:affected --run: format, lint, typecheck, layering (R5, R6,DAEMON_MODULARITY_BASELINE), eager-closure budgets, di-seams, fallow, mcp-metadata, build, package, integration-node (incl.smoke-cli) and macos-coverage all pass.vitest-related: 334/336 files pass. Both failures (app-log-session-resource,durable-capture-resource) assert achmod 0500directory is unwritable and fail because this container runs as uid 0; they are red onmainand touch nothing in this diff.git diff -M90% --stat origin/main...HEAD: 58 files, every move rename-detected. Device lanes not run.🤖 Generated with Claude Code
https://claude.ai/code/session_01CZkJjeEhLmyGpGtcwY8pqc
Generated by Claude Code