Skip to content

refactor(maestro): shape the replay backend as a create(host) plugin - #3623

Open
thymikee wants to merge 3 commits into
refactor/maestro-replay-backend-plugin-shapefrom
refactor/maestro-replay-backend-plugin
Open

thymikee wants to merge 3 commits into
refactor/maestro-replay-backend-plugin-shapefrom
refactor/maestro-replay-backend-plugin

Conversation

@thymikee

@thymikee thymikee commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Summary

Second half of the #3377 replay-backend prep. Stacks on #3622 (base is its branch; retarget to main once it merges). Behavior, wire shapes, help text and error wording are unchanged; the backend still resolves once per process (ADR 0015).

  • The Maestro adapter moved from replay-port into packages/maestro/src/replay-backend/ and ships as ReplayBackendPlugin = { declaration, create(host) } (@agent-device/maestro/replay-backend), with an engine-free declaration (.../replay-backend-declaration).
  • ReplayBackendHost (built in replay-backend-host.ts) is the only way the adapter reaches process state or daemon policy: trace append, builtin vars, script-source read, target-device resolution, request signal, and the divergence-failure builder from refactor(replay-port): own the replay backend contract in contracts #3622.
  • The registry loads the plugin through a function-scoped import and calls create(host) once. replay-backend-declarations.ts holds the declaration table, so the registry's eager closure does not grow.
  • help maestro reads its topic from the declaration, so cli-help no longer imports the engine.
  • Failure tests now drive the plugin through getReplayBackend('maestro'); two warnings checks became unit tests.
  • Dropped the unused ./daemon-runtime-port export.
  • Only the two replay-port files above name @agent-device/maestro in production (scripts/fuzz still does).

32 files touched. Sign-off needed: the APPROVED_OVER_CEILING row for replay-maestro-backend.ts names thymikee as owner, so it needs his approval.

Refs #3377.

Validation

Tested SHA: a12c6ab.

  • pnpm check:affected --base <layer-1 branch> --run: all runnable checks passed.
  • pnpm check:quick and focused vitest (replay-port, maestro, daemon sessions, CLI help/MCP, startup closure, closure budgets) passed.
  • Diff against the layer-1 branch: +607/−314. A -M90% stat shows more because several moved files are 80–91% similar after the host rewrite.
  • Coverage, provider integration and maestro-differential are CI-authoritative.

🤖 Generated with Claude Code

View guided diff Turn on auto-fix

@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.

1 issue found across 32 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/__tests__/eager-closure-budgets.ts">

<violation number="1" location="scripts/__tests__/eager-closure-budgets.ts:140">
P3: This allowance row is authored in the same PR that uses it, and the gate only checks that an `owner` string exists. Please record the owner's sign-off before merge, for example in the PR approval, since the diff itself does not show it.</violation>
</file>

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

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

issue: '#3377',
reason:
'The Maestro replay backend plugin IS the engine behind `replay --maestro`; the registry reaches it only through a function-scoped import(), and no startup hub evaluates it (cli-startup-import-closure pins that).',
owner: 'thymikee',

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.

P3: This allowance row is authored in the same PR that uses it, and the gate only checks that an owner string exists. Please record the owner's sign-off before merge, for example in the PR approval, since the diff itself does not show it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At scripts/__tests__/eager-closure-budgets.ts, line 140:

<comment>This allowance row is authored in the same PR that uses it, and the gate only checks that an `owner` string exists. Please record the owner's sign-off before merge, for example in the PR approval, since the diff itself does not show it.</comment>

<file context>
@@ -132,7 +132,14 @@ export const NEW_ENTRY_CEILINGS: Readonly<Record<EntryCategory, number>> = Objec
+    issue: '#3377',
+    reason:
+      'The Maestro replay backend plugin IS the engine behind `replay --maestro`; the registry reaches it only through a function-scoped import(), and no startup hub evaluates it (cli-startup-import-closure pins that).',
+    owner: 'thymikee',
+  },
+});
</file context>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No code change: maintainer approval of this PR is the sign-off for the APPROVED_OVER_CEILING row. Leaving this thread open so thymikee sees it.

@thymikee

Copy link
Copy Markdown
Member Author

The design holds at 5352eef, and one small test fix is needed before merge: the first inline thread below, where a test name promises suggestNodes but the test never calls it. CI is still pending: all 17 lanes were queued or running and none had failed. The lanes this diff touches are Typecheck & Package, Repo Guards and Integration/Smoke, and they decide whether it can merge. I read the diff but did not run the test suites or the closure-budget and layering gates, and I did not measure the eager-closure size of replay-maestro-backend.ts. I also did not check the CLI startup closure numerically after cli-help moved to replay-port/replay-backend-declarations, though reading the imports it should shrink. I checked the moved tests by reading the diff, not with git diff -M90%, because the PR's own rewrite leaves them 57-97% similar.

Not blocking: the host builds resolveTargetDevice (replay-backend-host.ts#L24) with a Maestro rule (appTarget is used only on iOS), and replay-device-selection.ts#L66 applies the same rule when it pre-binds the device. They agree today, so a second backend could make them diverge; a one-line doc on the host member is enough for now, or a declared policy both sites read later. Also, declaredUrl() in maestro-support-matrix.test.ts#L11 reads the URLs from the help body, so the two help assertions at lines 39-40 cannot fail; pinning the literals or exporting the constants would fix that. Take or leave both.

Three inline threads on this PR still apply. The first is the test name that promises suggestNodes. The daemon test at lines 342-475 covers the route end to end, so either assert the suggestion source or drop it from the name. The second is the lost first-event ordering check, where toHaveBeenNthCalledWith(1, ...) restores it. The third is the APPROVED_OVER_CEILING owner row. It needs no code change, because the maintainer's merge approval discharges it.

Before merge, the CI lanes above need to go green and thymikee needs to approve the APPROVED_OVER_CEILING row. After that, retarget the PR to main once #3622 merges. No conflicts.

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.24 MB 5.25 MB +1.1 kB
Package (unpacked) 5.24 MB 5.24 MB +1.1 kB
Package (download) 1.58 MB 1.58 MB +713 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 26.0 ms 25.8 ms -0.1 ms
CLI --help 76.1 ms 75.0 ms -1.1 ms

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://callstack.github.io/agent-device/pr-preview/pr-3623/

Built to branch gh-pages at 2026-10-14 19:08 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@thymikee
thymikee force-pushed the refactor/maestro-replay-backend-plugin branch from 5352eef to be07f5b Compare October 14, 2026 18:39
@thymikee

Copy link
Copy Markdown
Member Author

Both non-blocking notes taken in be07f5b: the host's resolveTargetDevice now documents that it applies the Maestro device-binding rule (the app target steers selection on iOS only), the same rule replay-device-selection.ts applies; and maestro-support-matrix.test.ts pins the ADR and issue URL literals, so the two help assertions can fail. The test-name thread, the first-event ordering thread and the closure-reason claim are fixed too; the owner row is left open for sign-off.

@thymikee
thymikee force-pushed the refactor/maestro-replay-backend-plugin branch from be07f5b to a12c6ab Compare October 14, 2026 18:57
@thymikee

Copy link
Copy Markdown
Member Author

The Maestro replay backend now has the create(host) plugin shape. The code at a12c6ab is clean: I found no new problems since the earlier review (#3623 (comment)), and the findings from 5352eef are fixed. I read the code. I did not run the unit suites, the eager-closure budget gate, the layering gate or the startup-closure test, and I did not measure the eager-closure size of replay-maestro-backend.ts, so the over-ceiling margin is unverified. I would like those results before this counts as proven.

The Smoke Tests lane failed in the iOS runner XCTest RunnerTests.testNonReadCommandStillLaunchesANotRunningSessionApp, because the fixture /tmp/agent-device-inject-tap-recorded-failure-for-testing was missing. This looks unrelated: the diff from e59514f to a12c6ab has no Swift, runner or Apple files, and the PR only changes Maestro replay packaging. I judged this only from that lack of overlap. I did not compare it with runs of the same test on main. Please rerun the lane.

One question on simplicity. Nothing reads ReplayBackendDeclaration.apiVersion, and only provider plugins validate theirs (src/plugins/manifest.ts:63). The registry never reads ReplayBackendPlugin.declaration, because help uses the separate REPLAY_BACKEND_DECLARATIONS table. Should apiVersion and plugin.declaration wait for the installed-plugin loader that would check them? Or should the registry be the one reader: derive the help table from the plugins' declarations and assert that declaration.id and backend.id match the registry key? Either way, the id and the declaration would no longer be registered in parallel with nothing keeping them in step.

Of the open review threads, the cubic-dev-ai P3 on scripts/tests/eager-closure-budgets.ts:136-141 still holds (#3623 (comment)). The owner row is self-authored, so it needs no code change, only the owner's approval. The reason text is now true, because isLazyEngineModule covers the plugin subpath. The other two threads are fixed at this head and can be resolved: the failure-suggestion test now compares against collectMaestroFailureSuggestions and asserts a non-empty result (#3623 (comment)), and the observer test uses toHaveBeenNthCalledWith(1, ...) (#3623 (comment)).

No conflicts are known. To merge, the Smoke Tests lane needs a green rerun, the owner must approve the APPROVED_OVER_CEILING row, and the PR must be retargeted to main after #3622 merges.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant