Grammar Conformance Audit — reserved words and state/action notation¶
This page is the evidence behind two findings of the pilot differential: that OpenSysML reserved words the OMG grammars do not, and rejected state-machine notation they allow. It lists every reserved word and every accepted state-machine construct, checked against the pinned OMG grammars, and states the resulting policy for each.
Ground truth¶
The grammars are the ones at the pin in scripts/pilot-pin.sh
(PILOT_TAG=2026-08, Systems-Modeling/SysML-v2-Pilot-Implementation), read
from a sparse clone rather than vendored:
org.omg.kerml.xtext/src/org/omg/kerml/xtext/KerML.xtext— cited asKerML.xtextorg.omg.sysml.xtext/src/org/omg/sysml/xtext/SysML.xtext— cited asSysML.xtextorg.omg.kerml.expressions.xtext/src/org/omg/kerml/expressions/xtext/KerMLExpressions.xtext— cited asKerMLExpressions.xtext
A word counts as standard when it appears as a quoted literal in one of those files, in the position where OpenSysML accepts it. Line numbers refer to the pinned revision.
Verdict per word¶
None of the eleven words below appears as a literal in any of the three grammars.
They are not notation OMG defines, so reserving them only stopped models from using
them as names. Each is now an ordinary name, recognized contextually where OpenSysML's
own notation needs it, which is how point, on and var were already treated.
| Word | KerML.xtext |
SysML.xtext |
KerMLExpressions.xtext |
Verdict |
|---|---|---|---|---|
choice |
absent | absent | absent | unreserve; notation is an OpenSysML extension (warning) |
decision |
absent | absent | absent | unreserve; an ordinary name only — the action node spelled decision is no longer accepted, write decide |
deep |
absent | absent | absent | unreserve; notation is an OpenSysML extension (warning) |
defer |
absent | absent | absent | unreserve; notation is an OpenSysML extension (warning) |
done |
absent | absent | absent | unreserve; silent — see "done is a library name, not notation" |
final |
absent | absent | absent | unreserve; an ordinary name only — neither the action node nor the state marker spelled final is accepted, write done |
history |
absent | absent | absent | unreserve; notation is an OpenSysML extension (warning) |
initial |
absent | absent | absent | unreserve; an ordinary name only — neither the action node nor the state marker spelled initial is accepted, write first <name> and entry; then <state>; |
junction |
absent | absent | absent | unreserve; notation is an OpenSysML extension (warning) |
region |
absent | absent | absent | unreserve; an ordinary name only — the orthogonal-region member spelled region <name> { … } is no longer accepted, mark the owning state's body parallel |
shallow |
absent | absent | absent | unreserve; notation is an OpenSysML extension (warning) |
done is the acceptance test that unreserving worked: the bundled normative
library declares features named done (Systems Library/Actions.sysml:50,
Items.sysml:34, Parts.sysml:29, States.sysml:34, UseCases.sysml:28) and
references them (Flows.sysml:57, :69). OpenSysML used to report an error on every one.
done is a library name, not notation¶
The OMG corpora write then done; (Systems Library/Actions.sysml:230;
training examples 17. Control/Fork Join Example.sysml:39, Decision
Example.sysml:32, Control Structures Example.sysml:27, 35. Use Cases/Use
Case Usage Example.sysml:35) and snapshot junked = done;
(27. Occurrences/Time Slice and Snapshot Example.sysml:25). Those are plain
references to Actions::Action::done, a feature of the standard library, not a
keyword. The parser reads done; as an anonymous final node and then done;
as a succession targeting the done library feature. Both stay silent:
warning on them would warn on OMG-authored files, which the classification
forbids. In a state body then done; names the same library feature and states
that the machine completes; the final <state>; marker that once spelled it is
no longer accepted.
Verdict per construct¶
Positions checked against SysML.xtext StateBodyItem (1755-1770),
StateDefBody (1744-1746), StateUsageBody (1836-1838), TransitionUsage
(1851-1880), and the action node productions (1666-1730).
Standard — silent¶
| Construct | Citation |
|---|---|
entry <action> state subaction |
SysML.xtext:1772-1778 (EntryActionMember, EntryActionKind : 'entry') |
do <action> state subaction |
SysML.xtext:1780-1786 (DoActionMember, DoActionKind : 'do') |
exit <action> state subaction |
SysML.xtext:1788-1794 (ExitActionMember, ExitActionKind : 'exit') |
parallel before a state body |
SysML.xtext:1745, :1837 (isParallel ?= 'parallel') |
then <target>; succession |
SysML.xtext:1705, :1711, :1724, :1799; KerML.xtext:894 |
first <source> |
SysML.xtext:1385, :1720, :1855; KerML.xtext:893 |
done; / then done; final node |
no literal; a reference to Actions::Action::done, written by the OMG corpora (above) |
fork <name>;, join <name>;, merge <name>;, decide <name>; |
SysML.xtext:1684, :1678, :1666, :1672; admitted in a state body by StateBodyItem → BehaviorUsageMember (SysML.xtext:1761-1763) |
accept <trigger> [via <port>] |
SysML.xtext:1447, :1894 (trigger = 'accept'), via at :1450 |
when <expr> trigger |
SysML.xtext:1483-1485 (ChangeTriggerKind : 'when') |
transition [<name>] first <src> … then <tgt>; |
SysML.xtext:1851-1880 (TransitionUsage) |
state <name>; / state <name> { … } |
SysML.xtext:1733, :1741, :1833 |
send, terminate, assign, perform, if/else, while, loop, for |
SysML.xtext:1500, :1643, :1540, :1412, :1600 and the loop node productions |
namespace N; / namespace N { … } in a .kerml file |
KerML.xtext:119, :124-125 ('namespace' Identification?), :128 (NamespaceBody : ';' \| '{' … '}') |
OpenSysML extension — warning nonstandard-notation¶
No production in the pinned grammars allows these anywhere. They are still parsed (removing notation users already write is worse than diagnosing it) and are reported as a warning by default. Under the opt-in strict conformance mode the same findings are errors. Strictness changes only the severity of this table's diagnostics, so the tree, the spans and the messages are the same in either mode. Strict mode is what answers the question "is this file conforming SysML v2?"; the default mode's acceptance of these constructs is intentional and unchanged.
The removed OpenSysML-only spellings then <source> <target>;, member-leading
<source> then <target>;, done <name>;, the orthogonal-region member
region <name> { … }, the state markers initial <state>; and final <state>;
and
transition [<name>] <src> to <tgt>; are no longer accepted. Use
succession first <source> then <target>;, done;, a parallel state body with
one state substate per region, entry; then <state>;, a transition targeting
done and transition [<name>] first <src> … then <tgt>; instead.
| Construct | Why it is not standard |
|---|---|
choice <name>;, junction <name>; |
no literal; no pseudostate production of any kind |
history <name>;, shallow history <name>;, deep history <name>; |
same |
defer <event> [, <event>]*; |
no defer literal; StatePerformance::deferrable has the semantics but no notation |
Two further findings are about position rather than spelling: the construct is standard where a production allows it and an OpenSysML extension everywhere else, so the warning names the position, not the keyword.
| Construct | Where it is standard | Why it is not standard elsewhere |
|---|---|---|
assume <constraint>;, require <constraint>; |
a requirement, concern, viewpoint or objective body | RequirementConstraintMember (SysML.xtext:2039) is the only production that admits it |
a one-ended first <node>; |
an action body | InitialNodeMember is reachable from ActionBodyItem alone (:1376), never from DefinitionBodyItem (:516); elsewhere a succession names both ends, first <source> then <target> |
Chain redefinitions — redefinition-through-reference¶
A redefinition target written as a feature chain of two or more segments,
:>> mid.leaf.value = 99.0;, is standard KerML semantics: the chain-expression
is itself a feature hosting the chain — its featuring type from the first
segment and its featured type from the last (KerML 1.0 §7.3.4) — and the host
feature is redefinable (§8.3.3.3). OpenSysML applies the redefining member
below every composite feature the chain walks: every object of the type behaves
as if the chain had been written as nested redefining usages
(part :>> mid { part :>> leaf { attribute :>> value = 99.0; } }), carrying a
declared value (= or default =), a declared type, a multiplicity and a body
of its own. The pinned pilot evaluator accepts the notation but reads the
original value — a pilot-evaluator gap, not a divergence the model is warned
about (see the pilot differential).
Rules of the reading, in detail:
- The shorthand ranks exactly as the nested-body form written in the same body does: a nested-body redefinition declared by the chain's owner or something specializing it wins; the child's type's own redefinition and bodies in types the owner specializes lose.
- Each chain applies below every object of the declaring type, including every
element of a multi-valued intermediate (
part wheels : Wheel[2];thenattribute :>> wheels.radius = 0.4;redefinesradiuson each wheel). - A value the redefining member declares is evaluated in the declaring body's
scope, so
= factor * 2.0reads the outer feature exactly as the nested-body form does. - A valued chain below a feature bound to an existing object follows the
body's rule for an inherited value: one declared in a more specific body
governs the binding (a fresh object materializes below it and the bound one
keeps its own value), while one written in the same body as the binding is
rejected as a restating body is (
feature both valued and restated in a body). A chain declaring only a type or multiplicity conflicts with nothing. - A chain walking through a reference — a
refusage, a port or asubject— owns no object below the reference for the redefinition to land on. OpenSysML reportsnested redefinition through reference <segment> has no owned object to redefine onas an error in every mode, and the redefinition is never applied at runtime. - A chain whose target does not resolve declares no nested redefinition and is reported by name resolution instead.
Removed extension notation — no longer accepted¶
An inline condition introduced by a keyword (assert <expression>; or
assume <expression>; in a constraint body, assume <expression>; or
require <expression>; in a requirement-style body) was an OpenSysML extension and
is now a parse error: AssertConstraintUsage (SysML.xtext:2007-2013) and
RequirementConstraintUsage (:2066-2071) allow a reference subsetting or a
constraint declaration after the keyword, never an expression. The standard
spellings, which are unchanged, are a bare condition in a constraint
body (total <= limit), assert [not] <reference>;,
assert constraint { … }, and assume/require constraint { … } in a
requirement body. A requirement body allows no bare condition
(RequirementBodyItem, :2039-2047). If you had a negated keyword form, write the
negation as not (…) inside the condition to keep the same meaning.
A spelling that is a pure alias of a standard construct is removed rather than
warned, so it is no longer accepted and has no row here. return <expression>;
in a calculation body is now a parse error; a computed result is written as
the body's trailing expression (ResultExpressionMember, SysML.xtext:1967).
return itself is unchanged as the result parameter declaration.
bind <feature> = <expression>; is removed the same way: a binding relates two
ConnectorEndMembers (BindingConnectorAsUsage, SysML.xtext:1020), so an
expression right end is now a parse error. Write the expression as the
feature's value (out result : Real = x * 2.0;), or declare a feature holding
the result and bind to it (attribute b2 = a + 1; then binding bind b = b2;).
Standard bindings (bind a = b;, with qualified, chained and indexed ends)
are unchanged.
The same holds for the two state-machine aliases. initial <state>; said where
a machine starts, which EntryTransitionMember (SysML.xtext:1796-1801) writes
as entry; then <state>;, and transition [<name>] <src> to <tgt>; gave a
transition's ends, which TransitionUsage (:1851-1880) writes with first and
then. to is a literal (:1077, :1168, :1253, :1287; KerML.xtext:838,
:1009) in connector, interface, message and flow ends only. Both are parse
errors now, and initial, which neither grammar reserves, stays an ordinary
name.
KerML-only notation in a .sysml file — warning kerml-notation¶
namespace is a literal in KerML.xtext only (:125); SysML.xtext does not have
it. A .sysml file's root is RootNamespace : PackageBodyElement*
(SysML.xtext:38), which allows package members, element filters, aliases and
imports, but not a namespace declaration. Both spellings, namespace N; and
namespace N { … }, are legal KerML, so the semicolon form is not the problem;
the problem is using the production in a SysML file at all. It is still parsed,
with a warning in .sysml and silently in .kerml.
Reserved by SysML only — a name in a .kerml file¶
A word is reserved by the grammar of the file it is written in, so a literal that
appears only in SysML.xtext is an ordinary name in KerML. These four are reserved
or not depending on the file kind; they keep their SysML meanings in .sysml, where
the literal exists.
| Word | KerML.xtext |
KerMLExpressions.xtext |
SysML.xtext |
Corpus witness |
|---|---|---|---|---|
at |
absent | absent | :1480 (TimeTriggerKind) |
expr at { … }, Variable Feature Examples/Enhancements/ExtendedOccurrences.kerml:16 |
while |
absent | absent | :1617 (WhileLoopActionUsage) |
expr while { … }, same file :25 |
merge |
absent | absent | :1666 (MergeNode) |
member step merge : …, Enhancements/TimeVaryingSteps.kerml:4, imported at :6 |
decide |
absent | absent | :1672 (DecisionNode) |
member step decide : …, same file :25, imported at :27 |
featured by is the opposite case: TypeFeaturingPart (KerML.xtext:569-571)
and OwnedTypeFeaturing (:659) are KerML productions with no SysML
counterpart, so the clause is parsed everywhere and warned as kerml-notation
in a .sysml file, the same treatment namespace gets.
Judgment calls¶
Everything above follows directly from a grammar citation. The decisions below do not, and are recorded here so a reviewer can disagree with them:
donesilent. No grammar has the literal.doneis classified standard because the OMG corpora write it (as a library-feature reference) and a warning there would be a false positive;finalappears in no OMG file and is no longer notation in any position.- An alias of a standard node is removed, not warned. The action nodes
spelled
initial,finalanddecisionwere pure aliases offirst,doneanddecide, so they are gone rather than diagnosed; each word stays an ordinary name. The state markersinitial <state>;andfinal <state>;and the transition spellingtransition <src> to <tgt>;are gone for the same reason. - Completion is stated, not inferred. A machine completes when a transition
reaches
done, the library feature the OMG corpora already reference in a state body. A state with no outgoing transition does not complete on its own, because an ancestor or cross-region transition may still leave it. - State-body
fork/joinsilent. They are action node literals, andStateBodyItemallows aBehaviorUsageMember, so they are read as standard in a state body even though the pilot's state examples do not use them there.