diff --git a/.config/mise/config.toml b/.config/mise/config.toml index 0232027d5..b2eb0e2c7 100644 --- a/.config/mise/config.toml +++ b/.config/mise/config.toml @@ -178,6 +178,10 @@ run = [ "jsonschema metaschema spec/workbench/draft.5/schemas", "jsonschema test spec/workbench/draft.5/tests -r spec/workbench/schemas -r spec/workbench/draft.5/schemas", "jsonschema validate spec/workbench/draft.5/schemas/mck-corpus.schema.json spec/workbench/mck/draft.5/cases.json -r spec/workbench/schemas -r spec/workbench/draft.5/schemas", + "jsonschema fmt spec/workbench/jobs/draft.1/schemas --check", + "jsonschema lint spec/workbench/jobs/draft.1/schemas -r spec/workbench/jobs/draft.1/schemas -r spec/workbench/draft.5/schemas -r spec/workbench/schemas", + "jsonschema metaschema spec/workbench/jobs/draft.1/schemas", + "jsonschema test spec/workbench/jobs/draft.1/tests -r spec/workbench/jobs/draft.1/schemas -r spec/workbench/draft.5/schemas -r spec/workbench/schemas", ] # Not part of `check`: website:build-schemas depends on website:install, whose diff --git a/spec/workbench/README.md b/spec/workbench/README.md index 52d83f41d..c783e7c38 100644 --- a/spec/workbench/README.md +++ b/spec/workbench/README.md @@ -171,3 +171,10 @@ terminal evidence to an admitted invocation suite and public manifest. Its [377-case kit](mck/draft.5/README.md) preserves returned values, SDK model errors, primary failures, cancellation and separate cleanup failures. Offline admission does not establish actual host execution or authoritative job cancellation. + +[Snapshot-bound job receipts](jobs/draft.1/README.md) define a separate exact +`morphir/workbench/jobs` `0.1.0-draft.1` profile. The portable reducer binds +authority, snapshot and call inventory; separates cancellation acknowledgement +from terminal evidence; and retains host receipts across same-session reconnect. +This contribution does not change any offline MCK draft or add live RPC methods. +Shared transition MCK qualification and authenticated host adapters remain pending. diff --git a/spec/workbench/jobs/draft.1/README.md b/spec/workbench/jobs/draft.1/README.md new file mode 100644 index 000000000..5ed5a69d0 --- /dev/null +++ b/spec/workbench/jobs/draft.1/README.md @@ -0,0 +1,128 @@ +# Snapshot-bound Workbench job receipts + +This transport-neutral profile is exactly `0.1.0-draft.1`, named +`morphir/workbench/jobs`. It is a new contract namespace, separate from value and +terminal admission drafts. Its terminal payload references the frozen +`0.1.0-draft.5` outcome envelope without changing it. + +This contribution defines receipt admission and client reduction. It does not +add JSON-RPC methods, authenticate hosts, execute jobs or advertise support in +the existing connected host. Connected `protocolVersion: 1`, generated-driver +v1 and the five offline Workbench MCK drafts remain unchanged. A host adapter +must implement and qualify the profile before a client enables live controls. + +## Authority and negotiation + +An authenticated host offers exactly: + +```json +{"profile":"morphir/workbench/jobs","contractVersion":"0.1.0-draft.1","hostId":"host","sessionId":"session","providerId":"provider","operations":["query","cancel"]} +``` + +`query` is required; `cancel` is optional. Operations are a unique set. Unknown +operations, members, profile names, versions and version build suffixes reject. +Only this exact prerelease is supported. No generic SemVer comparison is needed +for this fixed draft; a reader with version ranges must use a SemVer library. +An offline schema fixture is not a live capability advertisement. + +The caller obtains the expected binding from authenticated submission, never +from the receipt it is about to validate. The identity contains exactly +`hostId`, `sessionId`, `providerId`, `jobId` and `snapshotId`. Each contains +1 to 128 UTF-16 code units. The offer's first three fields must match. Provider +and snapshot are immutable for the job, including while reconnecting. A new +session or provider cannot borrow the old job's authority. A snapshot handle +denotes immutable execution input; it is not a local path or a content hash +unless a separately qualified host contract says so. + +Host authentication, provider trust, public-entry admission and snapshot +creation remain host responsibilities. The reducer checks binding and receipt +consistency, not cryptographic provenance. New project-scoped metadata bindings +must remain scoped when a host translates a planned engine job into this identity. + +## Receipts + +A receipt has exactly these six fields: + +```json +{"contractVersion":"0.1.0-draft.1","identity":{"hostId":"host","sessionId":"session","providerId":"provider","jobId":"job","snapshotId":"snapshot"},"sequence":0,"state":"submitted","cancelRequested":false,"outcomes":null} +``` + +| State | Outcomes | Meaning | +| --- | --- | --- | +| `submitted` | `null` | Host accepted this exact job and snapshot. | +| `running` | `null` | Host reports execution in progress. | +| `terminal` | Exact draft.5 envelope | Primary outcomes and separate cleanup are final. | + +Sequence numbers range from 0 through 2147483647 on every target. The initial +submission receipt is sequence 0, submitted, with `cancelRequested: false`. +Running and terminal receipts have positive sequences. Host revisions advance +for a state change or cancellation acknowledgement, not merely because a query +was issued. Polling may skip revisions; it does not require a complete event log. + +The client captures a nonempty ordered inventory of at most 1,000 invocation +call IDs at submission. IDs contain 1 to 128 UTF-16 units and are unique. A +terminal must have exactly that inventory, in order. Typed values retain the +draft.5 bounds and shape; the host must also admit every output against the +submitted manifest. This receipt reducer alone cannot establish output types. +`Result.Err` remains returned data. SDK errors, primary failures, cancellation +and cleanup keep their distinct variants. Cleanup never changes primary status. + +## Reduction and cancellation races + +Validate the entire supplied receipt and its identity before sequence handling. +Malformed or wrongly bound stale evidence rejects. With the exact binding: + +- A lower sequence is stale and leaves the cursor unchanged. +- An equal sequence and identical admitted payload is an idempotent replay. +- An equal sequence with conflicting payload rejects. +- A higher sequence can move submitted to running or directly to terminal. + Running cannot move back to submitted. Terminal is immutable. +- Cancellation acknowledgement can change false to true while submitted or + running. Once acknowledged it cannot return to false. It requires a negotiated + cancellation operation. The same state and acknowledgement cannot acquire a + new revision without a change. + +`cancelRequested` means the host acknowledged a request. It does not mean any +call terminated. Sending a client cancellation request changes no authoritative +receipt. A host may finish with returned values or failures after acknowledgement. +The host may also cancel by its own policy without a client request. The primary +terminal payload decides each call's outcome. + +If cancellation is unavailable, the client must not send it. If the job is +terminal, use the retained terminal rather than sending another request. If +disconnected, the client retains the last receipt and reports unavailable +transport. Disconnect and timeout are never synthesized as failed or cancelled +job receipts. A timeout can leave the host running. + +## Disconnect and reconnect + +Connection availability is client state, separate from submitted/running/terminal. +An offline cursor cannot adopt incoming receipts. Reconnect requires a newly +authenticated offer with the exact previous host, session, provider, draft and +operation set. It restores transport availability and permits a fresh query of +the existing identity. The ordinary stale/replay/advance rules admit that reply. + +This qualifies in-memory same-session reconciliation only. It does not promise +durable job retention, recovery after host restart, transferable sessions, +exactly-once submission or an authenticated transport implementation. A changed +session requires explicit host recovery support, not a fresh label on old evidence. + +## Bounds and qualification + +Raw receipt framing must be capped at 1 MiB before JSON parsing. JSON parsers at +the host boundary must reject duplicate members. Closed parsed shapes then feed +the portable reducer. No Ion receipt mapping is defined in this first job draft; +existing JSON and Ion evaluation inputs and outcome codecs remain supported. + +The schemas check shape, discriminants, closed members, versions and numeric +bounds. Schema string lengths count code points; the reducer enforces UTF-16 +identity limits. Sequence transitions, authority equality, call inventory, +acknowledgement monotonicity and authentication are semantic requirements, not +established by schema validation. + +Structural fixtures run through the existing `workbench:schema-check` task. +The MoonBit implementation has portable semantic tests on JS, native, Wasm and +Wasm GC. These are implementation tests, not a shared MCK adapter qualification +or evidence that the Rust connected host implements job execution. A future +shared MCK slice must add parent-owned transition goldens to the existing runner, +then qualify host adapters and bind query/cancel transport methods. diff --git a/spec/workbench/jobs/draft.1/schemas/identity.schema.json b/spec/workbench/jobs/draft.1/schemas/identity.schema.json new file mode 100644 index 000000000..3aa902ebe --- /dev/null +++ b/spec/workbench/jobs/draft.1/schemas/identity.schema.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://morphir.finos.org/spec/workbench/jobs/0.1.0-draft.1/identity.schema.json", + "title": "Snapshot-bound job identity", + "description": "Immutable host, session, provider, job and model snapshot binding. Identity strings also require bounded UTF-16 units in the reducer", + "examples": [ + { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + } + ], + "type": "object", + "required": [ "hostId", "sessionId", "providerId", "jobId", "snapshotId" ], + "properties": { + "hostId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "sessionId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "providerId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "jobId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "snapshotId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + "additionalProperties": false +} diff --git a/spec/workbench/jobs/draft.1/schemas/offer.schema.json b/spec/workbench/jobs/draft.1/schemas/offer.schema.json new file mode 100644 index 000000000..88884267b --- /dev/null +++ b/spec/workbench/jobs/draft.1/schemas/offer.schema.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://morphir.finos.org/spec/workbench/jobs/0.1.0-draft.1/offer.schema.json", + "title": "Exact Workbench jobs offer", + "description": "Exact prerelease receipt profile offered by an authenticated host. Query is required and cancellation is optional. This schema does not grant authority", + "examples": [ + { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ "query", "cancel" ] + } + ], + "type": "object", + "required": [ + "profile", + "contractVersion", + "hostId", + "sessionId", + "providerId", + "operations" + ], + "properties": { + "profile": { + "const": "morphir/workbench/jobs" + }, + "contractVersion": { + "const": "0.1.0-draft.1" + }, + "hostId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "sessionId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "providerId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "operations": { + "type": "array", + "maxItems": 2, + "minItems": 1, + "uniqueItems": true, + "contains": { + "const": "query" + }, + "items": { + "enum": [ "query", "cancel" ] + } + } + }, + "additionalProperties": false +} diff --git a/spec/workbench/jobs/draft.1/schemas/receipt.schema.json b/spec/workbench/jobs/draft.1/schemas/receipt.schema.json new file mode 100644 index 000000000..d3b60bc94 --- /dev/null +++ b/spec/workbench/jobs/draft.1/schemas/receipt.schema.json @@ -0,0 +1,122 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://morphir.finos.org/spec/workbench/jobs/0.1.0-draft.1/receipt.schema.json", + "title": "Authoritative job receipt", + "description": "Closed host receipt with separate cancellation acknowledgement and exact draft.5 terminal evidence. Cross-receipt semantics require the portable reducer", + "examples": [ + { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 0, + "state": "submitted", + "cancelRequested": false, + "outcomes": null + } + ], + "type": "object", + "allOf": [ + { + "if": { + "properties": { + "state": { + "const": "running" + } + } + }, + "then": { + "properties": { + "sequence": { + "minimum": 1 + } + } + } + }, + { + "if": { + "properties": { + "sequence": { + "const": 0 + } + } + }, + "then": { + "properties": { + "state": { + "const": "submitted" + }, + "cancelRequested": { + "const": false + } + } + } + } + ], + "if": { + "properties": { + "state": { + "const": "terminal" + } + } + }, + "then": { + "properties": { + "sequence": { + "minimum": 1 + }, + "outcomes": { + "$ref": "https://morphir.finos.org/spec/workbench/0.1.0-draft.5/terminal-outcomes.schema.json" + } + } + }, + "else": { + "properties": { + "outcomes": { + "type": "null" + } + } + }, + "required": [ + "contractVersion", + "identity", + "sequence", + "state", + "cancelRequested", + "outcomes" + ], + "properties": { + "contractVersion": { + "const": "0.1.0-draft.1" + }, + "identity": { + "$ref": "https://morphir.finos.org/spec/workbench/jobs/0.1.0-draft.1/identity.schema.json" + }, + "sequence": { + "type": "integer", + "maximum": 2147483647, + "minimum": 0 + }, + "state": { + "enum": [ "submitted", "running", "terminal" ] + }, + "cancelRequested": { + "type": "boolean" + }, + "outcomes": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "https://morphir.finos.org/spec/workbench/0.1.0-draft.5/terminal-outcomes.schema.json" + } + ] + } + }, + "additionalProperties": false +} diff --git a/spec/workbench/jobs/draft.1/tests/identity.json b/spec/workbench/jobs/draft.1/tests/identity.json new file mode 100644 index 000000000..74708411c --- /dev/null +++ b/spec/workbench/jobs/draft.1/tests/identity.json @@ -0,0 +1,60 @@ +{ + "target": "https://morphir.finos.org/spec/workbench/jobs/0.1.0-draft.1/identity.schema.json", + "tests": [ + { + "description": "Exact identity", + "data": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "valid": true + }, + { + "description": "Empty snapshot", + "data": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "" + }, + "valid": false + }, + { + "description": "No job", + "data": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "snapshotId": "snapshot" + }, + "valid": false + }, + { + "description": "Unknown member", + "data": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot", + "path": "/local/path" + }, + "valid": false + }, + { + "description": "Long provider", + "data": { + "hostId": "host", + "sessionId": "session", + "providerId": "ppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp", + "jobId": "job", + "snapshotId": "snapshot" + }, + "valid": false + } + ] +} diff --git a/spec/workbench/jobs/draft.1/tests/offer.json b/spec/workbench/jobs/draft.1/tests/offer.json new file mode 100644 index 000000000..8a6a5a03a --- /dev/null +++ b/spec/workbench/jobs/draft.1/tests/offer.json @@ -0,0 +1,154 @@ +{ + "target": "https://morphir.finos.org/spec/workbench/jobs/0.1.0-draft.1/offer.schema.json", + "tests": [ + { + "description": "Query and cancel", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query", + "cancel" + ] + }, + "valid": true + }, + { + "description": "Query without cancellation", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query" + ] + }, + "valid": true + }, + { + "description": "Reordered operations", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "cancel", + "query" + ] + }, + "valid": true + }, + { + "description": "Cancel alone", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "cancel" + ] + }, + "valid": false + }, + { + "description": "Duplicate operation", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query", + "query" + ] + }, + "valid": false + }, + { + "description": "Unknown operation", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query", + "evaluate" + ] + }, + "valid": false + }, + { + "description": "Other draft", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.2", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query", + "cancel" + ] + }, + "valid": false + }, + { + "description": "Release spelling", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query", + "cancel" + ] + }, + "valid": false + }, + { + "description": "Build spelling", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1+build", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query", + "cancel" + ] + }, + "valid": false + }, + { + "description": "Unknown flag", + "data": { + "profile": "morphir/workbench/jobs", + "contractVersion": "0.1.0-draft.1", + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "operations": [ + "query", + "cancel" + ], + "recovery": true + }, + "valid": false + } + ] +} diff --git a/spec/workbench/jobs/draft.1/tests/receipt.json b/spec/workbench/jobs/draft.1/tests/receipt.json new file mode 100644 index 000000000..3c51676fc --- /dev/null +++ b/spec/workbench/jobs/draft.1/tests/receipt.json @@ -0,0 +1,409 @@ +{ + "target": "https://morphir.finos.org/spec/workbench/jobs/0.1.0-draft.1/receipt.schema.json", + "tests": [ + { + "description": "Submitted", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 0, + "state": "submitted", + "cancelRequested": false, + "outcomes": null + }, + "valid": true + }, + { + "description": "Running", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 1, + "state": "running", + "cancelRequested": false, + "outcomes": null + }, + "valid": true + }, + { + "description": "Acknowledged while queued", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 1, + "state": "submitted", + "cancelRequested": true, + "outcomes": null + }, + "valid": true + }, + { + "description": "Return can win cancellation race", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 2, + "state": "terminal", + "cancelRequested": true, + "outcomes": { + "contractVersion": "0.1.0-draft.5", + "calls": [ + { + "id": "call", + "outcome": { + "status": "returned", + "value": { + "type": "bool", + "value": true + } + } + } + ], + "cleanup": { + "stage": "cleanup", + "code": "provider.dispose", + "message": "dispose failed" + }, + "extensions": null + } + }, + "valid": true + }, + { + "description": "Host cancellation without client request", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 2, + "state": "terminal", + "cancelRequested": false, + "outcomes": { + "contractVersion": "0.1.0-draft.5", + "calls": [ + { + "id": "call", + "outcome": { + "status": "cancelled" + } + } + ], + "cleanup": null, + "extensions": null + } + }, + "valid": true + }, + { + "description": "Premature running", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 0, + "state": "running", + "cancelRequested": false, + "outcomes": null + }, + "valid": false + }, + { + "description": "Acknowledged initial submission", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 0, + "state": "submitted", + "cancelRequested": true, + "outcomes": null + }, + "valid": false + }, + { + "description": "Terminal requires payload", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 1, + "state": "terminal", + "cancelRequested": false, + "outcomes": null + }, + "valid": false + }, + { + "description": "Nonterminal cannot carry values", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 2, + "state": "running", + "cancelRequested": true, + "outcomes": { + "contractVersion": "0.1.0-draft.5", + "calls": [ + { + "id": "call", + "outcome": { + "status": "returned", + "value": { + "type": "bool", + "value": true + } + } + } + ], + "cleanup": { + "stage": "cleanup", + "code": "provider.dispose", + "message": "dispose failed" + }, + "extensions": null + } + }, + "valid": false + }, + { + "description": "Unknown state", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 0, + "state": "disconnected", + "cancelRequested": false, + "outcomes": null + }, + "valid": false + }, + { + "description": "Negative sequence", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": -1, + "state": "submitted", + "cancelRequested": false, + "outcomes": null + }, + "valid": false + }, + { + "description": "Fractional sequence", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 0.5, + "state": "submitted", + "cancelRequested": false, + "outcomes": null + }, + "valid": false + }, + { + "description": "Out of range sequence", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 2147483648, + "state": "submitted", + "cancelRequested": false, + "outcomes": null + }, + "valid": false + }, + { + "description": "Maximum sequence", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 2147483647, + "state": "running", + "cancelRequested": false, + "outcomes": null + }, + "valid": true + }, + { + "description": "Wrong nested terminal draft", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 2, + "state": "terminal", + "cancelRequested": true, + "outcomes": { + "contractVersion": "0.1.0-draft.6", + "calls": [ + { + "id": "call", + "outcome": { + "status": "returned", + "value": { + "type": "bool", + "value": true + } + } + } + ], + "cleanup": { + "stage": "cleanup", + "code": "provider.dispose", + "message": "dispose failed" + }, + "extensions": null + } + }, + "valid": false + }, + { + "description": "Unknown receipt field", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 0, + "state": "submitted", + "cancelRequested": false, + "outcomes": null, + "success": true + }, + "valid": false + }, + { + "description": "Contradictory returned value", + "data": { + "contractVersion": "0.1.0-draft.1", + "identity": { + "hostId": "host", + "sessionId": "session", + "providerId": "provider", + "jobId": "job", + "snapshotId": "snapshot" + }, + "sequence": 2, + "state": "terminal", + "cancelRequested": true, + "outcomes": { + "contractVersion": "0.1.0-draft.5", + "calls": [ + { + "id": "call", + "outcome": { + "status": "returned", + "value": { + "type": "bool", + "value": true + }, + "failure": { + "stage": "evaluate", + "code": "x", + "message": "x" + } + } + } + ], + "cleanup": { + "stage": "cleanup", + "code": "provider.dispose", + "message": "dispose failed" + }, + "extensions": null + } + }, + "valid": false + } + ] +}