package store import ( "context" "errors" "time" ) // ErrDeploymentBusy means a previous legacy request may still be executing. var ErrDeploymentBusy = errors.New("store: speaker delivery reservation is active") // DeploymentDeliveryWindow retains delivery ownership after an ambiguous response. const DeploymentDeliveryWindow = 2 * time.Minute // JobFence identifies the currently leased deployment attempt. type JobFence struct { JobID, TenantID, OwnerID string Token int64 ExpectedGeneration int64 RetryRound int } // DeploymentSpeaker preserves delivery progress independently from job result metadata. // Generation is monotonic per speaker, including across different jobs. type DeploymentSpeaker struct { ObservationToken int64 JobID, TenantID, SpeakerID, RevisionID string Generation int64 RequestSequence int64 State, Confirmation, Error string DispatchAttempts int RetryRound int HealthReceivedAt *time.Time HealthRevisionID, HealthSourceAt, HealthError string } // DeploymentObservation is a compatible authenticated health report. SourceAt may // be absent on legacy agents; ReceivedAt is generated by the control-plane store. type DeploymentObservation struct{ RevisionID, SourceAt, Error string } // Deployments atomically fences publication and acknowledgement against the job // lease and the speaker's current deployment generation. type Deployments interface { BeginDeploymentSpeaker(context.Context, JobFence, string, string) (DeploymentSpeaker, error) RecordDeploymentSpeaker(context.Context, JobFence, DeploymentSpeaker, string, string, string) error ListDeploymentSpeakers(context.Context, string, string) ([]DeploymentSpeaker, error) ListPendingDeployments(context.Context, int) ([]DeploymentSpeaker, error) ListDeploymentObservations(context.Context, int) ([]DeploymentSpeaker, error) ObserveDeployment(context.Context, DeploymentSpeaker, DeploymentObservation) error }