Skip to content

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.

An m.room.message whose content carries suite_event_type: "dev.superpipeline.delivery.v2".

The carrier is whichever service carries the board’s chat: AgentPod’s hub, or SuperExchange for a board that has moved to it.

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

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"
}

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 by schema)
  • 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)