Skip to content

Commit 0067e1c

Browse files
committed
refactor(daemon): move interaction and find routes behind facade (#2178)
1 parent b643d0f commit 0067e1c

105 files changed

Lines changed: 895 additions & 722 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.fallowrc.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,31 @@
182182
},
183183
{
184184
"comment": "Daemon route handlers are reached only through the dynamic `import()` table in request-handler-chain.ts, which --production analysis cannot follow to a consumer.",
185-
"file": "src/daemon/handlers/{human-control,lease,session,snapshot,react-native,record-trace,find,interaction}.ts",
185+
"file": "src/daemon/handlers/{human-control,lease,session,snapshot,react-native,record-trace}.ts",
186186
"exports": [
187187
"handleHumanControlCommand",
188188
"handleLeaseCommands",
189189
"handleSessionCommands",
190190
"handleSnapshotCommands",
191191
"handleReactNativeCommands",
192-
"handleRecordTraceCommands",
192+
"handleRecordTraceCommands"
193+
]
194+
},
195+
{
196+
"comment": "The interaction facade exposes #2178's named route inputs and deferred handlers, plus the existing ref mutation response consumed by help conformance. Fallow's production graph cannot follow the request-handler-chain dynamic imports, so this exact list is the facade contract.",
197+
"file": "src/daemon/interaction/index.ts",
198+
"exports": [
199+
"FindRouteInput",
200+
"refMutationAdmissionResponse",
193201
"handleFindCommands",
194202
"handleInteractionCommands"
195203
]
196204
},
205+
{
206+
"comment": "The #2178 route implementations are reached only through the interaction facade's deferred delegates; Fallow's production graph cannot follow those dynamic imports. Keep this exemption limited to the two route entrypoints.",
207+
"file": "src/daemon/interaction/internal/{find,interaction}.ts",
208+
"exports": ["handleFindCommands", "handleInteractionCommands"]
209+
},
197210
{
198211
"comment": "Dedicated CLI command handlers are reached only through the dynamic `import()` table `dedicatedCliCommandHandlerLoaders` in src/cli/commands/router.ts, which --production analysis cannot follow to a consumer. Same shape as the daemon route-handler entry above; that table is what enumerates this list, so add/remove here whenever a loader is added/removed.",
199212
"file": "src/cli/commands/{auth,connection,daemon,device,proxy,replay,screenshot,takeover}.ts",

docs/adr/0012-interactive-replay.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ works" and "healed scripts are always valid":
761761
steps are re-executed during the repair replay; only if recording is armed from the start do they land
762762
in `session.actions` with fresh `target-v1` evidence. Arming late yields a hybrid healed script (an
763763
annotated corrective step glued to a bare, unannotated prefix) that re-diverges on its own next replay
764-
(`src/daemon/handlers/interaction-common.ts:64-65` attaches evidence only when `recordSession` was
764+
(`src/daemon/interaction/internal/interaction-common.ts:64-65` attaches evidence only when `recordSession` was
765765
true when the step ran).
766766
- **R2 — `--from` continuation only; never re-run the full replay on the same session.** After a
767767
divergence at step N and the corrective action, the agent must continue with `replay --from k
@@ -803,7 +803,7 @@ works" and "healed scripts are always valid":
803803
instead of leaving it to agent judgment.
804804
- **R4 — corrective actions must materialize to selector form; the writer fails loudly on a bare `@ref`
805805
cross-session export.** A `press @e12` normally resolves a `selectorChain` at runtime
806-
(`src/daemon/handlers/interaction-touch-targets.ts`), which `buildOptimizedActions`
806+
(`src/daemon/interaction/internal/interaction-touch-targets.ts`), which `buildOptimizedActions`
807807
(`src/daemon/session-script-writer.ts:69-83`) rewrites to a selector line. If no `selectorChain` was
808808
captured, the writer must refuse to emit a bare `@ref` line into a persisted `.ad` — a session-bound
809809
ref will not resolve in a fresh run. It **fails loudly**: an error surfaced to the user with a non-zero

docs/dependency-graph-findings.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ type-only inversions, R7 pins SessionState field ownership, and the shared selec
7070
gates for the next major.
7171
- The **ADR 0017 parameterization boundary is exactly where the ADR says it is**:
7272
`daemon/parameterized-recorded-fill.ts` has precisely two dependents — the response boundary
73-
(`handlers/interaction-common.ts`, step 3) and the recorder boundary
73+
(`daemon/interaction/internal/interaction-common.ts`, step 3) and the recorder boundary
7474
(`session-action-recorder.ts`, step 4). The two-pass structure is two call sites, not a scattered
7575
concern.
7676
- Still outside every rule: **dynamic** import direction (0 inversions today, nothing watching),
@@ -358,7 +358,7 @@ candidate facet, and each facet retired is a branch deleted in every command tha
358358
**This is not a defect list** — importing `kernel/errors.ts` directly is clearer than inheriting it
359359
through a sibling. It earns its keep per file: `daemon/server/daemon-runtime.ts` gets 18 of its 32
360360
imports from one neighbour, `handlers/session-open.ts` 17 of 30, `handlers/session.ts` 17 of 32,
361-
`handlers/find.ts` 16 of 20. A file whose neighbour already provides two-thirds of what it imports
361+
`daemon/interaction/internal/find.ts` 16 of 20. A file whose neighbour already provides two-thirds of what it imports
362362
is usually doing its neighbour's job too — the same orchestrator smell as §5, from the other side.
363363

364364
## 6. R2 is right, and the duplication it forces now has a home

fallow-baselines/health.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,22 +138,22 @@
138138
"count": 1
139139
}
140140
},
141-
"src/daemon/handlers/__tests__/interaction-touch.test.ts": {
141+
"src/daemon/interaction/internal/__tests__/interaction-touch.test.ts": {
142142
"crap_moderate": {
143143
"count": 2
144144
}
145145
},
146-
"src/daemon/handlers/__tests__/interaction-touch-press.test.ts": {
146+
"src/daemon/interaction/internal/__tests__/interaction-touch-press.test.ts": {
147147
"crap_moderate": {
148148
"count": 3
149149
}
150150
},
151-
"src/daemon/handlers/__tests__/interaction-touch-press-admission.test.ts": {
151+
"src/daemon/interaction/internal/__tests__/interaction-touch-press-admission.test.ts": {
152152
"crap_moderate": {
153153
"count": 2
154154
}
155155
},
156-
"src/daemon/handlers/__tests__/interaction-touch-response.test.ts": {
156+
"src/daemon/interaction/internal/__tests__/interaction-touch-response.test.ts": {
157157
"crap_moderate": {
158158
"count": 1
159159
}
@@ -207,15 +207,15 @@
207207
"count": 1
208208
}
209209
},
210-
"src/daemon/handlers/find.ts": {
210+
"src/daemon/interaction/internal/find.ts": {
211211
"complexity_moderate": {
212212
"count": 1
213213
},
214214
"crap_moderate": {
215215
"count": 1
216216
}
217217
},
218-
"src/daemon/handlers/interaction-touch-reference-frame.ts": {
218+
"src/daemon/interaction/internal/interaction-touch-reference-frame.ts": {
219219
"crap_moderate": {
220220
"count": 1
221221
}

packages/contracts/src/interaction-guarantees.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ const PARENT_OWNED_TOUCH_POINT_GAP_ISSUE = 'https://github.com/callstack/agent-d
143143
// (interaction-response-construction-guard.test.ts) keeps new branches on it.
144144
const SHARED_RESPONSE_CONSTRUCTION: GuaranteeEnforcement = {
145145
kind: 'runtime',
146-
via: 'src/daemon/handlers/interaction-touch-response.ts#buildInteractionResponseData',
146+
via: 'src/daemon/interaction/internal/interaction-touch-response.ts#buildInteractionResponseData',
147147
};
148148

149149
// The two runtime tree paths (selector and ref resolution) run the SAME shared
@@ -183,7 +183,7 @@ const RUNTIME_TREE_SHARED_GUARANTEES = {
183183
responseConstruction: SHARED_RESPONSE_CONSTRUCTION,
184184
responseIdentity: {
185185
kind: 'runtime',
186-
via: 'src/daemon/handlers/interaction-touch-targets.ts#interactionResultExtra',
186+
via: 'src/daemon/interaction/internal/interaction-touch-targets.ts#interactionResultExtra',
187187
},
188188
verifyEvidence: {
189189
kind: 'runtime',
@@ -271,7 +271,7 @@ export const INTERACTION_DISPATCH_PATHS: Record<InteractionPathId, InteractionPa
271271
},
272272
responseConstruction: {
273273
kind: 'runtime',
274-
via: 'src/daemon/handlers/interaction-gesture-response.ts#gestureResponseData',
274+
via: 'src/daemon/interaction/internal/interaction-gesture-response.ts#gestureResponseData',
275275
},
276276
responseIdentity: {
277277
kind: 'runtime',
@@ -340,7 +340,7 @@ export const INTERACTION_DISPATCH_PATHS: Record<InteractionPathId, InteractionPa
340340
responseConstruction: SHARED_RESPONSE_CONSTRUCTION,
341341
responseIdentity: {
342342
kind: 'runtime',
343-
via: 'src/daemon/handlers/interaction-touch-targets.ts#interactionResultExtra',
343+
via: 'src/daemon/interaction/internal/interaction-touch-targets.ts#interactionResultExtra',
344344
},
345345
verifyEvidence: {
346346
kind: 'delegated',
@@ -464,7 +464,7 @@ export const INTERACTION_DISPATCH_PATHS: Record<InteractionPathId, InteractionPa
464464
},
465465
resolutionDisclosure: {
466466
kind: 'runtime',
467-
via: 'src/daemon/handlers/interaction-touch-response.ts#buildInteractionResponseData',
467+
via: 'src/daemon/interaction/internal/interaction-touch-response.ts#buildInteractionResponseData',
468468
},
469469
},
470470
},

packages/contracts/src/interaction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export type RecordingTargetOverride = {
9696
* captured itself, handed to the interaction leaf so the leaf does not resolve
9797
* the same `@ref` a second time.
9898
*
99-
* The sole producer is a mutating `find` (`src/daemon/handlers/find.ts`): it
99+
* The sole producer is a mutating `find` (`src/daemon/interaction/internal/find.ts`): it
100100
* captures, matches by locator, promotes to a hittable ancestor, and mints
101101
* `@eN` off the node it chose — then re-enters the interaction leaf. Without
102102
* this channel the leaf repeated an in-memory `@eN` lookup after find had

src/daemon/handlers/__tests__/find-args.test.ts renamed to packages/selectors/src/internal/find-args.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
parseFindArgs,
55
parseFindSelectorExpression,
66
UNSUPPORTED_FIND_ACTION_HINT,
7-
} from '@agent-device/selectors';
7+
} from './find.ts';
88

99
test('parseFindArgs defaults to click with any locator', () => {
1010
const parsed = parseFindArgs(['Login']);

scripts/__tests__/help-conformance-sample-producers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { interactionCliOutputFormatters } from '../../src/commands/interaction/o
1919
import { snapshotCliOutput } from '../../src/commands/capture/output.ts';
2020
import { openCliOutput } from '../../src/commands/management/output.ts';
2121
import { NEVER_SETTLED_HINT } from '../../src/commands/interaction/runtime/settle.ts';
22-
import { buildAmbiguousMatchError } from '../../src/daemon/handlers/find-match-resolution.ts';
22+
import { buildAmbiguousMatchError } from '../../src/daemon/selector-match-errors.ts';
2323
import { refMutationAdmissionResponse } from '../../src/daemon/interaction/index.ts';
2424
import { buildDeviceInUseBySessionError } from '../../src/daemon/session-recovery-hints.ts';
2525
import { buildDeviceClaimConflictError } from '../../src/daemon/device-claim-conflict.ts';

scripts/__tests__/test-file-size-ratchet.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const PINNED_TEST_FILE_LINES: Readonly<Record<string, number>> = Object.freeze({
4747
'packages/platform-apple/src/runner/__tests__/runner-command-retry.test.ts': 1280,
4848
'src/__tests__/cli-client-commands.test.ts': 1304,
4949
'src/__tests__/cli-config.test.ts': 1282,
50-
'src/daemon/handlers/__tests__/find.test.ts': 1199,
50+
'src/daemon/interaction/internal/__tests__/find.test.ts': 1199,
5151
'packages/platform-apple/src/core/__tests__/perf.test.ts': 1222,
5252
'src/mcp/__tests__/command-tools.test.ts': 1216,
5353
'src/daemon/replay/internal/__tests__/session-replay-divergence.test.ts': 1100,

scripts/depgraph/affected.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,16 @@ test('commandsReaching follows the dynamic import a route uses to load its handl
8989
const edges = edgesOf({
9090
'src/daemon/handlers/session.ts':
9191
"import { helper } from '../../utils/helper.ts';\nexport const h = helper;",
92-
'src/daemon/handlers/find.ts': 'export const f = 1;',
92+
'src/daemon/interaction/index.ts': 'export const f = 1;',
9393
'src/utils/helper.ts': 'export const helper = 1;',
9494
'src/daemon/chain.ts': [
9595
"export const routes = { session: () => import('./handlers/session.ts'),",
96-
" find: () => import('./handlers/find.ts') };",
96+
" find: () => import('./interaction/index.ts') };",
9797
].join('\n'),
9898
});
9999
const chains = [
100100
{ command: 'open', route: 'session', entry: 'src/daemon/handlers/session.ts' },
101-
{ command: 'find', route: 'find', entry: 'src/daemon/handlers/find.ts' },
101+
{ command: 'find', route: 'find', entry: 'src/daemon/interaction/index.ts' },
102102
];
103103

104104
assert.deepEqual(
@@ -107,7 +107,9 @@ test('commandsReaching follows the dynamic import a route uses to load its handl
107107
);
108108
// The entry module itself counts as part of its own chain.
109109
assert.deepEqual(
110-
commandsReaching('src/daemon/handlers/find.ts', chains, edges).map((chain) => chain.command),
110+
commandsReaching('src/daemon/interaction/index.ts', chains, edges).map(
111+
(chain) => chain.command,
112+
),
111113
['find'],
112114
);
113115
});

0 commit comments

Comments
 (0)