3. From the command line¶
Every check the REPL performs is also a flag, so a model can be checked from a script, a Makefile or a CI job. This chapter is the narrative; every flag and exit status is tabulated in reference/cli.md.
The same checks the REPL runs are available as flags, so a model can be checked
from a script or a build step without a prompt. Take checks.sysml:
package MyModel {
part def Sensor {
attribute reading = 0.0;
attribute threshold = 100.0;
}
requirement def ReadingRequirement {
subject sensor : Sensor;
require sensor.reading <= sensor.threshold;
}
requirement healthy : ReadingRequirement;
part hot : Sensor {
attribute :>> reading = 140.0;
constraint inRange { reading <= threshold }
}
part cold : Sensor {
attribute :>> reading = 20.0;
constraint inRange { reading <= threshold }
}
part checks {
assert satisfy healthy by cold;
assert satisfy healthy by hot;
}
calc def Margin {
in reading;
in threshold;
return threshold - reading;
}
action calibrate {
attribute offset = 0.0;
first start;
action adjust {
assign offset := offset + 1.5;
}
done end;
then start adjust;
then adjust end;
}
state Monitor {
initial off;
state warming {
accept after 10 then running;
}
state running;
off then warming;
}
}
Each flag may be repeated, and -instantiate runs first — whatever order the
flags are written in — so the verdicts after it are about that object:
$ sysml -instantiate MyModel::cold -constraint MyModel::cold::inRange checks.sysml
✓ package MyModel
✓ Created instance of MyModel::cold
ID: 1
Use %features MyModel::cold to inspect
✓ Constraint MyModel::cold::inRange passed (on MyModel::cold ID: 1)
$ sysml -satisfy checks.sysml
✓ package MyModel
✓ satisfy healthy by cold holds (on MyModel::cold ID: 1)
✗ satisfy healthy by hot fails (on MyModel::hot ID: 2)
Required condition evaluated to false: sensor.reading <= sensor.threshold
Every check flag is listed in
reference/cli.md § Command Reference:
one constraint or requirement by name, every satisfaction assertion the model
states, a calculation, an action, a state machine, and -json for a machine-readable
report.
The exit status is what a build step gates on, and it is the same on every run
that is not a prompt — an evaluation, a conversion, a plain load — not only on a
check: 0 when what was asked for was done, 1 when the model answered false,
2 when nothing was decided. The whole contract is in
reference/cli.md § Exit status.
Status 2 is kept apart from 1 because an undecided check is not evidence against the model — treat it as a broken check, not a failing one. A condition that evaluated to false is the model's own answer; a name that does not resolve, or a condition over a feature with no value, is not:
$ sysml -constraint MyModel::hot::inRange -instantiate MyModel::hot checks.sysml; echo "exit=$?"
✓ package MyModel
✓ Created instance of MyModel::hot
ID: 1
Use %features MyModel::hot to inspect
✗ Constraint MyModel::hot::inRange failed (on MyModel::hot ID: 1)
Assertion evaluated to false: reading <= threshold
exit=1
$ sysml -constraint MyModel::nosuch checks.sysml; echo "exit=$?"
✓ package MyModel
error: unresolved reference: MyModel::nosuch
exit=2
$ sysml -requirement MyModel::healthy checks.sysml; echo "exit=$?"
✓ package MyModel
? Requirement MyModel::healthy could not be evaluated
Error: requirement healthy: require condition evaluation failed: no value for feature sensor
exit=2
That last case is the shape of a requirement with a subject: nothing binds the
subject, so it has no object to be about. Write the intended pair into the model
as assert satisfy healthy by hot; and check it with -satisfy, which creates
the subject itself — -requirement decides a requirement whose conditions stand
on their own, or one carried by a part an -instantiate created.
A verdict is written to stdout and an undecided check to stderr, as is every
other finding — diagnostics and warnings included — so
sysml -satisfy checks.sysml > verdicts.txt keeps the results and leaves what
went wrong on the terminal.
Checking as a gate¶
-validate asks nothing of the model's conditions: it loads it and reports what
analysis found, which is the lint step to run before any verdict is trusted.
$ sysml -validate checks.sysml; echo "exit=$?"
✓ package MyModel
✓ checks.sysml: no errors
exit=0
$ sysml -validate bad.sysml; echo "exit=$?" # a file with a syntax error in it
bad.sysml:2:45: error: expected an expression
part def Battery { attribute capacity = ; }
^
sysml: bad.sysml did not analyse cleanly; no check was made
exit=2
A lone - names standard input wherever a file is taken, so a model can be
piped in; its diagnostics are counted from <stdin>. A file really called - is
read by naming it ./-, and -convert needs -from for piped input because the
stream carries no extension to take the format from.
$ cat checks.sysml | sysml -validate -
✓ package MyModel
✓ <stdin>: no errors
$ cat checks.sysml | sysml - -convert ttl -from sysml > model.ttl
Every check mode is gated the same way, so a model with an error never reports a verdict about itself — a condition read out of a model the tool could not fully read would be an answer about a different model than the one you wrote. Name as many files as the model spans, in any order: the gate is about the model as a whole, so a reference from one file to a declaration in another resolves.
Running behavior¶
The debuggers have non-interactive forms that run to completion and report the
values they produced. -calc takes the invocation, and -action and -state
take the behavior's name optionally followed by the object performing it:
$ sysml -calc "MyModel::Margin(20.0, 100.0)" checks.sysml
✓ package MyModel
✓ MyModel::Margin(20.0, 100.0)
= 80.00
$ sysml -action MyModel::calibrate checks.sysml
✓ package MyModel
✓ Started action executor for "MyModel::calibrate"
State: Running
Tokens: 1
✓ Action completed
Final state: Completed
Results:
offset = 1.50
$ sysml -state MyModel::Monitor -advance 15 checks.sysml
✓ package MyModel
✓ Started state machine executor for "MyModel::Monitor"
Current state: off
Time: 0.00
Events: 1
✓ Advanced to 15.00 (2 event(s) processed)
Current state: running
Last event at: 10.00
Remaining events: 0
A state machine only takes its initial transition unless -advance says how much
simulated time to run it for; -advance 0 runs it to the present, dispatching what
is already due, and -advance with no -state to run is reported as a misuse
rather than silently dropped. An action that stopped short of completing
— a deadlock, or the step budget reached — is reported as a check that was never
decided, i.e. status 2, since it produced no outputs to judge.
Machine-readable results¶
-json reports the same run as one document, so a build step reads structure
rather than parsing ✓/✗. It reports the checks, not the model: use -convert
to serialize the model itself.
$ sysml -satisfy -json checks.sysml; echo "exit=$?"
{
"status": "fails",
"exit": 1,
"checks": [
{
"subject": "satisfy healthy by cold",
"status": "holds",
"values": null,
"lines": [
"✓ satisfy healthy by cold holds (on MyModel::cold ID: 1)"
]
},
{
"subject": "satisfy healthy by hot",
"status": "fails",
"values": null,
"lines": [
"✗ satisfy healthy by hot fails (on MyModel::hot ID: 2)",
" Required condition evaluated to false: sensor.reading \u003c= sensor.threshold"
]
}
],
"diagnostics": null,
"output": [
"✓ package MyModel"
],
"errors": null
}
exit=1
status is the worst verdict reached and exit the status the process exits
with. A calculation's or a machine's values are reported as values entries, the
findings of analysis as diagnostics — the warnings of a model that analyses
cleanly as well as the errors of one that does not, each with the file it is in
and its line and column there — and whatever stopped a check from being made as
errors, so the whole document goes to stdout and nothing needs to be read off
stderr.
Running from a script¶
-e evaluates without entering the prompt, so a model can be queried from a
shell:
$ sysml -e "RdfInteropDemo::Rover::mass" examples/rdf-interop-demo.sysml
✓ package RdfInteropDemo
✓ RdfInteropDemo::Rover::mass
= 899.00
Two things matter before a pipeline depends on it:
- What was asked for is on stdout and what went wrong on stderr. Evaluated
values, conversion output and verdict lines are results; a model's diagnostics
and warnings, a failed evaluation, a file that could not be read and the
wrote <file> …note of a successful-convert -oare not, so that stdout carries the conversion alone. - The exit status says whether the model answered what was asked:
0it did,1it answered false,2it answered nothing. A warning leaves the status0. The status codes are documented once, in reference/cli.md § Exit status, with a CI recipe that gates on them.
Next: 4. The REPL.