Checkpoint source 7 workflows and in-progress diagram authoring redesign
Rust checks / check (ubuntu-latest) (push) Canceled after 0s
Rust checks / check (windows-latest) (push) Canceled after 0s
Rust checks / check (ubuntu-latest) (push) Canceled after 0s
Rust checks / check (windows-latest) (push) Canceled after 0s
Preserve current core, source, REST, desktop, recovery, documentation and validation work, including AGENTS.md and the development summary. This is a work-in-progress checkpoint: the new compact palette has outstanding compilation errors and native acceptance; earlier passing gates retain their documented scope.
This commit is contained in:
@@ -81,6 +81,12 @@ pub struct CommunicationEndpointDecision {
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OperationOmission {
|
||||
pub source: Id,
|
||||
pub rationale: String,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct TransitionRequest {
|
||||
pub direction: TransitionDirection,
|
||||
pub sources: Vec<Id>,
|
||||
@@ -91,6 +97,8 @@ pub struct TransitionRequest {
|
||||
pub destination_diagram: Option<Id>,
|
||||
#[serde(default)]
|
||||
pub communication_endpoints: Vec<CommunicationEndpointDecision>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub operation_omissions: Vec<OperationOmission>,
|
||||
}
|
||||
impl TransitionRequest {
|
||||
pub fn new(direction: TransitionDirection, sources: Vec<Id>) -> Self {
|
||||
@@ -103,6 +111,7 @@ impl TransitionRequest {
|
||||
resolutions: vec![],
|
||||
destination_diagram: None,
|
||||
communication_endpoints: vec![],
|
||||
operation_omissions: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -319,6 +328,7 @@ fn mapped_relation(r: &Relation, direction: TransitionDirection) -> Option<Relat
|
||||
| RelationBody::MissionInvolvement { .. }
|
||||
| RelationBody::MissionCapability { .. }
|
||||
| RelationBody::SequenceLink { .. }
|
||||
| RelationBody::ContextualLink { .. }
|
||||
| RelationBody::ChainInvolvement { .. }
|
||||
| RelationBody::BoundaryExchange { .. }
|
||||
| RelationBody::InterfaceProvision { .. }
|
||||
@@ -500,7 +510,16 @@ pub fn plan_transition(
|
||||
continue;
|
||||
}
|
||||
if let Some(e) = project.elements.get(&id) {
|
||||
selected.extend(crate::references::element_references(e));
|
||||
let mut dependencies = e.clone();
|
||||
if request.direction == TransitionDirection::SaToOa
|
||||
&& let Some(SharedBody::Occurrence {
|
||||
body: OccurrenceBody::Exchange { operation, .. },
|
||||
..
|
||||
}) = dependencies.shared_mut()
|
||||
{
|
||||
*operation = None;
|
||||
}
|
||||
selected.extend(crate::references::element_references(&dependencies));
|
||||
// Allocations are owned by interfaces. Independent data
|
||||
// associations travel only when both endpoint types are
|
||||
// already required; they do not expand the dictionary.
|
||||
@@ -523,12 +542,13 @@ pub fn plan_transition(
|
||||
// their endpoint involvements, independently of list order.
|
||||
if matches!(e.kind(), Kind::Process | Kind::FunctionalChain) {
|
||||
selected.extend(project.relations.values().filter_map(|relation| {
|
||||
(relation.kind() == RelationKind::SequenceLink
|
||||
&& project
|
||||
.elements
|
||||
.get(&relation.source())
|
||||
.and_then(|e| e.parent)
|
||||
== Some(id))
|
||||
(relation.contextual_owner() == Some(id)
|
||||
|| (relation.kind() == RelationKind::SequenceLink
|
||||
&& project
|
||||
.elements
|
||||
.get(&relation.source())
|
||||
.and_then(|e| e.parent)
|
||||
== Some(id)))
|
||||
.then_some(relation.id)
|
||||
}));
|
||||
}
|
||||
@@ -594,6 +614,67 @@ pub fn plan_transition(
|
||||
false
|
||||
} else { true }
|
||||
});
|
||||
let mut operation_omissions = BTreeSet::new();
|
||||
for decision in &request.operation_omissions {
|
||||
if request.direction != TransitionDirection::SaToOa
|
||||
|| !selected.contains(&decision.source)
|
||||
|| !matches!(
|
||||
project
|
||||
.elements
|
||||
.get(&decision.source)
|
||||
.and_then(Element::shared),
|
||||
Some(SharedBody::Occurrence {
|
||||
body: OccurrenceBody::Exchange {
|
||||
operation: Some(_),
|
||||
message_kind: MessageKind::Call | MessageKind::Asynchronous,
|
||||
..
|
||||
},
|
||||
..
|
||||
})
|
||||
)
|
||||
|| decision.rationale.trim().is_empty()
|
||||
|| !validation::valid_text(&decision.rationale)
|
||||
|| !operation_omissions.insert(decision.source)
|
||||
{
|
||||
conflict(
|
||||
&mut plan,
|
||||
Some(decision.source),
|
||||
None,
|
||||
None,
|
||||
"Operation omission needs one selected SA invocation, SA→OA direction, and a nonempty rationale; irrelevant or duplicate decisions reject.",
|
||||
);
|
||||
} else {
|
||||
plan.warnings.push(format!(
|
||||
"Reviewed operation omission: {} ({}): {}. Source contract is preserved.",
|
||||
project.named(decision.source),
|
||||
decision.source,
|
||||
decision.rationale
|
||||
));
|
||||
}
|
||||
}
|
||||
if request.direction == TransitionDirection::SaToOa {
|
||||
for source in &selected {
|
||||
if matches!(
|
||||
project.elements.get(source).and_then(Element::shared),
|
||||
Some(SharedBody::Occurrence {
|
||||
body: OccurrenceBody::Exchange {
|
||||
operation: Some(_),
|
||||
..
|
||||
},
|
||||
..
|
||||
})
|
||||
) && !operation_omissions.contains(source)
|
||||
{
|
||||
conflict(
|
||||
&mut plan,
|
||||
Some(*source),
|
||||
None,
|
||||
None,
|
||||
"This technical operation has no OA operation slot. Review an explicit per-invocation omission with rationale; Reply derives the Call's decision.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut choices = BTreeMap::new();
|
||||
for mapping in &request.mappings {
|
||||
if choices.insert(mapping.source, mapping).is_some() {
|
||||
@@ -787,6 +868,15 @@ pub fn plan_transition(
|
||||
let mut created = e.clone();
|
||||
created.id = target;
|
||||
created.body = body;
|
||||
if request.direction == TransitionDirection::SaToOa
|
||||
&& operation_omissions.contains(source)
|
||||
&& let Some(SharedBody::Occurrence {
|
||||
body: OccurrenceBody::Exchange { operation, .. },
|
||||
..
|
||||
}) = created.shared_mut()
|
||||
{
|
||||
*operation = None;
|
||||
}
|
||||
created.alias = working.fresh_alias(
|
||||
&format!(
|
||||
"{}_{}",
|
||||
|
||||
Reference in New Issue
Block a user