package service import ( "encoding/json" "errors" "net/url" "sort" "strings" "time" "browser.local/platform/domain" "browser.local/platform/repo" "browser.local/platform/validator" ) const runUpdateChunkSize = 1024 * 1024 type dependencyResolution struct { instance domain.ServerInstance plugin domain.GamePlugin binding domain.RuntimeBinding endpoint domain.RunEndpoint } func (svc *CoreService) GetDependencyCatalogForSession(sessionID, serverInstanceID string) (domain.DependencyCatalog, error) { instance, err := svc.GetServerInstanceForSession(sessionID, serverInstanceID) if err != nil { return domain.DependencyCatalog{}, err } plugin, err := svc.store.GamePlugins().Get(instance.PluginID) if err != nil { return domain.DependencyCatalog{}, err } if !pluginDeclares(plugin, "server.dependencies.manage") { return domain.DependencyCatalog{}, forbiddenError("plugin does not declare required permission: server.dependencies.manage") } resolution, err := svc.resolveDependencyContext(serverInstanceID) if err != nil { return domain.DependencyCatalog{}, err } statuses, err := svc.store.DependencyStatuses().List(domain.DependencyStatusFilter{ServerInstanceID: serverInstanceID}) if err != nil { return domain.DependencyCatalog{}, err } statusByProbe := map[string]domain.DependencyStatus{} for _, status := range statuses { statusByProbe[status.ProbeKey] = status } plans := make([]domain.DependencyPlanView, 0, len(resolution.plugin.RuntimeProfiles.InstallPlans)) for _, plan := range resolution.plugin.RuntimeProfiles.InstallPlans { if !runtimePlatformsContain(plan.Platforms, resolution.endpoint.Platform) { continue } steps := make([]domain.DependencyPlanStepView, len(plan.Steps)) for i, step := range plan.Steps { host := "" if parsed, parseErr := url.Parse(step.DownloadRef); parseErr == nil { host = parsed.Hostname() } steps[i] = domain.DependencyPlanStepView{Type: step.Type, TargetKey: step.TargetKey, PackageManager: step.PackageManager, PackageName: step.PackageName, Version: step.Version, DownloadHost: host} } var planProbe domain.RuntimeDependencyProbe for _, candidate := range resolution.plugin.RuntimeProfiles.DependencyProbes { if runtimePlatformsContain(candidate.Platforms, resolution.endpoint.Platform) && planTargetsProbe(plan, candidate) { planProbe = candidate break } } plans = append(plans, domain.DependencyPlanView{Key: plan.Key, Title: plan.Title, TargetOS: resolution.endpoint.Platform, TargetArch: resolution.endpoint.Architecture, Digest: dependencyPlanDigest(resolution, planProbe, plan), Steps: steps}) } sort.Slice(plans, func(i, j int) bool { return plans[i].Key < plans[j].Key }) probes := make([]domain.DependencyProbeView, 0, len(resolution.plugin.RuntimeProfiles.DependencyProbes)) for _, probe := range resolution.plugin.RuntimeProfiles.DependencyProbes { if !runtimePlatformsContain(probe.Platforms, resolution.endpoint.Platform) { continue } status := statusByProbe[probe.Key] planKey := "" for _, plan := range resolution.plugin.RuntimeProfiles.InstallPlans { if runtimePlatformsContain(plan.Platforms, resolution.endpoint.Platform) && planTargetsProbe(plan, probe) { planKey = plan.Key break } } state := status.State if state == "" { state = domain.DependencyStateUnknown } probes = append(probes, domain.DependencyProbeView{Key: probe.Key, Kind: probe.Kind, Required: probe.Required, MinimumVersion: probe.MinimumVersion, State: state, Evidence: status.Evidence, InstallPlanKey: planKey}) } sort.Slice(probes, func(i, j int) bool { return probes[i].Key < probes[j].Key }) return domain.CopyDependencyCatalog(domain.DependencyCatalog{ServerInstanceID: resolution.instance.ID, PluginID: resolution.plugin.ID, PluginVersion: resolution.plugin.Version, ProfileKey: resolution.binding.ProfileKey, TargetOS: resolution.endpoint.Platform, TargetArch: resolution.endpoint.Architecture, Probes: probes, Plans: plans, UpdatedAt: svc.now()}), nil } func (svc *CoreService) ListRunUpdateJobsForSession(sessionID, serverInstanceID string) ([]domain.RunUpdateJob, error) { if _, err := svc.GetServerInstanceForSession(sessionID, serverInstanceID); err != nil { return nil, err } items, err := svc.store.RunUpdateJobs().List(domain.RunUpdateJobFilter{ServerInstanceID: serverInstanceID}) if err != nil { return nil, err } sort.Slice(items, func(i, j int) bool { return items[i].UpdatedAt.After(items[j].UpdatedAt) }) for i := range items { items[i] = domain.CopyRunUpdateJob(items[i]) } return items, nil } func (svc *CoreService) GetDependencyExecutionInput(request domain.DependencyExecutionInputRequest) (domain.DependencyExecutionInput, error) { if err := validator.ValidateDependencyExecutionInputRequest(request); err != nil { return domain.DependencyExecutionInput{}, err } job, err := svc.activeFencedInputJob(request.RunEndpointID, request.SessionToken, request.JobID, request.LeaseToken, request.Attempt) if err != nil { return domain.DependencyExecutionInput{}, err } if job.Capability != domain.JobCapabilityDependenciesCheck && job.Capability != domain.JobCapabilityDependenciesInstall { return domain.DependencyExecutionInput{}, validationError("job is not a dependency operation") } resolution, err := svc.resolveDependencyContext(job.ServerInstanceID) if err != nil { return domain.DependencyExecutionInput{}, err } if resolution.endpoint.ID != job.RunEndpointID { return domain.DependencyExecutionInput{}, validationError("dependency endpoint no longer matches") } probeKey := strings.TrimPrefix(job.TargetKey, "dependencies/") if job.Capability == domain.JobCapabilityDependenciesInstall { probeKey = "" } var probe domain.RuntimeDependencyProbe if probeKey != "" { probe, err = declaredDependencyProbe(resolution.plugin, probeKey, resolution.endpoint.Platform) if err != nil { return domain.DependencyExecutionInput{}, err } } var plan domain.RuntimeInstallPlan if job.Capability == domain.JobCapabilityDependenciesInstall { planKey := strings.TrimPrefix(job.TargetKey, "dependencies/install/") plan, err = declaredInstallPlan(resolution.plugin, planKey, resolution.endpoint.Platform) if err != nil { return domain.DependencyExecutionInput{}, err } statuses, listErr := svc.store.DependencyStatuses().List(domain.DependencyStatusFilter{ServerInstanceID: job.ServerInstanceID}) if listErr != nil { return domain.DependencyExecutionInput{}, listErr } for _, status := range statuses { if status.JobID == job.ID { probe, err = declaredDependencyProbe(resolution.plugin, status.ProbeKey, resolution.endpoint.Platform) if err != nil { return domain.DependencyExecutionInput{}, err } break } } } digest := dependencyPlanDigest(resolution, probe, plan) status, err := svc.dependencyStatusForJob(job.ID, job.ServerInstanceID) if err != nil { return domain.DependencyExecutionInput{}, err } if status.PlanDigest != digest { return domain.DependencyExecutionInput{}, validationError("dependency declaration changed after dispatch") } bindings, err := dependencyBindings(resolution.binding, probe, plan) if err != nil { return domain.DependencyExecutionInput{}, err } return domain.CopyDependencyExecutionInput(domain.DependencyExecutionInput{JobID: job.ID, ServerInstanceID: job.ServerInstanceID, RunEndpointID: job.RunEndpointID, PluginID: resolution.plugin.ID, PluginVersion: resolution.plugin.Version, ProfileKey: resolution.binding.ProfileKey, TargetOS: resolution.endpoint.Platform, TargetArch: resolution.endpoint.Architecture, PlanDigest: digest, Probe: probe, Plan: plan, Bindings: bindings}), nil } func (svc *CoreService) GetRunUpdateInput(request domain.RunUpdateInputRequest) (domain.RunUpdateInput, error) { if err := validator.ValidateRunUpdateInputRequest(request); err != nil { return domain.RunUpdateInput{}, err } job, err := svc.activeFencedInputJob(request.RunEndpointID, request.SessionToken, request.JobID, request.LeaseToken, request.Attempt) if err != nil { return domain.RunUpdateInput{}, err } if job.Capability != domain.JobCapabilityRunSelfUpdate { return domain.RunUpdateInput{}, validationError("job is not a Run self-update") } update, distribution, artifact, err := svc.resolveRunUpdate(job) if err != nil { return domain.RunUpdateInput{}, err } return domain.RunUpdateInput{JobID: job.ID, ServerInstanceID: job.ServerInstanceID, RunEndpointID: job.RunEndpointID, ArtifactID: artifact.ID, Checksum: artifact.Checksum, SizeBytes: artifact.SizeBytes, TargetOS: distribution.TargetOS, TargetArch: distribution.TargetArch, PackageFormat: distribution.PackageFormat, ExecutableName: executableFilename("run", distribution.TargetOS), TargetRelease: update.TargetRelease, ChunkSizeBytes: runUpdateChunkSize}, nil } func (svc *CoreService) ReadRunUpdateChunk(request domain.RunUpdateChunkRequest) (domain.RunUpdateChunk, error) { if err := validator.ValidateRunUpdateChunkRequest(request); err != nil { return domain.RunUpdateChunk{}, err } job, err := svc.activeFencedInputJob(request.RunEndpointID, request.SessionToken, request.JobID, request.LeaseToken, request.Attempt) if err != nil { return domain.RunUpdateChunk{}, err } if job.Capability != domain.JobCapabilityRunSelfUpdate { return domain.RunUpdateChunk{}, validationError("job is not a Run self-update") } _, _, artifact, err := svc.resolveRunUpdate(job) if err != nil { return domain.RunUpdateChunk{}, err } payload, err := svc.artifactPayload(artifact.ID) if err != nil { return domain.RunUpdateChunk{}, err } if int64(len(payload)) != artifact.SizeBytes || validator.BytesChecksum(payload) != artifact.Checksum { return domain.RunUpdateChunk{}, validationError("update artifact content does not match metadata") } if request.Offset >= artifact.SizeBytes { return domain.RunUpdateChunk{}, validationError("offset must be inside update artifact") } length := request.Length remaining := artifact.SizeBytes - request.Offset if int64(length) > remaining { length = int(remaining) } end := request.Offset + int64(length) return domain.CopyRunUpdateChunk(domain.RunUpdateChunk{JobID: job.ID, ArtifactID: artifact.ID, Offset: request.Offset, TotalBytes: artifact.SizeBytes, Checksum: artifact.Checksum, Payload: payload[int(request.Offset):int(end)], Complete: end == artifact.SizeBytes}), nil } func (svc *CoreService) activeFencedInputJob(endpointID, sessionToken, jobID, leaseToken string, attempt int) (domain.Job, error) { session, err := svc.validatedRunSession(endpointID, sessionToken) if err != nil { return domain.Job{}, err } svc.jobMu.Lock() defer svc.jobMu.Unlock() job, err := svc.fencedJob(session, jobID, leaseToken, attempt) if err != nil { return domain.Job{}, err } if job.State != domain.JobStateAccepted && job.State != domain.JobStateRunning { return domain.Job{}, validationError("job input is not active") } if !job.CancelRequestedAt.IsZero() { return domain.Job{}, validationError("job input is cancelled") } return job, nil } func (svc *CoreService) resolveDependencyContext(serverInstanceID string) (dependencyResolution, error) { instance, err := svc.store.ServerInstances().Get(serverInstanceID) if err != nil { return dependencyResolution{}, err } plugin, err := svc.store.GamePlugins().Get(instance.PluginID) if err != nil { return dependencyResolution{}, err } if plugin.Status != domain.GamePluginStatusInstalled || plugin.Version != instance.PluginVersion { return dependencyResolution{}, validationError("installed plugin version does not match server") } binding, err := svc.runtimeBindingForServer(instance.ID) if err != nil { return dependencyResolution{}, err } binding, err = normalizeRuntimeBinding(plugin, binding) if err != nil { return dependencyResolution{}, err } if binding.Status != domain.RuntimeBindingStatusComplete || binding.PluginVersion != plugin.Version { return dependencyResolution{}, validationError("runtime binding is incomplete or stale") } endpoint, err := svc.GetRunEndpoint(instance.RunEndpointID) if err != nil { return dependencyResolution{}, err } if endpoint.Platform == "" || endpoint.Architecture == "" { return dependencyResolution{}, validationError("Run endpoint target is not registered") } return dependencyResolution{instance: instance, plugin: plugin, binding: binding, endpoint: endpoint}, nil } func declaredDependencyProbe(plugin domain.GamePlugin, key, targetOS string) (domain.RuntimeDependencyProbe, error) { for _, probe := range plugin.RuntimeProfiles.DependencyProbes { if probe.Key == key && runtimePlatformsContain(probe.Platforms, targetOS) { return probe, nil } } return domain.RuntimeDependencyProbe{}, validationError("dependency probe is not declared for endpoint target") } func declaredInstallPlan(plugin domain.GamePlugin, key, targetOS string) (domain.RuntimeInstallPlan, error) { for _, plan := range plugin.RuntimeProfiles.InstallPlans { if plan.Key == key && runtimePlatformsContain(plan.Platforms, targetOS) { return plan, nil } } return domain.RuntimeInstallPlan{}, validationError("dependency install plan is not declared for endpoint target") } func runtimePlatformsContain(platforms []string, target string) bool { if len(platforms) == 0 { return true } for _, platform := range platforms { if platform == target { return true } } return false } func planTargetsProbe(plan domain.RuntimeInstallPlan, probe domain.RuntimeDependencyProbe) bool { for _, step := range plan.Steps { if step.TargetKey == probe.TargetKey { return true } } return false } func dependencyPlanDigest(resolution dependencyResolution, probe domain.RuntimeDependencyProbe, plan domain.RuntimeInstallPlan) string { keys := make([]string, 0, len(resolution.binding.Bindings)) for key := range resolution.binding.Bindings { keys = append(keys, key) } sort.Strings(keys) bindingEvidence := make([]string, 0, len(keys)) for _, key := range keys { bindingEvidence = append(bindingEvidence, key+"="+validator.BytesChecksum([]byte(resolution.binding.Bindings[key]))) } payload := struct { PluginID string `json:"pluginId"` PluginVersion string `json:"pluginVersion"` ProfileKey string `json:"profileKey"` TargetOS string `json:"targetOs"` TargetArch string `json:"targetArch"` Binding []string `json:"binding"` Probe domain.RuntimeDependencyProbe `json:"probe"` Plan domain.RuntimeInstallPlan `json:"plan"` }{resolution.plugin.ID, resolution.plugin.Version, resolution.binding.ProfileKey, resolution.endpoint.Platform, resolution.endpoint.Architecture, bindingEvidence, probe, plan} body, _ := json.Marshal(payload) return validator.BytesChecksum(body) } func dependencyBindings(binding domain.RuntimeBinding, probe domain.RuntimeDependencyProbe, plan domain.RuntimeInstallPlan) (map[string]string, error) { keys := map[string]struct{}{} if probe.TargetKey != "" { keys[probe.TargetKey] = struct{}{} } for _, step := range plan.Steps { if step.TargetKey != "" { keys[step.TargetKey] = struct{}{} } } out := make(map[string]string, len(keys)) for key := range keys { value := strings.TrimSpace(binding.Bindings[key]) if value == "" { value = key } lower := strings.ToLower(value) if strings.HasPrefix(lower, "secret://") || strings.Contains(lower, "password=") || strings.Contains(lower, "token=") { return nil, validationError("dependency target binding cannot be a secret") } out[key] = value } return out, nil } func (svc *CoreService) dependencyStatusForJob(jobID, serverInstanceID string) (domain.DependencyStatus, error) { statuses, err := svc.store.DependencyStatuses().List(domain.DependencyStatusFilter{ServerInstanceID: serverInstanceID}) if err != nil { return domain.DependencyStatus{}, err } for _, status := range statuses { if status.JobID == jobID { return status, nil } } return domain.DependencyStatus{}, repo.ErrNotFound } func (svc *CoreService) resolveRunUpdate(job domain.Job) (domain.RunUpdateJob, domain.RunDistribution, domain.Artifact, error) { updates, err := svc.store.RunUpdateJobs().List(domain.RunUpdateJobFilter{ServerInstanceID: job.ServerInstanceID}) if err != nil { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, err } var update domain.RunUpdateJob for _, candidate := range updates { if candidate.JobID == job.ID { update = candidate break } } if update.ID == "" || update.RunEndpointID != job.RunEndpointID { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, validationError("Run update record does not match active job") } distributions, err := svc.store.RunDistributions().List(domain.RunDistributionFilter{ServerInstanceID: job.ServerInstanceID, Status: domain.DistributionStatusAvailable}) if err != nil { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, err } var distribution domain.RunDistribution for _, candidate := range distributions { if candidate.ArtifactID == update.ArtifactID { distribution = candidate break } } if distribution.ID == "" || distribution.RunEndpointID != job.RunEndpointID || distribution.TargetOS != update.TargetOS || distribution.TargetArch != update.TargetArch || distribution.Checksum != update.Checksum { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, validationError("Run distribution no longer matches update") } endpoint, err := svc.GetRunEndpoint(job.RunEndpointID) if err != nil { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, err } if endpoint.Platform != distribution.TargetOS || endpoint.Architecture != distribution.TargetArch { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, validationError("Run update target no longer matches endpoint") } artifact, err := svc.store.Artifacts().Get(update.ArtifactID) if err != nil { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, err } if artifact.State != domain.ArtifactStateAvailable || artifact.OwnerKind != domain.ArtifactOwnerKindJob || artifact.OwnerID != distribution.BuildJobID || artifact.Checksum != update.Checksum { return domain.RunUpdateJob{}, domain.RunDistribution{}, domain.Artifact{}, validationError("Run update artifact is unavailable or outside distribution scope") } return update, distribution, artifact, nil } func (svc *CoreService) projectDependencyAndRunUpdateResult(job domain.Job, stamp time.Time) error { if job.Capability == domain.JobCapabilityDependenciesCheck || job.Capability == domain.JobCapabilityDependenciesInstall { status, err := svc.dependencyStatusForJob(job.ID, job.ServerInstanceID) if err != nil { return err } status.UpdatedAt = stamp status.CheckedAt = stamp status.JobID = job.ID if job.State == domain.JobStateSucceeded { var evidence domain.DependencyExecutionEvidence if err := json.Unmarshal([]byte(job.ExecutionResult.Content), &evidence); err != nil { return validationError("dependency result evidence is invalid") } if evidence.ProbeKey != status.ProbeKey || evidence.PlanDigest != status.PlanDigest || job.ExecutionResult.Checksum != status.PlanDigest { return validationError("dependency result evidence does not match approved plan") } status.State = domain.DependencyState(evidence.State) status.Evidence = evidence.Evidence status.CompletedSteps = evidence.CompletedSteps status.Message = "dependency execution completed" } else if job.State == domain.JobStateCancelled { status.State = domain.DependencyStateFailed status.Message = "dependency execution cancelled" } else { status.State = domain.DependencyStateFailed status.Message = "dependency execution failed" } if err := validator.ValidateDependencyStatus(status); err != nil { return err } if err := svc.store.DependencyStatuses().Update(status); err != nil { return err } return nil } if job.Capability != domain.JobCapabilityRunSelfUpdate { return nil } update, _, _, err := svc.resolveRunUpdate(job) if err != nil { return err } update.UpdatedAt = stamp if job.State == domain.JobStateSucceeded { var evidence domain.RunUpdateExecutionEvidence if err := json.Unmarshal([]byte(job.ExecutionResult.Content), &evidence); err != nil || evidence.TargetRelease != update.TargetRelease || evidence.Phase != "staged" || job.ExecutionResult.Checksum != update.Checksum { return validationError("Run update staged evidence is invalid") } update.Status = domain.DistributionJobStatusRunning update.Phase = domain.RunUpdatePhaseRestartRequested update.Message = "verified update staged; restart requested" } else if job.State == domain.JobStateCancelled { update.Status = domain.DistributionJobStatusFailed update.Phase = domain.RunUpdatePhaseFailed update.Message = "Run update cancelled before activation" } else { update.Status = domain.DistributionJobStatusFailed update.Phase = domain.RunUpdatePhaseFailed update.Message = "Run update verification or staging failed" } if err := validator.ValidateRunUpdateJob(update); err != nil { return err } if err := svc.store.RunUpdateJobs().Update(update); err != nil { return err } return nil } func (svc *CoreService) projectDependencyAndRunUpdateProgress(job domain.Job, stamp time.Time) error { if job.Capability == domain.JobCapabilityRunSelfUpdate { updates, err := svc.store.RunUpdateJobs().List(domain.RunUpdateJobFilter{ServerInstanceID: job.ServerInstanceID}) if err != nil { return err } for _, update := range updates { if update.JobID != job.ID || update.Status != domain.DistributionJobStatusQueued { continue } update.Status = domain.DistributionJobStatusRunning update.Phase = domain.RunUpdatePhaseDownloading update.Message = "Run is downloading and verifying the update" update.UpdatedAt = stamp if err := validator.ValidateRunUpdateJob(update); err != nil { return err } return svc.store.RunUpdateJobs().Update(update) } } return nil } func (svc *CoreService) ReportRunUpdateHealth(report domain.RunUpdateHealthReport) (domain.RunUpdateHealthResult, error) { if err := validator.ValidateRunUpdateHealthReport(report); err != nil { return domain.RunUpdateHealthResult{}, err } if _, err := svc.validatedRunSession(report.RunEndpointID, report.SessionToken); err != nil { return domain.RunUpdateHealthResult{}, err } svc.jobMu.Lock() defer svc.jobMu.Unlock() job, err := svc.store.Jobs().Get(report.JobID) if err != nil { return domain.RunUpdateHealthResult{}, err } if job.RunEndpointID != report.RunEndpointID || job.Capability != domain.JobCapabilityRunSelfUpdate || job.State != domain.JobStateSucceeded || job.Attempt != report.Attempt || !leaseTokenMatches(job.LeaseTokenHash, report.LeaseToken) { return domain.RunUpdateHealthResult{}, validationError("Run update health report does not match terminal attempt") } updates, err := svc.store.RunUpdateJobs().List(domain.RunUpdateJobFilter{ServerInstanceID: job.ServerInstanceID}) if err != nil { return domain.RunUpdateHealthResult{}, err } var update domain.RunUpdateJob for _, candidate := range updates { if candidate.JobID == job.ID && candidate.RunEndpointID == report.RunEndpointID { update = candidate break } } if update.ID == "" || job.ExecutionResult.Checksum != update.Checksum { return domain.RunUpdateHealthResult{}, validationError("Run update health report does not match staged update") } endpoint, err := svc.GetRunEndpoint(report.RunEndpointID) if err != nil { return domain.RunUpdateHealthResult{}, err } if endpoint.Version != report.Version || endpoint.Status != domain.RunEndpointStatusOnline { return domain.RunUpdateHealthResult{}, validationError("Run update health version does not match online endpoint") } stamp := svc.now() if report.Outcome == "succeeded" { if report.Version != update.TargetRelease || update.Phase == domain.RunUpdatePhaseRolledBack || update.Phase == domain.RunUpdatePhaseFailed { return domain.RunUpdateHealthResult{}, validationError("Run update health version does not match target release") } if update.Phase == domain.RunUpdatePhaseSucceeded { return domain.RunUpdateHealthResult{Accepted: true, JobID: job.ID, Phase: update.Phase, ServerTime: stamp}, nil } update.Status = domain.DistributionJobStatusSucceeded update.Phase = domain.RunUpdatePhaseSucceeded update.Rollback = false update.Message = "updated Run registered, reconciled, and reported healthy" } else { if update.PreviousVersion != "" && report.Version != update.PreviousVersion { return domain.RunUpdateHealthResult{}, validationError("rolled-back Run version does not match previous release") } if update.Phase == domain.RunUpdatePhaseRolledBack { return domain.RunUpdateHealthResult{Accepted: true, JobID: job.ID, Phase: update.Phase, ServerTime: stamp}, nil } update.Status = domain.DistributionJobStatusFailed update.Phase = domain.RunUpdatePhaseRolledBack update.Rollback = true update.Message = "Run update activation failed and previous executable was restored" } update.UpdatedAt = stamp if err := validator.ValidateRunUpdateJob(update); err != nil { return domain.RunUpdateHealthResult{}, err } if err := svc.store.RunUpdateJobs().Update(update); err != nil { return domain.RunUpdateHealthResult{}, err } return domain.RunUpdateHealthResult{Accepted: true, JobID: job.ID, Phase: update.Phase, ServerTime: stamp}, nil } func sameRunUpdateTarget(existing, expected domain.RunUpdateJob) bool { return existing.ServerInstanceID == expected.ServerInstanceID && existing.RunEndpointID == expected.RunEndpointID && existing.ArtifactID == expected.ArtifactID && existing.Checksum == expected.Checksum && existing.TargetOS == expected.TargetOS && existing.TargetArch == expected.TargetArch && existing.TargetRelease == expected.TargetRelease && existing.JobID == expected.JobID && existing.IdempotencyKey == expected.IdempotencyKey } func findRunDistributionForArtifact(distributions []domain.RunDistribution, artifactID string) (domain.RunDistribution, error) { for _, distribution := range distributions { if distribution.ArtifactID == artifactID && distribution.Status == domain.DistributionStatusAvailable { return distribution, nil } } return domain.RunDistribution{}, errors.New("available Run distribution not found") }