· 5 min read
Nominal, Alternate, Exception: Routes a Model Works Out for Itself
A derived state machine arrives already colored by route — green, blue and red. Only one thing in the source model was ever annotated. Here is how the other two colors are computed, and why the stamps that carry them are deliberately not semantic metadata.
Open a derived state machine in Cameo and it arrives already colored. Green for the run you expect. Blue for the legitimate variations. Red for the parts only reachable when something has gone wrong. It looks like someone spent an afternoon in the style editor.
Nobody did. One element in the source model was annotated. The other two colors were computed by walking the graph, and the walk is the interesting part.
What you actually write
Exactly one thing: the branch that means something failed.
#exception
action 'Reject Card' { out cardKept : Boolean; }
That is the whole of it. No #nominal, no #alternate. There is no keyword for
“this is the main line,” and there is no keyword for “this branch is a valid
variation,” because neither of those is something you know that the model does
not.
How the other two are worked out
The derivation walks every branch of every decision — ordinary branch coverage, so the number of traversals grows with the number of branches rather than as 2ⁿ. Each traversal is then classified by what it contains:
- The first route that reaches the goal is the nominal path.
- Any other route that reaches the goal is an alternate. It is correct; it simply is not the one you would describe first.
- A route that passes through something you marked
#exceptionis an exception path.
Look at what that costs you to state. The alternate is derived because there is nothing to say: where a decision has two valid branches, the use case does not nominate one as the main line, because there isn’t one. The nominal path is derived because “the first way through” is a fact about the flow. Only the valence of a failure — that this outcome is bad rather than merely different — is information the graph cannot carry, so that is the one thing you supply.
Least severe wins
Here is the rule that makes the coloring readable, and it is easy to miss.
A state can lie on more than one route. Authenticate Customer is on the
nominal path, and it is also on the exception path, because the run that ends in
a rejected card went through authentication to get there.
When routes disagree, the least severe classification wins. That state comes out green.
The reason is worth sitting with: the prefix every run shares is normal operation. If a state went red the moment any failing route touched it, almost the entire machine would be red, and the color would tell you nothing. Under “least severe wins,” what comes out red is precisely the set no expected run reaches — which is exactly the set worth picking out.
The part that surprises people
These three stamps are plain metadata defs. They are not semantic
metadata, and that is deliberate.
metadata def <nominalPath> NominalPath;
metadata def <alternatePath> AlternatePath;
metadata def <exceptionPath> ExceptionPath;
Compare that with #exception, which specializes SemanticMetadata and carries
a baseType:
metadata def <exception> Exception :> SemanticMetadata {
:> annotatedElement : SysML::ActionUsage;
:> annotatedElement : SysML::SuccessionAsUsage;
:>> baseType = exceptionBehaviors meta SysML::ActionUsage;
}
baseType asserts that the annotated element is that type. For #exception
that is exactly right: the action is an ExceptionBehavior, which is why a
project can declare action def PaymentDeclined :> ExceptionBehavior; and have
every usage classify with nothing written on it.
For a route stamp there is no such type to reach for. A state on the exception path is not a kind of state. It is an ordinary state that happens to lie on one route — and “lies on” is a relation between an element and a traversal, not a classification of the element. Inventing a base type purely to be the target of the assertion would be circular, and nothing a project could usefully extend.
It would also be false for half of them. A baseType pins one metaclass, and
these are applied to transitions as well as states.
A retreat worth admitting
The three stamps declare no annotatedElement either, and that one is a
concession rather than a principle.
Naming two — StateUsage and TransitionUsage, since the stamps go on both —
left every annotated state outlined in red in Cameo. A validation constraint that
marks correct output as invalid is worse than no constraint at all, so the
constraint came off. A plain metadata def cannot be misapplied by this tool in
any case: nothing but the derivation ever writes one.
Transitions need the long form
One syntactic detail that costs an hour if you meet it cold. A state accepts prefix metadata:
#NominalPath
state validateSuggestion {
do 'Suggest a Topic'.'Validate Suggestion';
}
A transition does not. So the derivation names the transition and annotates it by reference — this is real generated output, name and all:
transition awaitSuggestionToValidateSuggestionTransition
first awaitSuggestion
if submissions == SubmissionsKind::open
then validateSuggestion;
metadata NominalPath about awaitSuggestionToValidateSuggestionTransition;
The same restriction is why #exception gained a second annotatedElement for
SuccessionAsUsage. Valence really belongs on the route rather than on the
behavior — the same action can be nominal on one route and exceptional on
another — but #exception if … and #exception else … are both syntax errors.
To annotate the branch, you name it and point at it:
succession errorBranch first check if not 'Check'.ok then 'Log Failure';
metadata exception about errorBranch;
That needs the explicit succession … if … form, after which else no longer
parses, so both branches get written out.
What the stamps are for
Color is the visible half. A Cameo style sheet keys on
ByMetadataAnnotationCondition and paints the machine by route, which is how the
view colors itself.
The other half is query. Filter a table on @UseCaseSemantics::ExceptionPath and
you have every element of the model reachable only when something has failed —
the off-nominal surface, listed, without anyone maintaining a list. That question
has no answer if the classification lives in the tool’s head rather than in the
model.
The shape of the idea
A route is a traversal. It is not an element you can select, and it is not a property you can set. It is a fact the derivation computes by walking, and the stamps are how a computed fact becomes something the model can carry.
Which is why the vocabulary is as small as it is. You declare the exception, and the routes get walked.
More of this, on video
Walkthroughs in SysML v2 and MBSE tooling, with the model on screen.
