Files
ARCADIA-Studio/harness/experiments/navigation-native-preparation-e124029-20260913/evidence/.local/navigation-palette-native-oracle.rs
T

679 lines
24 KiB
Rust

//! Current-schema core-only native deletion/alias oracle. No desktop code or actual-derived expectation.
//! renamed BASE_ENTRY ACTUAL_ENTRY TARGET_UUID NEW_ALIAS | removed BASE_ENTRY ACTUAL_ENTRY TARGET_UUID
//! same BASE_ENTRY ACTUAL_ENTRY | self-check | generate NEW_DIR
use oa_core::{source_project::*, *};
use std::{collections::BTreeMap, fs, path::Path};
fn compile_exact(raw: &SourceBundle) -> CompiledSourceProject {
let result = compile_bundle(raw, ProjectLimits::default()).expect("source admission");
assert_eq!(
&result.bundle, raw,
"source migration/normalization is not permitted"
);
assert_eq!(
SCHEMA_VERSION, 7,
"this oracle is admitted only for current schema 7 core"
);
assert_eq!(
result.decoded.project.schema_version, 7,
"schema 7 required"
);
validate_candidate(&result.decoded.project).expect("model admission");
result
}
fn load(entry: &Path) -> CompiledSourceProject {
try_load(entry).unwrap_or_else(|error| panic!("{}: {error}", entry.display()))
}
fn try_load(entry: &Path) -> Result<CompiledSourceProject, String> {
let disk = source_files::load_project(entry, ProjectLimits::default())
.map_err(|error| format!("load source project: {error}"))?;
let errors: Vec<_> = disk
.diagnostics
.iter()
.filter(|issue| issue.diagnostic.severity == validation::Severity::Error)
.collect();
if !errors.is_empty() {
return Err(format!("source/discovery errors: {errors:?}"));
}
for issue in &disk.diagnostics {
eprintln!(
"Permitted non-error diagnostic in {}: {:?}",
entry.display(),
issue
);
}
let raw = disk.reachable_bundle();
if disk.bundle != raw {
return Err("detached/invalid discovered buffers are not admitted".into());
}
let compiled = compile_bundle(&raw, ProjectLimits::default())
.map_err(|issues| format!("source admission: {issues:?}"))?;
if compiled.bundle != raw {
return Err("source migration/normalization is not permitted".into());
}
if SCHEMA_VERSION != 7 || compiled.decoded.project.schema_version != 7 {
return Err("this oracle requires current schema 7 core and source".into());
}
validate_candidate(&compiled.decoded.project)
.map_err(|error| format!("model admission: {error}"))?;
Ok(compiled)
}
fn removed(base: &CompiledSourceProject, target: Id) -> CompiledSourceProject {
assert!(
base.decoded.project.contains(target),
"target absent from baseline"
);
let candidate = prepare_command(&base.decoded.project, &Command::Delete(target))
.expect("baseline Delete must be admissible");
assert!(
!candidate.project.contains(target),
"Delete must remove requested identity"
);
assert_ne!(
candidate.project, base.decoded.project,
"Delete must change model"
);
let result = update_bundle_with_identity_map(
base,
&candidate.project,
&candidate.identity_map,
ProjectLimits::default(),
)
.expect("ordinary source patch must be admissible");
assert_eq!(
result.decoded.project, candidate.project,
"source must exactly represent candidate"
);
assert_eq!(
result.bundle.files.keys().collect::<Vec<_>>(),
base.bundle.files.keys().collect::<Vec<_>>(),
"Delete must retain source files, including newly empty files"
);
result
}
// Independent model expectation: alter only the selected alias field. The public
// command must agree with it before the source updater receives the candidate.
fn assign_alias_only(project: &mut Project, target: Id, alias: &str) {
if project.id == target {
project.alias = alias.into();
} else if let Some(record) = project.elements.get_mut(&target) {
record.alias = alias.into();
} else if let Some(record) = project.relations.get_mut(&target) {
record.alias = alias.into();
} else if let Some(record) = project.diagrams.get_mut(&target) {
record.alias = alias.into();
} else if let Some(record) = project.artifact_links.get_mut(&target) {
record.alias = alias.into();
} else if let Some(record) = project.traces.get_mut(&target) {
record.alias = alias.into();
} else {
project
.diagrams
.values_mut()
.find_map(|view| view.nodes.get_mut(&target))
.expect("fixed alias target absent from baseline")
.alias = alias.into();
}
}
fn renamed(base: &CompiledSourceProject, target: Id, alias: &str) -> CompiledSourceProject {
assert_eq!(
SCHEMA_VERSION, 7,
"this oracle requires current schema 7 core"
);
assert_eq!(base.decoded.project.schema_version, 7);
let old_alias = base
.decoded
.project
.identities()
.into_iter()
.find_map(|(identity, old)| (identity == target).then(|| old.to_owned()))
.expect("fixed alias target absent from baseline");
assert_ne!(
old_alias, alias,
"rename mode requires an actual alias change"
);
let mut expected_project = base.decoded.project.clone();
assign_alias_only(&mut expected_project, target, alias);
let candidate = prepare_command(
&base.decoded.project,
&Command::SetAlias(target, alias.into()),
)
.expect("baseline alias rename must be admissible");
assert_eq!(
candidate.project, expected_project,
"only requested alias may change"
);
let identities: BTreeMap<_, _> = base
.decoded
.project
.identities()
.into_iter()
.map(|(identity, _)| (identity, identity))
.collect();
assert_eq!(
candidate.identity_map, identities,
"all UUIDs must remain unchanged"
);
let result = update_bundle_with_identity_map(
base,
&candidate.project,
&candidate.identity_map,
ProjectLimits::default(),
)
.expect("ordinary alias source patch must be admissible");
assert_eq!(
result.decoded.project, expected_project,
"complete alias-only expected model"
);
assert_eq!(
result.bundle.entry, base.bundle.entry,
"entry name must remain unchanged"
);
assert!(
result.bundle.files.keys().eq(base.bundle.files.keys()),
"file membership must remain unchanged"
);
assert_eq!(
result.index.lexical_owners, base.index.lexical_owners,
"lexical ownership must remain unchanged"
);
assert!(
base.index
.declarations
.iter()
.map(|(id, loc)| (id, &loc.path))
.eq(result
.index
.declarations
.iter()
.map(|(id, loc)| (id, &loc.path))),
"declaration file ownership must remain unchanged"
);
result
}
fn rename_fixture() -> CompiledSourceProject {
let raw = SourceBundle {
entry: "project.arcadia".into(),
files: BTreeMap::from([
(
"project.arcadia".into(),
format!(
"arcadia 7;\r\nproject rename_oracle \"Alias oracle\" id \"{}\" {{\r\n include \"target.arcadia\";\r\n include \"references.arcadia\";\r\n include \"notes.arcadia\";\r\n}}\r\n",
id(100)
),
),
(
"target.arcadia".into(),
format!(
"// Preserve rename_target comment 雨.\r\noa_activity rename_target \"Target engineering name\" id \"{}\" {{\r\n description \"Literal rename_target is not a reference.\";\r\n}}\r\noa_entity rename_team \"Team\" id \"{}\" {{}}\r\n",
id(101),
id(102)
),
),
(
"references.arcadia".into(),
format!(
"// Preserve @rename_target comment Ω.\r\nallocation rename_allocation \"Team performs target\" id \"{}\" {{\r\n source @rename_team; target @rename_target;\r\n}}\r\n",
id(103)
),
),
(
"notes.arcadia".into(),
"// Unrelated rename_target bytes 雨.\r\n\r\n".into(),
),
]),
};
compile_exact(&raw)
}
fn rename_self_check() {
let base = rename_fixture();
let expected = renamed(&base, id(101), "rename_target_union");
// This fixed fixture's independently authored source expectation does not
// call the command or updater and does not inspect any actual saved input.
let mut expected_text = base.bundle.clone();
for (path, before, after) in [
(
"target.arcadia",
"oa_activity rename_target ",
"oa_activity rename_target_union ",
),
(
"references.arcadia",
"target @rename_target;",
"target @rename_target_union;",
),
] {
let text = expected_text.files.get_mut(path).unwrap();
assert_eq!(text.matches(before).count(), 1, "exact fixed fixture token");
*text = text.replacen(before, after, 1);
}
assert_eq!(
expected.bundle, expected_text,
"only declaration/reference tokens change; comments, strings, CRLF and other files remain exact"
);
check(&expected, &compile_exact(&expected_text));
let mut independently_expected = base.decoded.project.clone();
independently_expected
.elements
.get_mut(&id(101))
.unwrap()
.alias = "rename_target_union".into();
assert_eq!(expected.decoded.project, independently_expected);
assert_eq!(
base.bundle.files["notes.arcadia"],
expected.bundle.files["notes.arcadia"]
);
assert_eq!(
base.bundle.files["project.arcadia"],
expected.bundle.files["project.arcadia"]
);
assert!(
!same(&expected, &base),
"rename must reject unchanged baseline"
);
let wrong = renamed(&base, id(101), "rename_target_wrong");
assert!(!same(&expected, &wrong), "rename must reject wrong alias");
let wrong_target = renamed(&base, id(102), "rename_team_union");
assert!(
!same(&expected, &wrong_target),
"rename must reject wrong target"
);
let mut partial = expected.bundle.clone();
let references = partial.files.get_mut("references.arcadia").unwrap();
*references = references.replacen("target @rename_target_union;", "target @rename_target;", 1);
assert!(
compile_bundle(&partial, ProjectLimits::default()).is_err(),
"a stale partial reference must fail source admission before equality"
);
let mut unrelated = expected.bundle.clone();
unrelated
.files
.get_mut("notes.arcadia")
.unwrap()
.push_str("// unrelated alteration\r\n");
let altered = compile_exact(&unrelated);
assert_eq!(altered.decoded.project, expected.decoded.project);
assert!(
!same(&expected, &altered),
"same model cannot hide altered unrelated file"
);
println!(
"PASS alias self-check: exact token expectation, full alias-only model/UUIDs, comments/strings/CRLF/other files, no-op/wrong alias/wrong target/partial reference/unrelated-file refusals"
);
}
fn same(expected: &CompiledSourceProject, actual: &CompiledSourceProject) -> bool {
expected.decoded.project == actual.decoded.project && expected.bundle == actual.bundle
}
fn check(expected: &CompiledSourceProject, actual: &CompiledSourceProject) {
assert_eq!(
actual.decoded.project, expected.decoded.project,
"complete Project differs"
);
assert_eq!(
actual.bundle, expected.bundle,
"complete SourceBundle differs (paths or exact UTF-8 bytes)"
);
}
fn id(n: u128) -> Id {
Id::from_u128(0xde1e7e00000040008000000000000000 + n)
}
fn fixture() -> CompiledSourceProject {
let mut p = Project::empty();
p.id = id(1);
p.alias = "delete_oracle".into();
p.name = "Delete oracle".into();
for (n, kind, name, parent) in [
(10, Kind::Activity, "Target work", None),
(11, Kind::Activity, "Untouched work", None),
(20, Kind::Scenario, "Reference scenario", None),
(21, Kind::Lifeline, "Target reference", Some(id(20))),
] {
let mut e = p.make_element(kind, Layer::Oa, name, parent).unwrap();
e.id = id(n);
e.alias = format!("delete_{n}");
p.elements.insert(e.id, e);
}
*p.elements.get_mut(&id(21)).unwrap().shared_mut().unwrap() = SharedBody::Lifeline {
represented: Some(id(10)),
};
for (view, placement) in [(30, 31), (40, 41)] {
let node = NodePlacement {
id: id(placement),
alias: format!("node_{placement}"),
element: id(10),
position: Position { x: 80., y: 80. },
size: Size {
width: 180.,
height: 90.,
},
collapsed: false,
port_anchors: vec![],
};
p.diagrams.insert(
id(view),
Diagram {
id: id(view),
alias: format!("view_{view}"),
name: format!("Work view {view}"),
description: String::new(),
layer: Layer::Oa,
projection: ProjectionKind::Allocation,
view_options: Default::default(),
nodes: BTreeMap::from([(node.id, node)]),
routes: vec![],
},
);
}
for (n, kind, layer, name, parent) in [
(12, Kind::Entity, Layer::Oa, "OA Dispatch team", None),
(
50,
Kind::Function,
Layer::Sa,
"SA Initialize controller",
None,
),
(
51,
Kind::StateMachine,
Layer::Sa,
"SA Controller modes",
None,
),
(52, Kind::Region, Layer::Sa, "SA Main region", Some(id(51))),
(53, Kind::State, Layer::Sa, "SA Ready", Some(id(52))),
] {
let mut e = p.make_element(kind, layer, name, parent).unwrap();
e.id = id(n);
e.alias = format!("delete_{n}");
p.elements.insert(e.id, e);
}
for (n, kind, name, source, target) in [
(
13,
RelationKind::Allocation,
"OA performs target work",
12,
10,
),
(54, RelationKind::StateAction, "SA Entry initialize", 53, 50),
] {
let generated = p.relate(kind, name, id(source), id(target));
let mut relation = p.relations.remove(&generated).unwrap();
relation.id = id(n);
relation.alias = format!("delete_{n}");
if let RelationBody::StateAction { phase, .. } = &mut relation.body {
*phase = StateActionKind::Entry;
}
p.relations.insert(relation.id, relation);
}
for (view, placement) in [(30, 32), (40, 42)] {
p.diagrams.get_mut(&id(view)).unwrap().nodes.insert(
id(placement),
NodePlacement {
id: id(placement),
alias: format!("node_{placement}"),
element: id(12),
position: Position { x: 40., y: 40. },
size: Size {
width: 380.,
height: 230.,
},
collapsed: false,
port_anchors: vec![],
},
);
}
let nodes = [
(61, 51, 40., 40., 620., 460.),
(62, 52, 60., 95., 580., 380.),
(63, 53, 100., 155., 320., 190.),
]
.into_iter()
.map(|(n, element, x, y, width, height)| {
(
id(n),
NodePlacement {
id: id(n),
alias: format!("node_{n}"),
element: id(element),
position: Position { x, y },
size: Size { width, height },
collapsed: false,
port_anchors: vec![],
},
)
})
.collect();
p.diagrams.insert(
id(60),
Diagram {
id: id(60),
alias: "sa_modes_view".into(),
name: "SA Controller modes view".into(),
description: String::new(),
layer: Layer::Sa,
projection: ProjectionKind::StateMachine { machine: id(51) },
view_options: Default::default(),
nodes,
routes: vec![],
},
);
validate_candidate(&p).unwrap();
let entry = language::format(&p).replacen("{\n", "{\n include \"notes.arcadia\";\n", 1);
let raw = SourceBundle {
entry: "project.arcadia".into(),
files: BTreeMap::from([
("project.arcadia".into(), entry),
(
"notes.arcadia".into(),
"// Preserve deletion evidence 雨.\r\n// Exact bytes matter.\r\n".into(),
),
]),
};
let compiled = compile_exact(&raw);
assert_eq!(compiled.decoded.project, p);
compiled
}
fn self_check() {
let base = fixture();
let expected = removed(&base, id(10));
check(&expected, &compile_exact(&expected.bundle));
assert!(!same(&expected, &base), "must reject no-op");
let wrong = removed(&base, id(11));
assert!(!same(&expected, &wrong), "must reject wrong deletion");
let placement = removed(&base, id(31));
assert!(placement.decoded.project.contains(id(10)));
assert!(placement.decoded.project.contains(id(41)));
assert!(
!same(&expected, &placement),
"placement removal is not semantic deletion"
);
assert!(!expected.decoded.project.contains(id(31)));
assert!(!expected.decoded.project.contains(id(41)));
assert!(
!expected.decoded.project.contains(id(13)),
"semantic deletion removes allocation"
);
assert!(
placement.decoded.project.contains(id(13)),
"placement removal retains allocation"
);
let entry_row = removed(&base, id(54));
assert!(
entry_row.decoded.project.contains(id(50)),
"Entry row removal retains function"
);
assert!(
entry_row.decoded.project.contains(id(53)),
"Entry row removal retains state"
);
assert!(
!same(&entry_row, &removed(&base, id(50))),
"row removal differs from function deletion"
);
assert!(
matches!(
expected.decoded.project.elements[&id(21)].shared(),
Some(SharedBody::Lifeline { represented: None })
),
"cross-reference must clear"
);
let extra = prepare_command(
&expected.decoded.project,
&Command::Rename(id(11), "Unrelated damage".into()),
)
.unwrap();
let unrelated = update_bundle(&expected, &extra.project, ProjectLimits::default()).unwrap();
assert!(
!same(&expected, &unrelated),
"must reject unrelated semantic change"
);
for text in [
"// Preserve deletion evidence 雨.\n// Exact bytes matter.\n",
"// Damaged\r\n",
] {
let mut raw = expected.bundle.clone();
raw.files.insert("notes.arcadia".into(), text.into());
let tampered = compile_exact(&raw);
assert_eq!(tampered.decoded.project, expected.decoded.project);
assert!(
!same(&expected, &tampered),
"must reject source-only changes"
);
}
let mut missing = expected.bundle.clone();
missing.files.remove("notes.arcadia");
assert!(compile_bundle(&missing, ProjectLimits::default()).is_err());
check(&base, &compile_exact(&base.bundle));
assert!(
!same(&base, &expected),
"restoration must reject deleted snapshot"
);
assert_eq!(
base.bundle.files["notes.arcadia"],
expected.bundle.files["notes.arcadia"]
);
disk_self_check(&base);
rename_self_check();
println!(
"PASS self-check: exact candidate/source, wrong target, no-op, unrelated changes, placement/model distinction, crossrefs, source-byte falsifiers, disk warning admission and missing-include/syntax rejection"
);
}
fn disk_self_check(base: &CompiledSourceProject) {
let nonce = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
let dir = std::env::temp_dir().join(format!(
"arcadia-delete-oracle-{}-{nonce}",
std::process::id()
));
fs::create_dir(&dir).expect("create unique owned disk self-check directory");
for (path, text) in &base.bundle.files {
fs::write(dir.join(path), text).unwrap();
}
let entry = dir.join(&base.bundle.entry);
let disk = source_files::load_project(&entry, ProjectLimits::default()).unwrap();
assert!(
disk.diagnostics
.iter()
.any(|issue| issue.diagnostic.severity == validation::Severity::Warning),
"fixture must exercise legitimate warning admission"
);
check(
base,
&try_load(&entry).expect("valid fixture with completeness warnings must load"),
);
fs::remove_file(dir.join("notes.arcadia")).unwrap();
assert!(
try_load(&entry).is_err(),
"missing include must fail disk admission"
);
fs::write(
dir.join("notes.arcadia"),
&base.bundle.files["notes.arcadia"],
)
.unwrap();
fs::write(&entry, "this is not valid Arcadia source").unwrap();
assert!(
try_load(&entry).is_err(),
"malformed source must fail disk admission"
);
// Remove only exact files created above; no recursive deletion or borrowed fixture mutation.
for path in base.bundle.files.keys() {
fs::remove_file(dir.join(path)).unwrap();
}
fs::remove_dir(&dir).unwrap();
}
fn generate(dir: &Path) {
let baseline = fixture();
fs::create_dir(dir).expect("output directory must not already exist; parent must exist");
for (path, text) in &baseline.bundle.files {
fs::write(dir.join(path), text).expect("write new fixture");
}
check(&baseline, &load(&dir.join(&baseline.bundle.entry)));
println!("PASS generated exact fixture {}", dir.display());
for (n, label) in [
(10, "OA target activity"),
(12, "OA entity"),
(13, "OA allocation"),
(30, "first architecture view"),
(31, "first activity placement"),
(32, "first entity placement"),
(40, "second architecture view"),
(41, "second activity placement"),
(42, "second entity placement"),
(50, "SA Entry function"),
(51, "SA machine"),
(52, "SA region"),
(53, "SA Ready state"),
(54, "SA Entry row relation"),
(60, "SA state view"),
(63, "SA Ready placement"),
] {
println!("{label}: {}", id(n));
}
}
fn main() {
let args: Vec<_> = std::env::args().collect();
match args.get(1).map(String::as_str) {
Some("self-check") if args.len() == 2 => self_check(),
Some("generate") if args.len() == 3 => generate(Path::new(&args[2])),
Some("same") if args.len() == 4 => {
let base = load(Path::new(&args[2]));
let actual = load(Path::new(&args[3]));
check(&base, &actual);
println!("PASS same: complete Project and exact SourceBundle restored");
}
Some("renamed") if args.len() == 6 => {
let base = load(Path::new(&args[2]));
let target: Id = args[4].parse().expect("TARGET_UUID must be a UUID");
// Complete expected model and source are fixed before actual is loaded.
let expected = renamed(&base, target, &args[5]);
let actual = load(Path::new(&args[3]));
check(&expected, &actual);
println!(
"PASS renamed {target} to {}: complete baseline-derived alias-only Project and exact SourceBundle",
args[5]
);
}
Some("removed") if args.len() == 5 => {
let base = load(Path::new(&args[2]));
let target: Id = args[4].parse().expect("TARGET_UUID must be a UUID");
// Expected is fully fixed before actual is loaded.
let expected = removed(&base, target);
let actual = load(Path::new(&args[3]));
check(&expected, &actual);
println!(
"PASS removed {target}: exact baseline-derived Delete candidate and normal source patch"
);
}
_ => panic!(
"usage: renamed BASE_ENTRY ACTUAL_ENTRY TARGET_UUID NEW_ALIAS | removed BASE_ENTRY ACTUAL_ENTRY TARGET_UUID | same BASE_ENTRY ACTUAL_ENTRY | self-check | generate NEW_DIR"
),
}
}