attention.pending v1
A card has come to rest on a person for a reason that is neither a question nor a review (charter: waiting cards and broker approvals reach chat §1-2). Pushed when the card parks, and read back by the carrier’s sweep from GET /v1/boards/:id/attention/pending, from one builder. Mirrors SuperPipeline’s AttentionPendingBody (apps/api/src/board/views.ts). It has no subject: nothing is frozen, so nothing is bound. Readers ignore properties they do not know.
CloudEvents
Section titled “CloudEvents”Every event below carries dataschema https://raw.githubusercontent.com/SuperJackfruitLabs/treaty/main/schemas/superpipeline/attention.pending.v1.json.
Body event |
CloudEvents type |
Subject |
|---|---|---|
attention.pending |
com.superjackfruit.superpipeline.attention.pending.v1 |
evt.<workspace>.superpipeline.attention.pending |
The subject is the NATS subject the relay files it under; <workspace> is the board’s workspace. See the envelope and subjects.
Who sends it, who reads it
Section titled “Who sends it, who reads it”- Produced by SuperPipeline, through the relay.
- Consumed by:
- SuperExchange: Posts it to the board’s room, for the boards it carries. Receives it through the relay.
- AgentPod: The hub’s board chat posts it, for the boards it still carries.
- SuperDispatch: Takes it as a nudge to look at the board soon, on a board opted into scheduling. Reads nothing from its data.
Fields
Section titled “Fields”Readers ignore properties they do not know, so a field may be added without a new version.
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
event |
"attention.pending" |
yes | ||
boardId |
string or null | yes | Null only on a board not yet initialised; a carrier needs it to route the event. | |
boardName |
string | yes | Empty string when the board has no name, never absent. | |
cardId |
string | yes | ||
cardTitle |
string | yes | ||
stageKey |
string | yes | ||
stageName |
string | yes | The stage’s name, or its key when the board no longer has that stage. | |
waitId |
string | yes | Names this wait. A card that parks again is a new wait; an answer naming an ended one is refused. | |
reason |
one of "repeated-failure", "blocked", "not-authorised" |
yes | ||
detail |
string or null | yes | The run’s own words; null when the park gave none. | |
summary |
string or null | yes | ||
failureCount |
integer or null | yes | How many attempts failed, when the breaker tripped; null otherwise. | at least 0 |
earlierStages |
array of object | yes | The stages before this one, in order. | |
earlierStages[].key |
string | yes | ||
earlierStages[].name |
string | yes | ||
options |
array of object | yes | resume_here (approve), one resume_at:<stageKey> (choose) per earlier stage, archive (reject). | |
options[].id |
string | yes | ||
options[].label |
string | yes | ||
options[].meaning |
one of "approve", "reject", "revise", "choose", "defer" |
yes | What choosing the option does (gate.v2 §2). | |
options[].needsComment |
false |
yes | ||
options[].input |
object | no | What choosing the option asks the person to type. | |
options[].input.kind |
one of "text", "url" |
yes | ||
options[].input.label |
string | yes | ||
options[].input.required |
boolean | yes | ||
options[].input.maxLength |
integer | yes | at least 1 | |
deadline |
object | no | When the decision is reminded about and escalated. Absent when its stage sets no timeout. | |
deadline.remindAt |
string | no | format date-time |
|
deadline.escalateAt |
string | no | format date-time |
|
ts |
string | yes | When the card came to rest. | format date-time |
Example
Section titled “Example”From fixtures/superpipeline-events/examples.json, case “blocked”:
{ "event": "attention.pending", "boardId": "brd_134a0ddb6d434478", "boardName": "Attention board", "cardId": "crd_0f3c9a2b7d4e4a11", "cardTitle": "Add login", "stageKey": "build", "stageName": "Build", "waitId": "wait_3c4d5e6f7a8b9c0d", "reason": "blocked", "detail": "the staging database is down", "summary": "Staging DB down", "failureCount": null, "earlierStages": [ { "key": "plan", "name": "Plan" } ], "options": [ { "id": "resume_here", "label": "Resume here", "meaning": "approve", "needsComment": false, "input": { "kind": "text", "label": "What should the next attempt do?", "required": true, "maxLength": 2730 } }, { "id": "resume_at:plan", "label": "Resume at Plan", "meaning": "choose", "needsComment": false, "input": { "kind": "text", "label": "What should the next attempt do?", "required": true, "maxLength": 2730 } }, { "id": "archive", "label": "Archive", "meaning": "reject", "needsComment": false } ], "ts": "2026-11-10T09:30:00.000Z"}The corpus has 2 valid cases in all:
breaker-tripped
{ "event": "attention.pending", "boardId": "brd_134a0ddb6d434478", "boardName": "Attention board", "cardId": "crd_0f3c9a2b7d4e4a11", "cardTitle": "Add login", "stageKey": "build", "stageName": "Build", "waitId": "wait_3c4d5e6f7a8b9c0d", "reason": "repeated-failure", "detail": "flaky", "summary": null, "failureCount": 3, "earlierStages": [], "options": [ { "id": "resume_here", "label": "Resume here", "meaning": "approve", "needsComment": false, "input": { "kind": "text", "label": "What should the next attempt do?", "required": true, "maxLength": 2730 } }, { "id": "archive", "label": "Archive", "meaning": "reject", "needsComment": false } ], "ts": "2026-11-10T09:30:00.000Z", "deadline": { "escalateAt": "2026-11-11T09:30:00.000Z" }}Refused
Section titled “Refused”Each of these must fail. The corpus says why:
- the reason is one of three
- detail is present, null when there is none
- waitId is required
- an attention option never asks for a comment
Source
Section titled “Source”- Schema:
schemas/superpipeline/attention.pending.v1.json - In the package:
import schema from "@superjackfruitlabs/treaty-event-schemas/superpipeline/attention.pending.v1.json" with { type: "json" };