package domain import "time" type SCUMDataCapability string const ( SCUMDataCapabilitySchemaProbe SCUMDataCapability = "schema-probe" SCUMDataCapabilityPlayerRead SCUMDataCapability = "players.read" SCUMDataCapabilityPlayerDetailRead SCUMDataCapability = "player-details.read" SCUMDataCapabilitySquadRead SCUMDataCapability = "squads.read" SCUMDataCapabilitySquadMemberRead SCUMDataCapability = "squad-members.read" SCUMDataCapabilityVehicleRead SCUMDataCapability = "vehicles.read" SCUMDataCapabilityFlagRead SCUMDataCapability = "flags.read" SCUMDataCapabilityPositionRead SCUMDataCapability = "positions.read" SCUMDataCapabilityProfileXMLWrite SCUMDataCapability = "profile-xml.write" SCUMDataCapabilityEconomyCommand SCUMDataCapability = "economy-command.write" SCUMDataCapabilityGiftCommand SCUMDataCapability = "gift-command.write" ) type SCUMCapabilityEvidenceStatus string const ( SCUMSchemaProbeStatusSucceeded SCUMCapabilityEvidenceStatus = "succeeded" SCUMCapabilityEvidenceMissing SCUMCapabilityEvidenceStatus = "missing" SCUMCapabilityEvidenceCompatible SCUMCapabilityEvidenceStatus = "compatible" SCUMCapabilityEvidenceIncompatible SCUMCapabilityEvidenceStatus = "incompatible" SCUMCapabilityEvidenceFailed SCUMCapabilityEvidenceStatus = "failed" ) type SCUMCapabilityGateState string const ( SCUMCapabilityGateEnabled SCUMCapabilityGateState = "enabled" SCUMCapabilityGateDisabled SCUMCapabilityGateState = "disabled" ) type SCUMSafeErrorCode string const ( SCUMSafeErrorNone SCUMSafeErrorCode = "none" SCUMSafeErrorProbeExecutorAbsent SCUMSafeErrorCode = "probe_executor_absent" SCUMSafeErrorProbeMissing SCUMSafeErrorCode = "probe_missing" SCUMSafeErrorProbeFailed SCUMSafeErrorCode = "probe_failed" SCUMSafeErrorSchemaIncompatible SCUMSafeErrorCode = "schema_incompatible" SCUMSafeErrorBindingMismatch SCUMSafeErrorCode = "binding_mismatch" SCUMSafeErrorAdapterMismatch SCUMSafeErrorCode = "adapter_mismatch" SCUMSafeErrorFingerprintMismatch SCUMSafeErrorCode = "fingerprint_mismatch" SCUMSafeErrorDigestMismatch SCUMSafeErrorCode = "digest_mismatch" SCUMSafeErrorEvidenceExpired SCUMSafeErrorCode = "evidence_expired" SCUMSafeErrorInvalidProbePayload SCUMSafeErrorCode = "invalid_probe_payload" SCUMSafeErrorInvalidRequest SCUMSafeErrorCode = "invalid_request" SCUMSafeErrorTargetUnavailable SCUMSafeErrorCode = "target_unavailable" SCUMSafeErrorSourceUnavailable SCUMSafeErrorCode = "source_unavailable" SCUMSafeErrorSQLiteOpenFailed SCUMSafeErrorCode = "sqlite_open_failed" SCUMSafeErrorSQLiteReadFailed SCUMSafeErrorCode = "sqlite_read_failed" SCUMSafeErrorDatabaseBusy SCUMSafeErrorCode = "database_busy" SCUMSafeErrorTimeout SCUMSafeErrorCode = "timeout" SCUMSafeErrorCancelled SCUMSafeErrorCode = "cancelled" SCUMSafeErrorSourceChanged SCUMSafeErrorCode = "source_changed" SCUMSafeErrorResultLimitExceeded SCUMSafeErrorCode = "result_limit_exceeded" SCUMSafeErrorTemplateMissing SCUMSafeErrorCode = "template_missing" SCUMSafeErrorTemplateMismatch SCUMSafeErrorCode = "template_digest_mismatch" SCUMSafeErrorParameterInvalid SCUMSafeErrorCode = "parameter_schema_invalid" SCUMSafeErrorRowLimitExceeded SCUMSafeErrorCode = "row_limit_exceeded" SCUMSafeErrorResultSchemaInvalid SCUMSafeErrorCode = "result_schema_invalid" ) type SCUMTerminalResultStatus string const ( SCUMTerminalResultSucceeded SCUMTerminalResultStatus = "succeeded" SCUMTerminalResultFailed SCUMTerminalResultStatus = "failed" SCUMTerminalResultCancelled SCUMTerminalResultStatus = "cancelled" ) type SCUMSafeError struct { Code SCUMSafeErrorCode Message string Retryable bool } type SCUMBindingIdentity struct { ServerInstanceID string RunBindingID string RunEndpointID string PluginID string PluginVersion string AdapterVersion string GameVersion string DatabaseIdentity string } type SCUMSchemaProbeBounds struct { MaxObjects int MaxColumnsPerObject int MaxIndexesPerObject int MaxForeignKeys int MaxCardinalityReads int MaxSampleRows int TimeoutMS int MaxResultBytes int } func DefaultSCUMSchemaProbeBounds() SCUMSchemaProbeBounds { return SCUMSchemaProbeBounds{MaxObjects: 256, MaxColumnsPerObject: 128, MaxIndexesPerObject: 64, MaxForeignKeys: 64, MaxCardinalityReads: 64, MaxSampleRows: 3, TimeoutMS: 5000, MaxResultBytes: 512 * 1024} } type SCUMSQLiteTemplateBounds struct { MaxParameters int MaxRows int TimeoutMS int BusyTimeoutMS int MaxResultBytes int } func DefaultSCUMSQLiteTemplateBounds() SCUMSQLiteTemplateBounds { return SCUMSQLiteTemplateBounds{MaxParameters: 64, MaxRows: 500, TimeoutMS: 5000, BusyTimeoutMS: 250, MaxResultBytes: 1024 * 1024} } type SCUMSchemaProbeRequest struct { RequestID string JobID string Binding SCUMBindingIdentity Bounds SCUMSchemaProbeBounds RequestedAt time.Time } type SCUMSQLiteTemplateRequest struct { RequestID string JobID string Binding SCUMBindingIdentity Capability SCUMDataCapability TargetKey string TemplateKey string AdapterVersion string RequiredSchemaFingerprint string AssetDigest string ParameterDigest string Parameters map[string]any Bounds SCUMSQLiteTemplateBounds RequestedAt time.Time } type SCUMSchemaProbeDeclaration struct { Capability string TargetKey string Bounds SCUMSchemaProbeBounds } type SCUMLiveDataCapabilityGateDeclaration struct { Capability SCUMDataCapability Gate SCUMCapabilityGateState AdapterVersion string RequiredSchemaFingerprint string RequiredAssetDigests []string EvidenceStatus SCUMCapabilityEvidenceStatus SafeReason string } type SCUMLiveDataManifest struct { SchemaVersion string Probe SCUMSchemaProbeDeclaration CapabilityGates []SCUMLiveDataCapabilityGateDeclaration } type SCUMSchemaColumnEvidence struct { NameFingerprint string DeclaredType string Nullable *bool PrimaryKey bool Ordinal int } type SCUMSchemaIndexEvidence struct { NameFingerprint string Unique bool ColumnHashes []string } type SCUMSchemaForeignKeyEvidence struct { FromColumnHash string ToObjectHash string ToColumnHash string } type SCUMSchemaObjectEvidence struct { ObjectHash string Kind string NameFingerprint string DeclaredColumns []SCUMSchemaColumnEvidence Indexes []SCUMSchemaIndexEvidence ForeignKeys []SCUMSchemaForeignKeyEvidence ApproximateRows *int64 SampleFingerprints []string } type SCUMSchemaProbeResult struct { RequestID string JobID string Binding SCUMBindingIdentity Status SCUMCapabilityEvidenceStatus SourceFingerprint string SchemaFingerprint string ObservedAt time.Time ResultDigest string Objects []SCUMSchemaObjectEvidence SafeError SCUMSafeError Limits SCUMSchemaProbeBounds } type SCUMSQLiteTemplateResult struct { RequestID string JobID string Binding SCUMBindingIdentity Status SCUMTerminalResultStatus Capability SCUMDataCapability TargetKey string TemplateKey string AdapterVersion string SchemaFingerprint string AssetDigest string ParameterDigest string SourceFingerprint string ObservedAt time.Time ResultDigest string RowCount int Rows []map[string]any Truncated bool SafeError SCUMSafeError Limits SCUMSQLiteTemplateBounds } type SCUMCapabilityRequirement struct { Capability SCUMDataCapability AdapterVersion string SchemaFingerprint string AssetDigests []string } type SCUMCapabilityEvidence struct { Capability SCUMDataCapability Status SCUMCapabilityEvidenceStatus Binding SCUMBindingIdentity AdapterVersion string SchemaFingerprint string ProbeResultDigest string AssetDigests []string ObservedAt time.Time ExpiresAt time.Time SafeError SCUMSafeError } type SCUMCapabilityGate struct { Capability SCUMDataCapability State SCUMCapabilityGateState Enabled bool ReasonCode SCUMSafeErrorCode Reason string Evidence SCUMCapabilityEvidence } func EvaluateSCUMCapabilityGate(requirement SCUMCapabilityRequirement, evidence SCUMCapabilityEvidence, active SCUMBindingIdentity, probeExecutorAvailable bool, now time.Time) SCUMCapabilityGate { gate := SCUMCapabilityGate{Capability: requirement.Capability, State: SCUMCapabilityGateDisabled, ReasonCode: SCUMSafeErrorProbeMissing, Reason: "current-service evidence is required before this SCUM capability can run"} if !probeExecutorAvailable { gate.ReasonCode = SCUMSafeErrorProbeExecutorAbsent gate.Reason = "bound Run does not expose the generic SQLite schema-probe executor" return gate } if evidence.Status == SCUMCapabilityEvidenceMissing || evidence.Capability == "" { return gate } gate.Evidence = CopySCUMCapabilityEvidence(evidence) if evidence.Status == SCUMCapabilityEvidenceFailed { gate.ReasonCode = SCUMSafeErrorProbeFailed gate.Reason = safeReason(evidence.SafeError.Message, "last schema probe failed") return gate } if evidence.Status == SCUMCapabilityEvidenceIncompatible { gate.ReasonCode = SCUMSafeErrorSchemaIncompatible gate.Reason = safeReason(evidence.SafeError.Message, "current schema is incompatible with the plugin adapter") return gate } if evidence.Capability != requirement.Capability { gate.ReasonCode = SCUMSafeErrorSchemaIncompatible gate.Reason = "capability evidence does not match the requested SCUM capability" return gate } if !sameSCUMBinding(evidence.Binding, active) { gate.ReasonCode = SCUMSafeErrorBindingMismatch gate.Reason = "evidence belongs to a different server, Run binding, plugin, adapter, game, or database identity" return gate } if evidence.AdapterVersion != requirement.AdapterVersion { gate.ReasonCode = SCUMSafeErrorAdapterMismatch gate.Reason = "evidence adapter version does not match the plugin requirement" return gate } if evidence.SchemaFingerprint == "" || evidence.SchemaFingerprint != requirement.SchemaFingerprint { gate.ReasonCode = SCUMSafeErrorFingerprintMismatch gate.Reason = "schema fingerprint does not match the plugin requirement" return gate } if !containsAllStrings(evidence.AssetDigests, requirement.AssetDigests) { gate.ReasonCode = SCUMSafeErrorDigestMismatch gate.Reason = "packaged asset digest does not match the compatible evidence" return gate } if !evidence.ExpiresAt.IsZero() && !now.IsZero() && !now.Before(evidence.ExpiresAt) { gate.ReasonCode = SCUMSafeErrorEvidenceExpired gate.Reason = "current-service evidence has expired and must be probed again" return gate } gate.State = SCUMCapabilityGateEnabled gate.Enabled = true gate.ReasonCode = SCUMSafeErrorNone gate.Reason = "current-service evidence matches the versioned plugin adapter" return gate } func CopySCUMCapabilityEvidence(value SCUMCapabilityEvidence) SCUMCapabilityEvidence { value.AssetDigests = append([]string(nil), value.AssetDigests...) return value } func CopySCUMSQLiteTemplateRequestPtr(value *SCUMSQLiteTemplateRequest) *SCUMSQLiteTemplateRequest { if value == nil { return nil } copy := *value copy.Parameters = CopySCUMValueMap(value.Parameters) return © } func CopySCUMSQLiteTemplateResultPtr(value *SCUMSQLiteTemplateResult) *SCUMSQLiteTemplateResult { if value == nil { return nil } copy := *value copy.Rows = CopySCUMRows(value.Rows) return © } func CopySCUMValueMap(value map[string]any) map[string]any { if value == nil { return nil } copy := make(map[string]any, len(value)) for key, item := range value { copy[key] = item } return copy } func CopySCUMRows(rows []map[string]any) []map[string]any { if rows == nil { return nil } copy := make([]map[string]any, len(rows)) for index, row := range rows { copy[index] = CopySCUMValueMap(row) } return copy } func CopySCUMSchemaProbeResult(value SCUMSchemaProbeResult) SCUMSchemaProbeResult { value.Objects = append([]SCUMSchemaObjectEvidence(nil), value.Objects...) for index := range value.Objects { value.Objects[index].DeclaredColumns = append([]SCUMSchemaColumnEvidence(nil), value.Objects[index].DeclaredColumns...) value.Objects[index].Indexes = append([]SCUMSchemaIndexEvidence(nil), value.Objects[index].Indexes...) value.Objects[index].ForeignKeys = append([]SCUMSchemaForeignKeyEvidence(nil), value.Objects[index].ForeignKeys...) value.Objects[index].SampleFingerprints = append([]string(nil), value.Objects[index].SampleFingerprints...) for idx := range value.Objects[index].Indexes { value.Objects[index].Indexes[idx].ColumnHashes = append([]string(nil), value.Objects[index].Indexes[idx].ColumnHashes...) } } return value } func CopySCUMSchemaProbeRequestPtr(value *SCUMSchemaProbeRequest) *SCUMSchemaProbeRequest { if value == nil { return nil } copy := *value return © } func CopySCUMSchemaProbeResultPtr(value *SCUMSchemaProbeResult) *SCUMSchemaProbeResult { if value == nil { return nil } copy := CopySCUMSchemaProbeResult(*value) return © } func CopySCUMLiveDataManifest(value SCUMLiveDataManifest) SCUMLiveDataManifest { value.CapabilityGates = append([]SCUMLiveDataCapabilityGateDeclaration(nil), value.CapabilityGates...) for index := range value.CapabilityGates { value.CapabilityGates[index].RequiredAssetDigests = append([]string(nil), value.CapabilityGates[index].RequiredAssetDigests...) } return value } func sameSCUMBinding(a SCUMBindingIdentity, b SCUMBindingIdentity) bool { return a.ServerInstanceID == b.ServerInstanceID && a.RunBindingID == b.RunBindingID && a.RunEndpointID == b.RunEndpointID && a.PluginID == b.PluginID && a.PluginVersion == b.PluginVersion && a.AdapterVersion == b.AdapterVersion && a.GameVersion == b.GameVersion && a.DatabaseIdentity == b.DatabaseIdentity } func containsAllStrings(values []string, required []string) bool { set := map[string]struct{}{} for _, value := range values { set[value] = struct{}{} } for _, value := range required { if _, ok := set[value]; !ok { return false } } return true } func safeReason(value string, fallback string) string { if value == "" { return fallback } return value }