This appendix says what the site and its proofs run on, so that a reader can rebuild every page and verdict on their own machine: the environment is a lockfile and the reviewer recipe is seven lines.
1What executable specification means here¶
The graphs are the model: the vocabulary, the sources, the rulings, the
essentials, the pruned SysML rendering and the measles evaluation are
Turtle files under version control, and no page states what they cannot
answer by query. The scripts render every figure and table into
generated/ and the explorer, and the gate regenerates them and diffs
them byte for byte, so a table cannot drift from its graph. The shapes and
the tests are the checks: SHACL over the record and the model graph,
pytest over the prose, the citations and the wiring. The gate is the only
verdict: one script, every step, one line. CI runs the same script on a
fresh runner and deploys the site only when it prints PASS.
The record is a PROV bundle every item and agent is a member of, and the
shapes and the record queries assume one default graph: the record, the
EPO vocabulary and the model graph loaded together, since an item’s step
is derived through the model and every global rule is anchored on the
record its focus node belongs to. Two records in one graph do not collide.
A quad store with one named graph per file answers nothing: the coverage
query returns no row and the shapes find nothing to check. The explorer
ships one merged file, explorer/data/all.ttl, for that reason.
2The layers¶
From the bottom up. The virtual environment is managed by uv:
pyproject.toml declares the direct dependencies, uv.lock pins the whole
resolution to versions and content hashes, and uv sync reproduces it on
any machine. OpenSysML is not in that environment, on purpose: it is the
modelling tool, used at authoring time for strict validation of the SysML
source and its rendering to RDF, and everything downstream reads only the
RDF; toolchain/get-sysml.sh fetches the pinned release as a binary and
checks the tarball and the installed binary against committed digests.
rdflib and pySHACL parse the graphs and run the shapes; pypdf reads the
PDF sources for the quote checks. MyST, the mystmd package over Node.js,
builds the site from the pages and the included fragments. nbclient
re-executes the proof notebooks and compares their outputs with the
committed ones. The ogc command line reads the graphs for people and AI
assistants; its skill file, .claude/skills/ogc-glossary/SKILL.md, tells
an assistant to ask the graph and never to answer from memory. The
vendored d3 and oxigraph run Appendices A and B in the browser without the network.
The graphs are written in a small set of ontologies, none invented here beyond the specification’s own handles. PROV-O says who did what and when. EARL says what was asserted, with an outcome of passed, failed or cannot tell, which is why a determination is never a Boolean. SKOS holds the glossary. OWL and RDF Schema declare the Evaluation Process Ontology’s classes and properties. SHACL states every check. The SysML v2 vocabulary is OpenSysML’s rendering of the OMG metamodel, with a few tool facts of its own. The specification’s namespaces under w3id.org name the terms, the sources, the rulings, the essentials, the crosswalk, the derived ends of the model graph and the measles evaluation. The table below counts what each is used for.
3The Python environment¶
Python >=3.12 (pyproject.toml), pinned to 3.12 by .python-version so that uv sync installs the same interpreter everywhere. uv sync reproduces the environment from uv.lock (lockfile version 1, revision 3): 111 packages in all, 11 direct (3 runtime, 8 dev) and 100 transitive, every one pinned to a version and a content hash. The project og-caie-spec is installed editable and provides the ogc command.
| Package | Group | Constraint (pyproject.toml) | Locked (uv.lock) |
|---|---|---|---|
rdflib | runtime | >=7.0 | 7.6.0 |
pyshacl | runtime | >=0.27 | 0.40.1 |
pypdf | runtime | >=6.0 | 6.17.0 |
pytest | dev | >=8.0 | 9.1.1 |
pyyaml | dev | >=6.0 | 6.0.3 |
mystmd | dev | >=1.3 | 1.10.1 |
nbclient | dev | >=0.10 | 0.11.0 |
nbformat | dev | >=5.10 | 5.11.1 |
jupyter | dev | >=1.0 | 1.1.1 |
ipykernel | dev | >=6.29 | 7.3.0 |
owlrl | dev | >=7.6.2 | 7.6.2 |
4The pinned converter¶
| Setting | Value | Read from |
|---|---|---|
| Release | OpenSysML v0.4.3 | model/model_manifest.json |
| Fetched from | https://github.com/Open-MBEE/OpenSysML/releases/download/v0.4.3 | toolchain/get-sysml.sh (VER=v0.4.3) |
| Invocation | -convert ttl | model/model_manifest.json |
| Digest file | toolchain/sysml-binaries.sha256, sha256 8efae36144923a29a21aa57d59286442db5ffaaa9a3773fafcc57616ade6f961 | model/model_manifest.json |
| Authoring source | model/og-caie.sysml, sha256 d0764a4ea026fc29c2b8f603216679e10be00d799f853bbff28cc539c2fff735 | model/model_manifest.json |
| Term map | model/sysml_term_map.csv, 59 terms, sha256 6a58361b86b4a4a0a94c077efdb23a9541da988fca8735f74a4b02c6e4dd270f | model/model_manifest.json |
| Canonical graph | model/og-caie.model.ttl, 5712 triples of 18976 converted (budget 6600, headroom 888), sha256 deffb0f33dcd5d7e58de07b4a0b42f84e3ef92c9f132095b7166c4804c43e1e6 | model/model_manifest.json |
Per platform, the digest the installed binary must hash to (toolchain/sysml-binaries.sha256) and the digest the release tarball must hash to before it is unpacked (toolchain/SHA256SUMS.pinned); toolchain/get-sysml.sh checks both on every run.
| Platform | Installed binary sha256 | Release tarball sha256 |
|---|---|---|
| darwin-arm64 | a3298d68a08b863fba276bd6d0d72aad9947cdeb4b28103ce9b526400f8f475b | 0927e2e7bbf86c6b6e546d275273c529808f98b6da9c525155e8a80bba4623bf |
| darwin-amd64 | 712b6c8290aea0b0395f1ea313b6a2af0754202524055733824f2064b49dfe2c | 95bfa593d773a5fabe99402dec8e860163d0673299ef8b038dd7c0d2e6f97350 |
| linux-amd64 | 1fba036a16367133e6f55026f254ca4749502bb35b0c6ae0e9990961e1461d30 | 661df51718d8506fff925d7b89d0cc119c5c1247f389f9bd9b87d6443ac4553d |
| linux-arm64 | 571ab5f1bf0ba0d27732cbc1afed4d724cdc38ddd6ba7636ef67422a77648925 | ceba7303c9ffd391b2849b4ae4e15ec52d9ccb951e81b8dc47b7359ee07cdc96 |
5The ontologies and vocabularies¶
What the graphs are written in, counted over the committed Turtle files (vocabulary/og-caie.ttl, vocabulary/epo.ttl, vocabulary/crosswalk.ttl, vocabulary/register.ttl, vocabulary/ogm.ttl, sources/sources.ttl, rulings/adjudications.ttl, model/trace.ttl, model/og-caie.model.ttl, track/measles-evaluation.ttl, shapes/epo.shapes.ttl, shapes/model.shapes.ttl, shapes/rulings.shapes.ttl): the classes and properties of each vocabulary that the graphs actually use, and the subjects each names. The W3C vocabularies are adopted as published; the SysML namespace is OpenSysML’s rendering of the OMG SysML v2 metamodel, not a vocabulary OMG publishes at that IRI; the specification’s own namespaces resolve under w3id.org.
| Prefix | Namespace | Whose | What it does here | Classes used | Properties used | Subjects | Reference |
|---|---|---|---|---|---|---|---|
rdf | http://www.w3.org/1999/02/22-rdf-syntax-ns# | W3C | RDF 1.1: typing (rdf:type) and lists | 0 | 3 | 0 | https:// |
rdfs | http://www.w3.org/2000/01/rdf-schema# | W3C | RDF Schema: labels, comments, subclassing | 0 | 6 | 0 | https:// |
owl | http://www.w3.org/2002/07/owl# | W3C | OWL 2: the EPO’s classes and properties | 4 | 3 | 0 | https:// |
skos | http://www.w3.org/2004/02/skos/core# | W3C | SKOS: the glossary’s concepts, labels, definitions and notes | 2 | 11 | 0 | https:// |
prov | http://www.w3.org/ns/prov# | W3C | PROV-O: who did what and when in the record (agents, activities, entities, derivation, attribution) | 7 | 9 | 0 | https:// |
earl | http://www.w3.org/ns/earl# | W3C | EARL 1.0: assertions with an assertor, a mode, a subject, a test and an outcome (passed, failed, cantTell) | 2 | 7 | 0 | https:// |
sh | http://www.w3.org/ns/shacl# | W3C | SHACL: the shapes that check the record, the model graph and the rulings, including SHACL-SPARQL constraints | 2 | 18 | 0 | https:// |
sysml | https://www.omg.org/spec/SysML# | OpenSysML (after the OMG SysML v2 metamodel) | SysML v2 vocabulary as the OpenSysML converter renders the model: definitions, usages, ports, interfaces, actions, successions, flows | 26 | 18 | 0 | https:// |
sysx | urn:opensysml:sysml: | OpenSysML | the converter’s own facts: the ends of a connection, the source text of a statement, a prefix keyword | 0 | 4 | 0 | https:// |
elmt | urn:sysmlv2:element: | OpenSysML | the converter’s element identifiers, one per model element | 0 | 0 | 647 | https:// |
expr | urn:opensysml:expr: | OpenSysML | the converter’s expression identifiers (end paths, multiplicity bounds) | 0 | 0 | 491 | https:// |
ogc | https://w3id.org/og-caie/ | this specification | the register: citation classes and properties, shapes’ names, concerns, rulings, crosswalk rows, trace essentials | 6 | 52 | 118 | https:// |
term | https://w3id.org/og-caie/terms# | this specification | the glossary’s terms | 0 | 0 | 69 | https:// |
src | https://w3id.org/og-caie/sources# | this specification | the source register | 0 | 0 | 79 | https:// |
rul | https://w3id.org/og-caie/rulings# | this specification | concerns and rulings | 0 | 0 | 114 | https:// |
epo | https://w3id.org/og-caie/epo# | this specification | the Evaluation Process Ontology’s handles: item classes, steps, layers, roles and their properties | 54 | 61 | 169 | https:// |
xw | https://w3id.org/og-caie/crosswalk# | this specification | the crosswalk rows of the front page’s bridge into the standards | 0 | 0 | 7 | https:// |
tr | https://w3id.org/og-caie/trace# | this specification | the essentials SCI-01 to SCI-13 | 0 | 0 | 13 | https:// |
ogm | https://w3id.org/og-caie/model# | this specification | the derived ends of the canonical model graph (resolved ports, flow ends, successions, relations) | 0 | 11 | 11 | https:// |
ev | https://w3id.org/og-caie/evaluation/measles# | this specification | the measles evaluation’s record, its items and agents (sheet 10-42) | 0 | 0 | 127 | https:// |
6The vendored browser libraries¶
Appendix B runs in the browser on two libraries committed under explorer/vendor/, so the explorer loads nothing from the network; Appendix A’s report draws with the same d3 file, loaded by the relative path ../explorer/vendor/d3.v7.min.js, so there is one copy. Versions and licences are as the files state them.
| Library | Version | Licence | Source or copyright | Stated in |
|---|---|---|---|---|
| d3 | 7.9.0 | not stated in the file | Copyright 2010-2023 Mike Bostock | explorer/vendor/d3.v7.min.js (first line) |
oxigraph (WebAssembly, web.js, web_bg.wasm) | 0.5.11 | MIT OR Apache-2.0 | https:// | explorer/vendor/oxigraph/NOTICE.md |
7The gate¶
checks/run-checks.sh runs 10 steps, every one, in this order; a step passes when its exit code is the expected one. The only summary is the CHECKS: PASS or CHECKS: FAIL line and checks/out/report.json; each step’s full output is in checks/out/last.log. Nothing is optional and nothing fails quietly.
| # | Step | Expected exit | Command |
|---|---|---|---|
| 1 | toolchain: pinned sysml v0.4.3, digest-verified | 0 | bash toolchain/get-sysml.sh |
| 2 | model: validate -strict (authoring view and model counterexamples) | 0 | toolchain/bin/sysml model/og-caie.sysml counterexamples/model/unwired-port.sysml counterexamples/model/expert-administers-tests.sysml counterexamples/model/missing-accountable.sysml counterexamples/model/no-obligation.sysml -validate -strict |
| 3 | model graph: convert, prune, byte-identical to the committed canonical graph | 0 | uv run python scripts/prune_model.py && git diff --quiet -- model/og-caie.model.ttl model/model_manifest.json |
| 4 | ogc: doctor (labels unambiguous, quotes located, record consistent) | 0 | uv run -q ogc doctor --no-cache |
| 5 | drift: the consistency loop, mechanical layer (appendix letters and counts, the mutation count, stale phrases, retired words, file mentions, sheet ticks, twins, absence rows, the CI condition on held-locally quotes) | 0 | uv run python scripts/drift_check.py |
| 6 | notebooks: executed by nbclient, outputs equal the committed ones, verdict NOTEBOOK: PASS | 0 | uv run python scripts/execute_notebooks.py --check |
| 7 | tests: full suite | 0 | uv run pytest -q |
| 8 | generated/, explorer/ and report/: regenerate byte-identically | 0 | bash checks/regen.sh (uv run python scripts/render.py && uv run python scripts/render_cli.py && uv run python scripts/render_diagrams.py && uv run python scripts/render_explorer.py && uv run python scripts/render_report.py && uv run python scripts/render_toolchain.py && uv run python scripts/render_bib.py && uv run python scripts/render_version.py) && git diff --quiet -- generated/ explorer/ report/ |
| 9 | site: myst build --html | 0 | uv run myst build --html |
| 10 | site: the explorer and the sample report copied next to the built site | 0 | bash scripts/copy_explorer.sh |
8Continuous integration¶
.github/workflows/deploy.yml (workflow checks-and-deploy) runs on push (branches: main), pull_request, workflow_dispatch. The checks job runs the same gate script; the deploy job needs it and runs only when github.ref == 'refs/heads/main' && github.event_name != 'pull_request'.
| Job | Step | Runs |
|---|---|---|
| checks | actions/checkout@v4 | actions/checkout@v4 |
| checks | astral-sh/setup-uv@v5 | astral-sh/setup-uv@v5 |
| checks | actions/setup-node@v4 | actions/setup-node@v4 (node-version: 20) |
| checks | python environment | uv sync |
| checks | full gate | bash checks/run-checks.sh |
| checks | gate log, for diagnosis when a step fails | actions/upload-artifact@v4 (name: gate-log, path: checks/out/last.log checks/out/report.json) |
| checks | build the site for Pages | BASE_URL="/${REPO_NAME}" uv run myst build --html |
| checks | the knowledge graph explorer next to the site | bash scripts/copy_explorer.sh |
| checks | actions/upload-pages-artifact@v3 | actions/upload-pages-artifact@v3 (path: _build/html) |
| deploy | actions/deploy-pages@v4 | actions/deploy-pages@v4 |
9Enforcement points¶
The same script gives the verdict at three points; none can be skipped by editing a page.
| Where | What runs | Read from |
|---|---|---|
| Before every push, in the author’s checkout | bash checks/gate-head.sh (installed with git config core.hooksPath checks/hooks) | checks/hooks/pre-push |
On the committed HEAD, in a detached worktree at .cache/gate-head.XXXXXX, never on the working tree | bash checks/run-checks.sh | checks/gate-head.sh |
| In CI, on a fresh runner, before any deploy | bash checks/run-checks.sh; deploy needs checks | .github/workflows/deploy.yml |
10The reviewer recipe¶
From a git clone with git, uv and Node.js 20 or later installed. The first run needs the network for the interpreter and the wheels, the converter’s tarball and the site theme; a second run is offline. The gate takes three to four minutes on a laptop, most of it the test suite.
uv sync
bash toolchain/get-sysml.sh
bash checks/run-checks.sh
uv run -q ogc doctor
uv run myst build --html
bash scripts/copy_explorer.sh
uv run python -m http.server -d _build/html 8000uv sync creates .venv from the lockfile. get-sysml.sh prints
sysml installed+verified: sysml v0.4.3 on a first fetch and nothing when
the verified binary is in place; a digest mismatch exits 1. The gate prints
each step’s name and pass or FAIL, then CHECKS: PASS or CHECKS: FAIL with the commit it judged; that line is what the pre-push hook and
CI require, and a failing step prints its last lines. ogc doctor ends
with VERDICT: PASS with the commit it judged, after one line per check
and a note per fact that is not a fault. The notebook step prints one line
per notebook, fresh or STALE, then NOTEBOOK: PASS or NOTEBOOK: FAIL; the kernel’s warning about an unencrypted local transport is
expected. myst build --html writes the site under _build/html; the
gate copies Appendices A and B next to it, and serving that folder over
http is what makes their frames and the SPARQL box work (myst start serves the pages but not the explorer). The fetch script supports
macOS and Linux on x86-64 and arm64 and needs curl, tar and a sha256 tool;
the site build and the notebooks need free local ports.
11The first rung¶
The appendices are the first rung of backup; the repository is the richer one, every graph, shape, script, test and notebook the site is rendered from, with the gate that judges them. A reader need not trust the authors: run the recipe and read the verdict.