Handle unsupported syntax

The Solver covers a growing subset of SysML v2. When a model uses something outside that subset, the Solver does not fail the whole run: it analyzes what it can, skips what it cannot, and tells you exactly what was skipped and why. Nothing is silently guessed.

A partly analyzable model

Create mixed.sysml. The flow-rate check is fully supported; the diameter-match check relies on attributes whose type nothing in the model decides:

package Pump {
    private import ScalarValues::Integer;
    part pump [1] {
        attribute flowRate : Integer = 40;
        attribute inletDiameter;
        attribute outletDiameter;
        attribute matched = inletDiameter == outletDiameter;
    }
    assert constraint flowOk { pump.flowRate <= 50 }
    assert constraint portsMatched { pump.matched }
}
syside solver check -i mixed.sysml
{
  "result": {
    "subject": "Pump",
    "expression": "assertions[2]",
    "determination": "unknown",
    "outcome": {
      "shape": "assertions",
      "assertions": [
        { "name": "Pump::flowOk", "status": "satisfied",
          "counterexample": null },
        {
          "name": "Pump::portsMatched",
          "status": "unanalyzable",
          "counterexample": null,
          "reason": "depends on 'Pump::pump::inletDiameter', ..."
        }
      ]
    },
    "causes": []
  },
  "warnings": [
    { "code": "Unimplemented", "span": null,
      "message": "'Pump::pump::inletDiameter' excluded from analysis ..." },
    { "code": "Unimplemented", "span": null,
      "message": "'Pump::pump::outletDiameter' excluded from analysis ..." }
  ],
  "exit_code": 0
}

(The reason and message strings are shortened here; the real output carries them in full.)

How to read this:

  • flowOk was checked normally and is satisfied. Unsupported syntax elsewhere in the model did not block it.

  • portsMatched is unanalyzable – neither satisfied nor violated. Its reason says which element caused it and, where the Solver can tell, what to change (here: declare a type for the two diameters).

  • Each skipped element also appears in warnings, so skipped parts of the model are visible even when every remaining assertion passes.

  • determination is unknown: the run as a whole could not decide every assertion.

An unanalyzable assertion is not a violation, so the exit code stays 0. If your CI should treat “could not check” as a failure, test for it explicitly – for example:

syside solver check -i mixed.sysml | jq -e \
    '.result.outcome.assertions | all(.status == "satisfied")'

jq -e sets the exit code to 1 unless the expression is true, failing the step when any assertion is violated or unanalyzable.

When the whole query is unsupported

If the expression you pass to evaluate --expr or check --predicate itself depends on an unanalyzable element, there is no partial answer to give. The Solver prints an error object with the same kind of reason and exits with code 2.

Common causes and fixes

  • Attribute has no declared type, and its uses do not decide one (as in the example above). Declare one: attribute inletDiameter : Real;.

  • A quantity attribute is missing its quantity type. Values with units need a declaration like : MassValue; see Compare values across units.

  • A package-level part usage without an explicit multiplicity. Write part rover [1] {...}, or see Add assumptions for the singular-usages override.

  • The construct’s meaning is genuinely open in the specification. Some syntax the Solver refuses by default can be given a stated meaning with an override; Add assumptions lists them.