Asks for what is needed to write a correct mapping, in a form that can be verified rather than read. Two documents: docs/audio-system-data-request.md - what to send, in what format, and why that format. docs/audio-system-bundle-validator.py - ships *with* the request rather than after it, so the sender can check their own work before it travels. Standard library only: whoever runs it runs it on the audio system, and adding a dependency to someone's working machine to validate a file is not a reasonable thing to ask. That means the schema checking is the subset possible without a library - a smoke alarm, not an inspector - and the file says so rather than implying more. The reasoning behind the format is the substance. Prose cannot be validated: every mismatch is something a human has to notice, and the ones that get missed are the interesting ones - derived chapter order, two fields that mean slightly different things, a path relative to something unspecified. A validator that names the record and the field turns a round trip into a checklist, and reports every problem rather than stopping at the first, because a validator that stops at the first failure makes a three-round-trip conversation. Also asks for the things that are cheapest to supply and most expensive to guess: the vocabulary table (guessing terminology is how a mapping looks correct and reads the wrong field), which fields are derived (a derived chapter order treated as authoritative will disagree the first time somebody reorders a chapter by hand), and what the TTS engine actually is - fork or patch, what changed, whether it loads a model and how big. That last one decides whether a 48 GB CPU-only node can run it at all, so the speak work function cannot be written until it is answered. Explicitly not asked for: media files, source code, screenshots, or anything the sender would have to reconstruct. "We do not record this" is a complete answer and far better than an estimate presented as fact. The validator was itself tested against a deliberately broken bundle, which is the only way to know a check can fail. It caught a dangling reference, a unitless duration, two unanchored paths and a planted credential, and passed a correct bundle. Two flaws in it were found that way and fixed: it reported the same path problem twice, and every credential twice, because a tool whose only job is to be trusted about specifics loses credibility the first time it says the same thing twice. 704 passed, 4 skipped - no product code touched.
8.6 KiB
What I need from the audio system, and in what format
To: whoever works on the audio system (mini-m4) From: the UmbraTrans controller side Why: to write a correct mapping from the audio system's data into UmbraTrans' artifact model, without guessing and without touching the running system.
Nothing here asks you to change anything. The audio system stays independent and keeps working exactly as it does. This is a description of what exists, plus a definition of what the new system will expect, so both sides are writing against the same thing.
The one thing that matters most
Prose cannot be validated. JSON can.
If the format arrives as a document describing fields, every mismatch is something a human has to notice, and the ones that get missed are the interesting ones — derived chapter order, two fields that mean slightly different things, a path that is relative to something unspecified.
So everything below is machine-readable, and it ships with a validator. When it does not match, the validator says exactly which record and which field, and exits non-zero. That turns a round trip into a checklist rather than a correspondence.
P0 — blocks the mapping. Nothing else can start without these.
1. One complete book, traced end to end
Not a synthetic example. One real book, with real identifiers, showing the whole path:
manuscript chapter → render → assembled audiobook
For that one book I need every record that exists at each stage, with the identifiers that link them. If I can trace one book completely, I can infer the pattern; if I only have aggregate shapes I will guess, and the guess will be wrong somewhere invisible.
2. The vocabulary
Your words for things, and mine. I suspect these do not line up, and where they don't is where the bugs will be.
| Concept | What I call it | What you call it |
|---|---|---|
| one rendered piece of audio | ? | ? |
| a chapter's worth of audio | ? | ? |
| the assembled book | ? | ? |
| the narration voice | ? | ? |
| a take that was rejected | ? | ? |
| the thing that gets published | ? | ? |
A table with two columns and a note per row is enough. Guessing terminology is how a mapping looks correct and reads the wrong field.
3. The fields of each record type, with meanings
For every kind of record the audio system keeps: its fields, what each means, which are required, and which are derived from something else.
Derived fields matter disproportionately. A derived chapter order that I treat as authoritative will disagree with your ordering the first time a chapter is reordered by hand.
P1 — needed for correctness
4. Lineage: what produces what
Which step produces which output, so I can express a derivation rather than just a list. An artifact that says "I came from these inputs" is far more useful than one that exists.
5. What the TTS engine actually is
Not the intention — the reality. I need to write the speak work function and I will not
write it blind:
- Is Qwen3-TTS a fork or a patch on the upstream? A link or a diff summary.
- What was changed, and why. In particular anything affecting the input contract: does it take the text the same way, does it need segment markers, phoneme tags, or a specific format?
- Does it load a model, and how big? This decides whether a 48 GB CPU-only node can run it at all, which changes the whole plan.
- What the output actually is: one file per chapter, or per paragraph, or a stream?
6. Formats on disk
What each produced file physically is: container, codec, sample rate, channel layout,
bitrate. And the naming convention, plus what the names mean — is the 003 in
ch003_take2.wav a chapter number, an index, or a sort position?
7. Scale
Roughly: how many books, how many chapters per book, total hours, and total bytes. This sizes everything downstream and tells me whether the catalogue is something a person maintains or something that has to be generated.
P2 — useful, not blocking
8. What exists but is not part of the product
Caches, scratch renders, rejected takes, test output. I need to know they exist so the mapping does not sweep them into the catalogue — a catalogue of scratch files is a catalogue nobody can answer a question against.
9. Anything that breaks
Known-bad files, chapters that fail, edge cases you already work around. This is the cheapest information I will ever get and it saves the most time.
The exact format
A single compressed archive, so it is one thing to move and one thing to version:
audio-system-bundle.tar.gz
├── README.md # what this is, how it was generated, how to regenerate it
├── bundle.json # root index: what is inside, counts, generated-at, source version
├── VOCABULARY.md # your terms <-> mine, per concept
├── schemas/
│ ├── manifest.schema.json
│ ├── <record-type>.schema.json # one per record type in the audio system
│ └── lineage.schema.json
├── manifest.jsonl # every record, one JSON object per line
├── examples/
│ └── <one-real-book>/
│ ├── manifest.json # every record for this book only
│ ├── lineage.json # what produced what, for this book
│ └── README.md # a short prose trace of this book, for a human
└── validate.py # exits non-zero, names the record and field on any mismatch
Conventions I am asking for, to remove ambiguity
These are the things that go wrong when nobody says them out loud:
- Units in the field name.
duration_ms,byte_size,vram_total_mb. Notdurationand notlength. - All timestamps UTC, ISO 8601 with an explicit
Zor+00:00. - Explicit versions on anything that can change: engine version, bundle format version, audio system version.
- Relative paths are declared relative to what. If a path is relative, say relative to the book directory, and give one worked example of an absolute one.
- Null means absent, not unknown. If a distinction is needed, use two fields or an
explicit
"unknown"— a null that means two things will be read as whichever the reader assumed. - No credentials of any kind in the bundle. No keys, no tokens, no hostnames that would be sensitive, no personal data. If a record needs a path that contains a username, replace it with a placeholder and say so in the README.
The validator
validate.py should check that:
- Every record validates against its schema.
- Every identifier referenced by another record exists.
- One real book traces end to end with no dangling references.
And it should print every problem, not stop at the first, then exit non-zero. A validator that stops at the first error makes a three-round-trip conversation.
What I do not need
To keep this small and quick to produce:
- Media files. Not for this step. A handful of small samples later, once I know what I am looking at — the metadata tells me what to ask for samples of.
- Source code, unless a specific question cannot be answered otherwise. I would rather ask one pointed question than read a repository.
- Screenshots.
- Anything you would have to reconstruct. If it does not exist, say so — "we do not record this" is a complete and useful answer, and far better than an estimate presented as fact.
Where to put it
Anything I can read. The most convenient is a copy on 238, which I already have access
to; scp it there and tell me the path.
If it is easier to hand it over directly, that works too.
Size: the metadata bundle should be well under a megabyte. If what you have is much larger, send P0 first — the worked example, the vocabulary and the field definitions are enough for me to start.
What happens next, so you know this is not a one-way request
Once I have it I will write back:
- A mapping document — every source field to every UmbraTrans field, with anything that has no equivalent marked as such rather than quietly dropped.
- A manifest format UmbraTrans will accept, as a JSON Schema plus a validator, so the audio system can emit it directly whenever you want.
- A first ingest, once the format agrees, which copies metadata and references into UmbraTrans. The audio system keeps its data and keeps running. Nothing is moved out from under it and nothing it depends on is touched.
If the mapping turns out to need something the bundle does not have, I will come back with a specific question rather than an open-ended request.