Files
ARCADIA-Studio/harness/experiments/library-compatibility-20260911/main.rs
T

2130 lines
79 KiB
Rust

//! Isolated finite-model experiment. Not Studio syntax or production admission.
use std::collections::{BTreeMap, BTreeSet};
use std::fs;
use std::path::{Path, PathBuf};
type Result<T> = std::result::Result<T, String>;
#[derive(Clone, Debug, PartialEq, Eq)]
struct Definition {
member: String,
class: String,
layer: String,
fields: Vec<String>,
refs: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Package {
identity: String,
version: String,
raw: String,
digest: String,
definitions: BTreeMap<String, Definition>,
description: String,
prototype: BTreeMap<String, Record>,
selected: BTreeSet<String>,
role_member: Option<String>,
}
impl Package {
fn parse(raw: String) -> Result<Self> {
let mut identity = None;
let mut version = None;
let mut definitions = BTreeMap::new();
let mut description = None;
let mut prototype = BTreeMap::new();
let mut selected = BTreeSet::new();
let mut role_member = None;
for line in raw.lines() {
let row: Vec<_> = line.split('|').collect();
match row.as_slice() {
["package", p, v] if identity.is_none() => {
identity = Some((*p).into());
version = Some((*v).into());
}
["description", text] if description.is_none() => {
description = Some((*text).into())
}
["def", member, class, layer, fields, refs] => {
let def = Definition {
member: (*member).into(),
class: (*class).into(),
layer: (*layer).into(),
fields: split(fields),
refs: split(refs),
};
if definitions.insert((*member).into(), def).is_some() {
return Err("duplicate member".into());
}
}
["prototype", member, ..] => {
let record = Record::parse(line.splitn(3, '|').nth(2).ok_or("bad prototype")?)?;
if record.id != *member || prototype.insert((*member).into(), record).is_some()
{
return Err("duplicate or mismatched prototype member".into());
}
}
["pattern", "monitor", members] if selected.is_empty() => {
selected = split(members).into_iter().collect()
}
["role", "sink", member, "Activity", "OA"] if role_member.is_none() => {
role_member = Some((*member).into())
}
["note", _] | ["analysis", "P", "K", "C"] => {}
_ => return Err(format!("unrecognized package row: {line}")),
}
}
let value = Self {
identity: identity.ok_or("missing package identity")?,
version: version.ok_or("missing version")?,
digest: sha256(raw.as_bytes()),
raw,
definitions,
description: description.ok_or("missing description")?,
prototype,
selected,
role_member,
};
for def in value.definitions.values() {
if !matches!(
def.class.as_str(),
"Kind" | "Unit" | "Scalar" | "Item" | "Field" | "Interface" | "Allocation"
) {
return Err("unsupported contract class".into());
}
if def.refs.iter().any(|r| !value.definitions.contains_key(r)) {
return Err("unresolved package reference".into());
}
}
if value
.selected
.iter()
.any(|member| !value.prototype.contains_key(member))
|| value
.role_member
.as_ref()
.is_some_and(|m| !value.prototype.contains_key(m) || value.selected.contains(m))
{
return Err("incomplete prototype/export/role".into());
}
Ok(value)
}
fn contract(&self, root: &str) -> Result<Vec<Definition>> {
let mut pending = vec![root.to_string()];
let mut seen = BTreeSet::new();
while let Some(id) = pending.pop() {
if seen.insert(id.clone()) {
pending.extend(
self.definitions
.get(&id)
.ok_or("missing contract root")?
.refs
.clone(),
);
}
}
Ok(seen.iter().map(|id| self.definitions[id].clone()).collect())
}
}
fn equivalent(a: &Package, am: &str, b: &Package, bm: &str) -> bool {
a.identity == b.identity
&& am == bm
&& a.contract(am)
.ok()
.zip(b.contract(bm).ok())
.is_some_and(|(a, b)| a == b)
}
#[derive(Clone, Debug)]
enum Policy {
Strict,
SameOrigin,
Bridges(BTreeSet<(String, String)>),
}
fn pair(a: &str, b: &str) -> (String, String) {
if a <= b {
(a.into(), b.into())
} else {
(b.into(), a.into())
}
}
fn policy_matches(a: &Package, am: &str, b: &Package, bm: &str, policy: &Policy) -> bool {
if a.identity == b.identity && a.digest == b.digest && am == bm {
return true;
}
match policy {
Policy::Strict => false,
Policy::SameOrigin => equivalent(a, am, b, bm),
Policy::Bridges(witnesses) => {
equivalent(a, am, b, bm)
&& witnesses.contains(&pair(
&format!("{}:{am}", a.digest),
&format!("{}:{bm}", b.digest),
))
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct DRef {
import: String,
member: String,
}
impl DRef {
fn new(import: &str, member: &str) -> Self {
Self {
import: import.into(),
member: member.into(),
}
}
fn text(&self) -> String {
format!("{}:{}", self.import, self.member)
}
fn parse(s: &str) -> Result<Self> {
let (i, m) = s.split_once(':').ok_or("bad definition reference")?;
Ok(Self::new(i, m))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Literal {
magnitude: i64,
unit: DRef,
}
impl Literal {
fn new(magnitude: i64, import: &str, unit: &str) -> Self {
Self {
magnitude,
unit: DRef::new(import, unit),
}
}
fn text(&self) -> String {
format!("{}@{}", self.magnitude, self.unit.text())
}
fn parse(s: &str) -> Result<Self> {
let (n, u) = s.split_once('@').ok_or("bad literal")?;
Ok(Self {
magnitude: n.parse().map_err(|_| "bad integer")?,
unit: DRef::parse(u)?,
})
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
enum Body {
Activity {
description: String,
},
Interaction {
source: String,
target: String,
item: String,
},
Property {
subject: String,
kind: DRef,
base: Literal,
},
Case {
subject: Option<String>,
overrides: BTreeMap<String, Literal>,
},
Check {
property: String,
limit: Literal,
},
Budget {
left: String,
right: String,
kind: DRef,
limit: Literal,
},
Consumer {
exchange: String,
interface: String,
allocation: String,
field: String,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Record {
id: String,
layer: String,
name: String,
body: Body,
}
impl Record {
fn line(&self) -> String {
let tail = match &self.body {
Body::Activity { description } => format!("Activity|{description}"),
Body::Interaction {
source,
target,
item,
} => format!("Interaction|{source}|{target}|{item}"),
Body::Property {
subject,
kind,
base,
} => format!("Property|{subject}|{}|{}", kind.text(), base.text()),
Body::Case { subject, overrides } => format!(
"Case|{}|{}",
subject.as_deref().unwrap_or("-"),
overrides
.iter()
.map(|(p, e)| format!("{p}={}", e.text()))
.collect::<Vec<_>>()
.join(",")
),
Body::Check { property, limit } => format!("Check|{property}|{}", limit.text()),
Body::Budget {
left,
right,
kind,
limit,
} => format!("Budget|{left}|{right}|{}|{}", kind.text(), limit.text()),
Body::Consumer {
exchange,
interface,
allocation,
field,
} => format!("Consumer|{exchange}|{interface}|{allocation}|{field}"),
};
format!("record|{}|{}|{}|{tail}", self.id, self.layer, self.name)
}
fn parse(line: &str) -> Result<Self> {
let r: Vec<_> = line.split('|').collect();
if r.len() < 5 || r[0] != "record" {
return Err("bad record".into());
}
let body = match &r[4..] {
["Activity", description] => Body::Activity {
description: (*description).into(),
},
["Interaction", source, target, item] => Body::Interaction {
source: (*source).into(),
target: (*target).into(),
item: (*item).into(),
},
["Property", subject, kind, value] => Body::Property {
subject: (*subject).into(),
kind: DRef::parse(kind)?,
base: Literal::parse(value)?,
},
["Case", subject, rows] => {
let mut overrides = BTreeMap::new();
for row in split(rows) {
let (id, value) = row.split_once('=').ok_or("bad override")?;
if overrides
.insert(id.into(), Literal::parse(value)?)
.is_some()
{
return Err("duplicate override".into());
}
}
Body::Case {
subject: (*subject != "-").then(|| (*subject).into()),
overrides,
}
}
["Check", property, limit] => Body::Check {
property: (*property).into(),
limit: Literal::parse(limit)?,
},
["Budget", left, right, kind, limit] => Body::Budget {
left: (*left).into(),
right: (*right).into(),
kind: DRef::parse(kind)?,
limit: Literal::parse(limit)?,
},
["Consumer", exchange, interface, allocation, field] => Body::Consumer {
exchange: (*exchange).into(),
interface: (*interface).into(),
allocation: (*allocation).into(),
field: (*field).into(),
},
_ => return Err("bad constructor".into()),
};
Ok(Self {
id: r[1].into(),
layer: r[2].into(),
name: r[3].into(),
body,
})
}
fn remap_live(&mut self, old: &str, new: &str) {
fn remap(id: &mut String, old: &str, new: &str) {
if id == old {
*id = new.into();
}
}
remap(&mut self.id, old, new);
match &mut self.body {
Body::Activity { .. } => {}
Body::Interaction {
source,
target,
item,
} => {
remap(source, old, new);
remap(target, old, new);
remap(item, old, new);
}
Body::Property { subject, .. } => remap(subject, old, new),
Body::Case { subject, overrides } => {
if let Some(subject) = subject {
remap(subject, old, new);
}
if let Some(v) = overrides.remove(old) {
overrides.insert(new.into(), v);
}
}
Body::Check { property, .. } => remap(property, old, new),
Body::Budget { left, right, .. } => {
remap(left, old, new);
remap(right, old, new);
}
Body::Consumer {
exchange,
interface,
allocation,
field,
} => {
remap(exchange, old, new);
remap(interface, old, new);
remap(allocation, old, new);
remap(field, old, new);
}
}
}
fn rebind_self_definitions(&mut self, import: &str) {
fn reference(r: &mut DRef, import: &str) {
if r.import == "SELF" {
r.import = import.into();
}
}
fn literal(l: &mut Literal, import: &str) {
reference(&mut l.unit, import);
}
match &mut self.body {
Body::Property { kind, base, .. } => {
reference(kind, import);
literal(base, import);
}
Body::Case { overrides, .. } => {
for value in overrides.values_mut() {
literal(value, import);
}
}
Body::Check { limit, .. } => literal(limit, import),
Body::Budget { kind, limit, .. } => {
reference(kind, import);
literal(limit, import);
}
Body::Activity { .. } | Body::Interaction { .. } | Body::Consumer { .. } => {}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Mount {
import: String,
members: BTreeMap<String, String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Instance {
import: String,
mount: String,
sink: String,
prefix: String,
original: BTreeMap<String, String>,
current: BTreeMap<String, Option<String>>,
lineage: BTreeMap<String, String>,
base: BTreeMap<String, Record>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Document {
identity: String,
revision: u32,
imports: BTreeMap<String, Package>,
mounts: BTreeMap<String, Mount>,
instances: BTreeMap<String, Instance>,
live: BTreeMap<String, Record>,
receipts: Vec<String>,
}
fn materialize(instance: &Instance, package: &Package, mount: &Mount) -> BTreeMap<String, Record> {
package
.selected
.iter()
.map(|member| {
let mut record = package.prototype[member].clone();
for (foreign, local) in &instance.original {
record.remap_live(foreign, local);
}
if let Some(role_member) = &package.role_member {
record.remap_live(role_member, &instance.sink);
}
for (foreign, local) in &mount.members {
record.remap_live(&format!("MOUNT/{foreign}"), local);
}
record.rebind_self_definitions(&instance.import);
record.name = format!("{} {}", instance.prefix, record.name);
(member.clone(), record)
})
.collect()
}
fn split(s: &str) -> Vec<String> {
if s.is_empty() || s == "-" {
vec![]
} else {
s.split(',').map(String::from).collect()
}
}
fn read(path: &Path) -> Result<String> {
fs::read_to_string(path).map_err(|e| format!("{}: {e}", path.display()))
}
fn write(path: &Path, text: &str) -> Result<()> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
}
fs::write(path, text).map_err(|e| e.to_string())
}
fn prepare_new(request: &str, packages: &BTreeMap<String, Package>) -> Result<Document> {
let mut doc = Document {
identity: String::new(),
revision: 1,
imports: BTreeMap::new(),
mounts: BTreeMap::new(),
instances: BTreeMap::new(),
live: BTreeMap::new(),
receipts: vec![],
};
for line in request.lines() {
let r: Vec<_> = line.split('|').collect();
match r.as_slice() {
["new", id] if doc.identity.is_empty() => doc.identity = (*id).into(),
["import", alias, package] => {
if doc
.imports
.insert(
(*alias).into(),
packages
.get(*package)
.ok_or("missing supplied package")?
.clone(),
)
.is_some()
{
return Err("duplicate import".into());
}
}
["mount", id, import] => {
let p = doc.imports.get(*import).ok_or("missing import")?;
let members = p
.definitions
.values()
.filter(|d| d.layer == "OA")
.map(|d| (d.member.clone(), format!("{id}/{}", d.member)))
.collect();
if doc
.mounts
.insert(
(*id).into(),
Mount {
import: (*import).into(),
members,
},
)
.is_some()
{
return Err("duplicate mount".into());
}
}
["activity", id, name] => {
doc.live.insert(
(*id).into(),
Record {
id: (*id).into(),
layer: "OA".into(),
name: (*name).into(),
body: Body::Activity {
description: String::new(),
},
},
);
}
["instantiate", id, import, mount, sink] => {
if !doc.live.contains_key(*sink) {
return Err("missing role binding".into());
}
let original: BTreeMap<String, String> = ["A", "E", "P", "C", "K"]
.into_iter()
.map(|m| (m.into(), format!("{id}/{m}")))
.collect();
let mut instance = Instance {
import: (*import).into(),
mount: (*mount).into(),
sink: (*sink).into(),
prefix: (*id).into(),
current: original
.iter()
.map(|(m, id)| (m.clone(), Some(id.clone())))
.collect(),
lineage: original
.values()
.map(|id| (id.clone(), id.clone()))
.collect(),
original,
base: BTreeMap::new(),
};
let mount = doc.mounts.get(*mount).ok_or("missing mount")?;
if mount.import != *import {
return Err("initial mount pin mismatch".into());
}
instance.base = materialize(
&instance,
doc.imports.get(*import).ok_or("missing import")?,
mount,
);
for r in instance.base.values() {
if doc.live.insert(r.id.clone(), r.clone()).is_some() {
return Err("identity collision".into());
}
}
if doc.instances.insert((*id).into(), instance).is_some() {
return Err("duplicate instance".into());
}
}
["budget", id, left, right, import] => {
doc.live.insert(
(*id).into(),
Record {
id: (*id).into(),
layer: "OA".into(),
name: "Combined duration".into(),
body: Body::Budget {
left: (*left).into(),
right: (*right).into(),
kind: DRef::new(import, "Duration"),
limit: Literal::new(2000, import, "ms"),
},
},
);
}
["consumer", id, exchange, mount] => {
let m = doc.mounts.get(*mount).ok_or("missing consumer mount")?;
doc.live.insert(
(*id).into(),
Record {
id: (*id).into(),
layer: "OA".into(),
name: "Outside typed receiver".into(),
body: Body::Consumer {
exchange: (*exchange).into(),
interface: m.members["Interface"].clone(),
allocation: m.members["Operation"].clone(),
field: m.members["Code"].clone(),
},
},
);
}
["global_case", id, property] => {
doc.live.insert(
(*id).into(),
Record {
id: (*id).into(),
layer: "OA".into(),
name: "Unrelated project-wide study".into(),
body: Body::Case {
subject: None,
overrides: BTreeMap::from([(
(*property).into(),
Literal::new(3000, "controls1", "ms"),
)]),
},
},
);
}
["receipt", id] => doc.receipts.push((*id).into()),
_ => return Err(format!("unsupported request row: {line}")),
}
}
admit(&doc)?;
Ok(doc)
}
fn admit(doc: &Document) -> Result<()> {
let mut identities: BTreeSet<String> = doc.live.keys().cloned().collect();
let mut labels = BTreeMap::new();
for (alias, p) in &doc.imports {
if sha256(p.raw.as_bytes()) != p.digest {
return Err(format!("wrong package bytes: {alias}"));
}
if Package::parse(p.raw.clone())? != *p {
return Err("forged parsed package".into());
}
if let Some(prior) =
labels.insert((p.identity.clone(), p.version.clone()), p.digest.clone())
&& prior != p.digest
{
return Err("same package/version has conflicting bytes".into());
}
}
for mount in doc.mounts.values() {
let p = doc
.imports
.get(&mount.import)
.ok_or("missing mount package")?;
let required: BTreeSet<_> = p
.definitions
.values()
.filter(|d| d.layer == "OA")
.map(|d| d.member.clone())
.collect();
if required != mount.members.keys().cloned().collect() {
return Err("mount not complete".into());
}
for id in mount.members.values() {
if !identities.insert(id.clone()) {
return Err("mount identity collision".into());
}
}
}
let mut tracked = BTreeSet::new();
for instance in doc.instances.values() {
let p = doc
.imports
.get(&instance.import)
.ok_or("missing base package")?;
let m = doc
.mounts
.get(&instance.mount)
.ok_or("missing base mount")?;
if m.import != instance.import {
return Err("base mount pin mismatch".into());
}
if instance.original.keys().cloned().collect::<BTreeSet<_>>()
!= BTreeSet::from(["A", "E", "P", "C", "K"].map(String::from))
{
return Err("incomplete original map".into());
}
if materialize(instance, p, m) != instance.base {
return Err("forged historical base".into());
}
if instance.current.keys().ne(instance.original.keys()) {
return Err("incomplete correspondence".into());
}
for (member, live) in &instance.current {
let original = &instance.original[member];
if let Some(id) = live {
if id != original && identities.contains(original) {
return Err("historical local identity was reused".into());
}
if !tracked.insert(id.clone()) || !doc.live.contains_key(id) {
return Err("bad current map".into());
}
if instance.lineage.get(original) != Some(id) {
return Err("missing typed lineage".into());
}
if std::mem::discriminant(&doc.live[id].body)
!= std::mem::discriminant(&instance.base[member].body)
{
return Err("record class changed".into());
}
} else if identities.contains(original) {
return Err("deleted identity was reused".into());
}
}
}
for r in doc.live.values() {
let required = match &r.body {
Body::Activity { .. } => vec![],
Body::Interaction {
source,
target,
item,
} => vec![source, target, item],
Body::Property {
subject,
kind,
base,
} => {
kind_compatible(doc, kind, &unit_kind(doc, &base.unit)?)?
.then_some(())
.ok_or("property unit kind mismatch")?;
vec![subject]
}
Body::Case { subject, overrides } => {
let mut ids: Vec<_> = overrides.keys().collect();
if let Some(s) = subject {
ids.push(s);
}
for (id, literal) in overrides {
let Body::Property { kind, .. } =
&doc.live.get(id).ok_or("missing override property")?.body
else {
return Err("wrong override kind".into());
};
if !kind_compatible(doc, kind, &unit_kind(doc, &literal.unit)?)? {
return Err("override unit kind mismatch".into());
}
}
ids
}
Body::Check { property, .. } => vec![property],
Body::Budget { left, right, .. } => vec![left, right],
Body::Consumer {
exchange,
interface,
allocation,
field,
} => vec![exchange, interface, allocation, field],
};
if required.iter().any(|id| !identities.contains(*id)) {
return Err(format!("dangling live reference in {}", r.id));
}
}
evaluate(doc, "budget")?;
consumer_match(doc, "outside")?;
Ok(())
}
fn kind_compatible(doc: &Document, a: &DRef, b: &DRef) -> Result<bool> {
let pa = doc.imports.get(&a.import).ok_or("missing kind import")?;
let pb = doc.imports.get(&b.import).ok_or("missing kind import")?;
Ok(pa
.definitions
.get(&a.member)
.is_some_and(|d| d.class == "Kind")
&& pb
.definitions
.get(&b.member)
.is_some_and(|d| d.class == "Kind")
&& equivalent(pa, &a.member, pb, &b.member))
}
fn unit_kind(doc: &Document, unit: &DRef) -> Result<DRef> {
let p = doc.imports.get(&unit.import).ok_or("missing unit import")?;
let d = p.definitions.get(&unit.member).ok_or("missing unit")?;
if d.class != "Unit" || d.refs.len() != 1 {
return Err("wrong unit kind".into());
}
Ok(DRef::new(&unit.import, &d.refs[0]))
}
fn millis(doc: &Document, literal: &Literal) -> Result<i64> {
let p = doc
.imports
.get(&literal.unit.import)
.ok_or("missing unit import")?;
let d = p
.definitions
.get(&literal.unit.member)
.ok_or("missing unit")?;
let scale = d
.fields
.first()
.ok_or("missing scale")?
.strip_prefix("millis=")
.ok_or("bad scale")?
.parse::<i64>()
.map_err(|_| "bad scale")?;
literal
.magnitude
.checked_mul(scale)
.ok_or("overflow".into())
}
fn evaluate(doc: &Document, id: &str) -> Result<(i64, bool)> {
evaluate_policy(doc, id, &Policy::SameOrigin)
}
fn evaluate_check(doc: &Document, check: &str, context: Option<&str>) -> Result<(i64, bool)> {
let Body::Check { property, limit } = &doc.live.get(check).ok_or("missing check")?.body else {
return Err("not check".into());
};
let Body::Property { kind, base, .. } = &doc.live.get(property).ok_or("missing property")?.body
else {
return Err("not property".into());
};
let effective = if let Some(context) = context {
let Body::Case { overrides, .. } = &doc.live.get(context).ok_or("missing case")?.body
else {
return Err("not case".into());
};
overrides.get(property).unwrap_or(base)
} else {
base
};
if !kind_compatible(doc, kind, &unit_kind(doc, &effective.unit)?)?
|| !kind_compatible(doc, kind, &unit_kind(doc, &limit.unit)?)?
{
return Err("check kind mismatch".into());
}
let value = millis(doc, effective)?;
Ok((value, value <= millis(doc, limit)?))
}
fn evaluate_policy(doc: &Document, id: &str, policy: &Policy) -> Result<(i64, bool)> {
let Body::Budget {
left,
right,
kind,
limit,
} = &doc.live.get(id).ok_or("missing budget")?.body
else {
return Err("not budget".into());
};
let mut total = 0i64;
for id in [left, right] {
let Body::Property {
kind: input_kind,
base,
..
} = &doc.live.get(id).ok_or("missing property")?.body
else {
return Err("not property".into());
};
let unit_kind = unit_kind(doc, &base.unit)?;
if !policy_matches(
&doc.imports[&kind.import],
&kind.member,
&doc.imports[&input_kind.import],
&input_kind.member,
policy,
) || !policy_matches(
&doc.imports[&input_kind.import],
&input_kind.member,
&doc.imports[&unit_kind.import],
&unit_kind.member,
policy,
) {
return Err("incompatible budget kind".into());
}
total += millis(doc, base)?;
}
Ok((total, total <= millis(doc, limit)?))
}
fn mounted<'a>(doc: &'a Document, id: &str) -> Result<(&'a Mount, String)> {
for mount in doc.mounts.values() {
for (member, local) in &mount.members {
if id == local {
return Ok((mount, member.clone()));
}
}
}
Err("not a mounted member".into())
}
fn consumer_match(doc: &Document, id: &str) -> Result<BTreeMap<String, String>> {
consumer_match_policy(doc, id, &Policy::SameOrigin)
}
fn consumer_match_policy(
doc: &Document,
id: &str,
policy: &Policy,
) -> Result<BTreeMap<String, String>> {
let Body::Consumer {
exchange,
interface,
allocation,
field,
} = &doc.live.get(id).ok_or("missing consumer")?.body
else {
return Err("not consumer".into());
};
let Body::Interaction { item, .. } = &doc.live.get(exchange).ok_or("missing exchange")?.body
else {
return Err("not exchange".into());
};
let (actual, member) = mounted(doc, item)?;
let (expected, expected_interface) = mounted(doc, interface)?;
if member != "Alarm" || expected_interface != "Interface" {
return Err("wrong contracted root".into());
}
let a = &doc.imports[&actual.import];
let e = &doc.imports[&expected.import];
if !policy_matches(a, "Interface", e, "Interface", policy) {
return Err("item/interface not compatible".into());
}
if expected.members.get("Operation") != Some(allocation)
|| expected.members.get("Code") != Some(field)
{
return Err("operation or field outside declared root".into());
}
Ok(expected
.members
.iter()
.map(|(member, local)| (local.clone(), actual.members[member].clone()))
.collect())
}
fn apply_edit(doc: &Document, request: &str) -> Result<Document> {
let r: Vec<_> = request.trim().split('|').collect();
let ["edit_base", id, literal] = r.as_slice() else {
return Err("bad edit request".into());
};
let mut candidate = doc.clone();
let Body::Property { base, .. } = &mut candidate
.live
.get_mut(*id)
.ok_or("missing edit target")?
.body
else {
return Err("not property".into());
};
*base = Literal::parse(literal)?;
candidate.revision += 1;
candidate.receipts.push(request.trim().into());
admit(&candidate)?;
Ok(candidate)
}
fn merge_value<T: PartialEq + Clone>(base: &T, local: &T, next: &T, keep_local: bool) -> Result<T> {
if local == base {
Ok(next.clone())
} else if next == base || local == next || keep_local {
Ok(local.clone())
} else {
Err("unresolved typed value conflict".into())
}
}
fn update(doc: &Document, request: &str, package: Package) -> Result<Document> {
let r: Vec<_> = request.trim().split('|').collect();
let [
"update",
id,
old_digest,
new_import,
new_mount,
expected_revision,
choice,
] = r.as_slice()
else {
return Err("bad update request".into());
};
if expected_revision
.parse::<u32>()
.map_err(|_| "bad revision")?
!= doc.revision
{
return Err("stale revision".into());
}
let old = doc.instances.get(*id).ok_or("missing instance")?;
if doc.imports[&old.import].digest != *old_digest {
return Err("stale base pin".into());
}
let mut candidate = doc.clone();
if candidate.imports.contains_key(*new_import) || candidate.mounts.contains_key(*new_mount) {
return Err("immutable import/mount collision".into());
}
let mount = Mount {
import: (*new_import).into(),
members: package
.definitions
.values()
.filter(|d| d.layer == "OA")
.map(|d| (d.member.clone(), format!("{new_mount}/{}", d.member)))
.collect(),
};
let mut next = old.clone();
next.import = (*new_import).into();
next.mount = (*new_mount).into();
next.original = old
.current
.iter()
.map(|(m, id)| {
id.clone()
.map(|id| (m.clone(), id))
.ok_or("deleted member needs explicit policy")
})
.collect::<std::result::Result<_, _>>()?;
next.base = materialize(&next, &package, &mount);
for (member, incoming) in &next.base {
let local_id = old.current[member]
.as_ref()
.ok_or("missing current member")?;
let mut baseline = old.base[member].clone();
for (original, current) in &old.lineage {
baseline.remap_live(original, current);
}
let local = &doc.live[local_id];
let value = if local == &baseline {
incoming.clone()
} else if incoming == &baseline || incoming == local {
local.clone()
} else if member == "P" && *choice == "P.base=keep_local" {
let (
Body::Property {
subject: bs,
kind: bk,
base: bb,
},
Body::Property {
subject: ls,
kind: lk,
base: lb,
},
Body::Property {
subject: ns,
kind: nk,
base: nb,
},
) = (&baseline.body, &local.body, &incoming.body)
else {
return Err("constructor mismatch".into());
};
Record {
id: merge_value(&baseline.id, &local.id, &incoming.id, false)?,
layer: merge_value(&baseline.layer, &local.layer, &incoming.layer, false)?,
name: merge_value(&baseline.name, &local.name, &incoming.name, false)?,
body: Body::Property {
subject: merge_value(bs, ls, ns, false)?,
kind: merge_value(bk, lk, nk, false)?,
base: merge_value(bb, lb, nb, true)?,
},
}
} else {
return Err(format!("unresolved typed facet conflict: {member}"));
};
candidate.live.insert(value.id.clone(), value);
}
for id in next.original.values() {
next.lineage.insert(id.clone(), id.clone());
}
candidate.imports.insert((*new_import).into(), package);
candidate.mounts.insert((*new_mount).into(), mount);
candidate.instances.insert((*id).into(), next);
candidate.revision += 1;
candidate.receipts.push(request.trim().into());
admit(&candidate)?;
Ok(candidate)
}
fn save(doc: &Document, dir: &Path) -> Result<()> {
let mut source = format!("document|{}|{}\n", doc.identity, doc.revision);
for (alias, p) in &doc.imports {
let path = format!("packages/{}.library", p.digest);
source += &format!(
"import|{alias}|{}|{}|{}|{path}\n",
p.identity, p.version, p.digest
);
write(&dir.join(path), &p.raw)?;
}
for (id, m) in &doc.mounts {
source += &format!("mount|{id}|{}|management/{id}.mount\n", m.import);
let body = m
.members
.iter()
.map(|(foreign, local)| format!("member|{foreign}|{local}\n"))
.collect::<String>();
write(&dir.join(format!("management/{id}.mount")), &body)?;
}
for (id, i) in &doc.instances {
source += &format!("instance|{id}|management/{id}\n");
let mut base = format!("base|{}|{}|{}|{}\n", i.import, i.mount, i.sink, i.prefix);
for (m, original) in &i.original {
base += &format!("original|{m}|{original}\n");
}
for (m, r) in &i.base {
base += &format!("member|{m}|{}\n", r.line());
}
write(&dir.join(format!("management/{id}/base.model")), &base)?;
let map = i
.current
.iter()
.map(|(m, current)| {
format!("current|{m}|{}\n", current.as_deref().unwrap_or("DELETED"))
})
.collect::<String>();
write(&dir.join(format!("management/{id}/map.model")), &map)?;
let lineage = i
.lineage
.iter()
.map(|(original, current)| format!("lineage|{original}|{current}\n"))
.collect::<String>();
write(
&dir.join(format!("management/{id}/lineage.model")),
&lineage,
)?;
}
for r in doc.live.values() {
source += &format!("{}\n", r.line());
}
for receipt in &doc.receipts {
source += &format!("applied|{receipt}\n");
}
write(&dir.join("project.model"), &source)
}
fn declared(dir: &Path, logical: &str) -> Result<PathBuf> {
if logical.starts_with('/')
|| logical.contains('\\')
|| logical
.split('/')
.any(|p| p.is_empty() || p == "." || p == ".." || p.contains(':'))
{
return Err("nonportable logical path".into());
}
Ok(dir.join(logical))
}
fn load(dir: &Path) -> Result<Document> {
let mut doc = Document {
identity: String::new(),
revision: 0,
imports: BTreeMap::new(),
mounts: BTreeMap::new(),
instances: BTreeMap::new(),
live: BTreeMap::new(),
receipts: vec![],
};
for line in read(&dir.join("project.model"))?.lines() {
let r: Vec<_> = line.split('|').collect();
match r.as_slice() {
["document", id, rev] => {
doc.identity = (*id).into();
doc.revision = rev.parse().map_err(|_| "bad revision")?;
}
["import", alias, identity, version, digest, path] => {
let p = Package::parse(read(&declared(dir, path)?)?)?;
if p.digest != *digest || p.identity != *identity || p.version != *version {
return Err("package pin mismatch".into());
}
if doc.imports.insert((*alias).into(), p).is_some() {
return Err("duplicate import".into());
}
}
["mount", id, import, path] => {
let mut members = BTreeMap::new();
for line in read(&declared(dir, path)?)?.lines() {
let row: Vec<_> = line.split('|').collect();
let ["member", member, local] = row.as_slice() else {
return Err("bad mount member".into());
};
if members.insert((*member).into(), (*local).into()).is_some() {
return Err("duplicate mount member".into());
}
}
doc.mounts.insert(
(*id).into(),
Mount {
import: (*import).into(),
members,
},
);
}
["instance", id, path] => {
let mut i = Instance {
import: String::new(),
mount: String::new(),
sink: String::new(),
prefix: String::new(),
original: BTreeMap::new(),
current: BTreeMap::new(),
lineage: BTreeMap::new(),
base: BTreeMap::new(),
};
for line in read(&declared(dir, &format!("{path}/base.model"))?)?.lines() {
let row: Vec<_> = line.split('|').collect();
match row.as_slice() {
["base", import, mount, sink, prefix] => {
i.import = (*import).into();
i.mount = (*mount).into();
i.sink = (*sink).into();
i.prefix = (*prefix).into();
}
["original", m, local] => {
if i.original.insert((*m).into(), (*local).into()).is_some() {
return Err("duplicate original".into());
}
}
["member", m, ..] => {
let body = line.splitn(3, '|').nth(2).ok_or("bad member record")?;
if i.base.insert((*m).into(), Record::parse(body)?).is_some() {
return Err("duplicate base member".into());
}
}
_ => return Err("bad base row".into()),
}
}
for line in read(&declared(dir, &format!("{path}/map.model"))?)?.lines() {
let row: Vec<_> = line.split('|').collect();
let ["current", m, local] = row.as_slice() else {
return Err("bad current row".into());
};
if i.current
.insert((*m).into(), (*local != "DELETED").then(|| (*local).into()))
.is_some()
{
return Err("duplicate current row".into());
}
}
for line in read(&declared(dir, &format!("{path}/lineage.model"))?)?.lines() {
let row: Vec<_> = line.split('|').collect();
let ["lineage", old, new] = row.as_slice() else {
return Err("bad lineage row".into());
};
if i.lineage.insert((*old).into(), (*new).into()).is_some() {
return Err("duplicate lineage row".into());
}
}
doc.instances.insert((*id).into(), i);
}
["record", ..] => {
let record = Record::parse(line)?;
if doc.live.insert(record.id.clone(), record).is_some() {
return Err("duplicate live record".into());
}
}
["applied", ..] => doc.receipts.push(line[8..].into()),
_ => return Err("unknown normalized row".into()),
}
}
admit(&doc)?;
Ok(doc)
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Transition {
layer: String,
records: BTreeMap<String, Definition>,
origin_pin: String,
target_pin: Option<String>,
origin_map: BTreeMap<String, String>,
mount: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
enum TargetRecord {
Function {
name: String,
},
Port {
owner: String,
direction: String,
accepted_item: String,
},
FunctionalExchange {
source: String,
target: String,
source_port: String,
target_port: String,
item: String,
},
}
fn target_architecture(transition: &Transition) -> Result<BTreeMap<String, TargetRecord>> {
let member = transition
.origin_map
.get("Alarm")
.ok_or("missing item correspondence")?;
let item = transition
.records
.get(member)
.ok_or("missing mapped item")?;
if transition.layer != "SA" || item.layer != "SA" || item.class != "Item" {
return Err("invalid SA item disposition".into());
}
let item = if transition.mount {
format!("sa_mount/{member}")
} else {
member.clone()
};
Ok(BTreeMap::from([
(
"sa/watch".into(),
TargetRecord::Function {
name: "Watch".into(),
},
),
(
"sa/receive".into(),
TargetRecord::Function {
name: "Receive left".into(),
},
),
(
"sa/watch_out".into(),
TargetRecord::Port {
owner: "sa/watch".into(),
direction: "Out".into(),
accepted_item: item.clone(),
},
),
(
"sa/receive_in".into(),
TargetRecord::Port {
owner: "sa/receive".into(),
direction: "In".into(),
accepted_item: item.clone(),
},
),
(
"sa/alarm".into(),
TargetRecord::FunctionalExchange {
source: "sa/watch".into(),
target: "sa/receive".into(),
source_port: "sa/watch_out".into(),
target_port: "sa/receive_in".into(),
item,
},
),
]))
}
fn derivative(package: &Package) -> Transition {
let members = package.definitions.values().filter(|d| d.layer == "OA");
let records = members
.map(|d| {
let mut copied = d.clone();
copied.layer = "SA".into();
copied.member = format!("SA/{}", d.member);
copied.refs = d
.refs
.iter()
.map(|r| {
if package.definitions[r].layer == "OA" {
format!("SA/{r}")
} else {
r.clone()
}
})
.collect();
(copied.member.clone(), copied)
})
.collect();
Transition {
layer: "SA".into(),
records,
origin_pin: package.digest.clone(),
target_pin: None,
origin_map: package
.definitions
.values()
.filter(|d| d.layer == "OA")
.map(|d| (d.member.clone(), format!("SA/{}", d.member)))
.collect(),
mount: false,
}
}
fn pinned_counterpart(
package: &Package,
target: &Package,
correspondence: &BTreeMap<String, String>,
) -> Result<Transition> {
let expected = derivative(package);
let records = target
.definitions
.values()
.filter(|d| d.layer == "SA")
.map(|d| (d.member.clone(), d.clone()))
.collect();
if expected.records != records || &expected.origin_map != correspondence {
return Err("incomplete/incompatible layer correspondence".into());
}
Ok(Transition {
layer: "SA".into(),
records,
origin_pin: package.digest.clone(),
target_pin: Some(target.digest.clone()),
origin_map: correspondence.clone(),
mount: true,
})
}
fn analysis_scope(
properties: &[&str],
checks: &[&str],
cases: &[&str],
external: &[&str],
) -> Result<BTreeSet<String>> {
let mut selected: BTreeSet<String> = properties
.iter()
.chain(checks)
.chain(cases)
.map(|s| (*s).into())
.collect();
let boundary: BTreeSet<_> = external.iter().copied().collect();
loop {
let old = selected.clone();
for id in &old {
let dependencies = match id.as_str() {
"P" => vec![],
"K" | "C" => vec!["P"],
"G" => vec!["P", "Q"],
"Q" => vec![],
_ => return Err("unknown analysis root".into()),
};
selected.extend(
dependencies
.into_iter()
.filter(|id| !boundary.contains(id))
.map(String::from),
);
}
if selected == old {
break;
}
}
if selected.contains("Q") {
return Err("outside property Q requires explicit subject/property boundary choice".into());
}
Ok(selected)
}
fn sha256(bytes: &[u8]) -> String {
const K: [u32; 64] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
0xc67178f2,
];
let mut h: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
0x5be0cd19,
];
let mut data = bytes.to_vec();
let bit_len = (data.len() as u64) * 8;
data.push(0x80);
while data.len() % 64 != 56 {
data.push(0);
}
data.extend(bit_len.to_be_bytes());
for chunk in data.chunks_exact(64) {
let mut w = [0u32; 64];
for (i, word) in chunk.chunks_exact(4).enumerate() {
w[i] = u32::from_be_bytes(word.try_into().expect("four bytes"));
}
for i in 16..64 {
let s0 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
let s1 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
w[i] = w[i - 16]
.wrapping_add(s0)
.wrapping_add(w[i - 7])
.wrapping_add(s1);
}
let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut hh] = h;
for i in 0..64 {
let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
let ch = (e & f) ^ (!e & g);
let t1 = hh
.wrapping_add(s1)
.wrapping_add(ch)
.wrapping_add(K[i])
.wrapping_add(w[i]);
let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
let maj = (a & b) ^ (a & c) ^ (b & c);
let t2 = s0.wrapping_add(maj);
hh = g;
g = f;
f = e;
e = d.wrapping_add(t1);
d = c;
c = b;
b = a;
a = t1.wrapping_add(t2);
}
for (state, value) in h.iter_mut().zip([a, b, c, d, e, f, g, hh]) {
*state = state.wrapping_add(value);
}
}
h.iter().map(|x| format!("{x:08x}")).collect()
}
fn main() -> Result<()> {
let args: Vec<String> = std::env::args().skip(1).collect();
if args.first().is_some_and(|a| a == "--reopen") {
if args.len() != 3 {
return Err("usage: --reopen INPUT_DIRECTORY OUTPUT_DIRECTORY".into());
}
let doc = load(Path::new(&args[1]))?;
let budget = evaluate(&doc, "budget")?;
save(&doc, Path::new(&args[2]))?;
println!(
"Fresh process reopened {} records at revision {}; budget={} ms satisfied={}",
doc.live.len(),
doc.revision,
budget.0,
budget.1
);
return Ok(());
}
let root = PathBuf::from(
args.first()
.ok_or("provide the owned experiment output directory")?,
);
fs::create_dir_all(&root).map_err(|e| e.to_string())?;
let mut checks = 0usize;
macro_rules! check {
($condition:expr) => {{
checks += 1;
assert!($condition, "check {}: {}", checks, stringify!($condition));
}};
}
check!(sha256(b"") == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
check!(sha256(b"abc") == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
let raw = concat!(
"package|ControlPatterns|1.0.0\n",
"description|Monitor alarm\n",
"note|Initial documentation\n",
"def|Duration|Kind|Neutral|dimension=0,0,1,0,0,0,0;linear|-\n",
"def|Energy|Kind|Neutral|dimension=2,1,-2,0,0,0,0;linear|-\n",
"def|Torque|Kind|Neutral|dimension=2,1,-2,0,0,0,0;linear|-\n",
"def|ms|Unit|Neutral|millis=1|Duration\n",
"def|s|Unit|Neutral|millis=1000|Duration\n",
"def|Flag|Scalar|OA|Boolean|-\n",
"def|Alarm|Item|OA|Flow|Code\n",
"def|Code|Field|OA|minimum=1;maximum=1|Alarm,Flag\n",
"def|Interface|Interface|OA|-|Operation\n",
"def|Operation|Allocation|OA|order=0|Interface,Alarm\n",
"prototype|A|record|A|OA|Watch|Activity|Monitor alarm\n",
"prototype|E|record|E|OA|Alarm|Interaction|A|H|MOUNT/Alarm\n",
"prototype|P|record|P|OA|Elapsed|Property|A|SELF:Duration|750@SELF:ms\n",
"prototype|C|record|C|OA|Stress|Case|-|P=1250@SELF:ms\n",
"prototype|K|record|K|OA|Elapsed limit|Check|P|1000@SELF:ms\n",
"prototype|H|record|H|OA|Prototype receiver|Activity|Context role only\n",
"prototype|Q|record|Q|OA|Outside delay|Property|H|SELF:Duration|1000@SELF:ms\n",
"prototype|G|record|G|OA|Project-wide study|Case|-|P=2500@SELF:ms,Q=4000@SELF:ms\n",
"pattern|monitor|A,E,P,C,K\n",
"analysis|P|K|C\n",
"role|sink|H|Activity|OA\n"
);
let p1 = Package::parse(raw.into())?;
let p2 = Package::parse(
raw.replace("1.0.0", "1.0.1")
.replace("Initial documentation", "Revised documentation only"),
)?;
let p3 = Package::parse(
raw.replace("1.0.0", "2.0.0")
.replace("maximum=1", "maximum=2"),
)?;
let changed_kind =
Package::parse(raw.replace("dimension=0,0,1,0,0,0,0", "dimension=1,0,0,0,0,0,0"))?;
let other = Package::parse(raw.replace("ControlPatterns", "OtherVocabulary"))?;
check!(p1.digest != p2.digest && p1.raw != p2.raw);
for member in p1.definitions.keys() {
check!(equivalent(&p1, member, &p2, member));
}
check!(!equivalent(&p1, "Duration", &p1, "Energy"));
check!(!equivalent(&p1, "Energy", &p1, "Torque"));
check!(!equivalent(&p1, "Duration", &other, "Duration"));
check!(!equivalent(&p1, "Duration", &changed_kind, "Duration"));
check!(!equivalent(&p1, "Interface", &p3, "Interface"));
check!(equivalent(&p1, "Duration", &p3, "Duration"));
let packages = BTreeMap::from([("D1".into(), p1.clone()), ("D2".into(), p2.clone())]);
let request = "new|Alpha\nimport|controls1|D1\nmount|data1|controls1\nactivity|sink_left|Receive left\nactivity|sink_right|Receive right\ninstantiate|left|controls1|data1|sink_left\ninstantiate|right|controls1|data1|sink_right\nbudget|budget|left/P|right/P|controls1\nconsumer|outside|left/E|data1\nglobal_case|global|left/P\nreceipt|create-two-instances\n";
write(&root.join("initial.request"), request)?;
let initial = prepare_new(&read(&root.join("initial.request"))?, &packages)?;
let expected_initial_rows = [
"record|sink_left|OA|Receive left|Activity|",
"record|sink_right|OA|Receive right|Activity|",
"record|left/A|OA|left Watch|Activity|Monitor alarm",
"record|left/E|OA|left Alarm|Interaction|left/A|sink_left|data1/Alarm",
"record|left/P|OA|left Elapsed|Property|left/A|controls1:Duration|750@controls1:ms",
"record|left/C|OA|left Stress|Case|-|left/P=1250@controls1:ms",
"record|left/K|OA|left Elapsed limit|Check|left/P|1000@controls1:ms",
"record|right/A|OA|right Watch|Activity|Monitor alarm",
"record|right/E|OA|right Alarm|Interaction|right/A|sink_right|data1/Alarm",
"record|right/P|OA|right Elapsed|Property|right/A|controls1:Duration|750@controls1:ms",
"record|right/C|OA|right Stress|Case|-|right/P=1250@controls1:ms",
"record|right/K|OA|right Elapsed limit|Check|right/P|1000@controls1:ms",
"record|budget|OA|Combined duration|Budget|left/P|right/P|controls1:Duration|2000@controls1:ms",
"record|outside|OA|Outside typed receiver|Consumer|left/E|data1/Interface|data1/Operation|data1/Code",
"record|global|OA|Unrelated project-wide study|Case|-|left/P=3000@controls1:ms",
];
let expected_initial_live: BTreeMap<_, _> = expected_initial_rows
.iter()
.map(|line| Record::parse(line).map(|r| (r.id.clone(), r)))
.collect::<Result<_>>()?;
check!(initial.live == expected_initial_live);
write(
&root.join("expected-initial.model"),
&(expected_initial_rows.join("\n") + "\n"),
)?;
check!(initial.live.len() == 15);
check!(initial.instances["left"].current.values().all(|id| {
!initial.instances["right"]
.current
.values()
.any(|other| id == other)
}));
check!(evaluate(&initial, "budget")? == (1500, true));
save(&initial, &root.join("01-initial"))?;
check!(load(&root.join("01-initial"))? == initial);
save(
&load(&root.join("01-initial"))?,
&root.join("01-recompiled"),
)?;
check!(
read(&root.join("01-initial/project.model"))?
== read(&root.join("01-recompiled/project.model"))?
);
write(
&root.join("local-edit.request"),
"edit_base|left/P|900@controls1:ms\n",
)?;
let edited = apply_edit(&initial, &read(&root.join("local-edit.request"))?)?;
check!(edited.instances == initial.instances);
check!(evaluate(&edited, "budget")? == (1650, true));
save(&edited, &root.join("02-edited"))?;
let request = format!(
"update|left|{}|controls2|data2|2|P.base=keep_local\n",
p1.digest
);
write(&root.join("selective-update.request"), &request)?;
check!(
update(
&edited,
&request.replace("P.base=keep_local", "unresolved"),
p2.clone()
)
.is_err()
);
check!(update(&edited, &request.replace("|2|", "|1|"), p2.clone()).is_err());
let updated = update(
&edited,
&read(&root.join("selective-update.request"))?,
p2.clone(),
)?;
check!(evaluate_policy(&initial, "budget", &Policy::Strict)? == (1500, true));
check!(consumer_match_policy(&initial, "outside", &Policy::Strict).is_ok());
check!(evaluate_policy(&updated, "budget", &Policy::Strict).is_err());
check!(consumer_match_policy(&updated, "outside", &Policy::Strict).is_err());
check!(evaluate(&updated, "budget")? == (1650, true));
check!(evaluate_check(&updated, "left/K", None)? == (900, true));
check!(evaluate_check(&updated, "left/K", Some("left/C"))? == (1250, false));
check!(evaluate_check(&updated, "left/K", Some("global"))? == (3000, false));
check!(evaluate_check(&updated, "right/K", Some("right/C"))? == (1250, false));
check!(updated.instances["right"] == edited.instances["right"]);
check!(updated.live["right/P"] == edited.live["right/P"]);
for id in ["outside", "budget", "global", "sink_left", "sink_right"] {
check!(updated.live[id] == edited.live[id]);
}
for (member, current) in &edited.instances["left"].current {
check!(updated.instances["left"].current[member] == *current);
}
let Body::Property { kind, base, .. } = &updated.live["left/P"].body else {
unreachable!()
};
check!(kind == &DRef::new("controls2", "Duration"));
check!(base == &Literal::new(900, "controls1", "ms"));
let Body::Property { base, .. } = &updated.instances["left"].base["P"].body else {
unreachable!()
};
check!(base == &Literal::new(750, "controls2", "ms"));
check!(updated.instances["left"].import == "controls2");
check!(
consumer_match(&updated, "outside")?
== BTreeMap::from([
("data1/Alarm".into(), "data2/Alarm".into()),
("data1/Code".into(), "data2/Code".into()),
("data1/Flag".into(), "data2/Flag".into()),
("data1/Interface".into(), "data2/Interface".into()),
("data1/Operation".into(), "data2/Operation".into())
])
);
save(&updated, &root.join("03-updated"))?;
check!(load(&root.join("03-updated"))? == updated);
// Independently authored expectations: no materialize()/update() call supplies these rows.
let expected_rows = [
"record|left/P|OA|left Elapsed|Property|left/A|controls2:Duration|900@controls1:ms",
"record|left/E|OA|left Alarm|Interaction|left/A|sink_left|data2/Alarm",
"record|left/C|OA|left Stress|Case|-|left/P=1250@controls2:ms",
"record|left/K|OA|left Elapsed limit|Check|left/P|1000@controls2:ms",
"record|right/P|OA|right Elapsed|Property|right/A|controls1:Duration|750@controls1:ms",
"record|budget|OA|Combined duration|Budget|left/P|right/P|controls1:Duration|2000@controls1:ms",
"record|outside|OA|Outside typed receiver|Consumer|left/E|data1/Interface|data1/Operation|data1/Code",
];
for line in expected_rows {
let expected = Record::parse(line)?;
check!(updated.live[&expected.id] == expected);
}
write(
&root.join("expected-key-records.model"),
&(expected_rows.join("\n") + "\n"),
)?;
// Full independent graph oracle, including every accepted baseline and management map.
let mut expected_live = expected_initial_live;
for line in expected_rows {
let r = Record::parse(line)?;
expected_live.insert(r.id.clone(), r);
}
let expected_mounts = BTreeMap::from([
(
"data1".into(),
Mount {
import: "controls1".into(),
members: BTreeMap::from([
("Alarm".into(), "data1/Alarm".into()),
("Code".into(), "data1/Code".into()),
("Flag".into(), "data1/Flag".into()),
("Interface".into(), "data1/Interface".into()),
("Operation".into(), "data1/Operation".into()),
]),
},
),
(
"data2".into(),
Mount {
import: "controls2".into(),
members: BTreeMap::from([
("Alarm".into(), "data2/Alarm".into()),
("Code".into(), "data2/Code".into()),
("Flag".into(), "data2/Flag".into()),
("Interface".into(), "data2/Interface".into()),
("Operation".into(), "data2/Operation".into()),
]),
},
),
]);
let mut expected_instances = BTreeMap::new();
for (prefix, import, mount, sink) in [
("left", "controls2", "data2", "sink_left"),
("right", "controls1", "data1", "sink_right"),
] {
let original: BTreeMap<String, String> = ["A", "C", "E", "K", "P"]
.into_iter()
.map(|m| (m.into(), format!("{prefix}/{m}")))
.collect();
let mut base: BTreeMap<String, Record> = original
.iter()
.map(|(m, id)| (m.clone(), expected_live[id].clone()))
.collect();
if prefix == "left" {
base.insert("P".into(), Record::parse("record|left/P|OA|left Elapsed|Property|left/A|controls2:Duration|750@controls2:ms")?);
}
expected_instances.insert(
prefix.into(),
Instance {
import: import.into(),
mount: mount.into(),
sink: sink.into(),
prefix: prefix.into(),
current: original
.iter()
.map(|(m, id)| (m.clone(), Some(id.clone())))
.collect(),
lineage: original
.values()
.map(|id| (id.clone(), id.clone()))
.collect(),
original,
base,
},
);
}
let expected_full = Document {
identity: "Alpha".into(),
revision: 3,
imports: BTreeMap::from([
("controls1".into(), p1.clone()),
("controls2".into(), p2.clone()),
]),
mounts: expected_mounts,
instances: expected_instances,
live: expected_live,
receipts: vec![
"create-two-instances".into(),
"edit_base|left/P|900@controls1:ms".into(),
request.trim().into(),
],
};
check!(updated == expected_full);
save(&expected_full, &root.join("expected-full-updated"))?;
// Unchanged exact identity remains a stricter relation than compatibility.
check!(updated.imports["controls1"].digest != updated.imports["controls2"].digest);
check!(DRef::new("controls1", "Duration") != DRef::new("controls2", "Duration"));
check!(updated.mounts["data1"].members["Alarm"] != updated.mounts["data2"].members["Alarm"]);
check!(update(&edited, &request, p3.clone()).is_err());
let mut forged = updated.clone();
forged
.instances
.get_mut("left")
.unwrap()
.base
.get_mut("P")
.unwrap()
.name = "Forged history".into();
check!(admit(&forged).is_err());
let mut forged = updated.clone();
forged.imports.get_mut("controls1").unwrap().raw.push(' ');
check!(admit(&forged).is_err());
let mut forged_parsed = updated.clone();
forged_parsed
.imports
.get_mut("controls1")
.unwrap()
.definitions
.get_mut("Alarm")
.unwrap()
.layer = "SA".into();
check!(admit(&forged_parsed).is_err());
let mut label_collision = updated.clone();
label_collision.imports.insert(
"conflicting_version".into(),
Package::parse(
p1.raw
.replace("Initial documentation", "Another revision claiming 1.0.0"),
)?,
);
check!(admit(&label_collision).is_err());
let mut collision = updated.clone();
collision
.instances
.get_mut("left")
.unwrap()
.current
.insert("P".into(), Some("right/P".into()));
check!(admit(&collision).is_err());
let mut missing = updated.clone();
missing.imports.remove("controls1");
check!(admit(&missing).is_err());
let mut other_local_edits = edited.clone();
let property = other_local_edits.live.get_mut("left/P").unwrap();
property.name = "Local measurement name".into();
let Body::Property { subject, .. } = &mut property.body else {
unreachable!()
};
*subject = "sink_left".into();
let twice_edited = update(&other_local_edits, &request, p2.clone())?;
check!(twice_edited.live["left/P"].name == "Local measurement name");
let Body::Property { subject, .. } = &twice_edited.live["left/P"].body else {
unreachable!()
};
check!(subject == "sink_left");
let mut extended = edited.clone();
extended.live.insert(
"local_extra".into(),
Record {
id: "local_extra".into(),
layer: "OA".into(),
name: "left Watch".into(),
body: Body::Activity {
description: "Independent extension".into(),
},
},
);
let extended_update = update(&extended, &request, p2.clone())?;
check!(extended_update.live["local_extra"] == extended.live["local_extra"]);
let mut dangling = edited.clone();
dangling.live.remove("left/E");
dangling
.instances
.get_mut("left")
.unwrap()
.current
.insert("E".into(), None);
check!(admit(&dangling).is_err());
// Explicit reidentify changes live references/current map/lineage, never base or foreign origins.
let mut reidentified = edited.clone();
let mut moved = reidentified.live.remove("left/A").unwrap();
moved.remap_live("left/A", "left/A2");
reidentified.live.insert(moved.id.clone(), moved);
for record in reidentified.live.values_mut() {
record.remap_live("left/A", "left/A2");
}
let i = reidentified.instances.get_mut("left").unwrap();
i.current.insert("A".into(), Some("left/A2".into()));
i.lineage.insert("left/A".into(), "left/A2".into());
check!(admit(&reidentified).is_ok());
check!(reidentified.instances["left"].base == edited.instances["left"].base);
check!(reidentified.imports == edited.imports);
let mut reused = reidentified.clone();
reused.live.insert(
"left/A".into(),
Record {
id: "left/A".into(),
layer: "OA".into(),
name: "New object".into(),
body: Body::Activity {
description: String::new(),
},
},
);
check!(admit(&reused).is_err());
save(&reidentified, &root.join("04-reidentified"))?;
check!(load(&root.join("04-reidentified"))? == reidentified);
let reupdated = update(&reidentified, &request, p2.clone())?;
check!(reupdated.live.contains_key("left/A2") && !reupdated.live.contains_key("left/A"));
// A deleted member remains reserved; no implicit resurrection or name adoption.
let mut deleted = edited.clone();
deleted.live.remove("left/K");
deleted
.instances
.get_mut("left")
.unwrap()
.current
.insert("K".into(), None);
check!(admit(&deleted).is_ok());
check!(update(&deleted, &request, p2.clone()).is_err());
deleted.live.insert(
"left/K".into(),
Record {
id: "left/K".into(),
layer: "OA".into(),
name: "Same-looking new check".into(),
body: Body::Check {
property: "right/P".into(),
limit: Literal::new(1000, "controls1", "ms"),
},
},
);
check!(admit(&deleted).is_err());
// Subjectless C/K are included only by explicit selection; G is never inverse-pulled.
check!(analysis_scope(&["P"], &[], &[], &[])? == BTreeSet::from(["P".into()]));
check!(
analysis_scope(&["P"], &["K"], &["C"], &[])?
== BTreeSet::from(["P".into(), "K".into(), "C".into()])
);
check!(analysis_scope(&[], &[], &["G"], &[]).is_err());
check!(analysis_scope(&[], &[], &["G"], &["Q"])? == BTreeSet::from(["G".into(), "P".into()]));
// Layer transformation has independent provenance and mutability, not implicit compatibility.
let sa = derivative(&p2);
check!(!sa.mount && sa.layer == "SA" && sa.origin_pin == p2.digest);
check!(sa.records.len() == 5 && sa.origin_map.len() == 5);
let mut sa_raw =
String::from("package|ControlPatternsSA|1.0.1\ndescription|Explicit SA counterpart\n");
for d in sa.records.values() {
sa_raw += &format!(
"def|{}|{}|{}|{}|{}\n",
d.member,
d.class,
d.layer,
d.fields.join(","),
d.refs.join(",")
);
}
let sa_package = Package::parse(sa_raw)?;
let pinned = pinned_counterpart(&p2, &sa_package, &sa.origin_map)?;
check!(
pinned.mount
&& pinned.records == sa.records
&& pinned.target_pin == Some(sa_package.digest.clone())
);
check!(!equivalent(&p2, "Alarm", &sa_package, "SA/Alarm"));
let mut incomplete = sa.origin_map.clone();
incomplete.remove("Code");
check!(pinned_counterpart(&p2, &sa_package, &incomplete).is_err());
let mut refined = sa.clone();
refined.records.get_mut("SA/Code").unwrap().fields = vec!["minimum=1;maximum=2".into()];
let refined_package = Package::parse(sa_package.raw.replace("maximum=1", "maximum=2"))?;
check!(pinned_counterpart(&p2, &refined_package, &sa.origin_map).is_err());
check!(derivative(&p2).records == sa.records); // Explicit reverse BindPinned may reuse the original unchanged OA contract.
check!(derivative(&p2).records != refined.records); // Reverse transition of an edited derivative must not mutate the original mount.
let pinned_architecture = target_architecture(&pinned)?;
let local_architecture = target_architecture(&sa)?;
check!(pinned_architecture.len() == 5 && local_architecture.len() == 5);
check!(
pinned_architecture["sa/alarm"]
== TargetRecord::FunctionalExchange {
source: "sa/watch".into(),
target: "sa/receive".into(),
source_port: "sa/watch_out".into(),
target_port: "sa/receive_in".into(),
item: "sa_mount/SA/Alarm".into()
}
);
check!(
local_architecture["sa/alarm"]
== TargetRecord::FunctionalExchange {
source: "sa/watch".into(),
target: "sa/receive".into(),
source_port: "sa/watch_out".into(),
target_port: "sa/receive_in".into(),
item: "SA/Alarm".into()
}
);
let mut wrong_layer = sa.clone();
wrong_layer.records.get_mut("SA/Alarm").unwrap().layer = "OA".into();
check!(target_architecture(&wrong_layer).is_err());
check!(sa == derivative(&p2)); // Original source/package revisions have not mutated the captured derivative.
check!(derivative(&p3).records != sa.records);
let mut illegal = p2.clone();
illegal.definitions.get_mut("Alarm").unwrap().layer = "SA".into();
check!(!equivalent(&p2, "Alarm", &illegal, "Alarm"));
write(
&root.join("oa-sa-transition.model"),
&format!(
"pinned-counterpart={pinned:#?}\npinned-architecture={pinned_architecture:#?}\nlocal-derivative={sa:#?}\nlocal-architecture={local_architecture:#?}\nrefined-derivative={refined:#?}\n"
),
)?;
// Checked identity bridges are scoped direct witnesses, not unverified flags or dimension casts.
let bridge = |a: &Package, am: &str, b: &Package, bm: &str| -> Result<String> {
if equivalent(a, am, b, bm) {
Ok(format!(
"checked-same-origin|{}|{am}|{}|{bm}",
a.digest, b.digest
))
} else {
Err("bridge proof failed".into())
}
};
check!(bridge(&p1, "Duration", &p2, "Duration").is_ok());
check!(bridge(&p1, "Interface", &p2, "Interface").is_ok());
check!(bridge(&p1, "Energy", &p1, "Torque").is_err());
check!(bridge(&p1, "Interface", &p3, "Interface").is_err());
let witnesses = BTreeSet::from([
pair(
&format!("{}:Duration", p1.digest),
&format!("{}:Duration", p2.digest),
),
pair(
&format!("{}:Interface", p1.digest),
&format!("{}:Interface", p2.digest),
),
]);
let explicit_policy = Policy::Bridges(witnesses);
check!(evaluate_policy(&updated, "budget", &explicit_policy)? == (1650, true));
check!(consumer_match_policy(&updated, "outside", &explicit_policy).is_ok());
check!(evaluate_policy(&updated, "budget", &Policy::Bridges(BTreeSet::new())).is_err());
check!(consumer_match_policy(&updated, "outside", &Policy::Bridges(BTreeSet::new())).is_err());
// Qualified layered definitions have the same compatibility/layer obligations without materialized IDs.
check!(policy_matches(
&p1,
"Interface",
&p2,
"Interface",
&Policy::SameOrigin
));
check!(!policy_matches(
&p1,
"Interface",
&p2,
"Interface",
&Policy::Strict
));
check!(p2.definitions["Alarm"].layer != "SA");
check!(sa_package.definitions["SA/Alarm"].layer == "SA");
let bridge_text = format!(
"{}\n{}\n",
bridge(&p1, "Duration", &p2, "Duration")?,
bridge(&p1, "Interface", &p2, "Interface")?
);
write(&root.join("explicit-bridges.model"), &bridge_text)?;
// Stable vocabulary separates pattern bytes from definition provenance, but vocabulary changes still need the same decision.
let vocabulary_pin = p1.digest.clone();
let pattern1 = ("PatternRevision1", vocabulary_pin.clone());
let pattern2 = ("PatternRevision2", vocabulary_pin.clone());
check!(pattern1.0 != pattern2.0 && pattern1.1 == pattern2.1);
check!(pattern1.1 != p3.digest);
let results = format!(
"# Finite-model results\n\nAssertions passed: {checks}\n\nInitial budget: 1500 ms, satisfied.\nAfter one local base edit: 1650 ms, satisfied.\nAfter selected cosmetic update: 1650 ms, satisfied; exact pins differ.\nOutside budget/consumer/global case: exact records unchanged.\nUpdated left baseline: 750 controls2:ms; current: 900 controls1:ms; declared kind controls2:Duration.\nRight instance/base/map: exact original.\nContract path projection: data1/Code -> data2/Code and data1/Operation -> data2/Operation.\nChanged field cardinality: selective candidate rejected.\nStrict revision identity: old/new refs unequal.\nSame-origin typed compatibility: cosmetic revision accepted; Energy/Torque, other origin, changed contract rejected.\nBridge alternative: 2 explicit validated direct witnesses; changed contracts rejected.\nStable vocabulary alternative: exact common pin survives pattern change; vocabulary change remains unresolved without compatibility/migration.\nSubjectless explicit C+K selected; unrelated G omitted; selected G requires Q boundary.\nOA/SA: explicit pinned counterpart or independent local derivative; refined reverse counterpart fails exact transformed contract.\n\nD1: {}\nD2: {}\nD3: {}\n\nThis dialect uses opaque symbolic identities, a restricted AST, one package per import and scalar integer-millisecond arithmetic. It is not Studio source, a full package dependency solver, production UUID allocation, complete data/operation/transition admission, REST or native acceptance.\n",
p1.digest, p2.digest, p3.digest
);
write(&root.join("RESULTS.md"), &results)?;
write(&root.join("package-D1.library"), &p1.raw)?;
write(&root.join("package-D2.library"), &p2.raw)?;
write(&root.join("package-D3.library"), &p3.raw)?;
write(&root.join("package-SA.library"), &sa_package.raw)?;
println!(
"{checks} assertions passed\nD1={}\nD2={}\nD3={}",
p1.digest, p2.digest, p3.digest
);
Ok(())
}