v0.0.6: Calc release
0.0.6 — 2026-08-13
The executable-model release: a calc body is now a computation rather than a
single expression, collections and sequences are evaluable, specialization,
redefinition and variation resolve to one slot each, and the standard
behavioural and structural notation the public SysML v2 models are written in
parses and runs. Five of the eight Open-MBEE SysML v2 models now load with zero
diagnostics, and a full lunar-descent model — curvilinear equations of motion,
a fixed-step RK4 integrator, and an in-model trajectory history — reproduces a
Python reference to ~1e-11.
Language and semantics
- A
calcbody is computational: statements, local declarations,if/else,
whileandforloops, andreturn. A calculation's declared result is
answered after its steps have run, so a body may compute towards it instead of
being one expression; a succession among a calculation's members is not a step. - A calc usage's
outfeatures are readable — every one of them, not only a
designated result — and an evaluation of a multi-output calc with no result
says so, naming the outputs and pointing at the usage, rather than answering
one of them arbitrarily. - An
outfeature assigned by a body statement is bound, including accumulation
into it across a loop, so a trajectory history exists in-model. An output given
both an initializer and a body assignment is a typed error, and a value the
bodyreturns no longer leaks into an output the same body assigned. - A nested calc usage binds its inputs in the environment reading it, so an
argument naming a feature of the enclosing body resolves to that body's value
rather than to the declaration's. - Inputs bind once per activation (KerML 7.4.9): two outputs of one usage can
never come from different input bindings, so readingp.a, assigning to the
usage's input, then readingp.banswers one consistent state instead of
silently mixing two. A usage declared in an action body or among a state
machine's members binds from the values the behaviour has reached. - Sequence indexing (
s#(i)), ranges (1..n, evaluated as the ordered integer
sequence the library declares), and the KerML collection operations —
including,excluding,size,isEmpty,head,tail,select,
collect,sum,min,maxand the rest — are evaluable, with a sequence
expression's results flattened as the library specifies. [*]means0..*, not*..*, so an unbounded part slot instantiates instead
of erroring; a feature chain reaches through a multi-valued feature
(sum(subsystem.volume)), which is what every roll-up model exists to
demonstrate; and a subset of a redefined collection is populated under either
name.- Specialization and redefinition merge: inherited members are merged through
redefinition rather than discarded, nested values of a redefined part survive,
and a renaming redefinition shares one slot whichever of its names carries
the value — base, intermediate or leaf, at any depth. Supplying a value under
two names for the same feature is a typed error, not a silent pick. - A struct-typed attribute valued by a nested body (
attribute :>> material { attribute :>> v = 3.0; }) materializes; a body and= expron the same
feature is a typed error. - Variation points resolve and a selected variant materialises — once, and per
owning instance, so two objects of one type may select differently. A variation
point that inherits its variation-ness is recognised, a variation offers only
its real variants as choices, a selection naming a non-variant is rejected, and
avariantoutside a variation keeps its value and is reported. - Visibility: a protected import is reachable from a specialization, an
unqualified reference no longer reaches a privately imported name, and an
exposeoutside a view usage is reported. viewandviewpointmembers have their own usage kinds.
Notation
- Standard behavioural notation parses and executes: named flows
(flow f from a.out to b.in),accept at/accept when/accept :> e
(named, short-named and nameless),send … viaandsend … to self,
then doneandthen loop … until,if/elsein an action flow,
exhibit statebodies, transition triggers with payload parameters visible to
the guard and effect, performed transition effects, entry-succession initial
states and pending signals. - Structural and interface notation: conjugated ports (
~P, read from the
feature typing, with aport-conjugationwarning on like-typed interface ends
andattribute x : ~Prejected),endusages including the default
end;interface end,require/assumeby qualified reference
(require Pkg::req { }), andsnapshot/timesliceoccurrence portions. The
standard view library ships with the binary. - The compact transition form with a statement effect
(transition active to fin do perform Bump;,do assign c := c + 1;) no
longer demands a second semicolon;;;is now an error rather than silently
accepted; and the compacttransition <src> to <tgt>spelling is recorded as a
Systemica extension rather than presented as OMG notation. - An anonymous
entry action { … }/do action { … }/exit action { … }
body lowers and executes instead of failing at runtime, and a named or empty
action body parameter runs as the loop body.
Runtime and tooling
- A fifth runaway bound,
SYSML_MAX_ELEMENTS(default 1 000 000), bounds the
collection elements one evaluation holds rather than the work a run does: an
element is a 104-byteValueliving as long as the collection holding it, so
the default holds ~104 MB, in the band the other defaults were sized against.
Every materialising path is charged — a range, a sequence literal,->collect
and the other collection operations — and exceeding it is
ErrElementLimitExceedednaming the variable, not the step limit:1..10000000
used to conjure ~1 GB before the step budget reported it. - Activations are scoped, so what a run holds is what it is using: an action
node's body ends the activation it ran in, and an evaluation outside a body — a
decision or transition guard, a change condition or duration, an inline node
expression, an attribute or slot default, an action argument, a constraint
check — runs in a scope of its own. A decision revisited after its body
assigned reads its usage again over those values instead of the first
evaluation's result. %budgetprints the five bounds a session runs on with the variable that
raises each, and a literal expression that spends one is answered with that
failure instead of "no declarations loaded".- Connector usages materialise, including an untyped one
(interface iface connect a.p to b.q;, previously an<unknown>slot), and a
connection's ends are bound by reference to the features it connects rather
than to fresh copies, so a connection identifies what is connected. A selected
variation-interface connection is realised at runtime and routed for the object
that selected it, and connector cycles are guarded. - Features are read through the occurrence a part usage denotes, an unselected
variation read as the base of a feature chain is reported, and a REPL session's
own declaration answers a name the library also declares. - Runtime conformance fixtures fail on an undeclared parser diagnostic, closing
the gate hole that let a fixture execute while emitting a parse error.
Python bindings and sysml-grpc
Instantiatereturns every instance reachable from the root, so a Python caller
expands a composite slot (inst.engine.power) instead of holding a bare instance
id, and a slot the service could not evaluate is reported inSlotValue.error
rather than as a null value. On the client, slot values convert to Python
scalars, lists and nestedInstances, with the raw protobuf still reachable
throughget_slot()/raw_slots; attribute and item access raise
AttributeError/KeyError/SlotErrorrather than returningNone.python -m pysysml.generateemits a Python class per SysML definition —
properties that carry the static type and perform the runtime delegation, so an
editor completesinst.massand a type checker rejectsinst.mas.GetSymbol
reports the type facts this needs (type_infowith primitive reduction,
multiplicity, all specialization edges),pysysmlshipspy.typed, and
emission is deterministic so the output can be committed.GetServerInforeports the service's build version and the capabilities it
supports by name, so a client can require a capability instead of comparing
version strings. Typed generation requires thetype_factscapability and
fails naming the service in use, where it came from and how to replace it:
against the v0.0.5sysml-grpc, which predatestype_info, every generated
feature was typedobject, indistinguishable from one that is genuinely
untyped.- A generated module records the model source hash and the generator's emission
schema, andpysysml.generate --checkregenerates in memory and exits non-zero
when the committed module is missing or would change, writing nothing — a stale
module was previously found at attribute access, or never. TypedObject.from_instancerejects an instance of another definition, naming
both types, instead of failing later with a confusingTypeMismatchErroron the
first slot read;unchecked(instance)is the explicit escape hatch.Model.findaccepts a symbol's own id, the gRPC instance graph terminates on
recursive parts, and set-valued and unmaterialized slots serialize correctly.
pysysml on PyPI is versioned and released independently of this tag
(pysysml-v<version>): it resolves a sysml-grpc binary at runtime from
whichever release the caller names, so its version says nothing about which core
release it runs against.
Known limitations
- No element-wise or broadcast arithmetic over sequences:
(a + b)and
(2.0 * a)are type mismatches, whilea#(i) + b#(i)works. A multi-component
state is written out component by component. - A calc whose only output-capable feature is an
inoutcannot be read and
reports the misleading "no result expression"; aninoutalongside a declared
outworks. - Port conjugation is static only — nothing routes differently at runtime for
~P. timesliceandsnapshotportions parse and resolve but materialize as
<unknown>slots.- A
dobehaviour runs one action per round and does not repeat without
re-entry. - Mixed named-action-plus-inline-body notation on a state is unsupported rather
than guessed at. - The conformance diagnostic gate matches parser diagnostics only, so a
fixture with an unresolved reference still passes silently. - The OMG training corpus stands at its pinned ceiling of 98/100 files clean; the
remaining 2 files / 4 errors are OMG source-model bugs. - Of the Open-MBEE SysML v2 corpus,
spacecraft_example_model,
Spacecraft_SysMLv2_Simcenter_Studio,starkit,BallAndChainand
CubesatExampleload clean;Modeling_in_Time_And_Space(3),
Dragon(6, including a bareend;inside aconnection def, which is not
standard notation) andSpacecraft_Example_SysML2(115) do not. The 2019–20
pilot-syntax notebooks (block,value type,activity) are not SysML v2 and
are out of scope. - The macOS and Windows binaries are unsigned, so a browser download is
quarantined by Gatekeeper or flagged by SmartScreen. Install with Homebrew or
curl; see docs/MACOS_DISTRIBUTION.md.