dev.superpipeline.gate.v1
The legacy custom event a v1 gate is sent as beside its prose message: the embedded card plus body. 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”A custom Matrix event of type dev.superpipeline.gate.v1, sent beside its prose message.
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 |
|---|---|---|---|---|
body |
string | 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 | ||
return_stage_key |
string | yes | ||
card_title |
string | yes | ||
produced_by |
string | yes | ||
prompt |
string | yes | ||
handoff_summary |
string | no | ||
options |
array of object | yes | at least 1 item; at most 3 items | |
options[].id |
one of "approve", "request_changes", "reject" |
yes | ||
options[].label |
string | yes | ||
deep_link |
string | no |
The schema also states these rules across fields, as written:
{ "allOf": [ { "description": "Fields dropped deliberately (tenant_id, run_id, task_id, expires_at): a sender that has them was built against a superseded sketch.", "not": { "anyOf": [ { "required": [ "tenant_id" ] }, { "required": [ "run_id" ] }, { "required": [ "task_id" ] }, { "required": [ "expires_at" ] } ] } } ]}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 “the ordinary case”:
{ "body": "Approval needed — \"Add OAuth login\" at stage `review`. Approve, request changes, or reject: https://superpipeline.dev/b/brd_7c1f/c/crd_9a22", "schema_version": 2, "board_id": "brd_7c1f", "card_id": "crd_9a22", "gate_id": "gate_4e8b", "stage_key": "review", "return_stage_key": "code", "card_title": "Add OAuth login", "produced_by": "agt_31d0", "prompt": "Ship the OAuth change to staging?", "options": [ { "id": "approve", "label": "Approve" }, { "id": "request_changes", "label": "Request changes" }, { "id": "reject", "label": "Reject" } ], "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_9a22", "handoff_summary": "Added the OAuth routes and a test for the refresh-token path."}The corpus has 5 valid cases in all:
a higher schema_version is tolerated — a v1 renderer reads the fields it knows and ignores the rest
{ "body": "Approval needed — \"Rotate the signing key\" at stage `review`.", "schema_version": 2, "board_id": "brd_7c1f", "card_id": "crd_0011", "gate_id": "gate_0012", "stage_key": "review", "return_stage_key": "prepare", "card_title": "Rotate the signing key", "produced_by": "agt_31d0", "prompt": "Rotate now?", "options": [ { "id": "approve", "label": "Rotate" }, { "id": "reject", "label": "Not yet" } ], "a_field_from_the_future": "ignored, not fatal"}two options rather than three — a gate need not offer request_changes
{ "body": "Approval needed — \"Delete the staging bucket\" at stage `review`.", "schema_version": 1, "board_id": "brd_7c1f", "card_id": "crd_5150", "gate_id": "gate_5151", "stage_key": "review", "return_stage_key": "plan", "card_title": "Delete the staging bucket", "produced_by": "agt_31d0", "prompt": "This cannot be undone. Proceed?", "options": [ { "id": "approve", "label": "Delete it" }, { "id": "reject", "label": "Cancel" } ]}choice: the variant gate above, as a v1 client sees it
{ "body": "Choice needed — \"Announce the release\" at stage `approve`. Choose a version in an updated app or on the board; request changes or reject can be sent from here. [Open the card](https://superpipeline.dev/b/brd_7c1f/c/crd_7e31)", "schema_version": 2, "board_id": "brd_7c1f", "card_id": "crd_7e31", "gate_id": "gate_5d72", "stage_key": "approve", "return_stage_key": "draft", "card_title": "Announce the release", "produced_by": "agt_31d0", "prompt": "Choose a version of \"Announce the release\"", "handoff_summary": "Choose one of 3 variants: \"Short\", \"With the thread\", \"Long form\". Open the card to see them before approving.", "options": [ { "id": "request_changes", "label": "Request changes" }, { "id": "reject", "label": "Reject" } ], "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_7e31"}built: a gate bound to no subject
{ "body": "Approval needed — \"Ship the release notes\" at stage `review`. Approve, request changes, or reject. [Open the card](https://superpipeline.dev/b/brd_7c1f/c/crd_6b40)", "schema_version": 2, "board_id": "brd_7c1f", "card_id": "crd_6b40", "gate_id": "gate_8f3a", "stage_key": "review", "return_stage_key": "draft", "card_title": "Ship the release notes", "produced_by": "agt_31d0", "prompt": "Approve \"Ship the release notes\"?", "handoff_summary": "Release notes for 0.4, three sections.", "options": [ { "id": "approve", "label": "Approve" }, { "id": "request_changes", "label": "Request changes" }, { "id": "reject", "label": "Reject" } ], "deep_link": "https://superpipeline.dev/b/brd_7c1f/c/crd_6b40"}Refused
Section titled “Refused”Each of these must fail. The corpus says why:
- an option id outside GateDecision. Renders a fine button and is refused on resolution — the failure this corpus exists to make loud. (refused by
schema) - no body. A message with nothing for a stock client to render defeats the reason the marker shape was chosen. (refused by
schema) - carries tenant_id. Dropped deliberately; its presence means a sender built against the superseded #34 sketch. (refused by
schema) - carries run_id, task_id and expires_at — all three dropped. Same superseded sketch. (refused by
schema) - empty options. A decision with nothing to choose is a card that cannot be answered; it must not render as pending. (refused by
schema) - duplicate option ids. Resolution is by id, so two
approveentries are ambiguous regardless of their labels. (refused byunique) - a handoff_summary that is not a string. It is displayed text; an object here would be rendered by whatever a host does with a non-string, which is exactly the coercion the renderers refuse. (refused by
schema) - choice: a v1 card for a variant gate offering approve. Its answer could carry no choice. (refused by
recorded)
Source
Section titled “Source”- Schema:
schemas/matrix/dev.superpipeline.gate.v1.json - In the package:
import schema from "@superjackfruitlabs/treaty-matrix-events/schemas/dev.superpipeline.gate.v1.json" with { type: "json" };