Technical article
The robot AI approval gate: from edge inference candidate to one-shot submit
RobotEdgeInferenceSrv and the robot AI approval API show how an AI-proposed robot command reaches dispatch only after policy validation, signed provider approval, and a one-shot submit — with every bypass path failing closed.
AI output is a proposal, not a command
Edge models can suggest high-level robot commands, but a suggestion must never reach dispatch directly. LightESB-Camel treats AI output as a candidate: it cannot declare its own source identity, risk level, policy version, or approval result, and the normal command API rejects AI-reserved command IDs with 422 ROBOT_AI_APPROVAL_REQUIRED.
From candidate to persisted decision
Every step is explicit; missing or incomplete configuration fails closed.
Policy validation
Candidates are checked against allowlisted commands, confidence thresholds, freshness windows, identity binding, anti-replay, and shared safety policies. Failures return rejected with a specific error code.
Explicit enablement
The capability is off by default. Enabling it requires a global HMAC provider configuration plus an approval switch in the service route, and secrets are injected through environment variables — never written to files, logs, or responses.
Persisted decision
Safe candidates become server-side validation decisions with an expiry derived from inference freshness, command TTL, and the configured maximum decision age. A pending decision is not an approval.
HMAC approval callback
The configured provider signs callbacks with HMAC-SHA256 over the raw request body. Verified callbacks move the decision to approved or rejected; retries are idempotent, and same-ID different-body replays return 409.
One-shot submit through the decision-only path
Submitting an approved decision takes no command payload. The server restores the candidate from the persisted decision, re-verifies the digest, denylist, capability, and current safety policy, then writes command, audit, outbox, state snapshot, and the consumed binding in one transaction — any failure rolls everything back.
The CLI mirrors this boundary: it can query a decision and submit it with --yes, but it cannot approve or reject, never reads candidate command files, and never stores the HMAC secret. Expired decisions, replayed events, and double consumption all fail closed.
A mock boundary you can verify offline
RobotEdgeInferenceSrv ships as a direct: + mock: route package with server.running=false and no HTTP, MQTT, or gRPC ingress. Post robot-edge-inference.v1 JSON to direct:robot-edge-inference-mock and read decisions from mock:robotEdgeInferenceDecisionSink.
The fixed ingress profile is not production authentication, the in-memory replay registry covers a single instance only, and the HMAC provider contract still needs field verification against a real approval platform. The mock package exists to prove the gate semantics before that integration starts.
Try it yourself
- Copy example/routes/RobotEdgeInferenceSrv into the runtime service directory and keep server.running=false.
- Post a robot-edge-inference.v1 candidate to direct:robot-edge-inference-mock and read the decision from mock:robotEdgeInferenceDecisionSink.
- Confirm safe candidates return pending_approval with submittable=false, while stale, low-confidence, identity-mismatched, or replayed candidates return rejected.
- Enable the HMAC provider and the service approval switch, send a signed approval callback, then query and submit the decision with lightesb robot inference submit --yes.