Skip to content

Add engine-owned SCL workspace API - #25

Merged
masarray merged 6 commits into
mainfrom
agent/scl-workspace-api
Jul 14, 2026
Merged

Add engine-owned SCL workspace API#25
masarray merged 6 commits into
mainfrom
agent/scl-workspace-api

Conversation

@masarray

@masarray masarray commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • add an engine-owned SclWorkspaceService for opening ICD/CID/IID/SCD/SSD/XML files
  • securely load XML with DTD and external entity processing prohibited
  • resolve MMS endpoints only from direct ConnectedAP/Address parameters
  • preserve IED models even when Communication/IP data is missing or invalid
  • produce one offline LiveIedModelDiscoveryDocument per IED and AccessPoint
  • expose typed DataSet, ReportControl, GOOSE, SV, endpoint, source-hash, and finding results
  • add expected SCL versus observed live MMS model comparison
  • add focused multi-IED, offline ICD, duplicate endpoint, and model comparison tests

Why

ArIED currently implements a separate application-level SCL endpoint parser and then repeats full MMS discovery. ARIEC61850 already owns SCL semantics and offline model projection, so product applications need one reusable API rather than duplicating protocol parsing.

Application impact

ArIED can replace its SclImportService with this engine API, browse LD/LN/DO/DA offline, retain templates without IP addresses, bind endpoints later, and compare the SCL design model with a live discovery document.

Validation

GitHub Actions run .NET CI #131 completed successfully:

  • source-clean verification
  • restore
  • warnings-as-errors Release build
  • full automated test suite

The authoring environment did not contain a local .NET SDK; GitHub Actions provided the compiler and test validation gate.

@masarray
masarray marked this pull request as ready for review July 14, 2026 03:46
@masarray
masarray merged commit dd069ee into main Jul 14, 2026
1 check 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

Here are some automated review suggestions for this pull request.

Reviewed commit: 59eb92db90

ℹ️ 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".


if (!string.IsNullOrWhiteSpace(pair.Value.DataSetReference) &&
!string.IsNullOrWhiteSpace(observedReport.DataSetReference) &&
!Same(ReferenceTail(pair.Value.DataSetReference), ReferenceTail(observedReport.DataSetReference)))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Normalize report DataSet references before comparing

When the observed model comes from LiveIedModelDiscoveryBuilder, report DataSetReference values are normalized from MMS $ separators to dots, while the SCL projection keeps references such as IEDLD0/LLN0$ds. This comparison therefore reports ReportDataSetMismatch for a matching live RCB that has a datSet, causing RequiresFullDiscovery to be true even when the live model matches; normalize both tails to the same separator before calling Same.

Useful? React with 👍 / 👎.

continue;
}

if (pair.Value.MemberCount != observedDataSet.MemberCount)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Compare DataSet members by index, not just counts

For a live DataSet with the same name and member count but different FCDA members or a different order, this block adds no finding and CompareLive can still return compatible. Reports, GOOSE, and SV interpret values by DataSet member order, so using the design model after this comparison can map live values to the wrong semantic points; compare member references/FCs by index, not only MemberCount.

Useful? React with 👍 / 👎.

Comment on lines +150 to +153
DataSets = parsed.DataSets.Where(x => Same(x.IedName, descriptor.IedName)).ToArray(),
ReportControls = parsed.ReportControls.Where(x => Same(x.IedName, descriptor.IedName)).ToArray(),
GooseStreams = parsed.GooseStreams.Where(x => Same(x.IedName, descriptor.IedName)).ToArray(),
SampledValuesStreams = parsed.SampledValuesStreams.Where(x => Same(x.IedName, descriptor.IedName)).ToArray(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Filter workspace inventories by AccessPoint

When a single IED has multiple AccessPoints with distinct Server models, each per-AccessPoint workspace gets all parsed DataSets, RCBs, GOOSE, and SV streams for the IED here, even though DesignModel was filtered to descriptor.AccessPointName. An app selecting IED/P1 can therefore display or bind process-bus/report objects that belong only to P2; derive these inventories from the isolated design model or carry the AccessPoint through parsing before filtering.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

ArIED integration is now implemented and validated in masarray/arsas#20. The application PR consumes SclWorkspaceService, opens SCL offline, fast-connects from the design model, preserves source/hash/IED/AP provenance, and uses the engine comparer after Re-scan. ArIED Windows Release build and portable publish completed successfully against this engine branch.

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