Migrate SysML models
When you open an existing SysML v2 model in Syside v1, you may see errors that earlier versions didn’t report. This guide explains how to fix them, whether you work in the Syside VS Code Extension or with the Python library. If you have Python scripts written for an earlier version, update them as well.
Fix model errors
Run
syside check(Check command) from each project’s root folder. In the VS Code Extension, the Problems panel lists the same errors and warnings with their rule IDs.Fix any
reference-errordiagnostics first, then runsyside checkagain.For each remaining error, find its rule ID below and follow the instructions. Then fix the warnings, as described in Fix model warnings.
Feature reference expression access
error (feature-reference-expression-access): Feature reference must be accessible from
the outer scope, did you mean to use chain notation?
Rule: feature-reference-expression-access. Use the fix for your case:
If the path starts from a usage, replace
::with.after the usage’s name.// before action def Responses { action restart; action shutdown; } action def FaultHandling { action responses : Responses; ref action recommendation = responses::restart; } // after action def Responses { action restart; action shutdown; } action def FaultHandling { action responses : Responses; ref action recommendation = responses.restart; }
If the path starts from a definition’s name, use a feature typed by that definition instead. For example, to read a feature of a case’s
subject, start the path with the subject’s name.// before part def BatteryMonitor { attribute reportedAccuracy : ScalarValues::Real; } verification def VerifyMonitorAccuracy { subject monitor : BatteryMonitor; action evaluateData { in measuredAccuracy : ScalarValues::Real = BatteryMonitor::reportedAccuracy; } } // after part def BatteryMonitor { attribute reportedAccuracy : ScalarValues::Real; } verification def VerifyMonitorAccuracy { subject monitor : BatteryMonitor; action evaluateData { in measuredAccuracy : ScalarValues::Real = monitor.reportedAccuracy; } }
If a name reaches a feature of another definition without a path, through an import or an alias, add a reference typed by that definition and chain through it. The diagnostic’s note names the element that owns the feature.
// before part def Hazards { part overheating; } analysis def AnalysisABC { private import Hazards::*; ref part mainHazard = overheating; } // after part def Hazards { part overheating; } analysis def AnalysisABC { ref part hazards : Hazards; ref part mainHazard = hazards.overheating; }
An alias is fixed the same way: replace
alias SOI for Vehicle::powertrain::battery;withref part SOI = vehicle.powertrain.battery;afterref part vehicle : Vehicle;. When the note names a usage, such asVehicle::powertrain, start the chain at the definition that owns it.If a filter reads a metadata attribute, use a cast such as
(as Review).isApproved. A filter that only checks for a tag, such asfilter @Review;, needs no change.// before metadata def Review { attribute isApproved : ScalarValues::Boolean; } view def ApprovedOnly { filter @ Review and Review::isApproved; } // after metadata def Review { attribute isApproved : ScalarValues::Boolean; } view def ApprovedOnly { filter @ Review and (as Review).isApproved; }
After this change, tables or diagrams that use the filter may show fewer elements because it now checks the attribute value correctly.
Usage types
error (view-usage-types): A view usage must be defined by a single view definition
error (enumeration-usage-types): Enumeration usage must be defined by a single
enumeration definition
error (item-usage-types): An item usage must only be defined by item definitions or
KerML structures
These rules check which definitions can type a usage, as required by chapter 7 of the SysML v2 specification. Syside v1 adds these checks, so an existing model may report errors even if it passed validation before. The fix depends on the kind of usage.
Single-definition usages
These usages must be defined by a single definition of their own kind:
Enumeration usages also need a single definition. See Enumeration usages for their fix. If a usage is typed by a definition of the wrong kind, see Matching-type usages.
If the usage lists several definitions, create a definition that specializes all of them, then type the usage by that new definition. The new definition can be concrete even if one of its parents is
abstract. If an extra definition only sets values, you can move those values into the usage’s body instead.// before abstract view def Filter_PartsActions { filter ( as SysML::PartUsage hastype SysML::PartUsage or as SysML::ActionUsage hastype SysML::ActionUsage ); } occurrence def Diagrams { view GV_PartsActions : StandardViewDefinitions::GeneralView, Filter_PartsActions; } // after abstract view def Filter_PartsActions { filter ( as SysML::PartUsage hastype SysML::PartUsage or as SysML::ActionUsage hastype SysML::ActionUsage ); } view def GeneralView_PartsActions specializes StandardViewDefinitions::GeneralView, Filter_PartsActions; occurrence def Diagrams { view GV_PartsActions : GeneralView_PartsActions; }
If the usage has a semantic metadata tag (metadata that specializes
Metaobjects::SemanticMetadata), the tag makes the usage specialize its base feature. This gives the usage a second definition. Move the tag to the usage’s definition, then type the usage by that definition alone. This applies to requirements, concerns, constraints, cases, views, viewpoints and renderings.// before concern def Tracked; abstract concern trackedConcerns : Tracked [*]; metadata def <tracked> TrackedMetadata specializes Metaobjects::SemanticMetadata { :>> baseType = trackedConcerns meta SysML::Type; } concern def Cost; concern def ProjectConcerns { #tracked concern cost : Cost; } // after concern def Tracked; abstract concern trackedConcerns : Tracked [*]; metadata def <tracked> TrackedMetadata specializes Metaobjects::SemanticMetadata { :>> baseType = trackedConcerns meta SysML::Type; } #tracked concern def Cost; concern def ProjectConcerns { concern cost : Cost; }
Moving the tag means an
@trackedfilter no longer selects the usage. If you need the filter to keep selecting it, leave the tag on the usage and make its definition specialize the type of the tag’s base feature (Trackedin this example):// after concern def Tracked; abstract concern trackedConcerns : Tracked [*]; metadata def <tracked> TrackedMetadata specializes Metaobjects::SemanticMetadata { :>> baseType = trackedConcerns meta SysML::Type; } concern def Cost specializes Tracked; concern def ProjectConcerns { #tracked concern cost : Cost; }
Matching-type usages
These usages can have multiple definitions, but only of their own kind or the matching KerML classifier:
A usage and its definition must describe the same kind of thing. An attribute def
describes a value, while an item def describes an object. If you type an item by
an attribute def, change either the usage’s keyword or the definition’s keyword to
match what you’re modeling.
Use attribute for data typed by an attribute def or a ScalarValues type. If
you’re modeling an item, use an item def for its definition instead.
The same requirement applies to single-definition usages. For example, a requirement
typed by a constraint def needs a requirement def. A concern, including a
frame concern, needs a concern def. A mismatch reports
requirement-usage-types.
// before
attribute def ManifestEntry { attribute stationId : ScalarValues::String; }
action def LoadVehicle {
in item manifest : ManifestEntry [*] ordered;
out item doorClosed : ScalarValues::Boolean;
}
// after
attribute def ManifestEntry { attribute stationId : ScalarValues::String; }
action def LoadVehicle {
in attribute manifest : ManifestEntry [*] ordered;
out attribute doorClosed : ScalarValues::Boolean;
}
A frame concern also reports
requirement-usage-types when its
concern def has the same name as the requirement def that frames it. Inside
requirement def Safety, the name Safety means that definition before any imported
Safety, so qualify the name:
// before
package Needs {
concern def Safety;
}
package Reqs {
private import Needs::*;
requirement def Safety {
frame concern : Safety;
}
}
// after
package Needs {
concern def Safety;
}
package Reqs {
private import Needs::*;
requirement def Safety {
frame concern : Needs::Safety;
}
}
Enumeration usages
An enum declared without def is an enumeration usage: it picks a value from an
enumeration definition. If your enum lists its own values, move those values into an
enum def and type the usage by it.
The enumeration-usage-types rule applies only outside an enumeration definition, where each usage needs a single enumeration definition.
// before
part def MyContext {
enum choices {
enum choice1;
enum choice2;
}
}
// after
enum def Choices {
enum choice1;
enum choice2;
}
part def MyContext {
enum choices : Choices;
}
Boolean expression results
error (boolean-expression-result-type): Boolean expression result must be boolean
evaluable
Rule: boolean-expression-result-type.
The result of a Boolean expression, such as a constraint body, must be true or
false. A common cause is ^ written for exclusive or: in SysML, ^ raises a number
to a power. Use xor instead.
// before
part def Valve {
attribute isOpen : ScalarValues::Boolean;
attribute isShut : ScalarValues::Boolean;
assert constraint exactlyOne { isOpen ^ isShut }
}
// after
part def Valve {
attribute isOpen : ScalarValues::Boolean;
attribute isShut : ScalarValues::Boolean;
assert constraint exactlyOne { isOpen xor isShut }
}
Bindings between features of different types
error (type-error): Antenna::externalIn does not conform to RFPort::'~RFPort'
Rule: type-error. A binding connects two features that must have conforming types. Syside v1 reports a binding between a typed feature and an untyped one, which earlier versions accepted. Give the untyped feature the same type:
// before
port def RFPort;
part def Antenna { port externalIn; }
part def Gateway {
part rfAntenna : Antenna;
port extLoraIn : ~RFPort;
bind extLoraIn = rfAntenna.externalIn;
}
// after
port def RFPort;
part def Antenna { port externalIn : ~RFPort; }
part def Gateway {
part rfAntenna : Antenna;
port extLoraIn : ~RFPort;
bind extLoraIn = rfAntenna.externalIn;
}
The same error appears when externalIn is typed RFPort: a binding makes both
sides one feature, so they need the same type, conjugation included. The fix is the
same.
Names from indirect Sysand dependencies
error (reference-error): No Namespace named 'CLib' found.
A project can now use names only from the Sysand projects it depends on directly,
the ones listed under usage in its .project.json. Names that a dependency brings in
from its own dependencies no longer resolve. In a Sysand workspace, the same applies
to each member project. Add every project whose names the model uses as a direct
dependency. For example, if your project depends on b-lib, which depends on c-lib,
and your model imports CLib from c-lib:
syside project add acme/c-lib --version-constraint 1.0.0
This adds c-lib to usage in .project.json. Its files are usually installed
already, since b-lib brought them in.
Fix model warnings
Rules new in Syside v1 also report warnings. syside check still passes with them,
or fails on them if you run it with --warnings-as-errors. Fix them so that they
don’t hide new ones. For each warning, find its rule ID below and follow the
instructions.
Renamed reserved features
warning (reserved-feature-name): Feature with reserved name `this` should only be
redefined by features with the same name
Rule: reserved-feature-name.
The library features self, that and this have fixed meanings, so a feature that
redefines one must keep its name. Models often redefine this under their own name,
such as context, so that an action can reach the part that performs it. Keep the
reserved name, and give your name as the short name. Feature chains through the short
name work as before:
// before
part def Vehicle {
attribute mass :> ISQ::mass;
}
action def Drive {
ref part context : Vehicle :>> this;
attribute load :> ISQ::mass = context.mass;
}
// after
part def Vehicle {
attribute mass :> ISQ::mass;
}
action def Drive {
ref part <context> this : Vehicle :>> this;
attribute load :> ISQ::mass = context.mass;
}
The same form fixes a renamed self or that, such as
abstract ref occurrence <thisFailureMode> self :>> self;. A specializing definition
can redefine the feature by its short name, such as
ref occurrence :>> thisFailureMode : BrakeFailure;.
This form fails with namespace-distinguishability in two cases:
The redefinition is written in the body of a typed action usage, one that names an action definition as its type, such as
action drive : Drive { ... }inside a part definition. The same redefinition in the action definitionDriveworks, and so does one in an untypedaction drive { ... }.A nested action redefines the feature, such as
ref part :>> context;in a subaction. The redefinition inherits the namethis.
In the first case, you can remove the redefinition instead and use the part’s
features by name, such as mass instead of context.mass. This reads the
values of each part usage, where the redefinition read the definition’s, so a part
usage that overrides mass gets a different result. Check the values that depend on
it. In the second case, keep the existing redefinition for now: it gives the warning
above, not an error.
A grid column that finds the feature by name needs updating (see Migrate grid views).
Decision node successions
warning (decision-node-successions): Outgoing successions from decision nodes should
be conditional
Rule: decision-node-successions.
Give each succession out of a decide an if guard, and the last one else:
// before
action def HandleFault {
in attribute isCritical : ScalarValues::Boolean;
first start;
then decide;
then shutDown;
then restart;
action shutDown;
action restart;
}
// after
action def HandleFault {
in attribute isCritical : ScalarValues::Boolean;
first start;
then decide;
if isCritical then shutDown;
else restart;
action shutDown;
action restart;
}
Rule settings
You can change the severity of some rules in the [lint]
table of syside.toml. Of the rules on this page, feature-reference-expression-access,
reserved-feature-name, decision-node-successions and type-error allow this. Set
lint.feature-reference-expression-access
to "warning", or to "off" to hide it.
[lint]
feature-reference-expression-access = "warning"
Note
The validation rules list marks each configurable rule with a icon.
Instructions for an LLM agent
If an LLM agent helps you migrate the model, give it the migration guides and these instructions:
Fix one rule at a time across the model, then run
syside check --warnings-as-errors. Stop when it exits 0, or when all that remains is what these instructions leave on purpose: areserved-feature-namewarning for a redefinition the guide says to keep, or errors in a copied library file.After each rule, export the views with
--allow-errors, since the model may still have errors, and compare them with the Syside v0.11 exports (Compare the exports). A passing check doesn’t prove a fix kept the values.Make only the changes needed to fix that rule. Don’t rename or restructure anything else.
Never make a check pass by downgrading a rule in
[lint]or adding anexcludeentry.If a library file copied into the project has errors, report them and leave the file unchanged.
Ask before making a modeling decision, such as choosing the kind of a definition.
Report every change in the exports and ask a person to review it.