sysml2kit 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/CHANGELOG.md +27 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/PKG-INFO +37 -12
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/README.md +34 -11
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/SPEC.md +27 -0
- sysml2kit-0.3.0/docker/compose.yaml +35 -0
- sysml2kit-0.3.0/docs/api-client.md +49 -0
- sysml2kit-0.3.0/docs/verification.md +87 -0
- sysml2kit-0.3.0/docs/views.md +24 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/mkdocs.yml +2 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/pyproject.toml +5 -1
- sysml2kit-0.3.0/scripts/wait_for_api.sh +17 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/_version.py +2 -2
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/api/client.py +42 -1
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/cli.py +170 -1
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/interchange/reader.py +30 -2
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/mcp/server.py +1 -1
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/mcp/tools_requirements.py +57 -0
- sysml2kit-0.3.0/src/sysml2kit/verify/__init__.py +33 -0
- sysml2kit-0.3.0/src/sysml2kit/verify/binding.py +120 -0
- sysml2kit-0.3.0/src/sysml2kit/verify/engines.py +81 -0
- sysml2kit-0.3.0/src/sysml2kit/verify/runner.py +251 -0
- sysml2kit-0.3.0/tests/test_api_live.py +123 -0
- sysml2kit-0.3.0/tests/test_cli_api.py +70 -0
- sysml2kit-0.3.0/tests/test_cli_verify.py +120 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_mcp.py +24 -0
- sysml2kit-0.3.0/tests/test_verify.py +216 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/uv.lock +24 -1
- sysml2kit-0.2.0/docs/api-client.md +0 -28
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/.gitignore +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/.pre-commit-config.yaml +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/.python-version +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/CITATION.cff +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/CLAUDE.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/CONTRIBUTING.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/LICENSE +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/NOTICE +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/SECURITY.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/backends.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/cli.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/concepts.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/index.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/interchange.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/mcp.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/quickstart.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/reference.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/rf-library.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/docs/traceability.md +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/scripts/slopcheck.sh +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/api/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/api/errors.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/api/models.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/backends/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/backends/protocol.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/backends/sysmlpy.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/diff.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/graph.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/interchange/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/interchange/typemap.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/interchange/writer.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/interop/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/interop/requirements.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/mcp/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/mcp/_common.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/mcp/tools_model.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/analysis.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/base.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/builder.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/container.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/metadata.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/relations.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/requirements.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/structure.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/model/values.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/py.typed +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/query.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/text/__init__.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/text/keywords.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/text/writer.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/units.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/validation.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/views.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/src/sysml2kit/workspace.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/conftest.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/fixtures/RFParts.sysml +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/fixtures/RFRequirements.sysml +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/fixtures/SatcomTerminal28GHz.sysml +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/fixtures/vehicle.sysml +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_api_client.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_backend_fidelity.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_backend_sysmlpy.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_cli.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_cli_fmt.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_diff.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_interchange.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_interop.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_model.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_package.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_query.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_roundtrip_json.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_roundtrip_text.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_text_writer/test_vehicle_golden.sysml +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_text_writer.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_validation.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_values_units.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_views/test_trace_contains_all_edge_kinds.trace.mmd +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_views/test_tree_contains_hierarchy.tree.mmd +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_views.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tests/test_workspace.py +0 -0
- {sysml2kit-0.2.0 → sysml2kit-0.3.0}/tools/conformance/run_oracle.py +0 -0
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-08-21
|
|
4
|
+
|
|
5
|
+
- **Verification execution** (`sysml2kit.verify`): `verificationBinding`
|
|
6
|
+
metadata binds an analysis case to an engine resolved by name from the
|
|
7
|
+
`sysml2kit.engines` entry-point group (model text never names code paths).
|
|
8
|
+
`run_verification` executes bound analyses and checks each metricKey
|
|
9
|
+
requirement with margins; `apply_results` writes metrics and verdicts back
|
|
10
|
+
into the model with provenance, idempotently. CLI `sysml2kit verify`, MCP
|
|
11
|
+
tool `requirements_verify` (nine tools now), `verify` extra for YAML
|
|
12
|
+
configs, and a `docs/verification.md` flagship page. First engine:
|
|
13
|
+
phased-array-systems (PR #2 there).
|
|
14
|
+
- **Live-server harness**: `docker/compose.yaml` runs the pilot
|
|
15
|
+
implementation (digest-pinned) + postgres; `api`-marked round-trip tests
|
|
16
|
+
pass against the real server; weekly advisory `live-api` workflow. Live
|
|
17
|
+
testing hardened the client and reader for the pilot dialect: list-typed
|
|
18
|
+
endpoints/typing/text adapted on push and tolerated on read, verify/derive
|
|
19
|
+
pushed as Dependency, multiplicity/doc dropped by the server, server-minted
|
|
20
|
+
element ids; known-@type records that do not fit the profile now degrade to
|
|
21
|
+
OpaqueElement instead of failing the read.
|
|
22
|
+
- **`api` CLI group**: `projects`, `pull` (newest commit by default),
|
|
23
|
+
`push --create`; `SYSML2KIT_API_URL`/`SYSML2KIT_API_TOKEN` env vars;
|
|
24
|
+
`SysMLApiClient.head_commit`.
|
|
25
|
+
- **Diagrams docs page** and a README refresh for the 0.3 surface.
|
|
26
|
+
- Upstream sysmlpy fixes submitted for the two pinned parse losses:
|
|
27
|
+
dependency statements (mycr0ft/sysmlpy#7) and allocate endpoints
|
|
28
|
+
(mycr0ft/sysmlpy#6).
|
|
29
|
+
|
|
3
30
|
## 0.2.0 — 2026-08-21
|
|
4
31
|
|
|
5
32
|
- **Parse fidelity**: the sysmlpy backend now walks the raw ANTLR dict
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sysml2kit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: API-first Python tooling for building, querying, validating, and automating SysML v2 models
|
|
5
5
|
Project-URL: Homepage, https://github.com/jman4162/sysml2kit
|
|
6
6
|
Project-URL: Source, https://github.com/jman4162/sysml2kit
|
|
@@ -34,6 +34,8 @@ Provides-Extra: mcp
|
|
|
34
34
|
Requires-Dist: mcp<2,>=1.26; extra == 'mcp'
|
|
35
35
|
Provides-Extra: parse
|
|
36
36
|
Requires-Dist: sysmlpy<0.37,>=0.36.2; extra == 'parse'
|
|
37
|
+
Provides-Extra: verify
|
|
38
|
+
Requires-Dist: pyyaml>=6.0; extra == 'verify'
|
|
37
39
|
Description-Content-Type: text/markdown
|
|
38
40
|
|
|
39
41
|
# sysml2kit
|
|
@@ -42,20 +44,25 @@ Description-Content-Type: text/markdown
|
|
|
42
44
|
[](https://pypi.org/project/sysml2kit/)
|
|
43
45
|
[](https://pypi.org/project/sysml2kit/)
|
|
44
46
|
[](LICENSE)
|
|
47
|
+
[](https://jman4162.github.io/sysml2kit/)
|
|
45
48
|
|
|
46
49
|
API-first Python tooling for building, querying, validating, and automating
|
|
47
50
|
SysML v2 models.
|
|
48
51
|
|
|
49
|
-
> **Status: pre-alpha.** The 0.
|
|
50
|
-
> interchange, queries, validation, diff,
|
|
51
|
-
>
|
|
52
|
-
>
|
|
52
|
+
> **Status: pre-alpha.** The 0.3.x line covers the full loop: model, writer,
|
|
53
|
+
> interchange, queries, validation, diff, mermaid views, parse backend, MCP
|
|
54
|
+
> server, API client with a live-server harness, and verification execution.
|
|
55
|
+
> The API may still move between minor versions; pin an exact version if you
|
|
56
|
+
> depend on it. Changes: [CHANGELOG.md](CHANGELOG.md).
|
|
53
57
|
|
|
54
58
|
`sysml2kit` is the requirements/architecture/traceability layer for
|
|
55
59
|
engineering automation stacks: build a system model in Python, emit standard
|
|
56
60
|
SysML v2 textual notation and Systems Modeling API JSON, run traceability
|
|
57
61
|
queries (which requirements are unsatisfied? unverified? allocated where?),
|
|
58
|
-
validate,
|
|
62
|
+
validate, diff, and **execute verification**: analyses bound to registered
|
|
63
|
+
engines run for real, and their metrics check the model's requirements. It
|
|
64
|
+
targets the OMG SysML v2 standard, not any vendor tool. Docs:
|
|
65
|
+
https://jman4162.github.io/sysml2kit/
|
|
59
66
|
|
|
60
67
|
## What it does
|
|
61
68
|
|
|
@@ -72,8 +79,15 @@ validate, and diff. It targets the OMG SysML v2 standard, not any vendor tool.
|
|
|
72
79
|
- **Traceability queries**: unsatisfied/unverified requirements, allocation
|
|
73
80
|
tables, requirement-to-part trace matrices.
|
|
74
81
|
- **Validation and diff**: rule-based model checks and element-level diffs.
|
|
82
|
+
- **Verification execution**: `verificationBinding` metadata binds an
|
|
83
|
+
analysis case to an engine from the `sysml2kit.engines` entry-point group;
|
|
84
|
+
`sysml2kit verify` runs it and checks each requirement with margins, and
|
|
85
|
+
can write results back into the model with provenance.
|
|
86
|
+
- **Mermaid views**: ownership-tree and requirement-trace diagrams.
|
|
87
|
+
- **MCP server**: nine tools for agents (`sysml2kit mcp serve`).
|
|
75
88
|
- **API client**: a thin HTTP client for the OMG Systems Modeling API and
|
|
76
|
-
Services endpoints
|
|
89
|
+
Services endpoints, plus a docker compose harness running the pilot
|
|
90
|
+
implementation for live round-trip testing.
|
|
77
91
|
|
|
78
92
|
## Install
|
|
79
93
|
|
|
@@ -81,6 +95,8 @@ validate, and diff. It targets the OMG SysML v2 standard, not any vendor tool.
|
|
|
81
95
|
pip install sysml2kit # core: build, write, query, validate, diff
|
|
82
96
|
pip install "sysml2kit[parse]" # + read .sysml files (sysmlpy backend)
|
|
83
97
|
pip install "sysml2kit[graph]" # + NetworkX export
|
|
98
|
+
pip install "sysml2kit[mcp]" # + MCP server for agents
|
|
99
|
+
pip install "sysml2kit[verify]" # + YAML verification-binding configs
|
|
84
100
|
```
|
|
85
101
|
|
|
86
102
|
## Quick start
|
|
@@ -119,9 +135,13 @@ sysml2kit
|
|
|
119
135
|
├── query # traceability queries
|
|
120
136
|
├── validation # rule-based checks (S2K001...)
|
|
121
137
|
├── diff # element-level model diff
|
|
138
|
+
├── views # mermaid diagrams (trace, tree)
|
|
139
|
+
├── verify # verification bindings, engine registry, runner
|
|
122
140
|
├── api # Systems Modeling API HTTP client
|
|
123
141
|
├── backends # parser backends (sysmlpy behind the [parse] extra)
|
|
124
142
|
├── interop # tool-agnostic requirement extraction
|
|
143
|
+
├── mcp # MCP server (behind the [mcp] extra)
|
|
144
|
+
├── graph, units, workspace # NetworkX export, pint helpers, path safety
|
|
125
145
|
└── cli # `sysml2kit` command line
|
|
126
146
|
```
|
|
127
147
|
|
|
@@ -131,13 +151,17 @@ The spec pin, element subset, and known deviations are documented in
|
|
|
131
151
|
|
|
132
152
|
Domain content lives outside the kit. For antenna/RF systems engineering, see
|
|
133
153
|
[sysml2kit-rf-library](https://github.com/jman4162/sysml2kit-rf-library), a
|
|
134
|
-
SysML v2 model library consumed through this package.
|
|
154
|
+
SysML v2 model library consumed through this package. Downstream bridges are
|
|
155
|
+
merged in [phased-array-systems](https://github.com/jman4162/phased-array-systems)
|
|
156
|
+
(`interop.sysml`: requirement sets and the `phased-array-systems` verification
|
|
157
|
+
engine) and [aedl](https://github.com/jman4162/aedl-electromagnetic-design-agent)
|
|
158
|
+
(`aedl.interop`: bound-form requirements).
|
|
135
159
|
|
|
136
160
|
## For agents
|
|
137
161
|
|
|
138
|
-
An MCP server ships behind the `mcp` extra with
|
|
162
|
+
An MCP server ships behind the `mcp` extra with nine tools: `model_show`,
|
|
139
163
|
`model_validate`, `model_diff`, `model_export`, `model_diagram`,
|
|
140
|
-
`requirements_trace`, `requirements_extract`, `library_load`. Artifacts are
|
|
164
|
+
`requirements_trace`, `requirements_extract`, `requirements_verify`, `library_load`. Artifacts are
|
|
141
165
|
returned as file paths, not payloads.
|
|
142
166
|
|
|
143
167
|
```bash
|
|
@@ -149,8 +173,9 @@ sysml2kit mcp serve # stdio; --transport http also supported
|
|
|
149
173
|
{"mcpServers": {"sysml2kit": {"command": "sysml2kit", "args": ["mcp", "serve"]}}}
|
|
150
174
|
```
|
|
151
175
|
|
|
152
|
-
The CLI
|
|
153
|
-
|
|
176
|
+
The CLI covers the same operations for shell use:
|
|
177
|
+
`sysml2kit show | validate | diff | export | fmt | verify | api | mcp serve`
|
|
178
|
+
(`export --to mermaid` renders diagrams).
|
|
154
179
|
|
|
155
180
|
## Development
|
|
156
181
|
|
|
@@ -4,20 +4,25 @@
|
|
|
4
4
|
[](https://pypi.org/project/sysml2kit/)
|
|
5
5
|
[](https://pypi.org/project/sysml2kit/)
|
|
6
6
|
[](LICENSE)
|
|
7
|
+
[](https://jman4162.github.io/sysml2kit/)
|
|
7
8
|
|
|
8
9
|
API-first Python tooling for building, querying, validating, and automating
|
|
9
10
|
SysML v2 models.
|
|
10
11
|
|
|
11
|
-
> **Status: pre-alpha.** The 0.
|
|
12
|
-
> interchange, queries, validation, diff,
|
|
13
|
-
>
|
|
14
|
-
>
|
|
12
|
+
> **Status: pre-alpha.** The 0.3.x line covers the full loop: model, writer,
|
|
13
|
+
> interchange, queries, validation, diff, mermaid views, parse backend, MCP
|
|
14
|
+
> server, API client with a live-server harness, and verification execution.
|
|
15
|
+
> The API may still move between minor versions; pin an exact version if you
|
|
16
|
+
> depend on it. Changes: [CHANGELOG.md](CHANGELOG.md).
|
|
15
17
|
|
|
16
18
|
`sysml2kit` is the requirements/architecture/traceability layer for
|
|
17
19
|
engineering automation stacks: build a system model in Python, emit standard
|
|
18
20
|
SysML v2 textual notation and Systems Modeling API JSON, run traceability
|
|
19
21
|
queries (which requirements are unsatisfied? unverified? allocated where?),
|
|
20
|
-
validate,
|
|
22
|
+
validate, diff, and **execute verification**: analyses bound to registered
|
|
23
|
+
engines run for real, and their metrics check the model's requirements. It
|
|
24
|
+
targets the OMG SysML v2 standard, not any vendor tool. Docs:
|
|
25
|
+
https://jman4162.github.io/sysml2kit/
|
|
21
26
|
|
|
22
27
|
## What it does
|
|
23
28
|
|
|
@@ -34,8 +39,15 @@ validate, and diff. It targets the OMG SysML v2 standard, not any vendor tool.
|
|
|
34
39
|
- **Traceability queries**: unsatisfied/unverified requirements, allocation
|
|
35
40
|
tables, requirement-to-part trace matrices.
|
|
36
41
|
- **Validation and diff**: rule-based model checks and element-level diffs.
|
|
42
|
+
- **Verification execution**: `verificationBinding` metadata binds an
|
|
43
|
+
analysis case to an engine from the `sysml2kit.engines` entry-point group;
|
|
44
|
+
`sysml2kit verify` runs it and checks each requirement with margins, and
|
|
45
|
+
can write results back into the model with provenance.
|
|
46
|
+
- **Mermaid views**: ownership-tree and requirement-trace diagrams.
|
|
47
|
+
- **MCP server**: nine tools for agents (`sysml2kit mcp serve`).
|
|
37
48
|
- **API client**: a thin HTTP client for the OMG Systems Modeling API and
|
|
38
|
-
Services endpoints
|
|
49
|
+
Services endpoints, plus a docker compose harness running the pilot
|
|
50
|
+
implementation for live round-trip testing.
|
|
39
51
|
|
|
40
52
|
## Install
|
|
41
53
|
|
|
@@ -43,6 +55,8 @@ validate, and diff. It targets the OMG SysML v2 standard, not any vendor tool.
|
|
|
43
55
|
pip install sysml2kit # core: build, write, query, validate, diff
|
|
44
56
|
pip install "sysml2kit[parse]" # + read .sysml files (sysmlpy backend)
|
|
45
57
|
pip install "sysml2kit[graph]" # + NetworkX export
|
|
58
|
+
pip install "sysml2kit[mcp]" # + MCP server for agents
|
|
59
|
+
pip install "sysml2kit[verify]" # + YAML verification-binding configs
|
|
46
60
|
```
|
|
47
61
|
|
|
48
62
|
## Quick start
|
|
@@ -81,9 +95,13 @@ sysml2kit
|
|
|
81
95
|
├── query # traceability queries
|
|
82
96
|
├── validation # rule-based checks (S2K001...)
|
|
83
97
|
├── diff # element-level model diff
|
|
98
|
+
├── views # mermaid diagrams (trace, tree)
|
|
99
|
+
├── verify # verification bindings, engine registry, runner
|
|
84
100
|
├── api # Systems Modeling API HTTP client
|
|
85
101
|
├── backends # parser backends (sysmlpy behind the [parse] extra)
|
|
86
102
|
├── interop # tool-agnostic requirement extraction
|
|
103
|
+
├── mcp # MCP server (behind the [mcp] extra)
|
|
104
|
+
├── graph, units, workspace # NetworkX export, pint helpers, path safety
|
|
87
105
|
└── cli # `sysml2kit` command line
|
|
88
106
|
```
|
|
89
107
|
|
|
@@ -93,13 +111,17 @@ The spec pin, element subset, and known deviations are documented in
|
|
|
93
111
|
|
|
94
112
|
Domain content lives outside the kit. For antenna/RF systems engineering, see
|
|
95
113
|
[sysml2kit-rf-library](https://github.com/jman4162/sysml2kit-rf-library), a
|
|
96
|
-
SysML v2 model library consumed through this package.
|
|
114
|
+
SysML v2 model library consumed through this package. Downstream bridges are
|
|
115
|
+
merged in [phased-array-systems](https://github.com/jman4162/phased-array-systems)
|
|
116
|
+
(`interop.sysml`: requirement sets and the `phased-array-systems` verification
|
|
117
|
+
engine) and [aedl](https://github.com/jman4162/aedl-electromagnetic-design-agent)
|
|
118
|
+
(`aedl.interop`: bound-form requirements).
|
|
97
119
|
|
|
98
120
|
## For agents
|
|
99
121
|
|
|
100
|
-
An MCP server ships behind the `mcp` extra with
|
|
122
|
+
An MCP server ships behind the `mcp` extra with nine tools: `model_show`,
|
|
101
123
|
`model_validate`, `model_diff`, `model_export`, `model_diagram`,
|
|
102
|
-
`requirements_trace`, `requirements_extract`, `library_load`. Artifacts are
|
|
124
|
+
`requirements_trace`, `requirements_extract`, `requirements_verify`, `library_load`. Artifacts are
|
|
103
125
|
returned as file paths, not payloads.
|
|
104
126
|
|
|
105
127
|
```bash
|
|
@@ -111,8 +133,9 @@ sysml2kit mcp serve # stdio; --transport http also supported
|
|
|
111
133
|
{"mcpServers": {"sysml2kit": {"command": "sysml2kit", "args": ["mcp", "serve"]}}}
|
|
112
134
|
```
|
|
113
135
|
|
|
114
|
-
The CLI
|
|
115
|
-
|
|
136
|
+
The CLI covers the same operations for shell use:
|
|
137
|
+
`sysml2kit show | validate | diff | export | fmt | verify | api | mcp serve`
|
|
138
|
+
(`export --to mermaid` renders diagrams).
|
|
116
139
|
|
|
117
140
|
## Development
|
|
118
141
|
|
|
@@ -77,6 +77,33 @@ test failure.
|
|
|
77
77
|
- `Model.assign_stable_ids()` rewrites ids as UUIDv5 hashes of qualified
|
|
78
78
|
names so generated interchange files diff cleanly under version control.
|
|
79
79
|
|
|
80
|
+
## Verification binding convention
|
|
81
|
+
|
|
82
|
+
A ``MetadataUsage`` named ``verificationBinding`` annotating an
|
|
83
|
+
``AnalysisCaseUsage`` binds that analysis to an executable engine. Values
|
|
84
|
+
(flat scalars, per the metadata model):
|
|
85
|
+
|
|
86
|
+
| key | type | meaning |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| ``engine`` | str, required | registry name, e.g. ``"phased-array-systems"`` |
|
|
89
|
+
| ``configRef`` | str, optional | ``.yaml``/``.yml``/``.json`` payload file next to the model file (resolved relative to its directory, containment-checked; no ``..``) |
|
|
90
|
+
| ``payload.<dotted>`` | scalar, optional | override deep-merged over the loaded config; dotted keys expand to nested dicts |
|
|
91
|
+
|
|
92
|
+
Engines resolve **by name** against a registry populated from the
|
|
93
|
+
``sysml2kit.engines`` entry-point group and explicit caller registration.
|
|
94
|
+
Model text never names importable code paths — models are data. The runner
|
|
95
|
+
does not interpret payload contents; each engine owns its payload schema
|
|
96
|
+
(engines needing a config plus scalar arguments define reserved top-level
|
|
97
|
+
keys such as ``config``/``args``).
|
|
98
|
+
|
|
99
|
+
Results written back by ``sysml2kit.verify.apply_results`` are attributes on
|
|
100
|
+
the analysis (``source`` starts with ``sysml2kit.verify``) and a
|
|
101
|
+
``verificationVerdict`` metadata on each requirement; both replace prior
|
|
102
|
+
same-named results, so reruns do not accumulate.
|
|
103
|
+
|
|
104
|
+
Bindings are an interchange-JSON feature: metadata values round-trip through
|
|
105
|
+
JSON, while textual-notation fidelity for metadata is not yet pinned.
|
|
106
|
+
|
|
80
107
|
## Provenance on values
|
|
81
108
|
|
|
82
109
|
`AttributeValue` carries optional `source` and `confidence` fields, following
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Local Systems Modeling API server (the OMG pilot implementation) for
|
|
2
|
+
# live-client testing: docker compose -f docker/compose.yaml up -d
|
|
3
|
+
# then scripts/wait_for_api.sh and pytest -m api with
|
|
4
|
+
# SYSML2KIT_API_URL=http://localhost:9000.
|
|
5
|
+
#
|
|
6
|
+
# The app image is the MBSE-mashup containerization of the pilot, pinned by
|
|
7
|
+
# digest (tag 244c221a..., pushed 2025-12-12). Its entrypoint rewrites
|
|
8
|
+
# persistence.xml from the JDBC_*/HIBERNATE_* env vars; hbm2ddl=update
|
|
9
|
+
# creates the schema on first boot. amd64-only: Apple-silicon hosts run it
|
|
10
|
+
# under emulation (the platform key below).
|
|
11
|
+
services:
|
|
12
|
+
db:
|
|
13
|
+
image: postgres:16
|
|
14
|
+
environment:
|
|
15
|
+
POSTGRES_PASSWORD: mysecretpassword
|
|
16
|
+
POSTGRES_DB: sysml2
|
|
17
|
+
healthcheck:
|
|
18
|
+
test: ["CMD-SHELL", "pg_isready -U postgres -d sysml2"]
|
|
19
|
+
interval: 5s
|
|
20
|
+
timeout: 3s
|
|
21
|
+
retries: 24
|
|
22
|
+
|
|
23
|
+
api:
|
|
24
|
+
image: mbsemashup/sysmlv2-api.pilotimpl@sha256:ac5607986dd529fc98a55aa391ac9f51b275c36f74f946285121c896f7e914c6
|
|
25
|
+
platform: linux/amd64
|
|
26
|
+
depends_on:
|
|
27
|
+
db:
|
|
28
|
+
condition: service_healthy
|
|
29
|
+
ports:
|
|
30
|
+
- "9000:9000"
|
|
31
|
+
environment:
|
|
32
|
+
JDBC_URL: jdbc:postgresql://db:5432/sysml2
|
|
33
|
+
JDBC_USER: postgres
|
|
34
|
+
JDBC_PASSWORD: mysecretpassword
|
|
35
|
+
HIBERNATE_HBM2DDL: update
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# API client
|
|
2
|
+
|
|
3
|
+
`sysml2kit.api.SysMLApiClient` is a hand-written httpx client for the OMG
|
|
4
|
+
Systems Modeling API and Services endpoints (the REST binding any conformant
|
|
5
|
+
model server exposes).
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from sysml2kit.api import SysMLApiClient
|
|
9
|
+
|
|
10
|
+
with SysMLApiClient("https://models.example.com", token="…") as client:
|
|
11
|
+
for project in client.list_projects():
|
|
12
|
+
print(project.id, project.name)
|
|
13
|
+
model = client.list_elements(project_id, commit_id) # -> sysml2kit Model
|
|
14
|
+
client.push_model(project_id, model, message="update")
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Covered in v0.1: `list_projects`, `get_project`, `list_branches`,
|
|
18
|
+
`list_commits`, `get_commit`, `get_element`, `list_elements` (returns a
|
|
19
|
+
`Model` via the interchange reader), `create_project`, and `push_model`
|
|
20
|
+
(POSTs a commit whose change set inserts the model's records). Branch
|
|
21
|
+
management and merges are not covered yet.
|
|
22
|
+
|
|
23
|
+
Failures raise `ApiError(status, detail)`. The client sends the bearer token
|
|
24
|
+
to whatever base URL you configure; use HTTPS.
|
|
25
|
+
|
|
26
|
+
## Local live server and the pilot dialect
|
|
27
|
+
|
|
28
|
+
`docker compose -f docker/compose.yaml up -d` starts the pilot
|
|
29
|
+
implementation (sha-pinned image + postgres); `scripts/wait_for_api.sh`
|
|
30
|
+
polls until it answers, and `SYSML2KIT_API_URL=http://localhost:9000
|
|
31
|
+
pytest -m api` runs the live round-trip suite (a weekly advisory workflow
|
|
32
|
+
does the same in CI). The CLI mirrors the client:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
export SYSML2KIT_API_URL=http://localhost:9000
|
|
36
|
+
sysml2kit api projects
|
|
37
|
+
sysml2kit api push model.json --project demo --create
|
|
38
|
+
sysml2kit api pull demo -o pulled.json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The pilot speaks the full abstract syntax, so `push_model` adapts records on
|
|
42
|
+
the way out and the interchange reader tolerates the differences on the way
|
|
43
|
+
back. What survives a server round trip: element kinds, names, short names,
|
|
44
|
+
requirement text. What does not (documented degradations — full fidelity
|
|
45
|
+
lives in interchange JSON files): ownership (the pilot models it as
|
|
46
|
+
OwningMembership elements and ignores our owner key), verify/derive kinds
|
|
47
|
+
(pushed as `Dependency`), multiplicity and doc strings (dropped), and
|
|
48
|
+
element ids (the server mints its own, so stable-id workflows are
|
|
49
|
+
local-file-only).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Verification execution
|
|
2
|
+
|
|
3
|
+
`sysml2kit.verify` closes the loop the traceability queries only describe:
|
|
4
|
+
it runs the analyses a model's verify links point at and checks each
|
|
5
|
+
requirement against real metrics.
|
|
6
|
+
|
|
7
|
+
## The binding convention
|
|
8
|
+
|
|
9
|
+
An analysis case becomes executable when it carries a `verificationBinding`
|
|
10
|
+
metadata (see SPEC.md for the normative statement):
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from sysml2kit.model import builder
|
|
14
|
+
|
|
15
|
+
analysis = builder.analysis(model, "pasStudy", owner=pkg, subject=terminal)
|
|
16
|
+
builder.verify(model, source=analysis, target=link_margin_req, owner=pkg)
|
|
17
|
+
builder.metadata(
|
|
18
|
+
model,
|
|
19
|
+
analysis,
|
|
20
|
+
{"engine": "phased-array-systems", "configRef": "study.yaml"},
|
|
21
|
+
name="verificationBinding",
|
|
22
|
+
)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- `engine` names an entry in the engine registry — never a code path.
|
|
26
|
+
Models are data; the registry decides what runs.
|
|
27
|
+
- `configRef` points at a YAML/JSON payload next to the model file.
|
|
28
|
+
- `payload.<dotted>` values override entries in the loaded config
|
|
29
|
+
(`payload.scenario.range_km: 500`).
|
|
30
|
+
|
|
31
|
+
## Engines
|
|
32
|
+
|
|
33
|
+
An engine is a callable: payload dict in, flat metrics mapping out.
|
|
34
|
+
Packages ship engines through the `sysml2kit.engines` entry-point group:
|
|
35
|
+
|
|
36
|
+
```toml
|
|
37
|
+
[project.entry-points."sysml2kit.engines"]
|
|
38
|
+
phased-array-systems = "phased_array_systems.interop.sysml:run_study"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Installing such a package makes its engine available by name. The CLI also
|
|
42
|
+
accepts operator-supplied engines (`--engine name=module:function`), and
|
|
43
|
+
library callers register directly on an `EngineRegistry`.
|
|
44
|
+
|
|
45
|
+
## Running
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
sysml2kit verify model.json --report run.json
|
|
49
|
+
sysml2kit verify model.json --write-back -o annotated.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from sysml2kit.verify import run_verification, apply_results
|
|
54
|
+
|
|
55
|
+
run = run_verification(model, model_path=path)
|
|
56
|
+
print(run.passed)
|
|
57
|
+
for verdict in run.requirements:
|
|
58
|
+
print(verdict.requirement_id, verdict.status, verdict.margin)
|
|
59
|
+
apply_results(model, run) # record results into the model, idempotent
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Each requirement verdict carries the metric key, operator, threshold,
|
|
63
|
+
actual value, and margin; `passed` is true only when every must-severity
|
|
64
|
+
requirement passes and no engine errored. Metrics that are absent or
|
|
65
|
+
non-numeric yield `unknown`, which does not pass. Engine exceptions are
|
|
66
|
+
captured per analysis, never raised.
|
|
67
|
+
|
|
68
|
+
Write-back records each checked metric as an attribute on its analysis with
|
|
69
|
+
a provenance `source` (`sysml2kit.verify <engine>==<version> <timestamp>`)
|
|
70
|
+
and a `verificationVerdict` metadata on each requirement, replacing prior
|
|
71
|
+
results so reruns do not accumulate.
|
|
72
|
+
|
|
73
|
+
Over MCP, the `requirements_verify` tool runs the same flow with
|
|
74
|
+
entry-point engines only, returning `passed`, must-failures, and the report
|
|
75
|
+
path.
|
|
76
|
+
|
|
77
|
+
## End to end with the RF library
|
|
78
|
+
|
|
79
|
+
With `phased-array-systems` and `sysml2kit-rf-library` installed:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
MODEL=$(python -c 'import sysml2kit_rf_library as m; print(m.models_dir())')/interchange/satcom_terminal_pas.json
|
|
83
|
+
sysml2kit verify "$MODEL" --report run.json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
runs a phased-array study and checks link margin, EIRP, sidelobes, prime
|
|
87
|
+
power, and cost against the model's thresholds.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Diagrams
|
|
2
|
+
|
|
3
|
+
`sysml2kit.views` renders two mermaid views; output is deterministic, so
|
|
4
|
+
diagrams diff cleanly and render anywhere mermaid fences do (these docs,
|
|
5
|
+
GitHub, Claude artifacts).
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from sysml2kit.views import to_mermaid_trace, to_mermaid_tree
|
|
9
|
+
|
|
10
|
+
print(to_mermaid_trace(model)) # requirements, parts, analyses + edges
|
|
11
|
+
print(to_mermaid_tree(model)) # package/part/port ownership
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
sysml2kit export model.json --to mermaid --diagram trace -o trace.mmd
|
|
16
|
+
sysml2kit export model.json --to mermaid --diagram tree
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The trace view draws requirements as hexagons, analyses as parallelograms,
|
|
20
|
+
and parts as rounded boxes, with edge styles per relationship kind: solid
|
|
21
|
+
`satisfy`, dotted `verify`/`derive`, thick `allocate`. Only elements that
|
|
22
|
+
participate in a relationship appear, so large models stay readable.
|
|
23
|
+
|
|
24
|
+
Over MCP, the `model_diagram` tool writes the same views to a `.mmd` file.
|
|
@@ -34,7 +34,9 @@ nav:
|
|
|
34
34
|
- Quickstart: quickstart.md
|
|
35
35
|
- Concepts: concepts.md
|
|
36
36
|
- Traceability: traceability.md
|
|
37
|
+
- Verification: verification.md
|
|
37
38
|
- Interchange: interchange.md
|
|
39
|
+
- Diagrams: views.md
|
|
38
40
|
- Command line: cli.md
|
|
39
41
|
- MCP server: mcp.md
|
|
40
42
|
- API client: api-client.md
|
|
@@ -52,6 +52,8 @@ parse = ["sysmlpy>=0.36.2,<0.37"]
|
|
|
52
52
|
graph = ["networkx>=3.2"]
|
|
53
53
|
# mcp 2.0.0 removed mcp.server.fastmcp; stay on 1.x until the surface is ported.
|
|
54
54
|
mcp = ["mcp>=1.26,<2"]
|
|
55
|
+
# YAML verification-binding configs; JSON configs work without it.
|
|
56
|
+
verify = ["pyyaml>=6.0"]
|
|
55
57
|
|
|
56
58
|
[project.scripts]
|
|
57
59
|
sysml2kit = "sysml2kit.cli:app"
|
|
@@ -70,15 +72,17 @@ test = [
|
|
|
70
72
|
"hypothesis>=6.130",
|
|
71
73
|
"respx>=0.22",
|
|
72
74
|
]
|
|
73
|
-
lint = ["mypy>=1.15", "ruff>=0.16"]
|
|
75
|
+
lint = ["mypy>=1.15", "ruff>=0.16", "types-PyYAML>=6.0"]
|
|
74
76
|
parse-test = ["sysmlpy>=0.36.2,<0.37"]
|
|
75
77
|
mcp-test = ["mcp>=1.26,<2"]
|
|
78
|
+
verify-test = ["pyyaml>=6.0"]
|
|
76
79
|
docs = ["mkdocs-material>=9.5", "mkdocstrings[python]>=0.27"]
|
|
77
80
|
dev = [
|
|
78
81
|
{ include-group = "test" },
|
|
79
82
|
{ include-group = "lint" },
|
|
80
83
|
{ include-group = "parse-test" },
|
|
81
84
|
{ include-group = "mcp-test" },
|
|
85
|
+
{ include-group = "verify-test" },
|
|
82
86
|
{ include-group = "docs" },
|
|
83
87
|
]
|
|
84
88
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Wait for a Systems Modeling API server to answer; used locally and in CI.
|
|
3
|
+
set -u
|
|
4
|
+
|
|
5
|
+
URL="${SYSML2KIT_API_URL:-http://localhost:9000}"
|
|
6
|
+
DEADLINE=$((SECONDS + ${WAIT_FOR_API_TIMEOUT:-180}))
|
|
7
|
+
|
|
8
|
+
echo "[wait_for_api] polling ${URL}/projects"
|
|
9
|
+
while [ $SECONDS -lt $DEADLINE ]; do
|
|
10
|
+
if curl -sf "${URL}/projects" >/dev/null 2>&1; then
|
|
11
|
+
echo "[wait_for_api] server is up (${SECONDS}s)"
|
|
12
|
+
exit 0
|
|
13
|
+
fi
|
|
14
|
+
sleep 3
|
|
15
|
+
done
|
|
16
|
+
echo "[wait_for_api] timed out after ${WAIT_FOR_API_TIMEOUT:-180}s" >&2
|
|
17
|
+
exit 1
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.3.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 3, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -101,6 +101,37 @@ class SysMLApiClient:
|
|
|
101
101
|
payload["description"] = description
|
|
102
102
|
return Project.model_validate(self._post("/projects", payload))
|
|
103
103
|
|
|
104
|
+
@staticmethod
|
|
105
|
+
def _to_server_record(record: dict[str, Any]) -> dict[str, Any]:
|
|
106
|
+
"""Adapt one interchange record to the pilot server's dialect.
|
|
107
|
+
|
|
108
|
+
The abstract syntax types relationship ``source``/``target`` as lists
|
|
109
|
+
of related elements; sysml2kit's records carry a single ``{"@id"}``
|
|
110
|
+
(a documented profile simplification). Wrap them on the way out; the
|
|
111
|
+
interchange reader unwraps single-element lists on the way back.
|
|
112
|
+
"""
|
|
113
|
+
adapted = dict(record)
|
|
114
|
+
for key in ("source", "target", "definition"):
|
|
115
|
+
value = adapted.get(key)
|
|
116
|
+
if isinstance(value, dict) and set(value) == {"@id"}:
|
|
117
|
+
adapted[key] = [value]
|
|
118
|
+
# Profile simplifications with no server-side shape are dropped on
|
|
119
|
+
# push (multiplicity is opaque text here, a Multiplicity element
|
|
120
|
+
# there). Fidelity lives in interchange JSON files, not the server.
|
|
121
|
+
adapted.pop("multiplicity", None)
|
|
122
|
+
# RequirementUsage/RequirementDefinition `text` is List<String> there.
|
|
123
|
+
if isinstance(adapted.get("text"), str):
|
|
124
|
+
adapted["text"] = [adapted["text"]]
|
|
125
|
+
# The pilot's type vocabulary has no DeriveRequirementUsage or
|
|
126
|
+
# VerifyRequirementUsage; those push as Dependency (client/supplier),
|
|
127
|
+
# losing the kind distinction on pull — same degradation class as the
|
|
128
|
+
# textual notation. Full fidelity lives in interchange JSON files.
|
|
129
|
+
if adapted.get("@type") in ("DeriveRequirementUsage", "VerifyRequirementUsage"):
|
|
130
|
+
adapted["@type"] = "Dependency"
|
|
131
|
+
adapted["client"] = adapted.pop("source", None) or []
|
|
132
|
+
adapted["supplier"] = adapted.pop("target", None) or []
|
|
133
|
+
return adapted
|
|
134
|
+
|
|
104
135
|
def push_model(
|
|
105
136
|
self,
|
|
106
137
|
project_id: str,
|
|
@@ -110,7 +141,10 @@ class SysMLApiClient:
|
|
|
110
141
|
message: str | None = None,
|
|
111
142
|
) -> Commit:
|
|
112
143
|
"""Create a commit whose change set inserts every element of the model."""
|
|
113
|
-
change = [
|
|
144
|
+
change = [
|
|
145
|
+
{"@type": "DataVersion", "payload": self._to_server_record(record)}
|
|
146
|
+
for record in model_to_json(model)
|
|
147
|
+
]
|
|
114
148
|
payload: dict[str, Any] = {"@type": "Commit", "change": change}
|
|
115
149
|
if message:
|
|
116
150
|
payload["description"] = message
|
|
@@ -118,3 +152,10 @@ class SysMLApiClient:
|
|
|
118
152
|
if branch:
|
|
119
153
|
path += f"?branchId={branch}"
|
|
120
154
|
return Commit.model_validate(self._post(path, payload))
|
|
155
|
+
|
|
156
|
+
def head_commit(self, project_id: str) -> Commit:
|
|
157
|
+
"""Return the newest commit of a project; raises ApiError when empty."""
|
|
158
|
+
commits = self.list_commits(project_id)
|
|
159
|
+
if not commits:
|
|
160
|
+
raise ApiError(404, f"project {project_id} has no commits")
|
|
161
|
+
return commits[-1]
|