# Audio classification formats
This library is the stable direct-re-export facade for the audio-classification transaction-event and local-fragment formats. It performs no filesystem I/O, canonical-transaction ordering, Peering submission, immutable Object work, provider calls, retry execution, status projection, identity decisions, training, persistence, or networking.
## Public API
The following paths are direct re-exports. `TxId`, `ExecutedAnalysis`, `FeatureVector24`, and `LocalSpeakerLabel` are defined by their owning libraries.
```rust
pub enum FragmentStageV1 {
Queue,
Transcript,
SpeakerLabels,
SpeakerFeatures,
Structuring,
LabelConfirmation,
}
pub struct QueueV2 {
pub audio_object_id: TxId,
}
pub struct ProgressV1 {
pub fragment_id: TxId,
pub update: ProgressUpdateV1,
}
pub enum ProgressUpdateV1 {
LlmJobStarted {
sequence: u64,
stage: FragmentStageV1,
name: String,
},
LlmJobSucceeded {
sequence: u64,
},
LlmJobFailed {
sequence: u64,
error: String,
},
StageCompleted {
stage: FragmentStageV1,
},
}
pub struct TranscriptionCompleteV1 {
pub fragment_id: TxId,
pub analysis: ExecutedAnalysis,
}
pub struct FailedV2 {
pub fragment_id: TxId,
pub stage: FragmentStageV1,
pub llm_job_sequence: Option<u64>,
pub error: String,
}
pub struct DiscardedV2 {
pub fragment_id: TxId,
}
pub struct SpeakerLabelV1 {
pub speaker: LocalSpeakerLabel,
pub person_id: String,
}
pub struct LabelConfirmationV1 {
pub fragment_id: TxId,
pub interim_txid: TxId,
pub speakers: Vec<SpeakerLabelV1>,
}
pub enum AudioClassificationEventV3 {
Queue(QueueV2),
Progress(ProgressV1),
TranscriptionComplete(TranscriptionCompleteV1),
Failed(FailedV2),
Discarded(DiscardedV2),
LabelConfirmation(LabelConfirmationV1),
}
pub struct StagedSpeakerV1 {
pub speaker: LocalSpeakerLabel,
pub language: String,
pub features: FeatureVector24,
pub usable_for_training: bool,
}
pub struct StagedFragmentV1 {
pub analysis_txid: TxId,
pub transcript: String,
pub speakers: Vec<StagedSpeakerV1>,
}
pub struct FinalSpeakerV1 {
pub speaker: LocalSpeakerLabel,
pub person_id: String,
pub language: String,
pub features: FeatureVector24,
pub usable_for_training: bool,
}
pub struct FinalFragmentV1 {
pub analysis_txid: TxId,
pub confirmation_txid: TxId,
pub transcript: String,
pub speakers: Vec<FinalSpeakerV1>,
}
pub enum FormatError {
Truncated,
LengthOverflow,
UnsupportedVersion(u8),
UnknownEventTag(u8),
InvalidEventBody,
InvalidFragmentKind(u8),
NonZeroReserved,
NonZeroPadding,
NonZeroStagedConfirmation,
InvalidTxIdSlotLength(usize),
InvalidUtf8,
InvalidSpeakerLabel,
InvalidFeatureBody,
InvalidBoolean(u8),
TrailingBytes,
InvalidPath,
}
pub struct TxIdSlot {
/* private fields */
}
impl TxIdSlot {
pub const LEN: usize = 16;
pub const PADDING_LEN: usize = 4;
pub const fn new(txid: TxId) -> Self;
pub const fn txid(self) -> TxId;
pub fn encode(self) -> [u8; Self::LEN];
pub fn decode(bytes: &[u8]) -> Result<Self, FormatError>;
}
pub fn encode_event(event: &AudioClassificationEventV3) -> Result<Vec<u8>, FormatError>;
pub fn decode_event(bytes: &[u8]) -> Result<AudioClassificationEventV3, FormatError>;
pub fn encode_staged_fragment(value: &StagedFragmentV1) -> Result<Vec<u8>, FormatError>;
pub fn decode_staged_fragment(bytes: &[u8]) -> Result<StagedFragmentV1, FormatError>;
pub fn encode_final_fragment(value: &FinalFragmentV1) -> Result<Vec<u8>, FormatError>;
pub fn decode_final_fragment(bytes: &[u8]) -> Result<FinalFragmentV1, FormatError>;
pub fn txid_path(txid: TxId) -> PathBuf;
pub fn txid_from_path(path: impl AsRef<Path>) -> Result<TxId, FormatError>;
```
`FragmentStageV1` implements `Debug`, `Clone`, `Copy`, `PartialEq`, `Eq`, `Serialize`, and `Deserialize`. `QueueV2`, `ProgressUpdateV1`, `FailedV2`, `DiscardedV2`, `SpeakerLabelV1`, and `LabelConfirmationV1` implement `Debug`, `Clone`, `PartialEq`, `Eq`, `Serialize`, and `Deserialize`. `ProgressV1` and `TranscriptionCompleteV1` implement `Debug`, `Clone`, `PartialEq`, `Serialize`, and `Deserialize`. `AudioClassificationEventV3`, `StagedSpeakerV1`, `StagedFragmentV1`, `FinalSpeakerV1`, and `FinalFragmentV1` implement `Debug`, `Clone`, and `PartialEq`. `FormatError` implements `Debug`, `Clone`, `PartialEq`, `Eq`, `Display`, and `Error`. `TxIdSlot` implements `Debug`, `Clone`, `Copy`, `PartialEq`, and `Eq`.
## Transaction events
`encode_event` and `decode_event` use envelope version byte `4`, followed by one stable tag byte and one postcard body for the selected variant. Tags are `1` Queue, `2` TranscriptionComplete, `3` Failed, `4` Discarded, `5` LabelConfirmation, and `6` Progress. Every event `TxId` serializes as exactly `[u8; 12]`.
`decode_event` accepts only version 4, a known tag, one structurally valid body, and no trailing bytes. It returns `FormatError::Truncated` before a complete envelope, `UnsupportedVersion` for another version, `UnknownEventTag` for an unknown tag, `InvalidEventBody` for an invalid postcard body, and `TrailingBytes` after an otherwise valid body. Decoding is structural: it does not reject blank strings, duplicate labels, invalid state references, or event ordering.
## Local fragments and paths
The staged and final fragment codecs use format version 1. Bytes 0 through 15 are a header containing version `1`, kind `1` staged or `2` final, and fourteen zero reserved bytes. Bytes 16 through 31 contain the aligned analysis `TxIdSlot`. Bytes 32 through 47 are zero for staged values and contain the aligned confirmation `TxIdSlot` for final values. The body starts at byte 48.
Variable lengths and speaker counts are little-endian `u64`. The body contains transcript UTF-8, speaker count, and ordered speakers. Speakers contain canonical labels, final-only person IDs, language, length-prefixed postcard `FeatureVector24`, and one usability byte restricted to 0 or 1.
`TxIdSlot` stores 12 ID bytes followed by four zero padding bytes. `TxIdSlot::decode` returns `InvalidTxIdSlotLength` for a slice other than 16 bytes and `NonZeroPadding` for nonzero padding. Fragment decoding returns the applicable `FormatError` for truncation, length overflow, unsupported versions or kinds, nonzero reserved bytes or padding, a nonzero staged confirmation slot, malformed UTF-8, labels or feature bodies, invalid booleans, and trailing bytes. It does not call semantic validators from the re-exported analysis values.
`txid_path` maps a `TxId` to `<first>/<remaining15>.dat` using a 16-character URL-safe unpadded base64 name. `txid_from_path` accepts only that two-component relative form and otherwise returns `FormatError::InvalidPath`. Neither function accesses a filesystem.
## Performance and concurrency
Event and fragment encoding and decoding take O(input plus output) work. Encoding allocates the returned bytes; decoding allocates only represented values, and untrusted fragment speaker counts are not eagerly allocated. Path conversion takes constant time and bounded memory. The library is stateless and owns no locks, queues, waits, callbacks, backpressure, or serialized resources, so independent calls do not block one another.