From 61c5feda388bd815ae69d9b004cd46757972a319 Mon Sep 17 00:00:00 2001 From: Malcolm Nixon Date: Tue, 7 Jul 2026 20:08:02 -0400 Subject: [PATCH 1/2] Split SysML2 model into per-System/Subsystem/Unit files with artifact-location metadata - Split docs/sysml2/{system}.sysml into docs/sysml2/model/ mirroring the folder depth of docs/design/, docs/reqstream/, and docs/verification/ (one file per System/Subsystem/Unit); docs/sysml2/views/ remains a sibling of model/. - Added named comment metadata (sourceRef/testRef/designRef/verificationRef/ reqRef) to each part def so agents can query companion-artifact locations via 'sysml2tools query describe' without grepping the source tree. - Bumped demaconsulting.sysml2tools.tool to 0.1.0-beta.5, which added native recursive glob expansion to lint/render/query. Simplified build.yaml's render step (plain PowerShell, no shell: bash/globstar workaround) and lint.ps1's sysml2 lint step (single quoted glob, no Get-ChildItem/content-filter). - Rewrote sysml2-modeling.md (repository structure, model content, artifact- location comments, build/lint integration, diagram embedding) and the sysml2tools-query skill (new paths, artifact-location metadata section, beta.5 quoted-glob examples) to document the new approach. - Added a one-sentence cross-reference in software-items.md's Software Item Artifact Model section pointing at the new SysML2 comment metadata. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .config/dotnet-tools.json | 2 +- .github/skills/sysml2tools-query/SKILL.md | 89 +++++++++---- .github/standards/software-items.md | 5 + .github/standards/sysml2-modeling.md | 120 ++++++++++++++---- .github/workflows/build.yaml | 13 +- docs/sysml2/dictionary-mark.sysml | 111 ---------------- docs/sysml2/model/dictionary-mark.sysml | 26 ++++ docs/sysml2/model/dictionary-mark/cli.sysml | 12 ++ .../model/dictionary-mark/cli/context.sysml | 11 ++ .../model/dictionary-mark/dictionary.sysml | 56 ++++++++ .../dictionary/conflict-detector.sysml | 11 ++ .../dictionary/dictionary-generator.sysml | 11 ++ .../dictionary/markdown-formatter.sysml | 11 ++ .../dictionary/yaml-loader.sysml | 11 ++ .../model/dictionary-mark/program.sysml | 11 ++ .../model/dictionary-mark/self-test.sysml | 12 ++ .../self-test/validation.sysml | 11 ++ .../model/dictionary-mark/utilities.sysml | 14 ++ .../utilities/glob-matcher.sysml | 11 ++ .../utilities/path-helpers.sysml | 11 ++ .../utilities/temporary-directory.sysml | 11 ++ docs/sysml2/model/ots.sysml | 27 ++++ docs/sysml2/ots.sysml | 15 --- lint.ps1 | 9 +- 24 files changed, 432 insertions(+), 189 deletions(-) delete mode 100644 docs/sysml2/dictionary-mark.sysml create mode 100644 docs/sysml2/model/dictionary-mark.sysml create mode 100644 docs/sysml2/model/dictionary-mark/cli.sysml create mode 100644 docs/sysml2/model/dictionary-mark/cli/context.sysml create mode 100644 docs/sysml2/model/dictionary-mark/dictionary.sysml create mode 100644 docs/sysml2/model/dictionary-mark/dictionary/conflict-detector.sysml create mode 100644 docs/sysml2/model/dictionary-mark/dictionary/dictionary-generator.sysml create mode 100644 docs/sysml2/model/dictionary-mark/dictionary/markdown-formatter.sysml create mode 100644 docs/sysml2/model/dictionary-mark/dictionary/yaml-loader.sysml create mode 100644 docs/sysml2/model/dictionary-mark/program.sysml create mode 100644 docs/sysml2/model/dictionary-mark/self-test.sysml create mode 100644 docs/sysml2/model/dictionary-mark/self-test/validation.sysml create mode 100644 docs/sysml2/model/dictionary-mark/utilities.sysml create mode 100644 docs/sysml2/model/dictionary-mark/utilities/glob-matcher.sysml create mode 100644 docs/sysml2/model/dictionary-mark/utilities/path-helpers.sysml create mode 100644 docs/sysml2/model/dictionary-mark/utilities/temporary-directory.sysml create mode 100644 docs/sysml2/model/ots.sysml delete mode 100644 docs/sysml2/ots.sysml diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 7e04a47..edf4c35 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -73,7 +73,7 @@ "rollForward": false }, "demaconsulting.sysml2tools.tool": { - "version": "0.1.0-beta.4", + "version": "0.1.0-beta.5", "commands": [ "sysml2tools" ], diff --git a/.github/skills/sysml2tools-query/SKILL.md b/.github/skills/sysml2tools-query/SKILL.md index 65f74b2..ffb42f3 100644 --- a/.github/skills/sysml2tools-query/SKILL.md +++ b/.github/skills/sysml2tools-query/SKILL.md @@ -20,30 +20,65 @@ dotnet tool restore ## Model files -- `docs/sysml2/{system-name}.sysml` — one file per system: subsystems, units, purpose - `doc` comments, and dependency usages. A repository may contain more than one system. -- `docs/sysml2/ots.sysml` — off-the-shelf (OTS) dependency parts (present when OTS items +- `docs/sysml2/model/{system-name}.sysml` — system-level `part def` only (no subsystems/units + inline). A repository may contain more than one system. +- `docs/sysml2/model/{system-name}/{subsystem-name}.sysml` and + `docs/sysml2/model/{system-name}/{subsystem-name}/{unit-name}.sysml` — one file per + Subsystem/Unit, nested to mirror the same folder depth as that item's companion + `docs/design/`, `docs/reqstream/`, and `docs/verification/` files. +- `docs/sysml2/model/ots.sysml` — off-the-shelf (OTS) dependency parts (present when OTS items exist). -- `docs/sysml2/shared.sysml` — Shared Package parts (present when Shared Package items +- `docs/sysml2/model/shared.sysml` — Shared Package parts (present when Shared Package items exist). -- `docs/sysml2/views/design-views.sysml` — named views rendered for the design document; - not usually needed for query workflows, but useful to see how diagrams are scoped. +- `docs/sysml2/views/design-views.sysml` — named views rendered for the design document; a + sibling of `model/`, not nested inside it. Not usually needed for query workflows, but + useful to see how diagrams are scoped. Always pass all `.sysml` files (or a glob covering them) to every `sysml2tools` -invocation — the model spans multiple files and cross-references between them. -Note: `sysml2tools` does not expand `*` glob patterns itself; either let the shell -expand an unquoted wildcard, or list the files explicitly: +invocation — the model spans multiple files and cross-references between them; files that +reopen the same `package Name { ... }` from different files merge into one namespace +automatically, no `import` required. As of `sysml2tools` 0.1.0-beta.5, every subcommand +(`lint`, `render`, `query`) expands `*`/`**` glob patterns internally and recurses +correctly — pass a single **quoted** glob string and let the tool resolve it, rather than +relying on the shell (quoting works identically in both PowerShell and bash): ```pwsh -dotnet sysml2tools query list docs/sysml2/*.sysml +dotnet sysml2tools query list 'docs/sysml2/model/**/*.sysml' ``` +## Artifact-location metadata + +Every System/Subsystem/Unit `part def` carries named `comment` elements pointing at its +companion artifacts (source, test, design, verification, and — for now, since this repo +still uses ReqStream — requirements file). `query describe` returns every comment attached to +an element, so one query gets you every artifact location for that item without grepping the +source tree: + +```pwsh +dotnet sysml2tools query describe -e DictionaryMark::YamlDictionaryLoader 'docs/sysml2/model/**/*.sysml' +``` + +```text +- Documentation: Loads YAML flat-dictionary files. +- Comment: Source: src/DemaConsulting.DictionaryMark/Dictionary/YamlDictionaryLoader.cs +- Comment: Test: test/DemaConsulting.DictionaryMark.Tests/Dictionary/YamlDictionaryLoaderTests.cs +- Comment: Design: docs/design/dictionary-mark/dictionary/yaml-loader.md +- Comment: Verification: docs/verification/dictionary-mark/dictionary/yaml-loader.md +- Comment: Requirements: docs/reqstream/dictionary-mark/dictionary/yaml-loader.yaml +``` + +Not every item has all five comments — Systems/Subsystems have no `Source` comment, and +units without a dedicated companion doc point at their parent's doc instead (see the +Artifact-Location Comments section of `sysml2-modeling.md` for the full rules). Prefer these +paths over guessing a file location from the unit name; fall back to `grep`/`glob` only when +a comment is missing or the model is stale. + ## Recommended workflow 1. **Discover the system(s) present** — do not assume a fixed name: ```pwsh - dotnet sysml2tools query list --kind "part def" docs/sysml2/*.sysml + dotnet sysml2tools query list --kind "part def" 'docs/sysml2/model/**/*.sysml' ``` Look for the top-level part def with no containing part (or the one with the most @@ -52,23 +87,25 @@ dotnet sysml2tools query list docs/sysml2/*.sysml 2. **Get the full hierarchy** (subsystems and units) for a system found above: ```pwsh - dotnet sysml2tools query describe -e docs/sysml2/*.sysml + dotnet sysml2tools query describe -e 'docs/sysml2/model/**/*.sysml' ``` - `describe` lists direct children; repeat on each child to walk deeper, or use - `query list` to see the full flat inventory. + `describe` lists direct children and every artifact-location comment; repeat on each + child to walk deeper, or use `query list` to see the full flat inventory. -3. **Understand a specific unit's purpose** before opening its source file: +3. **Understand a specific unit's purpose and find its files** before opening its source + file — `describe` returns both the purpose `doc` and every `Comment:` artifact-location + line in one call (see Artifact-location metadata above): ```pwsh - dotnet sysml2tools query describe -e docs/sysml2/*.sysml + dotnet sysml2tools query describe -e 'docs/sysml2/model/**/*.sysml' ``` 4. **Assess impact before editing a unit** — see what depends on it: ```pwsh - dotnet sysml2tools query used-by -e docs/sysml2/*.sysml - dotnet sysml2tools query impact -e docs/sysml2/*.sysml + dotnet sysml2tools query used-by -e 'docs/sysml2/model/**/*.sysml' + dotnet sysml2tools query impact -e 'docs/sysml2/model/**/*.sysml' ``` Note: this only surfaces structural (typing/containment) references modeled in @@ -78,24 +115,24 @@ dotnet sysml2tools query list docs/sysml2/*.sysml 5. **Trace requirements** linked to a unit, if modeled: ```pwsh - dotnet sysml2tools query requirements -e docs/sysml2/*.sysml + dotnet sysml2tools query requirements -e 'docs/sysml2/model/**/*.sysml' ``` 6. **Search by name or kind** when the qualified name is unknown: ```pwsh - dotnet sysml2tools query find --name docs/sysml2/*.sysml - dotnet sysml2tools query list --kind "part def" docs/sysml2/*.sysml + dotnet sysml2tools query find --name 'docs/sysml2/model/**/*.sysml' + dotnet sysml2tools query list --kind "part def" 'docs/sysml2/model/**/*.sysml' ``` Use `--format json` on any query verb for machine-parsed output. ## Fallback -If the model is stale, doesn't yet cover a unit, or a query returns nothing useful, -fall back to `grep`/`glob`/reading source directly. When you finish work that adds -or changes a Unit/Subsystem, update the corresponding `.sysml` model file in the -same change (mirrors the existing requirement to keep `docs/design/*.md` and +If the model is stale, doesn't yet cover a unit, or a query returns nothing useful, fall +back to `grep`/`glob`/reading source directly. When you finish work that adds or changes a +Unit/Subsystem, update the corresponding `.sysml` model file (including its artifact-location +comments) in the same change (mirrors the existing requirement to keep `docs/design/*.md` and `docs/reqstream/*.yaml` companion artifacts in sync). See the `sysml2-modeling.md` standard for full modeling and view-authoring conventions. @@ -104,5 +141,5 @@ standard for full modeling and view-authoring conventions. Before committing changes to any `.sysml` file, lint it: ```pwsh -dotnet sysml2tools lint docs/sysml2/*.sysml +dotnet sysml2tools lint 'docs/sysml2/**/*.sysml' ``` diff --git a/.github/standards/software-items.md b/.github/standards/software-items.md index 6c29525..3514228 100644 --- a/.github/standards/software-items.md +++ b/.github/standards/software-items.md @@ -130,3 +130,8 @@ the item is correct, well-designed, and proven to work: - **Verification Design** - HOW the requirements will be tested (applies to all item types) - **Source code** - The implementation of the design (local units only; not applicable to OTS or Shared Package) - **Tests** - PROOF the item does WHAT it is required to do (applies to all item types) + +Where the repository models its software structure in SysML2, each item's part def carries +`comment` metadata pointing at these same artifact locations (`sourceRef`/`testRef`/ +`designRef`/`verificationRef`/`reqRef`) so agents can query them directly — see +`sysml2-modeling.md`. diff --git a/.github/standards/sysml2-modeling.md b/.github/standards/sysml2-modeling.md index e14778b..60f7b96 100644 --- a/.github/standards/sysml2-modeling.md +++ b/.github/standards/sysml2-modeling.md @@ -28,33 +28,96 @@ why it exists, and what it depends on. ```text docs/sysml2/ -├── {system-name}.sysml # one file per system: subsystems, units, doc comments -├── ots.sysml # OTS dependency parts (optional; if OTS items exist) -├── shared.sysml # Shared Package parts (optional; if Shared Packages exist) +├── model/ +│ ├── {system-name}.sysml # system-level part def only (no subsystems/units inline) +│ ├── {system-name}/ +│ │ ├── {subsystem-name}.sysml # subsystem part def; nests further for sub-subsystems +│ │ └── {subsystem-name}/ +│ │ └── {unit-name}.sysml # one file per unit +│ ├── ots.sysml # OTS dependency parts (optional; if OTS items exist) +│ └── shared.sysml # Shared Package parts (optional; if Shared Packages exist) └── views/ - └── design-views.sysml # named view usages rendered for the design document + └── design-views.sysml # named view usages rendered for the design document ``` +`docs/sysml2/model/` mirrors the same folder shape as `docs/design/`, `docs/reqstream/`, and +`docs/verification/` — one `.sysml` file per System/Subsystem/Unit, at the same nesting depth +as that item's companion design/requirements/verification files. This keeps each file small +and keeps PRs that touch one unit's model from producing unrelated diffs in unrelated units. +`docs/sysml2/views/` is a sibling of `model/`, not nested inside it, so a single +`docs/sysml2/model/**/*.sysml` glob never needs to exclude view files (`sysml2tools` has no +exclude-glob syntax). + There is no separate "stable entry point" file — a repository may contain multiple systems, so no single alias name would generalize. Agents discover the system(s) present by running `query list --kind "part def"` or `query find` (see the `sysml2tools-query` skill) over -`docs/sysml2/*.sysml`, not by assuming a fixed name. +`docs/sysml2/model/**/*.sysml`, not by assuming a fixed name. Always pass the full set of `.sysml` files (or an equivalent glob) to every `sysml2tools` -invocation — the model spans multiple files and cross-references between them. Note: -`sysml2tools` does not expand `*` glob patterns itself; either let the shell expand an -unquoted wildcard, or list files explicitly in scripts/CI. +invocation — the model spans multiple files and cross-references between them; files sharing +the same `package Name { ... }` merge into one namespace automatically with no `import` +required, as long as all files are passed together. As of `sysml2tools` 0.1.0-beta.5, +`lint` and `render` both expand `*`/`**` glob patterns internally (recursing correctly into +subdirectories), so pass a single **quoted** glob string (e.g. `'docs/sysml2/**/*.sysml'`) +and let the tool resolve it — do not rely on the shell to expand it, and do not quote-strip +the pattern before it reaches the tool. Quoting keeps the behavior identical across +PowerShell and bash, since neither shell needs to (or reliably does) expand `**` itself. ## Model Content -- `{system-name}.sysml` defines one `part def` per System, Subsystem, and Unit, with a - `doc /* ... */` comment on each stating its purpose — mirroring what would otherwise be - written as prose in `docs/design/introduction.md`'s Software Structure section. -- Subsystems nest as `part` usages inside their parent's `part def`, matching the Software - Item Hierarchy in `software-items.md`. +- `{system-name}.sysml` defines one `part def` for the System only, with `part` usages + referencing its direct Subsystems/Units (defined in their own files, see below). +- Each `{subsystem-name}.sysml` / `{unit-name}.sysml` defines exactly one `part def`, with a + `doc /* ... */` comment stating its purpose — mirroring what would otherwise be written as + prose in `docs/design/introduction.md`'s Software Structure section. Subsystem files add + `part` usages for their own direct children (nested subsystems or units), matching the + Software Item Hierarchy in `software-items.md`. - `ots.sysml` / `shared.sysml` define one `part def` per OTS item / Shared Package, referenced as `part` usages from the system(s) that depend on them. +## Artifact-Location Comments + +Every System/Subsystem/Unit `part def` records where its companion artifacts live, as named +`comment` elements — not `attribute`s (attribute values are not surfaced by `sysml2tools query +describe`, even in JSON output; comments are). Comments have zero effect on rendered diagrams +(verified: a part def with several comments attached renders with no extra nodes or size +change) and are fully returned by `query describe`, in declaration order, as +`Comment: ...` summary lines — this is how an agent gets every artifact location for a unit +in a single query, without grepping the source tree. + +Use these comment names, in this order, when applicable to the item: + +```sysml +part def {UnitName} { + doc /* One-line purpose statement. */ + + comment sourceRef /* Source: {path to the unit's source file} */ + comment testRef /* Test: {path to the unit's test file} */ + comment designRef /* Design: {path to the unit's design doc} */ + comment verificationRef /* Verification: {path to the unit's verification doc} */ + comment reqRef /* Requirements: {path to the unit's reqstream file} */ +} +``` + +Not every item has all five: + +- **Systems and Subsystems** have no `sourceRef` (no single source file represents a whole + system or subsystem) — use `testRef` for the subsystem-level test file when one exists. +- **Units without a dedicated companion doc** (e.g. small data-model types documented inline + within their subsystem's design doc rather than in their own file) point `designRef` / + `verificationRef` / `reqRef` at the subsystem-level doc, with a short parenthetical note, + e.g. `/* Design: docs/design/{system}/{subsystem}.md (documented as a supporting value type) */`. +- **Units without a dedicated test file** (exercised only indirectly through another unit's + tests) omit `testRef` entirely rather than pointing at an unrelated test file. +- **OTS items** have no `sourceRef`/`testRef` (no local integration code); use `designRef` + (when the optional design doc exists) / `verificationRef` / `reqRef` only. + +This is prose-searchable metadata only — it is not a substitute for the authoritative +requirements/design/verification artifacts, and it does not replace ReqStream as the +requirements source of truth. (This repository currently keeps requirements traceability in +ReqStream; a future migration to native SysML2 `requirement`/`satisfy` modeling is a separate, +not-yet-scheduled change.) + ## Views (`docs/sysml2/views/design-views.sysml`) Views control what gets rendered into diagrams for the design document. Use named `view` @@ -101,12 +164,15 @@ whichever produces a single coherent overview diagram. ## Diagram Embedding -Render with: +Render with a single quoted recursive glob for the model tree, plus the views file +(`sysml2tools` 0.1.0-beta.5+ expands and recurses `**` internally, so no shell-side globbing +or explicit per-file listing is needed): ```pwsh dotnet sysml2tools render ` - docs/sysml2/{system-name}.sysml docs/sysml2/ots.sysml docs/sysml2/shared.sysml ` - docs/sysml2/views/design-views.sysml --output docs/design/generated --format svg + --output docs/design/generated --format svg ` + 'docs/sysml2/model/**/*.sysml' ` + 'docs/sysml2/views/design-views.sysml' ``` With multiple views declared and no `--view` flag, `sysml2tools` renders every declared view @@ -127,13 +193,18 @@ subsection, e.g. `![{Name} Structure]({ViewName}.svg)`. ## Build and Lint Integration -- `sysml2tools lint docs/sysml2/*.sysml` belongs in `lint.ps1`'s compliance-tools section, - **not** as a separate step in the CI design-document job — `lint.ps1` gates every later - job (including document generation) transitively, so linting the model there is both - earlier and non-duplicated. +- `sysml2tools lint` belongs in `lint.ps1`'s compliance-tools section, **not** as a separate + step in the CI design-document job — `lint.ps1` gates every later job (including document + generation) transitively, so linting the model there is both earlier and non-duplicated. + Pass a single quoted recursive glob, e.g. `dotnet sysml2tools lint 'docs/sysml2/**/*.sysml'` + — `sysml2tools` (0.1.0-beta.5+) expands and recurses this itself, so no + `Get-ChildItem`/shell-side globbing is needed. - The CI design-document job renders the views (see the render command above) before running Pandoc, so generated SVGs exist before HTML generation. Rename/stable-filename workarounds - are unnecessary since view names are stable by definition. + are unnecessary since view names are stable by definition. Pass the model and views globs as + separate quoted arguments (e.g. `'docs/sysml2/model/**/*.sysml' 'docs/sysml2/views/design-views.sysml'`) + — plain PowerShell (the default shell) is sufficient; no `shell: bash`/`shopt -s globstar` + workaround is needed. - Add `sysml2tools` to `.config/dotnet-tools.json` (`demaconsulting.sysml2tools.tool`) and to `.versionmark.yaml`'s captured tool list. @@ -148,7 +219,12 @@ sync. ## Quality Checks - [ ] Every System/Subsystem/Unit in `docs/design/introduction.md` has a matching `part def` - in `docs/sysml2/{system-name}.sysml` with a purpose `doc` comment + in its own file under `docs/sysml2/model/`, at the same folder depth as its companion + design/reqstream/verification files, with a purpose `doc` comment +- [ ] Every Unit-level `part def` has `sourceRef`/`testRef`/`designRef`/`verificationRef`/ + `reqRef` comments where applicable (see Artifact-Location Comments for documented + exceptions); System/Subsystem `part def`s have `testRef`/`designRef`/`verificationRef`/ + `reqRef` but no `sourceRef` - [ ] `docs/sysml2/views/design-views.sysml` uses `view Name { expose ...; }` usages, not `view def` definitions - [ ] View names follow the `SoftwareStructureView` / `{SystemName}View` / diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b75f335..dca26ba 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -740,13 +740,12 @@ jobs: run: mkdir -p docs/design/generated - name: Render Software Structure diagrams with SysML2Tools - shell: bash - run: > - dotnet sysml2tools render - --output docs/design/generated - --format svg - docs/sysml2/*.sysml - docs/sysml2/views/design-views.sysml + run: | + dotnet sysml2tools render ` + --output docs/design/generated ` + --format svg ` + 'docs/sysml2/model/**/*.sysml' ` + 'docs/sysml2/views/design-views.sysml' - name: Generate Design HTML with Pandoc shell: bash diff --git a/docs/sysml2/dictionary-mark.sysml b/docs/sysml2/dictionary-mark.sysml deleted file mode 100644 index f74d208..0000000 --- a/docs/sysml2/dictionary-mark.sysml +++ /dev/null @@ -1,111 +0,0 @@ -package DictionaryMark { - import OtsDependencies::*; - - doc - /* - * DictionaryMark is a .NET command-line application that reads YAML dictionary - * files and generates formatted Markdown output as bullet lists or tables. - */ - - part def DictionaryMarkSystem { - doc /* The DictionaryMark system as a whole. */ - - part program : Program; - part cli : CliSubsystem; - part dictionary : DictionarySubsystem; - part selfTest : SelfTestSubsystem; - part utilities : UtilitiesSubsystem; - part yamlDotNet : YamlDotNet; - part fileSystemGlobbing : FileSystemGlobbing; - part testResults : TestResults; - } - - part def Program { - doc /* Entry point and execution orchestrator. */ - } - - part def CliSubsystem { - doc /* Command-line interface: argument parsing and I/O ownership. */ - - part context : Context; - } - - part def Context { - doc /* Command-line argument parser and I/O owner. */ - } - - part def DictionarySubsystem { - doc /* Loads, validates, and formats dictionary data. */ - - part dictionaryGenerator : DictionaryGenerator; - part yamlDictionaryLoader : YamlDictionaryLoader; - part conflictDetector : ConflictDetector; - part markdownFormatter : MarkdownFormatter; - part dictionaryEntry : DictionaryEntry; - part markdownOptions : MarkdownOptions; - part outputFormat : OutputFormat; - part sortOrder : SortOrder; - } - - part def DictionaryGenerator { - doc /* Orchestrates dictionary generation. */ - } - - part def YamlDictionaryLoader { - doc /* Loads YAML flat-dictionary files. */ - } - - part def ConflictDetector { - doc /* Detects term conflicts across files. */ - } - - part def MarkdownFormatter { - doc /* Formats entries as Markdown. */ - } - - part def DictionaryEntry { - doc /* Data model: term-definition pair. */ - } - - part def MarkdownOptions { - doc /* Data model: Markdown output options. */ - } - - part def OutputFormat { - doc /* Data model: output format enum. */ - } - - part def SortOrder { - doc /* Data model: sort order enum. */ - } - - part def SelfTestSubsystem { - doc /* Self-validation test runner subsystem. */ - - part validation : Validation; - } - - part def Validation { - doc /* Self-validation test runner. */ - } - - part def UtilitiesSubsystem { - doc /* Shared, cross-cutting helper utilities. */ - - part globMatcher : GlobMatcher; - part pathHelpers : PathHelpers; - part temporaryDirectory : TemporaryDirectory; - } - - part def GlobMatcher { - doc /* File-matching via glob patterns. */ - } - - part def PathHelpers { - doc /* Safe path combination utilities. */ - } - - part def TemporaryDirectory { - doc /* Disposable temporary directory helper. */ - } -} diff --git a/docs/sysml2/model/dictionary-mark.sysml b/docs/sysml2/model/dictionary-mark.sysml new file mode 100644 index 0000000..67d1af7 --- /dev/null +++ b/docs/sysml2/model/dictionary-mark.sysml @@ -0,0 +1,26 @@ +package DictionaryMark { + import OtsDependencies::*; + + doc + /* + * DictionaryMark is a .NET command-line application that reads YAML dictionary + * files and generates formatted Markdown output as bullet lists or tables. + */ + + part def DictionaryMarkSystem { + doc /* The DictionaryMark system as a whole. */ + + comment designRef /* Design: docs/design/dictionary-mark.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark.yaml */ + + part program : Program; + part cli : CliSubsystem; + part dictionary : DictionarySubsystem; + part selfTest : SelfTestSubsystem; + part utilities : UtilitiesSubsystem; + part yamlDotNet : YamlDotNet; + part fileSystemGlobbing : FileSystemGlobbing; + part testResults : TestResults; + } +} diff --git a/docs/sysml2/model/dictionary-mark/cli.sysml b/docs/sysml2/model/dictionary-mark/cli.sysml new file mode 100644 index 0000000..40d18df --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/cli.sysml @@ -0,0 +1,12 @@ +package DictionaryMark { + part def CliSubsystem { + doc /* Command-line interface: argument parsing and I/O ownership. */ + + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Cli/CliSubsystemTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/cli.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/cli.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/cli.yaml */ + + part context : Context; + } +} diff --git a/docs/sysml2/model/dictionary-mark/cli/context.sysml b/docs/sysml2/model/dictionary-mark/cli/context.sysml new file mode 100644 index 0000000..513e20f --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/cli/context.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def Context { + doc /* Command-line argument parser and I/O owner. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Cli/Context.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Cli/ContextTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/cli/context.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/cli/context.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/cli/context.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/dictionary.sysml b/docs/sysml2/model/dictionary-mark/dictionary.sysml new file mode 100644 index 0000000..8e3547d --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/dictionary.sysml @@ -0,0 +1,56 @@ +package DictionaryMark { + part def DictionarySubsystem { + doc /* Loads, validates, and formats dictionary data. */ + + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Dictionary/DictionarySubsystemTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary.yaml */ + + part dictionaryGenerator : DictionaryGenerator; + part yamlDictionaryLoader : YamlDictionaryLoader; + part conflictDetector : ConflictDetector; + part markdownFormatter : MarkdownFormatter; + part dictionaryEntry : DictionaryEntry; + part markdownOptions : MarkdownOptions; + part outputFormat : OutputFormat; + part sortOrder : SortOrder; + } + + part def DictionaryEntry { + doc /* Data model: term-definition pair. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/DictionaryEntry.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Dictionary/DictionaryEntryTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary.md (documented as a supporting value type) */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary.yaml */ + } + + part def MarkdownOptions { + doc /* Data model: Markdown output options. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/MarkdownOptions.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary.md (documented as a supporting value type) */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary.yaml */ + } + + part def OutputFormat { + doc /* Data model: output format enum. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/OutputFormat.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary.md (documented as a supporting value type) */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary.yaml */ + } + + part def SortOrder { + doc /* Data model: sort order enum. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/SortOrder.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary.md (documented as a supporting value type) */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/dictionary/conflict-detector.sysml b/docs/sysml2/model/dictionary-mark/dictionary/conflict-detector.sysml new file mode 100644 index 0000000..b5da978 --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/dictionary/conflict-detector.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def ConflictDetector { + doc /* Detects term conflicts across files. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/ConflictDetector.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Dictionary/ConflictDetectorTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary/conflict-detector.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary/conflict-detector.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary/conflict-detector.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/dictionary/dictionary-generator.sysml b/docs/sysml2/model/dictionary-mark/dictionary/dictionary-generator.sysml new file mode 100644 index 0000000..71d7ee3 --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/dictionary/dictionary-generator.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def DictionaryGenerator { + doc /* Orchestrates dictionary generation. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/DictionaryGenerator.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Dictionary/DictionaryGeneratorTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary/dictionary-generator.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary/dictionary-generator.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary/dictionary-generator.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/dictionary/markdown-formatter.sysml b/docs/sysml2/model/dictionary-mark/dictionary/markdown-formatter.sysml new file mode 100644 index 0000000..57cdd1f --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/dictionary/markdown-formatter.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def MarkdownFormatter { + doc /* Formats entries as Markdown. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/MarkdownFormatter.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Dictionary/MarkdownFormatterTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary/markdown-formatter.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary/markdown-formatter.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary/markdown-formatter.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/dictionary/yaml-loader.sysml b/docs/sysml2/model/dictionary-mark/dictionary/yaml-loader.sysml new file mode 100644 index 0000000..30d0be3 --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/dictionary/yaml-loader.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def YamlDictionaryLoader { + doc /* Loads YAML flat-dictionary files. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Dictionary/YamlDictionaryLoader.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Dictionary/YamlDictionaryLoaderTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/dictionary/yaml-loader.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/dictionary/yaml-loader.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/dictionary/yaml-loader.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/program.sysml b/docs/sysml2/model/dictionary-mark/program.sysml new file mode 100644 index 0000000..e8f83c3 --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/program.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def Program { + doc /* Entry point and execution orchestrator. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Program.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/ProgramTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/program.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/program.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/program.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/self-test.sysml b/docs/sysml2/model/dictionary-mark/self-test.sysml new file mode 100644 index 0000000..f523830 --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/self-test.sysml @@ -0,0 +1,12 @@ +package DictionaryMark { + part def SelfTestSubsystem { + doc /* Self-validation test runner subsystem. */ + + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/SelfTest/SelfTestSubsystemTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/self-test.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/self-test.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/self-test.yaml */ + + part validation : Validation; + } +} diff --git a/docs/sysml2/model/dictionary-mark/self-test/validation.sysml b/docs/sysml2/model/dictionary-mark/self-test/validation.sysml new file mode 100644 index 0000000..21a152d --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/self-test/validation.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def Validation { + doc /* Self-validation test runner. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/SelfTest/Validation.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/SelfTest/ValidationTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/self-test/validation.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/self-test/validation.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/self-test/validation.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/utilities.sysml b/docs/sysml2/model/dictionary-mark/utilities.sysml new file mode 100644 index 0000000..13b7261 --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/utilities.sysml @@ -0,0 +1,14 @@ +package DictionaryMark { + part def UtilitiesSubsystem { + doc /* Shared, cross-cutting helper utilities. */ + + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Utilities/UtilitiesSubsystemTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/utilities.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/utilities.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/utilities.yaml */ + + part globMatcher : GlobMatcher; + part pathHelpers : PathHelpers; + part temporaryDirectory : TemporaryDirectory; + } +} diff --git a/docs/sysml2/model/dictionary-mark/utilities/glob-matcher.sysml b/docs/sysml2/model/dictionary-mark/utilities/glob-matcher.sysml new file mode 100644 index 0000000..588d3ff --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/utilities/glob-matcher.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def GlobMatcher { + doc /* File-matching via glob patterns. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Utilities/GlobMatcher.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Utilities/GlobMatcherTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/utilities/glob-matcher.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/utilities/glob-matcher.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/utilities/glob-matcher.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/utilities/path-helpers.sysml b/docs/sysml2/model/dictionary-mark/utilities/path-helpers.sysml new file mode 100644 index 0000000..1ec36ac --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/utilities/path-helpers.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def PathHelpers { + doc /* Safe path combination utilities. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Utilities/PathHelpers.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Utilities/PathHelpersTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/utilities/path-helpers.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/utilities/path-helpers.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/utilities/path-helpers.yaml */ + } +} diff --git a/docs/sysml2/model/dictionary-mark/utilities/temporary-directory.sysml b/docs/sysml2/model/dictionary-mark/utilities/temporary-directory.sysml new file mode 100644 index 0000000..04cf41e --- /dev/null +++ b/docs/sysml2/model/dictionary-mark/utilities/temporary-directory.sysml @@ -0,0 +1,11 @@ +package DictionaryMark { + part def TemporaryDirectory { + doc /* Disposable temporary directory helper. */ + + comment sourceRef /* Source: src/DemaConsulting.DictionaryMark/Utilities/TemporaryDirectory.cs */ + comment testRef /* Test: test/DemaConsulting.DictionaryMark.Tests/Utilities/TemporaryDirectoryTests.cs */ + comment designRef /* Design: docs/design/dictionary-mark/utilities/temporary-directory.md */ + comment verificationRef /* Verification: docs/verification/dictionary-mark/utilities/temporary-directory.md */ + comment reqRef /* Requirements: docs/reqstream/dictionary-mark/utilities/temporary-directory.yaml */ + } +} diff --git a/docs/sysml2/model/ots.sysml b/docs/sysml2/model/ots.sysml new file mode 100644 index 0000000..b0f19b1 --- /dev/null +++ b/docs/sysml2/model/ots.sysml @@ -0,0 +1,27 @@ +package OtsDependencies { + doc /* Off-the-shelf (OTS) dependencies used by DictionaryMark. */ + + part def YamlDotNet { + doc /* OTS: YAML parsing library used to load dictionary files. */ + + comment designRef /* Design: docs/design/ots/yaml-dot-net.md */ + comment verificationRef /* Verification: docs/verification/ots/yaml-dot-net.md */ + comment reqRef /* Requirements: docs/reqstream/ots/yaml-dot-net.yaml */ + } + + part def FileSystemGlobbing { + doc /* OTS: Microsoft.Extensions.FileSystemGlobbing, used for glob-based file matching. */ + + comment designRef /* Design: docs/design/ots/file-system-globbing.md */ + comment verificationRef /* Verification: docs/verification/ots/file-system-globbing.md */ + comment reqRef /* Requirements: docs/reqstream/ots/file-system-globbing.yaml */ + } + + part def TestResults { + doc /* OTS: DemaConsulting.TestResults, used for self-test result reporting. */ + + comment designRef /* Design: docs/design/ots/test-results.md */ + comment verificationRef /* Verification: docs/verification/ots/test-results.md */ + comment reqRef /* Requirements: docs/reqstream/ots/test-results.yaml */ + } +} diff --git a/docs/sysml2/ots.sysml b/docs/sysml2/ots.sysml deleted file mode 100644 index 45748f2..0000000 --- a/docs/sysml2/ots.sysml +++ /dev/null @@ -1,15 +0,0 @@ -package OtsDependencies { - doc /* Off-the-shelf (OTS) dependencies used by DictionaryMark. */ - - part def YamlDotNet { - doc /* OTS: YAML parsing library used to load dictionary files. */ - } - - part def FileSystemGlobbing { - doc /* OTS: Microsoft.Extensions.FileSystemGlobbing, used for glob-based file matching. */ - } - - part def TestResults { - doc /* OTS: DemaConsulting.TestResults, used for self-test result reporting. */ - } -} diff --git a/lint.ps1 b/lint.ps1 index 469010f..58a6fae 100644 --- a/lint.ps1 +++ b/lint.ps1 @@ -115,13 +115,8 @@ if (-not $skipDotnetTools) { dotnet reviewmark --lint if ($LASTEXITCODE -ne 0) { $lintError = $true } - # Files still containing the TEMPLATE-DIRECTIVE marker are un-customized scaffold and - # are skipped so file adds/renames need no manual list maintenance here. - $sysmlFiles = Get-ChildItem -Path docs/sysml2 -Recurse -Filter *.sysml -ErrorAction SilentlyContinue | - Where-Object { (Get-Content $_.FullName -Raw) -notmatch 'TEMPLATE-DIRECTIVE' } | - ForEach-Object { $_.FullName } - if ($sysmlFiles) { - dotnet sysml2tools lint @sysmlFiles + if (Test-Path docs/sysml2) { + dotnet sysml2tools lint 'docs/sysml2/**/*.sysml' if ($LASTEXITCODE -ne 0) { $lintError = $true } } } From 00fb5fa4b0603931bbfe88236bcab83354a27948 Mon Sep 17 00:00:00 2001 From: Malcolm Nixon Date: Tue, 7 Jul 2026 20:46:08 -0400 Subject: [PATCH 2/2] Use folded (>) YAML scalar for sysml2tools render step, drop backtick continuations The render invocation is a single logical command, so PowerShell's backtick line-continuation was unnecessary and fragile (it silently depends on the run step defaulting to pwsh on windows-latest, with no shell: declared). Switched to shell: pwsh (explicit, matching every other step's explicit shell: bash in this job) and the > folded block scalar, which joins the multi-line YAML into one space-separated command with no continuation characters needed at all. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/build.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index dca26ba..f5a5fc8 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -740,12 +740,13 @@ jobs: run: mkdir -p docs/design/generated - name: Render Software Structure diagrams with SysML2Tools - run: | - dotnet sysml2tools render ` - --output docs/design/generated ` - --format svg ` - 'docs/sysml2/model/**/*.sysml' ` - 'docs/sysml2/views/design-views.sysml' + shell: pwsh + run: > + dotnet sysml2tools render + --output docs/design/generated + --format svg + 'docs/sysml2/model/**/*.sysml' + 'docs/sysml2/views/design-views.sysml' - name: Generate Design HTML with Pandoc shell: bash