Skip to content

Releases: Open-MBEE/OpenSysML

v0.1.2: QOL release

Choose a tag to compare

@HuiJun HuiJun released this 20 Aug 17:37
12fc358

0.1.2 — 2026-08-20

A measurement release. Two advisory harnesses now ask the OMG pilot implementation and the
pinned OMG grammars where this implementation differs from them, and most of the behavior below
is what they found — chiefly in KerML, which the pilot's own KerML validator now judges. A
.kerml file is read as KerML rather than as SysML written with other keywords, so a KerML
model 0.1.1 rejected may analyze clean here; notation accepted beyond the grammars now warns
where it used to be silent. Nothing was renamed and no interface changed.

The pilot implementation judges every corpus, KerML included

  • cmd/pilot-diff compares our diagnostics against the pinned OMG pilot implementation
    (2026-05, jupyter-sysml-kernel 0.60.1) file by file, over 338 files in seven roots: the OMG
    training corpus, the pilot's own SysML example and validation corpora, its KerML examples, our
    testdata, our examples and our probes. 221 files agree exactly. It is advisory — a harness that
    finds work, not a gate — so nothing in CI depends on it, and its committed baseline
    (docs/project/pilot-differential-baseline.json) makes a rerun a diff rather than a reading.
    On the 100-file training corpus both implementations report nothing at all.
  • The KerML corpus is judged by the pilot's own KerML validator, not by our reading of the
    KerML specification: scripts/pilot-kerml-validator/ValidateKerML.java registers the pilot's
    KerMLStandaloneSetup, loads sysml.library and the corpus into one EMF ResourceSet, and
    asks the pilot's IResourceValidator with CheckMode.ALL. It contributes no rule of its own,
    so a disagreement it prints is the reference's verdict. Over the pilot's 58 KerML examples, the
    diagnostics only we reported fell from 439 to 150 as the KerML work below landed — the syntax
    class from 360 to 140, and the genuine name-resolution class from 123 to 7 — and 33 of the 58
    files now agree exactly.
  • Six diagnostics the pilot reports and we do not are a defect in the pilot, not a gap here:
    EMF's unpaired-bidirectional-reference check firing on the pilot's own
    Type::ownedDisjoining / Disjoining::owningType opposite, reproducible from three lines
    (classifier A; classifier B disjoint from A;) in a fresh resource set. It is recorded with
    its reproducer rather than absorbed into our own numbers.
  • cmd/grammar-coverage measures the pinned OMG grammars against every corpus we hold:
    483 of 727 productions and 802 of 807 notational forms have input-presence evidence. The
    number is deliberately an over-approximation — presence of an input a production admits, never
    parser-execution coverage or compliance — so the page's useful reading is the five forms with
    no evidence anywhere, each adjudicated: the % remainder operator and prefix metadata on a
    namespace are implemented but exercised by nothing, and the named disjoining, conjugation
    and redefinition relationship declarations are not implemented.

A .kerml file is analyzed as KerML

  • A KerML declaration specializes the library type its keyword implies, so the features of
    that library type are inherited: class reaches Occurrences::Occurrence, struct reaches
    Objects::Object, and so on through assoc, behavior, function, interaction,
    metaclass, datatype, classifier and type. No library member was inherited before, so
    portion focusedState : Camera subsets timeSlices; reported an unresolved reference to a
    feature the library declares. A declared generalization suppresses the implicit base only when
    it already reaches it, so struct MyWheel specializes Wheel still reaches Objects::Object,
    and a supertype restored from the index cache keeps those edges. A bare feature still gets
    no base: the SysML attribute base is not KerML's.
  • SysML's definition-and-usage checks no longer fire on KerML declarations. class Person specializes Object was reported as "only a definition may specialize; found a usage" — a
    distinction KerML does not draw. A .kerml specialization or typing now requires only that
    its target be a type, from an explicit list of what a type is rather than a guess about what
    isn't, so metaclass AtomMetadata specializes Metaobject is accepted while a non-type target
    is still reported. The SysML files keep the kind checks they had.
  • A union conforms through its unioning typesclassifier MyWheel unions MyWheel1, MyWheel2 — without unioning becoming a generalization.
  • A declaration's header sees its own body. Names in a featured by, crosses or
    subsetting clause resolve against the members and imports of the body of the same declaration
    before the enclosing scope, and stay reachable afterwards by qualified name and feature chain.
    Resolution of a member inherited through an implicit base no longer recurses.
  • An unknown subsetting target is tolerated rather than reported as a KerML type error about
    something else.

KerML notation the reference accepts now parses

  • featured by, an n-ary connector end list, and a typed or redefining succession parse:
    class Owner { member feature inCart : Product featured by Account; },
    connector c : A (a, b, c); and succession s : Link [1] first paint then dry; — whose own
    [1] belongs to the succession rather than to its first end — along with the succession redefines s : … spelling. A missing by, a missing target, a missing then and a trailing
    comma are still reported.
  • at, while, merge and decide are names in a .kerml file, where they are not KerML
    keywords, as about, bind and the other SysML-only words already were. The remaining KerML
    feature-prefix forms — abstract var feature x [0..*]; — are still not parsed and are recorded
    as such.

Imports and visibility

  • A public import is re-exported to importers of the importing namespace, transitively;
    before, re-export stopped after one namespace. A root-level import is visible from a nested
    package, an imported name may prefix a qualified name, and an import cycle terminates instead
    of recursing. A protected import is reachable through a specialization of the importing
    namespace and from nowhere else.
  • An import with no visibility indicator warns. The grammar requires one, so import Lib::*;
    now reports [syntax/import-visibility] import without a visibility indicator: SysML v2 requires public, private or protected before 'import'. It is a warning at the syntax tier and
    analysis continues through it; expose is exempt, its grammar supplying protected visibility
    implicitly.

SysML notation the parser was refusing

  • A connector, interface or flow written with shorthand ends may have a body:
    connect x.p to r.p { ... }, interface b1.p to b2.p { ... } and flow s1.x to s2.x { ... }
    parse with their members. An unclosed body, an interface without to and an unterminated flow
    body are still reported.
  • An accept node is an action statement, so then action engineStopped accept engineOff : EngineOff; parses and executes. An accept in a loop or branch body remains unsupported by
    lowering and is reported when reached, rather than accepted and silently skipped.
  • connect requires its ends and reads a leading multiplicity on each of them:
    connect [1] a to [1] b. connect;, connect { ... } and a missing target are reported where
    some were accepted and misrepresented.
  • Eleven words that no grammar production reserves are names again, on and var among
    them, so state on;, part on : On; and attribute var : ScalarValues::Integer; parse as
    declarations named on and var. Each word remains a keyword in the position its grammar
    gives it, so var a : Integer; without a kind is still reported.
  • A modifier before a kind prefix keeps the kind, which was dropped from the tree and from
    every diagnostic that read it.

Notation accepted beyond the grammars now says so

  • A construct we accept that no pinned production admits warns at the syntax tier, from the
    conformance audit: namespace, region, choice, junction, an entry/exit/history point,
    defer, the initial/final/decision node spellings, and transition <source> to <target>;. namespace P { } in a .sysml file reports "namespace is KerML notation: the
    SysML v2 grammar has no namespace declaration, so write package here or move the declaration
    to a .kerml file"; featured by in a .sysml file reports the same for the featuring clause.
    The same notation in a .kerml file is silent, because there it is standard. These are
    warnings — the models that use this notation still parse, and no higher tier is gated — and the
    REPL warns for its own buffer, which it reads as SysML.

Analysis corrections

  • An alias is followed through every type relationship — specialization, typing, subsetting,
    redefinition, multiplicity and invocation inference — so part def AvionicsLRU :> Box, where
    Box aliases RectangularCuboid, no longer reports "part cannot specialize alias (kind
    mismatch)" and inherits what the aliased definition declares. An alias cycle terminates.
  • An invocation of an aliased action or function is type-checked against its parameters
    instead of going unchecked.
  • A declaration with a short name is listed once among a document's members, not twice.
  • A part typing check that read an unrelated declaration is gone, with the diagnostics it
    produced on valid models.

Diagrams in the VS Code extension

  • SysML: Open Diagram renders the open model in a panel and keeps it current as the file
    changes, over three new LSP requests — opensysml/render, opensysml/views and
    `opensysml/ren...
Read more

v0.1.1: Fix Release

Choose a tag to compare

@HuiJun HuiJun released this 19 Aug 17:50
e81da04

A fix release. Every change corrects something 0.1.0 got wrong about a valid model, so a model
0.1.0 rejected or misread may analyze differently here. Nothing was renamed and no interface
changed.

Install: go install github.com/Open-MBEE/OpenSysML/cmd/sysml@v0.1.1, or take a platform archive
below. The Python client opensysml is released separately.

The OMG training corpus reports no errors

  • Every definition body inherits the features of the library definition its kind implies. Only
    behavior definitions had an implicit base, so snapshot sale = start; inside a part def
    reported unresolved reference: start even though Items::Item declares start and done and
    Parts::Part redefines both. Two corpus files previously recorded as "bugs in the OMG files" —
    Time Slice and Snapshot Example and Individuals and Time Slices — were never buggy; the
    corpus baseline now lists no files at 100/100 clean.
  • A member that reuses an inherited feature's name is now reported instead of shadowing
    silently: part def C { part start; } conflicts with Parts::Part::start. Redefine it to keep
    the name — part start :>> Parts::Part::start;.
  • A qualified redefinition of an inherited library feature is accepted.
    snapshot start :>> Parts::Part::start; was rejected as "not an inherited member" when the
    supertype came back from the index cache. Redefining a feature the owner does not inherit is
    still reported.
  • A definition may specialize a definition of a comparable kind. individual item def Alice :> Person was refused because Person is a part def; specialization now follows the definition
    taxonomy. Disjoint kinds — a part definition and an attribute definition — are still refused.
  • A transition may leave the entry action of the state that declares it. entry action begin { } transition begin then off; reported the action as "not a state or pseudostate"; it now
    designates the machine's initial state and executes as such, and is rendered in a view that
    exposes it. Only that bare completion shape designates a start — a triggered or guarded
    transition out of an entry action, a transition into one, and a name reaching another state's
    entry action or a junction are reported rather than accepted with the trigger, guard or effect
    dropped.
  • A metadata usage ends at its own ; or body. @M part def Car; was read as an annotation
    plus an undiagnosed declaration; #M part def Car; is the prefix spelling. A metadata usage
    member also names a type, so @Securty; reports an unresolved reference instead of going
    unchecked, and @M; now parses in a namespace, a body and a state body.
  • A value part accepts every operator the grammar allows= expr, := expr,
    default expr, default = expr, default := expr — wherever a usage, parameter, result or
    subject binds a value.
  • The REPL prints a syntax warning once, not once per deferred analysis.

A rendering read at a terminal

  • sysml -render writes the text form at a terminal and the machine-readable form of the kind
    rendered — Mermaid for a diagram, Markdown for a table — into a file or a pipe.
    sysml m.sysml -render Views::table showed a Markdown table on screen. > table.md, | tool,
    -o table.md and -render-form are unchanged.
  • The text form is ASCII. The rendering header and connection edges used an em dash, which an
    ASCII-only terminal showed as a replacement character.
  • A text table is written to fit the terminal, wrapping an over-wide cell rather than
    truncating it or overflowing the window, and narrowing no column below 8 characters. A table
    written to a file or a pipe keeps every column as wide as its widest cell, so a saved artifact
    does not depend on the window it came from.

RDF conversion (experimental)

RDF stays experimental: expressions are still carried as source text, ownership is collapsed rather
than materialized as membership elements, and no round trip against a triplestore has been run yet.
Two changes land here.

  • Element IRIs now carry a reversible encoded id instead of the raw qualified name.
    Demo::Vehicle is written as urn:sysmlv2:element:Demo__Vehicle: :: becomes __, _ itself
    escapes to _5f, and any other byte outside [A-Za-z0-9-] becomes _ plus two hex digits, so
    the id is unique, reversible and inside the [a-zA-Z0-9_-]+ character set that a SysML v2 API
    service requires of an element id. Element identity is read from the sysml:qualifiedName
    literal rather than reconstructed from the IRI, so a .ttl written by 0.1.0 still reads back —
    but a graph re-exported from 0.1.1 has different subject IRIs, and anything matching those IRIs
    by string needs updating.
  • A reference to an element the graph does not describe is reported with a typed diagnostic
    instead of crashing the converter.
  • A metadata usage member is refused with a typed diagnostic rather than written as an
    annotation on a different element.

Documentation and internal quality gates

  • docs/ is published as a documentation site built with MkDocs, with the build run in strict
    mode in CI so a broken link or a missing page fails the check rather than shipping.
  • The generated SysML OWL ontology table is checked into the tree, with a domain/range gate
    over the exported graphs, derived from the Open-MBEE SysML v2 RDF ontology's 411 property
    declarations. It ships with a committed inventory of the graph shapes that do not yet conform,
    so the remaining work is recorded rather than hidden.
  • Static analysis runs on every build through SonarCloud, scoped to hand-written source with
    coverage wired in. The one vulnerability it reported is fixed: the ontology table generator no
    longer resolves git through PATH, reading the checkout's Git metadata directly instead
    (loose refs, packed-refs, detached HEAD, worktrees, and SHA-1 or SHA-256 object ids). The
    generated table is byte-identical, so no recorded commit id changed.

v0.1.0: OpenSysML Release

Choose a tag to compare

@HuiJun HuiJun released this 18 Aug 20:57
ff3616c

ATTENTION: We have renamed the project to OpenSysML.

OpenSysML 0.1.0

First release under the OpenSysML name, and the release where a model does more than parse: an
object runs the behavior its type exhibits, an SMT solver decides what its conditions permit, a
view renders, and a model can be edited through the source it was parsed from.

Install

brew install Open-MBEE/tap/opensysml           # brings z3 along, so solving works out of the box
go install github.com/Open-MBEE/OpenSysML/cmd/sysml@latest
pip install opensysml                          # Python client, released separately

Or download opensysml-<os>-<arch>.tar.gz (.zip on Windows) below: sysml, sysml-lsp and
sysml-grpc for macOS, Linux and Windows on amd64/arm64.

What's new

An object runs its behavior. Materializing an object starts the state machines and actions its
type exhibits or performs — each object with its own execution, event queue and feature values,
each entry/do/exit/effect body reading and writing that object's values, and send … to reaching
the addressed object. Startup and quiescence are defined, and a machine that never settles reports
a budget error instead of hanging. %invoke <object> <op> p=… performs an operation of the
object's type; %state <object> points %step, %advance, %current, %events and %features
at that object's own machine.

A solver decides (experimental). %check answers whether a constraint, requirement or
satisfaction assertion can hold, with an assignment on sat; %explain reduces an unsat to a
minimal core, printing each conflicting condition with its declaring element and
file:line:col; %solve synthesises a witness while keeping fixed what already is; %configure
answers which variant selections an assertion permits; %optimize improves the objectives an
analysis def states, lexicographically, verifying every optimum by asking whether anything does
better. A solver is optional — discovered on PATH or named by OPENSYSML_SMT — and what a
backend can do is probed as capabilities, so a missing feature is a typed refusal, never a
fabricated verdict. z3 covers everything; cvc5 covers everything but %optimize.

A view renders. %render <name> [text|mermaid|markdown] and sysml -render <view> produce a
containment tree, an interconnection diagram, a state machine, an action flow or a table. State and
action renderings read the same lowered graphs the runtime executes, so a diagram cannot drift from
what runs, and rendering is a read: no object is materialized, and an %action/%state session
keeps stepping across it.

A model is edited in place. ApplyEdits, and model.edit() in Python, sets a feature's value
or renames a declaration by rewriting the bytes of the parsed source, so comments and the text as
typed survive; the result is re-parsed and re-analyzed before it is returned, and a request's edits
apply all or none.

%print writes the session's model — or one element — back as SysML notation at the prompt,
through the same writer %save uses.

RDF (experimental) now covers behavior: action and state bodies round-trip byte-identically
through Turtle, and 102 of 120 example models convert, up from 71, with the rest refused by
construct rather than partly written.

Semantics and notation fixes. A nested value body governs over an inherited value (KerML
§7.3.4.5); require/assume bodies resolve and type-check to any depth, in their own scope;
binding connectors propagate in both directions with typed conflict and cycle errors; bind
accepts qualified and chained ends, and a requirement body takes a prefixed connector; fork,
join, merge and decision register the names they declare; feature-chain resolution is linear
in chain length; and an element reached through two scope trees is exposed and rendered once.

Upgrading

The rename is a clean break, with no compatibility aliases:

  • Go module: github.com/Open-MBEE/OpenSysML (the old path resolves only for v0.0.x).
  • Python: pip install opensysml (first release under the new name is 0.3.0, carrying on from
    pysysml 0.2.0), import opensysml, OPENSYSML_* variables, OpenSysMLError,
    opensysml-generate, ~/.opensysml. pysysml gets one final 0.2.1 that only reports the
    rename; pin pysysml==0.2.0 to stay on the pre-rename client while migrating.
  • Env vars are OPENSYSML_*; SYSTEMICA_* is not read.
  • VS Code: extension opensysml-sysml, settings opensysml.server.* / opensysml.trace.server
    re-set them under the new keys.
  • Models importing SystemicaMathFunctions::* must import OpenSysMLMathFunctions::*. A bare
    exp, ln, log or atan2 without that import is now a typed error naming it, instead of
    being reported unresolved and evaluated anyway.
  • .ttl written before this release carries urn:systemica:sysml: properties and is refused
    rather than read with those properties dropped — re-export from the notation source.
  • %slots is now %features, and the "slot" vocabulary is gone everywhere: on the wire
    Instance.feature_values / FeatureValue (field 3 and the name slots stay reserved), and
    in Python features, raw_features, get_feature, FeatureValueError and
    feature_value/optional_feature_value/list_feature_value. The client requires the service's
    feature_values capability, so a pre-0.1.0 sysml-grpc is named rather than answering with an
    object that appears to hold nothing. Diagnostic text changed with the vocabulary (feature value …, do action steps); exit statuses are unchanged, so a script matching the old text needs
    updating.

Known limitations

  • Constraint solving is experimental and needs an external solver: %check, %explain, %solve
    and %configure want z3 or cvc5, %optimize wants z3 (optimization is a z3 extension). A
    condition with no SMT-LIB form refuses the whole query rather than dropping the condition.
  • RDF conversion is experimental: expressions are not emitted as triples, end-binding heads depend
    on sysx:sourceText, the vocabulary may change without a compatibility path, and no round trip
    through a running triplestore has been demonstrated.
  • An edit sets a value or renames a declaration; creating or deleting an element, and renaming a
    referenced one, are refused.
  • Only an action member is executable through %invoke; a calc or constraint operation is
    evaluated as an expression and says so.
  • A package-owned binding connector does not propagate values; one declared in a materialized type
    or usage body does.
  • A rendering is tool-defined output — SysML v2 §10.2 leaves rendering to the tool — so %render
    output is OpenSysML's own artifact, not a standard interchange form.
  • A that inside a nested action, constraint or transition-guard body binds to the innermost
    enclosing usage; an unqualified standard library name requires an import (conformant, won't-do);
    and a port that accepts TCP but never answers gRPC costs the Python client about 9 s.

Quality gates

gofmt, go build, go vet, go test -race ./..., staticcheck and gosec green; stdlib
conformance clean; the OMG training corpus at its pinned 98/100 baseline; the SMT path gated with
z3, with cvc5 and with no solver, including a differential gate requiring solver verdicts to agree
with the evaluator; Python client suite green. Rule-by-rule status: docs/project/spec-compliance.md.

Full detail: CHANGELOG.md § 0.1.0.

v0.0.9: Optimization release

Choose a tag to compare

@HuiJun HuiJun released this 17 Aug 05:10
fbcb430

Systemica 0.0.9

Behavior, tooling and performance release. 52 pull requests since 0.0.8. Nothing is removed
and no model that worked before needs editing; two Python names are renamed with the old
spellings kept as deprecating aliases. Ships with pysysml 0.2.0.

Highlights

  • The VS Code extension can start the language server. sysml-lsp accepts --stdio
    and implements the shutdown/exit lifecycle, so the shipped client no longer
    crash-loops the shipped server. If 0.0.8's extension never worked for you, this is why.
  • State machines behave correctly around composite states. A transition out of a
    composite state fires while a substate is active, and a transition between sibling regions
    exits only its source rather than the whole composite state.
  • a then b and transition endpoints resolve like the names they are — in the scope
    they were written in, with a diagnostic when an endpoint names a vertex of another machine
    or a first/then marker, instead of silently dropping the edge.
  • The Python client starts ~31× faster: 509 ms → 16.5 ms, and a cold model load on the
    service dropped from ~110 ms to under 1 ms, so short-lived scripts and per-call
    calculations are practical.
  • A valueless feature of a value type reads as <unset> on every surface, instead of an
    empty object.

Language and semantics

  • Messages route by port direction, conjugation and the performing part; a state machine
    inside a part reaches that part.
  • Blocks own their token flow: for iterates every collection it is given, outputs the
    block's own flow assigns are counted, and a for over a non-collection is reported.
  • Library evaluation: string operators and StringFunctions, VectorFunctions and
    ComplexFunctions, @/@@ classification, a queryable exposed set for views, library
    feature values by name (TrigFunctions::pi, deg/rad) and includingAt insertion.
  • Enumeration literals are values, in the runtime and across the API.
  • Multi-valued defaults are honoured when they conform and reported when they do not; a
    default with no declared multiplicity is held to the assumed 1..1.
  • Calc bodies with an implicit result are type-checked, and calc recursion runs under a
    budget rather than exhausting the stack.
  • The subject of a check or evaluation is chosen deterministically and named in verdicts,
    labels and over the wire, including a nested one.
  • A member chain from that (= that.a) resolves; a root-level private import X::*;
    serves its own document — the spelling OMG's training files use.
  • Parser: keyword-named parameters and loop variables, modifier-driven usage kinds, a
    classifier specializing any definition, and KerML classifier/datatype classification.

Tools

  • REPL: unclosed submissions, load diagnostics, object-resolved subjects, %view,
    ranked suggestions, quoted qualified names and a pinned %eval context. A piped session
    whose command could not materialize a slot exits 2, so scripts detect it.
  • CLI: materialization diagnostics are reported instead of swallowed, and an undecided
    check is reported under one prefix.
  • gRPC: quantities cross in both directions with magnitude, written unit and reduced
    term preserved; enumeration literals cross as literals; unreduced, zero-scale or
    reduction-less units are rejected; Value.unset is a new arm the service sends and
    refuses to accept.

pysysml 0.2.0

  • Startup 509 ms → ~17 ms, with the same bounded START_TIMEOUT and ConnectionError.
  • pysysml.UNSET for a slot holding no value — falsy, distinct from None.
  • Quantities can be sent, not only read.
  • pysysml.evalpysysml.evaluate, pysysml.RuntimeErrorpysysml.ExecutionError;
    the old names still resolve with a DeprecationWarning and are out of __all__.
  • UnpinnedReleaseError for a release no digest is pinned for, subclassing
    ChecksumMismatchError; only it may be answered from a cached binary.
  • pysysml.__version__ reports the declaration shipped beside the module; the generated
    protobuf stubs ship type annotations, so mypy is clean.
  • Owns only services it spawned, authenticates them by pid, and pins release digests.

Quality gates

Measured on the released commit; the per-figure home is
docs/project/spec-compliance.md.

Gate Result
Tests and subtests 4,447 — 4,440 pass, 7 self-skip
Execution conformance 297 cases, all passing
Golden execution traces 98
Golden AST fixtures / negative parser subtests 86 / 129
Robustness 165 runtime cases, 8 gRPC cases
gRPC conformance 14 cases
Standard library parse 95/95 files clean
OMG training corpus 98/100 files clean (2 files / 4 errors, pinned OMG source bugs)
Python suite 514 passed, 17 skipped

cmd/sysml-grpc now has a process-lifecycle gate; it was at 0% coverage in 0.0.8 despite
being a published artifact.

Known limitations

  • A port that accepts TCP but never answers gRPC fails after ~9 s of wall clock rather than
    the nominal 2.5 s START_TIMEOUT. Bounded, and it raises a clear ConnectionError.
  • that inside a nested action/constraint/transition-guard body binds to the innermost
    usage, so that.k naming a member of the enclosing part is unresolved. This follows the
    spec text as written; say so if you need the outward binding.
  • Unqualified standard-library names still require an import (private import ScalarValues::*;). This is spec-conformant — only public top-level elements of a root
    namespace are globally visible ([SysML, 7.2] over [KerML, 8.2.3.5]) — and is recorded as
    won't-do rather than open.
  • RDF/Turtle interchange remains partial: expressions are not emitted as triples, and some
    example models do not convert. Treat the RDF path as experimental.
  • macOS binaries are unsigned and un-notarized; the VS Code extension is not on the
    marketplace.
  • The release tag pipeline does not run the OMG corpus gate — it was run locally for this
    release.

v0.0.8: Shakeout release

Choose a tag to compare

@HuiJun HuiJun released this 16 Aug 03:38
e2d49be

Systemica v0.0.8

sysml 0.0.8 · sysml-lsp 0.0.8 · sysml-grpc 0.0.8 · pysysml 0.2.0

This release is about trust in the answers. v0.0.7 made the answers reachable from
a script, a prompt, an editor and Python; this one fixes nine ways a reachable
answer could still be the wrong one — a violating model reported ✓ passed with
exit 0, a released sysml-grpc reporting version dev, a Python client serving a
cached binary from a different release, an RDF export refusing every model with a
constraint. The editor surfaces the LSP advertised but stubbed are implemented, a
dimensional mistake is caught at validation time, and the documentation is a
handbook instead of a page per feature.

Highlights

A check answers about the object, not the declaration

A constraint or requirement declared on a definition is now evaluated against the
object that carries it, so %constraint, %requirement and -constraint on an
instantiated model read the object's values rather than the declaration's
defaults. A model violating its own mass budget used to be answered ✓ passed
with exit 0 — the failure mode that matters most, since it is silent:

$ sysml rover.sysml -instantiate Rover::rover -constraint Rover::RoverDef::MassBudget ; echo "status=$?"
✓ Created instance of Rover::rover
  ID: 1
✗ Constraint Rover::RoverDef::MassBudget failed (on Rover::rover ID: 1)
  Assertion evaluated to false: chassis.mass <= maxMass
status=1

%eval reads the same subject, so a check and an %eval of a feature in one
session can no longer answer about different objects (a nested redefined feature
is still the exception, below); where several objects carry the feature it refuses
to choose rather than picking one. And a condition whose evaluation could
not be carried out is worded as undecided (? … could not be evaluated) and names
why, where it used to print a failure while exiting 2.

Dimensional mistakes are caught before evaluation

A comparison or sum of quantities whose dimensions are both statically determined
and incommensurable is reported at validation time, as a type-tier warning,
from the stdlib QuantityDimension power factors:

$ sysml model.sysml -validate
model.sysml:6:9: warning: operator '<' combines incommensurable quantities: MassValue (dimension M) and m (dimension L)
        mass < 1000.0 [m]
        ^~~~~~~~~~~~~~~~~

Evaluation keeps its hard error, and a warning changes no exit status — so this
catches the mistake early without failing a build that used to pass. A dimension a
declaration does not determine stays unknown and is not reported: there are no new
warnings on examples/, the bundled library or the OMG corpus.

Editors get highlighting and quick fixes

textDocument/semanticTokens/full and /range are implemented over a new
internal/core/highlight package, so highlighting comes from the parse rather
than from a TextMate approximation. textDocument/codeAction answers quick fixes
carried as structured edits from the layer that reported the diagnostic — a
located missing semicolon, a near-miss spelling, an importable namespace. Token
deltas are not implemented and are not advertised.

RDF export stops refusing constraints

The members that state a condition — a constraint body's conditions, a
requirement's assumptions and required conditions, a subject, a result — have a
mapping, so converting a model with a constraint no longer aborts. Conditions are
carried as sysx:condition notation, as every expression-valued position in this
mapping is. Turtle written back as SysML also spells the notation now: an
unrestricted name gets its quotes, so a model with a quoted name re-parses — every
example model that converts and validates on its own — 44 of the 71 — now
round-trips through Turtle and back and validates again.

Python — pysysml 0.2.0

  • Model gained instantiate, execute_action and execute_state, so every
    call taking a model hash is reachable on the model it is about.
  • A cached ~/.pysysml/bin/sysml-grpc records the release and the repository
    it was downloaded from beside it, and a cache from another release is replaced
    rather than served — the failure that silently disabled newer RPCs. A failed
    integrity check is its own pysysml.ChecksumMismatchError — exported from the
    package, like every other exception a documented failure raises — and is never
    answered from the cache; a download that fails on the network keeps the working
    binary.
  • A service already listening is asked what it is and compared against the release
    and capabilities asked for, raising StaleServiceError naming the remedy
    instead of a MissingCapabilityError on the first newer call. It is stopped only
    when this client started it and no other client holds it.
  • sysml-grpc -version reports the metadata the linker sets, where a released
    binary said version dev / commit unknown.

The command line reads standard input

A lone - names standard input wherever a model path is taken, -convert
included, and is reported as <stdin>; it is read even when stdin is /dev/null,
and stays distinct from a file named -. sysml-lsp parses its command line with
the flag package, so -version works and an unreadable flag is a usage error
rather than protocol mode.

Documentation is a handbook

The pages are organized by what a reader is doing rather than by the feature that
landed: a numbered guide (install → first model → command line → REPL → checking →
behavior → saving and RDF → editors → Python → troubleshooting) under
docs/guide/, looked-up material under docs/reference/, design under
docs/internals/, status under docs/project/. QUICKSTART.md and
RDF_INTEROP.md are split into the chapters they already were, the guide content
stranded in examples/*.md and python/README.md is folded in, and the paths the
v0.0.7 README linked leave pointers behind. scripts/check-doc-links.py gates
every relative link and heading anchor in CI.

Release publishing keeps the notes

Release assets are published with ghr -replace. -delete is an alias of
-recreate: it deleted the release and its tag ref and created an empty one, so
re-running the workflow for a tag wiped hand-written release notes, the title and
the prerelease/latest flags. The Homebrew tap now updates itself from a scheduled
workflow in Open-MBEE/homebrew-tap, reading the release's SHA256SUMS.txt, with
scripts/render-homebrew-formula.sh as the manual fallback.

Verification

Gate Result
gofmt -l . clean
go build ./... / go vet ./... clean
make lint (staticcheck, gosec) pass
go test -race -count=1 ./... 3,687 tests and subtests — 3,682 pass, 5 self-skip, 0 fail
TestStdlibConformance 95/95 bundled library files clean
OMG training corpus 98/100 files clean (2 files / 4 errors, pinned OMG source bugs)
pytest python/tests/ 369 pass, 26 skip (integration, no service listening)
scripts/check-doc-links.py 0 broken links

Known limitations

  • Converting a model whose behavior is stated as action or state nodes to RDF
    still reports the node and aborts (initial nodes, perform, send,
    terminate, loop nodes, state regions): 71 of the 120 models under examples/
    convert.
  • A nested feature redefined on an instantiated object is not yet the subject of a
    check or an %eval, so those answer about the declaration — and print no
    (on …) — while %slots shows the instantiated value.
  • A calc body written without return is not expression-type-checked, so no
    static dimensional warning is reported inside it.
  • Submitting any declaration to the REPL ends an active %action or %state
    debugging session.
  • semanticTokens/full/delta is not implemented and is not advertised.

Install

# Homebrew
brew install Open-MBEE/tap/systemica

# or a release archive
curl -fLO https://github.com/Open-MBEE/Systemica/releases/download/v0.0.8/systemica-linux-amd64.tar.gz
curl -fLO https://github.com/Open-MBEE/Systemica/releases/download/v0.0.8/SHA256SUMS.txt
sha256sum -c --ignore-missing SHA256SUMS.txt && tar xzf systemica-linux-amd64.tar.gz

# Python client
pip install pysysml==0.2.0

The full list of changes is in CHANGELOG.md.

v0.0.7: QOL release

Choose a tag to compare

@HuiJun HuiJun released this 15 Aug 08:06
3b07b1b

Systemica v0.0.7

sysml 0.0.7 · sysml-lsp 0.0.7 · sysml-grpc 0.0.7 · pysysml 0.1.1

This release is about the surfaces. The engine's answers did not change in ways a
model author would notice; what changed is that the answers are now reachable,
discoverable and trustworthy from a script, a prompt, an editor and Python. It
also carries the element-filter, Query-RPC and loading-performance work that
v0.0.6 shipped without a changelog entry of its own.

Highlights

The command line can fail

sysml is usable in CI and in a Makefile for the first time:

  • Exit status means something on every path0 when the requested
    operation succeeded and every requested check held, 1 when a check answered
    false, 2 when nothing was decided (a model that did not analyse, an
    expression that could not be evaluated, an unreadable file, a misused flag). A
    check is gated on analysis, so no verdict is ever reported about a model nobody
    could read.
  • Streams are separated — findings and diagnostics on stderr, requested
    output on stdout, under one sysml: prefix. -h is stdout and exit 0; an
    unknown flag stays stderr and exit 2.
  • Checks run without a prompt-validate, -constraint, -requirement,
    -satisfy, -instantiate, -calc, -action, -state -advance, -json. One
    evaluation stands behind both the flag and the prompt's %constraint /
    %requirement / %satisfy.
  • A project loads as a projectsysml <dir>, sysml 'src/*.sysml' and
    %load <dir> expand, sort and deduplicate their inputs and submit them as one
    submission, so resolution no longer depends on load order; diagnostics keep
    each file's own line numbers.
$ sysml examples/combined-behavioral-demo.sysml -validate ; echo "status=$?"
✓ package VehicleModel
status=0

Breaking: conversion is spelled sysml model.sysml -convert ttl. The model is
a positional argument as in every other mode and -convert names the target
format; -convert <file> and -to <format> are gone (-to reports its
replacement), and the output path no longer picks the format, so -o /dev/null
or a FIFO needs nothing extra.

The REPL stops losing your session

Re-typing a namespace merges into the one already in the buffer instead of
replacing its body. An instance and an active %action / %state session
survive a submission that did not change what they depend on — declaring an
unrelated part def B; no longer discards the instance of A — and anything
genuinely invalidated is dropped with a notice naming the submission that ended
it. The library is discoverable from the prompt: %search, %builtins, Tab
completion over meta commands, symbols and paths, and history kept outside the
temporary directory.

Diagnostics point at the fix

An unresolved name carries the nearest spelling on every surface — command
line, prompt and editor — and candidates are ranked by how a reader would reach
them rather than by edit distance: the budget scales with the typed name's
length, a name in scope beats one reachable only by a path, your own declaration
beats a bundled library one, and a candidate too far out is dropped even when it
is the only one. Whel beside your own Wheel offers Wheel alone.

$ sysml model.sysml -validate
sysml: model.sysml:3:21: unresolved reference: Integer — did you mean ScalarValues::Integer?

The base library is not implicitly visible, so a bare Integer is an error with
its qualified spelling offered; every shipped examples/*.sysml and
examples/*.kerml imports what it uses and analyses cleanly.

Element filters are evaluated

filter <expr>; in a package, definition or usage body, import P::*[@T], and a
filter at a document's root all gate the names beside them. A condition is a
boolean predicate over one candidate with the candidate as the implicit self
(KerML 8.2.4), judged against a symbol and the metadata annotating it, with
conformance through supertypes — so @Safety matches a metadata type
specializing Safety. A condition outside the evaluated subset is reported as
such rather than silently selecting nothing, and completion applies the filters
in force where the name is being completed.

Runtime

  • An action flow ends at a node with no succession, so an action whose last
    node is a plain nested action reaches Completed instead of failing.
  • A performance holds its values in one feature space its tokens share, so a
    fork's concurrent branches no longer overwrite each other's assignments —
    which write decides a feature both branches assign is step order, stated in
    docs/SPEC_COMPLIANCE.md.
  • A fifth runaway bound, SYSML_MAX_ELEMENTS (default 1 000 000), bounds the
    collection elements one evaluation holds, so 1..10000000 is refused before it
    conjures ~1 GB. %budget prints the five bounds and the variable that raises
    each.
  • An evaluation outside a body (a guard, a change condition, a default, an
    argument, a constraint check) runs in a scope of its own, so a revisited
    decision re-reads its calc usage over current values instead of returning the
    first evaluation's result.

Editors

A first-party VS Code extension lives in editors/vscode: TextMate highlighting
for .sysml and .kerml, comment/bracket configuration, and an LSP client that
finds sysml-lsp from systemica.server.path, a workspace's bin/sysml-lsp, or
PATH. It is built and side-loaded from this repository (make vscode-package)
and is published to no marketplace. Completion is typed and context-aware, and
sysml-lsp now serves a session over one reader — it used to race two decoders
over its own stdio and die with corrupted framing within seconds of typing.

Python — pysysml 0.1.1

  • Model.eval() evaluates in the model's context; pysysml.eval() still works
    without one.
  • Instance expansion is complete and typed: nested parts, connector ends and
    slots carry their kind, so a value is a bool/int/float/str rather than
    a string, and a DataFrame column has a usable dtype.
  • Verification raises on a wrong-kind subject (WrongKindError) instead of
    answering an undecided verdict, and connect("host:port") is accepted.
  • Conversion APIs, a Query RPC accepting the SysML v2 API & Services query
    model's JSON payloads verbatim, and typed model generation are available.

Performance

Loading a large model is linear where it was quadratic (three lookups scanned a
namespace's members once per member), and ParseFile hits its cache on the
source it read, so re-loading unchanged content costs ~0.5 ms instead of ~35 ms.
docs/PERFORMANCE.md records the measurements.

Removed

internal/core/deps — the sysml.toml manifest, lockfile, git fetcher and
resolver — is deleted. Nothing imported it: no manifest was ever looked for by
the command line, the prompt or the server, and the README claim it backed is
gone.

Verification

Gate Result
gofmt -l . clean
go build ./... / go vet ./... clean
make lint (staticcheck, gosec) pass
go test -race -count=1 ./... 3,585 tests and subtests — 3,580 pass, 5 self-skip, 0 fail
TestStdlibConformance 95/95 bundled library files clean
OMG training corpus 98/100 files clean (2 files / 4 errors, pinned OMG source bugs)
pytest python/tests/ pass

Known limitations

  • A surviving REPL debugger session keeps the executor it was started with rather
    than being re-lowered.
  • @Safety; as a standalone semicolon-terminated annotation member does not
    parse; @Safety (no semicolon), @Safety part x; and metadata Safety; do.
  • The LSP advertises no code actions, and SemanticTokensFull is still a stub —
    highlighting comes from the TextMate grammar.
  • Model has no instantiate / execute_action / execute_state convenience
    method; the Connection methods behind them do exist.
  • sysml -validate - treats - as a filename (no stdin), and a piped
    expression is parsed as a model rather than evaluated.

Install

# Homebrew
brew install Open-MBEE/tap/systemica

# or a release archive
curl -fLO https://github.com/Open-MBEE/Systemica/releases/download/v0.0.7/systemica-linux-amd64.tar.gz
curl -fLO https://github.com/Open-MBEE/Systemica/releases/download/v0.0.7/SHA256SUMS.txt
sha256sum -c --ignore-missing SHA256SUMS.txt && tar xzf systemica-linux-amd64.tar.gz

# Python client
pip install pysysml==0.1.1

The full list of changes is in CHANGELOG.md.

v0.0.6: Calc release

Choose a tag to compare

@HuiJun HuiJun released this 14 Aug 14:28
5f80892

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 calc body is computational: statements, local declarations, if/else,
    while and for loops, and return. 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 out features 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 out feature 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
    body returns 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 reading p.a, assigning to the
    usage's input, then reading p.b answers 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, max and the rest — are evaluable, with a sequence
    expression's results flattened as the library specifies.
  • [*] means 0..*, 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 = expr on 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
    a variant outside 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
    expose outside a view usage is reported.
  • view and viewpoint members 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 … via and send … to self,
    then done and then loop … until, if/else in an action flow,
    exhibit state bodies, 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 a port-conjugation warning on like-typed interface ends
    and attribute x : ~P rejected), end usages including the default
    end; interface end, require/assume by qualified reference
    (require Pkg::req { }), and snapshot/timeslice occurrence 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 compact transition <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-byte Value living 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
    ErrElementLimitExceeded naming 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.
  • %budget prints 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

  • Instantiate returns 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 in SlotValue.error
    rather than as a null value. On the client, slot values convert to Python
    scalars, lists and nested Instances, with the raw protobuf still reachable
    through get_slot()/raw_slots; attribute and item access raise
    AttributeError/KeyError/SlotError rather than returning None.
  • python -m pysysml.generate emits a Python class per SysML definition —
    properties that carry the static type and perform the runtime delegation, so an
    editor completes inst.mass and a type checker rejects inst.mas. GetSymbol
    reports the type facts this needs (type_info with primitive reduction,
    multiplicity, all specialization edges), pysysml ships py.typed, and
    emission is deterministic so the output can be committed.
  • GetServerInfo reports 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 the type_facts capability and
    fails naming the service in use, where it came from and how to replace it:
    against the v0.0.5 sysml-grpc, which predates type_info, every generated
    feature was typed object, indistinguishable from one that is genuinely
    untyped.
  • A generated module records the model source hash and the generator's emission
    schema, and pysysml.generate --check regenerates 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_instance rejects an instance of another definition, naming
    both types, instead of failing later with a confusing TypeMismatchError on the
    first slot read; unchecked(instance) is the explicit escape hatch.
  • Model.find accepts 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 t...

Read more

v0.0.5: Quantities, satisfaction verdicts and RDF round trip

Choose a tag to compare

@HuiJun HuiJun released this 13 Aug 02:09
0d64386

Highlights

Requirements and constraints actually decide something. A requirement or constraint condition is evaluated against the features of the element stating it — its own attributes, the ones it inherits from its definition, and the values a usage rebinds (attribute :>> maxVerticalSpeed = 1.5;). This was the first known limitation listed for 0.0.4. assert satisfy <requirement> by <part>; now has a verdict of its own: the requirement's subject is bound to an object of the part named by by, and %satisfy evaluates the satisfaction assertions a model states — every one, or the ones a named element states. Assertions can be negated (assert not constraint { … }), a violated condition reports which condition failed, and a requirement with no condition has no verdict rather than passing vacuously.

Quantities and units. attribute maxVerticalSpeed = 1.5 [m/s]; is evaluated as a real quantity: units reduce to a scale factor over base units through the Quantities and Units library's own unitConversion, so commensurable units convert before a comparison or a sum — 1.5 [m/s] <= 5.4 [km/h] is true, exactly, at its boundary — and a composed unit is kept (10 [m] / 2 [s] is 5 [m/s], 4 [m] / 2 [m] is 2). Comparing incommensurable units is an error rather than a comparison of bare magnitudes. Units may be written unqualified at the prompt, a name a declaration shadows is reported with the shadowing declaration and the way out (… shadowing the measurement unit SI::metre — write SI::m to name the unit), %calc accepts quantity arguments in every argument form, and a quantity renders like the bare Real it measures (v = -15.20 [m/s]) instead of full float precision.

Math functions. The KerML function library's scalar numerics are evaluable (sqrt, abs, floor, round, max, min, isZero, isUnit, and the trigonometric family), as is exponentiation (**, ^). exp, ln, log(x, base) and atan2(y, x) have no OMG signature, so they live in a new non-normative extension library, SystemicaMathFunctions.kerml (import SystemicaMathFunctions::*;) — the vendored OMG files are unchanged and the stdlib parse gate is 95/95 clean. A result that is not a finite value of the declared type is reported where it is evaluated instead of folding to a NaN, an infinity or a wrapped integer.

Action and state execution. while, loop, for … in … and if … else … lower to real decision and merge nodes and execute, so an iterating body reaches its final node with the values it computed rather than deadlocking. A then written as a body member is a real succession edge, like the standalone form. An attribute default written in an action or state body is evaluated in the scope that declares it, so a unit or type an enclosing package imports resolves there.

Saving and RDF interop. %save <file> writes the session out — notation (.sysml) or RDF Turtle (.ttl), chosen by the extension, written atomically. A session that does not fully parse still saves as notation, with the syntax errors reported as warnings, so work is never trapped in the REPL. sysml -convert converts between notation and Turtle in both directions, round-tripping packages, definitions, usages, features, imports, connectors, successions and satisfy assertions; what the mapping normalizes and what it refuses is documented in docs/RDF_INTEROP.md.

Runaway bounds you can raise. The evaluation, action-step, event and do-activity budgets are each configurable (SYSML_MAX_STEPS, SYSML_MAX_ACTION_STEPS, SYSML_MAX_EVENTS, SYSML_MAX_DO_STEPS), defaults raised to 10M/1M/1M/5M, and every limit error names the variable that raises it. The evaluation budget bounds one run rather than a whole session, so a long REPL session no longer exhausts its allowance and starts failing everything.

Editor and tooling correctness. A relationship written with a keyword and one written with its symbol are the same relationship end to end (specializes/:>, subsets/:>, redefines/:>>, references/::>), so hover, go-to-definition, completion and the index agree whichever spelling a model uses; a feature taking its effective name from what it redefines is read under that name too. Removing a document unwinds what its wildcard re-exports contributed and reuses its index slot, so an editing session's memory no longer climbs with the number of reindexes. A parser try-parse that gives up now rewinds properly, fixing a condition beginning with a feature named constraint.

Installation

Homebrew (macOS and Linux, avoids the Gatekeeper quarantine a browser download sets):

brew install Open-MBEE/tap/systemica

Or download the bundle for your platform from the assets below and verify it:

curl -fLO https://github.com/Open-MBEE/Systemica/releases/download/v0.0.5/systemica-linux-amd64.tar.gz
curl -fLO https://github.com/Open-MBEE/Systemica/releases/download/v0.0.5/SHA256SUMS.txt
sha256sum -c SHA256SUMS.txt --ignore-missing
tar xzf systemica-linux-amd64.tar.gz && ./sysml --version

Assets

Per platform (linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64):

  • sysml-<os>-<arch> and sysml-lsp-<os>-<arch> archives (.tar.gz, .zip on Windows);
  • systemica-<os>-<arch> bundle archives holding both binaries under their plain names, which is the layout Homebrew and a PATH install expect;
  • sysml-grpc-<os>-<arch>, raw with a .sha256 sidecar — new in this release. This is what the Python client downloads, verifies, caches under ~/.pysysml/bin and starts, so a Python caller needs no Go toolchain. v0.0.4 described these assets but did not carry them; 0.0.5 is the first release that does;
  • SHA256SUMS.txt over every archive and every sysml-grpc binary.

Python client

pysysml is released independently, by its own pysysml-v* tag, because it resolves a sysml-grpc binary at runtime from whichever release the caller names rather than from a release matching its own version. Until that tag is pushed, install it from source:

pip install "git+https://github.com/Open-MBEE/Systemica.git#subdirectory=python"

Python 3.10+. See docs/RELEASING.md.

Known limitations

  • RDF/Turtle conversion has no mapping for a member that states a condition or a step, so a model containing one is reported rather than converted: require and assume members, a constraint body's condition, subject, a computed return, assign, if/while/loop/for, substates, transitions and entry/do/exit (cannot convert the *ast.RequireMember at <file>:<line>). A requirement stating a condition, and any state machine or action body with statements, must be saved as .sysml. Full list in docs/RDF_INTEROP.md.
  • The REPL's prompt evaluates in the last namespace the session declared. After typing a second package, the first package's members and the units its imports brought in are reached by qualified name only (1.0 [SI::m], not 1.0 [m]).
  • Re-typing a declaration whose name the session already holds replaces the earlier snippet rather than merging into it, so adding a member to a package by re-typing the package drops the members left out of the new text.
  • A multi-valued feature that is both typed and given a default takes the typed instantiation; the default is not merged into it (as in 0.0.4).
  • An attribute declared with a type but no value (attribute diameter : Real;) instantiates as an object of that type rather than an unset value, so %slots shows diameter = Instance(ID: n) with (no features) under it.
  • 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 for the workarounds and what signing would take.

Verification

Measured on the commit this release is cut from: gofmt clean, go build ./... and go vet ./... clean, make lint (staticcheck + gosec) passing, go test -race -count=1 ./...2,465 tests and subtests, 2,460 pass / 5 self-skip / 0 fail, stdlib conformance 95/95 clean, OMG training corpus 98/100 clean (the two remaining files hold four pinned OMG source errors), Python client 92 passed / 18 skipped.

v0.0.4: Package-scoped model support

Choose a tag to compare

@HuiJun HuiJun released this 11 Aug 05:11
a554b20
  • First tagged release of Systemica
  • Language & Semantics: Hand-written SysML v2 lexer/parser, lazy name resolution, type system, tiered validation, 98/100 OMG corpus compliance
  • Execution: Instantiation with derived defaults, constraint/requirement evaluation, action execution (fork/join/decision/merge, send/accept), state machine execution (transitions, guards, entry/do/exit, hierarchy, orthogonal regions, pseudostates, triggers)
  • REPL (sysml): Full declaration/instantiation/inspection commands, action & state debugging, output modes (quiet/debug/trace), scoped diagnostics
  • Tooling: LSP server (sysml-lsp), gRPC bindings with Python support, multi-platform release archives
  • Known Limitations: 2 edge cases documented

v0.0.3 - Semantic Fidelity & Textual Notation Improvements

Choose a tag to compare

@HuiJun HuiJun released this 07 Aug 15:12
343e3ee
Major improvements to SysML v2 specification compliance.

Highlights:
- Implicit parameter redefinition (by position)
- Reference subsetting member contribution (perform, references)
- Complete textual notation for history/entry/exit/defer
- If/else branch namespaces
- Flow payload declaration
- Homebrew distribution for macOS
- 51 execution conformance tests + 5 gRPC tests
- 950+ tests passing

See release notes for complete details.