kcode-audio-ingress 0.1.0

Durable automatic audio transcription with restart recovery
Documentation
# API

`kcode-audio-ingress` durably accepts complete WAV byte buffers and
automatically drives `kcode-audio-transcribe`. The caller supplies an already
configured transcriber and one persistence-root path. The library derives its
database and retained-original locations beneath that root.

```rust
pub struct AudioInput {
    pub bytes: Vec<u8>,
    pub recorded_at: chrono::DateTime<chrono::Utc>,
    pub original_filename: Option<String>,
}

pub struct Submission {
    pub recording_id: uuid::Uuid,
    pub deduplicated: bool,
}

pub struct Status {
    pub recordings: Vec<RecordingStatus>,
}

pub struct RecordingStatus {
    pub id: uuid::Uuid,
    pub sha256: String,
    pub original_filename: String,
    pub size_bytes: u64,
    pub recorded_at: chrono::DateTime<chrono::Utc>,
    pub received_at: chrono::DateTime<chrono::Utc>,
    pub transcription_model: String,
    pub reconciliation_model: String,
    pub reconciliation_reasoning: String,
    pub state: RecordingState,
}

pub enum RecordingState {
    Queued,
    Processing {
        attempt: u8,
        progress: kcode_audio_transcribe::TranscriptionStatus,
    },
    Complete {
        transcript: String,
    },
    Failed {
        attempts: u8,
        error: String,
        retryable: bool,
    },
}

pub enum ErrorKind {
    InvalidInput,
    NotFound,
    Conflict,
    Internal,
}

pub struct Error {
    // private fields
}

pub struct AudioIngress {
    // private fields
}

impl Error {
    pub fn kind(&self) -> ErrorKind;
}

impl AudioIngress {
    pub async fn open(
        persistence_root: impl AsRef<std::path::Path>,
        transcriber: kcode_audio_transcribe::AudioTranscriber,
    ) -> Result<AudioIngress, Error>;

    pub async fn submit(&self, input: AudioInput) -> Result<Submission, Error>;

    pub fn status(&self) -> Result<Status, Error>;

    pub fn retry(&self, recording_id: uuid::Uuid) -> Result<(), Error>;
}
```

## Operation

- `AudioIngress::open` creates or opens `<root>/state.sqlite3`, creates
  `<root>/originals/`, applies compatible schema migrations, recovers
  interrupted attempts, and starts the background worker. It requires an
  active Tokio runtime.
- `submit` rejects an empty buffer, computes its SHA-256 identity, retains the
  exact bytes in content-addressed storage, commits the recording row, and
  returns only after the original and metadata are durable. Repeated bytes
  return the existing recording with `deduplicated: true`.
- `status` returns one complete snapshot ordered by recording time, newest
  first. A completed state contains the canonical reconciled Markdown
  transcript. Processing progress never contains a transcript body.
- `retry` applies only to a failed recording. It clears the previous attempt
  budget and schedules a fresh automatic five-attempt budget. Retrying an
  unknown identifier returns `NotFound`; retrying any nonfailed recording
  returns `Conflict`.

The library automatically retries a retryable full transcription job at most
five times. Non-retryable input or provider failures stop immediately.
Exhausted work remains failed until `retry` is called. Active dependency jobs
are in memory; after process restart the library starts a new job from the
durable original.

The library has no HTTP, multipart, streaming-input, storage-quota, transcript
delivery, Kmap, Chatend, or application-framework API.