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:
./store — createAllocationOperationStore, AllocationOperationStore, AllocationOperationRead/Write/Create/Unreadable
./journal — createAllocationOperationJournal, AllocationOperationJournal, and the journal-types.ts types (AllocationBindingHooks, AllocationJournalResult, JournalContext, …)
./decision — decideAllocationAction, AllocationDecisionMode, AllocationBinding, AllocationAction
./record — the record model (AllocationOperationRecord, AllocationTransition, bindingFenceFor, …) plus newAllocationOperation and decodeAllocationOperationRecord
./transitions — applyAllocationTransition, applyAllocatorOutcome
./status — transitionFromAllocatorStatus
./schema — ALLOCATION_OPERATION_SCHEMA_VERSION
./fence — allocationOperationFence
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).
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 fromsrc/daemon, and nothing insrc/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.tsuses only the contracts vocabulary, and only tests reach the implementation.Measured on
mainatf1d4efe059(2026-09-05) with an import-graph walk over every non-test.tsundersrc/.Move it into its own workspace package now, before the managed runtime binding (ADR 0021 §3) becomes its first consumer, so the package
exportsmap 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.tsand__tests__/fixtures.ts.Not moved:
src/__tests__/managed-device-allocator-fake.test.tsandsrc/__tests__/test-utils/managed-device-allocator.fixtures.tsimport 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 oncontracts,kernel,host-kit,capture-kit, a compositetsconfig.jsonwithemitDeclarationOnly, and a per-fileexportsmap (types+default→./src/<file>.ts). Noindex.tsbarrel.Export only the entry points a consumer needs, derived from what the tests and the ADR 0021 flow reach today:
./store—createAllocationOperationStore,AllocationOperationStore,AllocationOperationRead/Write/Create/Unreadable./journal—createAllocationOperationJournal,AllocationOperationJournal, and thejournal-types.tstypes (AllocationBindingHooks,AllocationJournalResult,JournalContext, …)./decision—decideAllocationAction,AllocationDecisionMode,AllocationBinding,AllocationAction./record— the record model (AllocationOperationRecord,AllocationTransition,bindingFenceFor, …) plusnewAllocationOperationanddecodeAllocationOperationRecord./transitions—applyAllocationTransition,applyAllocatorOutcome./status—transitionFromAllocatorStatus./schema—ALLOCATION_OPERATION_SCHEMA_VERSION./fence—allocationOperationFenceEverything 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
package.json: add"@agent-device/managed-allocation": "workspace:*"and append the package to thetsc -blist in thetypecheckscript.tsdown.config.tsalready bundles every@agent-device/*(alwaysBundle); no change expected. Confirm withpnpm buildand the install-size report.pnpm installto update the lockfile..fallowrc.json, production-exports, and any ownership tables only if the gates report the new paths, in one finalchore(gates)commit.docs/adr/README.mdand ADR 0021 wheresrc/daemon/managed-device-allocationis 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 rootagent-devicepackage.Focused validation
pnpm vitest run packages/managed-allocation src/__tests__/managed-device-allocator-fake.test.ts src/managed-device-reachability.test.tspnpm typecheckpnpm check:layering,pnpm check:production-exports,pnpm check:fallowpnpm check:affected --runTitle the PR
refactor(move): …and prove it withgit 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 intopackages/managed-allocation/src/and observe R11 red; (2) import an internal file (for examplestore-lock.ts) through the package specifier and observe TS2307 frompnpm typecheck. Remove both.Shrink target
src/daemon/managed-device-allocation/is deleted (−27 files, −2,973 lines fromsrc/daemon). Production LOC after discounting the physical move does not grow. The only new surface is the packageexportsmap 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).