Skip to content

refactor(daemon): make the layer folders the declaration (PR 10) - #3520

Merged
thymikee merged 14 commits into
refactor/daemon-packagefrom
refactor/daemon-layer-folders
Oct 14, 2026
Merged

thymikee merged 14 commits into
refactor/daemon-packagefrom
refactor/daemon-layer-folders

Conversation

@thymikee

@thymikee thymikee commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

What

Every daemon file in packages/daemon/src moves under a layer folder — {core,resources,execution,sessions,server}/ — keeping its sub-structure inside the layer (e.g. device/device-claim-admission.ts -> resources/device/device-claim-admission.ts). Tests and test support follow their source module one-to-one. R81 stops reading the manifest and derives the layer from the first path segment under the daemon root; scripts/layering/daemon-layer-manifest.json and its drift check are deleted in the same PR. src/daemon.ts and the dist/src/internal/daemon.js output are unchanged.

Re-run on 11b a4c6208c2 (refactor/daemon-package, #3546) per coordinator: reset onto the tip, re-ran the move codemod with daemon root packages/daemon/src, no hand-resolved moved files. The base's narrowed facade is honored: every export KEY is stable — no importer outside the package is touched; the codemod rewrites only TARGETS: 107 named entries follow their file, and the four ./testing/<dir>/* pattern targets follow the folder their consumed members move into (handlers/__tests__ -> __tests__/support/handlers, interaction/internal/__tests__ -> execution/interaction/internal/__tests__, the two session-* ones -> their sessions/ homes). The one fixture a pattern consumes across layer folders (gesture-runtime-bindings.fixtures) follows its pattern's members so each pattern keeps a single target; all 117 keys resolve at head. R81 derives its root from DAEMON_SOURCE_ROOT and refuses an empty input set.

Mapping

671 tracked files under the package src root, 671 mapped, 10 identity (cross-layer __tests__/support/ leaves), 661 moved: head holds core 117, resources 49, execution 139, sessions 229, server 108, root __tests__/ 29.

  • Test leaves move beside their source module's new path. Owner layer picked deterministically: exact basename -> dash-prefix (ties by vi.mock targets, then physical colocation) -> single-layer direct-import closure -> highest-rank direct layer. Two tests with zero daemon imports land in core/__tests__/.
  • Cross-layer shared test support stays in the top-level __tests__/support/. R81's scan treats test-tree files as layerless; planting shared support into core/ would claim a layer it does not own.
  • Sweep rule: only paths of files that exist at head are retargeted, so historical text keeps its original spelling. The kit's lookahead now blocks path-continuation and extension-like suffixes but not prose periods, so sentence-final comment literals ("…conflict.ts. This path…") are swept on future re-runs; the two this run skipped are fixed in a follow-up commit. Covers md files and repo-path string literals, including sentence-final-period comment paths.

Line counts

  • Codemod-only move commit: 764 files (+2,707/-2,707; includes the repository-wide format sweep the rewritten lines require). 661 git mv, 2,909 relative-spec rewrites in 587 files (from, import(), require(), vi.mock), 535 text/path rewrites, 111 exports TARGET rewrites (107 named + 4 pattern folders). Zero specifier rewrites outside the package (keys stable). A separate re-flow commit (115 files, +585/-148) settles the lines the rewrites pushed past the print width.
  • Hand-written commits (10): R81 folder derivation + manifest deletion (303-line manifest JSON gone), fallow/audit-scope retargets, source-reading probe hops, self-review settle, teardown closure probe, docs(adr) owner pointers, R75 head-coordinates measure + live-root fixtures, the R75 fixture-repo test for the owner's finding, and the sweep-lookahead comment-literal fix from the owner's 14:21 note.

Evidence

  • Gates measured at this head: check:quick (lint + typecheck), check:layering (R81 over the moved graph), check:di-seams, check:gate-manifest (57 checks / 27 lanes), check:production-exports, check:agent-guidance (docs/agents 39,963 <= 40,000 bytes), eager-closure-budgets + test-file-size ratchet (1,034 cases), depgraph suites, and the four mutation suites including the alias test (workspace-aliases) — all green. Heavy gates under the host lock: check:affected --run, check:fallow, check:package — green.
  • Parity: dist/src/internal/daemon.js is byte-identical (6c32b7d508…) to a rebuild of the clean base at a4c6208c2. Test-name parity: extracted test(...)/it(...) names under packages/daemon/src are identical base vs head (2,072 / 2,072).
  • renamedSince at this head pairs every base handler file: all 38 production src/daemon/handlers/*.ts pair, session-store.ts pairs to core/session-store.ts (one base test file split in two and stays unpaired; no production file is unpaired).
  • R81 bite proofs (temporary probes, not committed): upward core -> sessions static import = 1 violation; production file at the daemon root = 1 violation; empty input set = 1 violation. All three caught; the registered test file pins all three permanently. R75 root bite: breaking either live handler root turns the overlay suite red (verified, not committed).
  • No tracked file names a moved-away daemon path at head; every non-glob .fallowrc.json file entry names a tracked path.

Owner review items applied

  • R75 overlay (refactor(daemon): make the layer folders the declaration (PR 10) #3520 review at cbb6bdf): the merge-base test no longer reads the real repo history. It builds a fixture repo (flat handlers/ base, git mv into layer folders as head, padded to stay rename-pairable), injects that base through a new baseRef override on mergeBaseRatchets, and asserts the rule: every base handler member survives canonicalization and arrives under a live handler root; the non-handler importer stays out of scope. No fetched origin/main, nothing to rot after merge.
  • .device-evidence/CHECKLIST.md press/no-capture pointer names the test's live home at this base; docs/adr/0023 row 23 names packages/daemon/src/resources/device/device-claim-admission.ts; ADR 0022's R75 sentence names the live {sessions,execution}/handlers/** roots. Other src/daemon/ citations in ADRs name files the tree no longer carries and stay historical.

@thymikee

Copy link
Copy Markdown
Member Author

The PR is ready at 21794fe. The code looks right to me.

Not blocking: the new .fallowrc.json entry exempts every export of src/__tests__/test-utils/replay-script-source.ts, but maestroScriptSourceBundleFor, noMaestroIncludeSources and withClientReplayScriptSources have no importers (callers use the copy under src/daemon/__tests__/support/), so deleting them and dropping the file from the glob would be cleaner. The path-literal rewrite also skipped docs/adr, scripts/depgraph/README.md, .device-evidence/CHECKLIST.md and src/commands/interaction/runtime/offscreen-double-check.test.ts:14, which still name files that no longer exist. R81's caller in scripts/layering/check.ts:588 filters on the literal 'src/daemon/' instead of DAEMON_ROOT, so the planned retarget to packages/daemon/src would hand it an empty list and pass without checking anything. You can take or leave these.

I did not run the layering, fallow or unit suites or pnpm build, and I did not reproduce the R81 bite proofs. The 309 node:test cases, the 889-file affected run and the dist/src/internal/daemon.js byte parity are unverified on my side.

No checks have reported on this head, so nothing has run against the gates this PR changes. The PR has merge conflicts with main, and the head does not descend from the base tip, so the diff also shows unrelated main commits such as the limrun #3504 changes. Before merge, rebase or retarget the base so CI runs the layering, fallow and unit gates, then remove the dead replay-script-source exports instead of suppressing them.

@thymikee
thymikee force-pushed the refactor/daemon-layer-folders branch from 21794fe to ab48059 Compare October 12, 2026 20:33
@thymikee
thymikee changed the base branch from refactor/daemon-test-data-fakes to refactor/daemon-package October 12, 2026 20:34
@thymikee

Copy link
Copy Markdown
Member Author

Base retargeted to refactor/daemon-package (#3546) per coordinator: reset onto the 11b tip and re-ran the move codemod with daemon root packages/daemon/src, then re-applied the hand-written commits with the review findings (R81 caller filter + empty-set guard, stale doc/test literals incl. codemod coverage for md files, dropped test-utils fallow exemption) folded in. Head: ab48059.

@thymikee

Copy link
Copy Markdown
Member Author

Final head 7937155ef (+1 retarget squashed into the probes commit: .device-evidence/CHECKLIST.md named a replay-disclosure test renamed before this stack — pointed at the live find-target-activation-disclosure.test.ts). Evidence in the body was measured at the previous head; the delta is comment-only in a checklist doc.

@thymikee
thymikee force-pushed the refactor/daemon-layer-folders branch from ab48059 to 7937155 Compare October 12, 2026 20:36
@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.20 MB 5.20 MB +47 B
Package (unpacked) 5.20 MB 5.20 MB +47 B
Package (download) 1.56 MB 1.56 MB -60 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 31.0 ms 34.2 ms +3.2 ms
CLI --help 85.9 ms 93.2 ms +7.2 ms

@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at 7937155, and the earlier conflict from 21794fe is fixed. Not blocking, and you can take or leave these: the retargeted line at .device-evidence/CHECKLIST.md:104 should point at execution/interaction/internal/tests/interaction-capture-disclosure.test.ts, where the press/no-capture test lives, and row 23 of docs/adr/0023-end-state-hop-trace.md:92 should name packages/daemon/src/resources/device/device-claim-admission.ts, since the old path was already stale at base.

The code looks right to me, but I did not build or run the tests, so the byte-identical daemon bundle and the unit-core and test-name parity claims are unverified. Required evidence is in place, and there are no conflicts.

The CI failures look unrelated to this PR. The Repo Guards R11 failure lists the same 63 escape specifiers in 39 files at base 87969a2 and at head (by my own scan of relative specifiers, which can miss multi-line imports), so this PR moves files but adds no escapes. The Mutants jobs fail on code this diff does not touch. The Ownership budget fails because docs/agents is already 40002 bytes at base, over the 40000 cap, and this PR adds 15 bytes through two path retargets. I saw no Typecheck & Package log, so I cannot confirm the PR body's claim that its failure is inherited from 11b.

Before merge, the base branch (refactor/daemon-package) needs to bring docs/agents back under 40000 bytes with about 17 bytes of headroom for this PR, and clear its R11 and typecheck failures.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 12, 2026
@thymikee
thymikee force-pushed the refactor/daemon-layer-folders branch from 7937155 to 5e88063 Compare October 13, 2026 02:08
@thymikee

Copy link
Copy Markdown
Member Author

Re-ran on the current 11b tip (reset to refactor/daemon-package head, codemod re-applied with root packages/daemon/src; no hand-resolved moves). Head 5e880636a. Review pointers applied:

  • CHECKLIST pointer: the press/consumed-no-capture test is src/__tests__/daemon-composition/interaction/interaction-capture-disclosure.test.ts at this base — 11b moved it out of the package, so execution/interaction/internal/__tests__/interaction-capture-disclosure.test.ts (your suggested path, correct on the old base) does not exist here; it was split at 11b and the press-side assertion lives in the root-composition file. The checklist names the live path.
  • ADR 0023 row 23 now names packages/daemon/src/resources/device/device-claim-admission.ts. Remaining src/daemon/ citations in the ADRs name files deleted before this stack and keep their historical spelling (same rule as 11b: only paths that exist at head get retargeted; sweep covers md).
  • R81: root derived from DAEMON_SOURCE_ROOT (11b's constant), no literal root filters in the rule or check.ts caller; empty input set returns a violation. Bite proofs re-run against this head: upward import / production file at daemon root / empty set, 1 violation each; all three are permanent tests in daemon-layers.test.ts (9/9 pass).
  • Manifest JSON + drift check deleted; exports map (16 production keys) moved with its files, ./testing/* wildcard follows automatically; no .fallowrc.json glob for the retired replay-script-source.ts (file is gone in this lineage).
  • Evidence: dist/src/internal/daemon.js byte-identical to the base build; per-file test names identical across all 656 moved files; check:quick, check:layering, check:di-seams, check:gate-manifest, check:production-exports, check:agent-guidance (docs/agents 39,963 ≤ 40,000 — 11b's trim left headroom, no extra trim needed), eager-closure-budgets (883) and test-file-size ratchet green; check:fallow/check:package/check:affected --run green under the host lock. Counts in the body are measured at this head.

@thymikee thymikee removed the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 13, 2026
@thymikee
thymikee force-pushed the refactor/daemon-layer-folders branch from 5e88063 to 75d7641 Compare October 13, 2026 03:41
@thymikee

Copy link
Copy Markdown
Member Author

Re-run on 11b 88f6e4234 per coordinator: reset onto the tip, codemod re-applied with root packages/daemon/src, hand commits replayed (teardown-closure probe merged with 11b's DAEMON_SOURCE_ROOT derivation; the oxlint override stays — its target file exists in this lineage, unlike the old base). Head 75d764166. Body counts and evidence are measured at this head: codemod 939 files / 656 renames; hand-written 6 commits, 25 files. Green at this head: check:quick, check:layering, check:di-seams, check:gate-manifest, check:production-exports, check:agent-guidance, eager-closure + test-file-size (886), depgraph (34), and under the host lock check:affected --run, check:fallow, check:package. Bundle byte-identical, 656/656 test-name parity, all three R81 bite proofs caught. Fresh-context self-review applied: depgraph in-memory fixture graphs retargeted by hand to stay self-consistent (this was the earlier affected failure), dead core/handlers/__tests__ scan root dropped, ADR 0022 handler glob retargeted to the live {sessions,execution}/handlers/**; R10 retired-path regexes intentionally keep their stale spelling (retargeting them would make them reject live files). One known base-ahead trigger: #3544 review fixes will move 11b again — I will re-run the codemod on the next tip.

@thymikee

Copy link
Copy Markdown
Member Author

Re-run on 11b base b03b59e2f: codemod-only move (941 files, 655 renames) plus the six hand commits replayed with zero conflicts; head 43a8978ef. Green at this head: check:quick, layering, di-seams, gate-manifest, production-exports, agent-guidance (39,963 ≤ 40,000), eager-closure + size ratchet (886), depgraph (34), and under the host lock check:affected --run, check:fallow, check:package. Bundle byte-identical vs the clean-base rebuild, 655/655 test-name parity, all three R81 bite proofs caught.

@thymikee
thymikee added this pull request to stack #3564 October 13, 2026 06:02
@thymikee

Copy link
Copy Markdown
Member Author

The code is in good shape at 43a8978. The earlier clean review at 7937155 still holds, and the layer folders now declare the layers. The 41 checks at this head show none failing. The PR conflicts with its base, refactor/daemon-package. I did not build or run any gate, so the byte-identical bundle, the 655/655 test-name parity, the R81 bite proofs and the green gate list are your claims, and I did not read the codemod commit 49e3d0f in full.

The base branch refactor/daemon-package was rewritten to 28949e4, and it adds three production daemon files outside the layer folders: handlers/session-device-status-response.ts, settle-observation-capture.ts and device/device-claim-conflict.ts. Please re-stack onto 28949e4 by re-running the layer codemod, so these files land in layer folders before R81 runs again. The conflicts in .device-evidence/CHECKLIST.md, .fallowrc.json, AGENTS.md, docs/adr and device-claim-conflict.ts also need to be resolved in that re-stack. Then please share a green R81 run on the new head.

Not blocking: the R81 success message in report() at scripts/layering/check.ts:440 hardcodes 'core < resources < execution < sessions < server' (the header comment at check.ts:57-61 does the same). You could print DAEMON_LAYER_ORDER.join(' < ') instead, and re-wrap the broken 'and no / static edge' line in the header. Take it or leave it.

One question on simplicity. The layer folder is now the declaration inside the package, and daemon-layers.ts owns it well. But the 16 named facade subpaths now include the folder, for example @agent-device/daemon/core/daemon-request, so about 33 importer sites outside the package encode an internal layer choice. Moving one file between layers, which R81 now invites, would then rewrite importers outside the package. Could the named exports keys stay layer-free (./daemon-request -> ./src/core/daemon-request.ts), with only the ./testing/* pattern following the layout, as ADR 0033's facade-not-reach policy suggests?

@thymikee
thymikee force-pushed the refactor/daemon-layer-folders branch from 43a8978 to a9cdd53 Compare October 13, 2026 07:35
@thymikee

Copy link
Copy Markdown
Member Author

Re-run on 11b base 28949e4a8 (stack on current main, #3550 fallow pruning absorbed): codemod-only move (946 files, 659 renames) + six hand commits, head a9cdd5369. Green at this head: check:quick, layering, di-seams, gate-manifest, production-exports, agent-guidance (39,963 ≤ 40,000), eager-closure + size ratchet (886), depgraph (34), and via the host lock check:affected --run, check:fallow, check:package. Bundle byte-identical vs the clean-base rebuild, 659/659 test-name parity, R81 bites 3/3.

@thymikee

Copy link
Copy Markdown
Member Author

Thanks for the update. The earlier clean review was on 7937155. At a9cdd53 I found no correctness problems, and CI is green with 41 checks and none failing. I did not run the gates myself. The bundle byte-identity and the 659/659 test-name parity are your reports. For the move commit I checked the non-path hunks with a grep filter and spot-read them, not hunk by hunk across all 1028 files. This PR is still a draft, and it can only merge after the 11b base (refactor/daemon-package) lands.

One design question remains open: https://github.com/callstack/agent-device/blob/a9cdd53/scripts/layering/session-authority-overlay.ts#L20 keeps the old packages/daemon/src/handlers/ and packages/daemon/src/session-store.ts paths plus a handlerKey fold. The comment says the merge-base tree still uses those paths. It does not. The merge-base uses src/daemon/..., and mergeBaseRatchets already maps every base path to its head path through renamedSince (all 38 base handler files pair, and session-store.ts pairs at R100). So the old spellings and the fold match nothing in either tree. The overlay test also still uses only the old spelling, so nothing exercises the live sessions/handlers/ and execution/handlers/ roots. The same applies to the dead handlers|execution/handlers alternatives in isDaemonRecordOwner in record-runtime-mechanics-policy.ts.

Could session-authority-overlay.ts rely on the rename mapping that mergeBaseRatchets already applies, and keep only the live roots with its tests moved to those paths?

thymikee added a commit that referenced this pull request Oct 14, 2026
layerOfEdgeEnd only wrapped daemonLayerOf — a leftover from the manifest
version of R81 — so rankedPair, its only caller, names the layer owner
itself (#3520 review). Behavior unchanged; the layering suite and R81's
reported edges are identical.
@thymikee
thymikee force-pushed the refactor/daemon-layer-folders branch from 05166de to 887c75d Compare October 14, 2026 06:17
@thymikee

Copy link
Copy Markdown
Member Author

Rebased onto #3546's new head 518e0cb28, which picked up #3517's two new commits (a shared inventory host stub, and an R11 gate keeping the caller-side replay collector out of daemon code). Nothing under packages/daemon/src changed below this PR, so this was a plain rebase --onto with no layer-move regeneration: 14 commits, no conflicts, content unchanged. Verified at 887c75d86: check:quick, check:layering (324 tests), and check:affected --run (all runnable checks passed).

Codemod-only: 662 renames of packages/daemon/src files under the five
layer folders (core, resources, execution, sessions, server), with
every relative specifier, path mention, and package-manifest entry
retargeted by the same pass. The map is the layer-manifest claim plus
deterministic owner-layer rules for tests and support files; two
support-only tests fall to core, and the one fixture a testing pattern
consumes across layer folders follows its pattern's members so
./testing/interaction/internal/__tests__/* keeps a single target. The
former transport folder does not fold onto its layer's name: the map
places it at server/http/, so the package never carries a server/server
path. The narrowed facade keeps every export KEY and rewrites only
TARGETS: 107 named entries follow their file, and the four
./testing/<dir>/* pattern folders follow the folder their consumed
members move into. Importers outside the package are untouched.

Generated with assistance.
The row cited src/daemon/device-claim-admission.ts, stale since the
package extraction; it now names the file's home in the resources
layer. The other src/daemon/ citations in the ADRs name files the
tree no longer carries at all and keep their historical spelling.

(cherry picked from commit 563b382)
…tale

The probe walked src/daemon/session-teardown.ts, a path the package
extraction had already orphaned; it now resolves through
packages/daemon/src/sessions/, where the move put the teardown owner.
The non-vacuity pins (closure size, materialized-path-registry
membership) carry over unchanged.

(cherry picked from commit 7937155)
(cherry picked from commit 5d943ca)

# Conflicts:
#	src/__tests__/daemon-composition/session-teardown-import-closure.test.ts
The five layer folders now carry the claim the manifest carried: the
first path segment under the daemon root is the file's layer, an
unknown segment or a production file at the zone root fails, and the
edge rule over core < resources < execution < sessions < server is
unchanged. The manifest JSON and its drift check retire with this
commit — the folder is the declaration, so ownership moves with the
file and cannot decay into fiction separately from the tree. The rule
derives its root from the shared DAEMON_SOURCE_ROOT constant and
refuses an empty input set, so a stale scan filter cannot pass it
silently.
…audit scope

The route-handler and interaction-facade fallow entries follow their
files into the sessions/execution layers. The atomic-publish
ownership probe reads its judged sources through new URL(...)
relative to the test, so its specifiers follow the move by hand.
The daemon-shaped test-support file the move brought into the audit
diff joins the per-file test-support exemption: every consumer is
test-tree code --production analysis cannot see.

(cherry picked from commit 687b53d)
(cherry picked from commit 977fbd7)
Ownership probes and eager-closure walks that read daemon modules by
path follow them into their layer folders: the replay ownership scan's
synthetic probe locations move one folder deeper, and the daemon-
shaped test-support fallow entry settles on the one file the move
actually brought into the audit diff.

(cherry picked from commit 41fa23b,
minus the lease.test.ts plugin-manifest hop: the 11b lineage removed
that probe's file body, so nothing follows the move there)
(cherry picked from commit 665850c)
Dead oxlint override for a file deleted before this stack, the
vacuous device-lane fixture pin (now asserts the fixture exists, at
its path in this tree), the R81 helpers that never needed to leave
their module, and the closure-probe hops that follow the interaction
routes and replay probes into their layer folders.

(cherry picked from commit baebba2;
the ime-capture fixture pin tracks its 11b home under
packages/platform-android/src/fixtures/)
(cherry picked from commit 5e88063)
The review caught that mergeBaseRatchets already canonicalizes every
merge-base path onto its head path through renamedSince, so the
overlay's pre-fold handlers/ root, the pre-fold SessionStore spelling,
and the handlerKey fold matched nothing in either measured tree, and
the record-owner regex carried the same dead alternatives. R75 now
keeps only the two live handler roots and the single store target; its
tests moved onto those paths, so the live roots are what the suite
exercises.
The first pass dropped the dead spellings but still hardcoded the two
handler roots as literals and left the rest of scripts/layering planting
synthetic daemon fixtures under the pre-fold handlers/ root. R75 now
derives both roots and the SessionStore target from DAEMON_SOURCE_ROOT,
gains an end-to-end classification case for each live handler folder
(the pre-fold spelling stays measurable but out of the ratcheted
subset, and each root is bite-proofed against a rename), and gains a
case that measures the real merge-base through mergeBaseRatchets and
asserts its handler-owned set arrives in head coordinates and the base
really held src/daemon/handlers/. Nine synthetic fixtures moved onto
sessions/handlers/. The R10 retired-handler path lists keep their
historical spelling on purpose: they name deleted files, and retargeting
them would reject legitimate new files in the live folders.
The merge-base overlay test read the real merge-base and asserted the
base tree still held src/daemon/handlers/. That pins one repo state —
this stack's — and starts failing on main and every later PR the moment
the stack lands, because check:layering runs these tests. The test now
builds a fixture repo whose base commit holds the pre-rename flat
handlers/ layout (padded so the specifier-rewriting move stays
rename-pairable) and whose head is the git mv into layer folders, then
injects that base through mergeBaseRatchets' new baseRef override and
asserts the rule: every base handler member survives canonicalization,
arrives under a live handler root, and the non-handler importer stays
out of the scoped set. No fetched origin/main, no repo history.
The move sweep's path lookahead refused any match followed by a period,
so comment literals ending a sentence ("...device-claim-conflict.ts.
This path...") kept their pre-fold spelling. The owner's review caught
the help-conformance sample; the same class left one cross-reference in
the offscreen double-check test. Both now name the live layer paths.
The codemod kit's lookahead is fixed alongside (#3520 re-run kit, not a
repo file), so the next re-run sweeps these forms automatically.
The codemod lengthened retargeted specifiers and path literals past the
print width; oxfmt settles them. Formatting only, no semantics.

Generated with assistance.
layerOfEdgeEnd only wrapped daemonLayerOf — a leftover from the manifest
version of R81 — so rankedPair, its only caller, names the layer owner
itself (#3520 review). Behavior unchanged; the layering suite and R81's
reported edges are identical.
The split of the old handlers/ tree into sessions/handlers/ and
execution/handlers/ was pasted as a pair of path roots in four places:
three arrays in architecture-ownership.ts and HANDLER_ROOTS in
session-authority-overlay.ts. The rule is the folder shape — any
<layer>/handlers/ folder under a declared layer — so daemon-layers.ts,
which already owns the layer folders, exports isDaemonHandlerFile and
the policies gained forbiddenTargetShapes beside the path roots. A
handler folder planted under another layer now joins R75's ratchet and
the facade policies with no rule edit; pinned by planted cases at both
gates (the pre-fold two-path rule fails exactly those pins).
@thymikee
thymikee force-pushed the refactor/daemon-layer-folders branch from 887c75d to deb67e0 Compare October 14, 2026 06:21
@thymikee

Copy link
Copy Markdown
Member Author

Rebased onto #3546's cd7fb345f. 14 commits, no conflicts, content unchanged; nothing under packages/daemon/src changed below. check:quick and check:layering (324 tests) pass. New head deb67e037.

@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at deb67e0. The fixes from the earlier review at 128c504 are in, and the required evidence is now in place.

Not blocking: LogicalModulePolicy.forbiddenTargetRoots is still a required field in scripts/layering/architecture-ownership.ts, and daemon-session-lifecycle keeps forbiddenTargetRoots: [] while the daemon-session-observability entry no longer has it. Behavior is correct, because forbiddenTargetMatches tolerates undefined and scripts/layering is outside the tsconfig.json include list, so satisfies never checks it. You could make the field optional or add the empty list to the observability entry so both entries match, or leave it as is.

I did not run check:layering, the unit lane or the bite probes myself. The 324-test layering pass and the byte-identical daemon.js bundle are your measurements. I also did not re-diff the sorted package.json export keys. I relied on the delta showing only target-line edits and on your empty sorted-key diff.

CI is still pending, and only the Mutants (selectors) shards are running. None has failed. This PR does not touch packages/selectors, and its only mutation-config change retargets the daemon ref-frame paths in stryker.config.json and scripts/mutation/modules.ts, which sit outside the selectors mutate set. So I expect those shards to pass. Before merge, they must finish green and base #3546 must land.

@thymikee
thymikee merged commit c137b5b into main Oct 14, 2026
41 checks passed
@thymikee
thymikee deleted the refactor/daemon-layer-folders branch October 14, 2026 07:54
thymikee added a commit that referenced this pull request Oct 14, 2026
* origin/main: (83 commits)
  feat(ios): interpret React Native accessibility value semantics (#3589)
  fix(android): reinstall and reselect the test IME helper after it disappears (#3606)
  feat(snapshot): carry provider keyboard observations through acquisition (#3593)
  chore(web): bump managed agent-browser backend to 0.39.0 (#3591)
  fix(fold): report a dispatched pose as unverified when devicectl has no hinge-angle stream (#3587)
  feat(android): expose system-bar membership on snapshot nodes (#3585)
  fix(android): align ADB and Appium field values (#3584)
  test(closure): read committed JSON modules on the merge-base side (#3602)
  fix(ci): preserve manual Android suite timing (#3554)
  refactor(daemon): make the layer folders the declaration (PR 10) (#3520)
  refactor(move): extract the daemon server into @agent-device/daemon (11b) (#3546)
  refactor(daemon): package-local runtime fakes for the remaining daemon ports [11a-4] (#3544)
  refactor(daemon): cut daemon test edges into root data fixtures and fakes [11a-3] (#3517)
  refactor(11a-2): package-local fakes at the daemon ports; root-own command-surface composition tests (#3519)
  test(replay): verify Settings queries and bound scrolling (#3560)
  feat(snapshot): measure Android Appium viewport (#3586)
  fix(ios): verify a fill whose unidentified field moved while it kept focus (#3596)
  refactor(coverage): one fallow config with per-function CRAP ceilings (#3588)
  test: bound CLI promotion cases and align provider budget (#3590)
  fix(metro): report what the dev-server stop proved instead of assuming success (#3575)
  ...
thymikee added a commit that referenced this pull request Oct 14, 2026
* origin/main: (83 commits)
  feat(ios): interpret React Native accessibility value semantics (#3589)
  fix(android): reinstall and reselect the test IME helper after it disappears (#3606)
  feat(snapshot): carry provider keyboard observations through acquisition (#3593)
  chore(web): bump managed agent-browser backend to 0.39.0 (#3591)
  fix(fold): report a dispatched pose as unverified when devicectl has no hinge-angle stream (#3587)
  feat(android): expose system-bar membership on snapshot nodes (#3585)
  fix(android): align ADB and Appium field values (#3584)
  test(closure): read committed JSON modules on the merge-base side (#3602)
  fix(ci): preserve manual Android suite timing (#3554)
  refactor(daemon): make the layer folders the declaration (PR 10) (#3520)
  refactor(move): extract the daemon server into @agent-device/daemon (11b) (#3546)
  refactor(daemon): package-local runtime fakes for the remaining daemon ports [11a-4] (#3544)
  refactor(daemon): cut daemon test edges into root data fixtures and fakes [11a-3] (#3517)
  refactor(11a-2): package-local fakes at the daemon ports; root-own command-surface composition tests (#3519)
  test(replay): verify Settings queries and bound scrolling (#3560)
  feat(snapshot): measure Android Appium viewport (#3586)
  fix(ios): verify a fill whose unidentified field moved while it kept focus (#3596)
  refactor(coverage): one fallow config with per-function CRAP ceilings (#3588)
  test: bound CLI promotion cases and align provider budget (#3590)
  fix(metro): report what the dev-server stop proved instead of assuming success (#3575)
  ...

# Conflicts:
#	packages/daemon/src/server/http/daemon-runtime-lease-expiry.test.ts
#	packages/daemon/src/server/http/daemon-runtime.ts
#	packages/daemon/src/sessions/__tests__/lease-lifecycle.test.ts
#	packages/daemon/src/sessions/lease-lifecycle.ts
thymikee added a commit that referenced this pull request Oct 14, 2026
* origin/main: (79 commits)
  feat(ios): interpret React Native accessibility value semantics (#3589)
  fix(android): reinstall and reselect the test IME helper after it disappears (#3606)
  feat(snapshot): carry provider keyboard observations through acquisition (#3593)
  chore(web): bump managed agent-browser backend to 0.39.0 (#3591)
  fix(fold): report a dispatched pose as unverified when devicectl has no hinge-angle stream (#3587)
  feat(android): expose system-bar membership on snapshot nodes (#3585)
  fix(android): align ADB and Appium field values (#3584)
  test(closure): read committed JSON modules on the merge-base side (#3602)
  fix(ci): preserve manual Android suite timing (#3554)
  refactor(daemon): make the layer folders the declaration (PR 10) (#3520)
  refactor(move): extract the daemon server into @agent-device/daemon (11b) (#3546)
  refactor(daemon): package-local runtime fakes for the remaining daemon ports [11a-4] (#3544)
  refactor(daemon): cut daemon test edges into root data fixtures and fakes [11a-3] (#3517)
  refactor(11a-2): package-local fakes at the daemon ports; root-own command-surface composition tests (#3519)
  test(replay): verify Settings queries and bound scrolling (#3560)
  feat(snapshot): measure Android Appium viewport (#3586)
  fix(ios): verify a fill whose unidentified field moved while it kept focus (#3596)
  refactor(coverage): one fallow config with per-function CRAP ceilings (#3588)
  test: bound CLI promotion cases and align provider budget (#3590)
  fix(metro): report what the dev-server stop proved instead of assuming success (#3575)
  ...
thymikee added a commit that referenced this pull request Oct 14, 2026
* origin/main: (79 commits)
  feat(ios): interpret React Native accessibility value semantics (#3589)
  fix(android): reinstall and reselect the test IME helper after it disappears (#3606)
  feat(snapshot): carry provider keyboard observations through acquisition (#3593)
  chore(web): bump managed agent-browser backend to 0.39.0 (#3591)
  fix(fold): report a dispatched pose as unverified when devicectl has no hinge-angle stream (#3587)
  feat(android): expose system-bar membership on snapshot nodes (#3585)
  fix(android): align ADB and Appium field values (#3584)
  test(closure): read committed JSON modules on the merge-base side (#3602)
  fix(ci): preserve manual Android suite timing (#3554)
  refactor(daemon): make the layer folders the declaration (PR 10) (#3520)
  refactor(move): extract the daemon server into @agent-device/daemon (11b) (#3546)
  refactor(daemon): package-local runtime fakes for the remaining daemon ports [11a-4] (#3544)
  refactor(daemon): cut daemon test edges into root data fixtures and fakes [11a-3] (#3517)
  refactor(11a-2): package-local fakes at the daemon ports; root-own command-surface composition tests (#3519)
  test(replay): verify Settings queries and bound scrolling (#3560)
  feat(snapshot): measure Android Appium viewport (#3586)
  fix(ios): verify a fill whose unidentified field moved while it kept focus (#3596)
  refactor(coverage): one fallow config with per-function CRAP ceilings (#3588)
  test: bound CLI promotion cases and align provider budget (#3590)
  fix(metro): report what the dev-server stop proved instead of assuming success (#3575)
  ...
thymikee added a commit that referenced this pull request Oct 14, 2026
* origin/main: (24 commits)
  feat(ios): interpret React Native accessibility value semantics (#3589)
  fix(android): reinstall and reselect the test IME helper after it disappears (#3606)
  feat(snapshot): carry provider keyboard observations through acquisition (#3593)
  chore(web): bump managed agent-browser backend to 0.39.0 (#3591)
  fix(fold): report a dispatched pose as unverified when devicectl has no hinge-angle stream (#3587)
  feat(android): expose system-bar membership on snapshot nodes (#3585)
  fix(android): align ADB and Appium field values (#3584)
  test(closure): read committed JSON modules on the merge-base side (#3602)
  fix(ci): preserve manual Android suite timing (#3554)
  refactor(daemon): make the layer folders the declaration (PR 10) (#3520)
  refactor(move): extract the daemon server into @agent-device/daemon (11b) (#3546)
  refactor(daemon): package-local runtime fakes for the remaining daemon ports [11a-4] (#3544)
  refactor(daemon): cut daemon test edges into root data fixtures and fakes [11a-3] (#3517)
  refactor(11a-2): package-local fakes at the daemon ports; root-own command-surface composition tests (#3519)
  test(replay): verify Settings queries and bound scrolling (#3560)
  feat(snapshot): measure Android Appium viewport (#3586)
  fix(ios): verify a fill whose unidentified field moved while it kept focus (#3596)
  refactor(coverage): one fallow config with per-function CRAP ceilings (#3588)
  test: bound CLI promotion cases and align provider budget (#3590)
  fix(metro): report what the dev-server stop proved instead of assuming success (#3575)
  ...

# Conflicts:
#	src/remote/daemon-artifacts.ts
thymikee added a commit that referenced this pull request Oct 14, 2026
* origin/main: (83 commits)
  feat(ios): interpret React Native accessibility value semantics (#3589)
  fix(android): reinstall and reselect the test IME helper after it disappears (#3606)
  feat(snapshot): carry provider keyboard observations through acquisition (#3593)
  chore(web): bump managed agent-browser backend to 0.39.0 (#3591)
  fix(fold): report a dispatched pose as unverified when devicectl has no hinge-angle stream (#3587)
  feat(android): expose system-bar membership on snapshot nodes (#3585)
  fix(android): align ADB and Appium field values (#3584)
  test(closure): read committed JSON modules on the merge-base side (#3602)
  fix(ci): preserve manual Android suite timing (#3554)
  refactor(daemon): make the layer folders the declaration (PR 10) (#3520)
  refactor(move): extract the daemon server into @agent-device/daemon (11b) (#3546)
  refactor(daemon): package-local runtime fakes for the remaining daemon ports [11a-4] (#3544)
  refactor(daemon): cut daemon test edges into root data fixtures and fakes [11a-3] (#3517)
  refactor(11a-2): package-local fakes at the daemon ports; root-own command-surface composition tests (#3519)
  test(replay): verify Settings queries and bound scrolling (#3560)
  feat(snapshot): measure Android Appium viewport (#3586)
  fix(ios): verify a fill whose unidentified field moved while it kept focus (#3596)
  refactor(coverage): one fallow config with per-function CRAP ceilings (#3588)
  test: bound CLI promotion cases and align provider budget (#3590)
  fix(metro): report what the dev-server stop proved instead of assuming success (#3575)
  ...
thymikee added a commit that referenced this pull request Oct 14, 2026
* origin/main: (83 commits)
  feat(ios): interpret React Native accessibility value semantics (#3589)
  fix(android): reinstall and reselect the test IME helper after it disappears (#3606)
  feat(snapshot): carry provider keyboard observations through acquisition (#3593)
  chore(web): bump managed agent-browser backend to 0.39.0 (#3591)
  fix(fold): report a dispatched pose as unverified when devicectl has no hinge-angle stream (#3587)
  feat(android): expose system-bar membership on snapshot nodes (#3585)
  fix(android): align ADB and Appium field values (#3584)
  test(closure): read committed JSON modules on the merge-base side (#3602)
  fix(ci): preserve manual Android suite timing (#3554)
  refactor(daemon): make the layer folders the declaration (PR 10) (#3520)
  refactor(move): extract the daemon server into @agent-device/daemon (11b) (#3546)
  refactor(daemon): package-local runtime fakes for the remaining daemon ports [11a-4] (#3544)
  refactor(daemon): cut daemon test edges into root data fixtures and fakes [11a-3] (#3517)
  refactor(11a-2): package-local fakes at the daemon ports; root-own command-surface composition tests (#3519)
  test(replay): verify Settings queries and bound scrolling (#3560)
  feat(snapshot): measure Android Appium viewport (#3586)
  fix(ios): verify a fill whose unidentified field moved while it kept focus (#3596)
  refactor(coverage): one fallow config with per-function CRAP ceilings (#3588)
  test: bound CLI promotion cases and align provider budget (#3590)
  fix(metro): report what the dev-server stop proved instead of assuming success (#3575)
  ...
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.

1 participant