Skip to content

engine: MDL writer units field re-import hard-fails on non-unit-expression text #862

Description

@bpowers

Description

The MDL writer's units field is a typed unit expression, not free text, but the app lets a modeler type arbitrary text into a units field, and that text survives to the datamodel. When a variable's units string is not a valid unit expression, the writer serializes it verbatim (after #849 free-text sanitization) and the exported MDL then hard-fails parse_mdl on re-import: the whole model fails to load with a units-grammar error (e.g. expected unit name, found /), rather than emitting an ExportWarning or being sanitized to a valid/empty unit expression.

Triggering inputs include:

  • a bare number as units, e.g. "3.14"
  • a stray comma
  • the / that the #849 sanitizer substitutes for a dangling | ("|" -> "/")

Relationship to #849 (this is a distinct gap)

#849's sanitizer keeps the units field structurally safe -- it never spawns phantom variables or drops the real one, verified by the passing units_free_text_is_structurally_safe proptest. But structural safety is not the same as validity: the sanitizer does not (and cannot) make arbitrary text a valid unit expression. So a units string can pass #849 and still make the exported model fail to load. This is a separate failure mode (hard load failure on re-import) from #849's silent structural corruption (phantom variables from |/~).

Why it matters

A | (or bare number) entered as units in the app survives to the datamodel, and an MDL export -> re-import round trip then fails to load the model with no actionable warning. The user gets an opaque units-grammar parse error instead of either a clean model or an ExportWarning naming the offending variable/field.

Components affected

  • src/simlin-engine/src/mdl/writer.rs -- sanitize_free_text (the units | -> / substitution) and the units-emission path
  • parse_mdl (units-expression grammar) on the re-import side

Possible approaches (policy decision for the writer owner)

  1. Validate the sanitized units against the unit-expression grammar in the writer; when it fails, drop to empty units and emit an ExportWarning (consistent with the #856 warnings channel).
  2. Make the units-field | substitute a space (units-insignificant) instead of /, and treat bare-number / dangling-operator units as unrepresentable-with-warning.

Note: the units | -> / choice in sanitize_free_text was made deliberately for comment-field trailing-space idempotence, so any change should be field-specific (units vs. comment), not global.

Context

Discovered while adding property-based tests for the MDL writer (branch mdl-writer-hardening, src/simlin-engine/src/mdl/writer_proptest.rs). The units_free_text_is_structurally_safe proptest confirms the #849 sanitizer keeps units structurally safe; this issue is the separate validity gap it does not cover.

Activity

  1. added
    bugSomething isn't working
    engineIssues with the rust-based simulation engine
    on Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingengineIssues with the rust-based simulation engine

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions