dev.superpipeline.delivery.v2
The follow-up a post approved for manual delivery owes: record its live link, or switch it to automatic delivery. Only those two options; switch_to_automatic only when the subject’s preview reached the room complete. Readers ignore properties they do not know. x-uniqueBy lists paths whose values must not repeat (JSON Schema cannot say so): a[].b is field b of each item of list a.
How it rides
Section titled “How it rides”An m.room.message whose content carries suite_event_type: "dev.superpipeline.delivery.v2".
Who sends it, who reads it
Section titled “Who sends it, who reads it”- Sent by AgentPod, SuperExchange.
- Read by SuperMessage.
The carrier is whichever service carries the board’s chat: AgentPod’s hub, or SuperExchange for a board that has moved to it.
Fields
Section titled “Fields”| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
msgtype |
"m.text" |
yes | ||
body |
string | yes | ||
suite_event_type |
"dev.superpipeline.delivery.v2" |
yes | ||
schema_version |
integer | yes | at least 1 | |
board_id |
string | yes | ||
card_id |
string | yes | ||
gate_id |
string | yes | at least 1 character | |
stage_key |
string | yes | ||
card_title |
string | yes | at most 200 characters | |
subject |
object | no | The exact thing an approving answer approves, re-bounded by the carrier. The sender still lists approving options when preview_complete is false; a client must not offer them, and the carrier refuses an approving answer to an incomplete preview. | |
subject.id |
string | yes | at least 1 character; at most 512 characters | |
subject.digest |
string | yes | at least 1 character; at most 512 characters | |
subject.schema |
string | yes | at least 1 character; at most 200 characters | |
subject.revision |
integer | yes | at least 0 | |
subject.expires_at |
string or null | yes | When the binding lapses: an RFC 3339 date-time with seconds and an explicit offset (2030-01-02T03:04:05Z, 2030-01-02T08:34:05.5+05:30), or null for none. The pattern states it for a validator that does not assert format. | format date-time; pattern ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?(Z|[+-]([01]\d|2[0-3]):[0-5]\d)$; at most 200 characters |
subject.preview |
array of object (type = “text”) or object (type = “field”) or object (type = “link”) | yes | at most 20 items | |
subject.preview[].type |
"text" |
yes | in the type = "text" shape |
|
subject.preview[].label |
string | no | in the type = "text" shape; at most 200 characters |
|
subject.preview[].text |
string | yes | in the type = "text" shape; at most 4000 characters |
|
subject.preview[].type |
"field" |
yes | in the type = "field" shape |
|
subject.preview[].label |
string | yes | in the type = "field" shape; at most 200 characters |
|
subject.preview[].value |
string | yes | in the type = "field" shape; at most 200 characters |
|
subject.preview[].type |
"link" |
yes | in the type = "link" shape |
|
subject.preview[].label |
string | yes | in the type = "link" shape; at most 200 characters |
|
subject.preview[].url |
string | yes | in the type = "link" shape; pattern ^https?://[^\s<>]+$; at most 4000 characters |
|
subject.preview_complete |
boolean | yes | ||
options |
array of object (id = “record_live_url”) or object (id = “switch_to_automatic”) | yes | at most 2 items | |
options[].id |
"record_live_url" |
yes | in the id = "record_live_url" shape |
|
options[].label |
string | yes | in the id = "record_live_url" shape; at most 200 characters |
|
options[].meaning |
one of "approve", "reject", "revise", "choose", "defer" |
yes | in the id = "record_live_url" shape |
|
options[].needs_comment |
boolean | yes | in the id = "record_live_url" shape |
|
options[].input |
yes | in the id = "record_live_url" shape |
||
options[].id |
"switch_to_automatic" |
yes | in the id = "switch_to_automatic" shape |
|
options[].label |
string | yes | in the id = "switch_to_automatic" shape; at most 200 characters |
|
options[].meaning |
one of "approve", "reject", "revise", "choose", "defer" |
yes | in the id = "switch_to_automatic" shape |
|
options[].needs_comment |
boolean | yes | in the id = "switch_to_automatic" shape |
|
options[].delivery |
"automatic" |
yes | in the id = "switch_to_automatic" shape |
|
deadline |
object | no | ||
deadline.remind_at |
string | no | pattern ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?(Z|[+-]\d{2}:\d{2})$; at most 40 characters |
|
deadline.escalate_at |
string | no | pattern ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?(Z|[+-]\d{2}:\d{2})$; at most 40 characters |
|
deep_link |
string | no |
The schema also states these rules across fields, as written:
{ "allOf": [ { "description": "switch_to_automatic needs a complete preview.", "if": { "not": { "required": [ "subject" ], "properties": { "subject": { "required": [ "preview_complete" ], "properties": { "preview_complete": { "const": true } } } } } }, "then": { "properties": { "options": { "not": { "contains": { "required": [ "id" ], "properties": { "id": { "const": "switch_to_automatic" } } } } } } } } ]}x-uniqueBy: the values at these paths must not repeat, the one rule JSON Schema cannot state. a[].b is field b of each item of list a.
options[].id
Example
Section titled “Example”From fixtures/matrix-events/examples.json, case “a complete preview: both choices”:
{ "msgtype": "m.text", "body": "Waiting on a live link — \"Announce the release\" was approved to be posted by hand. Once it is live, record its link here.\n\nPost:\n```\nOur next release ships today.\n\nThanks to everyone who tested it.\n```\n\nAccount: @fixture_account on X\n\n- Record the live link\n- Post it automatically\n\n[Open the card](https://superpipeline.dev/b/brd_7c1f/c/crd_6b40)", "suite_event_type": "dev.superpipeline.delivery.v2", "schema_version": 1, "board_id": "brd_7c1f", "card_id": "crd_6b40", "gate_id": "gate_8f3a", "stage_key": "approve", "card_title": "Announce the release", "subject": { "id": "aps_2c9e71", "digest": "sha256:9b2f4e0c1a7d", "schema": "social-publish/v1", "revision": 1, "expires_at": "2030-01-02T03:04:05Z", "preview": [ { "type": "text", "label": "Post", "text": "Our next release ships today.\n\nThanks to everyone who tested it." }, { "type": "field", "label": "Account", "value": "@fixture_account on X" } ], "preview_complete": true }, "options": [ { "id": "record_live_url", "label": "Record the live link", "meaning": "defer", "needs_comment": false, "input": { "kind": "url", "label": "Live link", "required": true, "max_length": 2000 } }, { "id": "switch_to_automatic", "label": "Post it automatically", "meaning": "approve", "needs_comment": false, "delivery": "automatic" } ], "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_6b40"}The corpus has 5 valid cases in all:
an incomplete preview: recording the live link only
{ "msgtype": "m.text", "body": "Waiting on a live link — \"Announce the release\" was approved to be posted by hand. Once it is live, record its link here.\n\nPost:\n```\nOur next release ships today.\n\nThanks to everyone who tested it.\n```\n\nAccount: @fixture_account on X\n\n- Record the live link\n\n[Open the card](https://superpipeline.dev/b/brd_7c1f/c/crd_6b40)", "suite_event_type": "dev.superpipeline.delivery.v2", "schema_version": 1, "board_id": "brd_7c1f", "card_id": "crd_6b40", "gate_id": "gate_8f3b", "stage_key": "approve", "card_title": "Announce the release", "subject": { "id": "aps_2c9e71", "digest": "sha256:9b2f4e0c1a7d", "schema": "social-publish/v1", "revision": 1, "expires_at": "2030-01-02T03:04:05Z", "preview": [ { "type": "text", "label": "Post", "text": "Our next release ships today.\n\nThanks to everyone who tested it." }, { "type": "field", "label": "Account", "value": "@fixture_account on X" } ], "preview_complete": false }, "options": [ { "id": "record_live_url", "label": "Record the live link", "meaning": "defer", "needs_comment": false, "input": { "kind": "url", "label": "Live link", "required": true, "max_length": 2000 } } ], "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_6b40"}deadline: a follow-up that only reminds
{ "msgtype": "m.text", "body": "Waiting on a live link — \"Launch post\" was approved to be posted by hand. Once it is live, record its link here.\n\n- Record the live link\n\n[Open the card](https://superpipeline.dev/b/brd_7c1f/c/crd_6b40)", "suite_event_type": "dev.superpipeline.delivery.v2", "schema_version": 1, "board_id": "brd_7c1f", "card_id": "crd_6b40", "gate_id": "gate_8f3a", "stage_key": "publish", "card_title": "Launch post", "options": [ { "id": "record_live_url", "label": "Record the live link", "meaning": "approve", "needs_comment": false, "input": { "kind": "url", "label": "Live link", "required": true, "max_length": 2000 } } ], "deadline": { "remind_at": "2026-11-08T15:00:00.000Z" }, "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_6b40"}built: a follow-up with a complete preview
{ "msgtype": "m.text", "body": "Waiting on a live link — \"Announce the release\" was approved to be posted by hand. Once it is live, record its link here.\n\nPost:\n```\nOur next release ships today.\n```\n\nAccount: @fixture_account on X\n\n- Record the live link\n- Post it automatically instead\n\n[Open the card](https://superpipeline.dev/b/brd_7c1f/c/crd_6b40)", "suite_event_type": "dev.superpipeline.delivery.v2", "schema_version": 1, "board_id": "brd_7c1f", "card_id": "crd_6b40", "gate_id": "gate_8f3a", "stage_key": "approve", "card_title": "Announce the release", "subject": { "id": "sub_post_1", "digest": "sha256:9a1e", "schema": "x-post/v1", "revision": 1, "expires_at": "2030-01-02T03:04:05Z", "preview": [ { "type": "text", "label": "Post", "text": "Our next release ships today." }, { "type": "field", "label": "Account", "value": "@fixture_account on X" } ], "preview_complete": true }, "options": [ { "id": "record_live_url", "label": "Record the live link", "meaning": "defer", "needs_comment": false, "input": { "kind": "url", "label": "Live link", "required": true, "max_length": 2000 } }, { "id": "switch_to_automatic", "label": "Post it automatically instead", "meaning": "approve", "needs_comment": false, "delivery": "automatic" } ], "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_6b40"}built: a follow-up whose preview was cut: no switch to automatic
{ "msgtype": "m.text", "body": "Waiting on a live link — \"Announce the release\" was approved to be posted by hand. Once it is live, record its link here.\n\nPost:\n```\nOur next release ships today.\n```\n\nAccount: @fixture_account on X\n\n- Record the live link\n\n[Open the card](https://superpipeline.dev/b/brd_7c1f/c/crd_6b40)", "suite_event_type": "dev.superpipeline.delivery.v2", "schema_version": 1, "board_id": "brd_7c1f", "card_id": "crd_6b40", "gate_id": "gate_8f3a", "stage_key": "approve", "card_title": "Announce the release", "subject": { "id": "sub_post_1", "digest": "sha256:9a1e", "schema": "x-post/v1", "revision": 1, "expires_at": "2030-01-02T03:04:05Z", "preview": [ { "type": "text", "label": "Post", "text": "Our next release ships today." }, { "type": "field", "label": "Account", "value": "@fixture_account on X" } ], "preview_complete": false }, "options": [ { "id": "record_live_url", "label": "Record the live link", "meaning": "defer", "needs_comment": false, "input": { "kind": "url", "label": "Live link", "required": true, "max_length": 2000 } } ], "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_6b40"}Refused
Section titled “Refused”Each of these must fail. The corpus says why:
- switch_to_automatic on an incomplete preview. Nobody turns on posting what the card could not show. (refused by
schema) - record_live_url with no input. The live link is required. (refused by
schema) - camelCase on the Matrix wire. The Matrix field is
max_length. (refused byschema) - record_live_url asking for text. The live link is a url input. (refused by
schema) - no body. A stock client would show nothing. (refused by
schema) - a subject revision that is not a whole number (refused by
schema) - an expiry that is a date only (refused by
schema) - an expiry written as a person would (refused by
schema) - an expiry with no offset (refused by
schema) - an expiry with no seconds (refused by
schema) - an expiry with a space for the T (refused by
schema) - an expiry whose offset has no colon (refused by
schema) - an expiry in lower case (refused by
schema) - an expiry on a day the month does not have (refused by
schema)
Source
Section titled “Source”- Schema:
schemas/matrix/dev.superpipeline.delivery.v2.json - In the package:
import schema from "@superjackfruitlabs/treaty-matrix-events/schemas/dev.superpipeline.delivery.v2.json" with { type: "json" };