Skip to content

refactor(daemon): move managed device allocation into its own workspace package #2316

Description

@thymikee

Blocked by: none. Implements the packaging choice ADR 0021 §8 leaves open; related to #2284, #2285, #2278.

Purpose

src/daemon/managed-device-allocation/ (27 production files, 2,973 lines) imports nothing from src/daemon, and nothing in src/ imports it. Its only dependencies are workspace packages: @agent-device/contracts (managed-device-allocation ×11, platform-runtime ×4, client ×3), @agent-device/kernel/errors, @agent-device/host-kit/file + /process, and @agent-device/capture-kit. It has no production consumer today: src/managed-device-reachability.ts uses only the contracts vocabulary, and only tests reach the implementation.

Measured on main at f1d4efe059 (2026-09-05) with an import-graph walk over every non-test .ts under src/.

Move it into its own workspace package now, before the managed runtime binding (ADR 0021 §3) becomes its first consumer, so the package exports map defines the API instead of a directory convention. Ownership does not change: the daemon still composes the store, journal, and decision policy (ADR 0021 §3, "allocation-operation journal" stays a daemon authority). Only the module boundary moves.

Scope — exact tracked files

Production (all of src/daemon/managed-device-allocation/):
decision.ts, fence.ts, journal.ts, journal-action-binding.ts, journal-action-context.ts, journal-action-persistence.ts, journal-action-runtime.ts, journal-lane.ts, journal-projection.ts, journal-results.ts, journal-types.ts, record.ts, record-codec.ts, record-codec-state.ts, record-factory.ts, record-json.ts, record-validation.ts, schema.ts, status.ts, store.ts, store-creation.ts, store-filesystem.ts, store-lock.ts, store-results.ts, transition-outcome.ts, transition-support.ts, transitions.ts.

Tests (move with the package):
src/daemon/managed-device-allocation/__tests__/{decision,journal,record,store}.test.ts and __tests__/fixtures.ts.

Not moved: src/__tests__/managed-device-allocator-fake.test.ts and src/__tests__/test-utils/managed-device-allocator.fixtures.ts import only @agent-device/contracts/managed-device-allocation; leave them where they are.

Destination

New private workspace package packages/managed-allocation (@agent-device/managed-allocation). The name is the one open decision; pick it before the move PR and do not rename afterwards.

Scaffold exactly like packages/provision-kit: private: true, type: module, workspace:* dependencies on contracts, kernel, host-kit, capture-kit, a composite tsconfig.json with emitDeclarationOnly, and a per-file exports map (types + default./src/<file>.ts). No index.ts barrel.

Export only the entry points a consumer needs, derived from what the tests and the ADR 0021 flow reach today:

  • ./storecreateAllocationOperationStore, AllocationOperationStore, AllocationOperationRead/Write/Create/Unreadable
  • ./journalcreateAllocationOperationJournal, AllocationOperationJournal, and the journal-types.ts types (AllocationBindingHooks, AllocationJournalResult, JournalContext, …)
  • ./decisiondecideAllocationAction, AllocationDecisionMode, AllocationBinding, AllocationAction
  • ./record — the record model (AllocationOperationRecord, AllocationTransition, bindingFenceFor, …) plus newAllocationOperation and decodeAllocationOperationRecord
  • ./transitionsapplyAllocationTransition, applyAllocatorOutcome
  • ./statustransitionFromAllocatorStatus
  • ./schemaALLOCATION_OPERATION_SCHEMA_VERSION
  • ./fenceallocationOperationFence

Everything else (journal-lane, journal-action-*, record-codec-state, record-validation, record-json, store-filesystem, store-lock, store-results, store-creation, transition-support, journal-projection, journal-results) stays internal. If the package tests need an internal symbol, they import it relatively from inside the package; do not export it.

Wiring

  • Root package.json: add "@agent-device/managed-allocation": "workspace:*" and append the package to the tsc -b list in the typecheck script.
  • tsdown.config.ts already bundles every @agent-device/* (alwaysBundle); no change expected. Confirm with pnpm build and the install-size report.
  • pnpm install to update the lockfile.
  • R11 package-boundaries discovers the manifest from tracked sources; no rule edit. Update .fallowrc.json, production-exports, and any ownership tables only if the gates report the new paths, in one final chore(gates) commit.
  • Update the path in docs/adr/README.md and ADR 0021 where src/daemon/managed-device-allocation is named.

Behavior invariants

Byte-identical logic: record codec, schema version, store locking and filesystem layout, journal lanes and persistence, transition and decision outcomes, refusal reasons and error hints. No wrapper, shim, or compatibility re-export left in src/daemon. No new public export from the root agent-device package.

Focused validation

  • pnpm vitest run packages/managed-allocation src/__tests__/managed-device-allocator-fake.test.ts src/managed-device-reachability.test.ts
  • pnpm typecheck
  • pnpm check:layering, pnpm check:production-exports, pnpm check:fallow
  • pnpm check:affected --run

Title the PR refactor(move): … and prove it with git diff -M90% --stat origin/main...HEAD; move PRs are exempt from the 1,000-line diff budget only with that proof.

Planted-red proof

No new structural rule. Before the green run: (1) add a relative import from a src/ file into packages/managed-allocation/src/ and observe R11 red; (2) import an internal file (for example store-lock.ts) through the package specifier and observe TS2307 from pnpm typecheck. Remove both.

Shrink target

src/daemon/managed-device-allocation/ is deleted (−27 files, −2,973 lines from src/daemon). Production LOC after discounting the physical move does not grow. The only new surface is the package exports map above.

Non-goals

Wiring the first consumer (managed runtime binding), the Simlock client, any ADR 0021 semantic change, and the durable-capture move (separate issue).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions