C1c-1: the three build seats' verb output answers a run's answer in chunks

The part build-step gains the verb `output` (the ask and the call in, the ask and the chunk count out, marked chunks, read by the
askers of a run), and the fields output and output-object of step-ended name the run's answer inline or as an object the holder
keeps. The three seats' fixtures carry the verb; the generated Go and TypeScript follow.

Builds: design 47 G A-254, A-139, §712, §354

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 09:34:48 +01:00
parent 6cbaa84c52
commit f06c9cf5fd
22 changed files with 243 additions and 17 deletions
@@ -21,6 +21,7 @@ const (
VerbDrop = "drop"
VerbKeptArtifact = "kept-artifact"
VerbSteps = "steps"
VerbOutput = "output"
)
const (
@@ -41,7 +42,7 @@ const (
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbCurrent, VerbPause, VerbResume, VerbDrop, VerbKeptArtifact, VerbSteps}
return []string{VerbCurrent, VerbPause, VerbResume, VerbDrop, VerbKeptArtifact, VerbSteps, VerbOutput}
}
// Events is every event published on the seat's subject: a new copy each call.
@@ -804,9 +805,9 @@ type StepEnded struct {
Node string `json:"node"`
// never passed for a step that ran nothing
Outcome string `json:"outcome"`
// the step's output when it fits the message
// the run's answer (its program's standard output's last line) when it fits the event (design 47 G A-254)
Output string `json:"output,omitempty"`
// the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)
// the name of the object that holds the run's answer, kept by the build seat's holder, when the answer is over what the event carries (design 47 G A-254); read through the verb output
OutputObject string `json:"output-object,omitempty"`
Pipeline string `json:"pipeline,omitempty"`
Rerun bool `json:"rerun,omitempty"`
@@ -1064,6 +1065,22 @@ type StepsAnswer struct {
Steps []DetectedStep `json:"steps,omitempty"`
}
// OutputInput is what output takes.
type OutputInput struct {
// the ask's id, the `output-object` of its step-ended naming it
Ask string `json:"ask"`
// 128 random bits the caller chooses: the subject token of this send's chunks and acknowledgements
Call string `json:"call"`
}
// OutputAnswer is what output answers.
type OutputAnswer struct {
// the ask's id
Ask string `json:"ask"`
// how many chunks are sent; 0 when this node keeps no answer of that ask
Chunks int64 `json:"chunks"`
}
// DeliveryAccept is the body of delivery.
type DeliveryAccept = StepAsk
@@ -121,6 +121,10 @@ func TestFixtures(t *testing.T) {
decode: func(b []byte) (any, error) { var v StepsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "steps answers a drop that the hand-act log refused", subject: "", given: "{\"error\":\"the hand-act log refused: nothing was deleted\"}", wire: "{\"error\":\"the hand-act log refused: nothing was deleted\"}",
decode: func(b []byte) (any, error) { var v StepsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "output asks a run's answer by its ask", subject: "", given: "{\"ask\":\"m2kx9a1b3c4d5f\",\"call\":\"0123456789abcdef0123456789abcdef\"}", wire: "{\"ask\":\"m2kx9a1b3c4d5f\",\"call\":\"0123456789abcdef0123456789abcdef\"}",
decode: func(b []byte) (any, error) { var v OutputInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "output answers how many chunks carry the answer", subject: "", given: "{\"ask\":\"m2kx9a1b3c4d5f\",\"chunks\":3}", wire: "{\"ask\":\"m2kx9a1b3c4d5f\",\"chunks\":3}",
decode: func(b []byte) (any, error) { var v OutputAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
@@ -21,6 +21,7 @@ const (
VerbDrop = "drop"
VerbKeptArtifact = "kept-artifact"
VerbSteps = "steps"
VerbOutput = "output"
)
const (
@@ -40,7 +41,7 @@ const (
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbCurrent, VerbPause, VerbResume, VerbDrop, VerbKeptArtifact, VerbSteps}
return []string{VerbCurrent, VerbPause, VerbResume, VerbDrop, VerbKeptArtifact, VerbSteps, VerbOutput}
}
// Events is every event published on the seat's subject: a new copy each call.
@@ -802,9 +803,9 @@ type StepEnded struct {
Node string `json:"node"`
// never passed for a step that ran nothing
Outcome string `json:"outcome"`
// the step's output when it fits the message
// the run's answer (its program's standard output's last line) when it fits the event (design 47 G A-254)
Output string `json:"output,omitempty"`
// the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)
// the name of the object that holds the run's answer, kept by the build seat's holder, when the answer is over what the event carries (design 47 G A-254); read through the verb output
OutputObject string `json:"output-object,omitempty"`
Pipeline string `json:"pipeline,omitempty"`
Rerun bool `json:"rerun,omitempty"`
@@ -1062,6 +1063,22 @@ type StepsAnswer struct {
Steps []DetectedStep `json:"steps,omitempty"`
}
// OutputInput is what output takes.
type OutputInput struct {
// the ask's id, the `output-object` of its step-ended naming it
Ask string `json:"ask"`
// 128 random bits the caller chooses: the subject token of this send's chunks and acknowledgements
Call string `json:"call"`
}
// OutputAnswer is what output answers.
type OutputAnswer struct {
// the ask's id
Ask string `json:"ask"`
// how many chunks are sent; 0 when this node keeps no answer of that ask
Chunks int64 `json:"chunks"`
}
// DeliveryAccept is the body of delivery.
type DeliveryAccept = StepAsk
@@ -103,6 +103,10 @@ func TestFixtures(t *testing.T) {
decode: func(b []byte) (any, error) { var v StepsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "steps answers a drop that the hand-act log refused", subject: "", given: "{\"error\":\"the hand-act log refused: nothing was deleted\"}", wire: "{\"error\":\"the hand-act log refused: nothing was deleted\"}",
decode: func(b []byte) (any, error) { var v StepsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "output asks a run's answer by its ask", subject: "", given: "{\"ask\":\"m2kx9a1b3c4d5f\",\"call\":\"0123456789abcdef0123456789abcdef\"}", wire: "{\"ask\":\"m2kx9a1b3c4d5f\",\"call\":\"0123456789abcdef0123456789abcdef\"}",
decode: func(b []byte) (any, error) { var v OutputInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "output answers how many chunks carry the answer", subject: "", given: "{\"ask\":\"m2kx9a1b3c4d5f\",\"chunks\":3}", wire: "{\"ask\":\"m2kx9a1b3c4d5f\",\"chunks\":3}",
decode: func(b []byte) (any, error) { var v OutputAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
@@ -21,6 +21,7 @@ const (
VerbDrop = "drop"
VerbKeptArtifact = "kept-artifact"
VerbSteps = "steps"
VerbOutput = "output"
)
const (
@@ -40,7 +41,7 @@ const (
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbCurrent, VerbPause, VerbResume, VerbDrop, VerbKeptArtifact, VerbSteps}
return []string{VerbCurrent, VerbPause, VerbResume, VerbDrop, VerbKeptArtifact, VerbSteps, VerbOutput}
}
// Events is every event published on the seat's subject: a new copy each call.
@@ -802,9 +803,9 @@ type StepEnded struct {
Node string `json:"node"`
// never passed for a step that ran nothing
Outcome string `json:"outcome"`
// the step's output when it fits the message
// the run's answer (its program's standard output's last line) when it fits the event (design 47 G A-254)
Output string `json:"output,omitempty"`
// the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)
// the name of the object that holds the run's answer, kept by the build seat's holder, when the answer is over what the event carries (design 47 G A-254); read through the verb output
OutputObject string `json:"output-object,omitempty"`
Pipeline string `json:"pipeline,omitempty"`
Rerun bool `json:"rerun,omitempty"`
@@ -1062,6 +1063,22 @@ type StepsAnswer struct {
Steps []DetectedStep `json:"steps,omitempty"`
}
// OutputInput is what output takes.
type OutputInput struct {
// the ask's id, the `output-object` of its step-ended naming it
Ask string `json:"ask"`
// 128 random bits the caller chooses: the subject token of this send's chunks and acknowledgements
Call string `json:"call"`
}
// OutputAnswer is what output answers.
type OutputAnswer struct {
// the ask's id
Ask string `json:"ask"`
// how many chunks are sent; 0 when this node keeps no answer of that ask
Chunks int64 `json:"chunks"`
}
// DeliveryAccept is the body of delivery.
type DeliveryAccept = StepAsk
@@ -107,6 +107,10 @@ func TestFixtures(t *testing.T) {
decode: func(b []byte) (any, error) { var v StepsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "steps answers a drop that the hand-act log refused", subject: "", given: "{\"error\":\"the hand-act log refused: nothing was deleted\"}", wire: "{\"error\":\"the hand-act log refused: nothing was deleted\"}",
decode: func(b []byte) (any, error) { var v StepsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "output asks a run's answer by its ask", subject: "", given: "{\"ask\":\"m2kx9a1b3c4d5f\",\"call\":\"0123456789abcdef0123456789abcdef\"}", wire: "{\"ask\":\"m2kx9a1b3c4d5f\",\"call\":\"0123456789abcdef0123456789abcdef\"}",
decode: func(b []byte) (any, error) { var v OutputInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "output answers how many chunks carry the answer", subject: "", given: "{\"ask\":\"m2kx9a1b3c4d5f\",\"chunks\":3}", wire: "{\"ask\":\"m2kx9a1b3c4d5f\",\"chunks\":3}",
decode: func(b []byte) (any, error) { var v OutputAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
@@ -233,6 +233,55 @@
"required": []
},
"class": "act"
},
{
"name": "output",
"class": "read",
"callers": [
"seat:mesh-catalog",
"seat:mesh-wants",
"seat:mesh-delivery-checker",
"seat:mesh-pipeline-runner"
],
"description": "A run's answer by its ask, when the step-ended of the run names it as `output-object` because the answer is over what the event carries (design 47 G A-254): the answer's bytes in chunks of at most 512 KiB on the chunk subject of the call, each acknowledged by the caller on the ack subject within 30 seconds; the answer is of any size. An answer inline in the event is never asked here.",
"input": {
"type": "object",
"properties": {
"ask": {
"type": "string",
"description": "the ask's id, the `output-object` of its step-ended naming it",
"minLength": 1
},
"call": {
"type": "string",
"description": "128 random bits the caller chooses: the subject token of this send's chunks and acknowledgements",
"minLength": 1
}
},
"required": [
"ask",
"call"
]
},
"answer": {
"type": "object",
"properties": {
"ask": {
"type": "string",
"description": "the ask's id"
},
"chunks": {
"type": "integer",
"minimum": 0,
"description": "how many chunks are sent; 0 when this node keeps no answer of that ask"
}
},
"required": [
"ask",
"chunks"
]
},
"chunks": true
}
],
"defs": {
@@ -1595,11 +1644,11 @@
},
"output": {
"type": "string",
"description": "the step's output when it fits the message"
"description": "the run's answer (its program's standard output's last line) when it fits the event (design 47 G A-254)"
},
"output-object": {
"type": "string",
"description": "the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)"
"description": "the name of the object that holds the run's answer, kept by the build seat's holder, when the answer is over what the event carries (design 47 G A-254); read through the verb output"
},
"rerun": {
"type": "boolean"
@@ -124,5 +124,21 @@
"given": {
"error": "the hand-act log refused: nothing was deleted"
}
},
{
"name": "output asks a run's answer by its ask",
"of": "verb:output.input",
"given": {
"ask": "m2kx9a1b3c4d5f",
"call": "0123456789abcdef0123456789abcdef"
}
},
{
"name": "output answers how many chunks carry the answer",
"of": "verb:output.answer",
"given": {
"ask": "m2kx9a1b3c4d5f",
"chunks": 3
}
}
]
@@ -124,5 +124,21 @@
"given": {
"error": "the hand-act log refused: nothing was deleted"
}
},
{
"name": "output asks a run's answer by its ask",
"of": "verb:output.input",
"given": {
"ask": "m2kx9a1b3c4d5f",
"call": "0123456789abcdef0123456789abcdef"
}
},
{
"name": "output answers how many chunks carry the answer",
"of": "verb:output.answer",
"given": {
"ask": "m2kx9a1b3c4d5f",
"chunks": 3
}
}
]
@@ -124,5 +124,21 @@
"given": {
"error": "the hand-act log refused: nothing was deleted"
}
},
{
"name": "output asks a run's answer by its ask",
"of": "verb:output.input",
"given": {
"ask": "m2kx9a1b3c4d5f",
"call": "0123456789abcdef0123456789abcdef"
}
},
{
"name": "output answers how many chunks carry the answer",
"of": "verb:output.answer",
"given": {
"ask": "m2kx9a1b3c4d5f",
"chunks": 3
}
}
]
@@ -13,6 +13,7 @@ export declare const verbs: {
readonly drop: "drop";
readonly keptArtifact: "kept-artifact";
readonly steps: "steps";
readonly output: "output";
};
export declare const accepts: {
@@ -146,6 +147,8 @@ export type LevelAnswerDigestPackagesItem = buildStep.LevelAnswerDigestPackagesI
export type LevelAnswerKeptItem = buildStep.LevelAnswerKeptItem;
export type LevelAnswerUnmetItem = buildStep.LevelAnswerUnmetItem;
export type ModuleTree = buildStep.ModuleTree;
export type OutputAnswer = buildStep.OutputAnswer;
export type OutputInput = buildStep.OutputInput;
export type Pause = buildStep.Pause;
export type PauseAnswer = buildStep.PauseAnswer;
export type PauseInput = buildStep.PauseInput;
@@ -11,6 +11,7 @@ export const verbs = {
drop: "drop",
keptArtifact: "kept-artifact",
steps: "steps",
output: "output",
};
export const accepts = {
@@ -9,6 +9,7 @@ export declare const verbs: {
readonly drop: "drop";
readonly keptArtifact: "kept-artifact";
readonly steps: "steps";
readonly output: "output";
};
export declare const events: {
@@ -432,9 +433,9 @@ export interface StepEnded {
"node": string;
/** never passed for a step that ran nothing */
"outcome": "passed" | "failed" | "nothing to run" | "could not run";
/** the step's output when it fits the message */
/** the run's answer (its program's standard output's last line) when it fits the event (design 47 G A-254) */
"output"?: string;
/** the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16) */
/** the name of the object that holds the run's answer, kept by the build seat's holder, when the answer is over what the event carries (design 47 G A-254); read through the verb output */
"output-object"?: string;
"pipeline"?: string;
"rerun"?: boolean;
@@ -655,6 +656,22 @@ export interface StepsAnswer {
"steps"?: DetectedStep[];
}
/** is what output takes. */
export interface OutputInput {
/** the ask's id, the `output-object` of its step-ended naming it */
"ask": string;
/** 128 random bits the caller chooses: the subject token of this send's chunks and acknowledgements */
"call": string;
}
/** is what output answers. */
export interface OutputAnswer {
/** the ask's id */
"ask": string;
/** how many chunks are sent; 0 when this node keeps no answer of that ask */
"chunks": number;
}
/** is the body of the event step-ended. */
export type StepEndedEvent = StepEnded;
@@ -9,6 +9,7 @@ export const verbs = {
drop: "drop",
keptArtifact: "kept-artifact",
steps: "steps",
output: "output",
};
export const events = {
@@ -13,6 +13,7 @@ export declare const verbs: {
readonly drop: "drop";
readonly keptArtifact: "kept-artifact";
readonly steps: "steps";
readonly output: "output";
};
export declare const accepts: {
@@ -143,6 +144,8 @@ export type LevelAnswerDigestPackagesItem = buildStep.LevelAnswerDigestPackagesI
export type LevelAnswerKeptItem = buildStep.LevelAnswerKeptItem;
export type LevelAnswerUnmetItem = buildStep.LevelAnswerUnmetItem;
export type ModuleTree = buildStep.ModuleTree;
export type OutputAnswer = buildStep.OutputAnswer;
export type OutputInput = buildStep.OutputInput;
export type Pause = buildStep.Pause;
export type PauseAnswer = buildStep.PauseAnswer;
export type PauseInput = buildStep.PauseInput;
@@ -11,6 +11,7 @@ export const verbs = {
drop: "drop",
keptArtifact: "kept-artifact",
steps: "steps",
output: "output",
};
export const accepts = {
@@ -9,6 +9,7 @@ export declare const verbs: {
readonly drop: "drop";
readonly keptArtifact: "kept-artifact";
readonly steps: "steps";
readonly output: "output";
};
export declare const events: {
@@ -432,9 +433,9 @@ export interface StepEnded {
"node": string;
/** never passed for a step that ran nothing */
"outcome": "passed" | "failed" | "nothing to run" | "could not run";
/** the step's output when it fits the message */
/** the run's answer (its program's standard output's last line) when it fits the event (design 47 G A-254) */
"output"?: string;
/** the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16) */
/** the name of the object that holds the run's answer, kept by the build seat's holder, when the answer is over what the event carries (design 47 G A-254); read through the verb output */
"output-object"?: string;
"pipeline"?: string;
"rerun"?: boolean;
@@ -655,6 +656,22 @@ export interface StepsAnswer {
"steps"?: DetectedStep[];
}
/** is what output takes. */
export interface OutputInput {
/** the ask's id, the `output-object` of its step-ended naming it */
"ask": string;
/** 128 random bits the caller chooses: the subject token of this send's chunks and acknowledgements */
"call": string;
}
/** is what output answers. */
export interface OutputAnswer {
/** the ask's id */
"ask": string;
/** how many chunks are sent; 0 when this node keeps no answer of that ask */
"chunks": number;
}
/** is the body of the event step-ended. */
export type StepEndedEvent = StepEnded;
@@ -9,6 +9,7 @@ export const verbs = {
drop: "drop",
keptArtifact: "kept-artifact",
steps: "steps",
output: "output",
};
export const events = {
@@ -13,6 +13,7 @@ export declare const verbs: {
readonly drop: "drop";
readonly keptArtifact: "kept-artifact";
readonly steps: "steps";
readonly output: "output";
};
export declare const accepts: {
@@ -143,6 +144,8 @@ export type LevelAnswerDigestPackagesItem = buildStep.LevelAnswerDigestPackagesI
export type LevelAnswerKeptItem = buildStep.LevelAnswerKeptItem;
export type LevelAnswerUnmetItem = buildStep.LevelAnswerUnmetItem;
export type ModuleTree = buildStep.ModuleTree;
export type OutputAnswer = buildStep.OutputAnswer;
export type OutputInput = buildStep.OutputInput;
export type Pause = buildStep.Pause;
export type PauseAnswer = buildStep.PauseAnswer;
export type PauseInput = buildStep.PauseInput;
@@ -11,6 +11,7 @@ export const verbs = {
drop: "drop",
keptArtifact: "kept-artifact",
steps: "steps",
output: "output",
};
export const accepts = {
@@ -9,6 +9,7 @@ export declare const verbs: {
readonly drop: "drop";
readonly keptArtifact: "kept-artifact";
readonly steps: "steps";
readonly output: "output";
};
export declare const events: {
@@ -432,9 +433,9 @@ export interface StepEnded {
"node": string;
/** never passed for a step that ran nothing */
"outcome": "passed" | "failed" | "nothing to run" | "could not run";
/** the step's output when it fits the message */
/** the run's answer (its program's standard output's last line) when it fits the event (design 47 G A-254) */
"output"?: string;
/** the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16) */
/** the name of the object that holds the run's answer, kept by the build seat's holder, when the answer is over what the event carries (design 47 G A-254); read through the verb output */
"output-object"?: string;
"pipeline"?: string;
"rerun"?: boolean;
@@ -655,6 +656,22 @@ export interface StepsAnswer {
"steps"?: DetectedStep[];
}
/** is what output takes. */
export interface OutputInput {
/** the ask's id, the `output-object` of its step-ended naming it */
"ask": string;
/** 128 random bits the caller chooses: the subject token of this send's chunks and acknowledgements */
"call": string;
}
/** is what output answers. */
export interface OutputAnswer {
/** the ask's id */
"ask": string;
/** how many chunks are sent; 0 when this node keeps no answer of that ask */
"chunks": number;
}
/** is the body of the event step-ended. */
export type StepEndedEvent = StepEnded;
@@ -9,6 +9,7 @@ export const verbs = {
drop: "drop",
keptArtifact: "kept-artifact",
steps: "steps",
output: "output",
};
export const events = {