feat(scum): remove legacy workflow client surfaces
This commit is contained in:
@@ -431,12 +431,12 @@ func (svc *CoreService) applySCUMSQLiteMutationApprovalGate(operation domain.SCU
|
||||
state, err := svc.latestSCUMPlayerLiveState(operation.ServerInstanceID, operation.PlayerID)
|
||||
if err != nil {
|
||||
if err == repo.ErrNotFound {
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepWaiting, "等待真实玩家投影", "需要先从当前服务的登录日志或 SCUM.db 读取玩家数据。")
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepWaiting, "等待当前玩家数据", "需要先从当前服务的登录日志或 SCUM.db 读取玩家数据。")
|
||||
}
|
||||
return domain.SCUMOperationRequest{}, false, err
|
||||
}
|
||||
if state.Freshness.Status != domain.SCUMProjectionFresh {
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepWaiting, "等待新鲜投影", "玩家投影不是 fresh,需先刷新 SCUM.db/readback。")
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepWaiting, "等待当前数据", "玩家数据还未通过当前服务读回确认。")
|
||||
}
|
||||
if template.Safety.RequiresOfflinePlayer && state.Online {
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepWaiting, "等待玩家离线", "DB-only 玩家字段修改必须等玩家离线或进入维护窗口。")
|
||||
@@ -449,10 +449,10 @@ func (svc *CoreService) applySCUMSQLiteMutationApprovalGate(operation domain.SCU
|
||||
}
|
||||
current, ok := scumCurrentMutationFieldValue(state, operation.Guard.FieldKey)
|
||||
if !ok {
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepWaiting, "等待字段读回", "当前投影没有该 DB-only 字段,需先执行确认查询。")
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepWaiting, "等待字段读回", "当前本地数据没有该 DB-only 字段,需先完成确认查询。")
|
||||
}
|
||||
if !scumScalarEqual(current, operation.Guard.Before) {
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepBlocked, "before value 已过期", "当前投影值与审批时 before guard 不一致,已阻止写入。")
|
||||
return svc.updateSCUMOperationGate(operation, domain.SCUMWorkflowStepBlocked, "before value 已过期", "当前字段值与提交时 before guard 不一致,已阻止写入。")
|
||||
}
|
||||
return domain.CopySCUMOperationRequest(operation), true, nil
|
||||
}
|
||||
@@ -624,7 +624,7 @@ func scumSQLiteMutationSafeSummary(templateKey, playerID string, guard domain.SC
|
||||
if guard.BackupRef != "" {
|
||||
details["backupRef"] = guard.BackupRef
|
||||
}
|
||||
return domain.SCUMSafeSummary{Title: "Typed SCUM DB mutation", Message: "Run executes this through a declared mutation template with before-value and row-bound guards; raw SQL is not stored.", Details: details}
|
||||
return domain.SCUMSafeSummary{Title: "Declared SCUM DB mutation", Message: "Run executes this through a declared mutation template with before-value and row-bound guards; raw SQL is not stored.", Details: details}
|
||||
}
|
||||
|
||||
func operationInteger(payload map[string]any, keys ...string) (int64, bool) {
|
||||
@@ -757,7 +757,7 @@ func operationSafeSummary(templateKey, playerID string, payload map[string]any)
|
||||
if amount, ok := operationInteger(payload, "fame", "amount", "balance", "value", "normalBalance", "goldBalance"); ok {
|
||||
details["value"] = fmt.Sprintf("%d", amount)
|
||||
}
|
||||
return domain.SCUMSafeSummary{Title: "Typed SCUM operation", Message: "RCON text is generated server-side and is not stored in the operation record.", Details: details}
|
||||
return domain.SCUMSafeSummary{Title: "Declared SCUM action", Message: "RCON text is generated server-side and is not stored in the local record.", Details: details}
|
||||
}
|
||||
|
||||
func scumOperationTemplate(plugin domain.GamePlugin, key string) (domain.GameClientBridgeOperationTemplateDeclaration, bool) {
|
||||
|
||||
@@ -46,7 +46,7 @@ func (svc *CoreService) ApplySCUMObservationResult(result domain.SCUMObservation
|
||||
if result.Status == domain.SCUMObservationAccepted && !latest.ObservedAt.IsZero() && scumObservationOlder(result, latest) {
|
||||
result.Status = domain.SCUMObservationStale
|
||||
result.ErrorCode = "older_observation"
|
||||
result.SafeSummary = domain.SCUMSafeSummary{Title: "旧观察已忽略", Message: "Run 返回的 SCUM.db 观察早于当前本地投影,未覆盖 last-known-good 数据。"}
|
||||
result.SafeSummary = domain.SCUMSafeSummary{Title: "旧数据已忽略", Message: "Run 返回的 SCUM.db 数据早于当前本地记录,未覆盖 last-known-good 数据。"}
|
||||
}
|
||||
observation := domain.SCUMDataObservation{ID: scumObservationID(result), ServerInstanceID: result.ServerInstanceID, PluginID: result.PluginID, Source: result.Source, QueryKey: result.QueryKey, Sequence: result.Sequence, Checksum: result.Checksum, Status: result.Status, ErrorCode: result.ErrorCode, SafeSummary: result.SafeSummary, ObservedAt: result.ObservedAt, ReceivedAt: result.ReceivedAt}
|
||||
if err := svc.upsertSCUMObservation(observation); err != nil {
|
||||
|
||||
@@ -58,7 +58,7 @@ func (svc *CoreService) CreateSCUMWorkflowForSession(sessionID, serverID string,
|
||||
return domain.SCUMWorkflowInstance{}, err
|
||||
}
|
||||
stamp := svc.now()
|
||||
workflow := domain.SCUMWorkflowInstance{ID: "scum-workflow-" + fingerprintID(serverID, request.IdempotencyKey), ServerInstanceID: serverID, PluginID: plugin.ID, TemplateKey: template.Key, RequestedBy: user.ID, IdempotencyKey: request.IdempotencyKey, Status: domain.SCUMWorkflowQueued, Input: domain.CopyGameClientBridgePayload(request.Input), SafeSummary: domain.SCUMSafeSummary{Title: template.Title, Message: "SCUM workflow queued with typed steps and safe summaries."}, CreatedAt: stamp, UpdatedAt: stamp}
|
||||
workflow := domain.SCUMWorkflowInstance{ID: "scum-workflow-" + fingerprintID(serverID, request.IdempotencyKey), ServerInstanceID: serverID, PluginID: plugin.ID, TemplateKey: template.Key, RequestedBy: user.ID, IdempotencyKey: request.IdempotencyKey, Status: domain.SCUMWorkflowQueued, Input: domain.CopyGameClientBridgePayload(request.Input), SafeSummary: domain.SCUMSafeSummary{Title: template.Title, Message: "SCUM background sequence queued with declared steps and safe summaries."}, CreatedAt: stamp, UpdatedAt: stamp}
|
||||
if err := svc.store.SCUMWorkflowInstances().Create(workflow); err != nil {
|
||||
return domain.SCUMWorkflowInstance{}, err
|
||||
}
|
||||
@@ -199,7 +199,7 @@ func (svc *CoreService) RetrySCUMWorkflowStep(stepID string) (domain.SCUMWorkflo
|
||||
return domain.SCUMWorkflowStep{}, validationError("SCUM workflow step retry limit reached")
|
||||
}
|
||||
if step.MutatesState && step.Status == domain.SCUMWorkflowStepUnknown && step.Confirmation.Status != "confirmed" {
|
||||
step.SafeSummary = domain.SCUMSafeSummary{Title: "确认后才能重试", Message: "State-changing SCUM step is unknown; workflow must run confirmation/readback before retry to avoid duplicate effects."}
|
||||
step.SafeSummary = domain.SCUMSafeSummary{Title: "确认后才能重试", Message: "State-changing SCUM step is unknown; confirmation/readback must complete before retry to avoid duplicate effects."}
|
||||
step.UpdatedAt = svc.now()
|
||||
if err := svc.store.SCUMWorkflowSteps().Update(step); err != nil {
|
||||
return domain.SCUMWorkflowStep{}, err
|
||||
@@ -380,14 +380,14 @@ func scumWorkflowTemplates() map[string]scumWorkflowTemplateDefinition {
|
||||
protectedSQL := domain.JobCapabilityRemoteRunProtectedSQL
|
||||
rcon := domain.JobCapabilityRemoteRunRCONCommand
|
||||
return map[string]scumWorkflowTemplateDefinition{
|
||||
"scum.bootstrap-real-data": {Key: "scum.bootstrap-real-data", Title: "Bootstrap SCUM real data", Steps: []scumWorkflowStepDefinition{{Key: "verify-run-binding", Capability: read, TargetKey: "scum-database", Summary: "Verify run binding and SCUM.db query capability."}, {Key: "schema-probe", DependsOn: []string{"verify-run-binding"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.schema.probe", Summary: "Probe SCUM.db schema before projection refresh."}, {Key: "login-cursor", DependsOn: []string{"schema-probe"}, Capability: logs, TargetKey: "scum-login", Summary: "Initialize login log observation cursor."}}},
|
||||
"scum.bootstrap-real-data": {Key: "scum.bootstrap-real-data", Title: "Bootstrap SCUM data", Steps: []scumWorkflowStepDefinition{{Key: "verify-run-binding", Capability: read, TargetKey: "scum-database", Summary: "Verify run binding and SCUM.db query capability."}, {Key: "schema-probe", DependsOn: []string{"verify-run-binding"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.schema.probe", Summary: "Probe SCUM.db schema before local sync."}, {Key: "login-cursor", DependsOn: []string{"schema-probe"}, Capability: logs, TargetKey: "scum-login", Summary: "Initialize login log cursor."}}},
|
||||
"scum.player-refresh": {Key: "scum.player-refresh", Title: "Refresh SCUM player", Steps: []scumWorkflowStepDefinition{{Key: "login-evidence", Capability: logs, TargetKey: "scum-login", Summary: "Sync login/logout evidence."}, {Key: "player-profile", DependsOn: []string{"login-evidence"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.player.profile", Summary: "Read player profile/economy facts."}, {Key: "position-read", DependsOn: []string{"player-profile"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.positions", Summary: "Read current player coordinates."}}},
|
||||
"scum.world-refresh": {Key: "scum.world-refresh", Title: "Refresh SCUM world", Steps: []scumWorkflowStepDefinition{{Key: "squad-read", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.squads", MaxAttempts: 2, Summary: "Refresh squads."}, {Key: "vehicle-read", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.vehicles", MaxAttempts: 2, Summary: "Refresh vehicles."}, {Key: "flag-read", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.flags", MaxAttempts: 2, Summary: "Refresh flags."}, {Key: "position-read", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.positions", MaxAttempts: 2, Summary: "Refresh map positions."}}},
|
||||
"scum.player-correction": {Key: "scum.player-correction", Title: "SCUM player correction", Steps: []scumWorkflowStepDefinition{{Key: "safety-check", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.player.profile", Summary: "Verify current projection, before value, offline state, and backup evidence."}, {Key: "apply-operation", DependsOn: []string{"safety-check"}, Capability: protectedSQL, TargetKey: "scum-database", OperationKey: "player.attribute.855.set", MutatesState: true, Summary: "Apply the approved typed operation through Run."}, {Key: "confirmation-read", DependsOn: []string{"apply-operation"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.player.profile", Summary: "Confirm the requested value by readback."}}},
|
||||
"scum.gift-delivery": {Key: "scum.gift-delivery", Title: "SCUM gift delivery", Steps: []scumWorkflowStepDefinition{{Key: "eligibility-check", Summary: "Evaluate gift eligibility and idempotency."}, {Key: "deliver-reward", DependsOn: []string{"eligibility-check"}, Capability: rcon, TargetKey: "scum-management", OperationKey: "reward.deliver", MutatesState: true, MaxAttempts: 2, Summary: "Deliver approved reward through typed operation."}, {Key: "notify-player", DependsOn: []string{"deliver-reward"}, Capability: rcon, TargetKey: "scum-management", OperationKey: "player.notify", MutatesState: true, Summary: "Notify the player after delivery."}, {Key: "confirmation-read", DependsOn: []string{"notify-player"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.player.profile", Summary: "Confirm grant state/readback before marking delivered."}}},
|
||||
"scum.territory-audit": {Key: "scum.territory-audit", Title: "SCUM territory audit", Steps: []scumWorkflowStepDefinition{{Key: "squad-roster", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.squad-members", Summary: "Refresh squad rosters."}, {Key: "flag-ownership", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.flags", Summary: "Refresh flag ownership."}, {Key: "risk-signal", DependsOn: []string{"squad-roster", "flag-ownership"}, Summary: "Project stale owner/member risk signals."}}},
|
||||
"scum.vehicle-audit": {Key: "scum.vehicle-audit", Title: "SCUM vehicle audit", Steps: []scumWorkflowStepDefinition{{Key: "vehicle-read", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.vehicles", Summary: "Refresh vehicle inventory."}, {Key: "vehicle-map", DependsOn: []string{"vehicle-read"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.positions", Summary: "Refresh vehicle map overlays."}}},
|
||||
"scum.ai-assist": {Key: "scum.ai-assist", Title: "SCUM AI assist", Steps: []scumWorkflowStepDefinition{{Key: "collect-allowed-fields", Summary: "Collect plugin-declared config fields and workflow inputs."}, {Key: "draft-review", DependsOn: []string{"collect-allowed-fields"}, Summary: "Create a reviewable typed diff or workflow draft."}, {Key: "approved-dispatch", DependsOn: []string{"draft-review"}, MutatesState: true, Summary: "Dispatch only after human approval through typed paths."}}},
|
||||
"scum.product-cleanup": {Key: "scum.product-cleanup", Title: "SCUM product cleanup", Steps: []scumWorkflowStepDefinition{{Key: "remove-raw-routes", Summary: "Remove raw logs, terminal, config, and operation-history product routes."}, {Key: "publish-safe-status", DependsOn: []string{"remove-raw-routes"}, Summary: "Route users to safe workflow/status surfaces."}}},
|
||||
"scum.player-correction": {Key: "scum.player-correction", Title: "SCUM player correction", Steps: []scumWorkflowStepDefinition{{Key: "safety-check", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.player.profile", Summary: "Verify current local data, before value, offline state, and backup evidence."}, {Key: "apply-operation", DependsOn: []string{"safety-check"}, Capability: protectedSQL, TargetKey: "scum-database", OperationKey: "player.attribute.855.set", MutatesState: true, Summary: "Apply the approved declared action through Run."}, {Key: "confirmation-read", DependsOn: []string{"apply-operation"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.player.profile", Summary: "Confirm the requested value by readback."}}},
|
||||
"scum.gift-delivery": {Key: "scum.gift-delivery", Title: "SCUM gift delivery", Steps: []scumWorkflowStepDefinition{{Key: "eligibility-check", Summary: "Evaluate gift eligibility and idempotency."}, {Key: "deliver-reward", DependsOn: []string{"eligibility-check"}, Capability: rcon, TargetKey: "scum-management", OperationKey: "reward.deliver", MutatesState: true, MaxAttempts: 2, Summary: "Deliver approved reward through the declared action."}, {Key: "notify-player", DependsOn: []string{"deliver-reward"}, Capability: rcon, TargetKey: "scum-management", OperationKey: "player.notify", MutatesState: true, Summary: "Notify the player after delivery."}, {Key: "confirmation-read", DependsOn: []string{"notify-player"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.player.profile", Summary: "Confirm grant state/readback before marking delivered."}}},
|
||||
"scum.territory-audit": {Key: "scum.territory-audit", Title: "SCUM territory check", Steps: []scumWorkflowStepDefinition{{Key: "squad-roster", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.squad-members", Summary: "Refresh squad rosters."}, {Key: "flag-ownership", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.flags", Summary: "Refresh flag ownership."}, {Key: "risk-signal", DependsOn: []string{"squad-roster", "flag-ownership"}, Summary: "Compare owner/member consistency signals."}}},
|
||||
"scum.vehicle-audit": {Key: "scum.vehicle-audit", Title: "SCUM vehicle check", Steps: []scumWorkflowStepDefinition{{Key: "vehicle-read", Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.vehicles", Summary: "Refresh vehicle inventory."}, {Key: "vehicle-map", DependsOn: []string{"vehicle-read"}, Capability: read, TargetKey: "scum-database", QueryTemplateKey: "scum.positions", Summary: "Refresh vehicle map overlays."}}},
|
||||
"scum.ai-assist": {Key: "scum.ai-assist", Title: "SCUM AI assist", Steps: []scumWorkflowStepDefinition{{Key: "collect-allowed-fields", Summary: "Collect plugin-declared config fields and player draft inputs."}, {Key: "draft-review", DependsOn: []string{"collect-allowed-fields"}, Summary: "Create a reviewable config diff or named-field draft."}, {Key: "approved-dispatch", DependsOn: []string{"draft-review"}, MutatesState: true, Summary: "Dispatch only after human confirmation through declared paths."}}},
|
||||
"scum.product-cleanup": {Key: "scum.product-cleanup", Title: "SCUM product cleanup", Steps: []scumWorkflowStepDefinition{{Key: "remove-raw-routes", Summary: "Remove raw logs, terminal, config, and operation-history product routes."}, {Key: "publish-safe-status", DependsOn: []string{"remove-raw-routes"}, Summary: "Route users to safe local status surfaces."}}},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user