v0.0.7: QOL release
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 path —
0when the requested
operation succeeded and every requested check held,1when a check answered
false,2when 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 onesysml:prefix.-his 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 project —
sysml <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=0Breaking: 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 reachesCompletedinstead 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, so1..10000000is refused before it
conjures ~1 GB.%budgetprints 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 abool/int/float/strrather 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, andconnect("host:port")is accepted. - Conversion APIs, a
QueryRPC 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;andmetadata Safety;do.- The LSP advertises no code actions, and
SemanticTokensFullis still a stub —
highlighting comes from the TextMate grammar. Modelhas noinstantiate/execute_action/execute_stateconvenience
method; theConnectionmethods 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.1The full list of changes is in CHANGELOG.md.