Compute
Narrow a workflow's output schema
Start from the schema the workflow declares, keep only the fields you will actually read, and bound every array and string. A wider schema, or one that carries an effect, is refused.
Before you start
You need the output schema from the workflow's descriptor, and a clear list of the fields your own system will read. Those two together decide your schema.
Intersect, never extend
The declared schema is the ceiling. Your schema is the intersection of that ceiling with what you need.
Remove every field you will not read. Keep the ones you will. You cannot add a field the workflow does not declare, and a request that tries is refused rather than partly honored.
Narrowing is not a formality. A field you never open still consumes output budget on every single item.
Bound your arrays and strings
Give every array a maximum item count. Give every string a maximum length. Leave nothing open-ended.
Unbounded fields make output size unpredictable per item, and output density decides how much work fits into one unit. One unbounded array can push a single item past the output bound while its input fits comfortably.
Bounds also make refusals arrive early and legibly, at request time, rather than as a surprise in the middle of a large run.
Effect-bearing fields are refused
Output is data. A field that would cause something to happen is refused, whatever it is called.
That covers a URL to fetch, a command to run, a destination to write to, and any field that would select a different billing path. None of those belong in a schema.
Delivery is configured separately, as a registered destination with its own approval. Keeping the two apart is what stops a schema edit from becoming an external write.
What arrives beside your fields
Tabular output carries namespaced result columns in addition to your own. They are lithi_status, lithi_result, lithi_error_code, lithi_confidence, lithi_evidence, lithi_verification and lithi_usage.
That prefix is reserved, so do not reuse it for your own fields. Read lithi_status first on every row, because an accepted row and a refused row both arrive in the same file.
What success looks like
Your quote echoes the schema you sent. Your result bundle records the schema digest in provenance.json, and result-manifest.json binds every file and count once the bundle is complete.
You should be able to open one accepted row and find only fields you asked for, plus the reserved columns.
If your schema is refused
The refusal names what it rejected and what to do next. Usually it is a field the workflow does not declare, an unbounded array, or something that carries an effect.
Fix that one thing against the current descriptor and quote again. Do not widen the schema hoping a superset will be accepted, because the ceiling does not move.
To see where these fields land, read the result bundle layout. To size output against the profile, see the profile token bounds.