harn-vm 0.10.68

Async bytecode virtual machine for the Harn programming language
Documentation
use super::*;
use crate::event_log::{
    install_active_event_log, install_memory_for_current_thread, reset_active_event_log,
    AnyEventLog, SqliteEventLog,
};
use crate::observability::execution_scope::{enter_execution_scope, mint_execution_scope};

fn string(value: &str) -> VmValue {
    VmValue::String(arcstr::ArcStr::from(value))
}

fn dict(entries: impl IntoIterator<Item = (&'static str, VmValue)>) -> VmValue {
    VmValue::dict(
        entries
            .into_iter()
            .map(|(key, value)| (crate::value::intern_key(key), value))
            .collect::<crate::value::DictMap>(),
    )
}

fn plan_fingerprint() -> String {
    format!("sha256:{}", "b".repeat(64))
}

fn hypothesis_event_payload_from_content(content: VmValue) -> (VmValue, String) {
    let canonical = crate::stdlib::json::vm_value_to_json(&content);
    let fingerprint = format!(
        "sha256:{}",
        harn_kernel::pure::sha256_hex(canonical.as_bytes())
    );
    let payload = dict([("content", content), ("fingerprint", string(&fingerprint))]);
    (payload, fingerprint)
}

fn hypothesis_event_payload() -> (VmValue, String) {
    hypothesis_event_payload_from_content(dict([
        ("schema", string("harn.hypothesis.event.v1")),
        ("event_id", string("event-1")),
        ("hypothesis_id", string("hyp-1")),
        ("plan_id", VmValue::Nil),
        ("run_id", VmValue::Nil),
        ("payload", dict([("kind", string("plan_registered"))])),
    ]))
}

fn ctx() -> crate::vm::AsyncBuiltinCtx {
    crate::vm::AsyncBuiltinCtx::for_test(Vm::new())
}

async fn mint_proof(
    authority_kind: &str,
    event_fingerprint: &str,
    plan_fingerprint: &str,
    run_id: Option<&str>,
) -> VmValue {
    let attestation = mint_hypothesis_native_attestation(
        authority_kind,
        event_fingerprint,
        plan_fingerprint,
        "hyp-1",
        run_id,
    )
    .expect("registered native adapter should issue an attestation");
    hypothesis_event_authority_mint_impl(
        ctx(),
        vec![
            attestation,
            string(authority_kind),
            string(event_fingerprint),
            string(plan_fingerprint),
            string("hyp-1"),
            run_id.map(string).unwrap_or(VmValue::Nil),
        ],
    )
    .await
    .expect("native authority mint should succeed")
}

fn append_args(
    proof: VmValue,
    payload: VmValue,
    event_fingerprint: &str,
    plan_fingerprint: &str,
    run_id: Option<&str>,
    expected_head: Option<&str>,
) -> Vec<VmValue> {
    vec![
        proof,
        string("hypothesis.plan_registered"),
        string(event_fingerprint),
        expected_head.map(string).unwrap_or(VmValue::Nil),
        string(event_fingerprint),
        string(plan_fingerprint),
        string("hyp-1"),
        run_id.map(string).unwrap_or(VmValue::Nil),
        payload,
        dict([]),
    ]
}

#[tokio::test(flavor = "current_thread")]
async fn native_append_rejects_provenance_headers_before_commit() {
    reset_active_event_log();
    install_memory_for_current_thread(EVENT_LOG_QUEUE_DEPTH);
    let _scope = enter_execution_scope(mint_execution_scope());
    let (payload, event_fingerprint) = hypothesis_event_payload();
    let plan_fingerprint = plan_fingerprint();
    let proof = mint_proof(
        "plan_admission",
        &event_fingerprint,
        &plan_fingerprint,
        None,
    )
    .await;
    let mut args = append_args(
        proof,
        payload,
        &event_fingerprint,
        &plan_fingerprint,
        None,
        None,
    );
    args[9] = dict([("harn.provenance.record_hash", string("caller-controlled"))]);

    let error = hypothesis_event_append_impl(ctx(), args)
        .await
        .expect_err("provenance headers must be rejected before persistence");
    assert!(error
        .to_string()
        .contains("header 'harn.provenance.record_hash' is reserved"));

    let topic = Topic::new(HYPOTHESIS_LEDGER_TOPIC).unwrap();
    let events = ensure_event_log()
        .read_range(&topic, None, usize::MAX)
        .await
        .unwrap();
    assert!(
        events.is_empty(),
        "a rejected append must not commit an event"
    );
    reset_active_event_log();
}

#[tokio::test(flavor = "current_thread")]
async fn native_sqlite_reopen_replays_then_appends_a_follow_up_event() {
    reset_active_event_log();
    let directory = tempfile::tempdir().unwrap();
    let path = directory.path().join("hypothesis-events.sqlite");
    install_active_event_log(Arc::new(AnyEventLog::Sqlite(
        SqliteEventLog::open(path.clone(), EVENT_LOG_QUEUE_DEPTH).unwrap(),
    )));
    let (plan_payload, plan_event_fingerprint) = hypothesis_event_payload();
    let plan_fingerprint = plan_fingerprint();
    {
        let _scope = enter_execution_scope(mint_execution_scope());
        let proof = mint_proof(
            "plan_admission",
            &plan_event_fingerprint,
            &plan_fingerprint,
            None,
        )
        .await;
        let inserted = hypothesis_event_append_impl(
            ctx(),
            append_args(
                proof,
                plan_payload.clone(),
                &plan_event_fingerprint,
                &plan_fingerprint,
                None,
                None,
            ),
        )
        .await
        .expect("native plan admission should persist to SQLite");
        assert_eq!(vm_value_to_json(&inserted)["inserted"], true);
    }

    reset_active_event_log();
    install_active_event_log(Arc::new(AnyEventLog::Sqlite(
        SqliteEventLog::open(path, EVENT_LOG_QUEUE_DEPTH).unwrap(),
    )));
    let _scope = enter_execution_scope(mint_execution_scope());
    let replay_proof = mint_proof(
        "plan_admission",
        &plan_event_fingerprint,
        &plan_fingerprint,
        None,
    )
    .await;
    let replay = hypothesis_event_append_impl(
        ctx(),
        append_args(
            replay_proof,
            plan_payload,
            &plan_event_fingerprint,
            &plan_fingerprint,
            None,
            Some("sha256:stale-after-reopen"),
        ),
    )
    .await
    .expect("a native adapter may remint exact authority and replay after reopen");
    assert_eq!(vm_value_to_json(&replay)["inserted"], false);

    let topic = Topic::new(HYPOTHESIS_LEDGER_TOPIC).unwrap();
    let persisted = ensure_event_log()
        .read_range(&topic, None, usize::MAX)
        .await
        .unwrap();
    let head = persisted[0].1.headers[crate::provenance::HEADER_RECORD_HASH].clone();
    let (follow_up_payload, follow_up_fingerprint) = hypothesis_event_payload_from_content(dict([
        ("schema", string("harn.hypothesis.event.v1")),
        ("event_id", string("event-2")),
        ("hypothesis_id", string("hyp-1")),
        ("plan_id", string("plan-1")),
        ("run_id", string("run-1")),
        (
            "payload",
            dict([
                ("kind", string("run_transition")),
                ("state", string("scheduled")),
            ]),
        ),
    ]));
    let follow_up_proof = mint_proof(
        "lifecycle_audit",
        &follow_up_fingerprint,
        &plan_fingerprint,
        Some("run-1"),
    )
    .await;
    let mut follow_up_args = append_args(
        follow_up_proof,
        follow_up_payload,
        &follow_up_fingerprint,
        &plan_fingerprint,
        Some("run-1"),
        Some(&head),
    );
    follow_up_args[1] = string("hypothesis.run_transition");
    let follow_up = hypothesis_event_append_impl(ctx(), follow_up_args)
        .await
        .expect("a reminted native lifecycle event should append after SQLite reopen");
    assert_eq!(vm_value_to_json(&follow_up)["inserted"], true);
    let events = ensure_event_log()
        .read_range(&topic, None, usize::MAX)
        .await
        .unwrap();
    assert_eq!(events.len(), 2);
    reset_active_event_log();
}