ea 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (529) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -0
  3. data/TODO.complete/01-t-xref-parsing.md +91 -0
  4. data/TODO.complete/02-per-label-geometry.md +50 -0
  5. data/TODO.complete/03-object-properties-constraints.md +57 -0
  6. data/TODO.complete/04-operation-params.md +37 -0
  7. data/TODO.complete/05-pdata-flag-matrix.md +52 -0
  8. data/TODO.complete/06-emf-image-rendering.md +34 -0
  9. data/TODO.complete/07-auxiliary-tables.md +47 -0
  10. data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
  11. data/TODO.complete/11-gml-xsd-generation.md +42 -0
  12. data/TODO.complete/13-shapescript-interpreter.md +28 -0
  13. data/TODO.complete/20-cli-diff.md +46 -0
  14. data/TODO.complete/21-cli-render.md +26 -0
  15. data/TODO.complete/22-cli-export.md +29 -0
  16. data/TODO.complete/23-cli-mdg.md +23 -0
  17. data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
  18. data/TODO.complete/31-public-send-cleanup.md +61 -0
  19. data/TODO.complete/32-spec-coverage.md +33 -0
  20. data/TODO.complete/33-blocked-parity-gaps.md +41 -0
  21. data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
  22. data/TODO.complete/37-cli-lint.md +32 -0
  23. data/TODO.complete/38-cli-query.md +26 -0
  24. data/TODO.complete/39-cli-info.md +23 -0
  25. data/TODO.complete/40-ocl-evaluator.md +31 -0
  26. data/TODO.complete/41-round-trip-spec.md +18 -0
  27. data/TODO.complete/42-html-diff-report.md +18 -0
  28. data/TODO.complete/43-json-schema-export.md +20 -0
  29. data/TODO.complete/44-remaining-qea-tables.md +40 -0
  30. data/TODO.complete/45-shapescript-extensions.md +25 -0
  31. data/TODO.complete/46-xsd-consolidation.md +20 -0
  32. data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
  33. data/TODO.complete/STATUS.md +109 -0
  34. data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
  35. data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
  36. data/TODO.diagrams/03-text-over-rendering.md +30 -0
  37. data/TODO.diagrams/04-rect-under-rendering.md +33 -0
  38. data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
  39. data/TODO.diagrams/06-group-layering-parity.md +39 -0
  40. data/TODO.diagrams/07-text-content-fidelity.md +65 -0
  41. data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
  42. data/TODO.diagrams/12-connector-labels.md +40 -0
  43. data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
  44. data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
  45. data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
  46. data/TODO.diagrams/14-center-header-text.md +33 -0
  47. data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
  48. data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
  49. data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
  50. data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
  51. data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
  52. data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
  53. data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
  54. data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
  55. data/TODO.diagrams/18-property-lookup-index.md +42 -0
  56. data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
  57. data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
  58. data/TODO.diagrams/20-split-labels-emitter.md +56 -0
  59. data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
  60. data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
  61. data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
  62. data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
  63. data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
  64. data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
  65. data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
  66. data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
  67. data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
  68. data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
  69. data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
  70. data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
  71. data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
  72. data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
  73. data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
  74. data/TODO.diagrams/36-instance-specification-model.md +42 -0
  75. data/TODO.diagrams/37-element-icon-decorations.md +41 -0
  76. data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
  77. data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
  78. data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
  79. data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
  80. data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
  81. data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
  82. data/TODO.diagrams/44-element-icon-decorations.md +34 -0
  83. data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
  84. data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
  85. data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
  86. data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
  87. data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
  88. data/TODO.diagrams/50-examples-parity.md +85 -0
  89. data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
  90. data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
  91. data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
  92. data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
  93. data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
  94. data/TODO.diagrams/56-package-contents-rendering.md +148 -0
  95. data/TODO.diagrams/57-instance-specification-model.md +100 -0
  96. data/TODO.diagrams/58-domain-model-note-text.md +67 -0
  97. data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
  98. data/TODO.diagrams/60-testschema-association-marker.md +40 -0
  99. data/TODO.diagrams/61-legend-block-rendering.md +55 -0
  100. data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
  101. data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
  102. data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
  103. data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
  104. data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
  105. data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
  106. data/TODO.diagrams/68-inherited-attributes.md +65 -0
  107. data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
  108. data/TODO.diagrams/70-mdg-technology-support.md +68 -0
  109. data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
  110. data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
  111. data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
  112. data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
  113. data/TODO.diagrams/75-plateau-text-gap.md +39 -0
  114. data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
  115. data/TODO.diagrams/77-basic-text-overrender.md +40 -0
  116. data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
  117. data/TODO.diagrams/79-architecture-backlog.md +65 -0
  118. data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
  119. data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
  120. data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
  121. data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
  122. data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
  123. data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
  124. data/TODO.diagrams/86-foreign-package-rule.md +62 -0
  125. data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
  126. data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
  127. data/TODO.diagrams/README.md +69 -0
  128. data/TODO.diagrams/STATUS.md +73 -0
  129. data/TODO.fixup/01-default-grouped-paths.md +34 -0
  130. data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
  131. data/TODO.fixup/03-diagram-font-inference.md +28 -0
  132. data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
  133. data/TODO.fixup/05-marker-registry-ocp.md +32 -0
  134. data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
  135. data/TODO.fixup/07-edge-attachment-formula.md +22 -0
  136. data/TODO.fixup/08-visual-diff-harness.md +28 -0
  137. data/TODO.fixup/09-extract-element-compartments.md +34 -0
  138. data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
  139. data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
  140. data/TODO.fixup/12-path-style-harmony.md +23 -0
  141. data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
  142. data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
  143. data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
  144. data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
  145. data/TODO.fixup/17-path-count-calibration.md +27 -0
  146. data/TODO.fixup/18-polygon-count-calibration.md +32 -0
  147. data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
  148. data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
  149. data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
  150. data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
  151. data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
  152. data/TODO.fixup/24-note-element-rendering.md +23 -0
  153. data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
  154. data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
  155. data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
  156. data/TODO.fixup/28-geometry-parser-identification.md +57 -0
  157. data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
  158. data/TODO.fixup/30-theme-system-stub.md +46 -0
  159. data/TODO.fixup/31-theme-value-object-registry.md +17 -0
  160. data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
  161. data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
  162. data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
  163. data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
  164. data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
  165. data/TODO.fixup/37-package-shape-rendering.md +22 -0
  166. data/TODO.fixup/38-note-element-rendering.md +15 -0
  167. data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
  168. data/TODO.fixup/40-connector-dashed-lines.md +15 -0
  169. data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
  170. data/TODO.fixup/42-textrenderer-centralization.md +10 -0
  171. data/TODO.fixup/43-colorresolver-unification.md +24 -0
  172. data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
  173. data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
  174. data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
  175. data/TODO.fixup/47-canvas-frame-inset.md +19 -0
  176. data/TODO.fixup/48-background-rect-format.md +15 -0
  177. data/TODO.fixup/49-all-samples-integration-test.md +17 -0
  178. data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
  179. data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
  180. data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
  181. data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
  182. data/TODO.fixup/54-diagram-theme-api.md +50 -0
  183. data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
  184. data/TODO.fixup/56-theme-yaml-files.md +65 -0
  185. data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
  186. data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
  187. data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
  188. data/TODO.fixup/60-cli-theme-option.md +22 -0
  189. data/TODO.fixup/61-theme-validation.md +28 -0
  190. data/TODO.fixup/62-theme-builder-dsl.md +31 -0
  191. data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
  192. data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
  193. data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
  194. data/TODO.fixup/66-styleex-writeback.md +22 -0
  195. data/TODO.fixup/67-delete-dead-code.md +28 -0
  196. data/TODO.fixup/68-figure-parity-status.md +82 -0
  197. data/TODO.fixup/69-package-polygon-rendering.md +54 -0
  198. data/TODO.fixup/70-tagged-values-compartment.md +39 -0
  199. data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
  200. data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
  201. data/TODO.fixup/73-delete-dead-transformations.md +14 -0
  202. data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
  203. data/TODO.fixup/75-visibility-legend-icons.md +23 -0
  204. data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
  205. data/TODO.fixup/77-canvas-frame-margins.md +28 -0
  206. data/TODO.fixup/78-note-element-rendering.md +30 -0
  207. data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
  208. data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
  209. data/TODO.fixup/81-figure-parity-current-state.md +63 -0
  210. data/config/qea_schema.yml +356 -0
  211. data/config/themes/119.yml +98 -0
  212. data/config/themes/default.yml +14 -0
  213. data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
  214. data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
  215. data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
  216. data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
  217. data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
  218. data/examples/exports/UmlModel_template/model.xml +23 -0
  219. data/examples/exports/basic/UML_EA.DTD +6856 -0
  220. data/examples/exports/basic/model.xml +8039 -0
  221. data/examples/exports/simple/UML_EA.DTD +6856 -0
  222. data/examples/exports/simple/model.xml +585 -0
  223. data/examples/exports/simple_example/UML_EA.DTD +6856 -0
  224. data/examples/exports/simple_example/model.xml +23 -0
  225. data/examples/exports/test/UML_EA.DTD +6856 -0
  226. data/examples/exports/test/model.xml +1638 -0
  227. data/examples/qea/basic.qea +0 -0
  228. data/frontend/README.md +51 -0
  229. data/frontend/dist/app.iife.js +24 -0
  230. data/frontend/dist/style.css +1 -0
  231. data/frontend/index.html +26 -0
  232. data/frontend/package-lock.json +2359 -0
  233. data/frontend/package.json +26 -0
  234. data/frontend/src/App.vue +59 -0
  235. data/frontend/src/app.ts +8 -0
  236. data/frontend/src/components/AppHeader.vue +127 -0
  237. data/frontend/src/components/AppSidebar.vue +119 -0
  238. data/frontend/src/components/ClassDetails.vue +247 -0
  239. data/frontend/src/components/DiagramView.vue +79 -0
  240. data/frontend/src/components/PackageDetails.vue +92 -0
  241. data/frontend/src/components/PackageTreeNode.vue +64 -0
  242. data/frontend/src/components/SearchResults.vue +48 -0
  243. data/frontend/src/components/WelcomeView.vue +87 -0
  244. data/frontend/src/shims-vue.d.ts +5 -0
  245. data/frontend/src/stores/dataStore.ts +79 -0
  246. data/frontend/src/stores/uiStore.ts +167 -0
  247. data/frontend/src/styles/main.css +1566 -0
  248. data/frontend/src/types.ts +221 -0
  249. data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
  250. data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
  251. data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
  252. data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
  253. data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
  254. data/frontend/tests/e2e/render.spec.ts +188 -0
  255. data/frontend/tsconfig.json +20 -0
  256. data/frontend/vite.config.ts +26 -0
  257. data/frontend/vitest.config.ts +8 -0
  258. data/lib/ea/cli/app.rb +57 -2
  259. data/lib/ea/cli/command/diagrams.rb +37 -28
  260. data/lib/ea/cli/command/diff.rb +46 -0
  261. data/lib/ea/cli/command/export.rb +80 -0
  262. data/lib/ea/cli/command/info.rb +75 -0
  263. data/lib/ea/cli/command/lint.rb +48 -0
  264. data/lib/ea/cli/command/mdg.rb +98 -0
  265. data/lib/ea/cli/command/query.rb +34 -0
  266. data/lib/ea/cli/command/render.rb +135 -0
  267. data/lib/ea/cli/command/svg.rb +8 -15
  268. data/lib/ea/cli/command.rb +7 -0
  269. data/lib/ea/diagram/display_config.rb +184 -0
  270. data/lib/ea/diagram.rb +4 -41
  271. data/lib/ea/diff/change.rb +30 -0
  272. data/lib/ea/diff/comparator.rb +82 -0
  273. data/lib/ea/diff/html_reporter.rb +91 -0
  274. data/lib/ea/diff.rb +15 -0
  275. data/lib/ea/export/json/generator.rb +42 -0
  276. data/lib/ea/export/json.rb +12 -0
  277. data/lib/ea/export/json_schema/generator.rb +77 -0
  278. data/lib/ea/export/json_schema.rb +12 -0
  279. data/lib/ea/export/plantuml/generator.rb +73 -0
  280. data/lib/ea/export/plantuml.rb +12 -0
  281. data/lib/ea/export/xmi/generator.rb +77 -0
  282. data/lib/ea/export/xmi.rb +11 -0
  283. data/lib/ea/export/xsd/class_mapping.rb +65 -0
  284. data/lib/ea/export/xsd/generator.rb +142 -0
  285. data/lib/ea/export/xsd/namespace_registry.rb +82 -0
  286. data/lib/ea/export/xsd.rb +19 -0
  287. data/lib/ea/export.rb +14 -0
  288. data/lib/ea/image/emf_renderer.rb +42 -0
  289. data/lib/ea/image.rb +12 -0
  290. data/lib/ea/lint/engine.rb +30 -0
  291. data/lib/ea/lint/lint_rule.rb +38 -0
  292. data/lib/ea/lint/offense.rb +18 -0
  293. data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
  294. data/lib/ea/lint/rules/duplicate_name.rb +28 -0
  295. data/lib/ea/lint/rules/missing_stereotype.rb +35 -0
  296. data/lib/ea/lint/rules/naming_convention.rb +44 -0
  297. data/lib/ea/lint/rules/orphan_element.rb +28 -0
  298. data/lib/ea/lint/rules.rb +14 -0
  299. data/lib/ea/lint.rb +13 -0
  300. data/lib/ea/mdg/document.rb +120 -0
  301. data/lib/ea/mdg/loader.rb +118 -0
  302. data/lib/ea/mdg/registry.rb +98 -0
  303. data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
  304. data/lib/ea/mdg/xml/applies_to.rb +18 -0
  305. data/lib/ea/mdg/xml/apply.rb +18 -0
  306. data/lib/ea/mdg/xml/content.rb +18 -0
  307. data/lib/ea/mdg/xml/documentation.rb +24 -0
  308. data/lib/ea/mdg/xml/stereotype.rb +28 -0
  309. data/lib/ea/mdg/xml/stereotypes.rb +18 -0
  310. data/lib/ea/mdg/xml/tag.rb +28 -0
  311. data/lib/ea/mdg/xml/tagged_values.rb +18 -0
  312. data/lib/ea/mdg/xml/technology.rb +28 -0
  313. data/lib/ea/mdg/xml/uml_profile.rb +22 -0
  314. data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
  315. data/lib/ea/mdg/xml.rb +24 -0
  316. data/lib/ea/mdg.rb +25 -0
  317. data/lib/ea/model/classifier.rb +4 -0
  318. data/lib/ea/model/constraint.rb +24 -0
  319. data/lib/ea/model/diagram.rb +85 -0
  320. data/lib/ea/model/diagram_connector.rb +34 -0
  321. data/lib/ea/model/diagram_element.rb +16 -0
  322. data/lib/ea/model/document.rb +47 -2
  323. data/lib/ea/model/ghost_label.rb +32 -0
  324. data/lib/ea/model/instance_specification.rb +34 -0
  325. data/lib/ea/model/legend.rb +43 -0
  326. data/lib/ea/model/legend_item.rb +26 -0
  327. data/lib/ea/model/note.rb +28 -0
  328. data/lib/ea/model/operation.rb +2 -0
  329. data/lib/ea/model/property.rb +2 -0
  330. data/lib/ea/model/relationship.rb +2 -0
  331. data/lib/ea/model/signal.rb +14 -0
  332. data/lib/ea/model/slot.rb +19 -0
  333. data/lib/ea/model.rb +8 -0
  334. data/lib/ea/ocl/evaluator.rb +94 -0
  335. data/lib/ea/ocl/nodes.rb +30 -0
  336. data/lib/ea/ocl/parser.rb +133 -0
  337. data/lib/ea/ocl/unsupported_error.rb +7 -0
  338. data/lib/ea/ocl.rb +13 -0
  339. data/lib/ea/qea/factory/document_builder.rb +24 -10
  340. data/lib/ea/qea/factory/generalization_builder.rb +9 -11
  341. data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
  342. data/lib/ea/qea/models/ea_author.rb +35 -0
  343. data/lib/ea/qea/models/ea_glossary.rb +34 -0
  344. data/lib/ea/qea/models/ea_image.rb +53 -0
  345. data/lib/ea/qea/models/ea_implement.rb +32 -0
  346. data/lib/ea/qea/models/ea_list.rb +42 -0
  347. data/lib/ea/qea/models/ea_object_effort.rb +34 -0
  348. data/lib/ea/qea/models/ea_object_problem.rb +37 -0
  349. data/lib/ea/qea/models/ea_object_require.rb +34 -0
  350. data/lib/ea/qea/models/ea_object_resource.rb +34 -0
  351. data/lib/ea/qea/models/ea_object_risk.rb +34 -0
  352. data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
  353. data/lib/ea/qea/models/ea_object_test.rb +35 -0
  354. data/lib/ea/qea/models/ea_object_trx.rb +34 -0
  355. data/lib/ea/qea/models/ea_operation.rb +7 -0
  356. data/lib/ea/qea/models/ea_palette.rb +30 -0
  357. data/lib/ea/qea/models/ea_palette_item.rb +36 -0
  358. data/lib/ea/qea/models/ea_phase.rb +40 -0
  359. data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
  360. data/lib/ea/qea/models/ea_secrypt.rb +34 -0
  361. data/lib/ea/qea/models/ea_version.rb +39 -0
  362. data/lib/ea/qea/models/ea_xref.rb +11 -1
  363. data/lib/ea/qea/models.rb +19 -0
  364. data/lib/ea/qea/services/database_loader.rb +22 -1
  365. data/lib/ea/query/builder.rb +108 -0
  366. data/lib/ea/query.rb +9 -0
  367. data/lib/ea/render/image_converter.rb +101 -0
  368. data/lib/ea/render.rb +10 -0
  369. data/lib/ea/shapescript/parser.rb +208 -0
  370. data/lib/ea/shapescript/renderer.rb +74 -0
  371. data/lib/ea/shapescript/shape.rb +34 -0
  372. data/lib/ea/shapescript.rb +24 -0
  373. data/lib/ea/sources/qea/adapter.rb +22 -5
  374. data/lib/ea/sources/qea/classifier_builder.rb +184 -7
  375. data/lib/ea/sources/qea/diagram_builder.rb +352 -24
  376. data/lib/ea/sources/qea/id_normalizer.rb +16 -1
  377. data/lib/ea/sources/qea/instance_builder.rb +113 -0
  378. data/lib/ea/sources/qea/legend_builder.rb +137 -0
  379. data/lib/ea/sources/qea/note_builder.rb +58 -0
  380. data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
  381. data/lib/ea/sources/qea/operation_builder.rb +1 -0
  382. data/lib/ea/sources/qea/package_builder.rb +16 -0
  383. data/lib/ea/sources/qea/relationship_builder.rb +21 -5
  384. data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
  385. data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
  386. data/lib/ea/sources/qea/xref/parser.rb +150 -0
  387. data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
  388. data/lib/ea/sources/qea/xref/record.rb +41 -0
  389. data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
  390. data/lib/ea/sources/qea/xref.rb +27 -0
  391. data/lib/ea/sources/qea.rb +4 -0
  392. data/lib/ea/sources/xmi/adapter.rb +80 -2
  393. data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
  394. data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
  395. data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
  396. data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
  397. data/lib/ea/sources/xmi/note_builder.rb +46 -0
  398. data/lib/ea/sources/xmi/property_builder.rb +9 -0
  399. data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
  400. data/lib/ea/sources/xmi/tag_builder.rb +45 -0
  401. data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
  402. data/lib/ea/sources/xmi.rb +4 -0
  403. data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
  404. data/lib/ea/spa/output/single_file_strategy.rb +8 -2
  405. data/lib/ea/spa/output/strategy.rb +34 -0
  406. data/lib/ea/svg/connector_router.rb +134 -0
  407. data/lib/ea/svg/ea_emitter/background.rb +2 -3
  408. data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
  409. data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
  410. data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
  411. data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
  412. data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
  413. data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
  414. data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
  415. data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
  416. data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
  417. data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
  418. data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
  419. data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
  420. data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
  421. data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
  422. data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
  423. data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
  424. data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
  425. data/lib/ea/svg/ea_emitter/compartment.rb +58 -0
  426. data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
  427. data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
  428. data/lib/ea/svg/ea_emitter/document.rb +15 -24
  429. data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
  430. data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
  431. data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
  432. data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
  433. data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
  434. data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
  435. data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
  436. data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
  437. data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
  438. data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
  439. data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
  440. data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
  441. data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
  442. data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
  443. data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
  444. data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
  445. data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
  446. data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
  447. data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
  448. data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
  449. data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
  450. data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
  451. data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
  452. data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
  453. data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +82 -0
  454. data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
  455. data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
  456. data/lib/ea/svg/ea_emitter/element.rb +37 -0
  457. data/lib/ea/svg/ea_emitter/elements.rb +283 -95
  458. data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
  459. data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
  460. data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
  461. data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
  462. data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
  463. data/lib/ea/svg/ea_emitter/label.rb +23 -0
  464. data/lib/ea/svg/ea_emitter/labels.rb +93 -27
  465. data/lib/ea/svg/ea_emitter/layer.rb +20 -0
  466. data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
  467. data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
  468. data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
  469. data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
  470. data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
  471. data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
  472. data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
  473. data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
  474. data/lib/ea/svg/ea_emitter/marker.rb +37 -0
  475. data/lib/ea/svg/ea_emitter/markers.rb +351 -64
  476. data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
  477. data/lib/ea/svg/ea_emitter/style.rb +15 -0
  478. data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
  479. data/lib/ea/svg/ea_emitter.rb +33 -11
  480. data/lib/ea/svg/parity/checker.rb +105 -0
  481. data/lib/ea/svg/parity/source.rb +59 -0
  482. data/lib/ea/svg/parity/suite.rb +113 -0
  483. data/lib/ea/svg/parity.rb +14 -0
  484. data/lib/ea/svg.rb +2 -15
  485. data/lib/ea/theme/definition.rb +176 -0
  486. data/lib/ea/theme/loader.rb +125 -0
  487. data/lib/ea/theme/registry.rb +96 -0
  488. data/lib/ea/theme.rb +37 -0
  489. data/lib/ea/transformations.rb +5 -88
  490. data/lib/ea/version.rb +4 -1
  491. data/lib/ea.rb +14 -4
  492. data/lib/tasks/svg_bench.rake +87 -0
  493. data/lutaml-uml-0.5.1.gem +0 -0
  494. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
  495. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
  496. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
  497. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
  498. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
  499. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
  500. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
  501. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
  502. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
  503. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
  504. data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
  505. metadata +449 -26
  506. data/lib/ea/diagram/configuration.rb +0 -379
  507. data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
  508. data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
  509. data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
  510. data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
  511. data/lib/ea/diagram/element_renderers.rb +0 -43
  512. data/lib/ea/diagram/extractor.rb +0 -566
  513. data/lib/ea/diagram/layout_engine.rb +0 -170
  514. data/lib/ea/diagram/path_builder.rb +0 -202
  515. data/lib/ea/diagram/style_parser.rb +0 -42
  516. data/lib/ea/diagram/style_resolver.rb +0 -291
  517. data/lib/ea/diagram/svg_renderer.rb +0 -274
  518. data/lib/ea/diagram/util.rb +0 -73
  519. data/lib/ea/svg/bounds_calculator.rb +0 -74
  520. data/lib/ea/svg/connector_path.rb +0 -138
  521. data/lib/ea/svg/element_box.rb +0 -256
  522. data/lib/ea/svg/renderer.rb +0 -77
  523. data/lib/ea/svg/style_resolver.rb +0 -72
  524. data/lib/ea/transformations/configuration.rb +0 -333
  525. data/lib/ea/transformations/format_registry.rb +0 -366
  526. data/lib/ea/transformations/parsers/base_parser.rb +0 -482
  527. data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
  528. data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
  529. data/lib/ea/transformations/transformation_engine.rb +0 -390
@@ -0,0 +1,59 @@
1
+ # TODO-D 61: Plateau parity gaps
2
+
3
+ ## Status: open (broad cross-cutting gaps on plateau QEA)
4
+
5
+ The plateau is the `20251010_current_plateau_v5.1.qea` file at
6
+ `examples/qea/`. Its 188 reference SVGs live at
7
+ `examples/exports/20251010_current_plateau_v5/Images/`.
8
+
9
+ A separate plateau XMI is at
10
+ `~/src/mn/mn-samples-plateau/sources/xmi/plateau_all_packages_export.xmi`
11
+ with its own reference SVGs at
12
+ `~/src/mn/mn-samples-plateau/sources/001-mds/xmi-images/`.
13
+
14
+ ## Current state — Plateau QEA (examples/)
15
+
16
+ | Metric | Before | After improvements | Change |
17
+ |--------|--------|-------------------|--------|
18
+ | Matched | 126/188 | **130/188** | +4 |
19
+ | rect | -460 | **-460** | — |
20
+ | path | -455 | **-92** | +363 recovered |
21
+ | polygon | +27 | **+27** | — |
22
+ | text | -519 | **-519** | — |
23
+
24
+ Key improvements this session:
25
+ - Horizontal-tree-routed arrow suppression (narrower check)
26
+ - Marker dedup changed to polygon-only (never dedup arrows)
27
+ → recovered ~200 association arrow paths on plateau
28
+
29
+ ## Current state — Plateau XMI (~/src/mn/)
30
+
31
+ | Metric | Value |
32
+ |--------|-------|
33
+ | Diagrams matched (tolerance ≤5) | 127/185 |
34
+ | rect delta | -221 (-11.0%) |
35
+ | path delta | -338 (-10.2%) |
36
+ | polygon delta | -6 (-0.6%) |
37
+ | text delta | +97 (+0.6%) |
38
+
39
+ ## Where the deltas come from
40
+
41
+ ### rect -460 (QEA) / -221 (XMI)
42
+ - Missing visibility icons (2 rects per attribute × many elements)
43
+ - Package-content child rows missing on some diagrams
44
+ - Element shape encoding (rect vs polygon)
45
+
46
+ ### path -455 (QEA) / -338 (XMI)
47
+ - Connector arrow markers (tree-routed suppression removes some)
48
+ - Visibility icon paths (7 per attr × many elements)
49
+ - Connector routing encoding differences
50
+
51
+ ### text -519 (QEA) / +97 (XMI)
52
+ - QEA has richer data (RunState, more tagged values) but some
53
+ texts are not rendered (instance labels, slot values)
54
+ - XMI over-renders some texts (from InstanceSpecification parsing)
55
+
56
+ ## Plan
57
+
58
+ Each delta spans dozens of diagrams. Improvements require broad
59
+ pipeline changes rather than single-diagram fixes.
@@ -0,0 +1,56 @@
1
+ # TODO-D 62: Ghost element rendering (off-canvas connector endpoints)
2
+
3
+ ## Status: open
4
+
5
+ EA phantom-renders classifier names near connector endpoints that
6
+ reference elements NOT placed on the current diagram. These "ghost
7
+ elements" appear as italic class names (e.g. `_CityObject`,
8
+ `_Site`, `_Geometry`) at the connector's off-canvas end. They are
9
+ NOT in `t_diagramobjects` for the diagram but ARE referenced by
10
+ `t_connector.Start_Object_ID` / `End_Object_ID` of connectors
11
+ that ARE on the diagram.
12
+
13
+ ## Evidence (plateau QEA, "indoor" diagram)
14
+
15
+ - `_CityObject` does not appear in `t_diagramobjects` for the
16
+ indoor diagram.
17
+ - It IS referenced by connectors on the indoor diagram (e.g.
18
+ generalizations from `Room` to `_CityObject`).
19
+ - EA renders the name as 5+ separate italic `<text>` elements at
20
+ different positions, one per connector endpoint.
21
+
22
+ ## Approach
23
+
24
+ 1. **Source side**: in `DiagramBuilder`, walk every renderable
25
+ connector and look up its source/target object via
26
+ `database.find_connector` → `start_object_id`/`end_object_id` →
27
+ `database.find_object`. When the object is NOT placed on this
28
+ diagram (no entry in `t_diagramobjects`), synthesise a
29
+ "ghost element" annotation on the connector: the off-canvas
30
+ end's classifier name + a virtual anchor position (probably
31
+ the on-canvas endpoint).
32
+
33
+ 2. **Model side**: add `ghost_labels` to `DiagramConnector` —
34
+ a collection of `(name, end_kind, anchor_offset)` tuples.
35
+
36
+ 3. **Renderer side**: emit each ghost label as an italic `<text>`
37
+ at the connector's endpoint, offset to one side. Match EA's
38
+ offset rules (need to reverse-engineer from reference SVGs).
39
+
40
+ ## Impact
41
+
42
+ Closing the text gap from -292 to near 0 on plateau QEA. Most of
43
+ the missing text delta comes from ghost labels:
44
+ - indoor: -17 (mostly `_CityObject`)
45
+ - frn_1: -7
46
+ - cons_1: -6
47
+ - tran_2: -5
48
+ - bldg_1: -6 (BuildingAttribute)
49
+ - and 10+ more diagrams with -1 to -5 each.
50
+
51
+ Combined: ~80-100 missing ghost labels across the plateau.
52
+
53
+ ## Related
54
+
55
+ - TODO-D 26 (Investigate phantom class headers from connector
56
+ endpoints) is the older writeup of the same issue.
@@ -0,0 +1,36 @@
1
+ # TODO-D 63: Qualified-name line wrap for long class names
2
+
3
+ ## Status: completed
4
+
5
+ EA wraps long qualified class names (e.g. `brid::OuterFloorSurface`)
6
+ across TWO `<text>` elements when the rendered width exceeds the
7
+ element's header width.
8
+
9
+ ## Implementation
10
+
11
+ `Ea::Svg::EaEmitter::Element::HeaderLines.for` now accepts
12
+ `bounds_width:` and `font_size:` keyword args. When the qualified
13
+ name's estimated rendered width (using `TextRenderer.estimate_width`
14
+ with `width_factor=0.55` and `QUALIFIED_WRAP_PADDING=8`) exceeds
15
+ the element's bounds, the name splits into two header lines:
16
+
17
+ 1. `"qualifier::"` (with trailing `::`)
18
+ 2. `"ClassName"` (the base name after `::`)
19
+
20
+ The `Elements` orchestrator threads `raw_bounds.width` and the
21
+ resolved `font_size` through to `HeaderLines.for`.
22
+
23
+ ## Results
24
+
25
+ - Plateau text delta: -3 → +5 (slight over-rendering on a few
26
+ borderline cases — both name+wrap and not-quite-fit names).
27
+ - 154/188 matched diagrams (unchanged).
28
+ - basic.qea, test.qea, simple.qea: unchanged.
29
+
30
+ ## Tuning
31
+
32
+ Width factor 0.55 matches Carlito 9pt bold's average glyph advance
33
+ for the CJK + Latin mix on the plateau. The 8px padding accounts
34
+ for the element's internal left+right padding that EA reserves
35
+ around header text. Both constants are at the top of HeaderLines
36
+ for easy future adjustment if EA's font metrics shift.
@@ -0,0 +1,22 @@
1
+ # TODO-D 64: Missing «property» stereotype labels on association roles
2
+
3
+ ## Status: completed
4
+
5
+ The `PROPERTY_OY_GAP_THRESHOLD = 15` constant in
6
+ `Ea::Svg::EaEmitter::Label::EndLabel` was incorrectly gating
7
+ `«property»` rendering. Reference SVGs show EA always emits the
8
+ stereotype when both a role name and multiplicity are present,
9
+ regardless of the OY gap between the LLT and LLB geometry boxes.
10
+
11
+ ## Fix
12
+
13
+ Removed the threshold; `property_label?` now returns true whenever
14
+ called. The basic.qea associations that skip `«property»` do so
15
+ because they have no role name, not because of any gap.
16
+
17
+ ## Results
18
+
19
+ Plateau QEA text delta: -292 → -3 (closed 289 missing text labels).
20
+ test.qea text delta: 0 → +2 (regression of 2 —
21
+ the threshold was masking a different issue there).
22
+ Matched count unchanged (154/188).
@@ -0,0 +1,62 @@
1
+ # TODO-D 65: Path coordinate frame mismatch (y-axis sign)
2
+
3
+ ## Status: open
4
+
5
+ Elements render at the wrong vertical position because
6
+ `bounds_from_rect` interprets `RectTop` as the math-convention
7
+ y (negative, larger=lower) when EA actually stores it as the
8
+ negation of the screen-space y (negative, larger=higher).
9
+
10
+ The bench's shape_delta_total doesn't catch this because counts
11
+ match — but per-path coordinate comparison shows every ref path
12
+ is "missing" from our output (coordinate values differ).
13
+
14
+ ## Evidence (plateau QEA, "Bridge" diagram)
15
+
16
+ Raw EA rect for `_CityObject`:
17
+ - RectLeft=611, RectTop=-64, RectRight=941, RectBottom=-186
18
+
19
+ Reference SVG renders `_CityObject` text at `y=73`.
20
+
21
+ Our model produces `bounds.y = -186` (taking `min(RectTop, RectBottom)`).
22
+ After canvas translation we render at `y > 1000` (bottom of canvas).
23
+
24
+ The correct interpretation is:
25
+ - screen-y of element's top edge = `-RectTop = 64`
26
+ - height = `RectTop - RectBottom = -64 - (-186) = 122`
27
+
28
+ With a small offset (33 in basic.qea, 9 in plateau Bridge) we'd
29
+ match the reference's text baseline.
30
+
31
+ ## Approach
32
+
33
+ Update `DiagramBuilder#bounds_from_rect`:
34
+
35
+ ```ruby
36
+ def bounds_from_rect(obj_row)
37
+ left = obj_row.rectleft || 0
38
+ right = obj_row.rectright || 0
39
+ top = obj_row.recttop || 0
40
+ bottom = obj_row.rectbottom || 0
41
+ Ea::Model::Bounds.new(
42
+ x: [left, right].min,
43
+ y: -[top, bottom].max, # flip y-axis
44
+ width: (right - left).abs,
45
+ height: (bottom - top).abs
46
+ )
47
+ end
48
+ ```
49
+
50
+ Then rework `Canvas#translate_y` and `BoundsCalculator` to use
51
+ positive y values consistently. The current min_y computation
52
+ also needs to flip.
53
+
54
+ This is a large change — needs careful re-verification against
55
+ basic.qea and test.qea to avoid regressing the 24/24 currently
56
+ matched.
57
+
58
+ ## Impact
59
+
60
+ Doesn't change counts (and so won't move the bench needle), but
61
+ makes the visual output match EA positionally. Required before
62
+ we can claim "100% identical to QEA->SVG" in any visual sense.
@@ -0,0 +1,62 @@
1
+ # TODO-D 67: Path coordinate frame (y-axis sign)
2
+
3
+ ## Status: open
4
+
5
+ Elements render at the wrong vertical position because
6
+ `bounds_from_rect` interprets `RectTop` as the math-convention
7
+ y (negative, larger=lower on screen) when EA actually stores
8
+ it as the negation of the screen-space y.
9
+
10
+ The bench's shape_delta_total doesn't catch this because counts
11
+ match — but per-path coordinate comparison shows every ref path
12
+ is "missing" from our output (coordinate values differ).
13
+
14
+ ## Evidence (plateau QEA, "Bridge" diagram)
15
+
16
+ Raw EA rect for `_CityObject`:
17
+ - RectLeft=611, RectTop=-64, RectRight=941, RectBottom=-186
18
+
19
+ Reference SVG renders `_CityObject` text at `y=73`.
20
+
21
+ Our model produces `bounds.y = -186` (taking `min(RectTop, RectBottom)`).
22
+ After canvas translation we render at `y > 1000` (bottom of canvas).
23
+
24
+ The correct interpretation is:
25
+ - screen-y of element's top edge = `-RectTop = 64`
26
+ - height = `RectTop - RectBottom = -64 - (-186) = 122`
27
+
28
+ With the canvas's positive offset (40 frame inset + diagram-specific),
29
+ we match the reference's text baseline.
30
+
31
+ ## Approach
32
+
33
+ Update `DiagramBuilder#bounds_from_rect`:
34
+
35
+ ```ruby
36
+ def bounds_from_rect(obj_row)
37
+ left = obj_row.rectleft || 0
38
+ right = obj_row.rectright || 0
39
+ top = obj_row.recttop || 0
40
+ bottom = obj_row.rectbottom || 0
41
+ Ea::Model::Bounds.new(
42
+ x: [left, right].min,
43
+ y: -[top, bottom].max, # flip y-axis
44
+ width: (right - left).abs,
45
+ height: (bottom - top).abs
46
+ )
47
+ end
48
+ ```
49
+
50
+ Then rework `Canvas#translate_y` and `BoundsCalculator` to use
51
+ positive y values consistently. The current min_y computation
52
+ also needs to flip.
53
+
54
+ This is a large change — needs careful re-verification against
55
+ basic.qea and test.qea to avoid regressing the 184/188 currently
56
+ matched.
57
+
58
+ ## Impact
59
+
60
+ Doesn't change counts (and so won't move the bench needle), but
61
+ makes the visual output match EA positionally. Required before
62
+ we can claim "100% identical to QEA->SVG" in any visual sense.
@@ -0,0 +1,65 @@
1
+ # TODO-D 68: Association-derived virtual properties (phantom attributes)
2
+
3
+ ## Status: open (discriminator unresolved)
4
+
5
+ EA renders some association SourceRole values as virtual
6
+ "property" attributes inside the source classifier's attribute
7
+ compartment. For example, ImplicitGeometry has 4 associations to
8
+ CityFurniture with SourceRoles lod1..4ImplicitRepresentation.
9
+ EA renders "+lod1ImplicitRepresentation" inside ImplicitGeometry's
10
+ attribute compartment on every diagram where ImplicitGeometry is
11
+ placed with an expanded attribute compartment.
12
+
13
+ ## Investigation findings
14
+
15
+ The phantom attributes come from t_connector.SourceRole on
16
+ Association and Aggregation connectors. In the plateau QEA:
17
+ - 206 Aggregations have SourceRoles
18
+ - 172 Associations have SourceRoles
19
+
20
+ Not all SourceRoles render as virtual attributes. The discriminator
21
+ that gates rendering has NOT been identified. Adding all 378
22
+ SourceRoles as properties causes massive over-rendering (text
23
+ delta: +20,000). The correct subset is much smaller.
24
+
25
+ ### What was tried
26
+
27
+ 1. **All SourceRoles as properties**: text +20k — far too many.
28
+ The vast majority of SourceRoles do NOT render in EA output.
29
+
30
+ 2. **Only when connector NOT on current diagram**: incorrect —
31
+ on the ImplicitGeometry diagram, the lod* connectors ARE on
32
+ the diagram AND the phantom attrs still show.
33
+
34
+ 3. **Only for GML stereotypes (Type/FeatureType)**: promising
35
+ but not all "Type" stereotyped classifiers show SourceRole
36
+ attrs on every diagram. CityGMLCore shows ImplicitGeometry
37
+ WITHOUT the lod texts (element is in collapsed mode).
38
+
39
+ ### What's known
40
+
41
+ - SourceRoles render ONLY when the element's attribute compartment
42
+ is visible AND expanded (has NSL/font settings in ObjectStyle).
43
+ - The position of phantom attr texts in the ref SVG is OUTSIDE
44
+ any element rect (floating) on some diagrams, suggesting EA
45
+ places them at connector-label positions rather than inside
46
+ the attribute compartment.
47
+ - Multiple phantom attrs at the same position suggests overlap
48
+ rendering (all at same x,y) which is characteristic of connector
49
+ end-labels, not attribute-compartment lines.
50
+
51
+ ### Next steps
52
+
53
+ 1. Investigate whether the phantom attrs are actually connector
54
+ LABELS (from $LLB/$LLT geometry) rather than attribute
55
+ compartment lines. The position (412, 473) doesn't match any
56
+ element's attribute compartment area.
57
+
58
+ 2. Check if the phantom attrs come from a per-diagram setting
59
+ like "Show inherited/association attributes" flag in the
60
+ t_diagram StyleEx or PDATA.
61
+
62
+ 3. If they ARE attribute-compartment lines (not labels),
63
+ identify the precise subset of SourceRoles that EA renders
64
+ (maybe only when the connector's DestRole is empty AND the
65
+ SourceRole matches a naming convention).
@@ -0,0 +1,29 @@
1
+ # TODO-D 69: Package anchor marker conditional rendering
2
+
3
+ ## Status: completed
4
+
5
+ The «import» connector's package_anchor marker (4-point closed
6
+ trapezoid at the source end) was rendered unconditionally,
7
+ causing 9 phantom paths on the plateau "Urban Planning ADE2"
8
+ diagram.
9
+
10
+ ## Root cause
11
+
12
+ EA's t_diagramlinks.Geometry string carries explicit SX/SY/EX/EY
13
+ offset fields when the connector has been explicitly configured
14
+ with edge-attachment offsets. When SX/SY are absent, the
15
+ connector is auto-routed and EA suppresses the package_anchor
16
+ marker.
17
+
18
+ ## Fix
19
+
20
+ Added `has_geometry_offsets` boolean to DiagramConnector model.
21
+ DiagramBuilder sets it by checking whether the raw Geometry
22
+ string contains "SX=". PackageImport marker returns [] when
23
+ false.
24
+
25
+ ## Verification
26
+
27
+ - basic.qea Package Imports: SX=0;SY=0 present -> marker renders
28
+ - plateau Urban Planning ADE2: SX/SY absent -> no marker
29
+ - Urban Planning ADE2 delta dropped from 9 to 0 → matched
@@ -0,0 +1,68 @@
1
+ # TODO-D 70: MDG Technology Support
2
+
3
+ ## Status: Phases 1 & 2 complete; Phase 3 deferred
4
+
5
+ EA's MDG (Model Driven Generation) technologies bundle UML
6
+ profiles, reference models, and toolbox definitions in a single
7
+ XMI file. When EA loads an MDG, the MDG's classes/attributes/
8
+ stereotypes become available to all models — including inherited
9
+ attribute rendering when a classifier's stereotype maps to an
10
+ MDG-defined metaclass.
11
+
12
+ ## Architecture (shipped)
13
+
14
+ ```
15
+ Ea::Mdg # standalone namespace
16
+ ├─ Document # one MDG file's parsed model
17
+ │ ├─ ClassifierEntry (id, name, package_name, properties)
18
+ │ ├─ PropertyEntry (name, type_name, visibility, mult)
19
+ │ └─ GeneralizationEntry (specific_id, general_id)
20
+ ├─ Loader # XMI parser → Document
21
+ └─ Registry # multi-MDG lookup, ancestor walking
22
+ ```
23
+
24
+ Integration:
25
+
26
+ - `Ea::Sources::Qea::Adapter.from_path(path, mdg_registry: nil)`
27
+ - When `mdg_registry:` is wired, `ClassifierBuilder#properties_for`
28
+ merges MDG-inherited attributes into the classifier's property
29
+ list.
30
+ - Backward-compatible: omitting `mdg_registry:` preserves prior
31
+ behavior exactly.
32
+
33
+ ## Verified against reference MDG files
34
+
35
+ - `MDG ISO19103.xml` (12 classifiers, 5 packages)
36
+ - `ISO 19103 Edition 1 XML.xml` (62 classifiers, 68 generalizations,
37
+ properties under UML:Classifier.feature)
38
+ - Ancestor walk yields correct inherited properties
39
+ (e.g. UnitsList → StandardUnits → 11 properties)
40
+
41
+ ## What's still needed for plateau parity
42
+
43
+ The plateau phantom attributes (`+lod1ImplicitRepresentation`
44
+ on `ImplicitGeometry`, `+boundedBy` on `_CityObject`, etc.) come
45
+ from a **CityGML/GML MDG** that is not in the user's
46
+ `~/src/lutaml/xmi/references/ImplementationModels/` directory.
47
+
48
+ To close those specific gaps:
49
+ 1. Obtain the CityGML/GML MDG technology XML file.
50
+ 2. Pass it via `mdg_registry:` when loading the plateau QEA.
51
+ 3. The classifier's `Type` stereotype will resolve to the MDG's
52
+ `Type` class, and its ancestor properties will merge in.
53
+
54
+ This is data-availability, not architecture. The plumbing works.
55
+
56
+ ## Phase 3 (deferred)
57
+
58
+ - Stereotype definition extraction (UML:Profile/Stereotype) for
59
+ applying tagged values from MDG stereotype definitions.
60
+ - CLI subcommand: `ea mdg list` / `ea mdg show <name>`.
61
+ - Toolbox definition parsing (for future toolbox rendering).
62
+
63
+ ## Test coverage
64
+
65
+ - `spec/ea/mdg/loader_spec.rb` (6 specs)
66
+ - `spec/ea/mdg/registry_spec.rb` (8 specs)
67
+ - `spec/ea/sources/qea/mdg_integration_spec.rb` (3 specs)
68
+ - Total: 17 new specs; full suite 1839 examples, 0 failures.
@@ -0,0 +1,45 @@
1
+ # TODO-D 71: Off-canvas parent class ghost line in element header
2
+
3
+ ## Status: completed (2026-08-01)
4
+
5
+ EA prepends the off-canvas parent classifier's name as an italic
6
+ line at the top of a placed element's header when ALL of:
7
+
8
+ 1. The diagram's HideParents PDATA flag is 0 (default).
9
+ 2. The placed element has a Generalization to a parent NOT placed
10
+ on the current diagram.
11
+ 3. No other element from the parent's package is placed on the
12
+ diagram (EA treats the parent's package as "represented").
13
+
14
+ e.g. on the indoor diagram (HideParents=0), Room's parent
15
+ _CityObject (in the "core" package, off-canvas, no other core
16
+ elements placed) renders as an italic "_CityObject" line above
17
+ Room's own header. On Building (HideParents=1), no parent ghosts
18
+ render at all.
19
+
20
+ ## Implementation
21
+
22
+ - RelationshipBuilder populates Generalization.specific_id and
23
+ .general_id (child + parent GUIDs).
24
+ - Diagram model gains show_parents attribute; DiagramBuilder
25
+ parses HideParents= from t_diagram.PDATA.
26
+ - RenderContext carries off_canvas_parent_name; Elements resolves
27
+ it via document.relationships + model_index + diagram.elements.
28
+ - HeaderLines prepends [name, :italic] when the value is non-nil.
29
+ - LayerSequencer threads `document:` to Elements.
30
+
31
+ ## Plateau QEA impact
32
+
33
+ - Before: text delta -98 (98 texts missing vs ref)
34
+ - After: text delta -36 (62 texts closed)
35
+ - 188/188 diagrams matched.
36
+
37
+ ## Remaining gap (-36)
38
+
39
+ The foreign-package rule is slightly too aggressive — some diagrams
40
+ (tran_2, urf_urbanFunction) render parent ghosts for parents in
41
+ "represented" packages. Removing the foreign-package check
42
+ over-corrects to +60 (over-render). The true discriminator is
43
+ narrower than "package represented" but broader than just
44
+ HideParents. Defer to a future investigation if a clearer signal
45
+ (e.g., a t_object flag, MDG stereotype pattern) is identified.
@@ -0,0 +1,39 @@
1
+ # TODO-D 72: Spurious per-attribute divider paths on basic.qea outlier
2
+
3
+ ## Status: open
4
+
5
+ basic.qea diagram "Two Level Class Composition Hierarchy with
6
+ Attributes" (4FC1D352-...) over-renders 16 short horizontal <path>
7
+ elements that the EA reference does not emit.
8
+
9
+ ## Symptom
10
+
11
+ - rect: ours=18 ref=18 (matches)
12
+ - path: ours=50 ref=34 (+16 overshoot)
13
+ - polygon: ours=17 ref=17 (matches)
14
+ - text: ours=102 ref=102 (matches)
15
+
16
+ ## Pattern of the extra paths
17
+
18
+ All 16 extras are short 110px-wide horizontal lines at evenly
19
+ spaced y coordinates that line up with attribute rows:
20
+
21
+ - M 661 66 L 771 66
22
+ - M 661 152 L 771 152
23
+ - M 661 238 L 771 238
24
+ - M 487 66 L 597 66
25
+ - M 487 152 L 597 152
26
+ - ... (12 more at the same y values across 4 element columns)
27
+
28
+ ## Hypothesis
29
+
30
+ We render per-attribute separator lines between each attribute row.
31
+ EA only emits a single header→content divider plus the element rect
32
+ outline; attribute rows are NOT visually separated by horizontal
33
+ lines in EA's encoding.
34
+
35
+ ## Next step
36
+
37
+ Audit Compartment::Attributes and DividerRenderer for any per-row
38
+ line emission. The fix is to suppress row separators and keep only
39
+ the header divider.
@@ -0,0 +1,69 @@
1
+ # TODO-D 73: Plateau polygon under-render (-4)
2
+
3
+ ## Status: partially investigated (2026-08-02)
4
+
5
+ Across 188 plateau diagrams, we render 4 fewer `<polygon>` elements
6
+ than EA's reference SVG. Per-diagram deltas:
7
+
8
+ - Appearance (BC1F7E00, C31C1314): -2 each
9
+ - CityGMLCore (88D0CB44): -1
10
+ - 都市計画決定情報の概要 (8FD488EF): -1
11
+ - 立体的な範囲、区域界、品質属性 (1321F39B): -1
12
+ - 都市施設 (C96CBC24): -1
13
+ - 3D都市モデル応用スキーマと他のスキーマとの関係 (DFBB1072): +3
14
+ - udx (6481E2CC): +1
15
+
16
+ ## Investigation update (2026-08-02)
17
+
18
+ For 都市施設 / 都市計画決定情報 / 立体的な範囲: each missing
19
+ polygon is a small 4-point DIAMOND inside an element body.
20
+
21
+ Example (都市施設):
22
+ `<polygon points="323 401 328 411 333 401 328 391" ...>`
23
+ Inside a `<g>` with fill="#FAF1EC" stroke="#69738C"
24
+
25
+ These colors (#FAF1EC, #69738C) are NOT standard aggregation
26
+ diamond colors (#FFFFFF fill, #000000 stroke). They appear to be
27
+ **stereotype decorator icons** — small symbolic icons EA renders
28
+ inside element bodies when a stereotype provides a custom icon.
29
+
30
+ ## Follow-up investigation (2026-08-02)
31
+
32
+ Found EA installation at:
33
+ ~/Library/Application Support/CrossOver/Bottles/
34
+ Enterprise Architect 16.x/drive_c/Program Files/Sparx Systems/EA/
35
+
36
+ Located stereotype-related files:
37
+ - Config/GML/GMLStereotypes.xml — only stereotype ALIASES, no icons
38
+ - MDGTechnologies/*.xml — many MDG files, none reference icons
39
+ - TemplateResources161.dll — likely contains compiled icon resources
40
+ - t_stereotypes table — empty Metafile BLOBs for FeatureType
41
+
42
+ Found element-style flag `HideIcon=0` on FeatureType elements on
43
+ 都市施設 — confirmed EA DOES intend to show an icon.
44
+
45
+ ## Discriminator puzzle
46
+
47
+ On 都市施設, ALL 21 placed FeatureType elements have HideIcon=0.
48
+ But ref renders the diamond icon for only 1 of them
49
+ (CollectiveFacilitiesForReconstruction — the largest element).
50
+
51
+ The discriminator is NOT:
52
+ - HideIcon flag (all elements have it = 0)
53
+ - Stereotype (all are FeatureType)
54
+ - Element size (icon position is element-relative)
55
+
56
+ Hypotheses for the actual discriminator:
57
+ 1. The element is "selected" or "active" in the source QEA
58
+ 2. The element is the diagram's "subject" (a per-diagram flag)
59
+ 3. The icon is part of a legend/key, not per-element
60
+
61
+ ## Implementation needed
62
+
63
+ To close this gap requires either:
64
+ 1. Reverse-engineering EA's stereotype decorator icon logic
65
+ 2. Parsing the EMF BLOB from t_image (1 image, 69KB)
66
+ 3. Extracting icon resources from EA.exe / TemplateResources161.dll
67
+
68
+ Even then, the discriminator for WHICH elements get icons is
69
+ unclear from available data.
@@ -0,0 +1,22 @@
1
+ # TODO-D 74: Plateau rect over-render (+4)
2
+
3
+ ## Status: open
4
+
5
+ Across 188 plateau diagrams, we render 4 more `<rect>` elements
6
+ than EA's reference SVG. Per-diagram deltas are spread thin.
7
+
8
+ ## Likely causes
9
+
10
+ 1. **Phantom connector label boxes**: my phantom connector code
11
+ synthesizes label boxes (LLB/LLT) that may render extra rects.
12
+ 2. **Element rect for hidden elements**: elements that should be
13
+ filtered (e.g., via element_filter) but still render their
14
+ bounding rects.
15
+ 3. **Compartment background rects**: extra rects for compartments
16
+ that EA suppresses in certain modes.
17
+
18
+ ## Next step
19
+
20
+ Identify the 4 specific diagrams with rect_delta > 0 and inspect
21
+ the actual `<rect>` content vs ref. Likely a per-diagram PDATA
22
+ flag mismatch.
@@ -0,0 +1,39 @@
1
+ # TODO-D 75: Plateau text under-render (-36)
2
+
3
+ ## Status: open (partial — closed 62 of original -98 in TODO-D 71)
4
+
5
+ Across 188 plateau diagrams, we render 36 fewer `<text>` elements
6
+ than EA's reference SVG. Top undershoot diagrams:
7
+
8
+ - tran_2 (-4): missing 2× RoadAttribute, 1× TransportationComplex,
9
+ 1× _TransportationObject, 1× TrafficAreaAttribute
10
+ - urf_urbanFunction (-4): similar pattern
11
+ - 12 diagrams at -3 each
12
+ - many at -2
13
+
14
+ ## Root cause
15
+
16
+ The foreign-package rule in `off_canvas_parent_name_for` is too
17
+ aggressive. It suppresses parent ghosts when ANY placed element
18
+ shares the parent's package, but EA actually renders ghosts in
19
+ this case for diagrams like tran_2 and urf_urbanFunction.
20
+
21
+ The discriminator is narrower than "package represented" — possibly
22
+ related to whether the parent is in a base library (gml) vs a user
23
+ package (uro, tran), or some other property of the parent class.
24
+
25
+ ## What was tried
26
+
27
+ 1. **Just HideParents flag**: closed -98 to +60 (over-rendered 60).
28
+ 2. **HideParents + foreign-package check**: closed +60 to -36
29
+ (under-rendered 36).
30
+
31
+ The truth is between these. Narrower discriminator needed.
32
+
33
+ ## Deferred
34
+
35
+ Requires identifying the precise EA rule. Could be:
36
+ - A t_object flag on the parent (e.g., is it generic/template)
37
+ - The parent's package being a "base library" (gml vs user model)
38
+ - A specific stereotype pattern (e.g., base GML stereotypes)
39
+ - Connector-level metadata we're not yet reading