@@ -262,6 +262,54 @@ function toDaemonEvidence(evidence: EngineTargetBindingEvidence): TargetBindingF
262262 } ;
263263}
264264
265+ /** The engine's pre-action identity guard, read off `AdReplayStepRuntime` itself (see `EngineTargetBindingEvidence` above for why `Parameters<...>` rather than a named façade export). */
266+ type ReplayDispatchGuard = Parameters < AdReplayStepRuntime [ 'dispatchStep' ] > [ 3 ] ;
267+
268+ /** `dispatchStep`'s result shape, read off `AdReplayStepRuntime` itself for the same reason. */
269+ type ReplayDispatchOutcome = Awaited < ReturnType < AdReplayStepRuntime [ 'dispatchStep' ] > > ;
270+
271+ /** Threads a pre-action identity guard into the request's `internal` block the interaction layer reads for its own resolution — a no-op when no guard applies. */
272+ function applyReplayDispatchGuard (
273+ replayReq : DaemonRequest ,
274+ guard : ReplayDispatchGuard ,
275+ ) : DaemonRequest {
276+ const guardInternal =
277+ guard ?. kind === 'target'
278+ ? { replayTargetGuard : guard . guard . expected }
279+ : guard ?. kind === 'landmark'
280+ ? { replayLandmarkGuard : guard . landmark }
281+ : undefined ;
282+ return guardInternal
283+ ? { ...replayReq , internal : { ...replayReq . internal , ...guardInternal } }
284+ : replayReq ;
285+ }
286+
287+ /** Classifies a failed dispatch response into an ordinary failure or one of the two post-resolution identity-refusal markers (`guard-mismatch`/`landmark-mismatch`) `dispatchStep` detects. */
288+ function classifyReplayDispatchFailure (
289+ response : Extract < DaemonResponse , { ok : false } > ,
290+ guard : ReplayDispatchGuard ,
291+ entries : readonly string [ ] ,
292+ ) : ReplayDispatchOutcome {
293+ const plainFailure = toAdReplayStepFailure ( response , entries ) ;
294+ if ( guard ?. kind === 'target' && isReplayTargetGuardMismatchResponse ( response ) ) {
295+ return {
296+ status : 'guard-mismatch' ,
297+ details : response . error . details ,
298+ plainFailure,
299+ artifactPaths : entries ,
300+ } ;
301+ }
302+ if ( guard ?. kind === 'landmark' && isWaitLandmarkMismatchResponse ( response ) ) {
303+ return {
304+ status : 'landmark-mismatch' ,
305+ details : response . error . details ,
306+ plainFailure,
307+ artifactPaths : entries ,
308+ } ;
309+ }
310+ return { status : 'failed' , failure : plainFailure } ;
311+ }
312+
265313/**
266314 * #1478 P5 stage C2b (narrowed further by the #1555 review's neutral-outcomes
267315 * pass, then again by the R3 pass that moved verify-then-dispatch into the
@@ -399,17 +447,8 @@ function createAdReplayStepRuntime(params: {
399447 // ever reached the target-binding wire builders (`build*Failure` below).
400448 async dispatchStep ( action , index , _stepArtifactPaths , guard ) {
401449 const sourceLine = ctx . actionLines [ index ] ?? 1 ;
402- const guardInternal =
403- guard ?. kind === 'target'
404- ? { replayTargetGuard : guard . guard . expected }
405- : guard ?. kind === 'landmark'
406- ? { replayLandmarkGuard : guard . landmark }
407- : undefined ;
408- const guardedReq = guardInternal
409- ? { ...ctx . replayReq , internal : { ...ctx . replayReq . internal , ...guardInternal } }
410- : ctx . replayReq ;
411450 const response = await invokeReplayAction ( {
412- req : guardedReq ,
451+ req : applyReplayDispatchGuard ( ctx . replayReq , guard ) ,
413452 sessionName : ctx . sessionName ,
414453 action,
415454 scope : ctx . scope ,
@@ -424,24 +463,7 @@ function createAdReplayStepRuntime(params: {
424463 const entries = collectReplayActionArtifactPaths ( response ) ;
425464 entries . forEach ( ( entry ) => artifactPaths . add ( entry ) ) ;
426465 if ( response . ok ) return { status : 'ok' , artifactPaths : entries } ;
427- const plainFailure = toAdReplayStepFailure ( response , entries ) ;
428- if ( guard ?. kind === 'target' && isReplayTargetGuardMismatchResponse ( response ) ) {
429- return {
430- status : 'guard-mismatch' ,
431- details : response . error . details ,
432- plainFailure,
433- artifactPaths : entries ,
434- } ;
435- }
436- if ( guard ?. kind === 'landmark' && isWaitLandmarkMismatchResponse ( response ) ) {
437- return {
438- status : 'landmark-mismatch' ,
439- details : response . error . details ,
440- plainFailure,
441- artifactPaths : entries ,
442- } ;
443- }
444- return { status : 'failed' , failure : plainFailure } ;
466+ return classifyReplayDispatchFailure ( response , guard , entries ) ;
445467 } ,
446468
447469 async buildRecordedUnverifiableFailure ( action , index , stepArtifactPaths ) {
@@ -657,48 +679,19 @@ function prepareReplayPlan(params: {
657679 coordinator : ReplayCoordinator ;
658680} ) : { ok : true ; value : PreparedReplayPlan } | { ok : false ; response : DaemonResponse } {
659681 const { req, sessionName, sessionStore, tracePath, resolved, coordinator } = params ;
660- // #1555 P1: the authoritative rejection for an unrecognized --replay-backend
661- // value. Extraction moved `.ad` inspection to `inspectAdReplay`, which never
662- // receives flags — restoring the check here (the one caller of
663- // `inspectAdReplay` that reaches this point with a non-Maestro request)
664- // matches `src/compat/replay-input.ts`'s `parseReplayInput` exactly, byte
665- // for byte, before any plan/session work begins. `replayBackend: 'maestro'`
666- // still passes here because `runReplayScriptFile` has already routed a real
667- // Maestro-format request to `runTypedMaestroReplayFile` above; only a
668- // stray/unknown value reaches this branch.
669- if ( req . flags ?. replayBackend && req . flags . replayBackend !== 'maestro' ) {
670- return {
671- ok : false ,
672- response : errorResponse (
673- 'INVALID_ARGS' ,
674- `Unsupported replay backend "${ req . flags . replayBackend } ".` ,
675- ) ,
676- } ;
677- }
678- // #1555 P1 (digest/resume behind runAdReplay): `digestFlags` is the raw
679- // request-level platform/target override — `inspectAdReplay` applies the
680- // SAME precedence (flag, then a script-declared platform, then the
681- // `context` header) internally that this call site used to apply itself
682- // via `readEffectiveReplayPlanDigestMetadata(replayReq.flags)`.
683- const manifest = inspectAdReplay ( resolved , {
684- platform : req . flags ?. platform ,
685- target : req . flags ?. target ,
686- } ) ;
682+ const backendRejection = validateReplayBackendFlag ( req ) ;
683+ if ( backendRejection ) return { ok : false , response : backendRejection } ;
684+
685+ const { manifest, replayReq } = inspectReplayPlanManifest ( req , resolved ) ;
687686 const { metadata, actions, actionLines, actionSourcePaths, planDigest } = manifest ;
688- const replayReq = applyReplayMetadata (
689- { ...req , flags : buildReplayScriptPlatformFlags ( req . flags , actions ) } ,
690- metadata ,
691- ) ;
692687 const preEntrySession = sessionStore . get ( sessionName ) ;
693- const entryIndex = manifest . resolveEntryIndex ( {
694- from : req . flags ?. replayFrom ,
695- digest : req . flags ?. replayPlanDigest ,
696- pendingRecordAndHeal : coordinator . view ( ) ?. pendingRecordAndHeal ,
697- sessionActionsLength : preEntrySession ?. actions . length ?? 0 ,
688+ const entryIndexResult = resolveReplayPlanEntryIndex ( {
689+ req,
690+ coordinator ,
691+ manifest ,
692+ preEntrySession,
698693 } ) ;
699- if ( ! entryIndex . ok ) {
700- return { ok : false , response : errorResponse ( 'INVALID_ARGS' , entryIndex . message ) } ;
701- }
694+ if ( ! entryIndexResult . ok ) return { ok : false , response : entryIndexResult . response } ;
702695
703696 return {
704697 ok : true ,
@@ -709,13 +702,75 @@ function prepareReplayPlan(params: {
709702 actionSourcePaths,
710703 planDigest,
711704 preEntrySession,
712- entryIndex : entryIndex . value ,
705+ entryIndex : entryIndexResult . value ,
713706 scope : buildPreparedReplayScope ( { req, replayReq, sessionName, resolved, metadata } ) ,
714707 actionTracePath : tracePath ?? preEntrySession ?. trace ?. outPath ,
715708 } ,
716709 } ;
717710}
718711
712+ /**
713+ * #1555 P1: the authoritative rejection for an unrecognized --replay-backend
714+ * value. Extraction moved `.ad` inspection to `inspectAdReplay`, which never
715+ * receives flags — restoring the check here (the one caller of
716+ * `inspectAdReplay` that reaches this point with a non-Maestro request)
717+ * matches `src/compat/replay-input.ts`'s `parseReplayInput` exactly, byte for
718+ * byte, before any plan/session work begins. `replayBackend: 'maestro'` still
719+ * passes here because `runReplayScriptFile` has already routed a real
720+ * Maestro-format request to `runTypedMaestroReplayFile` above; only a
721+ * stray/unknown value reaches this branch.
722+ */
723+ function validateReplayBackendFlag ( req : DaemonRequest ) : DaemonResponse | undefined {
724+ if ( req . flags ?. replayBackend && req . flags . replayBackend !== 'maestro' ) {
725+ return errorResponse (
726+ 'INVALID_ARGS' ,
727+ `Unsupported replay backend "${ req . flags . replayBackend } ".` ,
728+ ) ;
729+ }
730+ return undefined ;
731+ }
732+
733+ /**
734+ * #1555 P1 (digest/resume behind runAdReplay): `digestFlags` is the raw
735+ * request-level platform/target override — `inspectAdReplay` applies the
736+ * SAME precedence (flag, then a script-declared platform, then the `context`
737+ * header) internally that this call site used to apply itself via
738+ * `readEffectiveReplayPlanDigestMetadata(replayReq.flags)`.
739+ */
740+ function inspectReplayPlanManifest (
741+ req : DaemonRequest ,
742+ resolved : string ,
743+ ) : { manifest : AdReplayManifest ; replayReq : DaemonRequest } {
744+ const manifest = inspectAdReplay ( resolved , {
745+ platform : req . flags ?. platform ,
746+ target : req . flags ?. target ,
747+ } ) ;
748+ const replayReq = applyReplayMetadata (
749+ { ...req , flags : buildReplayScriptPlatformFlags ( req . flags , manifest . actions ) } ,
750+ manifest . metadata ,
751+ ) ;
752+ return { manifest, replayReq } ;
753+ }
754+
755+ function resolveReplayPlanEntryIndex ( params : {
756+ req : DaemonRequest ;
757+ coordinator : ReplayCoordinator ;
758+ manifest : AdReplayManifest ;
759+ preEntrySession : SessionState | undefined ;
760+ } ) : { ok : true ; value : number } | { ok : false ; response : DaemonResponse } {
761+ const { req, coordinator, manifest, preEntrySession } = params ;
762+ const entryIndex = manifest . resolveEntryIndex ( {
763+ from : req . flags ?. replayFrom ,
764+ digest : req . flags ?. replayPlanDigest ,
765+ pendingRecordAndHeal : coordinator . view ( ) ?. pendingRecordAndHeal ,
766+ sessionActionsLength : preEntrySession ?. actions . length ?? 0 ,
767+ } ) ;
768+ if ( ! entryIndex . ok ) {
769+ return { ok : false , response : errorResponse ( 'INVALID_ARGS' , entryIndex . message ) } ;
770+ }
771+ return { ok : true , value : entryIndex . value } ;
772+ }
773+
719774function applyReplayMetadata (
720775 req : DaemonRequest ,
721776 metadata : AdReplayManifest [ 'metadata' ] ,
0 commit comments