Skip to content

refactor(daemon): relocate the daemon client out of src/daemon - #2360

Merged
thymikee merged 4 commits into
mainfrom
claude/2342-relocate-daemon-client
Sep 7, 2026
Merged

refactor(daemon): relocate the daemon client out of src/daemon#2360
thymikee merged 4 commits into
mainfrom
claude/2342-relocate-daemon-client

Conversation

@thymikee

@thymikee thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member

Summary

src/daemon/client/ was the daemon's client, not the daemon — no daemon file imports it. Moved to src/daemon-client/ as git renames, tests carried unchanged, no re-export shim. Zone daemon-client and rank 5 are unchanged; the zone now falls out of the folder, retiring targetDagZone's src/daemon/client/ prefix.

Two leaves come out of session-store.ts (464 → 341 lines): session-repair-tombstone.ts, the client's disk reader, and session-artifact-paths.tssrc/cli.ts reached 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.ts no 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:7
  • daemon/daemon-request.ts ← lifecycle:7, progress:7, rpc:9, transport:5, client:5
  • daemon/daemon-process.ts ← metadata:4, timeout:5
  • daemon/request-progress-protocol.ts ← progress:13
  • daemon/session-repair-tombstone.ts ← lifecycle:17
  • remote/daemon-artifacts.ts ← rpc:10, client:16
  • remote/remote-request-diagnostics.ts ← rpc:11
  • core/replay-divergence.ts ← lifecycle:6
  • core/lease-scope.ts ← rpc:17

#2342's inventory was stale; corrections posted there — core/replay-divergence.ts was missing from it, and src/commands/management/output.ts is not a consumer.

Closes #2342.

Validation

Tested at 655faf641 with pnpm 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 a chmod 0500 directory is unwritable and fail because this container runs as uid 0; they are red on main and 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

… 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
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.50 MB 4.50 MB +426 B
Package (unpacked) 4.50 MB 4.50 MB +426 B
Package (download) 1.33 MB 1.33 MB +276 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 20.5 ms 20.9 ms +0.4 ms
CLI --help 59.5 ms 58.3 ms -1.1 ms

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

Android Smoke Tests is red on the base branch, not on this change

Failing check: Android → Smoke Tests (job on 655faf641).

step: press semantic canary
agent-device press id="automation-press" --platform android …
COMMAND_FAILED  Selector did not match: id="automation-press"   (reason: selector_not_found)
scenario: smoke:automation-system, failed-step-34

Why it is not this PR's. The same job fails on main at bd08e6e0f2 — this PR's exact merge-base — in the same smoke:automation-system scenario (run 34028752874, failed-step-28, wait for landscapewait_capture_stalled). Both land in the orientation/post-alert region of the fixture; the step it stops at moves with where the rotation state settles. #2350, already on main, records that this smoke "has failed on the post-alert canary since 2026-09-03" and added the rotation evidence collection to diagnose it — so the failure predates this branch and is tracked.

The diff also cannot reach it. It is a relocation: src/daemon/client/src/daemon-client/ as renames, plus two extractions of unmodified functions out of session-store.ts. It touches no selector, no Android runtime, no interaction path, and no orientation code. The only file it changes under test/integration/android-emulator-e2e/ is one import specifier in live-observability-scenario.ts — and the failing scenario is smoke:automation-system, which does not run through it. A broken specifier would fail at import, not at step 34 of a live run.

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: pnpm check:affected --run at 655faf641 passes format, lint, typecheck, layering (R5/R6/DAEMON_MODULARITY_BASELINE), eager-closure budgets, di-seams, fallow, mcp-metadata, build, package, integration-node and macos-coverage. I will keep watching the PR until it is mergeable.


Generated by Claude Code

@thymikee thymikee left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 under src/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.ts is genuinely a seam the issue omitted, and src/commands/management/output.ts imports 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

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

The Android Smoke failure on 655faf6 is not this PR's, and it is not a flake. I did not re-run it, because re-running would not have told us anything — the cross-PR evidence already settles it.

This PR and #2361 fail identically on the same base (bd08e6e): step 34, press semantic canary, press id="automation-press", selector_not_found, scenario smoke:automation-system. #2360 relocates the daemon client; #2361 extracts the session-event journal into a package. The diffs are disjoint and neither touches selectors, interactions or the Android path, so two disjoint changes failing at the identical step on a shared base means the base is red.

Step 34 runs right after the orientation sequence (landscape → portrait, then scroll down 0.7 to reveal the input canaries). The canary is missing because the device is still effectively in landscape when the press lands — which is the known open failure family #2356's author names under "What this does not explain": "the post-alert canary missing while the device is in landscape although orientation portrait had been confirmed) is still open; #2350 adds the rotation evidence for it."

So no fix exists to port: #2356 addresses the adjacent family (orientation returning before the display rotates) and explicitly excludes this one; #2350 is merged and only adds evidence; #2359 is still open to read the logcat tail.

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

@thymikee

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

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.

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

Re-run spent: the Android canary reproduces deterministically

Correcting my earlier note that the re-run was unspent — I have now spent it (run 34030604291, attempt 2). It failed identically:

attempt 1 attempt 2
step 34, press semantic canary 34, press semantic canary
command press id="automation-press" press id="automation-press"
reason selector_not_found selector_not_found
scenario smoke:automation-system smoke:automation-system

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 main at bd08e6e0f2 and the identical step-34 failure on #2361's disjoint diff, the lane is deterministically red independent of this PR.

main has not moved since (bd08e6e0f), and its own Android run on that commit is still red, so there is no recovered base to merge in and still no fix to port — #2356 explicitly excludes this family, #2350 is evidence only, #2359 is open.

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 main. The other 18 checks are green and everything the diff owns is validated at 655faf641.


Generated by Claude Code

@thymikee
thymikee merged commit 51ed621 into main Sep 7, 2026
18 of 21 checks passed
@thymikee
thymikee deleted the claude/2342-relocate-daemon-client branch September 7, 2026 05:49
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-07 05:52 UTC

thymikee commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

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, live-automation-scenario.ts:130 (job 101478482656), so the orientation fix does not cover it, and #2359 records the device as being in portrait at that failure — which rules out the "still effectively in landscape" reading I gave here.

The defect is in the scenario: it reveals the canary with one blind scroll down 0.7 and presses immediately, but scroll is a gesture whose final offset is decided by app scroll physics — least of all predictable right after the rotation round-trip relaid the list out. The iOS scenario already probes is visible and scrolls again until the element is on screen; Android did not. #2370 moves that policy into the shared live-device layer and applies it to both Android reveals, including the post-alert one.

Keeping it separate from this relocation rather than porting it in. Once #2370 lands I will merge main in here so CI re-runs on a fixed base. Nothing else on this head has changed: 18 of 19 green, no conflict.


Generated by Claude Code

thymikee added a commit that referenced this pull request Sep 7, 2026
* origin/main:
  test(android): reveal smoke canaries by visibility (#2369)
  refactor(daemon): extract the session event journal into a workspace package (#2361)
  refactor(daemon): relocate the daemon client out of src/daemon (#2360)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(daemon): relocate the daemon client out of src/daemon

2 participants