master
Drew Owens Port occurrence translation and contract authoring to Rust; publish verified R21 source a06dfd7 26d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
use super::*;
use std::cell::{Cell, RefCell};
pub(crate) const DOC: &str = "d:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:0000000000000001";
pub(crate) fn empty() -> Projection {
    Projection {
        root: Root {
            revision: "r0".into(),
            name: "Root".into(),
            active: true,
            parametric: true,
            hybrid: true,
            configured: false,
            offline: false,
            pending_snapshot: false,
            components: 1,
            occurrences: 0,
            timeline: 0,
            timeline_position: 0,
            bodies: 0,
            sketches: 0,
            mesh_bodies: 0,
            joints: 0,
            as_built_joints: 0,
            rigid_groups: 0,
            assembly_constraints: 0,
            motion_links: 0,
            joint_origins: 0,
        },
        components: vec![],
        occurrences: vec![],
        cloud_metadata: false,
    }
}
pub(super) fn component() -> Component {
    Component {
        name: "Component1".into(),
        revision: "c0".into(),
        attributes: BTreeMap::new(),
        part_number: Some("Component1".into()),
        description: Some(String::new()),
        bodies: 0,
        sketches: 0,
        occurrences: 0,
        mesh_bodies: 0,
        joints: 0,
        as_built_joints: 0,
        rigid_groups: 0,
        assembly_constraints: 0,
        motion_links: 0,
    }
}
pub(super) fn occurrence(ci: usize) -> Occurrence {
    Occurrence {
        component: ci,
        name: format!("Component{}:1", ci + 1),
        path: format!("Component{}:1", ci + 1),
        matrix: [
            1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.,
        ],
        grounded: false,
        grounded_to_parent: false,
        referenced: false,
        configured: false,
        suppressed: false,
        rolled_back: false,
        native: true,
        children: 0,
    }
}
pub(crate) struct Fake {
    pub state: RefCell<Projection>,
    pub add_calls: Cell<usize>,
    pub change_calls: Cell<usize>,
    pub mode: Cell<u32>,
    reads: Cell<usize>,
    pub changes: RefCell<Vec<String>>,
}
impl Default for Fake {
    fn default() -> Self {
        Self {
            state: RefCell::new(empty()),
            add_calls: Cell::new(0),
            change_calls: Cell::new(0),
            mode: Cell::new(0),
            reads: Cell::new(0),
            changes: RefCell::new(vec![]),
        }
    }
}
impl Backend for Fake {
    type Handle = u64;
    fn open(&self) -> Open<u64> {
        Open {
            handle: Some(9),
            acknowledged: self.mode.get() != 20,
        }
    }
    fn command(&self) -> Result<String> {
        Ok("SelectCommand".into())
    }
    fn snapshot(&self, h: &u64, cloud: bool) -> Result<Projection> {
        assert_eq!(*h, 9);
        self.reads.set(self.reads.get() + 1);
        if self.mode.get() == 4 && self.add_calls.get() > 0 {
            panic!("post-effect read");
        }
        let mut p = self.state.borrow().clone();
        p.cloud_metadata = cloud;
        if cloud && p.root.offline {
            return Err("native_assembly_native_metadata_requires_online".into());
        }
        if !cloud {
            for c in &mut p.components {
                c.part_number = None;
                c.description = None;
            }
        }
        if self.mode.get() == 8 && !p.components.is_empty() {
            p.components[0].part_number = Some("leaked".into());
            p.components[0].description = None;
        }
        if self.mode.get() == 9 {
            p.cloud_metadata = !cloud;
        }
        if self.mode.get() == 10 {
            p.root.revision = format!("read{}", self.reads.get());
        }
        Ok(p)
    }
    fn add(&self, _: &u64, existing: Option<usize>) -> Attempt {
        self.add_calls.set(self.add_calls.get() + 1);
        if self.mode.get() == 12 {
            panic!("add boundary panic");
        }
        if self.mode.get() == 3 {
            return Attempt::default();
        }
        let mut p = self.state.borrow_mut();
        let ci = existing.unwrap_or(p.components.len());
        if existing.is_none() {
            p.components.push(component());
            p.root.components += 1;
        }
        let oi = p.occurrences.len();
        p.occurrences.push(occurrence(ci));
        p.root.occurrences += 1;
        p.root.timeline += 1;
        p.root.timeline_position = p.root.timeline;
        p.root.revision = format!("add{}", self.add_calls.get());
        if self.mode.get() == 5 {
            p.root.pending_snapshot = true;
        }
        if self.mode.get() == 7 {
            p.root.name = "Foreign edit".into();
        }
        Attempt {
            invoked: true,
            acknowledged: self.mode.get() != 1,
            component: Some(if self.mode.get() == 6 { ci + 1 } else { ci }),
            occurrence: Some(oi),
        }
    }
    fn change(&self, _: &u64, ci: usize, c: &Change) -> Attempt {
        self.change_calls.set(self.change_calls.get() + 1);
        if self.mode.get() == 13 {
            panic!("metadata boundary panic");
        }
        self.changes.borrow_mut().push(c.key.clone());
        let mut p = self.state.borrow_mut();
        let comp = &mut p.components[ci];
        match c.key.as_str() {
            "name" => comp.name = c.value.clone(),
            "partNumber" => {
                comp.part_number = Some(if c.value.is_empty() {
                    comp.name.clone()
                } else {
                    c.value.clone()
                })
            }
            "description" => comp.description = Some(c.value.clone()),
            _ => {
                comp.attributes.insert(c.key.clone(), c.value.clone());
            }
        }
        comp.revision = format!("m{}", self.change_calls.get());
        if c.key == "name" {
            for o in &mut p.occurrences {
                if o.component == ci {
                    o.name = format!("{}:1", c.value);
                    o.path = o.name.clone();
                }
            }
        }
        p.root.revision = format!("m{}", self.change_calls.get());
        Attempt {
            invoked: true,
            acknowledged: self.mode.get() != 2 || self.change_calls.get() != 2,
            component: Some(ci),
            occurrence: None,
        }
    }
}
pub(crate) fn request(book: &mut Book<u64>, b: &Fake, epoch: &str, id: &str) -> PreparedRequest {
    let value = book.inspect(b, DOC, None, false).unwrap();
    prepare(
        json!({"op":"component_create","sessionId":epoch,"operationId":id,"target":value["data"]["target"],"name":"A"}),
        epoch,
    )
}
pub(super) fn prepare(v: Value, epoch: &str) -> PreparedRequest {
    fusion_mechanical_core::prepare_request(v, epoch).unwrap()
}
fn create(book: &mut Book<u64>, b: &Fake, name: &str) -> Value {
    let r = request(book, b, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", name);
    let mut a = r.arguments().clone();
    a["name"] = json!(name);
    let p = book
        .preflight(b, &prepare(a, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
        .unwrap();
    book.execute(b, p)
}
fn edit_request(book: &mut Book<u64>, b: &Fake, cloud: bool, changes: Value) -> PreparedRequest {
    let v = book.inspect(b, DOC, None, cloud).unwrap();
    prepare(
        json!({"op":"component_metadata","sessionId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","operationId":"metadata","target":v["data"]["target"],"component":v["data"]["components"][0]["ref"],"changes":changes}),
        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    )
}
#[test]
fn exact_two_definitions_three_instances_have_separate_ids_and_shared_component() {
    let b = Fake::default();
    let mut book = Book::default();
    assert_eq!(create(&mut book, &b, "A")["success"], true);
    assert_eq!(create(&mut book, &b, "B")["success"], true);
    let s = book.inspect(&b, DOC, None, false).unwrap();
    let r = prepare(
        json!({"op":"occurrence_insert","sessionId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","operationId":"shared","target":s["data"]["target"],"component":s["data"]["components"][0]["ref"]}),
        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    );
    let p = book.preflight(&b, &r).unwrap();
    let v = book.execute(&b, p);
    assert_eq!(v["success"], true, "{v}");
    let d = &v["data"];
    assert_eq!(d["components"].as_array().unwrap().len(), 2);
    assert_eq!(d["occurrences"].as_array().unwrap().len(), 3);
    assert_eq!(
        d["occurrences"][0]["componentId"],
        d["occurrences"][2]["componentId"]
    );
    assert_ne!(
        d["occurrences"][0]["occurrenceId"],
        d["occurrences"][2]["occurrenceId"]
    );
    assert_ne!(
        d["components"][0]["componentId"],
        d["components"][1]["componentId"]
    );
    assert_eq!(d["complete"], false);
    assert!(d["components"][0]["partNumber"].is_null());
}
#[test]
fn metadata_order_escaping_and_empty_part_number_reset_readback() {
    let b = Fake::default();
    let mut book = Book::default();
    create(&mut book, &b, "A");
    b.changes.borrow_mut().clear();
    let r = edit_request(
        &mut book,
        &b,
        true,
        json!({"supplier":"quote\"\\line\n","excludeFromBom":true,"name":"Renamed","description":"desc","partNumber":""}),
    );
    let p = book.preflight(&b, &r).unwrap();
    let v = book.execute(&b, p);
    assert_eq!(v["success"], true, "{v}");
    assert_eq!(
        *b.changes.borrow(),
        vec![
            "name",
            "partNumber",
            "description",
            "excludeFromBom",
            "supplier"
        ]
    );
    assert_eq!(v["data"]["components"][0]["partNumber"], "Renamed");
    let raw = v["data"]["components"][0]["attributes"]["supplier"]
        .as_str()
        .unwrap();
    assert_eq!(
        serde_json::from_str::<Value>(raw).unwrap(),
        json!("quote\"\\line\n")
    );
}
#[test]
fn online_refusal_does_not_retire_offline_safe_owned_view() {
    let b = Fake::default();
    let mut book = Book::default();
    create(&mut book, &b, "A");
    b.state.borrow_mut().root.offline = true;
    assert_eq!(
        book.inspect(&b, DOC, None, true).unwrap_err(),
        "native_assembly_native_metadata_requires_online"
    );
    assert!(book.inspect(&b, DOC, None, false).is_ok());
    let r = edit_request(&mut book, &b, false, json!({"supplier":"local"}));
    let p = book.preflight(&b, &r).unwrap();
    assert_eq!(book.execute(&b, p)["success"], true);
}
#[test]
fn partial_cloud_fields_and_wrong_requested_mode_are_rejected() {
    for mode in [8, 9] {
        let b = Fake::default();
        let mut book = Book::default();
        create(&mut book, &b, "A");
        b.mode.set(mode);
        assert!(book.inspect(&b, DOC, None, false).is_err());
        b.mode.set(0);
        assert_eq!(
            book.inspect(&b, DOC, None, false).unwrap_err(),
            "native_assembly_document_retired"
        );
    }
    let mut p = empty();
    p.cloud_metadata = true;
    p.components.push(component());
    p.occurrences.push(occurrence(0));
    p.root.components = 2;
    p.root.occurrences = 1;
    p.components[0].description = None;
    assert_eq!(
        validate(&p).unwrap_err(),
        "native_assembly_metadata_incomplete"
    );
}
#[test]
fn foreign_component_and_foreign_plan_never_invoke_effect() {
    let b = Fake::default();
    let mut book = Book::default();
    create(&mut book, &b, "A");
    let r = edit_request(&mut book, &b, false, json!({"name":"N"}));
    let mut args = r.arguments().clone();
    args["component"]["componentId"] = json!("c:foreign:0000000000000001");
    assert_eq!(
        book.preflight(&b, &prepare(args, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
            .unwrap_err(),
        "native_assembly_component_not_owned"
    );
    let p = book.preflight(&b, &r).unwrap();
    let mut other = Book::default();
    other.inspect(&b, DOC, None, false).unwrap();
    let changes = b.change_calls.get();
    assert_eq!(
        other.execute(&b, p)["errorCode"],
        "native_assembly_foreign_plan"
    );
    assert_eq!(b.change_calls.get(), changes);
}
#[test]
fn stale_plan_after_preflight_refuses_before_add() {
    let b = Fake::default();
    let mut book = Book::default();
    let r = request(&mut book, &b, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "stale");
    let p = book.preflight(&b, &r).unwrap();
    b.state.borrow_mut().root.revision = "user edit".into();
    let v = book.execute(&b, p);
    assert_eq!(v["errorCode"], "target_revision_mismatch");
    assert_eq!(v["nativeExecutionStarted"], false);
    assert_eq!(b.add_calls.get(), 0);
}
#[test]
fn sdk_unknown_prefixes_are_retained_and_book_cannot_repeat() {
    for mode in [1, 2, 4, 5, 6, 7, 12, 13] {
        let b = Fake::default();
        let mut book = Book::default();
        let mut r = request(&mut book, &b, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "fault")
            .arguments()
            .clone();
        r["metadata"] = json!({"supplier":"x"});
        let r = prepare(r, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        let p = book.preflight(&b, &r).unwrap();
        b.mode.set(mode);
        let v = book.execute(&b, p);
        assert_eq!(v["outcome"], "unknown", "mode {mode}: {v}");
        assert_eq!(v["nativeExecutionStarted"], true);
        assert_eq!(b.add_calls.get(), 1);
        assert!(!v["stages"].as_array().unwrap().is_empty());
        b.mode.set(0);
        assert_eq!(
            book.preflight(&b, &r).unwrap_err(),
            "native_assembly_book_unavailable"
        );
        assert_eq!(b.add_calls.get(), 1);
    }
}
#[test]
fn noninvoked_add_is_known_refusal_and_does_not_poison_book() {
    let b = Fake::default();
    let mut book = Book::default();
    let r = request(&mut book, &b, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "refused");
    let p = book.preflight(&b, &r).unwrap();
    b.mode.set(3);
    let v = book.execute(&b, p);
    assert_eq!(v["nativeExecutionStarted"], false);
    assert!(v.get("outcome").is_none());
    b.mode.set(0);
    assert!(book.inspect(&b, DOC, None, false).is_ok());
}
#[test]
fn effect_observation_capacity_refusal_is_before_add() {
    let b = Fake::default();
    let mut book = Book::default();
    let r = request(
        &mut book,
        &b,
        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
        "capacity",
    );
    let mut p = book.preflight(&b, &r).unwrap();
    p.action = Action::Create {
        changes: vec![
            Change {
                key: "name".into(),
                value: "x".into(),
                native: true
            };
            10
        ],
    };
    let v = book.execute(&b, p);
    assert_eq!(v["errorCode"], "native_assembly_observation_capacity");
    assert_eq!(b.add_calls.get(), 0);
    assert_eq!(b.change_calls.get(), 0);
}
#[test]
fn changing_projection_retires_identity_without_silent_read_recovery() {
    let b = Fake::default();
    let mut book = Book::default();
    book.inspect(&b, DOC, None, false).unwrap();
    b.mode.set(10);
    assert_eq!(
        book.inspect(&b, DOC, None, false).unwrap_err(),
        "native_assembly_projection_changed"
    );
    b.mode.set(0);
    assert_eq!(
        book.inspect(&b, DOC, None, false).unwrap_err(),
        "native_assembly_document_retired"
    );
}
#[test]
fn no_implicit_snapshot_capture_or_foreign_graph_is_accepted() {
    for field in 0..5 {
        let mut p = empty();
        match field {
            0 => p.root.pending_snapshot = true,
            1 => p.root.assembly_constraints = 1,
            2 => p.root.motion_links = 1,
            3 => p.root.joint_origins = 1,
            _ => p.root.configured = true,
        }
        assert!(validate(&p).is_err());
    }
}
#[test]
fn slot_bounds_no_eviction_and_release_failure_no_retry() {
    let b = Fake::default();
    let mut book = Book::default();
    for i in 0..MAX_DOCUMENTS {
        book.inspect(&b, &format!("doc{i}"), None, false).unwrap();
    }
    assert_eq!(
        book.inspect(&b, "extra", None, false).unwrap_err(),
        "native_assembly_document_capacity"
    );
    let calls = Cell::new(0);
    assert!(book
        .close(|_| {
            calls.set(calls.get() + 1);
            Err("release lost".into())
        })
        .is_err());
    assert!(book
        .close(|_| {
            calls.set(calls.get() + 1);
            Ok(())
        })
        .is_err());
    assert_eq!(calls.get(), 1);
    assert!(book.ensure_released().is_err());
}
#[test]
fn partial_open_retains_handle_until_one_explicit_release() {
    let b = Fake::default();
    b.mode.set(20);
    let mut book = Book::default();
    assert_eq!(
        book.inspect(&b, DOC, None, false).unwrap_err(),
        "native_assembly_open_unconfirmed"
    );
    assert!(book.ensure_released().is_err());
    let released = Cell::new(0);
    book.close(|h| {
        assert_eq!(h, 9);
        released.set(released.get() + 1);
        Ok(())
    })
    .unwrap();
    assert_eq!(released.get(), 1);
}
#[test]
fn unsupported_transform_parent_native_create_metadata_and_implicit_name_dependency_refuse() {
    let b = Fake::default();
    let mut book = Book::default();
    let request = request(&mut book, &b, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bad");
    for extra in [
        json!({"transform":{"position":[1,0,0]}}),
        json!({"transform":{"axis":[0,0,1],"angle":90}}),
        json!({"parent":{"documentId":DOC,"revision":"r","objectType":"Component"}}),
        json!({"metadata":{"partNumber":"cloud"}}),
    ] {
        let mut a = request.arguments().clone();
        a.as_object_mut()
            .unwrap()
            .extend(extra.as_object().unwrap().clone());
        assert!(supported_arguments(&prepare(a, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")).is_err());
    }
    create(&mut book, &b, "A");
    let r = edit_request(&mut book, &b, true, json!({"name":"N","description":"D"}));
    assert_eq!(
        supported_arguments(&r),
        Err("native_assembly_rename_cloud_update_requires_explicit_part_number")
    );
    assert_eq!(b.add_calls.get(), 1);
}
#[test]
fn definition_and_occurrence_capacity_checked_before_any_effect() {
    for definitions in [true, false] {
        let b = Fake::default();
        let mut book = Book::default();
        book.inspect(&b, DOC, None, false).unwrap();
        {
            let mut p = b.state.borrow_mut();
            let n = if definitions { MAX_COMPONENTS } else { 1 };
            p.components = (0..n).map(|_| component()).collect();
            let nocc = if definitions {
                MAX_COMPONENTS
            } else {
                MAX_OCCURRENCES
            };
            p.occurrences = (0..nocc).map(|i| occurrence(i % n)).collect();
            p.root.components = n as u64 + 1;
            p.root.occurrences = nocc as u64;
        }
        let r = request(&mut book, &b, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "full");
        assert_eq!(
            book.preflight(&b, &r).unwrap_err(),
            "native_assembly_capacity"
        );
        assert_eq!(b.add_calls.get(), 0);
    }
}
#[test]
fn complete_online_snapshot_has_all_fields_or_refuses() {
    let mut p = empty();
    p.components.push(component());
    p.occurrences.push(occurrence(0));
    p.root.components = 2;
    p.root.occurrences = 1;
    p.cloud_metadata = true;
    assert!(validate(&p).is_ok());
    p.root.offline = true;
    assert_eq!(
        validate(&p).unwrap_err(),
        "native_assembly_native_metadata_requires_online"
    );
}
#[test]
fn encoded_attribute_bound_is_checked_before_any_add() {
    let b = Fake::default();
    let mut book = Book::default();
    let r = request(&mut book, &b, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "escaped");
    let mut a = r.arguments().clone();
    a["metadata"] = json!({"supplier":"\u{0001}".repeat(1000)});
    let r = prepare(a, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
    assert_eq!(
        book.preflight(&b, &r).unwrap_err(),
        "native_assembly_metadata_encoded_bound"
    );
    assert_eq!(b.add_calls.get(), 0);
}
#[test]
fn wrong_metadata_readback_or_unrelated_instance_change_is_not_success() {
    let b = Fake::default();
    let mut book = Book::default();
    create(&mut book, &b, "A");
    let r = edit_request(&mut book, &b, false, json!({"name":"N"}));
    let p = book.preflight(&b, &r).unwrap();
    let mut after = p.before.clone();
    after.components[0].name = "wrong".into();
    assert_eq!(
        verify_delta(&p, &after, 0).unwrap_err(),
        "native_assembly_metadata_readback_mismatch"
    );
    after.components[0].name = "N".into();
    after.occurrences[0].matrix[3] = 1.;
    assert_eq!(
        verify_delta(&p, &after, 0).unwrap_err(),
        "native_assembly_unrelated_occurrence_changed"
    );
}
#[test]
fn metadata_projection_modes_have_distinct_revision_and_stale_ref_refuses() {
    let b = Fake::default();
    let mut book = Book::default();
    create(&mut book, &b, "A");
    let local = book.inspect(&b, DOC, None, false).unwrap();
    let online = book.inspect(&b, DOC, None, true).unwrap();
    assert_ne!(
        local["data"]["target"]["revision"],
        online["data"]["target"]["revision"]
    );
    let r = prepare(
        json!({"op":"component_metadata","sessionId":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","operationId":"wrong-mode","target":local["data"]["target"],"component":local["data"]["components"][0]["ref"],"changes":{"partNumber":"PN"}}),
        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    );
    assert_eq!(
        book.preflight(&b, &r).unwrap_err(),
        "target_revision_mismatch"
    );
    assert_eq!(b.change_calls.get(), 1);
}
#[test]
fn maximum_published_reference_overhead_fits_native_retained_record_budget() {
    let mut p = empty();
    p.components = (0..MAX_COMPONENTS).map(|_| component()).collect();
    for c in &mut p.components {
        c.part_number = None;
        c.description = None;
    }
    p.occurrences = (0..MAX_OCCURRENCES)
        .map(|i| occurrence(i % MAX_COMPONENTS))
        .collect();
    p.root.components = MAX_COMPONENTS as u64 + 1;
    p.root.occurrences = MAX_OCCURRENCES as u64;
    for i in 0..120 {
        p.components[0]
            .attributes
            .insert(format!("padding{i}"), "x".repeat(1024));
        if serde_json::to_vec(&p).unwrap().len() > MAX_BYTES {
            p.components[0].attributes.remove(&format!("padding{i}"));
            break;
        }
    }
    validate(&p).unwrap();
    let doc = "d".repeat(128);
    let data = output(&doc, &p).unwrap();
    let stages = prepare_stages(&Action::Metadata {
        component_id: String::new(),
        changes: (0..8)
            .map(|i| Change {
                key: format!("field{i}"),
                value: "v".repeat(4096),
                native: false,
            })
            .collect(),
    })
    .unwrap();
    let result = json!({"success":true,"data":data,"componentId":component_id(&doc,0),"stages":stages,"nativeExecutionStarted":true,"automaticReplayAllowed":false,"rollbackAttempted":false,"legacyParity":false});
    assert!(serde_json::to_vec(&result).unwrap().len() < 240 * 1024);
    // Successful settling evidence reserves at most 8KiB COMBINED for the
    // changed root and all component revisions, plus bounded capture hashes.
    let mut with_evidence = result;
    with_evidence["readbackEvidence"] = json!({"combinedRootAndComponentRevisionDiagnostics":"x".repeat(readback::MAX_SETTLING_DIAGNOSTIC_BYTES),"captureHashes":"h".repeat(2048)});
    assert!(serde_json::to_vec(&with_evidence).unwrap().len() < 256 * 1024);
}
#[test]
fn assembly_capability_inventory_preserves_prior_operations_and_narrows_native_arguments() {
    let c = crate::execution::capabilities();
    assert_eq!(c["contractVersion"], CONTRACT);
    assert_eq!(c["operations"].as_array().unwrap().len(), 27);
    assert_eq!(c["rootAssemblySupport"], true);
    assert_eq!(c["assemblyTransformsSupported"], false);
    assert_eq!(c["legacyParity"], false);
    assert!(c["schemas"]["component_create"]["properties"]
        .get("parent")
        .is_none());
    assert!(
        c["schemas"]["component_create"]["properties"]["metadata"]["properties"]
            .get("partNumber")
            .is_none()
    );
    assert_eq!(
        c["schemas"]["occurrence_insert"]["properties"]["independentCopy"]["enum"],
        json!([false])
    );
    for op in [
        "component_create",
        "occurrence_insert",
        "component_metadata",
        "native_assembly_inspect",
        "sketch_dimension",
        "sketch_constraint",
        "bom",
        "parameter_create",
    ] {
        assert!(c["operations"].as_array().unwrap().contains(&json!(op)));
    }
}

#[test]
fn capture_change_diagnostic_keeps_revision_only_difference_and_equal_is_empty() {
    let before = empty().root;
    assert!(root_capture_diagnostic(&before, &before).is_none());
    let mut after = before.clone();
    after.revision = "observed-revision".into();
    let d = root_capture_diagnostic(&before, &after).unwrap();
    assert_eq!(d["changedFields"], json!(["revision"]));
    assert_eq!(d["expected"], json!(before));
    assert_eq!(d["observed"], json!(after));
    assert_eq!(d["additionalSdkReads"], 0);
    assert_eq!(d["retryAttempted"], false);
}
#[test]
fn capture_change_diagnostic_keeps_nonrevision_fields_without_reclassifying_outcome() {
    let before = empty().root;
    let mut after = before.clone();
    after.pending_snapshot = true;
    after.timeline = 1;
    after.timeline_position = 1;
    after.offline = true;
    let d = root_capture_diagnostic(&before, &after).unwrap();
    let changed: std::collections::BTreeSet<_> = d["changedFields"]
        .as_array()
        .unwrap()
        .iter()
        .map(|v| v.as_str().unwrap())
        .collect();
    assert_eq!(
        changed,
        std::collections::BTreeSet::from([
            "pendingSnapshot",
            "timeline",
            "timelinePosition",
            "offline"
        ])
    );
    assert_eq!(d["expected"]["revision"], d["observed"]["revision"]);
    assert_eq!(
        d["errorCode"],
        "native_assembly_root_changed_during_capture"
    );
    assert_eq!(d["comparison"], "exact_equality");
    assert!(d.get("outcome").is_none());
    assert!(d.get("nativeExecutionStarted").is_none());
}