Skip to content

P5C: save discovered canonical IED model as SCL - #114

Merged
masarray merged 7 commits into
mainfrom
ux/p5c-discovery-save-scl
Sep 20, 2026
Merged

masarray merged 7 commits into
mainfrom
ux/p5c-discovery-save-scl

Conversation

@masarray

@masarray masarray commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

Implements P5C from #111 from immutable P5B baseline e455608bef1cca4c35d3a04bde51f4f295c4c9ab.

Workflow

  • A Live Discovery canonical context can be saved locally as IID/ICD/CID/SCD.
  • Save SCL works after Disconnect because it projects the cached canonical model; it performs no MMS rediscovery.
  • Browser exposes Save SCL for Live Discovery authority, including offline after Disconnect.
  • Open-SCL sources are deliberately excluded from discovery reconstruction and continue to use the existing exact-source Save As path.

Architecture

  • adds pure typed MmsLiveModelDocument -> SclDocument projection in live_model_projection.hpp
  • reuses the existing typed SclExporter; no parallel XML exporter is introduced
  • preserves discovered IED identity, AP name and MMS endpoint in Communication/ConnectedAP
  • reconstructs deterministic LD/LN/DO/DA, ordered DataSets, Reports and supported GOOSE/SV/SettingGroup semantics
  • supports whole-DataObject DataSet members with parser-compatible configured vs expanded membership
  • GOOSE/SV payload projection follows expanded DataSet membership while Reports retain configured membership
  • adds IID as a first-class canonical single-IED export profile
  • serializer now preserves MMS ConnectedAP/IP context and valid SettingControl evidence

Fail-closed rules

  • ambiguous/missing IED identity is rejected
  • unresolved CDC / SCL basic type / FC is rejected
  • unknown non-ctlModel Enum ordinals are rejected rather than invented
  • unresolved ordered DataSet members are rejected
  • Open-SCL authority is rejected by the discovery reconstruction method so vendor-lossless source preservation is never silently downgraded

QA

  • new ied_discovery_scl_export_qa proves Live Discovery -> disconnect -> Save IID -> re-open -> canonical Browser context
  • asserts endpoint preservation, ordered DataSet membership, Report/GOOSE/SettingGroup reconstruction, and fail-closed unresolved CDC

Regression boundary

  • no MMS association/discovery algorithm change
  • no Report/Control/File/SettingGroup wire behavior change
  • no Simulator/Sniffer ownership change

Draft until exact-head CI is fully green.

@masarray
masarray marked this pull request as ready for review September 20, 2026 09:03
@masarray
masarray merged commit 4b2dc4a into main Sep 20, 2026
39 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

for (const auto& object : node.data_objects) {
for (const auto& attribute : object.attributes) {

P1 Badge Reject discovered data objects with no attributes

When discovery records a top-level FC point without any child DA, object.attributes is intentionally empty; this nested loop then contributes nothing for that object. If another object supplies at least one model entry, validation succeeds and the generated DataTypeTemplates silently omit the empty object, so Save SCL produces an incomplete IED model instead of failing closed. Reject such unresolved objects or preserve them through an explicit typed representation.

AGENTS.md reference: AGENTS.md:L298-L300


if (const auto value = parse_u32(report.buffer_time_ms)) {
projected.buffer_time_milliseconds = *value;
}
if (const auto value = parse_u32(report.integrity_period_ms)) {
projected.integrity_period_milliseconds = *value;
}

P1 Badge Preserve discovered report option semantics

When an RCB deep read succeeds, MmsLiveReportControl contains trigger_options and optional_fields, but this projection copies neither field while still declaring the report successfully reconstructed. The exporter consequently emits no TrgOps/OptFields, and the self-comparison cannot detect the loss because the expected SclReportControl has already discarded them; reopening the saved SCL can therefore change which events trigger reports and which report fields clients expect.

AGENTS.md reference: AGENTS.md:L310-L311


const auto projection = scl::project_live_model_to_scl(*liveModel, *edition);

P2 Badge Move live-model projection off the UI thread

For large discovered IEDs, this call performs the complete nested model traversal, map construction, and numerous string/vector allocations synchronously from the QML invocation before busy_ is even set; only serialization is queued to ioPool_. This can freeze the Browser during Save SCL and cannot be cancelled while projection is running, so snapshot copying and projection should execute in the bounded worker as well.

AGENTS.md reference: AGENTS.md:L88-L92


result.warnings = document.warnings;

P2 Badge Retain setting-group omission warnings

When a discovered SGCB lacks valid ActSG/NumOfSG evidence, the warning added above is stored in result.warnings, but this assignment replaces the entire vector with document.warnings. The setting control is therefore omitted without the promised explicit loss diagnostic, leaving users with only the generic vendor-metadata warning.

AGENTS.md reference: AGENTS.md:L307-L311



P1 Badge Validate the generated SCL before replacing the target

If reparsing or semantic comparison fails, the destination has already been atomically committed and may have replaced a previously valid engineering file even though the UI reports that Save SCL was rejected. This occurs, for example, for an RCB whose live binding status is ReadFailed: projection records unresolved, serialization omits datSet, reparsing yields not_specified, and the comparison fails only after replacement. Perform round-trip validation on temporary output before committing it to the requested path.

AGENTS.md reference: AGENTS.md:L310-L311

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant