Relay
The relay is where your client connects. It exposes the same
PolicySession.Run as a station and pipes your stream onto the runner
waiting for your job id. It runs on the workstation behind a port-forward
today and can move to a cloud host without changing what you send.
Pairing
- One client stream per job at a time. A second connection to a live job is
refused with
JOB_BUSY. - If the client stream is lost while the runner remains attached, a new connection presenting the same job id is paired to that runner. The runner's handling of the interruption is described under rules.
- A job id nobody is waiting for is refused with
UNKNOWN_JOB.
Polling job status
Service JobStatus, package se3labs.eval.policy.v1. Its messages are
msg.StatusRequest and msg.Status:
service JobStatus {
rpc Get(StatusRequest) returns (Status);
}
message StatusRequest { string job_id = 1; }
message Status {
string job_id = 1;
string state = 2; // CREATED … SUCCEEDED / FAILED / CANCELLED
uint32 episode_index = 3;
uint32 episodes_total = 4;
map<string, uint32> outcomes = 5; // success, failure, indeterminate, invalidated
int64 updated_unix_ms = 6;
string message = 7;
}
From the command line:
se3labs eval status --job job_… --address relay.example.com:7443
se3labs eval status --job job_… --address relay.example.com:7443 --json
The runner pushes status on every state transition. The relay keeps it in
memory and, when started with --snapshot, in a JSON file that survives a
restart. Nothing else is stored.
from se3labs.eval import policy
status = policy.get_status("job_…", "relay.example.com:7443")
print(status.state, status.episode_index, "/", status.episodes_total, dict(status.outcomes))
get_status raises grpc.RpcError with status NOT_FOUND for a job id the
relay has never seen.
Transport security
The relay listens in plaintext on the LAN today. The client's --secure
flag and serve_policy(secure=True) use TLS with system roots for when the
relay moves off the LAN.