Skip to content

Mission.validate(): structured parse-only diagnostics #153

Description

@djankov

Goal

Add Mission.validate(path) — a parse-only classmethod that loads a script through GMAT, captures the engine's log, and returns structured diagnostics. Today Mission.load exposes only the bool from gmat.LoadScript; the actual error / warning text is written into the GMAT log file and never reaches the caller. Downstream consumers that want to surface what GMAT thinks of a script without committing to a run() (LLM authoring loops, CI lint gates, batch screening) currently have to re-implement the load-with-log-capture pattern by hand.

Interface

@dataclass(frozen=True)
class ParseDiagnostic:
    line: int | None     # populated when GMAT's message carries `in line: "<N>: …"`
    message: str         # cleaned Interpreter Exception / warning text
    raw: str             # original log line, for fallback when scraping misses something

@dataclass(frozen=True)
class LoadDiagnostics:
    ok: bool                          # LoadScript returned True AND post-load init didn't raise
    errors: list[ParseDiagnostic]
    warnings: list[ParseDiagnostic]
    summary: MissionSummary | None    # populated on ok=True; None on parse failure
    raw_log: str                      # verbatim GMAT log, escape hatch

class Mission:
    @classmethod
    def validate(cls, path, *, gmat_root=None) -> LoadDiagnostics: ...

Semantics:

  • Bypasses LoadScript's bool-only contract by redirecting UseLogFile to a temp file across the load, scraping *** ERROR *** / Interpreter Exception: / *** WARNING *** markers, then resetting the log handle.
  • Runs the same _initialize_spacecraft step Mission.load does — an APIException there sets ok=False and lands in errors. Does not call sandbox-wide gmat.Initialize() (breaks EventLocator scripts; see the existing comment in Mission.load).
  • summary is built via build_mission_summary on success so callers get the resource + command inventory for free.
  • Known false-negative: GMAT's interpreter silently accepts missing semicolons and similar lenient-syntax cases. Document in the docstring.

Error / warning format anchors

Three patterns observed in R2026a logs:

**** ERROR **** Interpreter Exception: <message> in line:
   "<line_number>: <line_text>"

Interpreter Exception: <path>: <message>           # no line context

*** WARNING ***  <message>

Out of scope

  • Static analysis beyond what GMAT itself emits.
  • Applying field overrides before the validate.
  • Reformatting / pretty-printing scripts.

Acceptance

  • Mission.validate(<valid>)ok=True, empty errors/warnings, populated summary.
  • Mission.validate(<unknown-field>)ok=False, ≥1 error with line+message, summary is None.
  • Mission.validate(<missing-BeginMissionSequence>)ok=True, ≥1 warning, populated summary.
  • Integration test against a stock GMAT sample plus a handcrafted bad script.
  • Docstring carries the known-lenient-syntax callout.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions