docs: finalize rvbox v1 design and implementation plan

This commit is contained in:
2026-08-24 06:23:17 +00:00
parent 97c2d5cf45
commit a89253be96
13 changed files with 2490 additions and 190 deletions
+86 -21
View File
@@ -12,32 +12,83 @@ an optional JSON-RPC 2.0 HTTP adapter for local debugging and batch automation.
It has no authentication by design. Binding it beyond loopback is an explicit
deployment choice and requires external protection.
gRPC can stream `RunCommandAndFollow` and `FollowCommand`. JSON-RPC remains
simple: callers issue work, query command state, poll event/output pages after
an event sequence, append stdin, close stdin, or signal a command. It does not
invent a separate event-stream protocol.
gRPC streams command history and live events through `FollowCommand`. JSON-RPC
remains simple: callers issue work, query command state, poll event/output pages
after an event sequence, append stdin, close stdin, or signal a command. It does
not invent a separate event-stream protocol.
The JSON-RPC method names are the lower-camel protobuf operation names:
`listClients`, `getClient`, `listCommands`, `getCommand`, `runCommand`,
`appendStdin`, `closeStdin`, `signalCommand`, and `getOutput`. Parameters and
results use protobuf JSON mapping (including base64 strings for `bytes` and UTC
RFC 3339 strings for timestamps); JSON-RPC errors carry the corresponding
`ControlError` code/data. `getOutput` and `getCommand` are the polling path for
what gRPC exposes as follow streams.
`appendStdin`, `closeStdin`, `signalCommand`, `getOutput`, and the three storage
incident methods documented below. Parameters and results use protobuf JSON
mapping (including base64 strings for `bytes` and UTC RFC 3339 strings for
timestamps). Control response messages contain successful results only. gRPC
failures use canonical non-OK status codes with structured RVBox details where
needed; the JSON-RPC adapter maps the same domain errors to standard JSON-RPC
error objects. `getOutput` and `getCommand` are the polling path for what gRPC
exposes as follow streams.
`rvc stat CLIENT` also shows the active durable client-instance ID and the most
recent different instance rejected while that client is live. An operator may
run `rvc client takeover CLIENT INSTANCE-ID`; this creates a one-shot 5-minute
authorization for that exact pending claim. Its matching reconnect consumes the
authorization and fences the old session. If the old session is no longer live,
the replacement connects normally without this command. The JSON-RPC method is
`authorizeClientTakeover`.
Both transports enforce the same decoded field limits. A control gRPC request
may be at most 16 MiB; a JSON-RPC HTTP body may be at most 24 MiB to accommodate
base64 expansion of the 10 MiB script maximum. `ExecutionSpec` itself may be at
most 768 KiB, which also keeps its agent dispatch below the 1 MiB envelope cap.
## CLI semantics
`rvc stat` maps to `ListClients`, `GetClient`, `ListCommands`, and `GetCommand`.
History pages default to 20 commands and may request at most 100. Output pages
default to 100 lines; a line is a display operation over ordered chunks, not a
protocol boundary. Output can be filtered by stream and timestamped with the
server's recorded client-observed timestamp plus stream name.
History pages default to 20 commands and may request at most 100. Historical
output uses opaque, byte-bounded cursors and may resume within an output event;
it is not numbered or paginated by lines. The server returns uncompressed output
slices with event sequence, byte offset, stream, observed timestamp, and server
receipt timestamp. `rvc` may render line-oriented human output, but line
boundaries are not storage or pagination boundaries.
`rvc run` creates a command. Foreground mode runs `RunCommandAndFollow`, which
streams output and stops on a terminal event. `--background` uses `RunCommand`
and returns the UUID immediately. Interrupting the CLI, timing out its local
wait, or losing the local control connection never cancels remote work. The
explicit `rvc kill` operation is the only termination path.
`rvc run` always creates a durable command through unary `RunCommand`, which
returns the UUID. Foreground mode then calls `FollowCommand` with that UUID,
`after_event_seq=0`, and `include_existing=true`, streaming output until a
terminal event. `--background` returns immediately after `RunCommand`.
Interrupting the CLI, timing out its local wait, or losing the local control
connection never cancels remote work. The explicit `rvc kill` operation is the
only termination path. A foreground caller can resume `FollowCommand` after its
last received event sequence without missing durable history.
`FollowCommandResponse` wraps either a client-sequenced `CommandEvent` or a
server-created retention marker and exposes server receipt/recording time
separately from client observation time. A retention marker does not advance the
resume cursor. When retained history is incomplete, the server emits the relevant
marker before any terminal event on that stream, so a follower never stops on
terminal while believing truncated history was complete.
Mutating requests accept an optional `request_id`. `rvc` generates one per
mutation and reuses it for transport retries; `--request-id` lets automation
reuse it across CLI invocations. The CLI accepts that option globally and drops
it for reads. For `RunCommand`, the supplied request ID is the command's
`issue_uuid`. For stdin, close, signal, repair, and acknowledgement operations
it deduplicates that action while `issue_uuid` or `incident_id` continues to
identify the target. The server generates a request ID when omitted, preserving
simple JSON-RPC use.
The server stores the mutation kind, target, immutable request hash, and result
under that ID. An identical retry returns the original result; reuse with any
different method, target, or content returns `CONFLICT`. The record is owned by
the affected command or incident for quota and retention. A retry after that
owner has been reclaimed cannot repeat the action: it returns retained
tombstone information where available or `NOT_FOUND`.
`rvc run --queue-ttl` controls how long work may wait for server-confirmed
acceptance and defaults to 15 minutes; zero means indefinite. `rvc stat`
distinguishes terminal `Expired`, `Expired (awaiting reconciliation)`, and
actual lifecycle with a late-after-expiry warning. It renders terminal
`Rejected` with the client's structured validation/platform reason; `Failed`
means the requested code actually launched.
`rvc append` turns a string into `StdinWrite` with `append_newline=true` unless
the caller selects raw mode; `--file` supplies raw bytes; `--attach` streams
@@ -53,6 +104,20 @@ must not be shown as a terminal state. Pagination response cursors are stable
within their declared ordering (newest issue time for command lists; increasing
`event_seq` for events/output).
The service returns `ControlError` codes for not found, offline, capacity,
invalid request, unsupported platform feature, conflict, truncation, and
internal/transient errors. It never encodes errors only as CLI text.
Control failures are never embedded in otherwise-successful response messages.
They use canonical gRPC status codes with structured RVBox details; JSON-RPC
returns the corresponding JSON-RPC error object, and `rvc` maps the same domain
error to a stable exit code rather than parsing text.
## Storage incidents
`rvc storage incidents` lists unresolved storage incidents by default and can
include resolved history. `rvc storage repair INCIDENT` attempts only a known
safe repair. `rvc storage acknowledge INCIDENT --note ...` accepts documented
irrecoverable loss and clears that incident from dirty health. Both mutations
use the same optional `--request-id` behavior as other mutations. An
acknowledgement note is required and bounded to 4 KiB. Repair or acknowledgement
changes incident state; it does not delete history as part of that action;
resolved history later follows the independent audit/incident quota. The
JSON-RPC equivalents are `listStorageIncidents`,
`repairStorageIncident`, and `acknowledgeStorageIncident`.