arete-interpreter 0.8.0

AST transformation runtime and VM for Arete streaming pipelines
Documentation
use std::collections::BTreeMap;

use arete_artifacts::{
    compose_stack_manifest_v2, decompose_legacy_stack, live_spec_v2, normalize_legacy_stack_v2,
    LiveSpecArtifactV2, PortableEntity, ProgramAdapterV2, ProgramSpecArtifact, SelectedViewV2,
};
use arete_hash::{CanonicalIdlDocument, PdaDefinitionV1, PdaSeedV1, ProgramSpecV1};
use arete_interpreter::public_artifacts::stack_specs_from_artifacts_v2;
use arete_interpreter::rust::compile_composed_public_artifacts_v2 as compile_rust_composition;
use arete_interpreter::typescript::{
    compile_composed_public_artifacts_v2 as compile_typescript_composition,
    compile_public_artifacts, compile_public_artifacts_v2, compile_stack_spec,
};
use arete_interpreter::versioned::load_stack_spec;

const ORE_STACK: &[u8] = include_bytes!("../../stacks/ore/.arete/OreStream.stack.json");

fn program() -> ProgramSpecArtifact {
    let document = CanonicalIdlDocument::parse(
        br#"{"address":"11111111111111111111111111111111","metadata":{"name":"system","version":"1.0.0","spec":"0.1.0"},"instructions":[],"accounts":[],"types":[],"events":[],"errors":[]}"#,
        None,
    )
    .unwrap();
    ProgramSpecArtifact::new(ProgramSpecV1::from_document(&document)).unwrap()
}

fn named_program(name: &str, address: &str) -> ProgramSpecV1 {
    let idl = format!(
        r#"{{"address":"{address}","metadata":{{"name":"{name}","version":"1.0.0","spec":"0.1.0"}},"instructions":[],"accounts":[],"types":[],"events":[],"errors":[]}}"#
    );
    let document = CanonicalIdlDocument::parse(idl.as_bytes(), None).unwrap();
    ProgramSpecV1::from_document(&document)
}

fn adapted_live(program: &ProgramSpecArtifact, entity: &str, pda_name: &str) -> LiveSpecArtifactV2 {
    live_spec_v2(
        std::slice::from_ref(program),
        vec![PortableEntity::new(entity, "id.address")],
        vec![ProgramAdapterV2 {
            program_spec_hash: program.artifact_hash,
            pdas: BTreeMap::from([(
                pda_name.to_string(),
                PdaDefinitionV1 {
                    name: pda_name.to_string(),
                    seeds: vec![PdaSeedV1::Literal {
                        value: pda_name.to_string(),
                    }],
                    program_id: None,
                    program: None,
                },
            )]),
            instruction_resolutions: Vec::new(),
        }],
    )
    .unwrap()
}

#[test]
fn ore_legacy_and_explicit_artifacts_generate_the_same_typescript() {
    let legacy = load_stack_spec(std::str::from_utf8(ORE_STACK).unwrap()).unwrap();
    let expected = compile_stack_spec(legacy, None).expect("legacy TypeScript");
    let artifacts = decompose_legacy_stack(ORE_STACK).expect("ORE decomposition");
    let actual = compile_public_artifacts(
        &artifacts.program_specs,
        &artifacts.live_spec,
        &artifacts.stack_manifest,
        None,
    )
    .expect("artifact TypeScript");

    assert_eq!(actual.full_file(), expected.full_file());
    assert_eq!(actual.warnings, expected.warnings);
    assert_eq!(actual.pda_degradations, expected.pda_degradations);
}

#[test]
fn ore_decomposition_hashes_are_repeatable_and_public() {
    let first = decompose_legacy_stack(ORE_STACK).expect("first decomposition");
    let second = decompose_legacy_stack(ORE_STACK).expect("second decomposition");
    assert_eq!(
        first.live_spec.artifact_hash,
        second.live_spec.artifact_hash
    );
    assert_eq!(
        first.stack_manifest.artifact_hash,
        second.stack_manifest.artifact_hash
    );

    let public_bytes = [
        first.live_spec.canonical_bytes().unwrap(),
        first.stack_manifest.canonical_bytes().unwrap(),
    ]
    .concat();
    let public = String::from_utf8(public_bytes).unwrap();
    for forbidden in [
        "platformParser",
        "platform_parser",
        "decoderBindingId",
        "decoderContentHash",
        "artifactRef",
    ] {
        assert!(!public.contains(forbidden), "found private key {forbidden}");
    }
}

#[test]
fn ore_v1_normalization_preserves_generated_behavior_without_legacy_extensions() {
    let legacy = load_stack_spec(std::str::from_utf8(ORE_STACK).unwrap()).unwrap();
    let expected = compile_stack_spec(legacy, None).expect("legacy TypeScript");
    let normalized = normalize_legacy_stack_v2(ORE_STACK).expect("V2 normalization");
    let actual = compile_public_artifacts_v2(
        &normalized.legacy.program_specs,
        &normalized.live_spec,
        &normalized.stack_manifest,
        None,
    )
    .expect("V2 artifact TypeScript");

    assert_eq!(actual.full_file(), expected.full_file());
    let bytes = normalized.live_spec.canonical_bytes().unwrap();
    let public = String::from_utf8(bytes).unwrap();
    assert!(!public.contains("legacyProgramExtensions"));
    assert!(public.contains("programAdapters"));
}

#[test]
fn ore_v2_single_live_rust_generation_preserves_the_legacy_output_shape() {
    let legacy = load_stack_spec(std::str::from_utf8(ORE_STACK).unwrap()).unwrap();
    let expected = arete_interpreter::rust::compile_stack_spec(legacy, None).unwrap();
    let normalized = normalize_legacy_stack_v2(ORE_STACK).unwrap();
    let actual = arete_interpreter::rust::compile_public_artifacts_v2(
        &normalized.legacy.program_specs,
        &normalized.live_spec,
        &normalized.stack_manifest,
        None,
    )
    .unwrap();
    assert_eq!(actual.lib_rs, expected.lib_rs);
    assert_eq!(actual.types_rs, expected.types_rs);
    assert_eq!(actual.entity_rs, expected.entity_rs);
}

#[test]
fn multi_live_interpretation_projects_views_and_isolates_adapters() {
    let program = program();
    let alpha = adapted_live(&program, "AlphaState", "alpha_pda");
    let beta = adapted_live(&program, "BetaState", "beta_pda");
    let lives = vec![("alpha".to_string(), alpha), ("beta".to_string(), beta)];
    let manifest = compose_stack_manifest_v2(
        "Composed",
        std::slice::from_ref(&program),
        lives
            .iter()
            .map(|(alias, live)| (alias.clone(), live))
            .collect(),
        vec![
            SelectedViewV2 {
                live_alias: "alpha".to_string(),
                view_id: "AlphaState/state".to_string(),
            },
            SelectedViewV2 {
                live_alias: "beta".to_string(),
                view_id: "BetaState/list".to_string(),
            },
        ],
    )
    .unwrap();

    let composed =
        stack_specs_from_artifacts_v2(std::slice::from_ref(&program), &lives, &manifest).unwrap();
    assert_eq!(
        composed
            .live_specs
            .iter()
            .map(|live| live.alias.as_str())
            .collect::<Vec<_>>(),
        vec!["alpha", "beta"]
    );
    assert_eq!(
        composed.live_specs[0].stack_spec.entities[0]
            .views
            .iter()
            .map(|view| view.id.as_str())
            .collect::<Vec<_>>(),
        vec!["AlphaState/state"]
    );
    assert_eq!(
        composed.live_specs[1].stack_spec.entities[0]
            .views
            .iter()
            .map(|view| view.id.as_str())
            .collect::<Vec<_>>(),
        vec!["BetaState/list"]
    );
    let alpha_pdas = &composed.live_specs[0].stack_spec.pdas["system"];
    let beta_pdas = &composed.live_specs[1].stack_spec.pdas["system"];
    assert!(alpha_pdas.contains_key("alpha_pda"));
    assert!(!alpha_pdas.contains_key("beta_pda"));
    assert!(beta_pdas.contains_key("beta_pda"));
    assert!(!beta_pdas.contains_key("alpha_pda"));
}

#[test]
fn empty_selected_views_generate_no_rust_client_views() {
    let program = program();
    let live = adapted_live(&program, "EmptyState", "empty_pda");
    let manifest = compose_stack_manifest_v2(
        "EmptyViews",
        std::slice::from_ref(&program),
        vec![("empty".to_string(), &live)],
        Vec::new(),
    )
    .unwrap();
    let output = arete_interpreter::rust::compile_public_artifacts_v2(
        std::slice::from_ref(&program),
        &live,
        &manifest,
        None,
    )
    .unwrap();

    assert!(!output.entity_rs.contains("EmptyStateEntityViews"));
    assert!(!output.entity_rs.contains("pub fn state"));
    assert!(!output.entity_rs.contains("pub fn list"));
    assert!(output
        .entity_rs
        .contains("pub struct EmptyViewsStackViews {\n\n}"));
}

#[test]
fn typescript_and_rust_compositions_keep_two_and_three_lives_namespaced() {
    let program = program();
    let shared = adapted_live(&program, "SharedState", "shared_pda");
    let third = adapted_live(&program, "ThirdState", "third_pda");
    let lives = vec![
        ("first-live".to_string(), shared.clone()),
        ("second_live".to_string(), shared),
        ("third".to_string(), third),
    ];
    let manifest = compose_stack_manifest_v2(
        "Jurassic",
        std::slice::from_ref(&program),
        lives
            .iter()
            .map(|(alias, live)| (alias.clone(), live))
            .collect(),
        vec![
            SelectedViewV2 {
                live_alias: "first-live".to_string(),
                view_id: "SharedState/list".to_string(),
            },
            SelectedViewV2 {
                live_alias: "third".to_string(),
                view_id: "ThirdState/list".to_string(),
            },
        ],
    )
    .unwrap();

    let typescript =
        compile_typescript_composition(std::slice::from_ref(&program), &lives, &manifest, None)
            .unwrap();
    assert_eq!(
        typescript
            .live_stacks
            .iter()
            .map(|live| (live.alias.as_str(), live.module_name.as_str()))
            .collect::<Vec<_>>(),
        vec![
            ("first-live", "first-live-stack"),
            ("second_live", "second-live-stack"),
            ("third", "third-stack")
        ]
    );
    assert!(typescript
        .session_definition
        .contains("mode: 'composition'"));
    assert!(typescript
        .session_definition
        .contains("\"first-live\": FirstLiveStack"));
    assert!(typescript
        .session_definition
        .contains("second_live: SecondLiveStack"));
    assert!(typescript
        .session_definition
        .contains("createJurassicSession"));
    assert!(typescript.live_stacks[0]
        .output
        .stack_definition
        .contains("list: listView<SharedState>('SharedState/list')"));
    assert!(!typescript.live_stacks[0]
        .output
        .stack_definition
        .contains("state: stateView<SharedState"));
    assert!(!typescript.live_stacks[1]
        .output
        .stack_definition
        .contains("SharedState/list"));

    let rust =
        compile_rust_composition(std::slice::from_ref(&program), &lives, &manifest, None).unwrap();
    assert_eq!(
        rust.live_stacks
            .iter()
            .map(|live| live.module_name.as_str())
            .collect::<Vec<_>>(),
        vec!["first_live", "second_live", "third"]
    );
    assert_eq!(
        rust.lib_rs,
        "pub mod first_live;\npub mod second_live;\npub mod third;\n"
    );
    assert!(rust.live_stacks[0].output.entity_rs.contains("pub fn list"));
    assert!(!rust.live_stacks[0]
        .output
        .entity_rs
        .contains("pub fn state"));
    assert!(!rust.live_stacks[1].output.entity_rs.contains("pub fn list"));
}

#[test]
fn typescript_composition_keeps_independent_program_reads() {
    let live_program = program();
    let independent = ProgramSpecArtifact::new(named_program(
        "independent_program",
        "Independent11111111111111111111111111111111",
    ))
    .unwrap();
    let live = adapted_live(&live_program, "LiveState", "live_pda");
    let lives = vec![("live".to_string(), live.clone())];
    let programs = vec![live_program, independent];
    let manifest = compose_stack_manifest_v2(
        "Jurassic",
        &programs,
        vec![("live".to_string(), &live)],
        Vec::new(),
    )
    .unwrap();

    let output = compile_typescript_composition(&programs, &lives, &manifest, None).unwrap();
    let collection = output.program_collection.as_ref().unwrap();
    assert_eq!(collection.module_name, "jurassic-programs");
    assert!(collection
        .output
        .stack_definition
        .contains("independentProgram"));
    assert!(collection
        .output
        .stack_definition
        .contains("JurassicProgramsEntity = never"));
    assert!(output
        .session_definition
        .contains("independentProgram: JurassicPrograms.programs.independentProgram"));
    assert!(output
        .session_definition
        .contains("independentProgram: JurassicPrograms.programReads.independentProgram"));
    assert!(output
        .session_definition
        .contains("export const JURASSIC_SDK"));
}