Skip to content

chore(gates): daemon layer manifest + R81 daemon-layer rule (no moves) - #3391

Merged
thymikee merged 3 commits into
mainfrom
refactor/daemon-layer-manifest
Oct 11, 2026
Merged

thymikee merged 3 commits into
mainfrom
refactor/daemon-layer-manifest

Conversation

@thymikee

@thymikee thymikee commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds the daemon layer manifest and the R81 verifier; moves no files, changes no behavior. Every production file under src/daemon/ is claimed exactly once in scripts/layering/daemon-layer-manifest.json — 286 files as of the rebase onto 6e80737 (daemon-core 62 / daemon-resources 26 / daemon-execution 82 / daemon-sessions 72 / daemon-server 44). scripts/layering/daemon-layers.ts rejects upward static value and type-only edges across core < resources < execution < sessions < server, reports dynamic cross-layer edges (4 today, all downward), and fails on omitted, duplicated, untracked, or empty-layer entries. Tests and fixtures carry no layer, matching the other daemon rules. Global spine rank stays 4 for all five. Planted-violation tests cover upward value/type edges, omission, duplicate, unknown path, unknown/missing/empty layer keys.

Deviations from the seed: managed-session-artifact-path.ts and platform-owner-lifecycle.ts → daemon-core (import only node:*/workspace types; path-guard and vocabulary contracts, and root platform-runtime-* already consumes the latter as contract vocabulary); handlers/human-control.ts → daemon-sessions (the seed's daemon-server left the one upward type edge: request-handler-chain.ts types typeof import() of it; its own imports reach only core/resources); daemon-stop.ts stays daemon-server. Post-seed arrivals from main: #3393's three http split files → daemon-server; #3400's dispatch-context.ts → daemon-core, interaction-response-data-transform.ts → daemon-execution. Residue: none.

Validation

Commits f680d70 + 1609f70 + 646d73d (head 646d73d). pnpm install --frozen-lockfile, pnpm build, pnpm format, pnpm check:quick, pnpm check:layering (324 tests + guard, exit 0, zero upward edges at the new head), pnpm check:affected --run (all selected runnable checks pass). Earlier evidence (depgraph:test 43 pass; depgraph summary unchanged vs main) recorded at 0fcfd34. Docs-only reasoning: no runtime paths touched.

@thymikee
thymikee force-pushed the refactor/daemon-layer-manifest branch from 3a79b6f to 0fcfd34 Compare October 10, 2026 17:53
@thymikee thymikee changed the title feat(layering): daemon layer manifest + R81 verifier (no moves) chore(gates): daemon layer manifest + R81 daemon-layer rule (no moves) Oct 10, 2026
@github-actions

github-actions Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.16 MB 5.16 MB 0 B
Package (unpacked) 5.16 MB 5.16 MB 0 B
Package (download) 1.55 MB 1.55 MB +2 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 29.1 ms 29.2 ms +0.1 ms
CLI --help 88.3 ms 89.7 ms +1.4 ms

@thymikee
thymikee marked this pull request as ready for review October 10, 2026 19:03

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 5 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread scripts/layering/daemon-layers.ts Outdated
Comment thread scripts/layering/check.ts
@thymikee

Copy link
Copy Markdown
Member Author

The daemon-layer manifest and the new R81 rule look correct at 0fcfd34, and I found no code problem that should hold the merge. CI is green: 19 checks, none failing. No conflicts. I did not run pnpm check:layering or depgraph locally, so the claim of zero upward edges today rests on the PR body and CI. I also did not audit the layer placement of each of the 281 files, only that the rule enforces whatever partition is declared.

Not blocking: daemonLayerManifestDrift in https://github.com/callstack/agent-device/blob/0fcfd34/scripts/layering/daemon-layers.ts#L86 repeats the undeclared, stale and duplicated logic that rootModuleZoneDrift already has in https://github.com/callstack/agent-device/blob/0fcfd34/scripts/layering/root-module-zones.ts#L137. A shared partitionDrift(declaration, presentFiles, isEligible) would serve both, or you can accept the parallel shape and track it as follow-up. Take it or leave it.

Would the smaller end state be one folder per layer under src/daemon/, with the layer derived from the path the way topFolder derives zones? That would delete the 293-line file list and the drift checks and keep only the rank comparison. I found no existing gate that could carry this today, since R5, R6 and R80 rank by zone and all five layers share spine rank 4. Growth of about 250 lines is under the roughly 700-line threshold, so the manifest is fine as an interim step. The move itself is 281 files and many importers, which fits the "no moves" scope. When it lands, the manifest and its drift check should be deleted in the same change.

On the open threads: the cubic-dev-ai P2 on empty layer arrays still applies (#3391 (comment)). daemon-layers.ts:102 only checks for undefined, so "daemon-execution": [] passes even though the error text says every declared layer must own files. Please also reject length === 0 and add a planted test, or dismiss it with a reason. The cubic-dev-ai P2 on require() coverage (#3391 (comment)) does not apply and can be resolved. It uses the same context.edges as R5, R80 and R6, so require() coverage is a scope choice of the shared scanner, and production src/daemon has no require() or createRequire.

Before merge, answer the empty-layer thread.

Partition every production file under src/daemon/ into five local layers
(core < resources < execution < sessions < server) with an exhaustive
machine-readable manifest, and verify it: reject upward static value and
type-only edges, report dynamic cross-layer edges without rejecting them,
and fail on omitted, duplicated, or untracked manifest entries. No files
move; the global spine rank stays 4 for all five layers.
An empty layer array kept a phantom position in the daemon layer order
after its last file moved; reject it, and isolate the orphaned-file test
from the empty-layer check.
#3393 split http-server.ts into http-authorization/http-rpc-envelope/
http-rpc-methods (daemon-server) and #3400 moved dispatch-context
(daemon-core: pure flag vocabulary read by core's context.ts) and
interaction-response-data-transform (daemon-execution, beside its
touch-response consumer) into the daemon; the exhaustive manifest
follows, verified upward-edge-free at the new head.
@thymikee
thymikee force-pushed the refactor/daemon-layer-manifest branch from 3e87465 to 646d73d Compare October 11, 2026 06:48
@thymikee

Copy link
Copy Markdown
Member Author

Re: the partitionDrift extraction — leaving the parallel shape. The manifest and its drift checks are deleted in the same change that lands one folder per layer under src/daemon/ (folder-derived layer, topFolder-style), so a shared helper now would be built to be removed.

Landed: empty-layer rejection in 1609f70 (planted test fails without it). Rebased onto latest main (6e80737, includes #3393 and #3400); the five new production daemon files joined the manifest in 646d73d — http-authorization/http-rpc-envelope/http-rpc-methods under daemon-server, dispatch-context under daemon-core (pure flag vocabulary), interaction-response-data-transform under daemon-execution — still zero upward static edges, manifest 286 files. Both review threads replied to and resolved.

@thymikee

Copy link
Copy Markdown
Member Author

Both findings from the earlier review (0fcfd34) are now fixed at 646d73d, and I found no new problems in the daemon layer manifest or the R81 rule. All 19 checks pass, and the diff touches only scripts/layering and docs, so no device-facing route is involved. No conflicts. Nothing else stands in the way of merging.

I did not run pnpm check:layering or the daemon-layers tests locally. The zero-upward-edge result at this head rests on CI and the live-graph test at https://github.com/callstack/agent-device/blob/646d73d/scripts/layering/daemon-layers.test.ts#L42. I also did not check whether each of the 286 files sits in the right layer, only that the partition is exhaustive and R81 enforces it.

On the other reviewer's threads: the empty-owner check thread (#3391 (comment)) is fixed, since daemon-layers.ts now rejects owned.length === 0 and the test at daemon-layers.test.ts#L187 covers it, so you can resolve it. The require() coverage thread (#3391 (comment)) does not apply: R81 uses the same context.edges as R5, R6 and R80, and production src/daemon has no require() or createRequire, so you can resolve it too.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 11, 2026
@thymikee
thymikee merged commit 59d00be into main Oct 11, 2026
19 checks passed
@thymikee
thymikee deleted the refactor/daemon-layer-manifest branch October 11, 2026 08:30
@github-actions

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-11 08:30 UTC

thymikee added a commit that referenced this pull request Oct 11, 2026
#3391's manifest was cut before #3403 and #3404 landed, so
src/daemon/platform-services.ts (imported by daemon-core files, so core)
and src/daemon/device/claim-recovery-gateway.ts (imported only from
daemon-server, beside its device-claim siblings in resources) were the
only files R81 found unowned. This PR re-ran check:layering after
rebasing over them and assigns both.

Co-authored-by: Copilot <2235562194+Copilot[bot]@users.noreply.github.com>
thymikee added a commit that referenced this pull request Oct 11, 2026
…fest (#3412)

#3391 added the daemon layer manifest while #3403 and #3404 were in flight,
and each merged green on its own: src/daemon/platform-services.ts and
src/daemon/device/claim-recovery-gateway.ts reached main in no layer, so R81
fails on main and every PR's Repo Guards. platform-services.ts fits only
daemon-core; the claim-recovery port fits any layer and goes in
daemon-resources beside the device claims, matching the assignment #3395
already carries.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
thymikee added a commit that referenced this pull request Oct 11, 2026
…n-contracts (#3395)

* refactor(move): extract the daemon-contracts zone into packages/daemon-contracts

The ten files of the daemon-contracts zone (the nine root modules declared by
ROOT_MODULE_ZONES plus src/daemon-contracts/daemon-diagnostics-scope.ts) move
behind a workspace-package boundary with narrow per-file subpath exports. The
shared daemon/client placement from #2559 and the #3288 zone declaration
become physical: R11 and the package manifest hold the boundary where the
per-file rows held it before. Consumers switch from relative specifiers to
@agent-device/daemon-contracts/<file>; the tests move with their sources.
Behavior is unchanged.

* chore(gates): retarget daemon-contracts path-keyed enforcement at the package

ROOT_MODULE_ZONES sheds its daemon-contracts rows (the package derives the
zone), the R78 guidance names the package as the shared-contract home, the
wire-compat manifest/ledger/mutation keys move with request-progress-protocol,
the mutation-lane exclusion pins the moved test path, and ADR 0033 records the
extraction with its rationale.

* test(daemon-contracts): own the daemon-registration fixture and export it as a subpath

publishDaemonRegistration was duplicated verbatim between
packages/daemon-contracts/src/daemon-registration.fixtures.ts and
src/__tests__/test-utils/device-claim-store.ts. Keep the package as the
single owner: export the fixture via ./daemon-registration-fixtures the
way capture-kit exports ./recording-artifact-fixtures, delete the root
copy, and point the six root tests at the subpath.

Co-authored-by: Copilot <2235562194+Copilot[bot]@users.noreply.github.com>

* docs(layering): name packages/daemon-contracts/ in the root-zone migration note

The example repeated src/command-runtime/ after the daemon-contracts
zone moved out of src/daemon-contracts/; name the package instead.

Co-authored-by: Copilot <2235562194+Copilot[bot]@users.noreply.github.com>

* fix(layering): place the two port files R81 found unlayered

#3391's manifest was cut before #3403 and #3404 landed, so
src/daemon/platform-services.ts (imported by daemon-core files, so core)
and src/daemon/device/claim-recovery-gateway.ts (imported only from
daemon-server, beside its device-claim siblings in resources) were the
only files R81 found unowned. This PR re-ran check:layering after
rebasing over them and assigns both.

Co-authored-by: Copilot <2235562194+Copilot[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot <2235562194+Copilot[bot]@users.noreply.github.com>
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