The mission vertical is EARL as the governed authorization boundary for autonomous systems. The EARL engine proposes mission-plan updates (re-route, reassign, retarget, reposition, a sensor task, an engagement). The boundary judges each proposal against your systems of record and a sealed rule set. Three things can happen:
Every proposal, review and refused attempt is a signed record. You can read and verify it on the platform and offline.
Status: developmental (gated). Not for unattended use. The reference deployment is SYNTHETIC end to end: synthetic rules, platforms, tracks, areas and ROE, from a littoral exercise world. Nothing here touches a real vehicle, area or track. Read capability-limitations before relying on it.
Nothing of the engine is shipped to you. You reach it by credential, through this platform, in the same protocol as every other capability.
Each application gets its own gateway, deployed from the platform.
creating, then running.Two-person control. The account that deploys the gateway controls who may authorize, so it cannot also be an authorizer; the form does not offer it and the platform refuses it.
Who designated whom is a signed record (designate_authorizers) on the application's workflow. Only the
account that deployed the gateway (or a platform administrator) can stop it, start it or change its authorizers.
Any other account of the organization, an authorizer included, cannot rewrite the registry it is checked against;
its attempt is refused (403) and is a signed deployment_control record.
When the platform installs a newer mission image, the deployer sees Upgrade to the installed image: the gateway
is recreated on it with its volumes kept, so its record continues, and the move is a signed upgrade_gateway record
naming both images. Each decision and intake-refusal record names the mission gateway version that made it
(mission_gateway_version; gateway_version is the version of the governance gateway it is built on); resolutions,
refused authorizations and executions follow their decision in the same chain and carry no version of their own.
What the deployment is:
In Mission · propose, signed in as a user account (an auditor cannot propose: a released movement executes
with no human review), pick a synthetic sample, or paste your own proposal, and Submit proposal. The panel
shows the decision, the rule, the level an authorization would need, and every gate: a fact computed from the
systems of record (platform online, waypoints inside the operations area, outside every no-fly area, track on file,
identified hostile, custody held, ROE permits, weapon-capable). Every gate is computed for every proposal, so a
movement's record also shows the engagement gates; the rule named in the decision says which facts it needed. In the
gateway (0.3.0 and later) also reports the rule's requirements (rule_checks): the facts the sealed rules for
this action check, what each rule requires (holds, or does not hold) and whether it was met. A blocked proposal names
the requirements it did not meet. In the synthetic ROE, weapons_tight permits engaging a target positively identified as hostile, which is why
roe_permits_engagement holds under it. Each sample states the decision the synthetic world expects, so you can
check the gateway against it.
The same proposal submitted twice is judged twice and opens two reviews. Each review says so. It is executed at most once (see below).
Two input formats are accepted:
application/xml). The proposal is a <detail><earl …> element inside the event
(abridged; the console's samples are exact):xml
<event version='2.0' uid='UAS-04' type='a-f-A-M-F-Q' how='m-g' time='…' start='…' stale='…'>
<point lat='31.535' lon='34.66' hae='120' ce='9999999' le='9999999'/>
<detail>
<earl proposal_id='p-1' action='engage' platform_id='UAS-04' requested_at='…'>
<proposer id='swarm-coordinator-m34' kind='system' confidence='0.5'/>
<target designation='OVERWATCH CHARLIE' track_id='CHARLIE' lat='31.535' lon='34.66'/>
<waypoint seq='1' lat='31.535' lon='34.66' alt_m='120'/>
<basis>what the proposer says supports it</basis>
</earl>
</detail>
</event>
A position report (no <earl> element) is refused, not guessed. A document with a DOCTYPE or an entity
declaration is refused.
- QGroundControl .plan (application/json). The mission items are the route. An earl object at the top level
carries the proposer, platform, action and basis. A route without it is refused.
The proposer's confidence and basis are recorded and never used in the decision. The facts on file decide.
Engagements wait in Mission · authorize. Only a designated authorizer at the required level is offered Approve, Deny or Withdraw. Each row shows what you would authorize: the action, the platform, the target and track, the proposal id, the proposer's stated basis (recorded, never used), the gates at the decision, and any other decision on the same proposal.
You resolve as yourself. The platform sends your signed-in account to the gateway, which checks it against your deployment's authorizers and the level the action requires. You never type a name. These rules always apply, and each refusal is a signed record answered with HTTP 409:
withdrawn_by_proposer. A proposer who is not an
authorizer cannot resolve anything; an authorizer denies its proposal. A proposal made through an application key is held against the account that
minted that key: that account cannot approve it either, and a key minted by an auditor cannot propose.The platform checks the proposer, auditor, workflow and typed-name rules before anything reaches the gateway; those refusals are on the platform's record only. The gateway checks the authorizer registry, the level, the duplicate and the gates, and records its refusals in its own record too. (The platform also refuses the duplicate up front.)
An approved engagement is executed once. The resolution record's request names the reviewer, the decision
record it resolved, the proposer and the reviewer's note. From gateway 0.3.0 the gateway's execution record names
its authorization (the approving resolution record and the reviewer), and the full verifier checks it (M7).
Limits. In the synthetic world the systems of record are a fixed file: executing an engagement does not change the track or the platform's state, so a new, separate proposal for the same target is judged on the same facts. A deployment of yours pins your own systems of record. A pending review does not expire.
There are two records, and you can check both.
The platform's record. Every call is a row in Records: what it was (mission · propose, mission ·
resolve, mission · designate_authorizers), and one line saying what happened (the decision; approve or deny of
which decision, by whom, and how it ended; a refusal and its code). Show result gives the full request and
result. Verify checks the record's Ed25519 signature against the issuer key the platform publishes at
GET /api/v1/capabilities. Records can also be verified offline: see evidence-and-policy.
The gateway's own record. Download the gateway's own record (or
GET /api/v1/workflows/{id}/mission/gateway-record) gives the gateway's hash-chained, signed record (every decision,
intake refusal, resolution, refused authorization and execution) with the gateway's public key. It is checkable with
nothing else:
import hashlib, json
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
body = json.load(open("mission-gateway-record-workflow-93.json"))
key, prev = Ed25519PublicKey.from_public_bytes(bytes.fromhex(body["gateway_public_key"])), ""
for i, r in enumerate(body["records"], 1):
core = {"seq": r["seq"], "prev": r["prev"], "kind": r["kind"], "core": r["core"]}
h = hashlib.sha256(json.dumps(core, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode()).hexdigest()
assert r["seq"] == i and r["prev"] == prev and h == r["record_hash"], i
key.verify(bytes.fromhex(r["signature"]), bytes.fromhex(r["record_hash"])) # raises if forged
prev = r["record_hash"]
print(len(body["records"]), "records: chain and signatures hold")
This shows the chain is complete and unaltered under that key. The platform pins the key: when a gateway
(0.3.0 and later) comes up, the platform records its key in a signed pin_gateway_key record, and the download
reports pinned_gateway_key and whether the served key matches it. Check the platform record's signature, then the
chain under the pinned key: the key is then vouched for by the platform, not only served by the gateway. A changed
key is pinned again, on record. The full verifier, which also recomputes every gate against the stored
systems-of-record snapshots and checks executed-once, ships inside the mission image and is not served by the
platform yet.
An auditor account reads and verifies everything in its organization. It cannot propose, authorize, deploy, stop or change authorizers.
from earl_sdk import EarlClient
client = EarlClient(BASE_URL, TOKEN) # an account token, or an application key (earl_ak_...)
app = client.application(APP_ID)
app.deploy_mission([{"username": "maj.levi", "level": 3}]) # then poll app.mission_deployment() until running
wf = client.workflow(app.mission_deployment()["workflow_id"])
out = wf.mission_propose(cot_xml) # out.result["gateway"]["decision"]: release / review / block / refused
pending = wf.mission_reviews() # this workflow's reviews only
# signed in as an authorizer (not the proposer); read pending[0]["proposal"] and ["gates"] first:
wf.mission_resolve(pending[0]["record"], "approve", note="custody confirmed")
chain = wf.mission_gateway_record() # the gateway's own record, with its public key
The REST routes are the same: POST /api/v1/workflows/{id}/mission/propose, GET …/mission/reviews,
POST …/mission/reviews/{record}, GET …/mission/gateway-record, and …/applications/{id}/mission-deployment (/authorizers, /start, /stop, /upgrade).
The full schema is at /api/docs.