5.4 KiB
Context
ServerDeploymentDefinition currently carries generic mode, paths, commands, and create inputs. dispatchLifecycleJob forwards that definition, while projectLifecycleJobResult only projects a generic ready/running/stopped state. The SCUM manifest has a SteamCMD app id and create fields, but no contract tying those fields to a real SCUM config file or verification evidence. The Run executor is a separate repository, so Platform must define a complete, bounded wire contract without pretending to implement host execution locally.
Goals / Non-Goals
Goals:
- Make install and adoption separate operations with authoritative Run preflight.
- Freeze a SCUM template into each leased job so plugin changes cannot mutate an in-flight deployment.
- Return safe, structured scan/config/verification projections that the future UI can render.
- Keep all raw paths, commands, credentials, and sockets inside Run; public Platform views expose only configured flags, logical keys, facts, and stable error codes.
- Preserve idempotency, retry, cancellation, and channel separation already used by lifecycle jobs.
Non-Goals:
- Implementing SteamCMD, SCUM binaries, Windows process control, or filesystem scanning in this repository.
- Allowing arbitrary plugin commands, arbitrary config paths, or direct browser-to-Run access.
- Replacing the existing generic lifecycle protocol for non-SCUM plugins.
Decisions
1. Add a typed SCUM deployment template to runtime profiles
Add serverDeployments to GamePluginRuntimeProfiles. A profile contains a stable key/version, target OS/architecture, Steam app id, executable marker, install root logical key, config file logical key, field-to-config mappings, discovery markers, and verification checks. The SCUM manifest declares one Windows template for app 3792580 and explicit mappings for serverName, gamePort, queryPort, and maxPlayers.
This is preferred over teaching Run to infer SCUM behavior from createInputs or free-form action JSON. Inference would make the same directory mean different things in different versions and would be impossible to audit.
2. Freeze the template into the leased assignment
JobExecutionInput gains a ServerDeploymentPlan containing schemaVersion, operation (install or adopt), template identity, and bounded template data. The existing protected ServerDeploymentDefinition remains the source of operator paths/commands. DTO conversion exposes the plan only in RunJobAssignmentResponse.executionInput, never in browser-facing job or server responses.
3. Return bounded lifecycle evidence through the terminal result
JobExecutionResult gains an optional ServerDeploymentEvidence object. It records preflight checks, discovery facts (executable/version/ports/config/log markers as logical names), config mapping outcomes, verification checks, and a stable failure code. Values are bounded and path/command redacted. Platform persists a safe projection on ServerInstance and only projects ready when the required verification checks pass.
This uses the existing job result channel so control, logs, and artifacts remain independent. Large scan output or logs use existing artifact/log channels and are referenced, not inlined.
4. Use explicit install/adopt operation semantics
Guided install dispatches install: preflight → SteamCMD install → config materialization → launch/status health checks. Existing-server adoption dispatches adopt: preflight → scan → optional reviewed config mapping → status health checks. A failed scan never silently falls back to install, and a failed verification projects failed with an actionable code.
5. Persist safe projection, not host evidence
Add a ServerDeploymentProjection to ServerInstance with state, operation, template key/version, safe discovered facts, mapping status, verification status, failure code, and timestamps. No raw path, command, credential, process id, or socket appears in the projection or DTO.
Risks / Trade-offs
- [Run is in an independent repository] -> Version the contract and add fixture-based Platform tests; mark real execution dependent on the coordinated Run implementation.
- [Existing installations have different config layouts] -> Discovery reports marker confidence and config mapping status; adoption requires explicit operator approval when mapping is incomplete.
- [Evidence can grow large] -> Enforce bounded counts/lengths and use artifact references for detailed reports.
- [Old Run versions cannot understand the plan] -> Gate dispatch on a new capability string and reject before changing server state.
Migration Plan
- Ship additive domain/DTO/protocol types and manifest declarations; old plugins continue using the legacy lifecycle path.
- Gate SCUM controlled install/adopt on
deployment.scum.v1capability. Existing genericdeployment.plan.v1remains valid for other plugins. - Coordinate the independent Run implementation and enable the capability only after its contract tests pass.
- Update the frontend to render the persisted projection and evidence; rollback leaves legacy deployments untouched.
Open Questions
- The exact SCUM config filename can vary by distribution. The first template uses the known
ServerSettings.inilogical marker and allows Run to report a discovered alternate marker without exposing its absolute path; a later template version can add mappings without changing the Platform projection.