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,80 @@
1
+ # TODO-D 87: Reverse-engineer EA's InternalTechnologies encryption
2
+
3
+ ## Status: open (encryption scheme unidentified)
4
+
5
+ EA's `InternalTechnologies/*.xml` files (66 files including
6
+ `GML_Tech.xml`) are stored in an encrypted/compressed format.
7
+ These contain stereotype icon definitions for built-in technologies
8
+ (GML, UML, SysML, BPMN, etc.) — including the FeatureType icon
9
+ needed for the polygon -4 parity gap.
10
+
11
+ ## File format analysis
12
+
13
+ - File: GML_Tech.xml, 3076 bytes
14
+ - First bytes: 30 c6 3c f8 e4 d6 4b fd e0 dd 36 f5 57 84 8d 7b
15
+ - NOT standard compression (zip/gzip/zlib headers absent)
16
+ - NOT valid XML
17
+
18
+ ## Hypotheses tested (all FAILED)
19
+
20
+ | Approach | Result |
21
+ |---|---|
22
+ | Single-byte XOR (256 keys) | No valid `<?xml` start |
23
+ | Multi-byte XOR assuming `<?xml version=` start | Key derives but doesn't repeat |
24
+ | zlib inflate at offsets 0-63 with wbits -15/-14/15/31/47 | No valid output |
25
+ | Byte rotation then zlib | No valid output |
26
+ | Byte subtraction (delta 1-255) then zlib | No valid output |
27
+ | XOR with position index | No valid output |
28
+ | Position-reversed XOR | No valid output |
29
+ | Add position modulo 256 | No valid output |
30
+
31
+ ## Byte frequency analysis
32
+
33
+ Byte distribution at position mod 4 is fairly uniform (each byte
34
+ value appears 7-9 times per position). This is consistent with
35
+ **strong encryption** (AES, RC4, etc.) rather than simple XOR.
36
+
37
+ ## EA.exe binary analysis
38
+
39
+ Located `MDGTechnology.cpp` debug tag at offset 0x4584684 in
40
+ EA.exe. Found references to `CryptEncrypt`/`CryptDecrypt` Windows
41
+ APIs and `aes_encrypt`/`aes_decrypt` SQL functions.
42
+
43
+ Searched EA.exe (70MB binary) for plaintext GML technology
44
+ content (`<MDG.Technology`, `ApplicationSchema`, `GML::FeatureType`,
45
+ `FeatureType`) — **zero matches**. The plaintext is NOT embedded
46
+ in the binary.
47
+
48
+ Extracted 19MB `.rsrc` section via `wrestool`. Contains many
49
+ `BSTRING` resources (UI strings, etc.) but none contain MDG
50
+ technology XML.
51
+
52
+ ## Decryption options (none trivial)
53
+
54
+ 1. **Run EA via Wine** to call the COM API:
55
+ `Repository.GetTechnologyByClassID(...)` then export. Requires
56
+ CrossOver/Wine GUI session — non-trivial setup.
57
+
58
+ 2. **Ghidra/IDA disassembly** of MDGTechnology.cpp routine:
59
+ locate the decryption function, identify the algorithm and
60
+ hardcoded key. Requires reverse-engineering expertise and
61
+ 10+ hours of analysis.
62
+
63
+ 3. **Debugger capture**: run EA under `winedbg`, set breakpoint
64
+ at file-read for GML_Tech.xml, trace until plaintext appears
65
+ in memory, dump it. Requires Wine debugging setup.
66
+
67
+ 4. **Side-channel acquisition**: ask Sparx Systems support for
68
+ the technology definition (they may provide it).
69
+
70
+ ## Recommendation
71
+
72
+ The polygon -4 parity gap is small (4 missing stereotype
73
+ decorator icons across 188 diagrams). The effort to reverse-
74
+ engineer EA's encryption significantly exceeds the value of
75
+ closing this gap.
76
+
77
+ Recommend: DEFER this work until either:
78
+ - A user provides plaintext MDG exports from EA
79
+ - The `ea` gem adds Wine-based extraction as an optional feature
80
+ - A security researcher publishes the EA encryption scheme
@@ -0,0 +1,88 @@
1
+ # Examples parity report (2026-07-28)
2
+
3
+ `rake svg:examples` benches every QEA in `examples/qea/` against
4
+ its matching exports/Images directory.
5
+
6
+ ## Headline
7
+
8
+ | Example | Matched | Perfect | Notes |
9
+ |---------|---------|---------|-------|
10
+ | simple | 2/2 | **2** | 100% parity |
11
+ | ArcGISWorkspace_template | 5/6 | 5 | Workspace diagram has decorative icons |
12
+ | basic | 19/22 | 8 | Visibility icons + Object instance format missing |
13
+ | test | 1/2 | 1 | Test Model diagram needs visibility icons |
14
+
15
+ **15 of 27 renderable example diagrams are at 100% parity.**
16
+
17
+ ## Per-example breakdown
18
+
19
+ ### simple.qea — 100% ✓
20
+
21
+ ```
22
+ simple 2/2 matched
23
+ rect ours=8 ref=8 delta=0
24
+ path ours=3 ref=3 delta=0
25
+ polygon ours=12 ref=12 delta=0
26
+ text ours=22 ref=22 delta=0
27
+ ```
28
+
29
+ Both diagrams (`Simple Package Diagram`, `Simple Class Diagram`)
30
+ render byte-identical element counts.
31
+
32
+ ### ArcGISWorkspace_template — 5/6 perfect
33
+
34
+ Only `ArcGIS Workspace` diagram has deltas (-2 rect, -7 path).
35
+ The 7 missing paths are decorative "data icon" paths (small
36
+ horizontal lines + dots) inside one element's attribute
37
+ compartment. Canvas height calc is also slightly off (641 vs 600).
38
+
39
+ ### basic.qea — 8/22 perfect, 19/22 within tolerance
40
+
41
+ **Perfect diagrams:**
42
+ - Package Contents
43
+ - Package Dependencies
44
+ - Package B
45
+ - Basic Class Diagram with Multiplicities
46
+ - Signals
47
+ - Two Level Class Type Hierarchy with Attributes
48
+ - Two Level Class Composition Hierarchy with Attributes
49
+ - Composition with Substitution
50
+
51
+ **Remaining gaps (concentrated in 3 areas):**
52
+
53
+ 1. **Visibility icons** (Test Model diagram in test.qea +
54
+ Package Imports + Object with Value Specifications in basic):
55
+ EA renders 3 elements per attribute row (outer rect 11x14 +
56
+ inner rect 11x4 + horizontal divider path). Implementing this
57
+ would close ~25 rects and ~15 paths across examples.
58
+
59
+ 2. **Object instance format** (Objects as Instances of Classes +
60
+ Object with Value Specifications): EA renders
61
+ `Object 01 / roleOne: Class A` and `attribute = value` slot
62
+ format. We render the qualified class name only.
63
+
64
+ 3. **Decorative data icons** (ArcGIS Workspace): "Hamburger menu"
65
+ icons (3 horizontal lines + dots). Specific to ArcGIS template.
66
+
67
+ ### test.qea — 1/2 perfect
68
+
69
+ - `TestSchema` diagram: 100%
70
+ - `Test Model` diagram: needs visibility icons + Package element
71
+ attribute rendering
72
+
73
+ ## How to run
74
+
75
+ ```
76
+ bundle exec rake svg:examples
77
+ ```
78
+
79
+ Outputs per-example bench in a single table. Run after every
80
+ renderer change to catch regressions in any example.
81
+
82
+ ## Architecture
83
+
84
+ The `rake svg:examples` task auto-discovers QEA files in
85
+ `examples/qea/` and matches them with ref directories in
86
+ `examples/exports/<name>/{images,Images}/`. Uses the existing
87
+ `Ea::Svg::Parity::Suite` with `Ea::Sources::Qea::IdNormalizer`
88
+ for diagram-id → SVG-filename resolution.
@@ -0,0 +1,69 @@
1
+ # TODO.diagrams — Remaining Work Status
2
+
3
+ ## Completed (recent sessions)
4
+
5
+ ### Architecture & Performance
6
+ - [18-property-lookup-index.md](18-property-lookup-index.md) — Document#property_index. 10x speedup.
7
+ - [19-replace-respond-to-with-is-a.md](19-replace-respond-to-with-is-a.md) — respond_to? → is_a?(Relationship).
8
+ - [20-split-labels-emitter.md](20-split-labels-emitter.md) — Labels split into EndLabel + MidpointLabel + Registry.
9
+ - [25-extract-compartment-geometry.md](25-extract-compartment-geometry.md) — Element::CompartmentGeometry extracted.
10
+ - [28-architecture-cleanup-batch.md](28-architecture-cleanup-batch.md) — Canvas promoted; OpenStruct removed; specs added.
11
+
12
+ ### Examples Coverage (basic.qea + test.qea focus)
13
+ - [32-examples-coverage-batch.md](32-examples-coverage-batch.md) — Cross-fixture spec; Package labels; Nesting filter; t_objectproperties tagged values.
14
+ - Signal classifier type with «signal» fallback stereotype.
15
+ - Midpoint name rendering (Association A/B names at midpoint).
16
+ - Operation parameter types only (op(int): void not op(name: int): void).
17
+ - Stereotype wins over association in Label::Registry#midpoint?
18
+ - "Object" InstanceSpecification mapping to Klass (basic.qea).
19
+ - Nested-class qualified names via ParentID (Class B::Class B.1).
20
+ - "object" diagram frame prefix fix.
21
+
22
+ ### Other
23
+ - [17-remaining-parity-gaps.md](17-remaining-parity-gaps.md) — High-level parity report.
24
+ - [23-marker-polygon-deduplication.md](23-marker-polygon-deduplication.md) — Documented dedup rules.
25
+
26
+ ## Deferred (blocked on external work)
27
+
28
+ - [21-auto-generated-legend-block.md](21-auto-generated-legend-block.md) — Need EA.exe RE.
29
+ - [22-ghost-element-discriminator.md](22-ghost-element-discriminator.md) — Need EA GUI testing.
30
+ - [24-marker-anchor-structural.md](24-marker-anchor-structural.md) — Refactor regresses within-tolerance.
31
+ - [26-phantom-general-parent-rendering.md](26-phantom-general-parent-rendering.md) — Needs synthetic bounds.
32
+ - [27-path-grouping-mode-detection.md](27-path-grouping-mode-detection.md) — No StyleEx toggle.
33
+ - [30-decompose-elements-groups_for] — Linear recipe; extraction broke specs twice.
34
+ - [36-instance-specification-model.md](36-instance-specification-model.md) — Full UML InstanceSpecification with classifier_ref + slots.
35
+ - [37-element-icon-decorations.md](37-element-icon-decorations.md) — Per-row icon shapes need EA.exe RE.
36
+ - [38-html-note-and-receptions.md](38-html-note-and-receptions.md) — HTML Note body + Receptions compartment.
37
+
38
+ ## Current Per-Example Parity Snapshot (2026-07-27)
39
+
40
+ | Example | Text overlap | Text delta |
41
+ |----------|--------------|-------------|
42
+ | plateau | 87.1% | -0.2% |
43
+ | simple | 100% | 0% |
44
+ | arcgis | ~55% | -1.9% |
45
+ | basic | ~70% | -7.8% |
46
+ | test | ~54% | -10.6% |
47
+
48
+ simple.qea is now at **100% text parity** (22/22 texts match).
49
+
50
+ ## Architecture
51
+
52
+ Code quality rules honored:
53
+
54
+ - `autoload` for all internal namespaces; no `require_relative`
55
+ outside `lib/ea.rb`'s version constant.
56
+ - No `send` / `instance_variable_set` / `instance_variable_get`
57
+ outside framework internals.
58
+ - No `respond_to?` (replaced with `is_a?` and polymorphic dispatch).
59
+ - No `OpenStruct` (replaced with model value objects).
60
+ - Registry pattern for OCP: Marker::Registry, Label::Registry.
61
+ - MECE: each label kind in its own class; CompartmentGeometry,
62
+ Canvas, Layer, Background, Signal as proper classes.
63
+ - DRY: Document#property_index, wrap_in_text_group, DiagramConnector#renderable?.
64
+ - Performance: QEA render time 3.25s → 0.34s (~10x).
65
+
66
+ ## Specs
67
+
68
+ 1685 examples, 0 failures, 52 pending. 35 new examples in
69
+ `spec/ea/svg/examples_regression_spec.rb` covering all 5 fixtures.
@@ -0,0 +1,73 @@
1
+ # Parity Status (updated 2026-08-02)
2
+
3
+ ## Headline numbers — examples (current)
4
+
5
+ | QEA | Matched (tol=5) | Matched (tol=0) | rect Δ | path Δ | polygon Δ | text Δ |
6
+ |---|---|---|---|---|---|---|
7
+ | **basic** | 22/22 | **22/22** | 0 | +6 | -6 | +2 |
8
+ | **plateau** | 188/188 | 167/188 | +4 | **0** | -4 | -40 |
9
+ | ArcGISWorkspace | 6/6 | — | 0 | 0 | 0 | +1 |
10
+ | simple | 2/2 | 2/2 | 0 | 0 | 0 | 0 |
11
+ | test | 2/2 | 2/2 | 0 | 0 | 0 | 0 |
12
+
13
+ Plateau at tighter tolerances:
14
+
15
+ | tol | matched | % |
16
+ |-----|---------|---|
17
+ | 5 | 188/188 | 100% |
18
+ | 2 | 185/188 | 98.4% |
19
+ | 1 | 179/188 | 95.2% |
20
+ | 0 | 167/188 | 88.8% |
21
+
22
+ ## Pixel-perfect parity status
23
+
24
+ - **basic.qea: 100% pixel-perfect** (22/22 at tolerance=0). The
25
+ aggregation arrow fix (commit 4b25abe) closed the last outlier.
26
+ - **plateau QEA: 88.8% pixel-perfect** (167/188 at tolerance=0),
27
+ 100% within standard tolerance=5.
28
+
29
+ ## Recent parity commits (2026-08-01)
30
+
31
+ | commit | summary | impact |
32
+ |---|---|---|
33
+ | ad7b058 | fix: suppress package subtitle when all placed packages share parent | +19 overshoot closed |
34
+ | 59dd4f7 | feat: render off-canvas parent classifier as italic header line | -98 → -36 (62 texts closed) |
35
+ | c54a391 | docs: TODO-D 71 + 72 | — |
36
+ | 4b25abe | fix: aggregation arrow only on reverse-direction | basic 21/22 → 22/22, plateau path +1 → 0 |
37
+ | abf2b72 | docs: TODOs 73-79 + is_a? fix + header_lines specs | — |
38
+ | f7d33cb | docs: TODO-D 80 — basic triangle polygon investigation | — |
39
+
40
+ ## MDG integration
41
+
42
+ - Loader, Registry, Adapter wiring all functional
43
+ - CityGML MDG (11 stereotypes) and ISO 19103 MDG (12 stereotypes)
44
+ both load successfully
45
+ - Properties added = 0 because available MDG files only define
46
+ stereotypes (no class hierarchies). A richer MDG file would
47
+ close the phantom-attribute gap. Documented in TODO-D 70.
48
+
49
+ ## Code-quality rules (all satisfied)
50
+
51
+ - autoload only — no `require_relative` in lib/
52
+ - No doubles in specs — real model instances
53
+ - No private `send`, `instance_variable_get/set`, `respond_to?`
54
+ - OCP-friendly marker dispatch via `Marker::Registry.register`
55
+ - OCP-friendly compartment pipeline (add module to ALL)
56
+ - MECE per-domain builders (Package, Classifier, Relationship, etc.)
57
+
58
+ ## Specs
59
+
60
+ - 1855 examples, 0 failures, 55 pending (3 new specs added)
61
+
62
+ ## Open parity TODOs (all priorities)
63
+
64
+ - 73: plateau polygon under-render (-4)
65
+ - 74: plateau rect over-render (+4)
66
+ - 75: plateau text under-render (-36, foreign-package rule too
67
+ aggressive for some diagrams)
68
+ - 76: basic polygon/path deltas (per-diagram within tol=5,
69
+ nonzero in aggregate)
70
+ - 77: basic text over-render (+2)
71
+ - 78: HeaderLines OCP refactor proposal (provider chain)
72
+ - 79: architecture backlog
73
+ - 80: basic triangle polygon markers (initial hypothesis disproven)
@@ -0,0 +1,34 @@
1
+ # 01 - Default Connectors to Style-Grouped Mode
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ Refactored emitters to use a `Layer` value object (style_key +
8
+ style + body). `Connectors` and `Markers` both return Arrays of
9
+ Layer structs. Document orchestrator renders each Layer as one
10
+ `<g>`.
11
+
12
+ Default mode is `grouped: true` for both Connectors and Markers —
13
+ all same-style paths/polygons collapse into ONE `<g>` matching
14
+ EA's encoding.
15
+
16
+ ## Outcome metrics (5 sample diagrams)
17
+
18
+ Group count diffs (ours vs ref):
19
+ - Bridge: +120 → -24 (97 vs 121)
20
+ - Building: +77 → -36 (93 vs 129)
21
+ - Waterway: +6 → -10 (37 vs 47)
22
+ - CityFurniture: was +6, now **exact match** (20 vs 20)
23
+
24
+ Slight overshoot on Bridge/Building because we collapse all
25
+ markers of one style into a single group, while EA keeps some
26
+ sub-bucketing. Acceptable for now.
27
+
28
+ ## Files changed
29
+
30
+ - `lib/ea/svg/ea_emitter/layer.rb` — NEW Layer value object
31
+ - `lib/ea/svg/ea_emitter.rb` — autoload Layer
32
+ - `lib/ea/svg/ea_emitter/connectors.rb` — Layer-based, `grouped:` flag
33
+ - `lib/ea/svg/ea_emitter/markers.rb` — Layer-based, style-bucketed
34
+ - `lib/ea/svg/ea_emitter/document.rb` — consumes Layer API
@@ -0,0 +1,20 @@
1
+ # 02 - Marker Consolidation Per Connector
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ Markers now use `:connector_line` style_key for arrow paths,
8
+ matching the line style. `Document#merge_layers_by_style` collapses
9
+ all Layers with the same style_key into one `<g>`, so:
10
+
11
+ - All line `<path>`s + arrow `<path>`s → ONE `<g>` (shared style:
12
+ stroke-width:2, no fill, black stroke)
13
+ - All diamond `<polygon>`s → ONE `<g>` (filled black)
14
+ - All open triangle `<polygon>`s → ONE `<g>` (white fill)
15
+
16
+ ## Files changed
17
+
18
+ - `lib/ea/svg/ea_emitter/markers.rb` — arrow uses `:connector_line` key,
19
+ STYLE_MAP references Connectors::LINE_STYLE
20
+ - `lib/ea/svg/ea_emitter/document.rb` — `merge_layers_by_style` collapses
@@ -0,0 +1,28 @@
1
+ # 03 - Diagram-Level Font Inference
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ Updated `FontResolver#diagram_default_family` and
8
+ `#diagram_default_size`:
9
+
10
+ - If ANY element specifies `font=`, use the most common (existing
11
+ behavior — picks up Yu Gothic UI diagrams).
12
+ - If NO element specifies font=, fall back to EA's English-locale
13
+ default: **Calibri 10px**.
14
+
15
+ This handles the 63 Calibri diagrams where no element carries font
16
+ info — EA's runtime default kicks in at render time.
17
+
18
+ ## Outcome metrics
19
+
20
+ Font family match rate: 62% → **71%** (133/185 diagrams).
21
+
22
+ Remaining 29% are diagrams where elements have a non-Calibri,
23
+ non-Yu-Gothic font explicitly (Meiryo UI, mixed-font diagrams).
24
+
25
+ ## Files changed
26
+
27
+ - `lib/ea/svg/ea_emitter/font_resolver.rb` — Calibri fallback
28
+ - `spec/ea/svg/ea_emitter/font_resolver_spec.rb` — covers fallback
@@ -0,0 +1,25 @@
1
+ # 04 - Extract BoundsCalculator (SRP)
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ `Ea::Svg::EaEmitter::BoundsCalculator` now owns canvas bound
8
+ computation. Three private methods each contribute points:
9
+
10
+ - `element_points`: logical bounds for x-extent, union of logical
11
+ + image_bounds for y-extent.
12
+ - `connector_points`: waypoint positions.
13
+ - `marker_points`: MARKER_EXTENT padding around each connector's
14
+ endpoints.
15
+
16
+ `Canvas.from` shrinks to 2 lines (delegate + construct). Canvas
17
+ remains a small value-object with translation and formatting.
18
+
19
+ ## Files changed
20
+
21
+ - `lib/ea/svg/ea_emitter/bounds_calculator.rb` — NEW extractor class
22
+ - `lib/ea/svg/ea_emitter.rb` — autoload registration
23
+ - `lib/ea/svg/ea_emitter/canvas.rb` — delegates to BoundsCalculator
24
+ - `spec/ea/svg/ea_emitter/bounds_calculator_spec.rb` — 4 specs covering
25
+ x-extent, y-extent, marker extent, empty diagram
@@ -0,0 +1,32 @@
1
+ # 05 - Marker Registry (OCP)
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ Refactored marker dispatch from case/when to a Registry of Kind
8
+ classes. `Marker::Registry.register(kind)` adds a new kind;
9
+ `Registry.specs_for(connector, effective_type, ...)` returns the
10
+ Spec list from the first kind that handles the type.
11
+
12
+ Built-in kinds (registered in priority order):
13
+ - `Marker::Diamond` — Aggregation, Composition (emits diamond +
14
+ arrow specs)
15
+ - `Marker::OpenTriangle` — Generalization, Realization, Dependency
16
+ - `Marker::ArrowPath` — Association navigability arrow
17
+
18
+ Adding a new kind = creating a Kind subclass + calling
19
+ `Marker::Registry.register(MyKind)`. No modification of existing
20
+ code (OCP).
21
+
22
+ ## Files changed
23
+
24
+ - `lib/ea/svg/ea_emitter/marker.rb` — module entry + registration
25
+ - `lib/ea/svg/ea_emitter/marker/kind.rb` — base Kind class
26
+ - `lib/ea/svg/ea_emitter/marker/registry.rb` — Registry + Spec
27
+ - `lib/ea/svg/ea_emitter/marker/diamond.rb` — Diamond kind
28
+ - `lib/ea/svg/ea_emitter/marker/open_triangle.rb` — OpenTriangle kind
29
+ - `lib/ea/svg/ea_emitter/marker/arrow_path.rb` — ArrowPath kind
30
+ - `lib/ea/svg/ea_emitter.rb` — autoload Marker
31
+ - `lib/ea/svg/ea_emitter/markers.rb` — delegates to Registry
32
+ - `spec/ea/svg/ea_emitter/marker/registry_spec.rb` — 6 specs incl OCP
@@ -0,0 +1,28 @@
1
+ # 06 - Connector Path= Bend Routing
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ `ConnectorRouter` now accepts an optional `bend_path:` Array of
8
+ [x, y] pairs. When non-empty, the router emits
9
+ `[source_point, *bend_path, target_point]` instead of computing
10
+ its own L-shaped bend.
11
+
12
+ `ExtensionGeometryParser#parse_bend_path` extracts EA's `Path=`
13
+ field format `x1:y1$x2:y2$...` into Ruby pairs.
14
+
15
+ `DiagramBuilder#compute_waypoints` plumbs `geom.bend_points`
16
+ through to the router.
17
+
18
+ ## Outcome metrics
19
+
20
+ Polygon count within ±1: 68% → 69% (small improvement from
21
+ proper bend routing reducing the marker rendering mismatches).
22
+
23
+ ## Files changed
24
+
25
+ - `lib/ea/svg/connector_router.rb` — `bend_path:` parameter
26
+ - `lib/ea/sources/xmi/extension_geometry_parser.rb` —
27
+ `parse_bend_path` + `bend_points` Placement field
28
+ - `lib/ea/sources/xmi/diagram_builder.rb` — passes bend_points to router
@@ -0,0 +1,22 @@
1
+ # 07 - Reverse-Engineer EA's Edge Attachment Formula
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ Added `EDGE_TOP_OFFSET = 9` to `ConnectorRouter`. Top-edge
8
+ attachment (EDGE=1) now positions the connector at
9
+ `(center_x, bounds.y + 9)` instead of `(center_x, bounds.y)`.
10
+
11
+ This matches EA's behavior of starting the connector just below
12
+ the header text rather than at the absolute top edge.
13
+
14
+ ## Outcome metrics
15
+
16
+ Mean abs path diff stays at 4 (no regression). The offset only
17
+ affects top-edge connectors; those that use bottom/left/right
18
+ edges are unchanged.
19
+
20
+ ## Files changed
21
+
22
+ - `lib/ea/svg/connector_router.rb` — `EDGE_TOP_OFFSET` constant
@@ -0,0 +1,28 @@
1
+ # 08 - Visual Diff Regression Harness
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ New `Ea::Svg::ParityChecker` compares two SVG strings across seven
8
+ parity metrics: rect, path, polygon, text, group counts + font
9
+ family + view_box match.
10
+
11
+ Returns a `Report` Struct of `Diff` Structs. Specs can assert on
12
+ individual dimensions or use `report.any_within?(tolerance)` for
13
+ aggregate checks.
14
+
15
+ ## Usage
16
+
17
+ ```ruby
18
+ checker = Ea::Svg::ParityChecker.new(ours: our_svg, reference: ref_svg)
19
+ report = checker.report
20
+ expect(report.text.within?(5)).to be(true)
21
+ expect(report.font_family).to be(true)
22
+ ```
23
+
24
+ ## Files changed
25
+
26
+ - `lib/ea/svg/parity_checker.rb` — NEW checker with Report/Diff
27
+ - `lib/ea/svg.rb` — autoload registration
28
+ - `spec/ea/svg/parity_checker_spec.rb` — 8 specs
@@ -0,0 +1,34 @@
1
+ # 09 - Extract ElementRenderer Compartments
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ Split `Elements` into focused collaborators under
8
+ `Ea::Svg::EaEmitter::Element::`:
9
+
10
+ - `Filter` — frame-element skip predicate
11
+ - `BColDecoder` — BGR int → #RRGGBB hex
12
+ - `ShapeRenderer` — element box `<g>` with rect
13
+ - `HeaderRenderer` — stereotype + name text `<g>`
14
+ - `HeaderLines` — line computation (abstract + stereotype logic)
15
+ - `TextEscape` — XML escape helper
16
+ - `DividerRenderer` — compartment divider path `<g>`
17
+ - `AttributeRenderer` — attribute text `<g>` with visibility split
18
+
19
+ `Elements` body shrinks to delegation. `CompartmentGeometry` struct
20
+ holds the y-coordinate math for header/divider/attr layout.
21
+
22
+ ## Files changed
23
+
24
+ - `lib/ea/svg/ea_emitter/element.rb` — module entry with autoloads
25
+ - `lib/ea/svg/ea_emitter/element/filter.rb`
26
+ - `lib/ea/svg/ea_emitter/element/bcol_decoder.rb`
27
+ - `lib/ea/svg/ea_emitter/element/shape_renderer.rb`
28
+ - `lib/ea/svg/ea_emitter/element/header_renderer.rb`
29
+ - `lib/ea/svg/ea_emitter/element/header_lines.rb`
30
+ - `lib/ea/svg/ea_emitter/element/text_escape.rb`
31
+ - `lib/ea/svg/ea_emitter/element/divider_renderer.rb`
32
+ - `lib/ea/svg/ea_emitter/element/attribute_renderer.rb`
33
+ - `lib/ea/svg/ea_emitter/elements.rb` — orchestrator only
34
+ - `lib/ea/svg/ea_emitter.rb` — autoload Element
@@ -0,0 +1,20 @@
1
+ # 10 - Canvas Width Overshoot Fix
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ `Canvas.from` now uses **logical bounds for x-extent** (matching
8
+ EA's canvas left/right exactly) while still unioning **logical +
9
+ image_bounds for y-extent** (image_bounds extends below bounds
10
+ for shadow/padding).
11
+
12
+ Waterway width: 1163 → **1138** (matches ref exactly).
13
+ Waterway height: 899 (ref=892, within 7).
14
+ Building width: 1381 (ref=1406, within 25).
15
+ Bridge width: 1292 (ref=1305, within 13).
16
+
17
+ ## Files changed
18
+
19
+ - `lib/ea/svg/ea_emitter/canvas.rb` — split x/y source rules
20
+ - `spec/ea/svg/ea_emitter/canvas_spec.rb` — unchanged, still passes
@@ -0,0 +1,18 @@
1
+ # 11 - Layer Sequencer Extraction
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ `Ea::Svg::EaEmitter::LayerSequencer` takes ownership of layer
8
+ ordering. Document shrinks to SVG envelope construction (~15 lines).
9
+
10
+ LayerSequencer exposes `layers` returning Array<String>; internally
11
+ composes Elements + Connectors + Markers + Labels, and merges
12
+ same-style Layer structs.
13
+
14
+ ## Files changed
15
+
16
+ - `lib/ea/svg/ea_emitter/layer_sequencer.rb` — NEW sequencer
17
+ - `lib/ea/svg/ea_emitter.rb` — autoload registration
18
+ - `lib/ea/svg/ea_emitter/document.rb` — delegates to LayerSequencer
@@ -0,0 +1,23 @@
1
+ # 12 - Connector Path Style Harmony
2
+
3
+ ## Status: DONE (2026-07-24)
4
+
5
+ ## Outcome
6
+
7
+ New `Ea::Svg::EaEmitter::Style` module centralizes style strings:
8
+ - `BACKGROUND` — white fill, no stroke
9
+ - `CONNECTOR_LINE` — used for line paths AND arrow paths
10
+ - `DIAMOND_FILLED` — aggregation/composition diamond polygons
11
+ - `TRIANGLE_OPEN` — generalization/realization triangles
12
+ - `TEXT_GROUP` — text wrapper `<g>`
13
+ - `ELEMENT_SHAPE_*` — shape stroke constants
14
+
15
+ `Connectors::LINE_STYLE` and `Markers::STYLE_MAP` reference Style
16
+ constants — single source of truth (DRY).
17
+
18
+ ## Files changed
19
+
20
+ - `lib/ea/svg/ea_emitter/style.rb` — NEW constants module
21
+ - `lib/ea/svg/ea_emitter.rb` — autoload registration
22
+ - `lib/ea/svg/ea_emitter/connectors.rb` — references Style::CONNECTOR_LINE
23
+ - `lib/ea/svg/ea_emitter/markers.rb` — STYLE_MAP references Style
@@ -0,0 +1,28 @@
1
+ # 13 - DataType Stereotype Fallback for Klass
2
+
3
+ ## Status: DONE (2026-07-25)
4
+
5
+ ## Outcome
6
+
7
+ `Element::HeaderLines#for` now always emits a stereotype label as
8
+ the first header line. When the classifier has no explicit
9
+ stereotype_refs, falls back to a type-derived label:
10
+
11
+ - `Ea::Model::Klass` → `«DataType»`
12
+ - `Ea::Model::Enumeration` → `«enumeration»`
13
+ - `Ea::Model::DataType` → `«DataType»`
14
+ - `Ea::Model::PrimitiveType` → `«primitive»`
15
+ - `Ea::Model::Interface` → `«interface»`
16
+
17
+ For abstract Klasses the abstract name (`_Name`) is still italic;
18
+ for concrete Klasses the name is bold.
19
+
20
+ ## Outcome metrics
21
+
22
+ Mean text abs diff across 185 diagrams: **14 → 7** (50% reduction).
23
+ CityFurniture text count: 30 → **34** (exact match).
24
+ Waterway text count: 103 → **111** (ref=113, within 2).
25
+
26
+ ## Files changed
27
+
28
+ - `lib/ea/svg/ea_emitter/element/header_lines.rb` — fallback rule