Refactor auto-trigger and recovery logic
This commit introduces a significant refactor to the auto-trigger and recovery mechanisms for the analysis pipeline. The core change is the introduction of a more granular `CaseAnalysisState` enum, replacing the simpler `AutoDecision`. The `evaluate_state` function now computes the full lifecycle state of a case, considering factors like the presence of recordings, pending transcripts, queued jobs, failure markers, document staleness, and an idle threshold. This provides a richer understanding of the case's status. The `evaluate_case` function is retained as a backwards-compatible adapter for existing callsites and tests. It maps the new `CaseAnalysisState` to the old `AutoDecision` enum, simplifying the decision to "enqueue" or "skip." The `recovery` module is also refactored. The `scan_and_enqueue` function is replaced by `boot_scan_state`, which is now purely observational. It aggregates statistics about cases in different states at boot time and logs them, but it no longer attempts to re-enqueue jobs. The responsibility for triggering analysis now lies with the per-render `try_enqueue_all_for_user` logic, which utilizes the new typed state machine. This refactoring aims to provide more clarity and control over the analysis pipeline's state management, particularly in handling cases that have previously failed or are waiting for further input.
This commit is contained in:
@@ -613,35 +613,28 @@ async fn replace_real_case_dry() {
|
||||
// Recovery
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/// Boot-scan is observation-only after the typed-state refactor: even a
|
||||
/// case sitting in the `Queued` state on disk must NOT be re-enqueued
|
||||
/// at startup. The per-page-render `try_enqueue_all_for_user` is the
|
||||
/// only auto-trigger.
|
||||
#[tokio::test]
|
||||
async fn recovery_enqueues_pending_analysis() {
|
||||
async fn recovery_does_not_enqueue_at_boot() {
|
||||
let tmp = unique_tmpdir("analyze-r1");
|
||||
let case_dir = tmp.join("dr_a/11111111-1111-1111-1111-111111111111");
|
||||
std::fs::create_dir_all(&case_dir).unwrap();
|
||||
std::fs::write(case_dir.join(ANALYSIS_INPUT_FILE), "{}").unwrap();
|
||||
|
||||
let (tx, mut rx) = analyze::channel();
|
||||
analyze::recovery::scan_and_enqueue(&tmp, &tx).await;
|
||||
|
||||
let job = rx.try_recv().expect("expected one job");
|
||||
assert_eq!(job.case_dir, case_dir);
|
||||
assert!(rx.try_recv().is_err(), "no further jobs expected");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn recovery_skips_completed_analysis() {
|
||||
let tmp = unique_tmpdir("analyze-r2");
|
||||
let case_dir = tmp.join("dr_a/11111111-1111-1111-1111-111111111111");
|
||||
std::fs::create_dir_all(&case_dir).unwrap();
|
||||
std::fs::write(case_dir.join(ANALYSIS_INPUT_FILE), "{}").unwrap();
|
||||
write_document_for_test(&case_dir, "done", "1970-01-01T00:00:00Z");
|
||||
|
||||
let (tx, mut rx) = analyze::channel();
|
||||
analyze::recovery::scan_and_enqueue(&tmp, &tx).await;
|
||||
let (_tx, mut rx) = analyze::channel();
|
||||
analyze::recovery::boot_scan_state(
|
||||
&tmp,
|
||||
std::time::Duration::ZERO,
|
||||
std::time::SystemTime::now(),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
rx.try_recv().is_err(),
|
||||
"completed analysis must not re-enqueue"
|
||||
"boot scan must not enqueue any jobs in the new state model"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1246,10 +1239,18 @@ async fn recovery_skips_closed_cases() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (tx, mut rx) = analyze::channel();
|
||||
analyze::recovery::scan_and_enqueue(&tmp, &tx).await;
|
||||
let summary = analyze::recovery::boot_scan_state(
|
||||
&tmp,
|
||||
std::time::Duration::ZERO,
|
||||
std::time::SystemTime::now(),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(rx.try_recv().is_err(), "closed case must not be enqueued");
|
||||
assert_eq!(
|
||||
summary,
|
||||
analyze::recovery::BootStateSummary::default(),
|
||||
"closed case must not appear in any state bucket"
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user