7.9 KiB
Run Protocol Contracts
The platform side of run communication is split into independent contracts.
Control
Implemented HTTP JSON routes:
POST /api/v1/run/control/helloPOST /api/v1/run/control/heartbeat
Named control DTOs:
RunHelloRequestRunHelloResponseRunHeartbeatRequestRunHeartbeatResponseRunCapabilityReportRunCapacityReport
Control payloads must remain small and must not include logs, artifact chunks, host paths, raw credentials, direct sockets, or long task results. Hello creates or updates run endpoint metadata and issues an in-memory platform session token. A server-scoped generated Run must use the endpoint identity reserved for its server; Platform rejects a valid component key presented for another endpoint. Heartbeat requires that active session token and may request capability refresh when the fingerprint changes.
Capacity reports include bounded maxJobs, runningJobs, queuedJobs, logBacklogBatches, artifactBacklogChunks, and enumerated pressure codes. They report queue and spool counts only, never log bodies, artifact chunks, machine paths, PIDs, sockets, credentials, or transport endpoints.
Control is the highest-priority run/platform path. Artifact/file transfer load must not delay heartbeat acceptance or mutate heartbeat capacity state through heavy payload fields.
Job
Implemented HTTP JSON routes:
POST /api/v1/run/jobs/claimPOST /api/v1/run/jobs/ackPOST /api/v1/run/jobs/progressPOST /api/v1/run/jobs/resultPOST /api/v1/run/jobs/cancelPOST /api/v1/run/jobs/reconcile
Named job DTOs:
RunJobClaimRequestRunJobClaimResponseRunJobAckRequestRunJobProgressRequestRunJobResultRequestRunJobCancelPollRequestRunJobReconcileRequestRunJobReconcileResponse
Jobs must carry bounded metadata such as jobId, runEndpointId, serverInstanceId, capability, idempotencyKey, lease token, attempt, progress, terminal state, message, error code, and result reference. Job payloads must not carry logs, artifact chunks, host paths, raw credentials, direct sockets, or large inline result bodies.
Plugin lifecycle assignments may add only a validated plugin identifier, enumerated lifecycle operation, target version, and logical workspace scope. Install, enable, disable, upgrade, rollback, retire, and dependency-check remain Platform-authorized jobs; assignments cannot carry arbitrary shell, provider configuration, raw credentials, host paths, PIDs, sockets, DSNs, or RCON secrets.
Approved config.write and bounded files.read/files.write assignments carry logical keys, scoped refs, and compare-and-swap revision/checksum inputs. Run executes them inside its scoped workspace with atomic writes and returns bounded logical result metadata; resolved machine paths remain Run-local.
Job ack, progress, cancellation polling, reconciliation, and terminal result calls are lightweight lifecycle metadata. They must remain valid while artifact chunks or log retries are pending, and duplicate equivalent terminal results remain idempotent under channel pressure.
Log Ingest
Implemented HTTP JSON routes:
POST /api/v1/run/logs/batchesPOST /api/v1/log-streams/query
Named log DTOs:
LogBatchIngestRequestLogBatchIngestResponseLogEntryLogStreamCursorRequestLogStreamCursorResponse
Log ingest supports bounded batches, sequence ranges, checksum validation, retry-safe duplicate acknowledgement, latest sequence tracking, and cursor query. Log payloads must not carry artifact chunks, host paths, raw credentials, direct sockets, or unbounded inline data.
Log ingest is durable and independently retried. Artifact/file transfer backlog must not prevent log batch acknowledgement, duplicate acknowledgement, cursor state updates, or spool cleanup.
The platform stores log stream metadata through repo.Store and stores log bodies through the configured LogBodyStore. The default file backend persists platform metadata to PLATFORM_METADATA_PATH and appends log entries to segmented JSONL files under PLATFORM_LOG_DIR; the memory backend is only for tests and disposable local development. MySQL/Postgres are appropriate for platform metadata, stream state, retention policy, indexes, and audit records, but should not be the primary row-per-log-line store for hundreds or thousands of servers. Production log bodies should move behind the same boundary to append/query backends such as ClickHouse, Loki, OpenSearch/Elasticsearch, or object-storage segments with compact indexes.
Artifact
Implemented HTTP JSON routes:
POST /api/v1/run/artifacts/openPOST /api/v1/run/artifacts/chunksPOST /api/v1/run/artifacts/statusPOST /api/v1/run/artifacts/complete
Named artifact DTOs:
ArtifactTransferOpenRequestArtifactTransferOpenResponseArtifactChunkUploadRequestArtifactChunkUploadResponseArtifactTransferStatusRequestArtifactTransferStatusResponseArtifactTransferCompleteRequestArtifactTransferCompleteResponseArtifactResponse
Artifact upload supports active run session validation, job/server-instance owner scoping, bounded JSON chunk payloads, per-chunk checksum validation, duplicate chunk acknowledgement, resume status, and final checksum verification before an artifact becomes available. Artifact transport is separate from control, job result, log ingest, plugin bridge, and browser file APIs.
Artifact/file transfer is the lower-priority heavy channel. Chunk upload and completion must not block control heartbeat, job ack/result delivery, cancellation/reconcile calls, or log ingest acknowledgement. Lightweight routes must reject heavy transfer payloads instead of accepting or storing them.
Client Manager lifecycle channel
Client Manager lifecycle jobs use the independent capabilities client-manager.deploy, client-manager.control, client-manager.update, client-manager.rollback, and client-manager.uninstall. Run obtains a fenced logical contract from POST /api/v1/run/jobs/client-manager-input and reads resumable artifact chunks from POST /api/v1/run/jobs/client-manager-chunk; these routes are separate from artifact upload, Run control, logs, and optional game-client traffic. The contract carries installation/profile, target, version/revision, checksum, deployment/key generations, fixed executable reference, bounded arguments/timeouts, and idempotency. For a plugin-declared companion profile it also carries a generic companionConfig materialization contract: safe relative template/schema/output references, the fenced component identity, declared component capabilities, Platform URL source, proof environment-variable name, component-session/TLS policy, and bounded timing values.
Run materializes the declared output such as config.yaml from the fenced values and its own configured Platform control URL. Source template values are not credentials and must not override the generated component identity or policy. The lifecycle input never contains the component proof itself, a component session, a browser credential, a host path, or a direct socket; proof remains inside the component package and is supplied to the supervised process only through the declared environment-variable name.
Run persists staging/active/previous slots and a local journal. It rejects stale lease/attempt/generation/target fences, traversal/link/device-file archives, checksum mismatches, undeclared executables, and arbitrary shell. Terminal results use client-manager.deployed, client-manager.controlled, client-manager.updated, client-manager.rolled-back, client-manager.rollback.restored, or client-manager.uninstalled with logical process/health state only. A stalled Client Manager download must not delay Run heartbeat, job ack/result/cancel, or log spool acknowledgement.
Game Client Bridge
The optional game client bridge is separate from run lifecycle, control registration, job handling, log ingest, and artifact transport.