enum and const in a Sume output schema: a status that cannot drift
Use enum and const in a Sume output_schema to pin a status field to values your publisher expects, since oneOf and allOf are rejected. Examples that pass.

Use enum for a field that may take one of several values, and const for a field that must take exactly one. Both are in the keyword set the Sume structured-output subset accepts, so a status or a schema version can be pinned in the schema itself rather than checked by your own code afterwards (Sume docs: Structured output, read 2026-10-06).
This is the clean replacement for the pattern people reach for oneOf to express. The subset rejects oneOf, allOf, not, if/then/else, nullable:true and patternProperties. It accepts anyOf, enum and const.
What a publisher needs
A publishing script wants a small set of facts it can branch on without guessing. Is this episode ready, does it need a human, or did the run give up? A free-text field invites a model to write 'Looks good!' where your code expects 'ready'. An enum removes the choice.
Add a schema_version const so you know which contract a stored receipt follows. When you change the shape, bump the const and the name, and old receipts stay readable.
A schema that passes
Remember the strict subset. The root is an object, additionalProperties is false on every object, and every property appears in required. An optional field is a nullable union such as an array with the type string and null. The example below has no optional fields. Also give every node a type, even when it has an enum or const: a bare enum node is rejected as missing_type, so the examples here pair each enum and const with type string.
import json
schema = {
"name": "acme/episode-status/v1",
"strict": True,
"schema": {
"type": "object",
"additionalProperties": False,
"required": ["schema_version", "status", "episode", "video"],
"properties": {
"schema_version": {"type": "string", "const": "1"},
"status": {"type": "string", "enum": ["ready", "needs_review", "gave_up"]},
"episode": {"type": "integer", "minimum": 1, "maximum": 99},
"video": {"$ref": "SumeMediaFile#"}
}
}
}
print(json.dumps(schema)[:60])
print("keys:", sorted(schema["schema"]["properties"]))What a schema cannot guarantee
A schema checks shape, and for media it checks more, but it does not judge quality. A status of ready is the run's own claim. Read filled_by too: when it is projection, the object was rebuilt after the fact from the media and the closing text, and the projection never saw your input. A status chosen by projection deserves a human look before publishing.
Also remember that a failed projection ends the run as failed with output_error, and a duration_ms that disagrees with the real file by more than ten percent fails the check. Those are protections, and they are why the media fields are safer to trust than free text.
| Need | Use | Do not use |
|---|---|---|
| One of several values | enum | oneOf |
| Exactly one value | const | if/then/else |
| One of several shapes | anyOf | oneOf, allOf |
| Optional field | Union with null | nullable: true |
Add a way out
Include a value that means 'could not finish', such as gave_up in the example. A schema that only allows success words pushes the model to pick one anyway. A legitimate failure value is easier to handle than a confident wrong answer.
Version the contract
The const on schema_version is only useful if you act on it. Have your consumer read the field first and branch on it, so a future version 2 receipt does not get parsed by version 1 code and silently mis-handled.
Name the schema with a namespace and a version, as the example does. The name appears on every receipt, so a stored receipt tells you which contract produced it without any other lookup.
Limits to keep in mind
Sume reports every violation in one 400 output_schema_invalid response, and nothing runs and nothing is charged, so a schema mistake costs you a request and no money. An enum may hold up to 1,000 values, the document may nest 10 levels deep, and the whole schema may have up to 5,000 properties, so a status list of three or four values is far inside the limits.
Keep the enum values short, lowercase and stable. They become the strings your publisher compares against, and renaming one is a contract change, so treat it like a new schema version.
Sources
Related posts
More in Formats
- 400 previous_run_format_mismatch: continue a run on its own Format
Continuing a Format run on a different Format returns 400 previous_run_format_mismatch. Call the Format where the run started, or start a new run.
- Format run output_extraction_failed: it stays completed, read again
output_extraction_failed is a transport failure, not a verdict. The run stays completed and Sume projects the output again on your next read of the receipt.
- Format run failed primary_not_deliverable: audio under a video key
A Format that makes video fails with agent_reported_failure and primary_not_deliverable when the primary output is audio or a still. How to read and fix it.
- Format run scene status stand-in vs failed: which scenes to retry
Give each scene a status of succeeded, stand-in or failed, then retry only the bad ones with previous_run_id. The schema, the receipt rule and the call.
Written by Sume