Skip to content

feat(runtime): apply nested redefinition chains below composite features - #634

Merged
HuiJun merged 30 commits into
developfrom
feature/nested-redefinition
Sep 28, 2026
Merged

HuiJun merged 30 commits into
developfrom
feature/nested-redefinition

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

What and why

A chain redefinition written on a usage — part top : Top { attribute :>> mid.leaf.value = 99.0; } — is legal SysML v2 and resolves cleanly, but neither the pinned pilot nor OpenSysML gave it any effect: top.mid.leaf.value still read the definition default. Modelers were writing the shorthand and silently getting nothing. Only the nested-body form part :>> mid { part :>> leaf { attribute :>> value = 99.0; } } worked.

This makes the shorthand behave exactly like the nested-body form:

  • semantics.NestedRedefinitionsOf(sym) (side table) lists the members of sym whose :>> target is a ≥2-segment feature chain that resolves.
  • Runtime: when materialize(sym, id, owner, feature) creates a nested object, it collects the chains of owner's types (and their member sources) whose first segment is feature (or any alias sharing its *FeatureValue), plus tails carried on owner. A one-segment tail replaces that feature's EffectiveFeature on a cloned shape with effectiveFeature(name, redefiningMember, sym) — so value (=/default =), declared type, multiplicity and a redefining body all take effect and CompositeTypeOf picks them up unchanged; longer tails are stored on Instance.nested and applied when the next level materializes. materializeMembers goes through the same path, so a multi-valued intermediate (:>> wheels.radius) applies per element.
  • Precedence is exactly the nested-body form's. Each chain is attributed to the type or usage whose body declares it (redefinitionContext: the enclosing definition, or the topmost usage). Between chains, a chain whose context specializes another's wins (so a classifier Sport :> Base added later beats Base's chain, for children materialized before or after the classification); carried tails and unrelated contexts keep first-wins. Against a standard redefinition already standing on the feature, the chain yields only when that redefinition's context conforms to the chain's — the same body, or a subtype's nested body (blocksChain); the child's type's own :>> and bodies in types the chain owner specializes lose, as they do to part :>> wheel { :>> radius = 3.0 }.
  • Classification (classify) applies the new classifier's chains to already-materialized descendants transactionally (installFeatureValue) and leaves them pending for lazy ones; it only walks objects the parent owns, so a populated ref/port/subject never has its target mutated. Held images (Image/Restore) round-trip Instance.nested.
  • Chains below a feature bound to an existing object follow the nested-body rules: a valued chain written in the same body as the binding (part :>> mid = existing; attribute :>> mid.leaf.value = 99.0;) is rejected with the existing ErrValuedFeatureRestated; a valued chain from a body that specializes the binding's (Top { part mid : Mid = existing; }, Sport :> Top { attribute :>> mid.leaf.value = 99.0; }) governs the inherited binding — EffectiveFeature.GovernedByChain makes valueBinds false, so a fresh object is materialized (also on classify) and the bound object is never touched; a chain declaring only a type or multiplicity conflicts with nothing.
  • Expressions are evaluated in the declaring body's scope (DefaultDecl = the redefining member), so :>> mid.leaf.value = factor * 2.0 reads factor from Top, as the nested-body form does.
  • New NestedRedefinitionPass reports an error, redefinition-through-reference, when a non-final segment is a ref/port/subject — there is no owned object to redefine below it, so the chain would silently not apply. A plain chain gets no diagnostic.
  • The = vs default = fixed-binding rule is unchanged and still applies to the chain's last feature.

Specification basis

A feature chain in a redefinition target parses to a feature that hosts the chain; the chain determines the host's featuring type (first segment) and featured type (last segment), and the host is redefinable — KerML 1.0 §7.3.4 (feature chains) and §8.3.3.3 (redefinition), as confirmed with the spec lead. Applying the redefinition below the chain is therefore the specification's reading, recorded as ✅ Faithful in docs/project/spec-compliance.md (redefinition section) and described under "Chain redefinitions" in docs/reference/grammar/conformance-audit.md. The pinned pilot evaluator (0.62.0) accepts the notation but reads the original value; that is noted as a pilot-evaluator gap in docs/project/pilot-differential.md. No corpus ratchet or differential baseline moves.

How it was verified

  • Conformance fixtures nested_redefinition_chain (3- and 2-level chains, chain with a body, outer-scope value, collection intermediate), nested_redefinition_chain_equiv (shorthand and nested-body forms read identically) and nested_redefinition_precedence (subtype over base, carried over intermediate).
  • TestRuntimeRobustnessNestedRedefinition: chain through a ref evaluates to the default without panic; unresolvable chain returns ErrNoSuchFeature; chain below a value-bound feature returns ErrValuedFeatureRestated and leaves the bound object untouched.
  • Unit tests for NestedRedefinitionsOf (1-level excluded, 2/3-level included, unresolved excluded), the pass (ref error; silent on plain chains and the standard forms, in default and strict mode), aliased names in both read orders, held-image round-trip of pending tails, and classify: chains reach materialized and lazy children, a later classifier's chain outranks the base type's (both read orders), the chain outranks the child's type's own redefinition while a subtype's nested body keeps its value, and a chain through a ref leaves the referenced object alone.
  • By hand with bin/sysml REPL (recording in the session): shorthand and nested-body forms both → 99.0 / 4.0, outer-scope expression → 14.0, collection → [0.4, 0.4], 4-level chain, inherited chains, fixed-binding protection, ref/port/subject errors.
  • gofmt -l ., go vet ./..., make lint, make docs-check, go test ./... all clean.

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

A chain redefinition written as a member of a type or usage
(attribute :>> mid.leaf.value = 99.0;) now applies below every composite
feature the chain walks, exactly as the nested-body form does: declared
values (= and default =), types, multiplicities and redefining bodies,
evaluated in the declaring body's scope, per element of a multi-valued
intermediate. A redefinition the object's own type declares wins over a
chain reaching the same feature, and a chain crossing a ref, port or
subject owns nothing below it and is never applied.

Each chain is reported as a nonstandard-semantics warning (an error in
strict mode, and in every mode when the chain crosses a reference):
the pinned pilot accepts the notation but applies no redefinition below
the first segment.

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 2 commits September 27, 2026 04:15
…definition change

The self-model edit moved the examples/ input digest, and the new
nonstandard-semantics warnings account for every added openSysMLOnly
finding; no other movement.

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

Re-recording the baseline moved the headline counts (344 fully
agreeing, 46 only ours); regenerate the gated doc-count lines and
update the quoted figures and the adjudication record to match.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 27, 2026 05:49
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 2 commits September 27, 2026 05:58
Order the chains reaching one feature most-specific first — the tails
carried down, then each type before its member sources — and let the
first win rather than the last. Carry an object's pending tails through
a held image so a member materialized after the restore is redefined
all the same. When a classifier is added to an object, apply its nested
redefinitions to the children already materialized, refining their
feature values as the classifier's direct features do.

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

This comment was marked as resolved.

…d's own redefinition

A redefined member shares one feature value under every name it reads
as, so a chain's first segment matches any name of the value being
materialized, not only the name read. And a child's own redefinition
wins over a chain a classifier applies to it, the same precedence the
materialize path gives it.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration devin-ai-integration Bot mentioned this pull request Sep 27, 2026
6 tasks
… extension

The feature chain in a redefinition target parses to a feature hosting
the chain, and the host is redefinable (KerML 1.0 §7.3.4, §8.3.3.3):
applying it below the chain's segments is the specification's reading,
which the pinned pilot evaluator simply does not implement. Drop the
nonstandard-semantics advisory and its strict escalation, name the
through-reference error redefinition-through-reference, and restore the
corpora ratchet, differential baseline and quoted figures the advisory
had moved.

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

This comment was marked as resolved.

… and stay within owned objects

A chain counts as a redefinition written in the body declaring it, so
it ranks exactly as the nested-body form does: a redefinition declared
by the chain's context or a type specializing it wins, and the child's
own type's redefinition, a base type's chain and unrelated bodies lose.
The classify path decides by the same rule before installing the
feature, and it refines only objects the owner holds — a reference,
port or subject's is not the owner's to redefine.

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

This comment was marked as resolved.

…ing object

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

This comment was marked as resolved.

…as a body does

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

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

…ank its value among aliases

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

This comment was marked as resolved.

…ning feature

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

This comment was marked as resolved.

…baseline

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

This comment was marked as resolved.

devin-ai-integration Bot and others added 4 commits September 27, 2026 22:02
…ery alias of a bound part

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

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

# Conflicts:
#	internal/exec/runtime/classify_test.go
#	internal/semantic/semantics/model.go
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

…ge governed features

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

This comment was marked as resolved.

devin-ai-integration Bot and others added 3 commits September 28, 2026 00:20
…r chains

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

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

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

# Conflicts:
#	docs/project/pilot-differential-baseline.json
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 5 commits September 28, 2026 03:27
…feature

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…he develop merge

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

This comment was marked as resolved.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun merged commit ac84d48 into develop Sep 28, 2026
19 checks passed
@HuiJun
HuiJun deleted the feature/nested-redefinition branch September 28, 2026 14:36
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