- 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
7.1 KiB
UMBRA AUDIO — METADATA HANDOVER, ACCEPTED FORMAT, AND THE TTS DOCUMENT
Prompt to the OpenCode session on the audio system (host umbraaudio-m4)
CONTEXT
You produced ~/audio-read/bundles/dh-bundle/ (manifest.jsonl sha256
21ce568787540cf7164b6ab4028f1caee51996447537022154d1e5768cde87ba). It has been
received and independently verified on the controller host:
- the declared content_hash matches the manifest bytes;
- your validate.py passes on the good bundle and fails on each broken copy;
- the controller's accepted-format validator passes: 8884 records, book=1 chapter=32 speaker=55 utterance=4319 render=4477.
Nothing was written to the controller. The confirmation gate is intact.
The controller's answer to your four requests is in three files, delivered alongside this prompt:
- audio-system-mapping-v1.md (field-by-field mapping, source -> controller)
- audio-system-manifest-v1.schema.json (the accepted manifest format)
- validate-audio-manifest.py (the accepted-format validator, run by the controller)
- audio-system-reply-v1.md (the full reply: verification, decisions, ingest, credential, and the TTS request)
Read those four before acting. This prompt is the instruction; those are the detail.
DECISIONS ALREADY MADE (do not re-open; implement against them)
-
Format: the same bundle format you already emit, NARROWED. Field names are unchanged. Do not rename anything on the wire. The accepted format is defined by audio-system-manifest-v1.schema.json.
-
Chapter identity is chapter.id. chapter_index is reading order and a hint; the filename number is neither. Your numbering_basis field is required and is what makes this unambiguous.
-
The narrator is a role. Both narrator speaker rows and all three spellings (NULL, 'narrator', 'Narrator') resolve to one narrator role for voicing; the source spellings are kept as aliases for audit. This is the controller's one merge, and it is reported on every import. Other speaker rows are NOT merged; casefold_collision_group is stored and surfaced.
-
A render's bytes are never fetched. Every artifact is recorded integrity='unverified'; content_sha256 is recorded as a claim, not a fact.
-
media_type is derived from audio_format.container, never from the path extension. The 33 files named .wav that are MPEG audio are the test case.
-
language_designations empty is accepted as an answer. Target languages are a translation-side decision; do not invent them.
-
Ingest is file-based first. No credential is required and nothing is pushed. A push endpoint, if built later, will use a scoped service token (
dataset:ingest), NOT a node key. No action from you on credentials today.
YOUR NEXT ACTIONS
Action 1 — Confirm the accepted format (short).
Copy audio-system-manifest-v1.schema.json and validate-audio-manifest.py into a copy of your bundle directory and run:
python3 validate-audio-manifest.py .
Expected: "
: 8884 record(s) accepted. content_hash . book=1, chapter=32, speaker=55, utterance=4319, render=4477", exit 0.If it fails, report the exact lines. Do not edit the bundle to make it pass unless the failure is a real defect in your generator, and say so if it is.
Note: the validator needs the jsonschema package. If it is not installed on
the audio host, it says so and refuses to report acceptance rather than
half-checking. Install it into a throwaway venv for the check; do not add it to
the audio system's own environment if that would disturb the running system.
Action 2 — Produce the TTS checked document (the blocking one).
You offered this in your reply and the controller needs it to write speak
without guessing. Produce it as a checked document with the same standard as
the bundle: measured, versioned, hashed, with a note per row where something is
unknown rather than a near-match. It must answer:
- Provenance: upstream repository and commit; the three commits on top, as a diff or a per-commit summary with purpose; the license.
- The model: exact model id(s) (Qwen3-TTS-12Hz-1.7B-VoiceDesign and -Base), which one serves which path, weights source and checksum, on-disk size, and the VRAM/working-set at load and at inference.
- The input contract: request fields (text, voice / voice-design, language, the instruct/emotion/pace fields, sample rate), the reference-audio (cloning) path and its format, maximum input length, and whether it streams or returns a whole file.
- The output contract: container, codec, sample rate, channels, bitrate for a
rendered take, so a render from
speakis described the same way your existing renders are. - Determinism: given identical text and voice, is the audio bit-identical? If sampling is involved, what is seeded and what is not.
- Language coverage: which languages the model actually speaks, how the language is selected, and where quality is known to be weak.
- Voice identity: how a voice_id maps to a speaker, and how tts_engine_used:"qwen" relates to assigned_edge_voice (e.g. "en-CA-ClaraNeural:-100") — is the Edge voice the fallback engine, the reference audio, or the design prompt? Explain the tts_engine_fallback_reason values.
- Failure modes: OOM, over-length text, unsupported language — what is returned and how it appears in tts_engine_fallback_reason.
- The runtime surface: the HTTP/queue API you expose (or that it is
in-process), its auth, and its concurrency limits — so
speakon the controller is a client of something defined.
Deliver as a document named tts-engine.md (or .json + a short README) with the measured values, not prose claims. Where a value is unknown, say "unknown" and why; do not estimate it as if measured.
Action 3 — Optional, only if asked: scale totals.
Totals across all projects (books, hours, bytes). The bundle carries per-book counts and byte_size on every render, so extend the build rather than hand over a number you did not measure. Not blocking.
CONSTRAINTS
- Do not modify the audio system. It is independent and keeps running. This is a read-only metadata export and a documentation task.
- Do not push anything to the controller. There is no endpoint and no credential by design; the handover is the file.
- Keep the generator deterministic: sorted JSON keys, fixed record order, so an unchanged project still hashes identically.
- Every claim in the TTS document must be checkable against the running system. "A validator nobody has seen fail is not evidence" applies here too: if you say the model produces 24 kHz mono, show the ffprobe output.
REPORT BACK
Post a short reply with:
- the validator result (Action 1);
- the TTS document, or the path where it was written, and any item from the nine you could not measure;
- anything in the mapping or the accepted format you believe is wrong — before implementing against it, not after.
The controller will not import the bundle until the accepted-format check passes and the operator confirms. There is no rush and no penalty for an honest "unknown".