Skip to content

feat(migrate): lower Cameo tables, matrices, relation maps and DocGen documents to DocumentQueries - #533

Merged
HuiJun merged 48 commits into
developfrom
feature/migrate-tables-and-documents
Sep 23, 2026
Merged

HuiJun merged 48 commits into
developfrom
feature/migrate-tables-and-documents

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

What and why

Cameo tables, matrices and relation maps are uml:Diagrams, so the migrator turned each into a view exposing whatever happened to be displayed and kept the table's definition — scope, row types, columns, sort, dependency criteria — only as a tool-profile comment. MDK DocGen documents (Document_Profile and Document_View_Collaborator_Profile applications) became comments plus stub action defs, so the documents were inert. Those definitions are semantic and have an exact target in this project's DocumentQueries vocabulary; this PR reads them in the XMI layer and lowers them to executable queries and renderable documents, so a migrated model answers -run-query and renders through -render-document.

Tables, matrices, relation maps (recognised only by the exact profile URIs MagicDrawProfile, Dependency_Matrix_Profile.xmi, and by the MagicDraw module snapshots bundled in the archive; a user stereotype merely named InstanceTable or TableStructure elsewhere stays ordinary metadata). Each definition on a diagram is written beside the diagram's view, in the diagram's owning namespace:

calc def 'Pump Table Rows' :> DocumentQueries::Query {
    DocumentQueries::Project(
        source = DocumentQueries::OrderBy(
            source = DocumentQueries::WhereFeature(
                source = DocumentQueries::WhereType(
                    source = DocumentQueries::Union(
                        source = DocumentQueries::Descendants(
                            source = DocumentQueries::Named(qualifiedName = ("Plant::Inventory"))),
                        other = DocumentQueries::Named(qualifiedName = ("Plant::Spares::s1", "Plant::Spares::s2"))),
                    type = ("Plant::Structure::Pump")),
                'feature' = "isIndividual", operator = "=", value = "true"),
            property = "mass", direction = "descending", missing = "last", multiple = "first"),
        properties = ("name"),
        columns = (DocumentQueries::Column(name = "mass", expression = Plant::Structure::Pump::mass ?? "")))
}
part def 'Pump Table Document' :> DocumentQueries::Document {
    attribute redefines title = "Pump Table";
    part rows : DocumentQueries::Table {
        attribute redefines caption = "Pump Table";
        calc rows : 'Pump Table Rows';
    }
}
  • «InstanceTable» / «DiagramTable»: scope → Descendants(Named(roots)) (a whole-model scope lists the migrated top-level roots); explicit rows → one Union(source = …, other = Named(qualifiedName = (row1, row2, …))); row type → WhereType (+ WhereFeature(isIndividual) for instance tables) or WhereMetadata for a user stereotype the migrator writes as a metadata def; columns → Project(properties) and Column(expression = T::p ?? ""); sort → OrderBy(missing = "last", multiple = "first").
  • «DependencyMatrix» + «MatrixFilter»: rows as above, one RelatedColumn(relationshipKind, direction, maxDepth = 1, aggregate = "list", targets = <column query>) per criterion; "With relations" → WhereRelated; Both → two related columns, approximated and reported; same-named criteria are made unique (Trace, Trace 2).
  • «RelationMap»: RelatedElements(source = Named(context), relationshipKind, direction, maxDepth = depth) per criterion, unioned and type-filtered.
  • Properties a generated Column reads are kept reachable (not written private), the same way a view's exposed features are.
  • Presentation-only attributes are dropped silently. A criterion no relationship kind spells, a column on a derived or tool property, QPROPs beyond name/documentation/qualifiedName/owner/id, sort by tool id, malformed dependencyCriteria XML, a non-integer depth, an unparsable sort, a dangling scope, and a table naming no row type are refused with an Unmapped report row quoting the construct and every fault; the view is still written.

DocGen documents (exact URIs Document_Profile.xmi, Document_View_Collaborator_Profile.xmi). A «Document» class becomes part def '<Name> Document' :> DocumentQueries::Document; its view tree becomes nested Sections in declaration order; each view's «Conform»ed method activity is walked from its initial node along control flow, with the «Expose» suppliers as the root:

  • CollectOwnedElementsDescendants, CollectOwnersAncestors, CollectByDirectedRelationshipStereotypesRelatedElements, FilterByMetaclassesWhereType, FilterByStereotypesWhereType/WhereMetadata, FilterByNamesWhereName(matches), include = falseExcept, SortByName/SortByAttributeOrderBy, Union/Intersection/XOR forks, CollectionAndFilterGroup and StructuredQuery inlined; depth = 0 → unbounded.
  • TableStructureTable, BulletedListList, Paragraph/collaborator paragraphs → Paragraph (literal text, or calc values : <query> when the paragraph reads its targets' documentation), Image → view-backed Diagram, Dynamic View → nested Section. A table's or image's caption attribute is its DocGen title (titles between titlePrefix/titleSuffix, the diagram's name by default); its captions text follows as a Paragraph only while showCaptions holds.
  • A Diagram block's source must be an accessible feature: a view held by a definition is reached through a ref <anchor> : <Def>; the Document declares, and a view nested under another view through the usage chain from its package (ref redefines source = truck.'Truck Internals';).
  • Generated member names never collide with the members inherited from DocumentQueries (title, rows, items, values, source, …), and references written inside a generated block are qualified past any synthesized member that would shadow them.
  • Refused with the construct quoted, the surrounding sections still written: CollectTypes, CollectByAssociation, OCL/expression steps beyond a bare feature read, user scripts, Parallel joined by anything but a set operation, a recursive dynamic view, a viewpoint naming no method, a collaborator paragraph naming no view, an Image of a diagram rendered as textual notation, a view under a namespace no feature chain reaches.

Library extensions to DocumentQueries (spelling gaps only): maxDepth on Descendants/Ancestors/RelatedElements/WhereRelated/RelatedColumn may be omitted or null for no bound (before, maxDepth <= 0 silently returned nothing); RelatedColumn.targets : Element[0..*] ordered keeps only related elements a second query lists (a matrix cell); the built-in query property isIndividual; and Named(qualifiedName : String[1..*]) resolving elements by qualified name so a package or definition can be a query root (packages and definitions are not valid feature values). In the executor, a declared satisfy/verify assertion typed by a requirement definition now relates its subject to that definition as well as to the anonymous assertion usage — otherwise every migrated matrix over requirement definitions (satisfy requirement : R; is how a v1 «Satisfy» migrates) had empty cells.

«typeModifier»: [] on a property or parameter with no collection multiplicity → [0..*] ordered nonunique, [n][n] ordered nonunique, */& on a part or item property → ref; two-dimensional shapes, [] on an existing collection and */& on an attribute or parameter stay comments with the reason reported.

Existing diagram behaviour is unchanged: the view with its expose set, render, and the MTIP DiagramLayout::Canvas/Layout/Route annotations are written as before; the Table Document is a sibling.

Specification basis

Non-normative: the target vocabulary is this project's DocumentQueries library (docs/manual/query-cookbook.md); the source semantics are Cameo's MagicDraw and Dependency Matrix profiles and the Open-MBEE MDK DocGen profile (CollectFilterParser, Utils in the public mdk repository: depth = 0 is unbounded, CollectOwnedElements excludes the source, FilterByNames is a full-match regex, every step deduplicates). No row of docs/project/spec-compliance.md moves.

How it was verified

  • gofmt -l . empty; go build ./...; go vet ./...; staticcheck clean; go test -count=1 ./... green with OPENSYSML_REQUIRE_PILOT_CORPORA, OPENSYSML_REQUIRE_TRAINING_CORPUS, OPENSYSML_REQUIRE_PILOT_LIBRARY_XMI and OPENSYSML_REQUIRE_PSSM_SUITE set (training corpus assertion, pilot corpora, PSSM migration and RDF round-trip ratchets unmoved). python3 scripts/changelog.py check and scripts/check-doc-ids.py pass.
  • New fixtures under tests/migrate/testdata/xmi/ with validated goldens (notation + report): tables (instance table with explicit rows and sorts, generic table, whole-model scope, metadata-filtered rows, dependency matrix with duplicate criteria and Both, relation map), documents (DocGen sections, literal and query-backed paragraphs, lists, tables, image diagrams including a view held by a part definition and a view nested in a view, hidden captions (showCaptions="false"), refusals, malformed collaborator, recursive dynamic view), table_homonyms (user InstanceTable/TableStructure stereotypes on non-profile URIs stay metadata; malformed table serialization refused with the exact faults), type_modifiers, and a table diagram with a HUDS layout record pinning Canvas/Layout and the Table Document on one view. TestMigratedNotationAnalysesClean validates every golden with no errors.
  • Executable and renderable: TestMigratedTablesExecute, TestMigratedTablesRender, TestMigratedDocumentsRender and TestTableHomonymsAndMalformedTables (tests/migrate/documents_test.go) run every generated Rows query through the real executor with row assertions, and render the migrated Documents through the real Markdown and HTML backends (headings, captions, cells, list items, five Mermaid diagrams in order, hidden captions absent). Unit tests for Named, nullable maxDepth, RelatedColumn.targets, isIndividual, the requirement-definition edge, the DocGen planner (cycles, refusals, image paragraphs) and the XMI readers.
  • Leakage audit: rg over internal/, docs/, changes/ for tool-internal identifiers, profile ids and work-item labels in reader-facing text — none.
  • Docs: docs/reference/sysml-v1-migration.md (tables, matrices, relation maps, DocGen, typeModifier, the refused list) and docs/manual/query-cookbook.md (Named, unbounded maxDepth, RelatedColumn.targets, isIndividual, with a checked cookbook example).

Real-model before/after (TMT-2024x.mdzip with -layout TMT_mtip.xml, this branch vs. develop at its merge base):

develop this branch
elements migrated 48,296 (32,360 mapped, 11,350 approximated, 4,586 unmapped) 49,060 (32,857 mapped, 11,458 approximated, 4,745 unmapped)
DocumentQueries::Query definitions / Document definitions 0 / 0 99 / 103 (98 Table, 101 Diagram, 769 Section blocks)
max generated query call depth (histogram) 7 ({2: 2, 3: 7, 4: 19, 5: 48, 6: 20, 7: 3})
layout join 721 records, 721 joined, 0 unmatched; 4,196 of 10,374 placements written (6,020 not exposed, 158 resolving to no element); 9 of 4,792 routes (4,783 not exposed, 0 dangling); 0 malformed; 481 Canvas annotations identical
results sidecar (-migration-results) 62 run configurations measured, 41 of them requested/behaviour-bearing (behavior = run), 30 with 82 stored snapshots standing for 4,158 runs byte-identical (cmp)
migration wall / RSS 14.9 s / 673 MB 15.6 s / 626 MB
-validate on the full output 0 errors, 3,550 warnings, 10.2 s 0 errors, 3,851 warnings, 10.5 s

The 301 additional warnings are all Duplicate of inherited member name for the generated Documents' title/rows/caption/section members, the same warning class develop already reports 2,658 times for the model's own view hierarchy. The new unmapped rows are the refused table criteria and DocGen steps listed above, each with its construct quoted. Explicit table rows are written as one list-valued Union, keeping call depth at 7 across every generated query; validation of nested calc invocations in the checker is unchanged by this PR.

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

devin-ai-integration Bot and others added 8 commits September 22, 2026 06:40
…s' into feature/migrate-tables-and-documents
…al property

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ugh a meta cast

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…applications and lower tables to DocumentQueries

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…s' into feature/migrate-tables-and-documents

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

# Conflicts:
#	internal/translate/xmi/sysmlv1/xmi.go
#	internal/translate/xmi/xmi.go
#	internal/workspace/libs/stdlib.snapshot
@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

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 2 commits September 22, 2026 17:41
…unique

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…s' into feature/migrate-tables-and-documents
Base automatically changed from feature/migrate-diagrams-to-views to develop September 22, 2026 20:39
devin-ai-integration Bot and others added 14 commits September 23, 2026 01:49
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ents' into feature/migrate-tables-and-documents
…adata defs

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Explicit table rows go into one Union whose other is Named over every
row; WhereType and WhereMetadata take several names, so a table with
many row types filters once per kind instead of once per type; the
remaining joins nest as a balanced tree. The deepest generated query
chain drops from 47 calls to 7.

Collaborator paragraphs are placed by the view their ownerId names
within the document their viewId names; paragraphs no view shows are
kept as stray paragraphs.

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

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

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

[] and [n] write the multiplicity [0..*] / [n] ordered nonunique; * and &
make a part or item a reference usage. Two-dimensional shapes, shapes over
a declared collection, pointers on values or parameters and unread forms
stay comments with a report note. Parameters now keep their applied
stereotypes as comments and metadata like properties do.

Adds the generic tables fixture (instance table, generic tables,
dependency matrices, relation map) and the type-modifier fixture with
goldens; table Documents are named '<diagram> Document'.

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

A DocGen «view» class is a view as the SysML «View» is; the DocGen profile's
applications are read by the document mapping, so they are not reported as
undefined-profile comments. Fork branches rejoined by a merge are unioned;
standard SysML relationship hrefs name RelatedElements kinds; a Dynamic View
section carries its name.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A declared satisfy assertion typed by a requirement definition now also
relates its subject to that definition, so matrices and relation maps over
migrated requirement definitions execute to the cells the tool showed.
Query-backed paragraphs bind their query as 'values', leaving the inherited
'text' attribute alone. Tests run every migrated table query with real rows
and render the table and DocGen documents through the Markdown and HTML
backends.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A user stereotype named InstanceTable, TableStructure or Document under
a non-profile URI stays ordinary metadata or a comment; only the exact
tool profile namespaces define tables. Malformed exact-profile tables
are refused naming every fault at once, and an unnamed matrix criterion
is called that rather than "the criterion other criterion".

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A table diagram with an MTIP record keeps Canvas and Layout on its view
usage while the table lowers to a sibling Document the view exposes.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ng, Named, and typeModifier

The migration reference gains sections on how a Cameo table, dependency
matrix, relation map and MDK DocGen document become DocumentQueries
queries and documents, and how MagicDraw's typeModifier is read; the query
cookbook gains a Named recipe pinned by the cookbook model's test; the
changelog fragment records the feature.

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 2 commits September 23, 2026 11:48
…table

A PackageableElement, Namespace, Type or Classifier row type now admits the
migrated kinds those metaclasses cover: a PackageableElement table lists the
packages, definitions, views and dependencies of its scope but not the
features a classifier owns, and the ViewUsage/ViewpointUsage a «View» or
«Viewpoint» class became count as the Type, Classifier and Namespace they
were.

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

A library symbol carries its declaration whether parsed, restored from the
on-disk cache or decoded from the snapshot, so the declaration-borne query
properties answer on each; the api reference no longer says a cached
element lacks one.

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 2 commits September 23, 2026 11:58
An alias whose target resolves to nothing, or that is part of an alias
cycle, denotes no element, so Named reports it as an unknown element
instead of returning the alias symbol itself as a row.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A control flow whose source or target names no node used to vanish from
the flow index, so the chain walker took the break for a clean end and
wrote the document up to it. DocGenChain now refuses the activity and
names the edge and its missing end, so the section carries the refusal
instead of a silently truncated body.

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 2 commits September 23, 2026 12:19
A DocGen method activity may own object flows between the pins of its
actions beside the control flows that order its steps. The chain walker
indexed every edge, so an object flow counted as a second outgoing flow
(refusing the chain as a fork), led traversal into a pin, and a dangling
object flow refused an otherwise well-formed method. Only ControlFlow
edges now take part in traversal and endpoint validation.

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

A view conforming to a viewpoint whose method tag names no element, or
names something other than an Activity, was written as an empty section
with a mapped verdict, indistinguishable from a view that has no method.
The reader now keeps why the method is missing, and the section is
refused with an unmapped report entry naming the viewpoint and the
reference; a view with no viewpoint or no method tag is still written as
structure only.

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

This comment was marked as resolved.

… their order

FilterByNames with several patterns was lowered to one WhereName per pattern
joined by Union, which grouped the rows by the pattern that matched them.
DocGen keeps a matching element in its place, so the patterns now form one
alternation of their whole-string forms and every pattern is still checked
as a regular expression.

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

This comment was marked as resolved.

…h PropertyColumn

Project always wrote the query properties before the computed columns, so a
Cameo or DocGen table interleaving built-in and value-property columns lost
its order, and a DocGen value property captioned like a projected property
produced two columns of one name.

DocumentQueries gains PropertyColumn(name, property): a columns entry that
reads a built-in property as the properties list does (every value, an empty
cell where absent, unknown-property failure), so a mixed table is written as
one ordered columns list. The migrator claims the property names first and
suffixes a colliding caption ("name 2"); a table whose properties all precede
its value properties keeps the plain properties list.

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 5 commits September 23, 2026 13:12
…rdering instead of adding PropertyColumn

A Project lists its properties before its columns, so a table whose built-in
and value-property columns interleave keeps that order approximately, with
the report saying which properties moved ahead. Column names stay unique: the
built-in properties claim theirs first and a value property captioned like one
is written with a numeric suffix. The PropertyColumn library operation is
withdrawn from DocumentQueries, its compiler, executor and docs.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Keeps the table lowering beside the geometry call that now receives the view form; the documents fixture's activity diagram becomes an ActionFlowView as every activity diagram now does.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…bles-and-documents

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

# Conflicts:
#	internal/translate/migrate/diagrams.go
#	internal/translate/migrate/migrate.go
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ents' into feature/migrate-tables-and-documents
devin-ai-integration[bot]

This comment was marked as resolved.

A Table's or Diagram's caption is the title DocGen prints over the block
(titles between titlePrefix and titleSuffix, the diagram's name by
default); the captions entry follows as a Paragraph only while
showCaptions holds, as MDK's Table and Image models set it.

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 2 commits September 23, 2026 14:11
…rts and collects

The diagrams a view exposes or a node targets were kept beside the query untouched, so an Image after FilterByNames, FilterByMetaclasses, FilterByStereotypes, a sort or a fork drew every diagram of the root. Each step now transforms the diagrams as it does the elements: name filters match the diagram's name, type filters keep it for Element, NamedElement, Diagram or its diagram-type stereotype, a sort by name orders it, a Union rejoin unites the branches' diagrams once each, CollectOwners adds the diagrams' owners to the query as Named roots, and the other collects drop them. An Image after a filter that kept none draws nothing and the report names the filter.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
A view exposing the same element through two Expose dependencies rooted the chain in Named(qualifiedName = ("A", "A")), listing it twice, while the same diagram exposed twice now drew once. Both are deduplicated in exposure order; the fixture exposes a package and a diagram twice.

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 2 commits September 23, 2026 14:35
A bare id written for a module element resolved to the first proxy whose href carried that fragment, so once two used modules shared a fragment (StandardProfile.xmi#Type beside UML.xmi#Type in a MagicDraw project) a later bare reference silently named the wrong element. The model now keeps every proxy per fragment and resolves a bare id only while one carries it; Model.Ambiguous lists the candidate hrefs, which the table, type-filter and DocGen refusals now state.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…veReqt from the original requirement

A matrix or relation-map criterion with includeSubtypes=false has no query
spelling: a user stereotype specializing «Satisfy» is written as the same
satisfy, so a RelatedColumn or RelatedElements walk of the kind lists its
relationships too. Such a criterion is now approximated with the specializing
stereotypes named; without any, the walk is exact and stays mapped.

A v1 DeriveReqt runs from the derived requirement to the original while the
v2 derivation runs the other way, so the lowered direction is inverted for
that kind; the tables golden's Trace 2 column changes accordingly.

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.

Devin Review found 2 new potential issues.

6 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread internal/translate/migrate/tables.go
Comment thread internal/translate/migrate/tables.go
@HuiJun
HuiJun merged commit b61ca44 into develop Sep 23, 2026
15 checks passed
@HuiJun
HuiJun deleted the feature/migrate-tables-and-documents branch September 23, 2026 15:54
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