# Chronicle Audio Entry Export v2

Status: **specified for #736; no runtime emits this format yet**

This is an open, password-protected, self-contained **per-entry** export for v2 audio sources in Origo web and Pocket. It does not change [Chronicle Export v1](chronicle-export-v1.md) or Pocket's frozen v1 `.pchronicle` payload. The protected envelope and decrypted payload have separate schemas: [`audio-entry-protected-v2.schema.json`](../schemas/audio-entry-protected-v2.schema.json) and [`audio-entry-payload-v2.schema.json`](../schemas/audio-entry-payload-v2.schema.json). A conforming implementation can be written from these specifications without Origo software or a network call.

## Protected envelope

The file is UTF-8 JSON, no byte-order mark, conforming to the protected schema. It has exactly `envelopeVersion: 2`, `format: "origo-chronicle-audio-entry"`, `kdf: {algorithm: "PBKDF2-HMAC-SHA256", iterations: 600000, saltBase64}`, `cipher: {algorithm: "AES-256-GCM", nonceBase64}`, and `ciphertextBase64`. Base64 is RFC 4648 standard alphabet with padding and no whitespace. Decode a 16-byte salt, a 12-byte nonce, and ciphertext with at least a 16-byte tag. Reject noncanonical base64 and invalid lengths. Generate fresh cryptographically random salt and nonce for **each** export; never reuse a nonce with the same key. Derive 32 bytes from the person's password using PBKDF2-HMAC-SHA256 at exactly 600000 iterations, with UTF-8 password bytes as supplied, without Unicode normalization or trimming. The user interface should accept a strong password; the format cannot make a weak password strong.

AES-256-GCM uses a 128-bit tag appended to ciphertext, as WebCrypto and Node's combined representation can produce. The authenticated additional data (AAD) is exactly:

```text
UTF8("origo/chronicle/audio-export/v2") || 0x00 ||
rawSalt[16] || rawNonce[12] || U32BE(600000)
```

`U32BE(n)` is the four-octet unsigned big-endian representation; for 600000 it is `00 09 27 c0` in hexadecimal.

All envelope interpretation fields are fixed or included in the AAD; reject any additional fields. Decrypt/authenticate before parsing or displaying any payload. Wrong password and tampering both fail authentication and must not disclose partial plaintext. The payload bytes are RFC 8785 JSON Canonicalization Scheme (JCS) UTF-8 JSON. Readers should reject noncanonical plaintext bytes after decryption; writers produce JCS directly. This enables portable fixture-byte comparison but is not an additional authentication layer.

## Decrypted payload

The payload has `exportFormatVersion: 2`, unique `exportId`, UTC millisecond `generatedAt`, `producer: {name,version}`, `custody`, `entry`, `sources`, `audioFiles`, `derivations`, and `integrityEvidence` (or `null` plus `integrityEvidenceNote`). `custody` explicitly states that this separate encrypted copy is beyond runtime deletion reach. `entry: {id,sourceIds,status,transcriptStatus}` identifies a review entry/group and its **ordered distinct** original source IDs. `entry.id` is not a chain entry ID. Source ordering, grouping, and split text boundaries are review relationships outside each audio source commitment and are **not chain-attested**.

For `status: "live"`, `sources` contains exactly one complete Source Record v2 for each **surviving** `entry.sourceIds` element, in that order. `audioFiles` has one `{sourceId,bytesBase64}` object per surviving source, in the same order. A selected source may be omitted only when its chain row explicitly has `materialStatus: "erased"`; a missing or `elided` selected source is invalid. Partial erasure of a merged entry is therefore representable, but the entry's full audio-byte verdict is incomplete. Decode each surviving exact Ogg Opus file, reject duplicates/missing/extra files, check byte length and ordinary SHA-256 against its source record. No export-time transcoding, audio cutting, or stitched file is allowed. A merged thought has several source IDs and therefore several unchanged original files in one protected export. A split passage may have the same source ID as another passage export; that is one source, not two recordings. For `status: "erased"`, every selected source is erased, `sources` and `audioFiles` are empty, `transcriptStatus: "unavailable"`, and the evidence view, when available, retains only positions/commitments.

`derivations` contains zero or more `{id,kind,sourceIds,content,createdAt,provenance}` objects; `kind` is `transcript`, `user_edited_transcript`, or `review_passage`. A transcript's required `provenance` is `{method:"speech_recognition",recognizer,modelId,modelVersion,executionPath}`. `executionPath` is `on_device`, `server`, or `provider`; the named recognizer and model are claims about the actual path used, never defaults inferred from the product. A review passage uses `{method:"human_review",actorType:"human"}`. A user edit uses `{method:"human_edit",actorType:"human"}` and additionally has `basedOnDerivationId` naming the preceding derivation. A derivation's source IDs are drawn from this entry's source IDs. Pending transcription is `entry.transcriptStatus: "pending"` with no transcript derivation; availability requires at least one transcript derivation. Content in `derivations` is text, never audio source content. The export authenticates this text against accidental modification within the file through AES-GCM, but the audio source commitment does not attest that it is a faithful transcript.

`integrityEvidence` is `{bundle,export}` with a v2 witness receipt bundle and its per-entry chain export view, or `null` with `integrityEvidenceNote` explaining missing witness capability or pending publication. Web assembly follows ADR-0034's authorized one-workspace scoped receipt path, without broad table reads or readable staging. An export may be produced before publication, but it must not claim an external-witness verdict. Pocket's local profile sets `integrityEvidence: null` with an honest note; its file digest and AEAD checks are local integrity checks, not independent witnessing.

The bundle's keys and token certificates are **untrusted suggestions**, never self-supplied trust anchors. The holder or independent verifier supplies accepted publisher and timestamp anchors (or declines them), performs the steps in [Integrity Evidence v2](integrity-evidence-v2.md), and reports source-byte, chain, and witness outcomes separately. A fully verified selected audio source establishes that these exact bytes match a source digest committed in a chain at the witnessed position and date. It does not establish speaker identity, capture completeness, transcript accuracy, that passage grouping existed at capture, or that the bytes decode as valid Ogg Opus. Encoding and encoder metadata are committed **producer claims**, not facts proven by a digest or the witness; checking actual codec/container conformance requires a separate decoder/container validation step.
