You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Turn the daemon into a serialized application host rather than the home of replay, Maestro, and
replay-test semantics. Contributors should be able to change one module by reading one façade and
its directory, with authority crossing seams only through narrow capabilities.
This issue is the implementation handoff for #1451. PR #1451 contains the architecture evidence,
ADRs, measurements, and design probes. The decisions below are the result of grilling those sketches
against current call sites and supersede the exact TypeScript sketches in the proposal where they
differ.
Start condition: merge #1451, then branch each implementation PR from the latest main.
Sequencing preconditions: P3 starts only after #1448 merges or its Vitest-runner changes are
otherwise accounted for. P0 remeasures every baseline on that latest main; the proposal R9
baseline is 102, and #1480 does not change the production dependency graph.
Preserve the shipped custom reporter object/factory contract, hook values, timing/order, output
context, error handling, and exit-code behavior exactly.
Do not publish reporter v2, deprecate the current shape, add a compatibility adapter, or write
migration guidance in this initiative. A new public reporter interface requires a demonstrated
external need and a separate compatibility decision.
Preserve ADRs 0001–0017, especially request admission/locking, provider-first translation, replay
resume/repair, ref-frame lifetime, direct Maestro semantics, active publication, and parameterized
recorded inputs.
The one intentional hardening is the unsupported raw-RPC record + saveScript path. Pin
reject-or-ignore behavior at the daemon seam before deleting its surface-dormant writer.
Change internal interfaces atomically. Do not carry compatibility shims for private imports.
State crosses seams as immutable values, authority as capabilities, and both only narrow.
A seam exists when its port has two real adapters.
Calls go down through module façades and back through ports. Do not add an inter-module event bus.
Each logical module has one façade, private implementation under internal/, and tests mirroring
the source topology.
No engine receives DaemonRequest, DaemonInvokeFn, DaemonError, SessionStore, mutable SessionState, provider handles, or concrete platform implementations.
No imports into another module's internal/ tree.
Local filesystems use temporary directories in tests; do not invent a filesystem port only for
mocking.
Locked module decisions
Replay-test
Use a function façade, not a framework class: runReplayTestSuite(request, host): Promise<ReplayTestSuiteResult>.
Replay-test is format-agnostic. It imports neither engine and sees only a minimal manifest plus
neutral attempt values/outcomes.
Replay-test owns discovery policy, filtering, sharding, retries, fail-fast, timeout policy,
attempt identity, result aggregation, reporter events, and the ordering/guarantees of attempt
finalization and cleanup.
The daemon adapter owns how an attempt is executed, finalized, and cleaned up. It maps an
engine-neutral ReplayTestAttemptId to daemon request/session identifiers, binds cancellation,
manages video/artifacts, and routes to the correct engine. The scheduler creates the attempt ID;
the host must not issue identity back to it.
Finalization happens before cleanup in replay-test-owned finally orchestration. Moving
orchestration does not give replay-test access to SessionStore or daemon lifecycle authority.
Keep the host small. Prefer one object created by a daemon factory over a class hierarchy.
Do not add source format, app ID, environment, Maestro tags/steps, digest, includes, config, or
source path unless a demonstrated scheduler or reporter call site requires it.
Discovery and format routing
Use one internal path expansion/traversal/ordering implementation for both .ad and Maestro test
inputs, matching Maestro behavior for explicit files, directories, and globs. Do not maintain a
second .ad ordering implementation.
Discovery is implementation-private. No public discovery interface is better than an unearned
interface.
Route format once, above both engines, with a pure internal resolver: resolveReplayFormat(sourcePath, backend): 'ad' | 'maestro'.
.ad always means native replay, including inside a suite run with --maestro.
.yaml/.yml means Maestro only when the Maestro backend was explicitly requested.
Do not parser-probe, register pluggable formats, fall back from one engine to another, or let
native replay import Maestro. Delete runTypedReplayIfNeeded after cutover.
Reporter preservation
The shipped reporter interface already has the desired seam: reporters receive
suite/test/progress/result values and output facilities only. Those values carry no authority to
inspect or control daemon, session, engine, attempt-finalization, or cleanup state.
Preserve the current module export spellings, object/factory loading, hook names, hook
timing/order, value fields, synchronous live-hook rule, awaited suite completion, error handling,
and exit-code recommendation semantics.
Reuse the existing typed semantic reporter event shape as private implementation. Move generic RequestProgressEvent translation to the CLI/daemon adapter as needed so replay-test has no
request-global import.
Do not add a public v2, deprecate the shipped shape, export new package types solely for this
extraction, or create migration docs. A better public interface can follow when an actual custom
reporter needs capability the current value-only contract cannot provide.
Do not expose engine IR, daemon errors, attempt sessions, runtime callbacks, or cleanup authority
merely because a reporter might find them convenient.
There is no module-public PreparedAdReplay. The module reads the source, expands includes,
computes provenance/digest, validates resume, plans, and executes behind its façade.
Cancellation is run control and belongs to the run request. The bound runtime inherits the same
request cancellation; do not make cancellation a device capability.
The runtime exposes only demonstrated execution/capture capabilities. Progress is a separate,
narrow output port, never a generic event stream.
Expected pass/fail/timeout/cancel/infrastructure states resolve as tagged outcomes. Throw only for
invalid programmatic usage or violated internal invariants.
Failure tags carry explicit neutral fields. Do not pass DaemonError, legacy, metadata, or an
opaque daemon details bag through the engine.
Parsing, include expansion, variables, plan digest, target verification, resume, divergence, and
repair suggestions become private implementation. The canonical .ad codec remains a
repository-private leaf shared only with session script publication.
Maestro
Keep Maestro as a source-preserving typed engine over MaestroRuntimePort.
Do not lower Maestro into .ad, create a shared replay VM, or define a common operation union.
Selectors, control flow, generations, stabilization, divergence, and repair semantics remain
Maestro-owned.
Add one Maestro façade and route non-test consumers through it. Keep engine IR, parser, plan,
ranking, expression state, and compatibility policy private.
Move the five daemon-runtime-* files from src/compat/maestro/ to src/daemon/adapters/maestro/; move only genuinely neutral snapshot helpers to a neutral module.
Internal Maestro observations use daemon-private capture. They must not call the public snapshot operation and must never publish a client ref frame.
Native and Maestro may share daemon-private request-bound command/capture mechanics below their
separate adapters. That shared implementation is not a module-public runtime vocabulary.
Session ownership and ref publication
The daemon remains the composition root and owns request admission, locks, leases, provider
binding, session lifetime, diagnostics, artifacts, response projection, and finalization.
Engines return outcomes. A daemon-private locked coordinator applies replay repair/publication
transitions and maps outcomes to the public wire.
Collapse co-resident replay/record/publication flags into one tagged private aggregate. The
aggregate and both ReplaySessionTransaction and SessionScriptPublication projections land
atomically in P4a; do not keep parallel old/new repair state. Neither projection crosses into an
engine.
The repair variant persists output target plus per-target force authorization and explicit armed, complete, close-succeeded, committed, and aborted status. close-succeeded carries a RepairPlatformCloseReceipt keyed to the effective platform-close
operation.
SessionScriptPublication owns close sequencing through a narrow operation identity plus bound
performer. Do not pass a caller-computed platformCloseSucceeded boolean.
Reserve mutable session records for capability implementations. Ordinary readers use immutable SessionView projections. Update R7 with every moved field cluster.
Keep the three consistency disciplines distinct:
immediate pessimistic transitions for ref/observation lineage;
staged arm/complete/close-succeeded/commit-or-abort protocols for repair/publication, with
operation-keyed receipts retained across retries;
append-only facts for recorded actions and diagnostics.
Do not introduce Redux, end-of-request rollback, a generic session transaction, or a session
event bus.
Internal observation capture updates operational observation state only; it does not issue refs.
Direct replay publishes refs only after the daemon has projected the exact outward response.
The engine may carry opaque capture evidence in a divergence outcome but has no publication or
commit capability. Daemon-private finalization validates that the capture still belongs to the
same locked session/snapshot/generation/runtime revision, applies redaction and response-level
caps, then synchronously activates exactly the exposed refs before returning the response.
A later capture, command, cancellation, session replacement/close, generation change,
finalization, or request end invalidates stale capture evidence.
Refs exposed inline or in a successfully exposed overflow artifact count as published. Failed
artifact creation with no inline refs publishes nothing. An empty set never supersedes the prior
frame.
Replay-test attempts clean up their session before the suite result is returned, so reporters get
values/artifact references but no promise of lasting ref authority.
Platform coupling and workspaces
Preserve provider-first translation and the current Interactor semantics.
Move concrete platform resources out of SessionState behind opaque daemon-owned handles. The
Apple perf edge is the measured load-bearing R9 edge; the Android-only move is ownership hygiene
and must not be credited with SCC reduction.
Introduce request-bound platform binding and focused facets only where current local/provider
implementations demonstrate a real seam. Do not create a universal command dispatcher.
Logical modules under src/ are the target. A private pnpm workspace package is optional and
earned only after zero root back-imports plus a measured need: a second consumer/build,
independent caching/declaration ownership, or repeated enforcement failures.
Preserve one published npm artifact and lazy platform loading if a workspace is eventually
earned.
Execution graph
One worker owns one PR. Rebase each worker from the dependency's merged commit. The default schedule
is serial through P5: avoiding merge repair and duplicate abstractions is more valuable than
speculative parallel throughput.
P0-P5 are the committed product-facing extraction arc. Do not run P2 and P4a concurrently by
default; both alter routing/session neighborhoods and the merge-risk concentration is not worth the
saved wall time. P6 proceeds only after the explicit checkpoint below.
Worker briefs
P0 — Characterize contracts and install migration ratchets
Goal: make accidental behavior drift fail before files move.
Pin current CLI/Node/MCP/RPC shapes, shipped reporter loading/hooks/timing/error/exit behavior,
artifact layout, exit codes, cancellation/timeout/finalize/cleanup order, provider-scope reuse,
and nested same-session execution.
Add format-routing tests for .ad under Maestro mode and YAML without explicit Maestro mode.
Pin shared discovery ordering for explicit files, directories, globs, duplicates, and mixed .ad/YAML inputs against current Maestro-compatible behavior.
Record R7/R9/module import baselines. The proposal measured R9 at 102; remeasure rather than
copying that number after prerequisites merge. Do not scaffold unused façades or speculative
ports.
Done: all characterization tests and gates pass; production behavior is unchanged.
P1 — Correct observation and ref publication
Goal: correct product behavior so internal captures never alter client ref authority and direct
replay publishes only what it actually exposes. Review this as an ADR 0014 behavior change, not as a
file-move refactor.
Add the daemon-private capture path and paired synchronous finalizer.
Switch native verification/divergence and Maestro internal observations away from public snapshot
issuance.
Validate capture lineage and exact wire/artifact ref projection.
Keep transport failure after publication fail-closed; do not roll back to older authority.
Add ref-publication counterfactuals for internal observation, direct divergence at
default/digest/full levels, overflow success/failure, stale capture, cancellation, and empty
publication in the same PR as the correction.
Run a purpose-built live divergence/ref-publication scenario on both iOS and Android following docs/agents/device-verification.md. Provider fixtures do not satisfy this evidence requirement;
attach the commands, target identity, and observed ref-authority result to the PR.
Done: ADR 0014 tests cover stale/superseded capture, later command, cancellation, session close,
generation change, response-level caps, overflow, artifact failure, and empty sets; the live iOS and
Android scenarios both pass. If either live target is unavailable, report residual risk and do not
mark the PR ready.
STOP if: correctness appears to require engine-callable publication, asynchronous work between
ref activation and response return, or rollback of pre-side-effect expiry.
P2 — Correct Maestro ownership and centralize routing/discovery
Goal: Maestro is a deep independent module; daemon-specific code lives in the daemon.
Add the Maestro façade and move the five daemon adapter files plus mirrored tests.
Move only helpers with two real neutral consumers.
Add the pure central format resolver and delete native-to-Maestro routing.
Replace duplicate .ad discovery ordering with the one Maestro-compatible implementation.
Return typed Maestro failure identity from outcomes instead of reconstructing it from an observer.
Gate Maestro-to-daemon imports at zero.
Done: no Maestro engine file imports daemon/platform/provider/native replay; .ad never enters
Maestro; pnpm maestro:conformance remains green.
STOP if: the move requires a shared replay VM, parser probing, engine fallback, or promoting DaemonRequest into contracts.
P3 — Extract replay-test while preserving reporters
Goal: scheduling/reporting becomes a format-neutral deep module with one daemon adapter and no
new public reporter surface.
Move the session-test* scheduler/runtime behavior and mirrored tests into src/replay/test/.
Add the function façade, minimal manifest, neutral outcomes, scheduler-owned attempt IDs, and
format-neutral host.
Keep attempt finalization-before-cleanup orchestration inside replay-test; keep daemon effects in
the adapter.
Preserve the shipped reporter object/factory contract and every timing/error/exit semantic pinned
by P0. Reuse the existing value-only semantic event shape privately and move generic request
progress translation to the adapter.
Do not add reporter v2, a v1 adapter, deprecation, migration docs, or new public type exports.
Remove daemon, platform, request-global, and engine-internal imports from replay-test.
Done: replay-test has zero daemon/platform/provider/engine-internal/request-global imports; one
façade is its only permitted import; all shipped custom reporters and public test behavior still
pass without a compatibility adapter.
STOP if: a scheduler decision requires mutable daemon state, engine-specific manifest fields,
reporter control over attempts/sessions, or a reporter-contract break. A demonstrated need for a new
public reporter interface becomes a separate proposal.
P4-pre — Harden unsupported raw-RPC record + saveScript
Goal: remove the surface-dormant writer path in a small behavior-hardening PR before the
highest-blast-radius state migration.
Pin consistent reject-or-ignore behavior at the daemon request seam for every record action
carrying unsupported saveScript.
Prove the unsupported request cannot arm script publication or write an artifact.
Delete the raw writer invocation only after that seam test is green.
Do not introduce the tagged aggregate or migrate supported publication writers in this PR.
Done: supported CLI/Node/MCP behavior is unchanged; the raw request is pinned closed; the dormant
writer invocation is deleted.
STOP if: closing this path changes a released surface or requires touching the P4a aggregate
migration.
P4a — Encapsulate session script publication
Goal: four supported publication paths consume one capability and one tagged state machine.
Introduce the tagged aggregate and both daemon-private capability projections atomically. Migrate
every old field writer in the same PR; do not leave a shadow repair/publication state.
Persist output target and its per-target force authorization with repair status. Changing the
target without live force clears the previous target's authorization.
Put active publish, ordinary close, repair close, and lifecycle teardown behind SessionScriptPublication.
Give the capability the effective platform-close operation identity and a bound performer. It
derives retargeting without mutation, runs an unmatched close, then persists target plus close-succeeded receipt before atomic publication.
Pin the failure/retry transitions: platform-close failure leaves state unchanged; publication
failure retains target/force plus receipt; the same operation retry skips close dispatch; a
different operation identity dispatches; committed and aborted states are explicit.
Consolidate the corresponding R7 rows.
Done: one aggregate and two projections own the migrated state; one publication capability owns
all supported writes; no engine can call either projection; no old field/writer assembly path
remains.
STOP if: the migration needs parallel repair state, a caller-computed close-success boolean, or
clears a close receipt before the retained session has reached terminal lifecycle cleanup.
P4b — Centralize replay transaction use in the locked coordinator
Goal: all use of the P4a replay projection is serialized behind one daemon-owned coordinator
before engine code moves.
Add a daemon-private coordinator around the current native replay path.
Route arm, corrective watermark, divergence, complete, abort, and tombstone calls through the ReplaySessionTransaction projection created in P4a; remove scattered direct transition calls.
Add immutable SessionView projections for readers touched by this slice.
Preserve admission/lease/lock/provider ordering and map neutral failures to the existing wire.
Keep request-scoped execute/capture mechanics private to daemon adapters.
Done: current replay behavior uses the P4a aggregate only through one locked coordinator;
engines cannot name/relock a session or reacquire a provider; R7 shrinks.
P5 — Extract native .ad replay
Goal: move native program semantics behind inspectAdReplay/runAdReplay.
Move parsing, includes, variables, planning, digest/resume, verification, divergence, and typed
outcomes into src/ad-replay/internal/, with one src/ad-replay/index.ts façade.
Add the narrow runtime plus deterministic in-memory adapter and run one contract suite against
both it and the daemon adapter.
Keep the canonical codec private and shared only with publication.
Cut all production callers over in the same PR, then delete superseded helpers and handler-mock
tests. Do not retain a fallback engine.
Keep all engine files outside the largest R9 SCC.
After building the extracted engine and refreshing daemon/helper state, run pnpm test-app:replay:ios and pnpm test-app:replay:android against live targets following docs/agents/device-verification.md; preserve the artifacts and target details as PR evidence.
Done: native replay has zero daemon/platform/provider/Maestro imports; no deep importer bypasses
the façade; released replay behavior and provenance remain byte/semantics compatible; both live
test-app replay suites pass against the extracted engine. Missing live evidence is residual risk,
not a ready-to-merge state.
P6 decision checkpoint
Goal: decide whether platform modularity is the next best investment rather than inheriting it
from P0-P5 momentum.
After P5, remeasure R9, concrete platform state in SessionState, daemon-to-platform imports,
platform-condition sites, adapter sizes, and contribution-locality pain.
Weigh the measured residual coupling against current product work such as replay composition, the
Maestro importer, and replay-corpus expansion.
Record an explicit go or defer decision in this issue. Deferring P6 is a valid completion of the
checkpoint and proceeds directly to P7.
Done: the decision cites current measurements and product priorities; no P6 worker starts from
the original proposal's momentum alone.
P6a/P6b — Narrow session resources and platform binding (conditional)
Goal: if the checkpoint says go, remove concrete platform state and routine platform branching
from daemon/session code.
P6a: introduce the ordered resource ledger, replace concrete perf/log/recording/helper state with
opaque handles, unify close/expiry/reap/shutdown cleanup, and lower the R9 baseline in the same PR
when the Apple perf edge is removed.
P6b: inject an immutable platform registry, bind one request-scoped device, and move focused
lifecycle/log/recording/perf mechanics behind facets one facet per PR where necessary.
Keep selectors/ref policy, settle/verify, response building, and guarantee classification in
daemon/core.
Measure platform-condition branches and concrete imports after every facet; do not claim success
from moved LOC alone.
Done: no concrete platform resource types remain in SessionState; composition/adapters own
concrete platform imports; R9 reaches the evidence-backed bound without recreating the Apple edge.
STOP if: a proposed facet has only one implementation, hides guarantee-path evidence, bypasses
provider-first integration, or becomes a universal command gateway.
Optional workspace decision
If P6 proceeds, record afterward whether a package trigger exists. If none exists, explicitly
close this checkbox as “logical modules are sufficient.” If P6 is deferred, workspace extraction
is deferred with it. Do not create packages for aesthetics.
P7 — Clean internal architecture documentation
Goal: leave durable decisions, not migration history.
Audit internal docs against code, ADRs, registries, help, and gates.
Update ADRs/CONTEXT.md only with durable “why” and accepted invariants.
Delete superseded proposals, completed migration/status tables, duplicate architecture prose, and
guidance now enforced by code or registries.
Remove the daemon-boundary prototypes, their README, and prototype:* package scripts after the
relevant modules and contract suites have landed.
Keep module-interface-principles.md only if it still carries durable guidance not better owned by CONTEXT.md, AGENTS.md, an ADR, or a gate.
Check all remaining internal links. Do not move historical prose into a new archive folder; git is
the archive.
ADR 0018 is a separate optional follow-up, not Phase 7 and not a prerequisite.
Done: current docs describe the current system; deleted history remains recoverable through git;
no prototype or stale migration entry point remains.
Validation
Every worker runs:
pnpm check:affected --base origin/main --run
Also run the focused gates selected by the touched contract:
replay grammar/provenance: pnpm exec vitest run --project unit-core test/replay-compat and pnpm check:replay-compat;
Maestro: pnpm maestro:conformance;
daemon/session concurrency: the focused unit suites plus test/integration/nightly/concurrency-torture.test.ts;
platform/provider response work: pnpm test:integration:provider and pnpm test:coverage;
P1 behavior correction: purpose-built live iOS and Android divergence/ref-publication evidence;
P5 engine cutover: pnpm test-app:replay:ios and pnpm test-app:replay:android on live targets;
final integration PR: pnpm check.
Use pnpm format, never a path-local formatter. CI remains authoritative.
Success metrics
daemon-server production LOC below 42,000 after extraction, with adapters below 300 LOC each;
compat/engine to daemon imports: 0;
replay-test to daemon/platform/provider/engine-internal imports: 0;
external production imports of daemon/types.ts: 0 by Maestro/replay-test cutover;
engine files in the largest SCC: 0;
R9 does not grow during engine work; if P6 proceeds, it reaches at most 91 after the
load-bearing Apple resource edge is removed;
if P6 proceeds, concrete platform state types in SessionState: 0;
if P6 proceeds, daemon platform-condition sites and concrete imports decrease per extracted
facet;
one script-publication capability owns four supported paths; unsupported raw writer removed;
no public compatibility regression and no duplicate/fallback engine.
Initiative STOP conditions
Stop the current worker and report rather than improvising if:
a released public contract must break or rpcProtocolVersion appears to need a bump;
an engine appears to require daemon/session/provider/concrete-platform authority;
a move introduces a second production path, parser probing, fallback engine, shared replay VM, or
generic event bus;
a test only passes by widening a module façade or adding test-only dependency injection;
the source has drifted enough that the named ownership/call-site evidence no longer holds;
the PR crosses more than one worker brief without an explicit rescope.
Handoff protocol
One worker/branch/PR per brief; conventional commit titles.
Link the PR here and check off only machine-verified criteria.
Report files moved/created/deleted, focused and aggregate gates run, R7/R9/import/LOC deltas, and
any released compatibility behavior intentionally retained.
Delete superseded code in the same PR that completes a cutover.
Do not merge workspace packaging or documentation cleanup before their decision gates.
Outcome
Turn the daemon into a serialized application host rather than the home of replay, Maestro, and
replay-test semantics. Contributors should be able to change one module by reading one façade and
its directory, with authority crossing seams only through narrow capabilities.
This issue is the implementation handoff for #1451. PR #1451 contains the architecture evidence,
ADRs, measurements, and design probes. The decisions below are the result of grilling those sketches
against current call sites and supersede the exact TypeScript sketches in the proposal where they
differ.
Start condition: merge #1451, then branch each implementation PR from the latest
main.Sequencing preconditions: P3 starts only after #1448 merges or its Vitest-runner changes are
otherwise accounted for. P0 remeasures every baseline on that latest
main; the proposal R9baseline is 102, and #1480 does not change the production dependency graph.
Planned against:
ef1a71afe(proposal branch), 2026-07-29.Tracking
record+saveScript.adreplayNon-negotiable compatibility
This is an internal refactor for every supported surface.
artifact layout, exit codes, timeout/cancellation behavior, and
rpcProtocolVersion.context, error handling, and exit-code behavior exactly.
migration guidance in this initiative. A new public reporter interface requires a demonstrated
external need and a separate compatibility decision.
code,message,hint,diagnosticId,logPath, and typedretry/support/divergence data.
resume/repair, ref-frame lifetime, direct Maestro semantics, active publication, and parameterized
recorded inputs.
record+saveScriptpath. Pinreject-or-ignore behavior at the daemon seam before deleting its surface-dormant writer.
Target shape
Rules:
internal/, and tests mirroringthe source topology.
DaemonRequest,DaemonInvokeFn,DaemonError,SessionStore, mutableSessionState, provider handles, or concrete platform implementations.internal/tree.mocking.
Locked module decisions
Replay-test
Use a function façade, not a framework class:
runReplayTestSuite(request, host): Promise<ReplayTestSuiteResult>.Replay-test is format-agnostic. It imports neither engine and sees only a minimal manifest plus
neutral attempt values/outcomes.
Replay-test owns discovery policy, filtering, sharding, retries, fail-fast, timeout policy,
attempt identity, result aggregation, reporter events, and the ordering/guarantees of attempt
finalization and cleanup.
The daemon adapter owns how an attempt is executed, finalized, and cleaned up. It maps an
engine-neutral
ReplayTestAttemptIdto daemon request/session identifiers, binds cancellation,manages video/artifacts, and routes to the correct engine. The scheduler creates the attempt ID;
the host must not issue identity back to it.
Finalization happens before cleanup in replay-test-owned
finallyorchestration. Movingorchestration does not give replay-test access to
SessionStoreor daemon lifecycle authority.Keep the host small. Prefer one object created by a daemon factory over a class hierarchy.
The neutral manifest is intentionally small:
Do not add source format, app ID, environment, Maestro tags/steps, digest, includes, config, or
source path unless a demonstrated scheduler or reporter call site requires it.
Discovery and format routing
.adand Maestro testinputs, matching Maestro behavior for explicit files, directories, and globs. Do not maintain a
second
.adordering implementation.interface.
resolveReplayFormat(sourcePath, backend): 'ad' | 'maestro'..adalways means native replay, including inside a suite run with--maestro..yaml/.ymlmeans Maestro only when the Maestro backend was explicitly requested.native replay import Maestro. Delete
runTypedReplayIfNeededafter cutover.Reporter preservation
suite/test/progress/result values and output facilities only. Those values carry no authority to
inspect or control daemon, session, engine, attempt-finalization, or cleanup state.
timing/order, value fields, synchronous live-hook rule, awaited suite completion, error handling,
and exit-code recommendation semantics.
RequestProgressEventtranslation to the CLI/daemon adapter as needed so replay-test has norequest-global import.
extraction, or create migration docs. A better public interface can follow when an actual custom
reporter needs capability the current value-only contract cannot provide.
merely because a reporter might find them convenient.
Native
.adreplayinspectAdReplay(sourcePath): AdReplayManifestrunAdReplay(request, runtime): Promise<AdReplayOutcome>PreparedAdReplay. The module reads the source, expands includes,computes provenance/digest, validates resume, plans, and executes behind its façade.
request cancellation; do not make cancellation a device capability.
narrow output port, never a generic event stream.
invalid programmatic usage or violated internal invariants.
DaemonError,legacy,metadata, or anopaque daemon
detailsbag through the engine.repair suggestions become private implementation. The canonical
.adcodec remains arepository-private leaf shared only with session script publication.
Maestro
MaestroRuntimePort..ad, create a shared replay VM, or define a common operation union.Selectors, control flow, generations, stabilization, divergence, and repair semantics remain
Maestro-owned.
ranking, expression state, and compatibility policy private.
daemon-runtime-*files fromsrc/compat/maestro/tosrc/daemon/adapters/maestro/; move only genuinely neutral snapshot helpers to a neutral module.snapshotoperation and must never publish a client ref frame.separate adapters. That shared implementation is not a module-public runtime vocabulary.
Session ownership and ref publication
binding, session lifetime, diagnostics, artifacts, response projection, and finalization.
transitions and maps outcomes to the public wire.
aggregate and both
ReplaySessionTransactionandSessionScriptPublicationprojections landatomically in P4a; do not keep parallel old/new repair state. Neither projection crosses into an
engine.
armed,complete,close-succeeded,committed, andabortedstatus.close-succeededcarries aRepairPlatformCloseReceiptkeyed to the effective platform-closeoperation.
SessionScriptPublicationowns close sequencing through a narrow operation identity plus boundperformer. Do not pass a caller-computed
platformCloseSucceededboolean.SessionViewprojections. Update R7 with every moved field cluster.operation-keyed receipts retained across retries;
event bus.
Direct replay publishes refs only after the daemon has projected the exact outward response.
commit capability. Daemon-private finalization validates that the capture still belongs to the
same locked session/snapshot/generation/runtime revision, applies redaction and response-level
caps, then synchronously activates exactly the exposed refs before returning the response.
finalization, or request end invalidates stale capture evidence.
artifact creation with no inline refs publishes nothing. An empty set never supersedes the prior
frame.
values/artifact references but no promise of lasting ref authority.
Platform coupling and workspaces
Interactorsemantics.SessionStatebehind opaque daemon-owned handles. TheApple perf edge is the measured load-bearing R9 edge; the Android-only move is ownership hygiene
and must not be credited with SCC reduction.
implementations demonstrate a real seam. Do not create a universal command dispatcher.
src/are the target. A private pnpm workspace package is optional andearned only after zero root back-imports plus a measured need: a second consumer/build,
independent caching/declaration ownership, or repeated enforcement failures.
earned.
Execution graph
One worker owns one PR. Rebase each worker from the dependency's merged commit. The default schedule
is serial through P5: avoiding merge repair and duplicate abstractions is more valuable than
speculative parallel throughput.
flowchart TD P0["P0 — Characterize contracts + ratchets"] --> P1["P1 — Correct observation/ref publication"] P1 --> P2["P2 — Maestro ownership + central routing/discovery"] P2 --> P3["P3 — Extract replay-test; preserve reporters"] P3 --> P4P["P4-pre — Close raw-RPC writer"] P4P --> P4A["P4a — Session script publication capability"] P4A --> P4B["P4b — Locked replay coordinator"] P4B --> P5["P5 — Extract native .ad module"] P5 --> P6G{"P6 platform-modularity work now?"} P6G -->|"go"| P6A["P6a — Session resource ledger + platform handles"] P6A --> P6B["P6b — Request-bound platform facets"] P6B --> P6C{"Workspace trigger earned?"} P6C -->|"yes"| WP["Optional private workspace extraction"] P6C -->|"no"| Stay["Keep logical modules under src"] P6G -->|"defer"| P7["P7 — Internal docs + prototype cleanup"] WP --> P7 Stay --> P7P0-P5 are the committed product-facing extraction arc. Do not run P2 and P4a concurrently by
default; both alter routing/session neighborhoods and the merge-risk concentration is not worth the
saved wall time. P6 proceeds only after the explicit checkpoint below.
Worker briefs
P0 — Characterize contracts and install migration ratchets
Goal: make accidental behavior drift fail before files move.
artifact layout, exit codes, cancellation/timeout/finalize/cleanup order, provider-scope reuse,
and nested same-session execution.
.adunder Maestro mode and YAML without explicit Maestro mode..ad/YAML inputs against current Maestro-compatible behavior.copying that number after prerequisites merge. Do not scaffold unused façades or speculative
ports.
Done: all characterization tests and gates pass; production behavior is unchanged.
P1 — Correct observation and ref publication
Goal: correct product behavior so internal captures never alter client ref authority and direct
replay publishes only what it actually exposes. Review this as an ADR 0014 behavior change, not as a
file-move refactor.
issuance.
default/digest/full levels, overflow success/failure, stale capture, cancellation, and empty
publication in the same PR as the correction.
docs/agents/device-verification.md. Provider fixtures do not satisfy this evidence requirement;attach the commands, target identity, and observed ref-authority result to the PR.
Done: ADR 0014 tests cover stale/superseded capture, later command, cancellation, session close,
generation change, response-level caps, overflow, artifact failure, and empty sets; the live iOS and
Android scenarios both pass. If either live target is unavailable, report residual risk and do not
mark the PR ready.
STOP if: correctness appears to require engine-callable publication, asynchronous work between
ref activation and response return, or rollback of pre-side-effect expiry.
P2 — Correct Maestro ownership and centralize routing/discovery
Goal: Maestro is a deep independent module; daemon-specific code lives in the daemon.
.addiscovery ordering with the one Maestro-compatible implementation.Done: no Maestro engine file imports daemon/platform/provider/native replay;
.adnever entersMaestro;
pnpm maestro:conformanceremains green.STOP if: the move requires a shared replay VM, parser probing, engine fallback, or promoting
DaemonRequestinto contracts.P3 — Extract replay-test while preserving reporters
Goal: scheduling/reporting becomes a format-neutral deep module with one daemon adapter and no
new public reporter surface.
session-test*scheduler/runtime behavior and mirrored tests intosrc/replay/test/.format-neutral host.
the adapter.
by P0. Reuse the existing value-only semantic event shape privately and move generic request
progress translation to the adapter.
Done: replay-test has zero daemon/platform/provider/engine-internal/request-global imports; one
façade is its only permitted import; all shipped custom reporters and public test behavior still
pass without a compatibility adapter.
STOP if: a scheduler decision requires mutable daemon state, engine-specific manifest fields,
reporter control over attempts/sessions, or a reporter-contract break. A demonstrated need for a new
public reporter interface becomes a separate proposal.
P4-pre — Harden unsupported raw-RPC
record+saveScriptGoal: remove the surface-dormant writer path in a small behavior-hardening PR before the
highest-blast-radius state migration.
recordactioncarrying unsupported
saveScript.Done: supported CLI/Node/MCP behavior is unchanged; the raw request is pinned closed; the dormant
writer invocation is deleted.
STOP if: closing this path changes a released surface or requires touching the P4a aggregate
migration.
P4a — Encapsulate session script publication
Goal: four supported publication paths consume one capability and one tagged state machine.
every old field writer in the same PR; do not leave a shadow repair/publication state.
target without live force clears the previous target's authorization.
SessionScriptPublication.derives retargeting without mutation, runs an unmatched close, then persists target plus
close-succeededreceipt before atomic publication.disjointness, retry behavior, and failure tombstones.
failure retains target/force plus receipt; the same operation retry skips close dispatch; a
different operation identity dispatches; committed and aborted states are explicit.
Done: one aggregate and two projections own the migrated state; one publication capability owns
all supported writes; no engine can call either projection; no old field/writer assembly path
remains.
STOP if: the migration needs parallel repair state, a caller-computed close-success boolean, or
clears a close receipt before the retained session has reached terminal lifecycle cleanup.
P4b — Centralize replay transaction use in the locked coordinator
Goal: all use of the P4a replay projection is serialized behind one daemon-owned coordinator
before engine code moves.
ReplaySessionTransactionprojection created in P4a; remove scattered direct transition calls.SessionViewprojections for readers touched by this slice.Done: current replay behavior uses the P4a aggregate only through one locked coordinator;
engines cannot name/relock a session or reacquire a provider; R7 shrinks.
P5 — Extract native
.adreplayGoal: move native program semantics behind
inspectAdReplay/runAdReplay.outcomes into
src/ad-replay/internal/, with onesrc/ad-replay/index.tsfaçade.both it and the daemon adapter.
tests. Do not retain a fallback engine.
pnpm test-app:replay:iosandpnpm test-app:replay:androidagainst live targets followingdocs/agents/device-verification.md; preserve the artifacts and target details as PR evidence.Done: native replay has zero daemon/platform/provider/Maestro imports; no deep importer bypasses
the façade; released replay behavior and provenance remain byte/semantics compatible; both live
test-app replay suites pass against the extracted engine. Missing live evidence is residual risk,
not a ready-to-merge state.
P6 decision checkpoint
Goal: decide whether platform modularity is the next best investment rather than inheriting it
from P0-P5 momentum.
SessionState, daemon-to-platform imports,platform-condition sites, adapter sizes, and contribution-locality pain.
Maestro importer, and replay-corpus expansion.
checkpoint and proceeds directly to P7.
Done: the decision cites current measurements and product priorities; no P6 worker starts from
the original proposal's momentum alone.
P6a/P6b — Narrow session resources and platform binding (conditional)
Goal: if the checkpoint says go, remove concrete platform state and routine platform branching
from daemon/session code.
opaque handles, unify close/expiry/reap/shutdown cleanup, and lower the R9 baseline in the same PR
when the Apple perf edge is removed.
lifecycle/log/recording/perf mechanics behind facets one facet per PR where necessary.
daemon/core.
from moved LOC alone.
Done: no concrete platform resource types remain in
SessionState; composition/adapters ownconcrete platform imports; R9 reaches the evidence-backed bound without recreating the Apple edge.
STOP if: a proposed facet has only one implementation, hides guarantee-path evidence, bypasses
provider-first integration, or becomes a universal command gateway.
Optional workspace decision
If P6 proceeds, record afterward whether a package trigger exists. If none exists, explicitly
close this checkbox as “logical modules are sufficient.” If P6 is deferred, workspace extraction
is deferred with it. Do not create packages for aesthetics.
P7 — Clean internal architecture documentation
Goal: leave durable decisions, not migration history.
CONTEXT.mdonly with durable “why” and accepted invariants.guidance now enforced by code or registries.
prototype:*package scripts after therelevant modules and contract suites have landed.
module-interface-principles.mdonly if it still carries durable guidance not better owned byCONTEXT.md,AGENTS.md, an ADR, or a gate.the archive.
Done: current docs describe the current system; deleted history remains recoverable through git;
no prototype or stale migration entry point remains.
Validation
Every worker runs:
Also run the focused gates selected by the touched contract:
pnpm exec vitest run --project unit-core test/replay-compatandpnpm check:replay-compat;pnpm maestro:conformance;test/integration/nightly/concurrency-torture.test.ts;pnpm test:integration:providerandpnpm test:coverage;pnpm test-app:replay:iosandpnpm test-app:replay:androidon live targets;pnpm check.Use
pnpm format, never a path-local formatter. CI remains authoritative.Success metrics
internal/: 0;SessionStatewriters outside capabilities: 0; R7 rows shrink per migrated cluster;daemon/types.ts: 0 by Maestro/replay-test cutover;load-bearing Apple resource edge is removed;
SessionState: 0;facet;
Initiative STOP conditions
Stop the current worker and report rather than improvising if:
rpcProtocolVersionappears to need a bump;generic event bus;
Handoff protocol
any released compatibility behavior intentionally retained.
References
docs/module-interface-principles.mddocs/adr/README.md, especially ADRs 0001, 0003, 0006–0008, and 0010–0017docs/agents/testing.mddocs/dependency-graph-findings.md