80 lines
5.3 KiB
Markdown
80 lines
5.3 KiB
Markdown
## Context
|
|
|
|
The platform already has a `RunEndpoint` domain resource and generic create/list/detail API. The run executable currently only produces a smoke summary and a base URL-normalizing client. The architecture requires a high-priority control channel for hello, heartbeat, version, capability, and capacity metadata before later job/log/artifact channels are implemented.
|
|
|
|
This change implements the first control-channel workflow across `run/` and `platform/`. It stays on HTTP JSON and in-memory platform storage because persistence and streaming transport are later changes. The control payloads must remain small and must not carry logs, artifact chunks, job result bodies, host paths, raw credentials, or direct sockets.
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
|
|
- Define typed run control protocol payloads in `run/protocol` and matching platform DTOs in `platform/dto`.
|
|
- Add platform control routes for hello registration and heartbeat.
|
|
- Persist/update run endpoint metadata through `service.Core` with validation and capability/capacity checks.
|
|
- Generate platform session tokens on hello and require the matching token on heartbeat.
|
|
- Add run-side client methods for hello and heartbeat.
|
|
- Add tests for protocol shape, platform service/API behavior, run client requests, and a registration/heartbeat integration flow.
|
|
|
|
**Non-Goals:**
|
|
|
|
- No job claim, ack, progress, result, cancel, or reconcile channel.
|
|
- No log ingest, artifact transfer, or game client bridge behavior.
|
|
- No WebSocket/gRPC streaming transport.
|
|
- No persistent database, token vault, mTLS, or auth policy engine.
|
|
- No frontend pages, plugin behavior, billing, cloud host sales, or direct plugin-to-run access.
|
|
|
|
## Decisions
|
|
|
|
### Decision 1: HTTP JSON control endpoints
|
|
|
|
The initial control channel uses `POST /api/v1/run/control/hello` and `POST /api/v1/run/control/heartbeat`. This matches the existing platform API shape and keeps the first registration workflow testable without introducing a streaming dependency.
|
|
|
|
Alternative considered: one long-lived WebSocket. Rejected because the architecture explicitly separates control from heavier job/log/artifact channels and later transport choices should be made after the metadata loop is stable.
|
|
|
|
### Decision 2: Session token is platform-generated and in-memory
|
|
|
|
Hello returns a deterministic session token derived from platform-side session state. Heartbeat must echo that token for the same run endpoint. The in-memory repository remains the backing state for now.
|
|
|
|
Alternative considered: accepting a run-provided session token. Rejected because platform must own control session acceptance and future auth hardening.
|
|
|
|
### Decision 3: Run endpoint metadata remains the platform source of truth
|
|
|
|
Hello and heartbeat write to the existing `RunEndpoint` domain resource. This avoids a separate control-session aggregate until persistence and auth requirements need it.
|
|
|
|
Alternative considered: adding a new run session table/model now. Rejected because current storage is in-memory and this change only needs one active session per run endpoint.
|
|
|
|
### Decision 4: Capability fingerprint is metadata only
|
|
|
|
Heartbeat accepts a compact capability fingerprint and may request a capability refresh when it differs from platform metadata. The full capability list is still kept on the run endpoint payload.
|
|
|
|
Alternative considered: transmitting full capability metadata on every heartbeat. Rejected because control payloads must stay small.
|
|
|
|
### Decision 5: Run client stays transport-only
|
|
|
|
`run/api.PlatformClient` will encode/decode control requests and responses, but runtime scheduling, retry loops, and background heartbeat timers remain future work.
|
|
|
|
Alternative considered: starting a daemon heartbeat loop in this change. Rejected because that would expand scope beyond registration and complicate tests before job/log/artifact channels exist.
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- [Risk] In-memory session tokens disappear on platform restart. Mitigation: document this as early development behavior and keep token handling behind `service.Core` for future persistence.
|
|
- [Risk] Capability fingerprint refresh cannot carry detailed capability changes alone. Mitigation: heartbeat returns `refreshCapabilities` and later changes can add a capability report endpoint.
|
|
- [Risk] No auth layer means registration token validation is minimal. Mitigation: require a non-empty registration token now and leave credential verification to the auth/control hardening change.
|
|
- [Risk] Run client has methods but no daemon loop. Mitigation: keep this change testable and defer scheduling/retry policy to later run lifecycle work.
|
|
|
|
## Migration Plan
|
|
|
|
1. Add control protocol and DTO contracts.
|
|
2. Add platform service methods and API handlers for hello/heartbeat.
|
|
3. Add run client methods and tests for request/response behavior.
|
|
4. Update protocol/route docs.
|
|
5. Verify with platform tests, run tests, structure check, and strict OpenSpec validation.
|
|
|
|
Rollback before dependent changes is removal of the control route/client additions and this OpenSpec change. After job/log/artifact changes depend on registered run endpoints, rollback must use a new OpenSpec change.
|
|
|
|
## Open Questions
|
|
|
|
- What registration credential source will replace the development registration token?
|
|
- Should session tokens become signed JWTs, opaque DB-backed tokens, or mTLS-bound session identifiers?
|
|
- What heartbeat interval and timeout thresholds should production use?
|