@fleetless/contracts 4.0.0-next.1 → 5.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -5
- package/artifacts/constants.json +4 -14
- package/artifacts/openapi.json +46 -13
- package/artifacts/routes.json +2 -2
- package/artifacts/schema/bridge-hello.schema.json +1 -0
- package/artifacts/schema/bridge-job-status.schema.json +114 -0
- package/artifacts/schema/bridge-job-update.schema.json +21 -0
- package/artifacts/schema/busy-details.schema.json +12 -2
- package/artifacts/schema/cloud-job-query.schema.json +29 -0
- package/artifacts/schema/command-result.schema.json +12 -2
- package/artifacts/schema/invoke-or-service-response.schema.json +12 -2
- package/artifacts/schema/invoke-response.schema.json +12 -2
- package/artifacts/schema/job-event.schema.json +12 -2
- package/artifacts/schema/job-response.schema.json +12 -2
- package/artifacts/schema/job-run-list-response.schema.json +4 -3
- package/artifacts/schema/job-run-query.schema.json +2 -1
- package/artifacts/schema/job-run.schema.json +4 -3
- package/artifacts/schema/job-state.schema.json +1 -0
- package/artifacts/schema/job.schema.json +12 -2
- package/artifacts/schema/robot-jobs-response.schema.json +12 -2
- package/artifacts/schema-outgoing/bridge-hello.schema.json +1 -0
- package/artifacts/schema-outgoing/bridge-job-status.schema.json +117 -0
- package/artifacts/schema-outgoing/bridge-job-update.schema.json +21 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +39 -8
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/jobs.d.ts +55 -6
- package/dist/jobs.js +43 -14
- package/dist/protocol.d.ts +165 -44
- package/dist/protocol.js +144 -59
- package/dist/realtime.d.ts +5 -0
- package/dist/rest.d.ts +20 -0
- package/dist/routes.js +6 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,13 +11,43 @@ version.
|
|
|
11
11
|
|
|
12
12
|
### Added
|
|
13
13
|
|
|
14
|
+
- **Protocol 5: `unknown` jobs, external goals, and a hard cut of protocols 3
|
|
15
|
+
and 4.** `PROTOCOL_VERSION` is 5 and the only version served: protocols 2,
|
|
16
|
+
3 and 4 are unsupported from this release on, with no sunset window, and
|
|
17
|
+
`PROTOCOL_VERSIONS` holds the single entry `{ version: 5, bridge_from:
|
|
18
|
+
'6.0.0' }`; `LATEST_BRIDGE_VERSION` is `6.0.0`. `jobState` gains `unknown`,
|
|
19
|
+
a non-terminal state for a job the cloud has lost sight of — its error
|
|
20
|
+
`bridge_disconnected` or `bridge_timeout`, both of which used to settle the
|
|
21
|
+
job `lost` — so `lost` is final and only ever follows a statement of the
|
|
22
|
+
bridge. `job` gains a required `origin` (`jobOrigin`: `fleetless` or
|
|
23
|
+
`external`), and `job_update` gains a required `origin` and `goal_id`
|
|
24
|
+
(the ROS 2 goal id, `null` for a service job), because the bridge now
|
|
25
|
+
reports every goal on a published action, including ones it did not send.
|
|
26
|
+
New frames `job_query` (`cloudJobQuery`) and `job_status`
|
|
27
|
+
(`bridgeJobStatus`, `bridgeJobStatusEntry`) let the cloud ask a connected
|
|
28
|
+
bridge how specific jobs stand. New error codes: `bridge_too_old`, the
|
|
29
|
+
`hello_error` for a bridge below protocol 5, naming bridge `6.0.0`; and
|
|
30
|
+
`job_unknown_to_bridge`, the final `lost` reason when the bridge does not
|
|
31
|
+
know a job and nothing it cannot attribute runs on the job's action.
|
|
32
|
+
|
|
33
|
+
### Removed
|
|
34
|
+
|
|
35
|
+
- **Protocols 2, 3 and 4, and an origin-less `job`; this is why the release
|
|
36
|
+
is a major.** A bridge below `6.0.0` is refused at `hello`, and a `job` or
|
|
37
|
+
`job_update` literal without `origin` (or a `job_update` without
|
|
38
|
+
`goal_id`) no longer parses.
|
|
39
|
+
|
|
40
|
+
## [4.0.0] — 2026-09-29
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
14
44
|
- **Protocol 4: a job heartbeat, and a vanished action server ends its job.**
|
|
15
|
-
Protocol bumped: bridges from `
|
|
16
|
-
2026-12-
|
|
45
|
+
Protocol bumped: bridges from `5.0.0`, and protocol 3 sunsets
|
|
46
|
+
2026-12-28 (protocol 2 sunset 2026-12-21). The bridge now sends a
|
|
17
47
|
`job_update` heartbeat every `JOB_HEARTBEAT_INTERVAL_MS` for every running
|
|
18
|
-
job
|
|
19
|
-
|
|
20
|
-
|
|
48
|
+
job, and ends a job whose action server vanished `lost` with
|
|
49
|
+
`action_server_lost` instead of leaving the cloud to guess; `job_lost`
|
|
50
|
+
gains an optional `error` that can say the same. `JOB_HEARTBEAT_TIMEOUT_MS` bounds a protocol-4 job's
|
|
21
51
|
silence once it has been heard from at all; `patience_ms` now bounds only
|
|
22
52
|
the acceptance gap on such a job (unchanged for protocol 3, which sends no
|
|
23
53
|
heartbeat). `JOB_OFFLINE_GRACE_MS` (five minutes) replaces the informal
|
package/artifacts/constants.json
CHANGED
|
@@ -1,25 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"AUDIT_RETENTION_DAYS": 90,
|
|
3
|
-
"PROTOCOL_VERSION":
|
|
3
|
+
"PROTOCOL_VERSION": 5,
|
|
4
4
|
"PROTOCOL_VERSIONS": [
|
|
5
5
|
{
|
|
6
|
-
"version":
|
|
7
|
-
"bridge_from": "
|
|
8
|
-
"deprecated_at": "2026-09-22"
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"version": 3,
|
|
12
|
-
"bridge_from": "4.0.0",
|
|
13
|
-
"deprecated_at": "2026-09-28"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"version": 4,
|
|
17
|
-
"bridge_from": "4.1.0",
|
|
6
|
+
"version": 5,
|
|
7
|
+
"bridge_from": "6.0.0",
|
|
18
8
|
"deprecated_at": null
|
|
19
9
|
}
|
|
20
10
|
],
|
|
21
11
|
"PROTOCOL_SUNSET_DAYS": 90,
|
|
22
|
-
"LATEST_BRIDGE_VERSION": "
|
|
12
|
+
"LATEST_BRIDGE_VERSION": "6.0.0",
|
|
23
13
|
"CLOSE_ROBOT_DELETED": 4004,
|
|
24
14
|
"CLOSE_TOKEN_ROTATED": 4005,
|
|
25
15
|
"JOB_HEARTBEAT_INTERVAL_MS": 1000,
|
package/artifacts/openapi.json
CHANGED
|
@@ -6730,10 +6730,11 @@
|
|
|
6730
6730
|
"in": "query",
|
|
6731
6731
|
"required": false,
|
|
6732
6732
|
"schema": {
|
|
6733
|
-
"description": "Only runs in this state — `running`, `succeeded`, `failed`, `cancelled` or `lost`.",
|
|
6733
|
+
"description": "Only runs in this state — `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`.",
|
|
6734
6734
|
"type": "string",
|
|
6735
6735
|
"enum": [
|
|
6736
6736
|
"running",
|
|
6737
|
+
"unknown",
|
|
6737
6738
|
"succeeded",
|
|
6738
6739
|
"failed",
|
|
6739
6740
|
"cancelled",
|
|
@@ -6878,7 +6879,7 @@
|
|
|
6878
6879
|
}
|
|
6879
6880
|
}
|
|
6880
6881
|
},
|
|
6881
|
-
"description": "**One route for both kinds**, because a path segment naming the kind would demand a fact a role grant does not carry. An action answers `202` with an `invokeResponse` the moment the job exists; a service answers `200` with a `serviceCallResponse` once the result is in — two shapes, carried by one union (`invokeOrServiceResponse`) and told apart by whether `kind` or a bare `result` arrives. Parameters are checked **before** anything about the world (offline, busy): the same request must get the same verdict whether or not the robot happens to be reachable, or a developer testing against an offline robot never learns their parameters were wrong. A service the robot reports as failed answers `502` carrying **the job's own error code**, which is an open set and not one of the codes above.",
|
|
6882
|
+
"description": "**One route for both kinds**, because a path segment naming the kind would demand a fact a role grant does not carry. An action answers `202` with an `invokeResponse` the moment the job exists; a service answers `200` with a `serviceCallResponse` once the result is in — two shapes, carried by one union (`invokeOrServiceResponse`) and told apart by whether `kind` or a bare `result` arrives. Parameters are checked **before** anything about the world (offline, busy): the same request must get the same verdict whether or not the robot happens to be reachable, or a developer testing against an offline robot never learns their parameters were wrong. A slug is `409 busy` while it holds a `running` job, an `unknown` one the robot has not accounted for yet, or an `external` goal someone else started; the refusal's `details.running` names that job, `state` and `origin` included. A service the robot reports as failed answers `502` carrying **the job's own error code**, which is an open set and not one of the codes above.",
|
|
6882
6883
|
"requestBody": {
|
|
6883
6884
|
"required": true,
|
|
6884
6885
|
"content": {
|
|
@@ -7012,7 +7013,7 @@
|
|
|
7012
7013
|
}
|
|
7013
7014
|
}
|
|
7014
7015
|
},
|
|
7015
|
-
"description": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`.",
|
|
7016
|
+
"description": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`.",
|
|
7016
7017
|
"requestBody": {
|
|
7017
7018
|
"required": false,
|
|
7018
7019
|
"content": {
|
|
@@ -8188,10 +8189,11 @@
|
|
|
8188
8189
|
"in": "query",
|
|
8189
8190
|
"required": false,
|
|
8190
8191
|
"schema": {
|
|
8191
|
-
"description": "Only runs in this state — `running`, `succeeded`, `failed`, `cancelled` or `lost`.",
|
|
8192
|
+
"description": "Only runs in this state — `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`.",
|
|
8192
8193
|
"type": "string",
|
|
8193
8194
|
"enum": [
|
|
8194
8195
|
"running",
|
|
8196
|
+
"unknown",
|
|
8195
8197
|
"succeeded",
|
|
8196
8198
|
"failed",
|
|
8197
8199
|
"cancelled",
|
|
@@ -14608,12 +14610,21 @@
|
|
|
14608
14610
|
"type": "string",
|
|
14609
14611
|
"enum": [
|
|
14610
14612
|
"running",
|
|
14613
|
+
"unknown",
|
|
14611
14614
|
"succeeded",
|
|
14612
14615
|
"failed",
|
|
14613
14616
|
"cancelled",
|
|
14614
14617
|
"lost"
|
|
14615
14618
|
],
|
|
14616
|
-
"description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `
|
|
14619
|
+
"description": "Where the job stands: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. `unknown` is not an outcome — the robot went offline or silent and the cloud does not know yet; the slug stays occupied and the bridge's next statement resolves it, `error` naming why the cloud lost sight of it. `lost` is final: the bridge stated it does not know the job and nothing else runs on its action, or the action server vanished mid-goal."
|
|
14620
|
+
},
|
|
14621
|
+
"origin": {
|
|
14622
|
+
"type": "string",
|
|
14623
|
+
"enum": [
|
|
14624
|
+
"fleetless",
|
|
14625
|
+
"external"
|
|
14626
|
+
],
|
|
14627
|
+
"description": "Who started this job. `fleetless` for everything minted by the cloud; `external` for a goal the bridge found active on a published action without having sent it — no parameters, no starter, never written to `job_runs`."
|
|
14617
14628
|
},
|
|
14618
14629
|
"started_at": {
|
|
14619
14630
|
"type": "string",
|
|
@@ -14671,7 +14682,7 @@
|
|
|
14671
14682
|
"type": "null"
|
|
14672
14683
|
}
|
|
14673
14684
|
],
|
|
14674
|
-
"description": "Why the job failed: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. `
|
|
14685
|
+
"description": "Why the job failed, or why the cloud does not know how it stands: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. Set on `failed` and `lost`, and on `unknown` — where `code` is `bridge_disconnected` or `bridge_timeout`, the cloud's own reason for not knowing, cleared when the bridge reports the job running again."
|
|
14675
14686
|
}
|
|
14676
14687
|
},
|
|
14677
14688
|
"required": [
|
|
@@ -14679,6 +14690,7 @@
|
|
|
14679
14690
|
"robot_id",
|
|
14680
14691
|
"slug",
|
|
14681
14692
|
"state",
|
|
14693
|
+
"origin",
|
|
14682
14694
|
"started_at",
|
|
14683
14695
|
"updated_at",
|
|
14684
14696
|
"seq",
|
|
@@ -14770,12 +14782,21 @@
|
|
|
14770
14782
|
"type": "string",
|
|
14771
14783
|
"enum": [
|
|
14772
14784
|
"running",
|
|
14785
|
+
"unknown",
|
|
14773
14786
|
"succeeded",
|
|
14774
14787
|
"failed",
|
|
14775
14788
|
"cancelled",
|
|
14776
14789
|
"lost"
|
|
14777
14790
|
],
|
|
14778
|
-
"description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `
|
|
14791
|
+
"description": "Where the job stands: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. `unknown` is not an outcome — the robot went offline or silent and the cloud does not know yet; the slug stays occupied and the bridge's next statement resolves it, `error` naming why the cloud lost sight of it. `lost` is final: the bridge stated it does not know the job and nothing else runs on its action, or the action server vanished mid-goal."
|
|
14792
|
+
},
|
|
14793
|
+
"origin": {
|
|
14794
|
+
"type": "string",
|
|
14795
|
+
"enum": [
|
|
14796
|
+
"fleetless",
|
|
14797
|
+
"external"
|
|
14798
|
+
],
|
|
14799
|
+
"description": "Who started this job. `fleetless` for everything minted by the cloud; `external` for a goal the bridge found active on a published action without having sent it — no parameters, no starter, never written to `job_runs`."
|
|
14779
14800
|
},
|
|
14780
14801
|
"started_at": {
|
|
14781
14802
|
"type": "string",
|
|
@@ -14833,7 +14854,7 @@
|
|
|
14833
14854
|
"type": "null"
|
|
14834
14855
|
}
|
|
14835
14856
|
],
|
|
14836
|
-
"description": "Why the job failed: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. `
|
|
14857
|
+
"description": "Why the job failed, or why the cloud does not know how it stands: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. Set on `failed` and `lost`, and on `unknown` — where `code` is `bridge_disconnected` or `bridge_timeout`, the cloud's own reason for not knowing, cleared when the bridge reports the job running again."
|
|
14837
14858
|
}
|
|
14838
14859
|
},
|
|
14839
14860
|
"required": [
|
|
@@ -14841,6 +14862,7 @@
|
|
|
14841
14862
|
"robot_id",
|
|
14842
14863
|
"slug",
|
|
14843
14864
|
"state",
|
|
14865
|
+
"origin",
|
|
14844
14866
|
"started_at",
|
|
14845
14867
|
"updated_at",
|
|
14846
14868
|
"seq",
|
|
@@ -14900,12 +14922,13 @@
|
|
|
14900
14922
|
"type": "string",
|
|
14901
14923
|
"enum": [
|
|
14902
14924
|
"running",
|
|
14925
|
+
"unknown",
|
|
14903
14926
|
"succeeded",
|
|
14904
14927
|
"failed",
|
|
14905
14928
|
"cancelled",
|
|
14906
14929
|
"lost"
|
|
14907
14930
|
],
|
|
14908
|
-
"description": "How the run ended, or `running` while it is still going. `lost`
|
|
14931
|
+
"description": "How the run ended, or `running` while it is still going. `unknown` while the robot has not accounted for it — offline or silent — and updated once the bridge says how it stands. `lost` is final: the bridge did not know the run and nothing else ran on its action, so the outcome is unknowable rather than unknown."
|
|
14909
14932
|
},
|
|
14910
14933
|
"started_at": {
|
|
14911
14934
|
"type": "string",
|
|
@@ -14924,7 +14947,7 @@
|
|
|
14924
14947
|
"type": "null"
|
|
14925
14948
|
}
|
|
14926
14949
|
],
|
|
14927
|
-
"description": "When the run finished, as an ISO 8601 timestamp. `null` while it is still `running` — a run has an end only once it has one."
|
|
14950
|
+
"description": "When the run finished, as an ISO 8601 timestamp. `null` while it is still `running` or `unknown` — a run has an end only once it has one."
|
|
14928
14951
|
},
|
|
14929
14952
|
"duration_ms": {
|
|
14930
14953
|
"anyOf": [
|
|
@@ -14937,7 +14960,7 @@
|
|
|
14937
14960
|
"type": "null"
|
|
14938
14961
|
}
|
|
14939
14962
|
],
|
|
14940
|
-
"description": "How long the run took, in milliseconds. `null` while it is still `running`, never `0` standing in for \"nothing so far\"."
|
|
14963
|
+
"description": "How long the run took, in milliseconds. `null` while it is still `running` or `unknown`, never `0` standing in for \"nothing so far\"."
|
|
14941
14964
|
},
|
|
14942
14965
|
"result": {
|
|
14943
14966
|
"anyOf": [
|
|
@@ -17361,12 +17384,21 @@
|
|
|
17361
17384
|
"type": "string",
|
|
17362
17385
|
"enum": [
|
|
17363
17386
|
"running",
|
|
17387
|
+
"unknown",
|
|
17364
17388
|
"succeeded",
|
|
17365
17389
|
"failed",
|
|
17366
17390
|
"cancelled",
|
|
17367
17391
|
"lost"
|
|
17368
17392
|
],
|
|
17369
|
-
"description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `
|
|
17393
|
+
"description": "Where the job stands: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. `unknown` is not an outcome — the robot went offline or silent and the cloud does not know yet; the slug stays occupied and the bridge's next statement resolves it, `error` naming why the cloud lost sight of it. `lost` is final: the bridge stated it does not know the job and nothing else runs on its action, or the action server vanished mid-goal."
|
|
17394
|
+
},
|
|
17395
|
+
"origin": {
|
|
17396
|
+
"type": "string",
|
|
17397
|
+
"enum": [
|
|
17398
|
+
"fleetless",
|
|
17399
|
+
"external"
|
|
17400
|
+
],
|
|
17401
|
+
"description": "Who started this job. `fleetless` for everything minted by the cloud; `external` for a goal the bridge found active on a published action without having sent it — no parameters, no starter, never written to `job_runs`."
|
|
17370
17402
|
},
|
|
17371
17403
|
"started_at": {
|
|
17372
17404
|
"type": "string",
|
|
@@ -17424,7 +17456,7 @@
|
|
|
17424
17456
|
"type": "null"
|
|
17425
17457
|
}
|
|
17426
17458
|
],
|
|
17427
|
-
"description": "Why the job failed: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. `
|
|
17459
|
+
"description": "Why the job failed, or why the cloud does not know how it stands: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. Set on `failed` and `lost`, and on `unknown` — where `code` is `bridge_disconnected` or `bridge_timeout`, the cloud's own reason for not knowing, cleared when the bridge reports the job running again."
|
|
17428
17460
|
}
|
|
17429
17461
|
},
|
|
17430
17462
|
"required": [
|
|
@@ -17432,6 +17464,7 @@
|
|
|
17432
17464
|
"robot_id",
|
|
17433
17465
|
"slug",
|
|
17434
17466
|
"state",
|
|
17467
|
+
"origin",
|
|
17435
17468
|
"started_at",
|
|
17436
17469
|
"updated_at",
|
|
17437
17470
|
"seq",
|
package/artifacts/routes.json
CHANGED
|
@@ -4078,7 +4078,7 @@
|
|
|
4078
4078
|
"internal_error"
|
|
4079
4079
|
],
|
|
4080
4080
|
"transport": "http",
|
|
4081
|
-
"notes": "**One route for both kinds**, because a path segment naming the kind would demand a fact a role grant does not carry. An action answers `202` with an `invokeResponse` the moment the job exists; a service answers `200` with a `serviceCallResponse` once the result is in — two shapes, carried by one union (`invokeOrServiceResponse`) and told apart by whether `kind` or a bare `result` arrives. Parameters are checked **before** anything about the world (offline, busy): the same request must get the same verdict whether or not the robot happens to be reachable, or a developer testing against an offline robot never learns their parameters were wrong. A service the robot reports as failed answers `502` carrying **the job's own error code**, which is an open set and not one of the codes above."
|
|
4081
|
+
"notes": "**One route for both kinds**, because a path segment naming the kind would demand a fact a role grant does not carry. An action answers `202` with an `invokeResponse` the moment the job exists; a service answers `200` with a `serviceCallResponse` once the result is in — two shapes, carried by one union (`invokeOrServiceResponse`) and told apart by whether `kind` or a bare `result` arrives. Parameters are checked **before** anything about the world (offline, busy): the same request must get the same verdict whether or not the robot happens to be reachable, or a developer testing against an offline robot never learns their parameters were wrong. A slug is `409 busy` while it holds a `running` job, an `unknown` one the robot has not accounted for yet, or an `external` goal someone else started; the refusal's `details.running` names that job, `state` and `origin` included. A service the robot reports as failed answers `502` carrying **the job's own error code**, which is an open set and not one of the codes above."
|
|
4082
4082
|
},
|
|
4083
4083
|
{
|
|
4084
4084
|
"method": "GET",
|
|
@@ -4150,7 +4150,7 @@
|
|
|
4150
4150
|
"robot_offline"
|
|
4151
4151
|
],
|
|
4152
4152
|
"transport": "http",
|
|
4153
|
-
"notes": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`."
|
|
4153
|
+
"notes": "The body is optional: a bodyless `POST` was every caller's shape before `job_id` existed, and absent or `job_id: null` both mean \"cancel whatever is running\". A named `job_id` that is **not** what is running cancels nothing and answers `404` — the caller named an id and thereby ruled the other one out. An `external` job is cancelled the same way, through its goal id. Cancelling an `unknown` job also cancels every external goal on its action, since one of them may be that job. A service is `422 not_cancellable`: a service call has no goal to cancel. Nothing running is a `200` with `job: null`."
|
|
4154
4154
|
},
|
|
4155
4155
|
{
|
|
4156
4156
|
"method": "POST",
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"type": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"const": "job_status"
|
|
8
|
+
},
|
|
9
|
+
"request_id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"minLength": 1,
|
|
12
|
+
"maxLength": 64
|
|
13
|
+
},
|
|
14
|
+
"jobs": {
|
|
15
|
+
"type": "array",
|
|
16
|
+
"items": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"job_id": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"format": "uuid",
|
|
22
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
23
|
+
},
|
|
24
|
+
"state": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"enum": [
|
|
27
|
+
"running",
|
|
28
|
+
"unknown",
|
|
29
|
+
"succeeded",
|
|
30
|
+
"failed",
|
|
31
|
+
"cancelled",
|
|
32
|
+
"lost"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"feedback": {
|
|
36
|
+
"anyOf": [
|
|
37
|
+
{},
|
|
38
|
+
{
|
|
39
|
+
"type": "null"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"progress": {
|
|
44
|
+
"anyOf": [
|
|
45
|
+
{
|
|
46
|
+
"type": "number",
|
|
47
|
+
"minimum": 0,
|
|
48
|
+
"maximum": 1
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "null"
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"result": {
|
|
56
|
+
"anyOf": [
|
|
57
|
+
{},
|
|
58
|
+
{
|
|
59
|
+
"type": "null"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"error": {
|
|
64
|
+
"anyOf": [
|
|
65
|
+
{
|
|
66
|
+
"type": "object",
|
|
67
|
+
"properties": {
|
|
68
|
+
"code": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"minLength": 1
|
|
71
|
+
},
|
|
72
|
+
"message": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"minLength": 1
|
|
75
|
+
},
|
|
76
|
+
"details": {}
|
|
77
|
+
},
|
|
78
|
+
"required": [
|
|
79
|
+
"code",
|
|
80
|
+
"message"
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "null"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"required": [
|
|
90
|
+
"job_id",
|
|
91
|
+
"state",
|
|
92
|
+
"feedback",
|
|
93
|
+
"progress",
|
|
94
|
+
"result",
|
|
95
|
+
"error"
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"unknown_job_ids": {
|
|
100
|
+
"type": "array",
|
|
101
|
+
"items": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"format": "uuid",
|
|
104
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"required": [
|
|
109
|
+
"type",
|
|
110
|
+
"request_id",
|
|
111
|
+
"jobs",
|
|
112
|
+
"unknown_job_ids"
|
|
113
|
+
]
|
|
114
|
+
}
|
|
@@ -21,12 +21,31 @@
|
|
|
21
21
|
"type": "string",
|
|
22
22
|
"enum": [
|
|
23
23
|
"running",
|
|
24
|
+
"unknown",
|
|
24
25
|
"succeeded",
|
|
25
26
|
"failed",
|
|
26
27
|
"cancelled",
|
|
27
28
|
"lost"
|
|
28
29
|
]
|
|
29
30
|
},
|
|
31
|
+
"origin": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"enum": [
|
|
34
|
+
"fleetless",
|
|
35
|
+
"external"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"goal_id": {
|
|
39
|
+
"anyOf": [
|
|
40
|
+
{
|
|
41
|
+
"type": "string",
|
|
42
|
+
"minLength": 1
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"type": "null"
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
30
49
|
"feedback": {
|
|
31
50
|
"anyOf": [
|
|
32
51
|
{},
|
|
@@ -91,6 +110,8 @@
|
|
|
91
110
|
"job_id",
|
|
92
111
|
"slug",
|
|
93
112
|
"state",
|
|
113
|
+
"origin",
|
|
114
|
+
"goal_id",
|
|
94
115
|
"feedback",
|
|
95
116
|
"progress",
|
|
96
117
|
"result",
|
|
@@ -28,12 +28,21 @@
|
|
|
28
28
|
"type": "string",
|
|
29
29
|
"enum": [
|
|
30
30
|
"running",
|
|
31
|
+
"unknown",
|
|
31
32
|
"succeeded",
|
|
32
33
|
"failed",
|
|
33
34
|
"cancelled",
|
|
34
35
|
"lost"
|
|
35
36
|
],
|
|
36
|
-
"description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `
|
|
37
|
+
"description": "Where the job stands: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. `unknown` is not an outcome — the robot went offline or silent and the cloud does not know yet; the slug stays occupied and the bridge's next statement resolves it, `error` naming why the cloud lost sight of it. `lost` is final: the bridge stated it does not know the job and nothing else runs on its action, or the action server vanished mid-goal."
|
|
38
|
+
},
|
|
39
|
+
"origin": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"enum": [
|
|
42
|
+
"fleetless",
|
|
43
|
+
"external"
|
|
44
|
+
],
|
|
45
|
+
"description": "Who started this job. `fleetless` for everything minted by the cloud; `external` for a goal the bridge found active on a published action without having sent it — no parameters, no starter, never written to `job_runs`."
|
|
37
46
|
},
|
|
38
47
|
"started_at": {
|
|
39
48
|
"type": "string",
|
|
@@ -91,7 +100,7 @@
|
|
|
91
100
|
"type": "null"
|
|
92
101
|
}
|
|
93
102
|
],
|
|
94
|
-
"description": "Why the job failed: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. `
|
|
103
|
+
"description": "Why the job failed, or why the cloud does not know how it stands: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. Set on `failed` and `lost`, and on `unknown` — where `code` is `bridge_disconnected` or `bridge_timeout`, the cloud's own reason for not knowing, cleared when the bridge reports the job running again."
|
|
95
104
|
}
|
|
96
105
|
},
|
|
97
106
|
"required": [
|
|
@@ -99,6 +108,7 @@
|
|
|
99
108
|
"robot_id",
|
|
100
109
|
"slug",
|
|
101
110
|
"state",
|
|
111
|
+
"origin",
|
|
102
112
|
"started_at",
|
|
103
113
|
"updated_at",
|
|
104
114
|
"seq",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"type": {
|
|
6
|
+
"type": "string",
|
|
7
|
+
"const": "job_query"
|
|
8
|
+
},
|
|
9
|
+
"request_id": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"minLength": 1,
|
|
12
|
+
"maxLength": 64
|
|
13
|
+
},
|
|
14
|
+
"job_ids": {
|
|
15
|
+
"minItems": 1,
|
|
16
|
+
"type": "array",
|
|
17
|
+
"items": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"format": "uuid",
|
|
20
|
+
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": [
|
|
25
|
+
"type",
|
|
26
|
+
"request_id",
|
|
27
|
+
"job_ids"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -42,12 +42,21 @@
|
|
|
42
42
|
"type": "string",
|
|
43
43
|
"enum": [
|
|
44
44
|
"running",
|
|
45
|
+
"unknown",
|
|
45
46
|
"succeeded",
|
|
46
47
|
"failed",
|
|
47
48
|
"cancelled",
|
|
48
49
|
"lost"
|
|
49
50
|
],
|
|
50
|
-
"description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `
|
|
51
|
+
"description": "Where the job stands: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. `unknown` is not an outcome — the robot went offline or silent and the cloud does not know yet; the slug stays occupied and the bridge's next statement resolves it, `error` naming why the cloud lost sight of it. `lost` is final: the bridge stated it does not know the job and nothing else runs on its action, or the action server vanished mid-goal."
|
|
52
|
+
},
|
|
53
|
+
"origin": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"enum": [
|
|
56
|
+
"fleetless",
|
|
57
|
+
"external"
|
|
58
|
+
],
|
|
59
|
+
"description": "Who started this job. `fleetless` for everything minted by the cloud; `external` for a goal the bridge found active on a published action without having sent it — no parameters, no starter, never written to `job_runs`."
|
|
51
60
|
},
|
|
52
61
|
"started_at": {
|
|
53
62
|
"type": "string",
|
|
@@ -104,7 +113,7 @@
|
|
|
104
113
|
"type": "null"
|
|
105
114
|
}
|
|
106
115
|
],
|
|
107
|
-
"description": "Why the job failed: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. `
|
|
116
|
+
"description": "Why the job failed, or why the cloud does not know how it stands: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. Set on `failed` and `lost`, and on `unknown` — where `code` is `bridge_disconnected` or `bridge_timeout`, the cloud's own reason for not knowing, cleared when the bridge reports the job running again."
|
|
108
117
|
}
|
|
109
118
|
},
|
|
110
119
|
"required": [
|
|
@@ -112,6 +121,7 @@
|
|
|
112
121
|
"robot_id",
|
|
113
122
|
"slug",
|
|
114
123
|
"state",
|
|
124
|
+
"origin",
|
|
115
125
|
"started_at",
|
|
116
126
|
"updated_at",
|
|
117
127
|
"seq",
|
|
@@ -30,12 +30,21 @@
|
|
|
30
30
|
"type": "string",
|
|
31
31
|
"enum": [
|
|
32
32
|
"running",
|
|
33
|
+
"unknown",
|
|
33
34
|
"succeeded",
|
|
34
35
|
"failed",
|
|
35
36
|
"cancelled",
|
|
36
37
|
"lost"
|
|
37
38
|
],
|
|
38
|
-
"description": "Where the job stands: `running`, `succeeded`, `failed`, `cancelled` or `lost`. `
|
|
39
|
+
"description": "Where the job stands: `running`, `unknown`, `succeeded`, `failed`, `cancelled` or `lost`. `unknown` is not an outcome — the robot went offline or silent and the cloud does not know yet; the slug stays occupied and the bridge's next statement resolves it, `error` naming why the cloud lost sight of it. `lost` is final: the bridge stated it does not know the job and nothing else runs on its action, or the action server vanished mid-goal."
|
|
40
|
+
},
|
|
41
|
+
"origin": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"enum": [
|
|
44
|
+
"fleetless",
|
|
45
|
+
"external"
|
|
46
|
+
],
|
|
47
|
+
"description": "Who started this job. `fleetless` for everything minted by the cloud; `external` for a goal the bridge found active on a published action without having sent it — no parameters, no starter, never written to `job_runs`."
|
|
39
48
|
},
|
|
40
49
|
"started_at": {
|
|
41
50
|
"type": "string",
|
|
@@ -93,7 +102,7 @@
|
|
|
93
102
|
"type": "null"
|
|
94
103
|
}
|
|
95
104
|
],
|
|
96
|
-
"description": "Why the job failed: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. `
|
|
105
|
+
"description": "Why the job failed, or why the cloud does not know how it stands: a human `message`, a `code` where one exists, and `details` for the codes that carry a documented payload. Set on `failed` and `lost`, and on `unknown` — where `code` is `bridge_disconnected` or `bridge_timeout`, the cloud's own reason for not knowing, cleared when the bridge reports the job running again."
|
|
97
106
|
}
|
|
98
107
|
},
|
|
99
108
|
"required": [
|
|
@@ -101,6 +110,7 @@
|
|
|
101
110
|
"robot_id",
|
|
102
111
|
"slug",
|
|
103
112
|
"state",
|
|
113
|
+
"origin",
|
|
104
114
|
"started_at",
|
|
105
115
|
"updated_at",
|
|
106
116
|
"seq",
|