Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
dotnet-version: ['8.x', '9.x', '10.x']
dotnet-version: ['10.x']

steps:
# === INSTALL DEPENDENCIES ===
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ documentation, CI/CD pipelines, and AI-assisted modeling workflows.
- **Self-Validation**: Built-in validation tests with TRX/JUnit output for regulated
environments
- **Multi-Platform Support**: Builds and runs on Windows, Linux, and macOS
- **Multi-Runtime Support**: Targets .NET 8, 9, and 10
- **Multi-Runtime Support**: CLI tool targets .NET 10; library packages (`Core`/`Language`/
`Stdlib`) support .NET 8, 9, and 10

## Installation

Expand Down
34 changes: 34 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,40 @@ that:
local feed → restore → exercise parse→layout→render-to-SVG-in-memory and render-to-PNG (again
proving SkiaSharp natives for `.Png` consumers).

### Tool package size (confirmed: 435 MB, over NuGet.org's ~250 MB limit)

Packing `DemaConsulting.SysML2Tools.Tool` locally confirmed a **434.94 MB** `.nupkg` — well past
NuGet.org's hard size limit. Inspecting the archive found three compounding, independently
fixable causes:

1. **Native SkiaSharp debug symbols ship in the package.** `761.7 MB` (57%) of the uncompressed
content is `libSkiaSharp.pdb` (Windows x86/x64/arm64) — third-party native debug symbols nobody
debugs into. These arrive as ordinary content files from the transitive `SkiaSharp` package (via
`DemaConsulting.Rendering.Skia`) and are not excluded today. **Fix:** add an MSBuild target
(e.g. `BeforeTargets="_GetPackageFiles"` or the tool-packing equivalent) that filters
`**/native/*.pdb` out of the packed file list.
2. **Full triplication from multi-targeting.** `Tool` targets `net8.0;net9.0;net10.0`, and
`PackAsTool` stages a complete, independent `tools/{tfm}/any/runtimes/**` tree per TFM — tripling
every native asset. **.NET 9 is STS and already out of support**; `.NET 8` (LTS, supported to
Nov 2026) and `.NET 10` (current LTS) are the only versions worth shipping. **Decision: target
`net10.0` only** for the `Tool` package (single TFM, maximal size reduction; `Core`/`Language`/
`Stdlib` remain multi-targeted `net8.0;net9.0;net10.0` since they're ordinary libraries consumed
by projects on any of those TFMs — this change is scoped to `Tool` only).
3. **Untrimmed RID matrix.** The transitive `SkiaSharp` native-asset packages bundle every RID
SkiaSharp supports, including ones this project doesn't need to support (`linux-loongarch64`,
`linux-bionic-*`, `linux-musl-loongarch64`, etc.). The `Tool.csproj`'s own OS-conditioned
`SkiaSharp.NativeAssets.{Win32,Linux.NoDependencies,macOS}` references are effectively
redundant/dead — the full matrix arrives unconditionally via `DemaConsulting.Rendering.Skia`
regardless of host OS. **Fix:** pin an explicit, curated RID list (Windows x64/x86/arm64, Linux
x64/arm64 + musl x64/arm64, macOS x64/arm64) so only supported platforms are packaged.

**Scope:** `src/DemaConsulting.SysML2Tools.Tool/DemaConsulting.SysML2Tools.Tool.csproj` only.
**Visual/verification gate:** `dotnet pack` the `Tool` project and confirm the resulting
`.nupkg` is comfortably under NuGet.org's limit (target: well under 100 MB); the packed tool must
still install and render correctly (SVG + PNG) on at least the currently-tested OS matrix
(Windows/Linux/macOS) — this is exactly what the "Package validation gate" tool smoke test above
already covers, so it doubles as the regression check for this fix.

### Licensing, docs, gallery, publish

- **Licensing/attribution:** `--licenses` output covering Noto Sans (SIL OFL 1.1) and other OTS;
Expand Down
2 changes: 1 addition & 1 deletion docs/design/sysml2-tools-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ N/A - not a safety-classified software item.

## Design Constraints

- Platform: multi-targets net8.0, net9.0, and net10.0 framework compatibility specifications on Windows, Linux, and macOS.
- Platform: targets net10.0 framework compatibility specifications on Windows, Linux, and macOS.
- Threading: single-threaded console application; no shared mutable state between invocations.
- Immutability: `Context` properties are set once at construction via `init` accessors and are
read-only thereafter.
Expand Down
2 changes: 1 addition & 1 deletion docs/design/sysml2-tools-tool/program.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ accessor is hand-written (a thin static class with one `ResourceManager` field a
`public static string` property per resx key) rather than generated by the Visual Studio
"ResXFileCodeGenerator" custom tool, because that generator only runs inside Visual Studio —
a hand-written class builds identically under `dotnet build`/CI on every target framework
(net8.0/net9.0/net10.0), with or without an IDE. Adding a future locale (e.g., French)
(net10.0), with or without an IDE. Adding a future locale (e.g., French)
requires zero code changes: adding `ProgramStrings.fr.resx` with the same key names is
enough — the .NET SDK's default resx-embedding behavior produces a satellite assembly that
`ResourceManager` discovers automatically based on the current UI culture, falling back to
Expand Down
20 changes: 1 addition & 19 deletions docs/reqstream/sysml2-tools-tool/platform-requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@
# These requirements specify the platforms and runtimes the tool must support.
# They ensure the tool works across the required execution environments.
#
# Test links can include a source filter prefix (e.g. "windows@", "ubuntu@", "dotnet8.x@") to restrict
# Test links can include a source filter prefix (e.g. "windows@", "ubuntu@", "dotnet10.x@") to restrict
# which test results count as evidence for a requirement. This is critical for platform and runtime
# requirements - removing these filters invalidates the evidence-based proof.
#
# Source filter prefixes:
# windows@TestName - proves the test passed on a Windows platform
# ubuntu@TestName - proves the test passed on a Linux (Ubuntu) platform
# macos@TestName - proves the test passed on a macOS platform
# dotnet8.x@TestName - proves the self-validation test ran with .NET 8.x runtime
# dotnet9.x@TestName - proves the self-validation test ran with .NET 9.x runtime
# dotnet10.x@TestName - proves the self-validation test ran with .NET 10.x runtime

sections:
Expand Down Expand Up @@ -46,22 +44,6 @@ sections:
- "macos@TemplateTool_VersionDisplay"
- "macos@TemplateTool_HelpDisplay"

- id: Template-Platform-Net8
title: The tool shall support .NET 8 runtime.
justification: |
.NET 8 is an LTS release providing long-term stability for enterprise users.
tests:
- "dotnet8.x@TemplateTool_VersionDisplay"
- "dotnet8.x@TemplateTool_HelpDisplay"

- id: Template-Platform-Net9
title: The tool shall support .NET 9 runtime.
justification: |
.NET 9 support enables users to leverage the latest .NET features.
tests:
- "dotnet9.x@TemplateTool_VersionDisplay"
- "dotnet9.x@TemplateTool_HelpDisplay"

- id: Template-Platform-Net10
title: The tool shall support .NET 10 runtime.
justification: |
Expand Down
8 changes: 4 additions & 4 deletions docs/verification/sysml2-tools-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ Detailed, per-subsystem verification for each of the tool's eight subsystems (`C

## Test Environment

Integration tests run on .NET 8.0, .NET 9.0, and .NET 10.0 across Windows, Linux, and macOS.
All scenarios are expected to produce identical results on all supported runtime and platform
combinations. Temporary files and directories are created and cleaned up within each test.
Integration tests run on .NET 10.0 across Windows, Linux, and macOS. All scenarios are expected
to produce identical results on all supported platforms. Temporary files and directories are
created and cleaned up within each test.

## Acceptance Criteria

- All integration tests pass with zero failures across all supported runtimes and platforms.
- All integration tests pass with zero failures across all supported platforms.
- Exit code 0 is returned for all valid invocations.
- Exit code non-zero is returned for all invalid argument combinations.
- Results files are created at the specified paths when `--results` is used with `--validate`.
Expand Down
4 changes: 2 additions & 2 deletions docs/verification/sysml2-tools-tool/export.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ test in `test/DemaConsulting.SysML2Tools.Tool.Tests/SelfTest/ValidationTests.cs`
invoke `Context.Create`, `ExportCommand.RunAsync`, `Program.RunAsync`, and (for the
end-to-end scenario) the built tool as a real process via `Runner.Run`, asserting on
captured console output, exit code, produced file content, and deserialized JSON/JSONL
shape. Tests run against all three target frameworks.
shape. Tests run against the tool's target framework.

#### Test Environment

- Framework: xUnit v3
- Target frameworks: net8.0, net9.0, net10.0
- Target framework: net10.0
- Test project: `DemaConsulting.SysML2Tools.Tool.Tests`
- Dependencies: `DemaConsulting.SysML2Tools.Tool` (internal access via `InternalsVisibleTo`);
OMG reference models under `test/SysMLModels/OMG/` (locatable via a repo-root search
Expand Down
4 changes: 2 additions & 2 deletions docs/verification/sysml2-tools-tool/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ The Help subsystem is verified using unit/integration tests in two files under
`HelpArgumentParser.Parse` directly (parser-only tests), and `Context.Create` +
`Program.RunAsync` (end-to-end tests), asserting on captured console output, exit code, and
byte-for-byte parity between `help <command>[<verb>]` and `<command> [<verb>] --help`. Tests
run against all three target frameworks.
run against the tool's target framework.

#### Test Environment

- Framework: xUnit v3
- Target frameworks: net8.0, net9.0, net10.0
- Target framework: net10.0
- Test project: `DemaConsulting.SysML2Tools.Tool.Tests`
- Dependencies: `DemaConsulting.SysML2Tools.Tool` (internal access via `InternalsVisibleTo`)

Expand Down
6 changes: 3 additions & 3 deletions docs/verification/sysml2-tools-tool/query.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ The Query subsystem is verified using unit/integration tests in five files under
`test/DemaConsulting.SysML2Tools.Tool.Tests/Cli/ContextTests.cs`. Tests invoke
`Context.Create`, `QueryCommand.RunAsync`, `Program.RunAsync`, and (for a subset of
real-workspace scenarios) `QueryEngine`'s verb methods directly, asserting on captured
console output, exit code, and `QueryResult` shape. Tests run against all three target
frameworks.
console output, exit code, and `QueryResult` shape. Tests run against the tool's target
framework.

#### Test Environment

- Framework: xUnit v3
- Target frameworks: net8.0, net9.0, net10.0
- Target framework: net10.0
- Test project: `DemaConsulting.SysML2Tools.Tool.Tests`
- Dependencies: `DemaConsulting.SysML2Tools.Tool` (internal access via `InternalsVisibleTo`);
OMG reference models under `test/SysMLModels/OMG/` (locatable via a repo-root search
Expand Down
4 changes: 2 additions & 2 deletions docs/verification/sysml2-tools-tool/render.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ The Render subsystem is verified using unit tests in
`test/DemaConsulting.SysML2Tools.Tool.Tests/Render/RenderSubsystemTests.cs`.
Tests invoke `Program.RunAsync` with controlled `Context` instances and assert
on context output and exit code. File-writing scenarios use a temporary directory
(`Path.GetTempPath()`). Tests run against all three target frameworks.
(`Path.GetTempPath()`). Tests run against the tool's target framework.

### Test Environment

- Framework: xUnit v3
- Target frameworks: net8.0, net9.0, net10.0
- Target framework: net10.0
- Test project: `DemaConsulting.SysML2Tools.Tool.Tests`
- Dependencies: `DemaConsulting.SysML2Tools.Tool` (internal access via `InternalsVisibleTo`)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down Expand Up @@ -50,11 +50,19 @@
<!-- Runtime Dependencies -->
<ItemGroup>
<PackageReference Include="DemaConsulting.TestResults" Version="1.9.0" />
<PackageReference Include="SkiaSharp.NativeAssets.Win32" Version="4.148.0" Condition="$([MSBuild]::IsOSPlatform('Windows'))" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="4.148.0" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="SkiaSharp.NativeAssets.macOS" Version="4.148.0" Condition="$([MSBuild]::IsOSPlatform('macOS'))" />
</ItemGroup>

<!-- Curated, semicolon-delimited set of RIDs whose native SkiaSharp assets are kept in the
published tool. All other RIDs shipped transitively by SkiaSharp's NativeAssets packages
are trimmed by the TrimPublishedNativeAssets target below, since a dotnet global tool
cannot be built with <RuntimeIdentifiers> (that triggers per-RID package splitting and
breaks packing with NU5017).
Note: SkiaSharp.NativeAssets.macOS ships a single universal dylib under RID "osx" (not
split into osx-x64/osx-arm64), so only "osx" is listed for macOS. -->
<PropertyGroup>
<SupportedNativeAssetRids>;win-x64;win-x86;win-arm64;linux-x64;linux-arm64;linux-musl-x64;linux-musl-arm64;osx;</SupportedNativeAssetRids>
</PropertyGroup>

<!-- Build Tool Dependencies -->
<ItemGroup>
<PackageReference Include="Microsoft.Sbom.Targets" Version="4.1.5" PrivateAssets="All" />
Expand Down Expand Up @@ -99,4 +107,41 @@
<None Include="..\..\Icon.png" Pack="true" PackagePath="\" />
</ItemGroup>

<!--
Trims the published/packed output down to the native SkiaSharp assets this tool actually
supports, dramatically reducing the packed NuGet tool size (see ROADMAP.md "Tool package
size").

Native ".pdb" debug symbol files and non-curated RID folders arrive unconditionally as part
of the publish output (via DemaConsulting.Rendering.Skia's transitive SkiaSharp dependency,
which resolves native assets for every RID regardless of build host OS). These files are NOT
Content/None pack items, so hooking BeforeTargets="_GetPackageFiles" (filtering
Content/None) has no effect on them - they are built directly from
@(ResolvedFileToPublish)/@(_PublishFiles) by the PackTool SDK targets.

This target must run AfterTargets="ComputeResolvedFilesToPublishList" - the target that
populates @(ResolvedFileToPublish) - so the removals happen before publish output is copied
and before "dotnet pack" consumes it. This dependency on internal/undocumented SDK target
and item names (ComputeResolvedFilesToPublishList, ResolvedFileToPublish) could break in a
future .NET SDK release; if package size regresses unexpectedly after an SDK upgrade, verify
this target still fires and still matches the expected paths.
-->
<Target Name="TrimPublishedNativeAssets" AfterTargets="ComputeResolvedFilesToPublishList">
<ItemGroup>
<!-- Remove native debug symbol (.pdb) files - never needed at runtime. -->
<ResolvedFileToPublish
Remove="@(ResolvedFileToPublish)"
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\', '/').Contains('/native/'))
and $([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').EndsWith('.pdb'))" />

<!-- Remove "runtimes/<rid>/..." entries for RIDs not in the curated
$(SupportedNativeAssetRids) allowlist declared above. The RID segment is the path
component immediately after "runtimes/" (e.g. "runtimes/linux-arm/native/..." -> "linux-arm"). -->
<ResolvedFileToPublish
Remove="@(ResolvedFileToPublish)"
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\', '/').StartsWith('runtimes/'))
and !$(SupportedNativeAssetRids.Contains(';$([System.String]::Copy(`%(ResolvedFileToPublish.RelativePath)`).Replace(`\`, `/`).Split(`/`)[1]);'))" />
</ItemGroup>
</Target>

</Project>
2 changes: 1 addition & 1 deletion src/DemaConsulting.SysML2Tools.Tool/ProgramStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace DemaConsulting.SysML2Tools;
/// <c>ProgramStrings.resx</c>. Deliberately not generated by the Visual Studio
/// "ResXFileCodeGenerator" custom tool, because that generator only runs inside Visual
/// Studio and is not invoked by <c>dotnet build</c>/CI — this class must build identically
/// everywhere <c>dotnet build</c> runs (net8.0/net9.0/net10.0, any OS, any IDE or none).
/// everywhere <c>dotnet build</c> runs (net10.0, any OS, any IDE or none).
/// </summary>
/// <remarks>
/// Adding a future locale requires zero code changes: place a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<!-- Build Configuration -->
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down