Files
UmbraTrans/docs/audio-system-manifest-v1.schema.json
umbra audio dda079f605 commit audio ingest: apply 0008+0009 migrations, wire Postgres adapter to commit path
- Apply migration 0008_audio_source_import (additive schema for source import)
- Apply migration 0009_translation_import_runs (ledger table for import runs)
- Wire PostgresAudioImportStore into HTTP commit path with org from node credential
- Commit path uses PG store with org from node, no payload org
- Bundle hash 21ce5687… remains frozen until v2; no authority transferred
2026-10-19 04:35:07 -07:00

337 lines
14 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://umbra.invalid/schemas/umbracontrol/audio-bundle/v1/manifest.schema.json",
"title": "UmbraAudio metadata bundle, v1, as accepted by UmbraTrans",
"description": "Validates the wrapper the controller builds from a bundle directory: {bundle: <bundle.json>, records: [<manifest.jsonl lines>]}. This is the bundle you already produce, narrowed - field names are unchanged, and nothing is renamed on the wire. Required fields here are a superset of the ones your own validator enforces, because these are the fields the mapping reads.",
"type": "object",
"required": ["bundle", "records"],
"additionalProperties": false,
"properties": {
"bundle": { "$ref": "#/$defs/envelope" },
"records": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/record" }
}
},
"$defs": {
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
"iso8601": { "type": "string", "format": "date-time" },
"relativeTo": { "const": "book_directory" },
"envelope": {
"title": "bundle.json",
"type": "object",
"required": [
"bundle_format_version",
"content_hash",
"generated_at",
"source",
"counts",
"record_kinds",
"scope"
],
"properties": {
"bundle_format_version": { "const": 1 },
"content_hash": {
"type": "object",
"required": ["algorithm", "of", "value"],
"properties": {
"algorithm": { "const": "sha256" },
"of": { "type": "string" },
"value": { "$ref": "#/$defs/sha256" }
}
},
"generated_at": { "$ref": "#/$defs/iso8601" },
"source": {
"type": "object",
"required": ["system", "node_id"],
"properties": {
"system": { "type": "string", "minLength": 1 },
"node_id": { "type": "string", "minLength": 1 },
"product_version": { "type": "string" },
"database_schema_fingerprint": { "type": "string" }
}
},
"counts": {
"type": "object",
"required": ["books", "chapters", "utterances", "speakers", "render_records", "records_total"],
"properties": {
"books": { "type": "integer", "minimum": 1 },
"chapters": { "type": "integer", "minimum": 0 },
"utterances": { "type": "integer", "minimum": 0 },
"speakers": { "type": "integer", "minimum": 0 },
"render_records": { "type": "integer", "minimum": 0 },
"records_total": { "type": "integer", "minimum": 1 }
}
},
"record_kinds": {
"type": "object",
"required": ["discriminator", "values"],
"properties": {
"discriminator": { "const": "kind" },
"values": {
"type": "array",
"allOf": [
{ "contains": { "const": "book" } },
{ "contains": { "const": "chapter" } },
{ "contains": { "const": "speaker" } },
{ "contains": { "const": "utterance" } },
{ "contains": { "const": "render" } }
]
}
}
},
"scope": {
"type": "object",
"required": ["books_full_detail"],
"properties": {
"books_full_detail": { "type": "array", "minItems": 1, "items": { "type": "string" } },
"books_summary_only": { "type": "array", "items": { "type": "string" } },
"note": { "type": "string" }
}
},
"required_fields": { "type": "object" }
}
},
"record": {
"title": "one manifest.jsonl record",
"oneOf": [
{ "$ref": "#/$defs/book" },
{ "$ref": "#/$defs/chapter" },
{ "$ref": "#/$defs/speaker" },
{ "$ref": "#/$defs/utterance" },
{ "$ref": "#/$defs/render" }
]
},
"book": {
"type": "object",
"required": [
"id", "kind", "generated_at", "name", "chapters",
"chapter_count", "utterance_count", "language_designations"
],
"properties": {
"id": { "type": "string", "minLength": 1 },
"kind": { "const": "book" },
"generated_at": { "$ref": "#/$defs/iso8601" },
"name": { "type": "string", "minLength": 1 },
"title": { "type": ["string", "null"] },
"status": { "type": ["string", "null"] },
"chapters": { "type": "array", "minItems": 1, "items": { "type": "string" } },
"chapter_count": { "type": "integer", "minimum": 0 },
"utterance_count": { "type": "integer", "minimum": 0 },
"speaker_count": { "type": "integer", "minimum": 0 },
"novel_chapter_count": { "type": "integer" },
"front_and_back_matter_count": { "type": "integer" },
"published_artifact_ids": { "type": "array", "items": { "type": "string" } },
"language_designations": {
"type": "array",
"items": { "type": "string" },
"description": "Empty is an accepted answer, not an error. Target languages are decided on the translation side."
},
"language_designation_note": { "type": "string" },
"extension_container_mismatch_count": { "type": "integer", "minimum": 0 },
"extension_container_mismatches": { "type": "array" },
"speaker_names_without_a_profile": { "type": "array" },
"declared_total_chapters": { "type": ["integer", "null"] },
"declared_total_words": { "type": ["integer", "null"] },
"declared_vs_measured_note": { "type": ["string", "null"] },
"numbering": { "type": "object" },
"path_relative_to": { "type": ["string", "null"] },
"source_document_format": { "type": ["string", "null"] },
"source_path_redacted": { "type": ["string", "null"] },
"created_at": { "type": ["string", "null"] },
"updated_at": { "type": ["string", "null"] }
}
},
"chapter": {
"type": "object",
"required": [
"id", "kind", "generated_at", "book_id", "chapter_index",
"database_row_id", "title", "source_text_sha256", "renders",
"numbering_basis", "utterance_count"
],
"properties": {
"id": { "type": "string", "minLength": 1 },
"kind": { "const": "chapter" },
"generated_at": { "$ref": "#/$defs/iso8601" },
"book_id": { "type": "string", "minLength": 1 },
"chapter_index": {
"type": "integer",
"description": "Reading order. Negative is front matter. NEVER identity."
},
"database_row_id": { "type": "integer", "description": "Source row id. Provenance only." },
"title": { "type": ["string", "null"] },
"source_text_sha256": { "$ref": "#/$defs/sha256" },
"source_text_char_count": { "type": "integer", "minimum": 0 },
"word_count": { "type": "integer", "minimum": 0 },
"utterance_count": { "type": "integer", "minimum": 0 },
"renders": { "type": "array", "items": { "type": "string" } },
"numbering_basis": {
"type": "object",
"description": "Required so a derived order can never be mistaken for identity."
},
"status": { "type": ["string", "null"] }
}
},
"speaker": {
"type": "object",
"required": [
"id", "kind", "generated_at", "primary_name", "has_profile",
"is_narrator", "aliases", "utterance_count", "utterance_count_casefold_grouped"
],
"properties": {
"id": { "type": "string", "minLength": 1 },
"kind": { "const": "speaker" },
"generated_at": { "$ref": "#/$defs/iso8601" },
"primary_name": { "type": "string", "minLength": 1 },
"aliases": { "type": "array", "items": { "type": "string" } },
"has_profile": { "type": "boolean" },
"is_narrator": { "type": "boolean" },
"is_group": { "type": "boolean" },
"unidentified": { "type": "boolean" },
"utterance_count": { "type": "integer", "minimum": 0 },
"utterance_count_casefold_grouped": { "type": "integer", "minimum": 0 },
"utterance_count_including_implicit_narrator": { "type": "integer", "minimum": 0 },
"casefold_collision_group": { "type": ["string", "null"] },
"chapters_appeared": { "type": "array" },
"name_is_distinct_from_spellings": { "type": "array", "items": { "type": "string" } },
"voice_review_status": { "type": ["string", "null"] },
"voice_review_recorded": { "type": ["boolean", "null"] },
"tts_engine_used": { "type": ["string", "null"] },
"tts_engine_decided_at": { "type": ["string", "null"] },
"tts_engine_fallback_reason": { "type": ["string", "null"] },
"assigned_edge_voice": { "type": ["string", "null"] }
}
},
"utterance": {
"type": "object",
"required": [
"id", "kind", "generated_at", "book_id", "chapter_id",
"utterance_index", "text", "text_sha256", "utterance_type",
"speaker_id", "speaker_name_raw", "speaker_name_resolved",
"speaker_resolution", "render_id", "needs_review"
],
"properties": {
"id": { "type": "string", "minLength": 1 },
"kind": { "const": "utterance" },
"generated_at": { "$ref": "#/$defs/iso8601" },
"book_id": { "type": "string", "minLength": 1 },
"chapter_id": { "type": "string", "minLength": 1 },
"database_row_id": { "type": "integer" },
"utterance_index": { "type": "integer", "minimum": 0 },
"utterance_type": { "enum": ["narration", "dialogue", "scene_break"] },
"text": { "type": "string" },
"text_sha256": { "$ref": "#/$defs/sha256" },
"text_char_count": { "type": "integer", "minimum": 0 },
"speaker_id": { "type": "string", "minLength": 1 },
"speaker_name_raw": {
"type": ["string", "null"],
"description": "Exactly what is stored. null means narrator, not missing."
},
"speaker_name_resolved": { "type": "string", "minLength": 1 },
"speaker_resolution": { "enum": ["explicit", "implicit_narrator"] },
"render_id": { "type": ["string", "null"] },
"attribution_confidence": { "type": ["number", "null"] },
"attribution_uncertain": { "type": ["boolean", "null"] },
"attribution_evidence_kind": { "type": ["string", "null"] },
"needs_review": { "type": "boolean" },
"review_reason": { "type": ["string", "null"] },
"emotion": { "type": ["string", "null"] },
"pace": { "type": ["string", "null"] },
"instruct_is_set": { "type": ["boolean", "null"] },
"status": { "type": ["string", "null"] }
},
"allOf": [
{
"if": {
"properties": { "speaker_resolution": { "const": "implicit_narrator" } },
"required": ["speaker_resolution"]
},
"then": {
"properties": { "speaker_name_raw": { "type": "null" } }
}
},
{
"if": {
"properties": { "speaker_resolution": { "const": "explicit" } },
"required": ["speaker_resolution"]
},
"then": {
"properties": { "speaker_name_raw": { "type": "string", "minLength": 1 } }
}
}
]
},
"render": {
"type": "object",
"required": [
"id", "kind", "generated_at", "render_role", "path", "relative_to",
"path_is_absolute", "audio_format", "duration_ms", "byte_size",
"content_sha256", "book_id", "inputs"
],
"properties": {
"id": { "type": "string", "minLength": 1 },
"kind": { "const": "render" },
"generated_at": { "$ref": "#/$defs/iso8601" },
"render_role": {
"enum": [
"utterance_audio", "chapter_audio", "distribution_track",
"assembled_book", "voice_reference"
]
},
"render_stage": { "type": ["string", "null"] },
"book_id": { "type": ["string", "null"] },
"chapter_id": {
"type": ["string", "null"],
"description": "Absent for project-level renders (voice_reference, assembled_book). Absent and null are both 'no chapter'; the ingest treats them the same."
},
"path": { "type": "string", "minLength": 1 },
"relative_to": { "$ref": "#/$defs/relativeTo" },
"path_is_absolute": { "type": "boolean" },
"audio_format": {
"type": ["object", "null"],
"required": ["container", "codec", "extension_matches_container", "detected_by"],
"properties": {
"container": { "type": "string", "minLength": 1 },
"codec": { "type": ["string", "null"] },
"sample_rate_hz": { "type": ["integer", "null"] },
"channel_count": { "type": ["integer", "null"] },
"bit_rate_bps": { "type": ["integer", "null"] },
"file_extension": { "type": ["string", "null"] },
"extension_matches_container": { "type": ["boolean", "null"] },
"detected_by": { "enum": ["wave-module", "ffprobe", "none"] }
}
},
"duration_ms": {
"type": ["integer", "null"],
"minimum": 0,
"description": "Unit in the name. null is unknown, which is not zero."
},
"byte_size": { "type": ["integer", "null"], "minimum": 0 },
"content_sha256": { "$ref": "#/$defs/sha256" },
"inputs": { "type": "array", "items": { "type": "string" } },
"file_present": { "type": ["boolean", "null"] },
"file_modified_at": { "type": ["string", "null"] },
"stale": { "type": ["boolean", "null"] },
"voice_id": { "type": ["string", "null"] },
"track_number_in_name": {
"type": ["string", "integer", "null"],
"description": "A string here, e.g. \"01\". Never the reading order."
},
"title_in_name": { "type": ["string", "null"] },
"embedded_metadata_language": { "type": ["string", "null"] },
"embedded_metadata_narrator": { "type": ["string", "null"] },
"embedded_metadata_title": { "type": ["string", "null"] }
}
}
}
}