Complete source 6 engineering workflows and preserve release validation evidence

This commit is contained in:
Codex
2026-09-06 21:49:04 -07:00
parent 2b2d2bc18b
commit 4b6b5fc197
290 changed files with 48271 additions and 1791 deletions
+55 -8
View File
@@ -12,6 +12,7 @@ use iced::{
};
use oa_core::{transitions::*, *};
use std::collections::BTreeSet;
mod communication;
pub(crate) mod recovery;
#[derive(Debug, Clone)]
@@ -31,6 +32,7 @@ pub enum Event {
Scope(String),
MappingTarget(Id, Choice),
MappingKind(Id, Kind),
CommunicationPort(Id, bool, communication::PortMenuChoice),
Resolve(Id, TransitionField, FieldDecision),
Preview,
}
@@ -125,10 +127,12 @@ impl Relationship {
return validation::can_create_interface_role(p, id);
}
if self.kind == RelationKind::ExchangeAllocation {
return p
.relations
.get(&id)
.is_some_and(|r| r.kind() == RelationKind::BoundaryExchange);
return p.relations.get(&id).is_some_and(|r| {
matches!(
r.kind(),
RelationKind::BoundaryExchange | RelationKind::CommunicationMean
)
});
}
p.elements.get(&id).is_some_and(|e| {
Kind::ALL
@@ -187,6 +191,10 @@ impl Relationship {
format!("{} {verb} {}", p.named(source), p.named(target))
}
fn default_orientation(&mut self, p: &Project) {
if self.kind == RelationKind::CommunicationMean {
self.oriented = false;
return;
}
self.oriented = !self
.source
.as_ref()
@@ -230,8 +238,15 @@ impl Relationship {
if let RelationBody::CapabilityExtend { condition, .. } = &mut body {
*condition = self.condition.text();
}
if let RelationBody::BoundaryExchange { oriented, .. } = &mut body {
if let RelationBody::BoundaryExchange {
oriented, items, ..
}
| RelationBody::CommunicationMean {
oriented, items, ..
} = &mut body
{
*oriented = self.oriented;
*items = self.items.clone();
}
let commands = vec![Command::CreateRelation(Relation {
id,
@@ -248,6 +263,7 @@ impl Relationship {
pub struct Transition {
pub request: TransitionRequest,
pub plan: TransitionPlan,
communication_ports: std::collections::BTreeMap<Id, communication::PortDraft>,
}
impl Workflow {
pub fn manual_trace(p: &Project, selected: Id) -> Result<Self, String> {
@@ -334,7 +350,11 @@ impl Workflow {
let mut request = TransitionRequest::new(direction, vec![selected]);
request.scope = DependencyScope::Required;
let plan = plan_transition(p, &request).map_err(|e| e.to_string())?;
Ok(Self::Transition(Box::new(Transition { request, plan })))
Ok(Self::Transition(Box::new(Transition {
request,
plan,
communication_ports: Default::default(),
})))
}
/// Return a complete accepted candidate only on explicit Apply. Intermediate
/// choices and previews never mutate the Session.
@@ -439,6 +459,9 @@ impl Workflow {
},
Self::Transition(d) => {
match event {
Event::CommunicationPort(exchange, source, value) => {
d.choose_communication_port(p, exchange, source, value)?;
}
Event::Scope(scope) => {
d.request.scope = match scope.as_str() {
"Required references" => DependencyScope::Required,
@@ -546,6 +569,16 @@ impl Workflow {
Event::Apply => {
let mut candidate =
apply_transition(p, &d.plan).map_err(|e| e.to_string())?;
// Behavior is already usable in its dedicated workspace. An
// unrequested architecture placement would alter an unrelated
// view, including its routes, just to display this operation.
if d.request.destination_diagram.is_none()
&& d.request.sources.first().is_some_and(|source| {
crate::behavior::selected_behavior(p, *source).is_some()
})
{
return Ok(Some(candidate));
}
let layer = d.request.direction.target_layer();
let diagram = d
.request
@@ -720,10 +753,13 @@ impl Workflow {
.padding(9),
);
}
if d.kind == RelationKind::BoundaryExchange {
if matches!(
d.kind,
RelationKind::BoundaryExchange | RelationKind::CommunicationMean
) {
content = content.push(
checkbox(d.oriented)
.label("Oriented component exchange")
.label("Directed source → target (unchecked: bidirectional)")
.on_toggle(|v| Message::Workflow(Event::Oriented(v))),
);
}
@@ -753,6 +789,14 @@ impl Workflow {
.width(Fill),
);
}
}
if matches!(
d.kind,
RelationKind::FunctionalExchange
| RelationKind::BoundaryExchange
| RelationKind::CommunicationMean
) {
content = content.push(text("Declared carried items").size(14));
for item in p
.elements
.values()
@@ -905,6 +949,9 @@ impl Workflow {
);
}
}
if let Some(ports) = d.communication_view(p, source) {
item = item.push(ports);
}
content = content.push(
iced::widget::container(item)
.padding(12)