Record revised release requirements and native scenario oracle

This commit is contained in:
Codex
2026-09-10 11:44:35 -07:00
parent 4ecad78433
commit 8547b85825
6 changed files with 901 additions and 26 deletions
+672
View File
@@ -0,0 +1,672 @@
//! Independent B2/B3 native fixture; no desktop implementation is linked.
//! generate DIR | check CHECKPOINT ENTRY | same VERIFIED_ENTRY RESTORED_ENTRY | self-check
use oa_core::{source_project::*, *};
use std::{
collections::{BTreeMap, BTreeSet},
fs,
path::Path,
};
fn id(n: u128) -> Id {
Id::from_u128(0x5ceaa100000040008000000000000000 + n)
}
#[derive(Clone, Copy)]
struct Side {
layer: Layer,
word: &'static str,
base: u128,
}
const SIDES: [Side; 2] = [
Side {
layer: Layer::Oa,
word: "OA",
base: 100,
},
Side {
layer: Layer::Sa,
word: "SA",
base: 200,
},
];
impl Side {
fn id(self, n: u128) -> Id {
id(self.base + n)
}
fn name(self, text: &str) -> String {
format!("{} {text}", self.word)
}
}
fn seed(p: &mut Project, side: Side, n: u128, kind: Kind, text: &str, parent: Option<Id>) {
let mut element = p
.make_element(kind, side.layer, &side.name(text), parent)
.unwrap();
element.id = side.id(n);
element.alias = format!("scenario_{}_{}", side.word.to_lowercase(), n);
p.elements.insert(element.id, element);
}
fn seed_occurrence(
p: &mut Project,
side: Side,
n: u128,
text: &str,
parent: u128,
body: OccurrenceBody,
) {
seed(p, side, n, Kind::Occurrence, text, Some(side.id(parent)));
*p.elements
.get_mut(&side.id(n))
.unwrap()
.shared_mut()
.unwrap() = SharedBody::Occurrence {
body,
precondition: String::new(),
postcondition: String::new(),
};
}
fn action(side: Side, work: u128, line: u128) -> OccurrenceBody {
OccurrenceBody::Action {
action: Some(side.id(work)),
lifeline: Some(side.id(line)),
}
}
fn reuse(side: Side, target: u128, remote: [u128; 2], local: [u128; 2]) -> OccurrenceBody {
OccurrenceBody::ScenarioUse {
scenario: Some(side.id(target)),
bindings: remote
.into_iter()
.zip(local)
.map(|(referenced, local)| LifelineBinding {
referenced: side.id(referenced),
local: side.id(local),
})
.collect(),
}
}
fn fixture() -> Project {
let mut p = Project::empty();
p.id = id(1);
p.alias = "scenario_authoring".into();
p.name = "Scenario authoring contract".into();
p.description = "Native clicked-slot and caller-return contract.".into();
for side in SIDES {
let work = if side.layer == Layer::Oa {
Kind::Activity
} else {
Kind::Function
};
seed(&mut p, side, 10, work, "Inspect ticket", None);
seed(&mut p, side, 11, work, "Record result", None);
seed(&mut p, side, 20, Kind::StateMachine, "Ticket modes", None);
seed(
&mut p,
side,
21,
Kind::Region,
"Ticket region",
Some(side.id(20)),
);
seed(&mut p, side, 22, Kind::State, "Ready", Some(side.id(21)));
for (n, text) in [(30, "A caller"), (31, "B verification"), (32, "C detail")] {
seed(&mut p, side, n, Kind::Scenario, text, None);
}
for (n, owner, represented, text) in [
(40, 30, 10, "A inspector"),
(41, 30, 11, "A recorder"),
(42, 31, 10, "B inspector"),
(43, 31, 11, "B recorder"),
(44, 32, 10, "C inspector"),
(45, 32, 11, "C recorder"),
] {
seed(&mut p, side, n, Kind::Lifeline, text, Some(side.id(owner)));
*p.elements
.get_mut(&side.id(n))
.unwrap()
.shared_mut()
.unwrap() = SharedBody::Lifeline {
represented: Some(side.id(represented)),
};
}
seed_occurrence(&mut p, side, 50, "Root entry", 30, action(side, 10, 40));
seed_occurrence(
&mut p,
side,
51,
"Outer ALT",
30,
OccurrenceBody::Fragment {
operator: FragmentOperator::Alternative,
branches: vec![side.id(52), side.id(53)],
},
);
seed_occurrence(
&mut p,
side,
52,
"Outer chosen operand",
51,
OccurrenceBody::Branch {
guard: "ticket.present".into(),
occurrences: vec![side.id(54)],
},
);
seed_occurrence(
&mut p,
side,
53,
"Outer fallback operand",
51,
OccurrenceBody::Branch {
guard: "else".into(),
occurrences: vec![side.id(59)],
},
);
seed_occurrence(
&mut p,
side,
54,
"Inner ALT",
52,
OccurrenceBody::Fragment {
operator: FragmentOperator::Alternative,
branches: vec![side.id(55), side.id(56)],
},
);
seed_occurrence(
&mut p,
side,
55,
"Inner chosen operand",
54,
OccurrenceBody::Branch {
guard: "ticket.ready".into(),
occurrences: vec![side.id(57)],
},
);
seed_occurrence(
&mut p,
side,
56,
"Inner other operand",
54,
OccurrenceBody::Branch {
guard: "else".into(),
occurrences: vec![side.id(58)],
},
);
for (n, text, parent, line) in [
(57, "Inner anchor", 55, 40),
(58, "Inner other anchor", 56, 40),
(59, "Fallback anchor", 53, 41),
(62, "Root exit", 30, 41),
(63, "B entry", 31, 42),
(65, "B exit", 31, 43),
(66, "C entry", 32, 44),
] {
seed_occurrence(
&mut p,
side,
n,
text,
parent,
action(side, if line % 2 == 0 { 10 } else { 11 }, line),
);
}
seed_occurrence(
&mut p,
side,
60,
"First use of B",
30,
reuse(side, 31, [42, 43], [40, 41]),
);
seed_occurrence(
&mut p,
side,
61,
"Second use of B",
30,
reuse(side, 31, [42, 43], [40, 41]),
);
seed_occurrence(
&mut p,
side,
64,
"B use of C",
31,
reuse(side, 32, [44, 45], [42, 43]),
);
for (owner, steps) in [
(30, vec![50, 51, 60, 61, 62]),
(31, vec![63, 64, 65]),
(32, vec![66]),
] {
*p.elements
.get_mut(&side.id(owner))
.unwrap()
.steps_mut()
.unwrap() = steps.into_iter().map(|n| side.id(n)).collect();
}
}
execute_batch(&p, &[]).expect("deterministic fixture must satisfy core admission")
}
fn bundle(p: &Project) -> CompiledSourceProject {
let entry = language::format(p).replacen("{\n", "{\n include \"rationale.arcadia\";\n", 1);
let raw = SourceBundle {
entry: "project.arcadia".into(),
files: BTreeMap::from([
("project.arcadia".into(), entry),
("rationale.arcadia".into(), "// Retain caller/operand evidence: ticket 雨.\r\n// Navigation never edits this note.\r\n".into()),
]),
};
let compiled = compile_bundle(&raw, ProjectLimits::default()).unwrap();
assert_eq!(compiled.decoded.project, *p);
assert_eq!(compiled.bundle, raw);
compiled
}
fn load(entry: &Path) -> CompiledSourceProject {
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 or source normalization permitted"
);
execute_batch(&compiled.decoded.project, &[]).unwrap();
compiled
}
fn advance(base: &mut CompiledSourceProject, commands: Vec<Command>) {
let expected = execute_batch(&base.decoded.project, &[Command::Batch(commands)]).unwrap();
*base = update_bundle(base, &expected, ProjectLimits::default()).unwrap();
}
struct Roles<'a> {
actual: &'a Project,
baseline: Project,
used: BTreeSet<Id>,
}
impl Roles<'_> {
fn occurrence(&mut self, side: Side, text: &str) -> Id {
let name = side.name(text);
let found: Vec<_> = self
.actual
.elements
.values()
.filter(|e| e.kind() == Kind::Occurrence && e.layer() == side.layer && e.name == name)
.map(|e| e.id)
.collect();
assert_eq!(
found.len(),
1,
"Exactly one fresh occurrence for role {name}"
);
let id = found[0];
assert_eq!(
id.get_version_num(),
4,
"Native occurrence needs UUIDv4: {name}"
);
assert!(!self.baseline.contains(id), "Role reused a seed: {name}");
assert!(
self.used.insert(id),
"Role identities must be distinct: {name}"
);
id
}
}
fn authored(
p: &Project,
side: Side,
id: Id,
text: &str,
parent: Id,
body: OccurrenceBody,
) -> Element {
let name = side.name(text);
Element {
id,
alias: p.fresh_alias(&name, "element", id),
name,
description: String::new(),
parent: Some(parent),
body: ElementBody::shared_in(
side.layer,
SharedBody::Occurrence {
body,
precondition: String::new(),
postcondition: String::new(),
},
),
}
}
fn insert_before(base: &mut CompiledSourceProject, parent: Id, anchor: Id, elements: Vec<Element>) {
let mut steps = base.decoded.project.elements[&parent]
.steps()
.unwrap()
.clone();
let position = steps
.iter()
.position(|id| *id == anchor)
.expect("declared insertion anchor");
let inserted: Vec<_> = elements
.iter()
.filter(|e| e.parent == Some(parent))
.map(|e| e.id)
.collect();
steps.splice(position..position, inserted);
let mut commands: Vec<_> = elements.into_iter().map(Command::CreateElement).collect();
commands.push(Command::SetSteps(parent, steps));
advance(base, commands);
}
fn checkpoint(mode: &str) -> Option<(Side, usize)> {
if mode == "baseline" {
return None;
}
let (prefix, stage) = mode
.split_once('-')
.expect("checkpoint is baseline or oa/sa-stage");
let side = match prefix {
"oa" => SIDES[0],
"sa" => SIDES[1],
_ => panic!("Unknown layer"),
};
let count = match stage {
"action" => 1,
"state" => 2,
"reuse" => 3,
"fragment" => 4,
_ => panic!("Unknown checkpoint"),
};
Some((side, count))
}
fn expected(mode: &str, actual: &Project) -> CompiledSourceProject {
let baseline = fixture();
let mut base = bundle(&baseline);
let Some((side, count)) = checkpoint(mode) else {
return base;
};
let mut roles = Roles {
actual,
baseline,
used: BTreeSet::new(),
};
let key = roles.occurrence(side, "native action");
let e = authored(
&base.decoded.project,
side,
key,
"native action",
side.id(30),
action(side, 10, 40),
);
insert_before(&mut base, side.id(30), side.id(50), vec![e]);
if count == 1 {
return base;
}
let key = roles.occurrence(side, "native state");
let e = authored(
&base.decoded.project,
side,
key,
"native state",
side.id(55),
OccurrenceBody::State {
state: Some(side.id(22)),
lifeline: Some(side.id(40)),
},
);
insert_before(&mut base, side.id(55), side.id(57), vec![e]);
if count == 2 {
return base;
}
let key = roles.occurrence(side, "native reuse");
let e = authored(
&base.decoded.project,
side,
key,
"native reuse",
side.id(55),
reuse(side, 31, [42, 43], [40, 41]),
);
insert_before(&mut base, side.id(55), side.id(57), vec![e]);
if count == 3 {
return base;
}
let fragment = roles.occurrence(side, "native alternative");
let branch1 = roles.occurrence(side, "native alternative · operand 1");
let branch2 = roles.occurrence(side, "native alternative · operand 2");
let p = &base.decoded.project;
let elements = vec![
authored(
p,
side,
fragment,
"native alternative",
side.id(30),
OccurrenceBody::Fragment {
operator: FragmentOperator::Alternative,
branches: vec![],
},
),
authored(
p,
side,
branch1,
"native alternative · operand 1",
fragment,
OccurrenceBody::Branch {
guard: "ticket.priority > 2".into(),
occurrences: vec![],
},
),
authored(
p,
side,
branch2,
"native alternative · operand 2",
fragment,
OccurrenceBody::Branch {
guard: "ticket.priority <= 2".into(),
occurrences: vec![],
},
),
];
insert_before(&mut base, side.id(30), side.id(62), elements);
base
}
fn same_snapshot(verified: &CompiledSourceProject, restored: &CompiledSourceProject) -> bool {
verified.decoded.project == restored.decoded.project && verified.bundle == restored.bundle
}
fn self_check() {
let baseline = fixture();
assert_eq!(
baseline,
fixture(),
"seed identities and fields must be deterministic"
);
let base = bundle(&baseline);
assert_eq!(expected("baseline", &baseline).bundle, base.bundle);
for side in SIDES {
// Role carrier intentionally has wrong parent, alias and occurrence body.
// Only its fresh IDs may survive in any prediction.
let mut carrier = baseline.clone();
for text in [
"native action",
"native state",
"native reuse",
"native alternative",
"native alternative · operand 1",
"native alternative · operand 2",
] {
let mut e = carrier
.make_element(Kind::Occurrence, side.layer, &side.name(text), None)
.unwrap();
e.alias = "wrong_carrier_alias".into();
e.description = "must never enter the prediction".into();
carrier.elements.insert(e.id, e);
}
for stage in ["action", "state", "reuse", "fragment"] {
let mode = format!("{}-{stage}", side.word.to_lowercase());
let correct = expected(&mode, &carrier);
assert_ne!(correct.decoded.project, carrier);
let again = expected(&mode, &correct.decoded.project);
assert_eq!(again.decoded.project, correct.decoded.project);
assert_eq!(
again.bundle, correct.bundle,
"full source checkpoint fixed point"
);
let mut wrong = correct.decoded.project.clone();
wrong.elements.get_mut(&side.id(10)).unwrap().description =
"unrequested seed edit".into();
assert_ne!(expected(&mode, &wrong).decoded.project, wrong);
let native = wrong
.elements
.values()
.find(|e| e.name == side.name("native action"))
.unwrap()
.id;
let mut wrong = correct.decoded.project.clone();
wrong.elements.get_mut(&native).unwrap().parent = Some(side.id(55));
assert_ne!(
expected(&mode, &wrong).decoded.project,
wrong,
"parent is predicted, not read back"
);
let mut wrong = correct.decoded.project.clone();
wrong
.elements
.get_mut(&side.id(30))
.unwrap()
.steps_mut()
.unwrap()
.swap(0, 1);
assert_ne!(
expected(&mode, &wrong).decoded.project,
wrong,
"clicked order is independently fixed"
);
}
let mode = format!("{}-fragment", side.word.to_lowercase());
let correct = expected(&mode, &carrier);
// Both semantic checks may legitimately discover fresh native IDs. An
// Undo/Redo check must additionally pin them to the earlier snapshot.
let mut other_carrier = carrier.clone();
let old = other_carrier
.elements
.values()
.find(|e| e.name == side.name("native action"))
.unwrap()
.id;
let mut replaced = other_carrier.elements.remove(&old).unwrap();
replaced.id = Id::new_v4();
other_carrier.elements.insert(replaced.id, replaced);
let recreated = expected(&mode, &other_carrier);
let correct_prediction = expected(&mode, &correct.decoded.project);
let recreated_prediction = expected(&mode, &recreated.decoded.project);
assert!(same_snapshot(&correct_prediction, &correct));
assert!(same_snapshot(&recreated_prediction, &recreated));
assert!(
!same_snapshot(&correct, &recreated),
"recreated native IDs pass semantic roles but must fail exact history restoration"
);
let mut wrong = correct.decoded.project.clone();
let e = wrong
.elements
.values_mut()
.find(|e| e.name == side.name("native reuse"))
.unwrap();
let Some(SharedBody::Occurrence {
body: OccurrenceBody::ScenarioUse { bindings, .. },
..
}) = e.shared_mut()
else {
unreachable!()
};
bindings[0].local = side.id(41);
assert_ne!(
expected(&mode, &wrong).decoded.project,
wrong,
"bindings are never copied from actual"
);
let mut changed_source = correct.bundle.clone();
changed_source
.files
.get_mut("rationale.arcadia")
.unwrap()
.push_str("// unrequested note\n");
let changed = compile_bundle(&changed_source, ProjectLimits::default()).unwrap();
assert_eq!(changed.decoded.project, correct.decoded.project);
assert_ne!(
changed.bundle,
expected(&mode, &changed.decoded.project).bundle
);
}
println!(
"PASS self-check: deterministic OA/SA baseline, eight semantic checkpoints, independent fields/source bytes and exact history identity discrimination"
);
}
fn main() {
assert_eq!(SCHEMA_VERSION, 7);
let args: Vec<_> = std::env::args().collect();
if args.get(1).is_some_and(|s| s == "self-check") {
assert_eq!(args.len(), 2);
self_check();
return;
}
if args.get(1).is_some_and(|s| s == "generate") {
assert_eq!(args.len(), 3);
let dir = Path::new(&args[2]);
assert!(
!dir.exists(),
"Generate only into a fresh directory; preserve existing evidence"
);
let p = fixture();
let base = bundle(&p);
fs::create_dir_all(dir).unwrap();
for (name, bytes) in base.bundle.files {
fs::write(dir.join(name), bytes).unwrap();
}
fs::write(
dir.join("expected-baseline.json"),
serde_json::to_vec_pretty(&p).unwrap(),
)
.unwrap();
println!(
"PASS generated deterministic OA/SA fixture: {} elements, 2 sources; native roles absent",
p.elements.len()
);
return;
}
if args.get(1).is_some_and(|s| s == "same") {
assert_eq!(args.len(), 4, "same VERIFIED_SAVED_ENTRY RESTORED_ENTRY");
let verified = load(Path::new(&args[2]));
let restored = load(Path::new(&args[3]));
assert!(
same_snapshot(&verified, &restored),
"Restored snapshot must preserve every Project identity/field and every SourceBundle byte"
);
println!(
"PASS same: exact saved/restored Project and SourceBundle, including all native identities"
);
return;
}
assert_eq!(
args.len(),
4,
"check baseline|oa-action|oa-state|oa-reuse|oa-fragment|sa-action|sa-state|sa-reuse|sa-fragment ENTRY"
);
assert_eq!(args[1], "check");
let actual = load(Path::new(&args[3]));
let prediction = expected(&args[2], &actual.decoded.project);
assert_eq!(
actual.decoded.project, prediction.decoded.project,
"Complete Project differs from independent checkpoint"
);
assert_eq!(
actual.bundle, prediction.bundle,
"Complete source bundle differs, including retained note bytes"
);
println!(
"PASS {}: whole model and {} exact reachable sources; only unique fresh role IDs borrowed",
args[2],
actual.bundle.files.len()
);
}