master
Drew Owens Share frozen native Rust mechanical development checkpoint and qualification scope b2d7cdb 26d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404
use super::*;
use fusion_mechanical_core::prepare_request;
use serde_json::json;
use std::sync::Barrier;

struct Directory(PathBuf);
impl Directory {
    fn new() -> Self {
        static NEXT: AtomicU64 = AtomicU64::new(0);
        let value = Self(std::env::temp_dir().join(format!(
            "fusion-rust-journal-test-{}-{}-{}",
            std::process::id(),
            now_ms().unwrap(),
            NEXT.fetch_add(1, Ordering::Relaxed)
        )));
        #[cfg(not(windows))]
        let builder = fs::DirBuilder::new();
        #[cfg(unix)]
        let mut builder = builder;
        #[cfg(unix)]
        {
            use std::os::unix::fs::DirBuilderExt;
            builder.mode(0o700);
        }
        #[cfg(not(windows))]
        builder.create(&value.0).unwrap();
        #[cfg(windows)]
        validate_directory(&value.0, true).unwrap();
        value
    }
    fn open(&self, session: &str) -> Journal {
        Journal::open_at(&self.0, session, "rust-test.1", Limits::default(), 100).unwrap()
    }
}
impl Drop for Directory {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.0);
    }
}

fn request(session: &str, operation: &str, sample: usize) -> PreparedRequest {
    prepare_request(json!({"op":"exploded_preview_sample", "sessionId":session, "operationId":operation,
        "target":{"documentId":"document", "revision":"revision"}, "previewId":"preview", "expectedGeneration":0, "sampleIndex":sample}), session).unwrap()
}
fn admit(journal: &Journal, operation: &str) -> AdmissionClaim {
    match journal
        .admit(&request(journal.session_id(), operation, 0), 101)
        .unwrap()
    {
        Admission::Created(claim) => claim,
        other => panic!("unexpected {other:?}"),
    }
}
fn dispatch(journal: &Journal, operation: &str) -> DispatchClaim {
    match journal
        .dispatch(&admit(journal, operation), "dispatch-a", 102)
        .unwrap()
    {
        DispatchOutcome::Claimed(claim) => claim,
        other => panic!("unexpected {other:?}"),
    }
}
fn executing(journal: &Journal, operation: &str) -> DispatchClaim {
    let claim = dispatch(journal, operation);
    assert!(
        journal
            .start(
                &claim,
                json!({"documentId":"document", "revision":"revision"}),
                103
            )
            .unwrap()
            .claimed
    );
    claim
}

#[test]
fn commits_admission_dispatch_execution_terminal_then_reopens_exact_history() {
    let directory = Directory::new();
    let journal = directory.open("session-a");
    let claim = executing(&journal, "op");
    let finished = journal
        .finish(
            &claim,
            json!({"success":true,"sampleIndex":0,"value":14.999999999999993}),
            104,
        )
        .unwrap();
    assert!(finished.claimed);
    assert_eq!(
        finished
            .record
            .events
            .iter()
            .map(|event| event.phase)
            .collect::<Vec<_>>(),
        [
            Phase::Admitted,
            Phase::Dispatched,
            Phase::Executing,
            Phase::Succeeded
        ]
    );
    assert_eq!(
        finished.record.request_digest,
        request_digest(request("session-a", "op", 0).canonical_bytes())
    );
    drop(journal);
    let new = directory.open("session-b");
    assert_eq!(
        new.lookup("session-a", "op").unwrap(),
        Some(finished.record)
    );
    let status = new.status("session-a", "op").unwrap();
    assert!(status.historical);
    assert_eq!(status.state, State::Succeeded);
    assert_eq!(status.outcome, Outcome::Recorded);
    assert!(!status.reconciliation_required);
    assert_eq!(
        new.start(&claim, json!({}), 105).unwrap_err().code,
        "session_mismatch"
    );
}

#[test]
fn same_session_cannot_be_reopened_and_missing_registered_database_is_not_recreated() {
    let directory = Directory::new();
    let journal = directory.open("session");
    assert_eq!(
        Journal::open(&directory.0, "session", "test", Limits::default())
            .err()
            .unwrap()
            .code,
        "session_reused"
    );
    fs::rename(
        journal.database_path(),
        directory.0.join("retained.sqlite3"),
    )
    .unwrap();
    assert!(
        journal
            .lookup("session", "absent")
            .unwrap_err()
            .reconciliation_required
    );
    assert!(!journal.database_path().exists());
}

#[test]
fn old_session_nonterminal_is_unknown_interrupted_and_never_replayed() {
    let directory = Directory::new();
    let old = directory.open("old");
    admit(&old, "admitted");
    dispatch(&old, "dispatched");
    let claim = executing(&old, "executing");
    let new = directory.open("new");
    for operation in ["admitted", "dispatched", "executing"] {
        let status = new.status("old", operation).unwrap();
        assert_eq!(status.state, State::Interrupted);
        assert_eq!(status.outcome, Outcome::Unknown);
        assert!(status.reconciliation_required);
    }
    assert_eq!(
        new.admit(&request("old", "new-request", 0), 200)
            .unwrap_err()
            .code,
        "session_mismatch"
    );
    assert_eq!(
        new.finish(&claim, json!({"success":true}), 200)
            .unwrap_err()
            .code,
        "session_mismatch"
    );
}

#[test]
fn duplicate_admission_never_reissues_effect_claim_and_conflict_preserves_original() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let claim = admit(&journal, "op");
    assert!(matches!(
        journal.admit(&request("session", "op", 0), 102).unwrap(),
        Admission::Existing(_)
    ));
    assert_eq!(
        journal
            .admit(&request("session", "op", 1), 103)
            .unwrap_err()
            .code,
        "operation_conflict"
    );
    let record = journal.lookup("session", "op").unwrap().unwrap();
    assert_eq!(record.request_digest, claim.request_digest());
    assert_eq!(record.events.len(), 1);
    assert_eq!(
        journal.status("session", "op").unwrap().state,
        State::ReconciliationRequired
    );
}

#[test]
fn concurrent_duplicate_events_and_admission_issue_one_claim() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let barrier = Arc::new(Barrier::new(12));
    let handles: Vec<_> = (0..12)
        .map(|_| {
            let journal = journal.clone();
            let barrier = barrier.clone();
            std::thread::spawn(move || {
                barrier.wait();
                journal.admit(&request("session", "op", 0), 101).unwrap()
            })
        })
        .collect();
    let outcomes: Vec<_> = handles
        .into_iter()
        .map(|handle| handle.join().unwrap())
        .collect();
    let claims: Vec<_> = outcomes
        .into_iter()
        .filter_map(|value| match value {
            Admission::Created(claim) => Some(claim),
            _ => None,
        })
        .collect();
    assert_eq!(claims.len(), 1);
    let claim = match journal.dispatch(&claims[0], "dispatch", 102).unwrap() {
        DispatchOutcome::Claimed(claim) => claim,
        _ => panic!(),
    };
    let barrier = Arc::new(Barrier::new(12));
    let handles: Vec<_> = (0..12)
        .map(|_| {
            let journal = journal.clone();
            let barrier = barrier.clone();
            let claim = claim.clone();
            std::thread::spawn(move || {
                barrier.wait();
                journal
                    .start(&claim, json!({"documentId":"document"}), 103)
                    .unwrap()
                    .claimed
            })
        })
        .collect();
    assert_eq!(
        handles
            .into_iter()
            .map(|handle| usize::from(handle.join().unwrap()))
            .sum::<usize>(),
        1
    );
}

#[test]
fn concurrent_fresh_initializers_publish_one_valid_database_without_overwrite() {
    let directory = Directory::new();
    let barrier = Arc::new(Barrier::new(8));
    let handles: Vec<_> = (0..8)
        .map(|number| {
            let directory = directory.0.clone();
            let barrier = barrier.clone();
            std::thread::spawn(move || {
                barrier.wait();
                Journal::open_at(
                    directory,
                    &format!("session-{number}"),
                    "test",
                    Limits::default(),
                    100,
                )
                .map(|journal| journal.session_id().to_owned())
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap().unwrap();
    }
    let journal = directory.open("last-session");
    let connection = journal.connect().unwrap();
    assert_eq!(
        connection
            .query_row("SELECT COUNT(*) FROM sessions", [], |row| row
                .get::<_, usize>(0))
            .unwrap(),
        9
    );
}

#[test]
fn terminal_is_immutable_and_delivery_failure_cannot_erase_execution() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let claim = executing(&journal, "op");
    assert!(
        !journal
            .not_executed(
                &claim,
                json!({"success":false,"nativeExecutionStarted":false}),
                104
            )
            .unwrap()
            .claimed
    );
    let terminal = journal
        .finish(&claim, json!({"success":true}), 105)
        .unwrap()
        .record;
    for replacement in [
        json!({"success":false}),
        json!({"success":true,"changed":true}),
    ] {
        let duplicate = journal.finish(&claim, replacement, 106).unwrap();
        assert!(!duplicate.claimed);
        assert_eq!(duplicate.record, terminal);
    }
    assert!(!journal.start(&claim, json!({}), 107).unwrap().claimed);
}

#[test]
fn not_executed_requires_false_success_and_explicit_no_native_work() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let claim = dispatch(&journal, "op");
    assert_eq!(
        journal
            .not_executed(&claim, json!({"success":false}), 103)
            .unwrap_err()
            .code,
        "operation_record_invalid"
    );
    assert_eq!(
        journal
            .not_executed(
                &claim,
                json!({"success":true,"nativeExecutionStarted":false}),
                103
            )
            .unwrap_err()
            .code,
        "operation_record_invalid"
    );
    assert!(
        journal
            .not_executed(
                &claim,
                json!({"success":false,"nativeExecutionStarted":false}),
                104
            )
            .unwrap()
            .claimed
    );
    assert_eq!(
        journal.status("session", "op").unwrap().state,
        State::NotExecuted
    );
    assert!(!journal.start(&claim, json!({}), 105).unwrap().claimed);
}

#[test]
fn uncertain_admission_before_or_after_commit_never_issues_a_claim_on_retry() {
    for fault in [Fault::BeforeCommit, Fault::AfterCommit] {
        let directory = Directory::new();
        let journal = directory.open("session");
        *journal.inner.fault.lock().unwrap() = Some(fault);
        assert!(
            journal
                .admit(&request("session", "op", 0), 101)
                .unwrap_err()
                .reconciliation_required
        );
        assert_eq!(
            journal
                .admit(&request("session", "op", 0), 102)
                .unwrap_err()
                .code,
            "operation_reconciliation_required"
        );
        let record = journal.lookup("session", "op").unwrap();
        assert_eq!(record.is_some(), fault == Fault::AfterCommit);
        let status = journal.status("session", "op").unwrap();
        assert_eq!(status.outcome, Outcome::Unknown);
        assert!(status.reconciliation_required);
    }
}

#[test]
fn lost_dispatch_acknowledgement_cannot_be_retried_even_when_commit_rolled_back() {
    for fault in [Fault::BeforeCommit, Fault::AfterCommit] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let claim = admit(&journal, "op");
        *journal.inner.fault.lock().unwrap() = Some(fault);
        assert!(
            journal
                .dispatch(&claim, "dispatch", 102)
                .unwrap_err()
                .reconciliation_required
        );
        assert_eq!(
            journal.dispatch(&claim, "dispatch", 103).unwrap_err().code,
            "operation_reconciliation_required"
        );
        assert_eq!(
            journal.lookup("session", "op").unwrap().unwrap().phase,
            if fault == Fault::AfterCommit {
                Phase::Dispatched
            } else {
                Phase::Admitted
            }
        );
    }
}

#[test]
fn lost_start_acknowledgement_never_authorizes_native_execution() {
    for fault in [Fault::BeforeCommit, Fault::AfterCommit] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let claim = dispatch(&journal, "op");
        *journal.inner.fault.lock().unwrap() = Some(fault);
        assert!(
            journal
                .start(&claim, json!({}), 103)
                .unwrap_err()
                .reconciliation_required
        );
        assert_eq!(
            journal.start(&claim, json!({}), 104).unwrap_err().code,
            "operation_reconciliation_required"
        );
        assert_eq!(
            journal.status("session", "op").unwrap().outcome,
            Outcome::Unknown
        );
    }
}

#[test]
fn lost_terminal_ack_reconciles_durable_terminal_or_retains_unknown_without_reexecution() {
    for fault in [Fault::BeforeCommit, Fault::AfterCommit] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let claim = executing(&journal, "op");
        *journal.inner.fault.lock().unwrap() = Some(fault);
        assert!(
            journal
                .finish(&claim, json!({"success":true,"nativeObserved":true}), 104)
                .unwrap_err()
                .reconciliation_required
        );
        assert_eq!(
            journal.start(&claim, json!({}), 105).unwrap_err().code,
            "operation_reconciliation_required"
        );
        let status = journal.status("session", "op").unwrap();
        assert_eq!(
            status.outcome,
            if fault == Fault::AfterCommit {
                Outcome::Recorded
            } else {
                Outcome::Unknown
            }
        );
        assert_eq!(
            status.record.unwrap().phase,
            if fault == Fault::AfterCommit {
                Phase::Succeeded
            } else {
                Phase::Executing
            }
        );
    }
}

#[test]
fn refuses_foreign_empty_corrupt_database_without_changing_bytes() {
    for bytes in [Vec::new(), b"not a SQLite operation journal".to_vec()] {
        let directory = Directory::new();
        let path = directory.0.join(DATABASE_NAME);
        fs::write(&path, &bytes).unwrap();
        assert!(Journal::open(&directory.0, "session", "test", Limits::default()).is_err());
        assert_eq!(fs::read(&path).unwrap(), bytes);
    }
    let directory = Directory::new();
    let path = directory.0.join(DATABASE_NAME);
    Connection::open(&path)
        .unwrap()
        .execute_batch("CREATE TABLE unrelated (id INTEGER); INSERT INTO unrelated VALUES (7);")
        .unwrap();
    let bytes = fs::read(&path).unwrap();
    assert_eq!(
        Journal::open(&directory.0, "session", "test", Limits::default())
            .err()
            .unwrap()
            .code,
        "operation_storage_corrupt"
    );
    assert_eq!(fs::read(&path).unwrap(), bytes);
}

#[test]
fn refuses_newer_version_extra_schema_objects_and_checksum_tampering() {
    for mutation in [
        "PRAGMA user_version=2",
        "CREATE TRIGGER extra AFTER UPDATE ON operations BEGIN SELECT 1; END",
        "UPDATE operations SET record_digest='incorrect'",
    ] {
        let directory = Directory::new();
        let journal = directory.open("session");
        admit(&journal, "op");
        Connection::open(journal.database_path())
            .unwrap()
            .execute_batch(mutation)
            .unwrap();
        let before = fs::read(journal.database_path()).unwrap();
        assert!(journal.lookup("session", "op").is_err());
        assert!(journal.admit(&request("session", "next", 0), 200).is_err());
        assert_eq!(fs::read(journal.database_path()).unwrap(), before);
    }
}

#[test]
fn valid_checksum_does_not_hide_invalid_phase_history_or_request_identity() {
    for alteration in 0..3 {
        let directory = Directory::new();
        let journal = directory.open("session");
        let _claim = executing(&journal, "op");
        let mut record = journal.lookup("session", "op").unwrap().unwrap();
        match alteration {
            0 => record.events[1].phase = Phase::Succeeded,
            1 => record.operation_id = "other".into(),
            _ => record.request_json = record.request_json.replace("preview", "modified"),
        }
        let bytes = encode(&record, Limits::default().max_record_bytes).unwrap();
        Connection::open(journal.database_path())
            .unwrap()
            .execute(
                "UPDATE operations SET record_json=?1,record_digest=?2",
                params![bytes, record_digest(&bytes)],
            )
            .unwrap();
        assert_eq!(
            journal.lookup("session", "op").unwrap_err().code,
            "operation_storage_corrupt"
        );
    }
}

#[test]
fn capacity_retains_nonterminal_and_terminal_history_without_eviction() {
    let directory = Directory::new();
    let limits = Limits {
        max_records: 2,
        ..Limits::default()
    };
    let journal = Journal::open_at(&directory.0, "session", "test", limits, 100).unwrap();
    admit(&journal, "pending");
    let claim = executing(&journal, "finished");
    journal
        .finish(&claim, json!({"success":true}), 104)
        .unwrap();
    assert_eq!(
        journal
            .admit(&request("session", "overflow", 0), 200)
            .unwrap_err()
            .code,
        "operation_capacity"
    );
    assert_eq!(
        journal.lookup("session", "pending").unwrap().unwrap().phase,
        Phase::Admitted
    );
    assert_eq!(
        journal
            .lookup("session", "finished")
            .unwrap()
            .unwrap()
            .phase,
        Phase::Succeeded
    );
}

#[test]
fn record_byte_limit_refuses_large_terminal_without_truncating_existing_record() {
    let directory = Directory::new();
    let journal = Journal::open_at(
        &directory.0,
        "session",
        "test",
        Limits {
            max_record_bytes: 2048,
            ..Limits::default()
        },
        100,
    )
    .unwrap();
    let claim = executing(&journal, "op");
    let failure = journal
        .finish(
            &claim,
            json!({"success":true,"large":"x".repeat(4096)}),
            104,
        )
        .unwrap_err();
    assert_eq!(failure.code, "operation_record_too_large");
    assert!(failure.reconciliation_required);
    assert_eq!(
        journal.lookup("session", "op").unwrap().unwrap().phase,
        Phase::Executing
    );
    assert_eq!(
        journal.status("session", "op").unwrap().outcome,
        Outcome::Unknown
    );
    assert_eq!(
        journal
            .finish(&claim, json!({"success":true}), 105)
            .unwrap_err()
            .code,
        "operation_reconciliation_required"
    );
}

#[test]
fn refusal_of_reads_bad_clock_and_invalid_dispatch_does_not_mutate_history() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let read = prepare_request(json!({"op":"inspect"}), "session").unwrap();
    assert_eq!(
        journal.admit(&read, 100).unwrap_err().code,
        "operation_record_invalid"
    );
    let claim = admit(&journal, "op");
    assert_eq!(
        journal.dispatch(&claim, "", 102).unwrap_err().code,
        "operation_record_invalid"
    );
    assert_eq!(
        journal.dispatch(&claim, "dispatch", 1).unwrap_err().code,
        "operation_record_invalid"
    );
    assert_eq!(
        journal
            .lookup("session", "op")
            .unwrap()
            .unwrap()
            .events
            .len(),
        1
    );
    let absent = journal.status("session", "absent").unwrap();
    assert_eq!(absent.state, State::Unknown);
    assert_eq!(absent.outcome, Outcome::Unknown);
}

#[test]
fn legacy_database_bytes_are_never_opened_or_migrated() {
    let directory = Directory::new();
    let legacy = directory.0.join("operations-v1.sqlite3");
    let bytes = b"legacy data must remain untouched";
    fs::write(&legacy, bytes).unwrap();
    let journal = directory.open("session");
    admit(&journal, "op");
    assert_eq!(fs::read(legacy).unwrap(), bytes);
    assert_ne!(
        journal.database_path().file_name().unwrap(),
        "operations-v1.sqlite3"
    );
}

#[cfg(unix)]
#[test]
fn symlink_hardlink_world_writable_and_parent_traversal_are_refused() {
    use std::os::unix::fs::{symlink, PermissionsExt};
    let directory = Directory::new();
    let linked = directory.0.join("link");
    let real = directory.0.join("real");
    fs::create_dir(&real).unwrap();
    symlink(&real, &linked).unwrap();
    assert_eq!(
        Journal::open(&linked, "session", "test", Limits::default())
            .err()
            .unwrap()
            .code,
        "operation_storage_invalid_path"
    );
    let journal = directory.open("session");
    let link = directory.0.join("external-link");
    fs::hard_link(journal.database_path(), &link).unwrap();
    assert_eq!(
        journal.lookup("session", "absent").unwrap_err().code,
        "operation_storage_invalid_path"
    );
    fs::remove_file(link).unwrap();
    let target = directory.0.join("other");
    fs::rename(journal.database_path(), &target).unwrap();
    symlink(&target, journal.database_path()).unwrap();
    assert_eq!(
        journal.lookup("session", "absent").unwrap_err().code,
        "operation_storage_invalid_path"
    );
    assert_eq!(
        Journal::open(
            directory.0.join("missing/../other"),
            "session",
            "test",
            Limits::default()
        )
        .err()
        .unwrap()
        .code,
        "operation_storage_invalid_path"
    );
    fs::set_permissions(&directory.0, fs::Permissions::from_mode(0o777)).unwrap();
    assert_eq!(
        Journal::open(&directory.0, "session", "test", Limits::default())
            .err()
            .unwrap()
            .code,
        "operation_storage_invalid_path"
    );
}

#[test]
fn sqlite_immediate_lock_contention_is_bounded_and_does_not_claim_admission() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let blocker = Connection::open(journal.database_path()).unwrap();
    blocker.execute_batch("BEGIN IMMEDIATE").unwrap();
    let failure = journal
        .admit(&request("session", "op", 0), 101)
        .unwrap_err();
    assert!(failure.reconciliation_required);
    blocker.execute_batch("ROLLBACK").unwrap();
    assert_eq!(
        journal
            .admit(&request("session", "op", 0), 102)
            .unwrap_err()
            .code,
        "operation_reconciliation_required"
    );
    assert!(journal.lookup("session", "op").unwrap().is_none());
}

// This worker exits without Rust destructors to model a process disappearing at
// persisted lifecycle boundaries and with an outstanding SQLite transaction.
#[test]
fn crash_worker() {
    let Ok(directory) = std::env::var("FUSION_JOURNAL_CRASH_DIRECTORY") else {
        return;
    };
    let stage = std::env::var("FUSION_JOURNAL_CRASH_STAGE").unwrap();
    if stage == "foreign-hot-rollback" {
        let connection = Connection::open(Path::new(&directory).join(DATABASE_NAME)).unwrap();
        connection.execute_batch("CREATE TABLE foreign_records (payload BLOB); INSERT INTO foreign_records VALUES (zeroblob(16)); BEGIN IMMEDIATE; PRAGMA cache_size=1; UPDATE foreign_records SET payload=zeroblob(1048576);").unwrap();
        std::process::exit(73);
    }
    let journal =
        Journal::open_at(directory, "crashed-session", "test", Limits::default(), 100).unwrap();
    let admission = admit(&journal, "op");
    if stage == "admitted" {
        std::process::exit(73);
    }
    let claim = match journal.dispatch(&admission, "dispatch", 102).unwrap() {
        DispatchOutcome::Claimed(claim) => claim,
        _ => panic!(),
    };
    if stage == "dispatched" {
        std::process::exit(73);
    }
    journal
        .start(&claim, json!({"documentId":"owned-fixture"}), 103)
        .unwrap();
    if stage == "executing" {
        std::process::exit(73);
    }
    if stage == "hot-rollback" {
        let connection = journal.connect().unwrap();
        connection
            .execute_batch("BEGIN IMMEDIATE; UPDATE operations SET record_digest='not-committed';")
            .unwrap();
        // Force dirty pages through SQLite's pager to leave a genuine rollback
        // journal; this is not a mocked in-memory failure.
        connection.execute_batch("PRAGMA cache_size=1; CREATE TABLE uncommitted (payload BLOB); INSERT INTO uncommitted VALUES (zeroblob(1048576));").unwrap();
        std::process::exit(73);
    }
    assert_eq!(stage, "terminal");
    journal
        .finish(&claim, json!({"success":true,"geometryObserved":true}), 104)
        .unwrap();
    std::process::exit(73);
}

#[test]
fn child_process_crash_reopens_history_and_recovers_hot_rollback_without_redispatch() {
    for (stage, phase) in [
        ("admitted", Phase::Admitted),
        ("dispatched", Phase::Dispatched),
        ("executing", Phase::Executing),
        ("terminal", Phase::Succeeded),
        ("hot-rollback", Phase::Executing),
    ] {
        let directory = Directory::new();
        let output = std::process::Command::new(std::env::current_exe().unwrap())
            .args(["--exact", "tests::crash_worker", "--nocapture"])
            .env("FUSION_JOURNAL_CRASH_DIRECTORY", &directory.0)
            .env("FUSION_JOURNAL_CRASH_STAGE", stage)
            .output()
            .unwrap();
        assert_eq!(
            output.status.code(),
            Some(73),
            "stage {stage}: {}",
            String::from_utf8_lossy(&output.stderr)
        );
        if stage == "hot-rollback" {
            assert!(directory
                .0
                .join(format!("{DATABASE_NAME}-journal"))
                .exists());
        }
        let journal = directory.open("fresh-session");
        let status = journal.status("crashed-session", "op").unwrap();
        assert_eq!(status.record.as_ref().unwrap().phase, phase);
        assert_eq!(
            status.outcome,
            if phase.is_terminal() {
                Outcome::Recorded
            } else {
                Outcome::Unknown
            }
        );
        if !phase.is_terminal() {
            assert_eq!(status.state, State::Interrupted);
        }
        assert_eq!(
            journal
                .admit(&request("crashed-session", "op", 0), 200)
                .unwrap_err()
                .code,
            "session_mismatch"
        );
    }
}

#[test]
fn foreign_hot_rollback_is_refused_before_sqlite_can_modify_its_files() {
    let directory = Directory::new();
    let output = std::process::Command::new(std::env::current_exe().unwrap())
        .args(["--exact", "tests::crash_worker", "--nocapture"])
        .env("FUSION_JOURNAL_CRASH_DIRECTORY", &directory.0)
        .env("FUSION_JOURNAL_CRASH_STAGE", "foreign-hot-rollback")
        .output()
        .unwrap();
    assert_eq!(output.status.code(), Some(73));
    let database = directory.0.join(DATABASE_NAME);
    let rollback = directory.0.join(format!("{DATABASE_NAME}-journal"));
    let before_database = fs::read(&database).unwrap();
    let before_rollback = fs::read(&rollback).unwrap();
    assert!(!before_rollback.is_empty());
    let failure = Journal::open(&directory.0, "session", "test", Limits::default())
        .err()
        .unwrap();
    assert_eq!(failure.code, "operation_storage_corrupt");
    assert_eq!(fs::read(database).unwrap(), before_database);
    assert_eq!(fs::read(rollback).unwrap(), before_rollback);
}

#[test]
fn deeply_nested_native_result_fails_closed_after_execution() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let claim = executing(&journal, "op");
    let mut nested = Value::Null;
    for _ in 0..140 {
        nested = Value::Array(vec![nested]);
    }
    let failure = journal
        .finish(&claim, json!({"success":true,"result":nested}), 104)
        .unwrap_err();
    assert!(failure.reconciliation_required);
    assert_eq!(
        journal.status("session", "op").unwrap().outcome,
        Outcome::Unknown
    );
}

#[test]
fn observed_result_without_executing_claim_is_unknown_and_blocks_further_claims() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let claim = dispatch(&journal, "op");
    let failure = journal
        .finish(&claim, json!({"success":true}), 103)
        .unwrap_err();
    assert_eq!(failure.code, "operation_conflict");
    assert!(failure.reconciliation_required);
    assert_eq!(
        journal.start(&claim, json!({}), 104).unwrap_err().code,
        "operation_reconciliation_required"
    );
    assert_eq!(
        journal.status("session", "op").unwrap().outcome,
        Outcome::Unknown
    );
}

#[test]
fn page_bound_failure_never_authorizes_terminal_or_evicts_admission() {
    let directory = Directory::new();
    let journal = Journal::open_at(
        &directory.0,
        "session",
        "test",
        Limits {
            max_database_bytes: 32_768,
            ..Limits::default()
        },
        100,
    )
    .unwrap();
    let claim = executing(&journal, "op");
    let failure = journal
        .finish(
            &claim,
            json!({"success":true,"large":"x".repeat(40_000)}),
            104,
        )
        .unwrap_err();
    assert!(failure.reconciliation_required);
    assert!(fs::metadata(journal.database_path()).unwrap().len() <= 32_768);
    assert_eq!(
        journal.lookup("session", "op").unwrap().unwrap().phase,
        Phase::Executing
    );
}

#[test]
fn fresh_session_capacity_refuses_registration_without_eviction() {
    let directory = Directory::new();
    let limits = Limits {
        max_sessions: 1,
        ..Limits::default()
    };
    let journal = Journal::open_at(&directory.0, "session", "test", limits, 100).unwrap();
    admit(&journal, "retained");
    assert_eq!(
        Journal::open_at(&directory.0, "second", "test", limits, 200)
            .err()
            .unwrap()
            .code,
        "operation_capacity"
    );
    assert!(journal.lookup("session", "retained").unwrap().is_some());
}

#[test]
fn uncertain_missing_admission_capacity_is_bounded_and_fails_closed() {
    let directory = Directory::new();
    let journal = Journal::open_at(
        &directory.0,
        "session",
        "test",
        Limits {
            max_records: 1,
            ..Limits::default()
        },
        100,
    )
    .unwrap();
    *journal.inner.fault.lock().unwrap() = Some(Fault::BeforeCommit);
    assert!(
        journal
            .admit(&request("session", "uncertain", 0), 101)
            .unwrap_err()
            .reconciliation_required
    );
    assert_eq!(
        journal
            .admit(&request("session", "different", 0), 102)
            .unwrap_err()
            .code,
        "operation_reconciliation_required"
    );
    assert_eq!(journal.inner.uncertain.lock().unwrap().len(), 1);
    assert!(journal.lookup("session", "different").unwrap().is_none());
}

#[test]
fn full_uncertainty_ledger_marks_existing_execution_unknown_without_memory_growth() {
    let directory = Directory::new();
    let journal = Journal::open_at(
        &directory.0,
        "session",
        "test",
        Limits {
            max_records: 2,
            ..Limits::default()
        },
        100,
    )
    .unwrap();
    let claim = executing(&journal, "running");
    for operation in ["unknown-a", "unknown-b"] {
        *journal.inner.fault.lock().unwrap() = Some(Fault::BeforeCommit);
        assert!(
            journal
                .admit(&request("session", operation, 0), 105)
                .unwrap_err()
                .reconciliation_required
        );
    }
    assert_eq!(
        journal.status("session", "running").unwrap().outcome,
        Outcome::Unknown
    );
    assert!(
        journal
            .finish(&claim, json!({"malformed":true}), 106)
            .unwrap_err()
            .reconciliation_required
    );
    assert_eq!(journal.inner.uncertain.lock().unwrap().len(), 2);
    assert_eq!(
        journal
            .finish(&claim, json!({"success":true}), 107)
            .unwrap_err()
            .code,
        "operation_reconciliation_required"
    );
}

#[test]
fn nested_private_storage_is_created_and_reopened_without_touching_its_parent() {
    let directory = Directory::new();
    let storage = directory.0.join("application/mechanical/rust");
    let journal = Journal::open_at(&storage, "session", "test", Limits::default(), 100).unwrap();
    admit(&journal, "op");
    assert!(storage.join(DATABASE_NAME).exists());
    let reopened = Journal::open_at(&storage, "fresh", "test", Limits::default(), 200).unwrap();
    assert_eq!(
        reopened.status("session", "op").unwrap().state,
        State::Interrupted
    );
    assert!(!directory.0.join(DATABASE_NAME).exists());
}

#[cfg(windows)]
#[test]
fn windows_hardlinked_database_is_refused_without_modification() {
    let directory = Directory::new();
    let journal = directory.open("session");
    admit(&journal, "retained");
    let original = journal.lookup("session", "retained").unwrap();
    let bytes = fs::read(journal.database_path()).unwrap();
    let alias = directory.0.join("unaccounted-hardlink.sqlite3");

    let before = file_identity(
        journal.database_path(),
        &fs::symlink_metadata(journal.database_path()).unwrap(),
    )
    .unwrap();
    assert_eq!(before.links, 1);
    fs::hard_link(journal.database_path(), &alias).unwrap();
    // On Windows these calls exercise the actual GetFileInformationByHandle
    // implementation, independently confirming two links to the same file.
    let linked = file_identity(
        journal.database_path(),
        &fs::symlink_metadata(journal.database_path()).unwrap(),
    )
    .unwrap();
    let alias_identity = file_identity(&alias, &fs::symlink_metadata(&alias).unwrap()).unwrap();
    assert_eq!(linked.links, 2);
    assert_eq!(alias_identity.links, 2);
    assert!(linked.same_file(alias_identity));

    assert_eq!(
        journal.lookup("session", "retained").unwrap_err().code,
        "operation_storage_invalid_path",
    );
    assert_eq!(
        journal
            .admit(&request("session", "refused", 0), 102)
            .unwrap_err()
            .code,
        "operation_storage_invalid_path",
    );
    assert_eq!(fs::read(journal.database_path()).unwrap(), bytes);
    assert_eq!(fs::read(&alias).unwrap(), bytes);

    fs::remove_file(alias).unwrap();
    assert_eq!(journal.lookup("session", "retained").unwrap(), original);
    assert!(journal.lookup("session", "refused").unwrap().is_none());
}

#[test]
fn transient_sidecar_disappearing_between_metadata_and_identity_is_safe() {
    let directory = Directory::new();
    let journal = directory.open("session");
    admit(&journal, "retained");
    let original = journal.lookup("session", "retained").unwrap();
    let bytes = fs::read(journal.database_path()).unwrap();
    for suffix in ["-journal", "-wal", "-shm"] {
        let sidecar = PathBuf::from(format!("{}{suffix}", journal.database_path().display()));
        fs::write(&sidecar, b"transient inspection fixture").unwrap();
        let mut removed = false;
        validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
            if path == sidecar && !removed {
                removed = true;
                fs::remove_file(path).unwrap();
                // This is the real I/O failure the Windows identity handle open
                // encounters after a concurrent SQLite commit deletes a sidecar.
                return Err(fs::File::open(path).unwrap_err().into());
            }
            file_identity(path, metadata)
        })
        .unwrap();
        assert!(removed);
        assert!(!sidecar.exists());
        assert_eq!(fs::read(journal.database_path()).unwrap(), bytes);
    }
    assert_eq!(journal.lookup("session", "retained").unwrap(), original);
}

#[test]
fn inspection_race_exception_never_hides_missing_database_or_existing_sidecar_error() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let sidecar = PathBuf::from(format!("{}-journal", journal.database_path().display()));
    fs::write(&sidecar, b"transient inspection fixture").unwrap();
    let failure = validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
        if path == sidecar {
            return Err(std::io::Error::from(std::io::ErrorKind::PermissionDenied).into());
        }
        file_identity(path, metadata)
    })
    .unwrap_err();
    assert_eq!(failure.code, "operation_storage_failed");
    assert!(sidecar.exists());

    let failure = validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
        if path == sidecar {
            fs::remove_file(path).unwrap();
            return Err(error(
                "operation_storage_invalid_path",
                "Identity inspection found a forbidden reparse point.",
            ));
        }
        file_identity(path, metadata)
    })
    .unwrap_err();
    assert_eq!(failure.code, "operation_storage_invalid_path");

    let failure = validate_files_with(&directory.0, journal.database_path(), |path, _metadata| {
        assert_eq!(path, journal.database_path());
        fs::remove_file(path).unwrap();
        Err(fs::File::open(path).unwrap_err().into())
    })
    .unwrap_err();
    assert_eq!(failure.code, "operation_storage_failed");
    assert!(journal.lookup("session", "retained").is_err());
    assert!(!journal.database_path().exists());
}

#[test]
fn zero_link_sidecar_is_rechecked_after_disappearance_or_regular_replacement() {
    for replace in [false, true] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let sidecar = directory.0.join(format!("{DATABASE_NAME}-journal"));
        fs::write(&sidecar, b"old sidecar").unwrap();
        #[cfg(unix)]
        let retained_handle = File::open(&sidecar).unwrap();
        let mut first = true;
        let mut sidecar_inspections = 0;
        let mut old_identity = None;
        validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
            let mut identity = file_identity(path, metadata)?;
            if path == sidecar {
                sidecar_inspections += 1;
                if first {
                    first = false;
                    old_identity = Some(identity);
                    fs::remove_file(path).unwrap();
                    if replace {
                        fs::write(path, b"replacement sidecar").unwrap();
                    }
                    // The real Windows failure reports this state after an
                    // opened sidecar handle outlives its directory entry.
                    identity.links = 0;
                } else {
                    assert!(!identity.same_file(old_identity.unwrap()));
                }
            }
            Ok(identity)
        })
        .unwrap();
        assert_eq!(sidecar_inspections, if replace { 2 } else { 1 });
        #[cfg(unix)]
        drop(retained_handle);
    }
}

#[test]
fn zero_link_replacement_must_pass_regular_file_and_hardlink_validation() {
    for hardlink in [false, true] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let sidecar = directory.0.join(format!("{DATABASE_NAME}-journal"));
        let other = directory.0.join("unaccounted-sidecar-owner");
        fs::write(&sidecar, b"old sidecar").unwrap();
        fs::write(&other, b"other").unwrap();
        let mut replaced = false;
        let failure =
            validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
                let mut identity = file_identity(path, metadata)?;
                if path == sidecar && !replaced {
                    replaced = true;
                    fs::remove_file(path).unwrap();
                    if hardlink {
                        fs::hard_link(&other, path).unwrap();
                    } else {
                        fs::create_dir(path).unwrap();
                    }
                    identity.links = 0;
                }
                Ok(identity)
            })
            .unwrap_err();
        assert_eq!(failure.code, "operation_storage_invalid_path");
    }
}

#[cfg(unix)]
#[test]
fn zero_link_replacement_symlink_or_foreign_write_permission_is_refused() {
    use std::os::unix::fs::{symlink, PermissionsExt};
    for link in [false, true] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let sidecar = directory.0.join(format!("{DATABASE_NAME}-journal"));
        let other = directory.0.join("other-sidecar");
        fs::write(&sidecar, b"old sidecar").unwrap();
        fs::write(&other, b"other").unwrap();
        let mut replaced = false;
        let failure =
            validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
                let mut identity = file_identity(path, metadata)?;
                if path == sidecar && !replaced {
                    replaced = true;
                    fs::remove_file(path).unwrap();
                    if link {
                        symlink(&other, path).unwrap();
                    } else {
                        fs::write(path, b"replacement").unwrap();
                        fs::set_permissions(path, fs::Permissions::from_mode(0o666)).unwrap();
                    }
                    identity.links = 0;
                }
                Ok(identity)
            })
            .unwrap_err();
        assert_eq!(failure.code, "operation_storage_invalid_path");
    }
}

#[test]
fn zero_link_sidecar_gets_one_fresh_validation_and_main_zero_remains_forbidden() {
    let directory = Directory::new();
    let journal = directory.open("session");
    let sidecar = directory.0.join(format!("{DATABASE_NAME}-journal"));
    fs::write(&sidecar, b"sidecar").unwrap();
    let mut attempts = 0;
    validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
        let mut identity = file_identity(path, metadata)?;
        if path == sidecar {
            attempts += 1;
            identity.links = 0;
        }
        Ok(identity)
    })
    .unwrap();
    assert_eq!(attempts, 2);
    let mut main_inspections = 0;
    let failure = validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
        let mut identity = file_identity(path, metadata)?;
        if path == journal.database_path() {
            main_inspections += 1;
            if main_inspections == 1 {
                identity.links = 0;
            }
        }
        Ok(identity)
    })
    .unwrap_err();
    assert_eq!(failure.code, "operation_storage_invalid_path");
    assert_eq!(main_inspections, 1);
}

#[test]
fn zero_link_fresh_inspection_keeps_existing_errors_and_invalid_identity_fatal() {
    for mode in ["existing-error", "invalid-then-absent", "absent-io-error"] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let sidecar = directory.0.join(format!("{DATABASE_NAME}-journal"));
        fs::write(&sidecar, b"sidecar").unwrap();
        let mut inspections = 0;
        let result =
            validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
                let mut identity = file_identity(path, metadata)?;
                if path == sidecar {
                    inspections += 1;
                    if inspections == 1 {
                        identity.links = 0;
                    } else {
                        match mode {
                            "existing-error" => {
                                return Err(std::io::Error::from(
                                    std::io::ErrorKind::PermissionDenied,
                                )
                                .into())
                            }
                            "invalid-then-absent" => {
                                fs::remove_file(path).unwrap();
                                return Err(error(
                                    "operation_storage_invalid_path",
                                    "Forbidden identity observed.",
                                ));
                            }
                            "absent-io-error" => {
                                fs::remove_file(path).unwrap();
                                return Err(File::open(path).unwrap_err().into());
                            }
                            _ => unreachable!(),
                        }
                    }
                }
                Ok(identity)
            });
        assert_eq!(inspections, 2);
        match mode {
            "existing-error" => assert_eq!(result.unwrap_err().code, "operation_storage_failed"),
            "invalid-then-absent" => {
                assert_eq!(result.unwrap_err().code, "operation_storage_invalid_path")
            }
            "absent-io-error" => result.unwrap(),
            _ => unreachable!(),
        }
    }
}

#[test]
fn staged_publication_match_cannot_excuse_replaced_main_or_extra_hardlink() {
    for change in [
        "replace-main",
        "third-link",
        "complete-publication",
        "replace-directory",
        "replace-staging-with-unaccounted-alias",
    ] {
        let directory = Directory::new();
        let journal = directory.open("session");
        let staged = directory.0.join(".operations-rust-v1-regression.tmp");
        let extra = directory.0.join("extra-hardlink");
        fs::hard_link(journal.database_path(), &staged).unwrap();
        let mut changed = false;
        let result =
            validate_files_with(&directory.0, journal.database_path(), |path, metadata| {
                let identity = file_identity(path, metadata)?;
                if path == staged && !changed {
                    changed = true;
                    match change {
                        "replace-main" => {
                            fs::remove_file(journal.database_path()).unwrap();
                            fs::write(journal.database_path(), b"different file identity").unwrap();
                        }
                        "third-link" => fs::hard_link(journal.database_path(), &extra).unwrap(),
                        "complete-publication" => fs::remove_file(&staged).unwrap(),
                        "replace-directory" => {
                            fs::remove_file(journal.database_path()).unwrap();
                            fs::create_dir(journal.database_path()).unwrap();
                        }
                        "replace-staging-with-unaccounted-alias" => {
                            fs::remove_file(&staged).unwrap();
                            fs::hard_link(journal.database_path(), &extra).unwrap();
                        }
                        _ => unreachable!(),
                    }
                }
                Ok(identity)
            });
        assert!(changed);
        if change == "complete-publication" {
            result.unwrap();
        } else {
            assert_eq!(result.unwrap_err().code, "operation_storage_invalid_path");
        }
    }
}