Skip to content

feat(identity): fix ids for OpenSysML's own library elements so references link by id - #1332

Merged
HuiJun merged 5 commits into
feat/apijson-bridge-opensysml-librariesfrom
feat/extension-library-identity
Oct 21, 2026
Merged

HuiJun merged 5 commits into
feat/apijson-bridge-opensysml-librariesfrom
feat/extension-library-identity

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What and why

A reference into one of OpenSysML's own libraries (DocumentQueries, MOSA, OOSEM, …) was written as a {"@ref": "caption"} name reference, where the pilot writes an element id — Redefinition.redefinedFeature, FeatureTyping.type, MetadataUsage.type, ViewUsage.type, FeatureReferenceExpression.referent, ReferenceSubsetting.referencedFeature (gap row 41 of docs/project/api-json-differential.md, measured by #1328 once the pilot bridge loaded OpenSysML Libraries/). Cause: rdf_identity.go libraryElement gave an id only to symbols the norm identifies (SourceNormative); the extension libraries are not normative, so the writer fell back to the name.

The extension libraries' named elements now carry a fixed, deterministic id, derived exactly as a normative id is but under the libraries' own URL:

  • identity.Language gains OpenSysML, whose Prefix() is ExtensionPrefix = "https://github.com/Open-MBEE/OpenSysML-Extensions-Library/" (the libraries' upstream home, as the OMG libraries hash under their specification URLs). A package's id is uuid5(URL name space, prefix + package), each named element under it uuid5(package id, escaped qualified name), the owning membership …/owningMembership — ElementID/OwningMembershipID unchanged, LibraryLanguage(TierOpenSysML) maps to it, so LibraryCatalog catalogues the 800 named extension elements beside the normative ones.
  • identity.Source gains SourceExtension ("extension"), kept apart from SourceNormative: Info.Normative() still means "the norm fixes it"; the new Source.Fixed()/Info.Fixed() means "a bundled library fixes it" and is what the writer (libraryElement, symbolTerm, normativeFQN, the library-document names), the reader (catalog lookup by id, unchanged) and the LSP (hover (extension, OpenSysML), no minted-id code action) key on.
  • Result on examples/mosa-demo/mosa-demo.sysml: 683 {"@ref": …} on the base → 0; each becomes {"@id": <uuid>} with the target named by a library stub (sysml:isLibraryElement true, qualifiedName, elementId) in the Turtle, as a standard-library target is.

Not the pilot's ids. The pilot, loading the same files as a library directory, hashes every library package under https://www.omg.org/spec/SysML/ (its LibraryPackageAdapter), so its ids for MOSA::… differ from ours by the prefix constant alone. The OMG namespace is for OMG-published content: minting a non-OMG library under it is a pilot departure, not a specification requirement, and the referee's outcome is identical either way, so the prefix stays OpenSysML's own (ExtensionPrefix, one constant) and the difference is stated in docs/reference/rdf-mapping.md.

Related. #1232's LibraryCatalogWithOpenSysML (a second, OMG-prefixed catalog of the extension libraries) becomes redundant once this lands, and its rebase will conflict in internal/semantic/identity/library.go. #1331 and #1333 re-record the same docs/project/api-json-differential-baseline.json and docs/project/api-json-differential.md as this PR: whichever of the three lands second re-merges the first and re-runs go run -C tools ./cmd/pilot-apijson-diff -update plus make docs-counts on the merged tree.

Specification basis

KerML 1.1 Beta 2 §8.3.2.1.2 Element::elementId — every Element has one — and §8.3.3.3.7/§8.3.3.3.8 for the Redefinition/FeatureTyping ends, which are elements, not names. No clause fixes the ids of non-normative libraries; the scheme here is the implementation's, deterministic and never random per run, and is documented as such. No spec-compliance.md row moves.

In-flight overlap

How it was verified

  • tests/identity: TestOpenSysMLLibraryElementCarriesAFixedExtensionID (source, language, ElementID/OwningMembershipID, the uuid5(URL, ExtensionPrefix+name) package rule, not a specification-URL id, deterministic across independent analyses, catalogued both ways); TestPilotLibraryXMI now also asserts no extension id collides with an id in the pilot's XMI (every other XMI assertion unchanged; extension elements are excluded from the "pilot serializes nothing with that id" check since the XMI has none). TestUserElementIsDerivedAndOpenSysMLLibraryIsNotNormative is split: the user-element half stays, the extension half now asserts the extension id (the behaviour it pinned — a derived id — is the one this PR changes, intentionally).
  • tests/export/extension_library_identity_test.go: API JSON has no @ref; Redefinition.redefinedFeature, FeatureTyping.type, MetadataUsage.type, NamespaceImport.importedNamespace reference the catalogued ids; the Turtle stub carries elementId/qualifiedName/isLibraryElement; Turtle and API JSON both read back to notation.
  • LSP hover: (extension, OpenSysML) case added to TestHoverStatesDeclaredAndNormativeIdentity.
  • Round-trip ratchets: TestCorpusRoundTrip and TestCorpusAPIJSONRoundTrip with OPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 OPENSYSML_REQUIRE_SPEC_EXAMPLES=1: pass, no verdict moved (the Turtle of every model referencing these libraries changed — IRIs and stubs where names were — and every one still round-trips as before).
  • Full gate: go build ./..., go vet ./..., gofmt -l . (empty), go test ./..., go test -C tools ./..., make lint, python3 scripts/changelog.py check, make docs-counts ("Documentation counts and refereed figures are current").

Referee: reproduction and movement

Fresh XDG_CACHE_HOME each run, pilot 2026-08 (0.62.0), 920 files.

  • develop reproduces its committed baseline byte for byte but for the recording date (86974 matched; 596664 / 47633 / 1021444 / 65920 / 2020649 / 20867).
  • feat(referee): load the OpenSysML Libraries into the pilot JSON bridge and re-record the api-json differential #1328's head reproduces its committed baseline per root (89957 matched; 618674 / 50027 / 1058325 / 68494 / 2102500 / 21034).
  • This branch: 90023 matched (28511 ours-only, 38797 pilot-only); 619268 present-equal, 45688 present-different, 1058259 ours-missing, 68560 pilot-missing, 2103094 absent-both, 25703 indeterminate. Re-recorded as the committed baseline (-update writes the run's report verbatim; the committed file is that report, and a -check run over it reproduces).

Movement against #1328's baseline — pilot side and keys untouched, so every movement is the writer's — 56 rows, all adjudicated in the record (docs/project/api-json-differential.md § "References into this repository's libraries link by id"):

root (the gap's six) present-different indeterminate
Redefinition.redefinedFeature 388 → 58 (−330) 542 → 938 (+396: 330 moved + 66 newly matched)
FeatureTyping.type 670 → 338 (−332) 1904 → 2236
MetadataUsage.type 147 → 13 (−134) 82 → 216
ViewUsage.type 19 → 3 (−16) 29 → 45
FeatureReferenceExpression.referent 99 → 71 (−28) 436 → 464
ReferenceSubsetting.referencedFeature 40 → 38 (−2) 24 → 26

Same shape, same direction, on the rows the brief did not list: InvocationExpression.function 245 → 19, Membership.memberElement 353 → 99, PartUsage.type 235 → 63, Subclassification.superclassifier 126 → 13, Subsetting.subsettedFeature 44 → 34, NamespaceImport.importedNamespace 25 → 8, MembershipImport.importedMembership 15 → 13, CalculationUsage.type 7 → 3, ItemUsage.type 20 → 16, ReferenceUsage.type 48 → 46, and each relationship's restated ends (target, relatedElement, general, subsettedFeature) with the end they restate.

Why indeterminate and not equal: the element form carries the model's own elements only, so a library target has no key on our side and the referee cannot equate it — the bucket that already holds references to standard library elements. No row's present-equal fell; no counter moved toward the pilot's disadvantage except the shapes the 66 newly matched elements carry: the metadata body feature @MOSAPackage { pillar = … } was written as a ReferenceUsage with declaredName "pillar" and a value (its redefinition reached a library feature the writer could not link); it is now unnamed with an owned Redefinition of MOSAPackage::pillar, as the pilot writes it, so 66 Redefinitions match (matched +66, pilot-only −66, ReferenceUsage.declaredName pilot-missing 70 → 4, ReferenceUsage.ownedRedefinition/ownedSpecialization/ownedSubsetting +66 present-equal each) and carry the Redefinition rows' existing shapes (isLibraryElement/owningType ours-missing +66, owner/redefines pilot-missing +66). Remaining Redefinition.redefinedFeature present-different (58): redefinitions of a feature inherited within the model the writer still spells as a name (vehicle_b_1::providePower), not into these libraries — a separate gap, out of scope here.

Behaviour changes

  • A reference into an OpenSysML library is an id, not a name, in Turtle (IRI + library stub) and API JSON ({"@id"}); a reader resolves it against the bundled catalog by id, or by the stub's qualifiedName when the id is foreign (the existing standard-library path).
  • A metadata body feature binding a library metadata definition's feature is written as a redefinition with an effective name, not a declared name.
  • Hover on an extension-library element now states its id, (extension, OpenSysML); the "annotate with a minted id" code action is no longer offered for one (it has a fixed id).
  • identity.LibraryCatalog catalogues the 800 named extension-library elements; Info.Normative() is unchanged (false for them), Info.Fixed() is the new predicate.

Checklist

  • make test and make lint pass locally
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (see CONTRIBUTING.md)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md
  • baselines regenerated and make docs-counts run if a gate count moved (compliance rows need nothing: the census is counted at docs build)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

Link to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/9096ac68d66141d487cd94f44d459425
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/9096ac68d66141d487cd94f44d459425?variant=devin
Requested by: @HuiJun

devin-ai-integration Bot and others added 2 commits October 21, 2026 00:21
…ences link by id

A reference into one of the bundled extension libraries (DocumentQueries,
MOSA, OOSEM, ...) was written as a {"@ref": name} name reference, because
libraryElement gave an id only to symbols the norm identifies. The
extension libraries now carry fixed, deterministic ids derived as the
normative ones are, under the libraries' upstream URL (identity.OpenSysML,
SourceExtension), so the writer links them by id and names them with a
library stub, hover reports them as (extension, OpenSysML), and the
identity gate checks they collide with nothing in the pilot's XMI.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

…to OpenSysML's libraries linked by id

The writer now links every reference into this repository's own libraries by
the element's fixed id, so the baseline moves present-different 50027 -> 45688
and indeterminate 21034 -> 25703 on the same 920 files; the record adjudicates
every row that moved and closes gap row 41 for those libraries.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review October 21, 2026 01:57
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits October 21, 2026 02:29
…braries' into feat/extension-library-identity
…library identity change

The base branch now records the writer's source digest in the baseline; a
full -update over the merged tree moves only that digest, every count being
the one already recorded.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun merged commit 8d2e3ff into feat/apijson-bridge-opensysml-libraries Oct 21, 2026
27 checks passed
@HuiJun
HuiJun deleted the feat/extension-library-identity branch October 21, 2026 06:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant