Skip to content

feat(export): own the referent Membership of a FeatureReferenceExpression where the notation places it - #1331

Merged
HuiJun merged 22 commits into
developfrom
feat/feature-reference-membership
Oct 22, 2026
Merged

HuiJun merged 22 commits into
developfrom
feat/feature-reference-membership

Conversation

@devin-ai-integration

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

Copy link
Copy Markdown
Contributor

What and why

A FeatureReferenceExpression owns a Membership whose memberElement is the referenced Feature, and referent is derived from it. The writer collapsed the reference to the referent edge and a later pass (materializeReferentMemberships) restated it as a Membership appended after the result parameter and absent from ownedMembership, so ownedRelationship and ownedMembership differed from the pilot on every feature reference expression (api-json differential gap row 43). A FeatureChainExpression's target feature had the same shape.

Now the writer owns the Membership itself, where the notation places it:

  • FeatureReferenceExpression: [Membership(referent), ReturnParameterMembership] (featureReferent in rdf_expr.go), with the same ids the restating pass minted (<node>_preferent under an expression node, <element>_referent beside an expression element, claimed against declared ids);
  • FeatureChainExpression naming a plain member: [ParameterMembership(operand), Membership(targetFeature), ReturnParameterMembership]; a chained member keeps its OwningMembership of the owned chain feature;
  • the Membership an expression owns to the element it names (MetadataAccessExpression's referenced element, an invocation's callee) is listed under ownedMembership as well as ownedRelationship (Namespace::ownedMembership = ownedRelationship->selectByKind(Membership)).

The restating pass is removed; materializeNormative keeps its other work.

Targets develop. The branch was cut on #1328's branch and lands after #1332 in the bridge follow-up order, so #1328's head (97f8c58, which merges develop with #1325) and #1332's head (63cb7b2) are merged in as merge commits, and the baseline and report are re-recorded from the combined tree rather than resolved by picking a side. origin/develop (5db0f74) is merged in as well, with the baseline re-recorded from the merged tree (no scorecard row moved; the writer digest and spec-examples' type-mismatch count moved with develop).

Specification basis

KerML 1.1 Beta 2:

  • § 8.2.5.8.3 Base Expressions: FeatureReferenceExpression : ownedRelationship += FeatureReferenceMember, FeatureReferenceMember : Membership = memberElement = FeatureReference; FeatureChainExpression … '.' ownedRelationship += FeatureChainMember, FeatureChainMember : Membership = FeatureReferenceMember | OwnedFeatureChainMember.
  • § 8.3.4.8.5 deriveFeatureReferenceExpressionReferent: the referent is the memberElement of the first ownedMembership that is not a ParameterMembership; § 8.3.4.8.4 deriveFeatureChainExpressionTargetFeature likewise for the target feature.
  • § 8.4.4.8 Expression semantics: "A FeatureReferenceExpression is parsed with a non-owning Membership relationship to its referent Feature (see 8.2.5.8.3)".

The owned Membership is the abstract-syntax mapping of the notation, not a pilot habit; the pilot agrees. Moves the referent/targetFeature row of docs/project/spec-compliance.md to its new locus (still ✅).

In-flight overlap

Counter movements (api-json referee, fresh XDG_CACHE_HOME)

Against #1332's baseline (the state this PR lands on): present-equal 619268 → 624752 (+5484), present-different 45688 → 40210 (−5478), ours-missing 1058259 → 1058253 (−6); matched 90023, ours-only, pilot-only, pilot-missing, absent-both and indeterminate unchanged; provenance differs in the api-json-writer source digest and the date only. A fresh-cache -check on the combined tree reproduces the recorded baseline.

Before this PR was combined, the same deltas were measured against #1328's baseline (-check on #1328's then head 3d8d957 in a separate worktree reproduced it exactly): 618674 → 624158, 50027 → 44549, 1058325 → 1058319.

row before (equal / different / ours-missing) after reading
FeatureReferenceExpression.ownedRelationship, .ownedMembership 38 / 2110 / 0 2141 / 7 / 0 the referent Membership now sits before the result and under ownedMembership; the 7 left are a function named as an argument (->reduce '+' in Simple Tests/Expressions.kerml), which the pilot owns as a FeatureMembership of an Expression typed by the function (§ 8.2.5.8.3 FunctionReferenceMember) where ours writes a Membership of the function — a different mapping, recorded in gap row 43
FeatureChainExpression.ownedRelationship, .ownedMembership 0 / 504 / 0 415 / 89 / 0 the target-feature Membership now sits between operand and result; the 89 left are chains the pilot owns as a FeatureChain through an OwningMembership where ours resolves the member to a Membership of the named feature (Control Structures Example.sysml)
InvocationExpression.ownedMembership 0 / 468 / 0 439 / 29 / 0 the callee Membership is an ownedMembership; the 29 left are receiver-first invocations (s.f(x)), where the pilot orders [ParameterMembership, Membership, …] and ours the callee first — the same 29 the ownedRelationship row already carried
ConstructorExpression.ownedMembership 0 / 57 / 0 3 / 54 / 0 the same; the 54 left own a ParameterMembership per argument where the pilot owns none (ActionTest.sysml) — the ownedRelationship row's existing 54
MetadataAccessExpression.ownedMembership 0 / 0 / 6 6 / 0 / 0 the referenced-element Membership is an ownedMembership

Per root, present-equal rises and present-different falls by the same amount (training +563, sysml-examples +1897, sysml-validation +665, kerml-examples +182, spec-examples +145/−144 with one ours-missing closed, tests/testdata +17, examples +1403 with five ours-missing closed, probes +2, manual-examples +610). No other scorecard row moved.

How it was verified

  • tests/export goldens: 33 files move. By category: every FeatureReferenceExpression node gains ownedMembership of its referent Membership and lists it before _pout_om (88 nodes), the 11 expression-element feature references (constraint { x }) keep their <element>_referent id and lose the trailing position, FeatureChainExpression/MetadataAccessExpression/invocation nodes list their Membership under ownedMembership (19 nodes reordered); no triple other than ownedRelationship/ownedMembership lists and the moved Membership nodes changes. On the combined tree tests/export and tests/identity pass without further golden movement.
  • tests/export/result_expression_test.go TestExpressionBodyParameterIsDeclaredOutsideTheBody pins the new shape; TestReferentMembershipIDCollisionIsRefused pins the id claim at its new locus.
  • TestCorpusRoundTrip, TestCorpusAPIJSONRoundTrip, TestSameTriples, TestRefusalClass with OPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 OPENSYSML_REQUIRE_SPEC_EXAMPLES=1: pass on the combined tree, no ratchet movement.
  • go run -C tools ./cmd/pilot-apijson-diff -update from the combined tree with a fresh XDG_CACHE_HOME, then -check with another fresh cache: reproduces; make docs-counts current.
  • On the combined tree: go build ./..., go vet ./..., gofmt -l . (empty), go test ./... (119 packages ok), go test -C tools ./..., make lint, python3 scripts/changelog.py check: pass.

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/08dcd1a81c9f4d8881aa21febe894183
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/08dcd1a81c9f4d8881aa21febe894183?variant=devin
Requested by: @HuiJun

devin-ai-integration Bot and others added 5 commits October 20, 2026 21:16
…' into feat/apijson-bridge-opensysml-libraries
…e as explicit extension libraries

The bridge takes --extension-library <dir> (repeatable; .kerml then .sysml,
read as library resources after the pinned standard library, as the two
validator bridges do). The api-json referee passes the directory the pilot
differential already hands its validators (diff.LibrariesHandedOver) and
records it in the baseline as the opensysml-libraries input.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
… Libraries loaded

2983 elements move from unmatched to matched and none is lost: the 357
library-named members of docs/manual/examples and 2626 in examples, 1712 of
them in the two files the pilot could not export while MOSA and OOSEM were
unloaded. The newly resolved comparisons differ in three shapes the scorecard
already carried (a library target spelled as a name, the order of a usage's
Redefinition and FeatureValue, the referent Membership of a
FeatureReferenceExpression), recorded as launch-ready gap rows 41-43.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…sion where the notation places it

A FeatureReferenceExpression owns a Membership whose memberElement is the
referenced Feature (KerML 8.2.5.8.3 FeatureReferenceMember); referent is
derived from it (8.3.4.8.5 deriveFeatureReferenceExpressionReferent). The
writer now emits that Membership before the result parameter and lists it
under ownedMembership too, instead of restating referent after the fact at
the end of ownedRelationship. A Membership an expression owns to the element
it names (metadata access, invocation callee) is an ownedMembership as well.

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

devin-ai-integration Bot and others added 8 commits October 21, 2026 00:29
…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>
…p where the notation places it

A FeatureChainExpression names its target through a Membership it owns
(KerML 8.2.5.8.3 FeatureChainMember), from which targetFeature is derived
(8.3.4.8.4 deriveFeatureChainExpressionTargetFeature). The writer now emits
that Membership between the operand and the result parameter and lists it
under ownedMembership, which retires the pass that restated referent and
targetFeature Memberships at the end of ownedRelationship.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ridge-opensysml-libraries

The api-json provenance now carries both the writer's source digest and the
opensysml-libraries input.
…-provenance tree

Same counts, scorecard and matches as before the merge (0 lost, 0 gained
against the previous run); the provenance now names the writer digest and
the opensysml-libraries input together.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ridge-opensysml-libraries

Brings the referee's -trimpath refusal and develop with #1323 merged; the
api-json provenance keeps the writer digest and the opensysml-libraries input.
…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>
…erent Memberships

FeatureReferenceExpression ownedRelationship/ownedMembership move from
38 equal / 2110 different to 2141 / 7, FeatureChainExpression from 0 / 504
to 415 / 89, InvocationExpression ownedMembership from 0 / 468 to 439 / 29,
MetadataAccessExpression ownedMembership from 6 ours-missing to 6 equal;
gap row 43 records what the 7 remaining elements are.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…sml-libraries

The referee is handed its build checkout for the writer digest; the
provenance keeps the opensysml-libraries input beside it.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration devin-ai-integration Bot added the ci:full Run the full CI tier on this pull request, draft or not label Oct 21, 2026
devin-ai-integration Bot and others added 3 commits October 21, 2026 02:10
…sml-libraries

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…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>

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Newer findings are available below. Devin Review posted a newer report on this PR, in addition to the findings presented here.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

devin-ai-integration Bot and others added 4 commits October 21, 2026 04:45
…mbership

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

# Conflicts:
#	docs/project/api-json-differential-baseline.json
#	docs/project/api-json-differential.md
…ed with the extension-library identity change

Re-run from the merged tree rather than taking a side: against the baseline
the identity change recorded, only the owned-Membership rows move
(FeatureReferenceExpression 38/2110 -> 2141/7, FeatureChainExpression
0/504 -> 415/89, InvocationExpression ownedMembership 0/468 -> 439/29,
ConstructorExpression ownedMembership 0/57 -> 3/54, MetadataAccessExpression
ownedMembership 6 ours-missing -> 6 equal) and the writer digest.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ence-membership

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

# Conflicts:
#	docs/project/api-json-differential-baseline.json
No scorecard row moves; the writer digest, one spec-examples type
mismatch and three extension properties move with develop.

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

This comment was marked as resolved.

@devin-ai-integration
devin-ai-integration Bot changed the base branch from feat/apijson-bridge-opensysml-libraries to develop October 21, 2026 23:55
@HuiJun
HuiJun merged commit 0a1c8a2 into develop Oct 22, 2026
31 checks passed
@HuiJun
HuiJun deleted the feat/feature-reference-membership branch October 22, 2026 00:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:full Run the full CI tier on this pull request, draft or not

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant