diff --git a/internal/client/agent/executor.go b/internal/client/agent/executor.go index 40eff2e..e09ca12 100644 --- a/internal/client/agent/executor.go +++ b/internal/client/agent/executor.go @@ -114,14 +114,12 @@ func (executor *Executor) launch(ctx context.Context, issue domain.UUID, revisio if workingDirectory == "" { workingDirectory = executor.WorkDir } - if err := executor.Store.SetLaunchPhase(ctx, issue, domain.LaunchPhasePrepared, "", 0); err != nil { - return err - } - // The native Windows supervisor creates/assigns the Job while the child is - // suspended. It does not cross the durable authorization barrier until the - // process object has been fully prepared and its immutable identity is - // available. A daemon crash before this write leaves only launch_prepared; - // the kill-on-close Job prevents a suspended child from surviving restart. + // The supervisor resolves all token fallback and creates/assigns the child + // while it is still suspended. Only after that immutable identity exists do + // we persist launch_prepared; therefore no context fallback can occur after + // the durable preparation barrier. A daemon crash before this write leaves + // no authorized launch, and the kill-on-close Job prevents a suspended child + // from surviving restart. runContext, cancel := context.WithCancel(context.Background()) process, err := executor.Supervisor.Start(runContext, supervisor.StartSpec{IssueUUID: issue, CommandRevision: revision, Execution: proto.Clone(spec).(*rvboxv1.ExecutionSpec), ScriptBody: scriptBody, WorkingDirectory: workingDirectory, Environment: cloneEnvironment(spec.GetEnvOverrides()), ExecutionProfiles: executionProfileNames(spec.GetExecutionProfiles())}) if err != nil { @@ -134,6 +132,11 @@ func (executor *Executor) launch(ctx context.Context, issue domain.UUID, revisio return executor.reject(ctx, issue, revision, err) } identity := process.Identity() + if err := executor.Store.SetLaunchPhase(ctx, issue, domain.LaunchPhasePrepared, identity.Context, 0); err != nil { + _, _ = executor.Supervisor.Signal(context.Background(), process, supervisor.SignalKill) + cancel() + return err + } if err := executor.Store.SetLaunchPhase(ctx, issue, domain.LaunchPhaseAuthorized, identity.Context, 0); err != nil { _, _ = executor.Supervisor.Signal(context.Background(), process, supervisor.SignalKill) cancel()