Skip to content

fix(view): route specialization edges from Cameo and keep the keyword line in a stated box - #1166

Merged
HuiJun merged 9 commits into
developfrom
fix/generalization-routes-keyword-fit
Oct 16, 2026
Merged

HuiJun merged 9 commits into
developfrom
fix/generalization-routes-keyword-fit

Conversation

@devin-ai-integration

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

Copy link
Copy Markdown
Contributor

What and why

A migrated Cameo block definition diagram drew its inheritance lines and its boxes wrongly in two ways; the migrated model text keeps its meaning.

Generalization routes were dropped. A v1 Generalization becomes a :> clause on the subtype, which declares no member a metadata DiagramLayout::Route about X could name, so the migrator reported routes of Generalization: N no v2 member and the positioned tree auto-routed the hollow-triangle edge. The route is now written about the specific definition, naming the general the line is drawn to:

metadata DiagramLayout::Route about Engine { points = (170, 160, 170, 80); ref :>> general : Component; }

The semantic model reads general into LayoutSite.General and resolves a Route per general (Model.SpecializationRouteOf); RouteOf passes such sites over, so a connection def Sub :> Base keeps its own Route for its own line. The positioned tree gives each specialization, typing and subsetting edge the Route naming its target: a subtype with two generals follows one Route per general, the same subtype drawn in two views follows each view's own, and an unpositioned tree is unchanged. The layout check keys duplicate Routes by general and reports a Route naming a general the view draws no edge to. The migration report counts these routes as written.

Options for carrying the route, ranked by spec compliance (each probed with the pinned pilot validate-sysml-batch and sysml -validate):

  1. Chosen: a Route about the specific element, typing a general reference (ref :>> general : Sup;). Valid SysML v2 textual notation (the ref :>> x : T; idiom MigrationMetadata::DeferredEvent already uses), 0 pilot errors, unambiguous for several generals and for several views. Needs the extension-library change below.
  2. A Route about the subtype naming nothing: valid text, but a subtype with two generals cannot be routed (the second Route is a duplicate) and it contradicts the documented rule that a Route steers the declaring element of an edge.
  3. A standalone KerML specialization G subclassifier A :> B; member: KerML-only. The pilot rejects it in a .sysml file (no viable alternative at input 'G') and so does OpenSysML (expected a namespace member).

Extension-library change, Open-MBEE/OpenSysML-Extensions-Library#7 (merged): DiagramLayout::Route gains ref general : Base::Anything[0..1];; EXTENSIONS_COMMIT is pinned at its merge commit, the vendored copy and engine-contract.json synced with scripts/sync-extension-libraries.sh, stdlib.snapshot regenerated and the pilot-differential baseline re-recorded for the library digest alone.

The keyword line was dropped from Cameo-sized boxes when the name wrapped. dotFittedLabel fitted the head first and wrote the keyword line only while height remained, so in a 33px box Instrument kept its «part def» line and Display System, wrapping to two lines, lost it. The head and keyword are now fitted together, shrunk in proportion from the node's size to the floor (whole words before broken ones), and the keyword is dropped only when no size holds both; detail lines and compartments are fitted after them with their clipping unchanged. The order is documented on dotFittedLabel. Mermaid, PlantUML and D2 have no stated-box fitting of their own, so nothing there changes.

Before and after, the tree-generalization.sysml fixture rendered in the Cameo style:

before
after

Measured on a Cameo model with two block definition diagrams of the detector hierarchy, re-migrated on this head with the library change applied: the model text differs from a develop build by exactly the four Generalization Route lines (two subtypes × two BDDs, each ref :>> general : Detector); the report moves from routes of Generalization: 4 no v2 member to 4 written, routes 284 → 288 of 316, placements 410 unchanged; -validate clean, pilot 0 errors; the rendered BDD draws both inherits on Cameo's waypoints and keywords all 19 boxes (6 of 19 before).

Specification basis

SysML v2 textual notation admits a metadata usage body feature redefined with a typing, ref :>> general : Sup; (the same form MigrationMetadata::DeferredEvent uses for signal), and admits no standalone specialization member: KerML's specialization/subclassifier declarations are KerML-only, as internal/syntax/parser/f86_relationship_member.go documents and both validators confirm. No row of docs/project/spec-compliance.md moves; docs/project/diagram-layout-annotations.md and docs/reference/sysml-v1-migration.md describe the new Route form.

How it was verified

  • New fixture internal/ir/view/testdata/tree-generalization.sysml: Detector, Sensor and two subtypes (one with two generals) in 33px boxes with Cameo-like Routes, a second view drawing one subtype with another Route, and an unpositioned copy. TestGoldenTreeGeneralization (dot, cameo dot, mermaid, plantuml, d2, text, plus the second and unpositioned views) and TestTreeSpecializationRoutes (each edge's waypoints per view; nothing routed unpositioned). Pilot validate-sysml-batch: 0 errors on the fixture and on the migrated golden.
  • TestDOTFitsTheLabelToAStatedBox now encodes the joint fit (shrunk keyword kept beside a wrapped name, dropped only below the floor, absent when ElementKeywords is off) and TestDOTHeadsAnEnclosingBoxAboveItsMembers the keyword line on an enclosing box's title.
  • Goldens moved, by fixture:
    • tests/migrate/testdata/xmi/diagram_edges.layout.golden.sysml and .golden.report.txt: the one Generalization connector of the BDD is now written as a Route about Engine naming Component; routes of Generalization: 1 no v2 member → 1 written, routes 12 of 24 → 13 of 24, its points running from Engine to Component as every migrated line now runs from its first end to its second; layout_test.go counts follow.
    • No existing internal/ir/view golden moved: no fixture there has a stated box too short for its keyword line.
  • gofmt -l . empty, go build ./..., go vet ./...; go test -count=1 ./internal/ir/view/... ./internal/translate/migrate/... ./tests/migrate/... and ./internal/check/... ./internal/semantic/semantics/ pass. go run -C tools ./cmd/transformation-census -check: census document and baseline agree. python3 scripts/check-doc-ids.py and python3 scripts/changelog.py check clean.
  • go test ./... with the training corpus and pilot corpora fetched: the one failure left is TestExecutionConformance/verification_chain_package_usage_value*, which fails identically on develop.

Checklist

  • make test and make lint pass locally (see above for the one develop failure)
  • 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/850d56a6ed3e4b39b7a1dc2b4b9ec6d8
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/850d56a6ed3e4b39b7a1dc2b4b9ec6d8?variant=devin
Requested by: @HuiJun

devin-ai-integration Bot and others added 3 commits October 14, 2026 23:23
The DOT writer fitted the head first and wrote the keyword line only while
height remained, so a Cameo-sized box whose two-word name wrapped lost its
«part def» line. The head and keyword are now fitted together, shrunk in
proportion from the node's size down to the floor, and the keyword is
dropped only when no size holds both; detail lines and compartments are
fitted after them as before. The fit order is documented on dotFittedLabel.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A specialization declares no element an `about` could name, so a Route
about the specific element types DiagramLayout::Route::general with the
element the line is drawn to (`ref :>> general : Sup;`). The semantic model
reads it into LayoutSite.General and resolves it per general with
SpecializationRouteOf, RouteOf passing such sites over; the positioned tree
gives each specialization, typing and subsetting edge the Route naming its
target, so a subtype with two generals and the same subtype in two views
each follow their own waypoints while an unpositioned tree is unchanged.
The layout check keys duplicates by general and reports a Route naming a
general the view draws no edge to.

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

A v1 Generalization becomes a `:>` clause with no member of its own, so its
route was reported as "no v2 member" and the rendered inheritance line was
auto-routed. The migrator now writes it as a DiagramLayout::Route about the
specific definition naming the general the clause is drawn to, when a block
definition diagram shows both ends and the `:>` was written, one per
general; the report counts it as written.

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]

This comment was marked as resolved.

devin-ai-integration Bot and others added 3 commits October 14, 2026 23:59
…nt's route

A setRoute edit rewrote the first Route stated about the element, which
could be the one steering its specialization edge; the edit now passes
such Routes over and writes the element's own.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
DiagramLayout::Route gains `ref general : Base::Anything[0..1]`, the
element a Route about a specific element steers its specialization edge
to; the engine contract lists it, the library snapshot is regenerated and
the pilot-differential baseline re-recorded for the library digest alone.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun marked this pull request as ready for review October 15, 2026 02:06
…-routes-keyword-fit

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

# Conflicts:
#	docs/project/pilot-differential-baseline.json
…-routes-keyword-fit

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

# Conflicts:
#	tests/migrate/testdata/xmi/diagram_edges.layout.golden.report.txt
…-routes-keyword-fit

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

# Conflicts:
#	internal/translate/migrate/diagrams.go
@HuiJun
HuiJun merged commit 325735f into develop Oct 16, 2026
27 checks passed
@HuiJun
HuiJun deleted the fix/generalization-routes-keyword-fit branch October 16, 2026 13:09
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