Files
ARCADIA-Studio/harness/behavior-creation-contract.rs
T

677 lines
23 KiB
Rust

//! Independent native creation oracle; no desktop producer is imported.
//! self-check BASE | check STAGE BASE ACTUAL ROLES | same EXPECTED ACTUAL [UNDO_FROM]
use oa_core::{source_project::*, *};
use std::{
collections::{BTreeMap, BTreeSet},
fs,
path::Path,
};
const PROCESS: &str = "Coordinate rescue";
const SCENARIO: &str = "Rescue coordination conversation";
const MACHINE: &str = "Rescue team operating modes";
const VIEW: &str = "Rescue team operating modes · states";
const CAPABILITY: u128 = 0xb451c00000004000800000000000001f;
const OWNER: u128 = 0xc062944912094b50afacf558a9a0fc7f;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Stage {
Baseline,
Process,
Scenario,
Machine,
}
impl Stage {
fn parse(value: &str) -> Self {
match value {
"baseline" => Self::Baseline,
"process" => Self::Process,
"scenario" => Self::Scenario,
"machine" => Self::Machine,
_ => panic!("Stage must be baseline, process, scenario or machine"),
}
}
fn additions(self) -> usize {
match self {
Self::Baseline => 0,
Self::Process => 1,
Self::Scenario => 2,
Self::Machine => 3,
}
}
}
type DiskSources = BTreeMap<String, Vec<u8>>;
fn source_paths(root: &Path, here: &Path, paths: &mut DiskSources) {
for entry in fs::read_dir(here).unwrap() {
let entry = entry.unwrap();
let kind = entry.file_type().unwrap();
assert!(
!kind.is_symlink(),
"Native checkpoint must contain ordinary files"
);
if kind.is_dir() {
source_paths(root, &entry.path(), paths);
} else if entry.path().extension().is_some_and(|ext| ext == "arcadia") {
assert!(kind.is_file());
paths.insert(
entry
.path()
.strip_prefix(root)
.unwrap()
.to_str()
.unwrap()
.replace('\\', "/"),
fs::read(entry.path()).unwrap(),
);
}
}
}
fn load_checkpoint(entry: &Path) -> (CompiledSourceProject, DiskSources) {
let files = source_files::load_project(entry, ProjectLimits::default()).unwrap();
let raw = files.reachable_bundle();
let compiled = compile_bundle(&raw, ProjectLimits::default()).unwrap();
assert_eq!(
compiled.bundle, raw,
"No migration, normalization or implicit identity insertion"
);
execute_batch(&compiled.decoded.project, &[]).unwrap();
let mut disk = BTreeMap::new();
let root = entry.parent().unwrap();
source_paths(root, root, &mut disk);
(compiled, disk)
}
fn predicted_disk(reachable: &SourceBundle, undo_from: Option<&DiskSources>) -> DiskSources {
// Saving Undo writes the restored reachable files and deliberately keeps
// detached files from the previously saved checkpoint. Never infer their
// bytes from the actual Undo directory: its explicit origin is the oracle.
let mut expected = undo_from.cloned().unwrap_or_default();
expected.extend(
reachable
.files
.iter()
.map(|(path, source)| (path.clone(), source.as_bytes().to_vec())),
);
expected
}
fn load(entry: &Path) -> CompiledSourceProject {
let (compiled, disk) = load_checkpoint(entry);
assert_eq!(
disk,
predicted_disk(&compiled.bundle, None),
"Ordinary checkpoints must contain exactly their reachable source files; retained Undo files require an explicit origin"
);
compiled
}
fn fnv1a(bytes: &[u8]) -> u64 {
bytes.iter().fold(0xcbf29ce484222325, |hash, byte| {
(hash ^ u64::from(*byte)).wrapping_mul(0x100000001b3)
})
}
fn pinned_baseline(base: &CompiledSourceProject) -> bool {
// Fixed byte fingerprints of the root-preserved transition/reopen input,
// recorded before any creation. SHA-256 provenance is in the fixture README.
let pins = [
("project.arcadia", 4844, 0x450c6ffd8225af32),
("rationale.arcadia", 57, 0xf87e3c2e303f9b62),
("traceability.arcadia", 395, 0xb47992dbdacab344),
("oa/participants.arcadia", 403, 0x1e109eef81968b5f),
(
"oa/activities/activity_assess_incident.arcadia",
376,
0x0e67e533db3cff78,
),
("sa/participants.arcadia", 124, 0xcadb35025aea18cc),
];
base.bundle.entry == "project.arcadia"
&& base.bundle.files.len() == pins.len()
&& pins.iter().all(|(path, length, hash)| {
base.bundle
.files
.get(*path)
.is_some_and(|text| text.len() == *length && fnv1a(text.as_bytes()) == *hash)
})
}
fn baseline(entry: &Path) -> CompiledSourceProject {
let base = load(entry);
assert!(
pinned_baseline(&base),
"The six-file baseline differs from the frozen pre-creation input"
);
let p = &base.decoded.project;
assert_eq!(
(
p.elements.len(),
p.relations.len(),
p.diagrams.len(),
p.traces.len()
),
(10, 2, 4, 1)
);
let context = &p.elements[&Id::from_u128(CAPABILITY)];
assert_eq!(
(
context.name.as_str(),
context.kind(),
context.layer(),
context.parent
),
("Rescue capability", Kind::Capability, Layer::Oa, None)
);
let owner = &p.elements[&Id::from_u128(OWNER)];
assert_eq!(
(
owner.name.as_str(),
owner.kind(),
owner.layer(),
owner.parent
),
("Rescue team", Kind::SystemActor, Layer::Sa, None)
);
for name in [PROCESS, SCENARIO, MACHINE] {
assert!(
!p.elements.values().any(|e| e.name == name),
"Baseline already contains requested creation"
);
}
base
}
struct Roles<'a> {
actual: &'a Project,
baseline: &'a Project,
used: BTreeSet<Id>,
}
impl Roles<'_> {
fn fresh(&mut self, choices: Vec<Id>, role: &str) -> Id {
assert_eq!(
choices.len(),
1,
"Exactly one literal identity role required: {role}"
);
let id = choices[0];
assert_eq!(id.get_version_num(), 4, "{role} must be a fresh UUIDv4");
assert!(
!self.baseline.contains(id),
"{role} reuses a baseline identity"
);
assert!(self.used.insert(id), "{role} reuses another fresh role");
id
}
fn element(&mut self, kind: Kind, layer: Layer, name: &str) -> Id {
self.fresh(
self.actual
.elements
.values()
.filter(|e| e.kind() == kind && e.layer() == layer && e.name == name)
.map(|e| e.id)
.collect(),
name,
)
}
fn view(&mut self, machine: Id) -> Id {
self.fresh(
self.actual
.diagrams
.values()
.filter(|d| {
d.layer == Layer::Sa
&& d.name == VIEW
&& d.projection == ProjectionKind::StateMachine { machine }
})
.map(|d| d.id)
.collect(),
VIEW,
)
}
fn node(&mut self, diagram: Id, machine: Id) -> Id {
self.fresh(
self.actual.diagrams[&diagram]
.nodes
.values()
.filter(|node| node.element == machine)
.map(|node| node.id)
.collect(),
"new machine's exact view placement",
)
}
}
fn element(p: &Project, id: Id, name: &str, parent: Option<Id>, body: ElementBody) -> Element {
Element {
id,
alias: p.fresh_alias(name, "behavior", id),
name: name.into(),
description: String::new(),
parent,
body,
}
}
fn advance(base: &mut CompiledSourceProject, commands: Vec<Command>) {
let project = execute_batch(&base.decoded.project, &[Command::Batch(commands)]).unwrap();
*base = update_bundle(base, &project, ProjectLimits::default()).unwrap();
}
fn predict(base: &CompiledSourceProject, stage: Stage, carrier: &Project) -> CompiledSourceProject {
let mut result = base.clone();
let mut roles = Roles {
actual: carrier,
baseline: &base.decoded.project,
used: BTreeSet::new(),
};
if stage >= Stage::Process {
let id = roles.element(Kind::Process, Layer::Oa, PROCESS);
let record = element(
&result.decoded.project,
id,
PROCESS,
None,
ElementBody::Oa(OaBody::Process { steps: vec![] }),
);
advance(&mut result, vec![Command::CreateElement(record)]);
}
if stage >= Stage::Scenario {
let id = roles.element(Kind::Scenario, Layer::Oa, SCENARIO);
let record = element(
&result.decoded.project,
id,
SCENARIO,
None,
ElementBody::shared_in(
Layer::Oa,
SharedBody::Scenario {
viewpoint: ScenarioViewpoint::ParticipantInteraction,
context: Some(Id::from_u128(CAPABILITY)),
precondition: String::new(),
postcondition: String::new(),
steps: vec![],
},
),
);
advance(&mut result, vec![Command::CreateElement(record)]);
}
if stage == Stage::Machine {
let machine = roles.element(Kind::StateMachine, Layer::Sa, MACHINE);
let diagram = roles.view(machine);
let placement = roles.node(diagram, machine);
let record = element(
&result.decoded.project,
machine,
MACHINE,
Some(Id::from_u128(OWNER)),
ElementBody::shared_in(Layer::Sa, SharedBody::StateMachine),
);
let p = execute_batch(
&result.decoded.project,
&[Command::CreateElement(record.clone())],
)
.unwrap();
// Published first-view contract, independently constructed: one root,
// default options, no routes/regions/states. Shared core Layout owns the
// final geometry; no observed geometry or desktop planner is consulted.
let view = Diagram {
id: diagram,
alias: p.fresh_alias(VIEW, "state_view", diagram),
name: VIEW.into(),
description: String::new(),
layer: Layer::Sa,
projection: ProjectionKind::StateMachine { machine },
routes: vec![],
view_options: Default::default(),
nodes: BTreeMap::from([(
placement,
NodePlacement {
id: placement,
alias: p.fresh_alias(&format!("{MACHINE} placement"), "placement", placement),
element: machine,
position: Position { x: 60., y: 60. },
size: Size {
width: 336.,
height: 104.,
},
collapsed: false,
port_anchors: vec![],
},
)]),
};
advance(
&mut result,
vec![
Command::CreateElement(record),
Command::CreateDiagram(view),
Command::Layout(diagram),
],
);
}
let p = &result.decoded.project;
assert_eq!(
p.elements.len(),
base.decoded.project.elements.len() + stage.additions()
);
assert_eq!(
p.diagrams.len(),
base.decoded.project.diagrams.len() + usize::from(stage == Stage::Machine)
);
assert_eq!(p.relations, base.decoded.project.relations);
assert_eq!(p.traces, base.decoded.project.traces);
result
}
fn equal(left: &CompiledSourceProject, right: &CompiledSourceProject) -> bool {
left.decoded.project == right.decoded.project && left.bundle == right.bundle
}
fn assert_equal(expected: &CompiledSourceProject, actual: &CompiledSourceProject) {
assert_eq!(
actual.decoded.project, expected.decoded.project,
"Complete Project differs from independent prediction"
);
assert_eq!(
actual.bundle, expected.bundle,
"Complete SourceBundle differs, including comments and all included bytes"
);
}
fn test_id(n: u128) -> Id {
Id::from_u128(0xc4ea7100000040008000000000000000 + n)
}
fn false_carrier(base: &Project) -> Project {
let mut p = base.clone();
for (n, kind, layer, name) in [
(1, Kind::Process, Layer::Oa, PROCESS),
(2, Kind::Scenario, Layer::Oa, SCENARIO),
(3, Kind::StateMachine, Layer::Sa, MACHINE),
] {
p.elements.insert(
test_id(n),
Element {
id: test_id(n),
alias: format!("false_alias_{n}"),
name: name.into(),
description: "Must never be copied".into(),
parent: None,
body: ElementBody::new(kind, layer).unwrap(),
},
);
}
p.diagrams.insert(
test_id(4),
Diagram {
id: test_id(4),
alias: "false_view_alias".into(),
name: VIEW.into(),
description: "False view description".into(),
layer: Layer::Sa,
projection: ProjectionKind::StateMachine {
machine: test_id(3),
},
routes: vec![],
view_options: Default::default(),
nodes: BTreeMap::from([(
test_id(5),
NodePlacement {
id: test_id(5),
alias: "false_node_alias".into(),
element: test_id(3),
position: Position {
x: 9999.,
y: -9999.,
},
size: Size {
width: 1.,
height: 1.,
},
collapsed: true,
port_anchors: vec![],
},
)]),
},
);
p
}
fn self_check(base: &CompiledSourceProject) {
let original = base.clone();
let carrier = false_carrier(&base.decoded.project);
assert_equal(base, &predict(base, Stage::Baseline, &carrier));
for stage in [Stage::Process, Stage::Scenario, Stage::Machine] {
let expected = predict(base, stage, &carrier);
assert_equal(&expected, &predict(base, stage, &expected.decoded.project));
let parsed = compile_bundle(&expected.bundle, ProjectLimits::default()).unwrap();
assert_equal(&expected, &parsed);
let mut altered = expected.clone();
altered
.decoded
.project
.elements
.get_mut(&test_id(1))
.unwrap()
.description = "Unrequested metadata".into();
assert!(!equal(&expected, &altered));
let mut altered = expected.clone();
altered
.decoded
.project
.elements
.get_mut(&Id::from_u128(CAPABILITY))
.unwrap()
.name = "Changed unrelated baseline".into();
assert!(!equal(&expected, &altered));
let mut changed_source = expected.bundle.clone();
changed_source
.files
.get_mut("rationale.arcadia")
.unwrap()
.push_str("// Extra comment\n");
let altered = compile_bundle(&changed_source, ProjectLimits::default()).unwrap();
assert_eq!(altered.decoded.project, expected.decoded.project);
assert!(
!equal(&expected, &altered),
"Identical semantics do not excuse changed source bytes"
);
if stage >= Stage::Scenario {
let mut altered = expected.clone();
*altered
.decoded
.project
.elements
.get_mut(&test_id(2))
.unwrap()
.shared_mut()
.unwrap() = SharedBody::Scenario {
viewpoint: ScenarioViewpoint::OperationalActivity,
context: None,
precondition: String::new(),
postcondition: String::new(),
steps: vec![],
};
assert!(!equal(&expected, &altered));
}
if stage == Stage::Machine {
assert_ne!(
expected.decoded.project, carrier,
"Never adopt role-carrier metadata/geometry"
);
assert_eq!(
expected.decoded.project.elements[&test_id(3)].parent,
Some(Id::from_u128(OWNER))
);
let view = &expected.decoded.project.diagrams[&test_id(4)];
assert_eq!(view.nodes.len(), 1);
let node = &view.nodes[&test_id(5)];
println!(
"PREDICT first view: {VIEW}; machine-root position {:?}, size {:?}; {} exact source files",
node.position,
node.size,
expected.bundle.files.len()
);
let mut altered = expected.clone();
altered
.decoded
.project
.diagrams
.get_mut(&test_id(4))
.unwrap()
.nodes
.get_mut(&test_id(5))
.unwrap()
.position
.x += 1.;
assert!(!equal(&expected, &altered));
let mut altered = expected.clone();
let extra = element(
&altered.decoded.project,
test_id(6),
"Unrequested region",
Some(test_id(3)),
ElementBody::shared_in(Layer::Sa, SharedBody::Region),
);
altered.decoded.project.elements.insert(extra.id, extra);
assert!(!equal(&expected, &altered), "Reject extra semantic objects");
let mut altered = expected.clone();
altered
.bundle
.files
.insert("unrequested.arcadia".into(), "// Extra file\n".into());
assert!(!equal(&expected, &altered));
}
println!(
"PASS self-check {stage:?}: full source fixed point; false metadata, unrelated edits and source-only drift rejected"
);
}
let mut altered_base = base.clone();
altered_base
.bundle
.files
.get_mut("rationale.arcadia")
.unwrap()
.push(' ');
assert!(
!pinned_baseline(&altered_base),
"Reject an altered baseline before use"
);
assert_equal(&original, base);
let before = predict(base, Stage::Scenario, &carrier);
let created = predict(base, Stage::Machine, &carrier);
let origin = predicted_disk(&created.bundle, None);
let detached: Vec<_> = created
.bundle
.files
.keys()
.filter(|path| !before.bundle.files.contains_key(*path))
.cloned()
.collect();
assert_eq!(
detached.len(),
1,
"A machine creation adds one source module"
);
// Independently simulate the saver's observable result: restored reachable
// bytes plus the one new module left on disk by the prior creation.
let mut retained = predicted_disk(&before.bundle, None);
retained.insert(
detached[0].clone(),
created.bundle.files[&detached[0]].as_bytes().to_vec(),
);
assert_eq!(
retained[&detached[0]], origin[&detached[0]],
"Retained bytes must come from the exact created checkpoint"
);
assert_ne!(
retained,
predicted_disk(&before.bundle, None),
"Ordinary comparison must not accept detached history files"
);
assert_eq!(
retained,
predicted_disk(&before.bundle, Some(&origin)),
"Explicit Undo origin permits only the expected retained bytes"
);
let mut unknown = retained.clone();
unknown.insert("unknown.arcadia".into(), b"// Unclaimed file\n".to_vec());
assert_ne!(
unknown,
predicted_disk(&before.bundle, Some(&origin)),
"Reject unknown detached files"
);
let mut changed = retained.clone();
changed.get_mut(&detached[0]).unwrap().push(b' ');
assert_ne!(
changed,
predicted_disk(&before.bundle, Some(&origin)),
"Reject changed detached bytes"
);
let mut missing = retained.clone();
missing.remove(&detached[0]);
assert_ne!(
missing,
predicted_disk(&before.bundle, Some(&origin)),
"The retained file set is exact, not optional"
);
let mut reachable_drift = retained.clone();
reachable_drift
.get_mut("rationale.arcadia")
.unwrap()
.push(b' ');
assert_ne!(
reachable_drift,
predicted_disk(&before.bundle, Some(&origin)),
"An Undo exemption cannot hide reachable-source changes"
);
println!(
"PASS explicit Undo disk contract: known detached retention accepted; unknown, changed, missing and reachable drift rejected"
);
println!("PASS baseline retained unchanged; no native acceptance claimed");
}
fn main() {
assert_eq!(SCHEMA_VERSION, 7);
let args: Vec<_> = std::env::args().collect();
match args.get(1).map(String::as_str) {
Some("self-check") => {
assert_eq!(args.len(), 3, "self-check BASELINE_ENTRY");
self_check(&baseline(Path::new(&args[2])));
}
Some("check") => {
assert_eq!(
args.len(),
6,
"check baseline|process|scenario|machine BASELINE_ENTRY ACTUAL_ENTRY ROLE_ENTRY"
);
let stage = Stage::parse(&args[2]);
let base = baseline(Path::new(&args[3]));
let actual = load(Path::new(&args[4]));
let carrier = load(Path::new(&args[5]));
let expected = predict(&base, stage, &carrier.decoded.project);
assert_equal(&expected, &actual);
println!(
"PASS {stage:?}: complete Project + {} exact source files; only fresh literal-role UUIDs borrowed",
actual.bundle.files.len()
);
}
Some("same") => {
assert!(
matches!(args.len(), 4 | 5),
"same EXPECTED_CHECKPOINT ACTUAL_CHECKPOINT [UNDO_FROM_CHECKPOINT]"
);
let expected = load(Path::new(&args[2]));
let (actual, disk) = load_checkpoint(Path::new(&args[3]));
assert_equal(&expected, &actual);
let origin = args.get(4).map(|entry| {
// The first committed checkpoint is itself exact. This keeps
// arbitrary pre-existing detached files out of the exception.
let committed = load(Path::new(entry));
predicted_disk(&committed.bundle, None)
});
assert_eq!(
disk,
predicted_disk(&expected.bundle, origin.as_ref()),
"Disk source files differ from the exact checkpoint plus explicitly proven retained Undo files"
);
println!(
"PASS exact checkpoint identity/model/{}-file SourceBundle equality; {} exact disk files ({} known retained)",
actual.bundle.files.len(),
disk.len(),
disk.len() - actual.bundle.files.len()
);
}
_ => panic!(
"self-check BASE | check STAGE BASE ACTUAL ROLES | same EXPECTED ACTUAL [UNDO_FROM]"
),
}
}