Refactor recording metadata to JSON sidecar
Replaces the `.transcript.txt` sidecar with a structured `.json` file for recording metadata. This change consolidates transcript text, duration, and other potential metadata into a single, extensible JSON object. This also refactors the `TranscriptState` enum to better represent the on-disk state (absence of file means pending) and the in-memory representation. The `Transcript` enum now specifically models the terminal outcomes of the transcriber (`Silent` or `Content`). The commit includes updates to documentation, data structures, path handling, and various tests to align with the new metadata format.
This commit is contained in:
@@ -318,6 +318,31 @@ mod tests {
|
||||
fs::write(path, b"").await.unwrap();
|
||||
}
|
||||
|
||||
/// Seed a `<stem>.json` next to a (presumed already-touched)
|
||||
/// `<stem>.m4a`. Variant is `Transcript::Silent` because these
|
||||
/// tests historically used an empty `.transcript.txt`, which
|
||||
/// mapped to `TranscriptState::Silent`. Tests that need real
|
||||
/// content call `seed_meta_with` with the desired variant.
|
||||
async fn seed_meta(case_dir: &std::path::Path, stem: &str) {
|
||||
crate::paths::write_recording_meta_sync(
|
||||
case_dir,
|
||||
stem,
|
||||
doctate_common::Transcript::Silent,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
async fn seed_meta_with(case_dir: &std::path::Path, stem: &str, text: &str) {
|
||||
crate::paths::write_recording_meta_sync(
|
||||
case_dir,
|
||||
stem,
|
||||
doctate_common::Transcript::Content {
|
||||
text: text.to_owned(),
|
||||
},
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
fn set_mtime(path: &std::path::Path, t: SystemTime) {
|
||||
set_file_mtime(path, FileTime::from_system_time(t)).unwrap();
|
||||
}
|
||||
@@ -335,7 +360,7 @@ mod tests {
|
||||
async fn missing_transcript_skips() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.m4a")).await;
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.transcript.txt")).await;
|
||||
seed_meta(dir.path(), "2026-01-01T10-00-00Z").await;
|
||||
touch(&dir.path().join("2026-01-01T11-00-00Z.m4a")).await;
|
||||
assert_eq!(
|
||||
evaluate_case(dir.path()).await,
|
||||
@@ -347,7 +372,7 @@ mod tests {
|
||||
async fn all_transcribed_no_document_enqueues() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.m4a")).await;
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.transcript.txt")).await;
|
||||
seed_meta(dir.path(), "2026-01-01T10-00-00Z").await;
|
||||
assert_eq!(evaluate_case(dir.path()).await, AutoDecision::Enqueue);
|
||||
}
|
||||
|
||||
@@ -356,7 +381,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let m4a = dir.path().join("2026-01-01T10-00-00Z.m4a");
|
||||
touch(&m4a).await;
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.transcript.txt")).await;
|
||||
seed_meta(dir.path(), "2026-01-01T10-00-00Z").await;
|
||||
let doc = dir.path().join(DOCUMENT_FILE);
|
||||
touch(&doc).await;
|
||||
|
||||
@@ -375,7 +400,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let m4a = dir.path().join("2026-01-01T10-00-00Z.m4a");
|
||||
touch(&m4a).await;
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.transcript.txt")).await;
|
||||
seed_meta(dir.path(), "2026-01-01T10-00-00Z").await;
|
||||
let doc = dir.path().join(DOCUMENT_FILE);
|
||||
touch(&doc).await;
|
||||
|
||||
@@ -390,7 +415,7 @@ mod tests {
|
||||
async fn analysis_input_present_skips() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.m4a")).await;
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.transcript.txt")).await;
|
||||
seed_meta(dir.path(), "2026-01-01T10-00-00Z").await;
|
||||
touch(&dir.path().join(ANALYSIS_INPUT_FILE)).await;
|
||||
assert_eq!(
|
||||
evaluate_case(dir.path()).await,
|
||||
@@ -403,7 +428,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let m4a = dir.path().join("2026-01-01T10-00-00Z.m4a");
|
||||
touch(&m4a).await;
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.transcript.txt")).await;
|
||||
seed_meta(dir.path(), "2026-01-01T10-00-00Z").await;
|
||||
|
||||
let base = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);
|
||||
set_mtime(&m4a, base);
|
||||
@@ -431,7 +456,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let m4a = dir.path().join("2026-01-01T10-00-00Z.m4a");
|
||||
touch(&m4a).await;
|
||||
touch(&dir.path().join("2026-01-01T10-00-00Z.transcript.txt")).await;
|
||||
seed_meta(dir.path(), "2026-01-01T10-00-00Z").await;
|
||||
|
||||
let base = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);
|
||||
set_mtime(&m4a, base);
|
||||
@@ -478,12 +503,12 @@ mod tests {
|
||||
fs::write(eligible.join("2026-01-01T10-00-00Z.m4a"), b"fake")
|
||||
.await
|
||||
.unwrap();
|
||||
fs::write(
|
||||
eligible.join("2026-01-01T10-00-00Z.transcript.txt"),
|
||||
b"patient mit brustschmerz",
|
||||
seed_meta_with(
|
||||
&eligible,
|
||||
"2026-01-01T10-00-00Z",
|
||||
"patient mit brustschmerz",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
.await;
|
||||
|
||||
// Not eligible: has a fresh document.
|
||||
let current_id = "22222222-2222-2222-2222-222222222222";
|
||||
@@ -491,12 +516,7 @@ mod tests {
|
||||
fs::create_dir_all(¤t).await.unwrap();
|
||||
let m4a = current.join("2026-01-01T10-00-00Z.m4a");
|
||||
fs::write(&m4a, b"fake").await.unwrap();
|
||||
fs::write(
|
||||
current.join("2026-01-01T10-00-00Z.transcript.txt"),
|
||||
b"stable",
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
seed_meta_with(¤t, "2026-01-01T10-00-00Z", "stable").await;
|
||||
let doc = current.join(DOCUMENT_FILE);
|
||||
fs::write(&doc, b"doc").await.unwrap();
|
||||
let base = SystemTime::UNIX_EPOCH + Duration::from_secs(1_700_000_000);
|
||||
@@ -509,9 +529,7 @@ mod tests {
|
||||
fs::write(junk.join("2026-01-01T10-00-00Z.m4a"), b"fake")
|
||||
.await
|
||||
.unwrap();
|
||||
fs::write(junk.join("2026-01-01T10-00-00Z.transcript.txt"), b"x")
|
||||
.await
|
||||
.unwrap();
|
||||
seed_meta_with(&junk, "2026-01-01T10-00-00Z", "x").await;
|
||||
|
||||
let (tx, mut rx) = analyze_channel();
|
||||
let events_tx = events_channel();
|
||||
|
||||
Reference in New Issue
Block a user