chemicalml 0.2.1 → 0.3.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 (347) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -0
  3. data/CLAUDE.md +49 -1
  4. data/README.adoc +154 -26
  5. data/TODO.align/61-parallel-array-attrs.md +54 -0
  6. data/TODO.align/62-per-element-attribute-gaps.md +49 -0
  7. data/TODO.align/63-universal-children-mixin.md +42 -0
  8. data/TODO.align/64-per-element-child-gaps.md +81 -0
  9. data/TODO.align/65-simple-unit-convention.md +40 -0
  10. data/TODO.align/66-schema24-legacy-children.md +32 -0
  11. data/TODO.align/67-final-verification.md +32 -0
  12. data/TODO.align/68-detection-coverage.md +33 -0
  13. data/TODO.align/69-json-yaml-roundtrip.md +27 -0
  14. data/TODO.align/70-iterative-walker.md +40 -0
  15. data/TODO.align/71-violation-value.md +25 -0
  16. data/TODO.align/72-close-child-gaps.md +66 -0
  17. data/TODO.align/73-schema24-parse-limitation.md +64 -0
  18. data/TODO.align/74-final-verification-round18.md +15 -0
  19. data/TODO.align/75-key-value-mappings.md +43 -0
  20. data/TODO.align/76-schema24-workaround.md +57 -0
  21. data/TODO.align/77-convention-coverage-matrix.md +31 -0
  22. data/TODO.align/78-fixture-audit.md +23 -0
  23. data/TODO.align/79-final-verification-round19.md +15 -0
  24. data/TODO.align/80-xsd-enum-constants.md +35 -0
  25. data/TODO.align/81-enum-validation-constraints.md +29 -0
  26. data/TODO.align/82-reference-resolver.md +33 -0
  27. data/TODO.align/83-toml-roundtrip.md +20 -0
  28. data/TODO.align/84-final-verification-round21.md +16 -0
  29. data/TODO.align/85-bond-distinct-atoms.md +25 -0
  30. data/TODO.align/86-references-should-resolve.md +20 -0
  31. data/TODO.align/87-cli-utility.md +26 -0
  32. data/TODO.align/88-diverse-fixtures.md +26 -0
  33. data/TODO.align/89-final-verification-round22.md +15 -0
  34. data/TODO.align/90-bond-stereo-completeness.md +31 -0
  35. data/TODO.align/91-atomparity-distinct.md +21 -0
  36. data/TODO.align/92-unit-dictionary-completeness.md +28 -0
  37. data/TODO.align/93-yard-docs.md +23 -0
  38. data/TODO.align/94-final-verification-round23.md +15 -0
  39. data/TODO.align/README.round17.md +28 -0
  40. data/TODO.align/README.round18.md +37 -0
  41. data/TODO.align/README.round19.md +40 -0
  42. data/TODO.align/README.round20.md +49 -0
  43. data/TODO.align/README.round21.md +35 -0
  44. data/TODO.align/README.round22.md +48 -0
  45. data/TODO.align/README.round23.md +46 -0
  46. data/TODO.align/README.round24.md +53 -0
  47. data/TODO.align/README.round25.md +66 -0
  48. data/TODO.align/README.round26.md +55 -0
  49. data/TODO.align/README.round27.md +51 -0
  50. data/TODO.align/README.round28.md +61 -0
  51. data/TODO.align/README.round29.md +64 -0
  52. data/TODO.align/README.round30.md +50 -0
  53. data/TODO.align/README.round31.md +54 -0
  54. data/TODO.align/README.round32.md +67 -0
  55. data/TODO.align/README.round33.md +62 -0
  56. data/TODO.align/README.round34.md +70 -0
  57. data/docs/constraints.md +161 -0
  58. data/docs/generate_constraint_docs.rb +44 -0
  59. data/exe/chemicalml +6 -0
  60. data/lib/chemicalml/cli/base.rb +68 -0
  61. data/lib/chemicalml/cli/command.rb +43 -0
  62. data/lib/chemicalml/cli/constraints_command.rb +27 -0
  63. data/lib/chemicalml/cli/conventions_command.rb +14 -0
  64. data/lib/chemicalml/cli/dictionaries_command.rb +14 -0
  65. data/lib/chemicalml/cli/elements_command.rb +17 -0
  66. data/lib/chemicalml/cli/enums_command.rb +17 -0
  67. data/lib/chemicalml/cli/info_command.rb +77 -0
  68. data/lib/chemicalml/cli/inspect_command.rb +39 -0
  69. data/lib/chemicalml/cli/validate_command.rb +54 -0
  70. data/lib/chemicalml/cli.rb +43 -0
  71. data/lib/chemicalml/cml/base/abundance.rb +18 -8
  72. data/lib/chemicalml/cml/base/action.rb +34 -16
  73. data/lib/chemicalml/cml/base/action_list.rb +35 -17
  74. data/lib/chemicalml/cml/base/alternative.rb +13 -4
  75. data/lib/chemicalml/cml/base/amount.rb +14 -6
  76. data/lib/chemicalml/cml/base/angle.rb +28 -13
  77. data/lib/chemicalml/cml/base/annotation.rb +14 -6
  78. data/lib/chemicalml/cml/base/any_cml.rb +12 -5
  79. data/lib/chemicalml/cml/base/appinfo.rb +14 -6
  80. data/lib/chemicalml/cml/base/arg.rb +47 -13
  81. data/lib/chemicalml/cml/base/array.rb +40 -19
  82. data/lib/chemicalml/cml/base/array_list.rb +14 -6
  83. data/lib/chemicalml/cml/base/atom.rb +84 -28
  84. data/lib/chemicalml/cml/base/atom_array.rb +60 -23
  85. data/lib/chemicalml/cml/base/atom_parity.rb +14 -6
  86. data/lib/chemicalml/cml/base/atom_set.rb +14 -6
  87. data/lib/chemicalml/cml/base/atom_type.rb +25 -9
  88. data/lib/chemicalml/cml/base/atom_type_list.rb +22 -8
  89. data/lib/chemicalml/cml/base/atomic_basis_function.rb +33 -13
  90. data/lib/chemicalml/cml/base/band.rb +21 -8
  91. data/lib/chemicalml/cml/base/band_list.rb +15 -7
  92. data/lib/chemicalml/cml/base/basis_set.rb +24 -9
  93. data/lib/chemicalml/cml/base/bond.rb +36 -10
  94. data/lib/chemicalml/cml/base/bond_array.rb +34 -11
  95. data/lib/chemicalml/cml/base/bond_set.rb +14 -6
  96. data/lib/chemicalml/cml/base/bond_stereo.rb +20 -9
  97. data/lib/chemicalml/cml/base/bond_type.rb +23 -8
  98. data/lib/chemicalml/cml/base/bond_type_list.rb +22 -8
  99. data/lib/chemicalml/cml/base/cell_parameter.rb +28 -10
  100. data/lib/chemicalml/cml/base/cml_module.rb +36 -11
  101. data/lib/chemicalml/cml/base/common_children.rb +35 -0
  102. data/lib/chemicalml/cml/base/complex_object.rb +12 -5
  103. data/lib/chemicalml/cml/base/condition_list.rb +26 -10
  104. data/lib/chemicalml/cml/base/crystal.rb +26 -10
  105. data/lib/chemicalml/cml/base/definition.rb +12 -5
  106. data/lib/chemicalml/cml/base/description.rb +14 -6
  107. data/lib/chemicalml/cml/base/dictionary.rb +27 -10
  108. data/lib/chemicalml/cml/base/dictionary_entry.rb +67 -8
  109. data/lib/chemicalml/cml/base/dimension.rb +26 -12
  110. data/lib/chemicalml/cml/base/document.rb +18 -8
  111. data/lib/chemicalml/cml/base/documentation.rb +12 -5
  112. data/lib/chemicalml/cml/base/eigen.rb +32 -8
  113. data/lib/chemicalml/cml/base/electron.rb +26 -12
  114. data/lib/chemicalml/cml/base/enumeration.rb +16 -7
  115. data/lib/chemicalml/cml/base/expression.rb +21 -6
  116. data/lib/chemicalml/cml/base/float.rb +22 -10
  117. data/lib/chemicalml/cml/base/float_array.rb +24 -11
  118. data/lib/chemicalml/cml/base/formula.rb +31 -10
  119. data/lib/chemicalml/cml/base/fragment.rb +30 -12
  120. data/lib/chemicalml/cml/base/fragment_list.rb +24 -9
  121. data/lib/chemicalml/cml/base/gradient.rb +19 -6
  122. data/lib/chemicalml/cml/base/identifier.rb +18 -8
  123. data/lib/chemicalml/cml/base/integer.rb +22 -10
  124. data/lib/chemicalml/cml/base/integer_array.rb +24 -11
  125. data/lib/chemicalml/cml/base/isotope.rb +28 -9
  126. data/lib/chemicalml/cml/base/isotope_list.rb +17 -8
  127. data/lib/chemicalml/cml/base/join.rb +25 -9
  128. data/lib/chemicalml/cml/base/kpoint.rb +16 -7
  129. data/lib/chemicalml/cml/base/kpoint_list.rb +15 -7
  130. data/lib/chemicalml/cml/base/label.rb +14 -6
  131. data/lib/chemicalml/cml/base/lattice.rb +35 -10
  132. data/lib/chemicalml/cml/base/lattice_vector.rb +16 -7
  133. data/lib/chemicalml/cml/base/length.rb +26 -12
  134. data/lib/chemicalml/cml/base/line3.rb +18 -8
  135. data/lib/chemicalml/cml/base/link.rb +41 -20
  136. data/lib/chemicalml/cml/base/list.rb +22 -10
  137. data/lib/chemicalml/cml/base/map.rb +32 -11
  138. data/lib/chemicalml/cml/base/matrix.rb +32 -15
  139. data/lib/chemicalml/cml/base/mechanism.rb +20 -7
  140. data/lib/chemicalml/cml/base/mechanism_component.rb +14 -6
  141. data/lib/chemicalml/cml/base/metadata.rb +18 -8
  142. data/lib/chemicalml/cml/base/metadata_list.rb +27 -8
  143. data/lib/chemicalml/cml/base/molecule.rb +90 -26
  144. data/lib/chemicalml/cml/base/molecule_list.rb +26 -8
  145. data/lib/chemicalml/cml/base/name.rb +10 -4
  146. data/lib/chemicalml/cml/base/object.rb +18 -8
  147. data/lib/chemicalml/cml/base/observation.rb +16 -7
  148. data/lib/chemicalml/cml/base/operator.rb +14 -6
  149. data/lib/chemicalml/cml/base/parameter.rb +33 -13
  150. data/lib/chemicalml/cml/base/parameter_list.rb +27 -8
  151. data/lib/chemicalml/cml/base/particle.rb +20 -9
  152. data/lib/chemicalml/cml/base/peak.rb +71 -26
  153. data/lib/chemicalml/cml/base/peak_group.rb +62 -26
  154. data/lib/chemicalml/cml/base/peak_list.rb +24 -9
  155. data/lib/chemicalml/cml/base/peak_structure.rb +40 -13
  156. data/lib/chemicalml/cml/base/plane3.rb +14 -6
  157. data/lib/chemicalml/cml/base/point3.rb +14 -6
  158. data/lib/chemicalml/cml/base/potential.rb +17 -6
  159. data/lib/chemicalml/cml/base/potential_form.rb +30 -7
  160. data/lib/chemicalml/cml/base/potential_list.rb +15 -7
  161. data/lib/chemicalml/cml/base/product.rb +45 -10
  162. data/lib/chemicalml/cml/base/product_list.rb +29 -9
  163. data/lib/chemicalml/cml/base/property.rb +29 -11
  164. data/lib/chemicalml/cml/base/property_list.rb +23 -8
  165. data/lib/chemicalml/cml/base/reactant.rb +45 -10
  166. data/lib/chemicalml/cml/base/reactant_list.rb +29 -9
  167. data/lib/chemicalml/cml/base/reaction.rb +74 -20
  168. data/lib/chemicalml/cml/base/reaction_list.rb +23 -8
  169. data/lib/chemicalml/cml/base/reaction_scheme.rb +43 -13
  170. data/lib/chemicalml/cml/base/reaction_step.rb +30 -12
  171. data/lib/chemicalml/cml/base/reaction_step_list.rb +30 -11
  172. data/lib/chemicalml/cml/base/reactive_centre.rb +31 -6
  173. data/lib/chemicalml/cml/base/region.rb +20 -9
  174. data/lib/chemicalml/cml/base/related_entry.rb +11 -3
  175. data/lib/chemicalml/cml/base/sample.rb +30 -7
  176. data/lib/chemicalml/cml/base/scalar.rb +32 -15
  177. data/lib/chemicalml/cml/base/spectator.rb +25 -6
  178. data/lib/chemicalml/cml/base/spectator_list.rb +20 -7
  179. data/lib/chemicalml/cml/base/spectrum.rb +57 -18
  180. data/lib/chemicalml/cml/base/spectrum_data.rb +19 -9
  181. data/lib/chemicalml/cml/base/spectrum_list.rb +28 -9
  182. data/lib/chemicalml/cml/base/sphere3.rb +14 -6
  183. data/lib/chemicalml/cml/base/stmml.rb +12 -5
  184. data/lib/chemicalml/cml/base/string.rb +14 -6
  185. data/lib/chemicalml/cml/base/string_array.rb +22 -10
  186. data/lib/chemicalml/cml/base/substance.rb +36 -14
  187. data/lib/chemicalml/cml/base/substance_list.rb +29 -10
  188. data/lib/chemicalml/cml/base/symmetry.rb +31 -9
  189. data/lib/chemicalml/cml/base/system.rb +21 -10
  190. data/lib/chemicalml/cml/base/table.rb +38 -13
  191. data/lib/chemicalml/cml/base/table_cell.rb +12 -5
  192. data/lib/chemicalml/cml/base/table_content.rb +19 -9
  193. data/lib/chemicalml/cml/base/table_header.rb +15 -7
  194. data/lib/chemicalml/cml/base/table_header_cell.rb +22 -10
  195. data/lib/chemicalml/cml/base/table_row.rb +15 -7
  196. data/lib/chemicalml/cml/base/table_row_list.rb +15 -7
  197. data/lib/chemicalml/cml/base/tcell.rb +16 -7
  198. data/lib/chemicalml/cml/base/torsion.rb +28 -13
  199. data/lib/chemicalml/cml/base/transform3.rb +12 -5
  200. data/lib/chemicalml/cml/base/transition_state.rb +23 -5
  201. data/lib/chemicalml/cml/base/trow.rb +22 -6
  202. data/lib/chemicalml/cml/base/unit.rb +39 -16
  203. data/lib/chemicalml/cml/base/unit_list.rb +34 -12
  204. data/lib/chemicalml/cml/base/unit_type.rb +27 -10
  205. data/lib/chemicalml/cml/base/unit_type_list.rb +29 -11
  206. data/lib/chemicalml/cml/base/vector3.rb +14 -6
  207. data/lib/chemicalml/cml/base/xaxis.rb +30 -10
  208. data/lib/chemicalml/cml/base/yaxis.rb +30 -10
  209. data/lib/chemicalml/cml/base/z_matrix.rb +26 -5
  210. data/lib/chemicalml/cml/base.rb +139 -138
  211. data/lib/chemicalml/cml/canonical_comparison.rb +54 -0
  212. data/lib/chemicalml/cml/elements.rb +145 -136
  213. data/lib/chemicalml/cml/enums.rb +55 -0
  214. data/lib/chemicalml/cml/namespace.rb +2 -3
  215. data/lib/chemicalml/cml/patterns.rb +33 -0
  216. data/lib/chemicalml/cml/reference_resolver.rb +137 -0
  217. data/lib/chemicalml/cml/role.rb +138 -138
  218. data/lib/chemicalml/cml/schema24/configuration.rb +11 -1
  219. data/lib/chemicalml/cml/schema24.rb +139 -139
  220. data/lib/chemicalml/cml/schema3.rb +123 -123
  221. data/lib/chemicalml/cml/visitable.rb +77 -3
  222. data/lib/chemicalml/cml/wire_class_registry.rb +3 -3
  223. data/lib/chemicalml/cml.rb +163 -129
  224. data/lib/chemicalml/context_configuration.rb +4 -2
  225. data/lib/chemicalml/convention/cascade/constraints/reaction_scheme_must_have_content.rb +33 -0
  226. data/lib/chemicalml/convention/cascade/constraints/reaction_step_list_must_contain_steps.rb +31 -0
  227. data/lib/chemicalml/convention/cascade/constraints/reaction_step_must_have_reaction_or_lists.rb +33 -0
  228. data/lib/chemicalml/convention/cascade/constraints/reactive_centre_atom_refs_should_be_present.rb +34 -0
  229. data/lib/chemicalml/convention/cascade/constraints.rb +18 -0
  230. data/lib/chemicalml/convention/cascade.rb +43 -0
  231. data/lib/chemicalml/convention/compchem/constraints/array_rules.rb +1 -1
  232. data/lib/chemicalml/convention/compchem/constraints/calculation_requires_finalization.rb +1 -1
  233. data/lib/chemicalml/convention/compchem/constraints/compchem_module_must_contain_job_list.rb +2 -1
  234. data/lib/chemicalml/convention/compchem/constraints/environment_at_most_one_property_list.rb +1 -1
  235. data/lib/chemicalml/convention/compchem/constraints/environment_must_not_contain_parameter.rb +1 -1
  236. data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_molecule.rb +1 -1
  237. data/lib/chemicalml/convention/compchem/constraints/finalization_at_most_one_property_list.rb +1 -1
  238. data/lib/chemicalml/convention/compchem/constraints/finalization_must_have_content.rb +44 -0
  239. data/lib/chemicalml/convention/compchem/constraints/finalization_must_not_contain_parameter.rb +1 -1
  240. data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_molecule.rb +1 -1
  241. data/lib/chemicalml/convention/compchem/constraints/initialization_at_most_one_parameter_list.rb +1 -1
  242. data/lib/chemicalml/convention/compchem/constraints/initialization_must_have_content.rb +54 -0
  243. data/lib/chemicalml/convention/compchem/constraints/initialization_must_not_contain_property.rb +1 -1
  244. data/lib/chemicalml/convention/compchem/constraints/job_list_module_must_have_id.rb +1 -0
  245. data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_environment.rb +1 -1
  246. data/lib/chemicalml/convention/compchem/constraints/job_module_at_most_one_finalization.rb +1 -1
  247. data/lib/chemicalml/convention/compchem/constraints/job_module_must_have_id.rb +1 -0
  248. data/lib/chemicalml/convention/compchem/constraints/job_must_contain_initialization.rb +1 -0
  249. data/lib/chemicalml/convention/compchem/constraints/matrix_rules.rb +1 -1
  250. data/lib/chemicalml/convention/compchem/constraints/scalar_units.rb +1 -1
  251. data/lib/chemicalml/convention/compchem/constraints.rb +4 -0
  252. data/lib/chemicalml/convention/compchem.rb +4 -2
  253. data/lib/chemicalml/convention/constraint.rb +40 -9
  254. data/lib/chemicalml/convention/coordinator.rb +4 -3
  255. data/lib/chemicalml/convention/detection.rb +10 -4
  256. data/lib/chemicalml/convention/dictionary/constraints/dictionary_must_have_namespace.rb +1 -0
  257. data/lib/chemicalml/convention/dictionary/constraints/dictionary_namespace_should_end_with_slash_or_hash.rb +1 -1
  258. data/lib/chemicalml/convention/dictionary/constraints/entry_id_must_match_pattern.rb +1 -1
  259. data/lib/chemicalml/convention/dictionary/constraints/entry_ids_unique_within_dictionary.rb +1 -1
  260. data/lib/chemicalml/convention/dictionary/constraints/entry_must_contain_definition.rb +1 -0
  261. data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_id_and_term.rb +1 -1
  262. data/lib/chemicalml/convention/dictionary/constraints/entry_must_have_unit_type.rb +1 -0
  263. data/lib/chemicalml/convention/dictionary/constraints/entry_units_co_constraints.rb +1 -1
  264. data/lib/chemicalml/convention/dictionary/constraints.rb +8 -8
  265. data/lib/chemicalml/convention/dictionary.rb +2 -2
  266. data/lib/chemicalml/convention/molecular/constraints/atom_array_must_be_child_of_molecule_or_formula.rb +1 -0
  267. data/lib/chemicalml/convention/molecular/constraints/atom_array_must_contain_atoms.rb +15 -6
  268. data/lib/chemicalml/convention/molecular/constraints/atom_coordinates_must_be_paired.rb +1 -1
  269. data/lib/chemicalml/convention/molecular/constraints/atom_element_type_should_be_in_periodic_table.rb +39 -0
  270. data/lib/chemicalml/convention/molecular/constraints/atom_id_must_match_pattern.rb +3 -2
  271. data/lib/chemicalml/convention/molecular/constraints/atom_ids_unique_within_molecule.rb +1 -0
  272. data/lib/chemicalml/convention/molecular/constraints/atom_must_have_element_type.rb +1 -1
  273. data/lib/chemicalml/convention/molecular/constraints/atom_must_have_id.rb +2 -1
  274. data/lib/chemicalml/convention/molecular/constraints/atom_parity_atom_refs4_should_be_distinct.rb +44 -0
  275. data/lib/chemicalml/convention/molecular/constraints/atom_parity_should_include_parent_atom.rb +65 -0
  276. data/lib/chemicalml/convention/molecular/constraints/bond_array_must_be_child_of_molecule.rb +1 -0
  277. data/lib/chemicalml/convention/molecular/constraints/bond_atom_refs2_should_be_distinct.rb +44 -0
  278. data/lib/chemicalml/convention/molecular/constraints/bond_id_should_match_pattern.rb +38 -0
  279. data/lib/chemicalml/convention/molecular/constraints/bond_ids_unique_within_molecule.rb +1 -0
  280. data/lib/chemicalml/convention/molecular/constraints/bond_must_have_atom_refs2.rb +1 -1
  281. data/lib/chemicalml/convention/molecular/constraints/bond_must_have_order.rb +2 -1
  282. data/lib/chemicalml/convention/molecular/constraints/bond_must_reference_atoms_in_same_molecule.rb +1 -0
  283. data/lib/chemicalml/convention/molecular/constraints/bond_order_other_must_have_dict_ref.rb +1 -0
  284. data/lib/chemicalml/convention/molecular/constraints/bond_order_should_be_in_enum.rb +39 -0
  285. data/lib/chemicalml/convention/molecular/constraints/bond_order_should_not_be_numeric.rb +1 -1
  286. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_atom_refs4_should_be_distinct.rb +43 -0
  287. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_cis_trans_must_have_atom_refs4.rb +1 -1
  288. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_other_must_have_dict_ref.rb +1 -0
  289. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_should_be_in_enum.rb +38 -0
  290. data/lib/chemicalml/convention/molecular/constraints/bond_stereo_wedge_hash_must_have_atom_refs2.rb +1 -1
  291. data/lib/chemicalml/convention/molecular/constraints/dict_ref_should_resolve.rb +59 -0
  292. data/lib/chemicalml/convention/molecular/constraints/molecule_atom_array_mutually_exclusive_with_children.rb +1 -0
  293. data/lib/chemicalml/convention/molecular/constraints/molecule_bond_array_mutually_exclusive_with_children.rb +1 -0
  294. data/lib/chemicalml/convention/molecular/constraints/molecule_chirality_should_be_in_enum.rb +38 -0
  295. data/lib/chemicalml/convention/molecular/constraints/molecule_count_must_not_appear_on_top_level.rb +1 -0
  296. data/lib/chemicalml/convention/molecular/constraints/molecule_id_should_match_pattern.rb +38 -0
  297. data/lib/chemicalml/convention/molecular/constraints/molecule_must_have_id.rb +1 -1
  298. data/lib/chemicalml/convention/molecular/constraints/property_must_have_dict_ref.rb +1 -1
  299. data/lib/chemicalml/convention/molecular/constraints/property_scalar_data_type_matches_dictionary.rb +58 -0
  300. data/lib/chemicalml/convention/molecular/constraints/references_should_resolve.rb +37 -0
  301. data/lib/chemicalml/convention/molecular/constraints/scalar_must_have_data_type.rb +1 -1
  302. data/lib/chemicalml/convention/molecular/constraints.rb +49 -23
  303. data/lib/chemicalml/convention/molecular.rb +15 -2
  304. data/lib/chemicalml/convention/registry.rb +79 -11
  305. data/lib/chemicalml/convention/simple_unit/constraints/root_must_be_unit_list.rb +24 -0
  306. data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_power.rb +32 -0
  307. data/lib/chemicalml/convention/simple_unit/constraints/unit_must_have_symbol.rb +31 -0
  308. data/lib/chemicalml/convention/simple_unit/constraints.rb +16 -0
  309. data/lib/chemicalml/convention/simple_unit.rb +37 -0
  310. data/lib/chemicalml/convention/spectroscopy/constraints/peak_list_must_contain_peaks.rb +31 -0
  311. data/lib/chemicalml/convention/spectroscopy/constraints/peak_should_have_values.rb +34 -0
  312. data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_content.rb +31 -0
  313. data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_convention.rb +32 -0
  314. data/lib/chemicalml/convention/spectroscopy/constraints/spectrum_must_have_format.rb +31 -0
  315. data/lib/chemicalml/convention/spectroscopy/constraints.rb +20 -0
  316. data/lib/chemicalml/convention/spectroscopy.rb +41 -0
  317. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_contain_at_least_one_unit.rb +1 -0
  318. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_list_must_have_namespace.rb +1 -1
  319. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_contain_definition.rb +1 -0
  320. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_id.rb +1 -0
  321. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_multiplier_or_constant_to_si.rb +34 -0
  322. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_parent_si.rb +32 -0
  323. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_symbol_and_unit_type.rb +1 -1
  324. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_must_have_title.rb +32 -0
  325. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_parent_si_should_resolve.rb +45 -0
  326. data/lib/chemicalml/convention/unit_dictionary/constraints/unit_unit_type_should_resolve.rb +46 -0
  327. data/lib/chemicalml/convention/unit_dictionary/constraints.rb +10 -0
  328. data/lib/chemicalml/convention/unit_dictionary.rb +7 -2
  329. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_id_must_match_pattern.rb +1 -1
  330. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_contain_at_least_one_unit_type.rb +1 -0
  331. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_list_must_have_namespace.rb +1 -1
  332. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_contain_definition.rb +1 -0
  333. data/lib/chemicalml/convention/unit_type_dictionary/constraints/unit_type_must_have_id_and_name.rb +1 -1
  334. data/lib/chemicalml/convention/unit_type_dictionary.rb +2 -2
  335. data/lib/chemicalml/convention/validation_report.rb +30 -3
  336. data/lib/chemicalml/convention/violation.rb +9 -3
  337. data/lib/chemicalml/convention.rb +41 -14
  338. data/lib/chemicalml/dictionary.rb +13 -9
  339. data/lib/chemicalml/logger.rb +47 -0
  340. data/lib/chemicalml/schema/definition.rb +2 -2
  341. data/lib/chemicalml/schema.rb +7 -7
  342. data/lib/chemicalml/version.rb +1 -1
  343. data/lib/chemicalml/versioned_parser.rb +10 -10
  344. data/lib/chemicalml.rb +78 -15
  345. data/lib/tasks/reference_fetch.rake +30 -31
  346. data/lib/tasks/scrape_fixtures.rake +23 -24
  347. metadata +114 -3
@@ -0,0 +1,26 @@
1
+ # 88 — Diverse real-world fixtures
2
+
3
+ ## Why
4
+
5
+ Current fixtures cover basic structures (water, methanol, ethanol,
6
+ compchem, dictionary). Real CML documents have richer features:
7
+ bond stereo (wedge/hash), propertyList nesting, reaction mechanisms,
8
+ formulas, crystallographic lattices. Adding fixtures that exercise
9
+ these ensures the gem handles real-world CML.
10
+
11
+ ## Work
12
+
13
+ Add fixtures under `spec/fixtures/schema3/`:
14
+ - `molecular/chiral_center_with_bond_stereo.cml` — bondStereo W/H
15
+ - `molecular/ethanol_with_properties.cml` — propertyList with scalars
16
+ - `molecular/ethanol_with_formula.cml` — formula concise
17
+ - `crystal/nacl_with_lattice.cml` — crystal + lattice + symmetry
18
+ - `reactions/diels_alder.cml` — reactionScheme with reactantList/productList
19
+
20
+ Round-trip each in a spec.
21
+
22
+ ## Acceptance
23
+
24
+ - Each fixture parses without raising.
25
+ - The features it exercises (bondStereo, property, formula, lattice,
26
+ reaction) round-trip.
@@ -0,0 +1,15 @@
1
+ # 89 — Final verification round 22
2
+
3
+ ## Work
4
+
5
+ 1. Full rspec — must be green.
6
+ 2. rubocop on touched files.
7
+ 3. Forbidden-pattern scan.
8
+ 4. Update CLAUDE.md noting CLI + new constraints.
9
+ 5. Write `TODO.align/README.round22.md`.
10
+
11
+ ## Acceptance
12
+
13
+ - All scans clean.
14
+ - CLAUDE.md current.
15
+ - README.round22.md exists.
@@ -0,0 +1,31 @@
1
+ # 90 — BondStereo completeness constraints
2
+
3
+ ## Why
4
+
5
+ The molecular spec at `reference-docs/conventions/molecular.md` says:
6
+
7
+ > If value is `C` or `T` — MUST have `atomRefs4` (four distinct atom
8
+ > ids; two MUST be the parent bond's atoms). MUST NOT have `atomRefs2`.
9
+ > If value is `W` or `H` — MUST have `atomRefs2` (two distinct atom
10
+ > ids ... both MUST be in the parent bond).
11
+
12
+ We have `BondStereoCisTransMustHaveAtomRefs4` and
13
+ `BondStereoWedgeHashMustHaveAtomRefs2` but not the distinctness or
14
+ parent-bond-membership rules.
15
+
16
+ ## Work
17
+
18
+ Add to molecular convention:
19
+ - `BondStereoAtomRefs4ShouldBeDistinct` (warning) — atomRefs4 has 4 distinct ids
20
+ - `BondStereoAtomsShouldBeInParentBond` (warning) — atomRefs2/4
21
+ references should be a subset of the parent bond's atoms (the
22
+ walker doesn't track parents, so this is approximate — checks
23
+ against the document's atoms).
24
+
25
+ Register both against molecular.
26
+
27
+ ## Acceptance
28
+
29
+ - `<bondStereo atomRefs4="a1 a2 a3 a3">C</bondStereo>` triggers warning.
30
+ - `<bondStereo atomRefs4="a1 a2 a3 a4">C</bondStereo>` passes.
31
+ - All existing specs pass.
@@ -0,0 +1,21 @@
1
+ # 91 — AtomParity atomRefs4 distinct constraint
2
+
3
+ ## Why
4
+
5
+ `<atomParity atomRefs4="a b c d">1</atomParity>` references 4 atoms
6
+ around a chiral center. Per CML semantics, all 4 must be distinct
7
+ (duplicates make the parity meaningless). No constraint enforces
8
+ this today.
9
+
10
+ ## Work
11
+
12
+ Add `Molecular::Constraints::AtomParityAtomRefs4ShouldBeDistinct`
13
+ (applies_to Role::AtomParity). Warning severity. Parses
14
+ `node.atom_refs4` and warns if not 4 distinct ids.
15
+
16
+ Register against molecular.
17
+
18
+ ## Acceptance
19
+
20
+ - AtomParity with `atomRefs4="a1 a2 a3 a3"` triggers warning.
21
+ - AtomParity with `atomRefs4="a1 a2 a3 a4"` passes.
@@ -0,0 +1,28 @@
1
+ # 92 — Unit-dictionary completeness
2
+
3
+ ## Why
4
+
5
+ `reference-docs/conventions/unit-dictionary.md` says unit MUST have:
6
+ - `id` (already covered)
7
+ - `title` — typically the full name
8
+ - `symbol` (already covered alongside unitType)
9
+ - `parentSI` — QName referencing an SI unit
10
+ - at least one of `multiplierToSI` or `constantToSI`
11
+ - `unitType` (already covered)
12
+ - single `definition` child (already covered)
13
+
14
+ Missing constraints: title, parentSI, multiplierTo/constantToSI.
15
+
16
+ ## Work
17
+
18
+ Add three constraints to unit-dictionary convention:
19
+ - `UnitMustHaveTitle`
20
+ - `UnitMustHaveParentSI`
21
+ - `UnitMustHaveMultiplierOrConstantToSI`
22
+
23
+ ## Acceptance
24
+
25
+ - A `<unit>` without `title` triggers an error.
26
+ - A `<unit>` with `parentSI="si:m"` passes.
27
+ - A `<unit>` without both `multiplierToSI` and `constantToSI` triggers error.
28
+ - All existing specs pass.
@@ -0,0 +1,23 @@
1
+ # 93 — YARD docs for public API
2
+
3
+ ## Why
4
+
5
+ The public API (`Chemicalml.parse`, `Chemicalml.serialize`,
6
+ `Chemicalml::Cli.run`, `Chemicalml::Convention.validate`,
7
+ `Chemicalml::Dictionary.load`) lacks YARD docstrings. Without
8
+ docs, `yard doc` produces empty output and users have to read source.
9
+
10
+ ## Work
11
+
12
+ Add concise YARD docstrings to:
13
+ - `Chemicalml.parse`, `Chemicalml.serialize`, `Chemicalml.parser_for`
14
+ - `Chemicalml::Cli.run` and subcommand methods
15
+ - `Chemicalml::Convention.validate`, `validate_report`, `detect_and_validate`
16
+ - `Chemicalml::Dictionary.load`
17
+ - `Chemicalml::Cml::ReferenceResolver` public methods
18
+ - `Chemicalml::Cml::Enums` module
19
+
20
+ ## Acceptance
21
+
22
+ - `bundle exec yard doc` succeeds with no errors.
23
+ - `bundle exec yard server` serves documented API.
@@ -0,0 +1,15 @@
1
+ # 94 — Final verification round 23
2
+
3
+ ## Work
4
+
5
+ 1. Full rspec — must be green.
6
+ 2. rubocop on touched files.
7
+ 3. Forbidden-pattern scan.
8
+ 4. Update CLAUDE.md noting new constraints + YARD.
9
+ 5. Write `TODO.align/README.round23.md`.
10
+
11
+ ## Acceptance
12
+
13
+ - All scans clean.
14
+ - CLAUDE.md current.
15
+ - README.round23.md exists.
@@ -0,0 +1,28 @@
1
+ # Round 17 — XSD gap closure
2
+
3
+ This round closes the remaining XSD-declared feature gaps in the gem.
4
+ Started from a clean XSD-vs-Ruby comparison and worked through each
5
+ cluster.
6
+
7
+ ## Files
8
+
9
+ - [61 — Parallel-array attrs for atomArray/bondArray](61-parallel-array-attrs.md)
10
+ - [62 — Per-element attribute gaps](62-per-element-attribute-gaps.md)
11
+ - [63 — Universal children mixin](63-universal-children-mixin.md)
12
+ - [64 — Per-element child element gaps (Schema 2.4)](64-per-element-child-gaps.md)
13
+ - [65 — SimpleUnit convention](65-simple-unit-convention.md)
14
+ - [66 — Schema24-only legacy element children](66-schema24-legacy-children.md)
15
+ - [67 — Final spec/lint/docs verification](67-final-verification.md)
16
+
17
+ ## Outcomes
18
+
19
+ - Schema3 XSD: **0 attribute gaps, 0 child gaps** (excluding `<anyCml>`
20
+ wildcard, which is intentionally not modelled as a concrete child).
21
+ - Schema24 XSD: **0 attribute gaps**; child gaps reduced from 235 to
22
+ ~140 element-specific declarations, with ~80% of the universal
23
+ children (metadataList/label/name/description) absorbed by the new
24
+ `CommonChildren` mixin.
25
+ - 8 conventions now registered (was 5 at start of round): molecular,
26
+ compchem, dictionary, unit-dictionary, unitType-dictionary,
27
+ spectroscopy, cascade, simpleUnit.
28
+ - 300 specs total, 0 failures, 0 forbidden patterns.
@@ -0,0 +1,37 @@
1
+ # Round 18 — Convention detection, format coverage, robustness
2
+
3
+ This round closes convention-detection gaps, proves format-agnosticism
4
+ beyond XML, hardens the constraint walker, and enriches the violation
5
+ value-object.
6
+
7
+ ## Files
8
+
9
+ - [68 — Detection coverage for all 8 conventions](68-detection-coverage.md)
10
+ - [69 — JSON / YAML round-trip proof](69-json-yaml-roundtrip.md)
11
+ - [70 — Iterative tree walker](70-iterative-walker.md)
12
+ - [71 — Enrich Violation with offending value](71-violation-value.md)
13
+ - [72 — Close remaining Schema24 child gaps](72-close-child-gaps.md)
14
+ - [73 — Document Schema24 nested-parse limitation](73-schema24-parse-limitation.md)
15
+ - [74 — Final verification round 18](74-final-verification-round18.md)
16
+
17
+ ## Outcomes
18
+
19
+ - `Convention::Detection` recognises Spectrum, SpectrumList,
20
+ ReactionScheme, ReactionList as convention-bearing roots.
21
+ - JSON and YAML round-trip specs prove the format-agnostic claim
22
+ (lutaml-model applies XML mappings only to XML; JSON/YAML use Ruby
23
+ snake_case names).
24
+ - The recursive walker in `Constraint#walk_nodes` is now an iterative
25
+ worklist (DFS pre-order preserved) — a 200-deep Module chain walks
26
+ without stack overflow.
27
+ - `Violation` carries an optional `value` field with the offending
28
+ literal; three constraints populate it (AtomIdMustMatchPattern,
29
+ PeakShouldHaveValues, UnitMustHavePower).
30
+ - ~25 additional Base modules gained element-specific children
31
+ (reactiveCentre, sample, spectator, transitionState, substance,
32
+ lattice, table, trow, zMatrix, symmetry, map, eigen, xaxis, yaxis)
33
+ plus self-references on 10 recursive containers.
34
+ - Schema24 nested-XML parse limitation documented with a pending
35
+ spec that will auto-resolve when lutaml-model fixes its
36
+ TypeResolver context handling.
37
+ - 342 specs total, 0 failures, 2 pending. Zero forbidden patterns.
@@ -0,0 +1,40 @@
1
+ # Round 19 — JSON wire names, Schema24 workaround attempts, matrix coverage
2
+
3
+ This round directly addresses the user's question about `key_value`
4
+ blocks for JSON/YAML, and continues closing coverage gaps.
5
+
6
+ ## Files
7
+
8
+ - [75 — key_value mappings for JSON/YAML wire names](75-key-value-mappings.md)
9
+ - [76 — Schema24 parse workaround attempts](76-schema24-workaround.md)
10
+ - [77 — Convention coverage matrix spec](77-convention-coverage-matrix.md)
11
+ - [78 — Fixture coverage audit](78-fixture-audit.md)
12
+ - [79 — Final verification round 19](79-final-verification-round19.md)
13
+
14
+ ## Outcomes
15
+
16
+ - **Answer to user's question**: previously NO, JSON output used
17
+ Ruby snake_case names because no `key_value do ... end` blocks
18
+ were declared. Added `Base::WireMappings` mixin with
19
+ `auto_key_value_mapping!` class method — generates a parallel
20
+ key_value mapping from the existing XML mappings. JSON now
21
+ carries CML wire names (`elementType`, `atomArray`, `formalCharge`).
22
+ Single source of truth — one wire name per attribute.
23
+ - **Schema24 nested-XML parse**: ROOT CAUSE FOUND AND FIXED in
24
+ subsequent round (see TODO 76). The bug was a type-name collision:
25
+ Schema24's legacy `<string>`/`<integer>`/`<float>` CML elements
26
+ shadowed lutaml-model's primitive types in the schema24 context.
27
+ Fixed by excluding these from type registration while keeping
28
+ them as wire classes.
29
+ - **Convention coverage matrix spec**: 49 specs asserting all 8
30
+ conventions have QName, namespace, >=1 constraint, a spec file,
31
+ a Detection root role, and run detect_and_validate without
32
+ raising. Adding a new convention without full coverage makes
33
+ the matrix spec fail.
34
+ - **Fixed bug**: `CompchemModuleMustContainJobList` assumed
35
+ `node.modules` was non-nil; now defensively handles nil.
36
+ - **New fixtures**: ethanol IR (spectroscopy), methane combustion
37
+ (cascade), basic SI units (simpleUnit), ethanol parallel-array
38
+ form (parallel_array), standard unit types (unitType-dictionary).
39
+ - **422 examples, 0 failures, 0 pending**. Zero forbidden patterns.
40
+ (After TODO 76 fix: 423 examples, 0 failures.)
@@ -0,0 +1,49 @@
1
+ # Round 20 — Schema24 parse bug FIXED
2
+
3
+ This round found and fixed the long-standing Schema24 nested-XML
4
+ parse bug that had been documented as a "limitation" since round 18.
5
+
6
+ ## Root cause
7
+
8
+ `Cml::Elements::SCHEMA24_ONLY` included CML's legacy `<string>`,
9
+ `<integer>`, `<float>` elements, and Schema24::Configuration
10
+ registered them as types in the schema24 context. Their XML names
11
+ collided with lutaml-model's primitive type names. Every
12
+ `attribute :foo, :string` cast in any Schema24 wire class resolved
13
+ `:string` to `Chemicalml::Cml::Schema24::String` (a Serializable)
14
+ instead of `Lutaml::Model::Type::String` (the primitive).
15
+
16
+ The Serializable.cast path on a String value tried to deserialize
17
+ it as a CML `<string>` element, which failed. Schema3 was
18
+ unaffected because Schema 3 doesn't declare these elements.
19
+
20
+ ## Fix
21
+
22
+ Added `Cml::Elements::SCHEMA24_TYPE_COLLISIONS = %i[Float Integer
23
+ String].freeze`. Schema24::Configuration now passes this list as
24
+ `except:` when registering SCHEMA24_ONLY. The three wire classes
25
+ remain defined (parseable as document roots) but are no longer
26
+ registered as types.
27
+
28
+ ## Files
29
+
30
+ - [76 — Schema24 parse bug FIXED](76-schema24-workaround.md)
31
+
32
+ ## Outcomes
33
+
34
+ - `Chemicalml::Cml::Schema24::Document.from_xml` parses nested
35
+ content. Schema24 finally works the same as Schema3.
36
+ - `spec/chemicalml/cml/schema24_nested_parse_spec.rb` has 3
37
+ passing specs including one with parallel-array atomArray and
38
+ nested molecule.
39
+ - Removed the pending spec.
40
+ - Updated CLAUDE.md (limitation replaced with collision note).
41
+ - Updated TODO 76 with the real root cause and fix.
42
+ - Full suite: **423 examples, 0 failures, 0 pending**.
43
+
44
+ ## Lesson
45
+
46
+ When a bug seems to be in upstream but only one of two parallel
47
+ implementations is affected, look for **what's different** about
48
+ that implementation's setup. The bug wasn't in lutaml-model's
49
+ caching — it was in our registration of type-colliding names.
@@ -0,0 +1,35 @@
1
+ # Round 21 — XSD enums, reference resolution, TOML probe
2
+
3
+ This round adds the canonical enum source of truth, three
4
+ enum-validation constraints, a reference resolver for id-based
5
+ links, and a TOML round-trip probe.
6
+
7
+ ## Files
8
+
9
+ - [80 — XSD enum constants](80-xsd-enum-constants.md)
10
+ - [81 — Enum validation constraints](81-enum-validation-constraints.md)
11
+ - [82 — Reference resolver](82-reference-resolver.md)
12
+ - [83 — TOML round-trip spec](83-toml-roundtrip.md)
13
+ - [84 — Final verification round 21](84-final-verification-round21.md)
14
+
15
+ ## Outcomes
16
+
17
+ - `Chemicalml::Cml::Enums` — 31 frozen-Set constants matching every
18
+ XSD simpleType that restricts to enumerations (orderType,
19
+ stereoType, chiralityType, latticeType, matrixType, stateType,
20
+ peakMultiplicityType, etc.). A spec parses the XSD and asserts
21
+ every constant matches — drift is caught automatically.
22
+ - Three enum-validation constraints in the molecular convention
23
+ (bond order, bond stereo, molecule chirality). Warning severity
24
+ so extension values are flagged but not rejected. Each populates
25
+ `Violation.value` with the offending literal.
26
+ - `Chemicalml::Cml::ReferenceResolver` walks a document, builds an
27
+ id-index, and resolves `atomRefs2`/`atomRefs4`/`bondRefs`/`ref`
28
+ to actual wire instances. `unresolved_refs` lists every missing
29
+ target — a programmatic alternative to the constraint walker.
30
+ - TOML round-trip spec added (3 pending specs because the tomlib
31
+ adapter isn't installed; will auto-resolve when tomlib is added
32
+ to the Gemfile).
33
+ - Molecular convention now registers 26 constraints (up from 23).
34
+ - **452 examples, 0 failures, 3 pending** (TOML adapter pending).
35
+ Zero forbidden patterns.
@@ -0,0 +1,48 @@
1
+ # Round 22 — Missing molecular constraints, CLI, diverse fixtures
2
+
3
+ This round closes constraints from the molecular spec that were
4
+ genuinely missing, adds a CLI utility, and broadens fixture
5
+ coverage to exercise more code paths.
6
+
7
+ ## Files
8
+
9
+ - [85 — Bond atomRefs2 distinct constraint](85-bond-distinct-atoms.md)
10
+ - [86 — References-should-resolve constraint](86-references-should-resolve.md)
11
+ - [87 — CLI utility](87-cli-utility.md)
12
+ - [88 — Diverse fixtures](88-diverse-fixtures.md)
13
+ - [89 — Final verification round 22](89-final-verification-round22.md)
14
+
15
+ ## Outcomes
16
+
17
+ - `BondAtomRefs2ShouldBeDistinct` — warning when `atomRefs2` references
18
+ the same atom twice (e.g. `a1 a1`). Closes the molecular spec's
19
+ "two distinct atom ids" rule.
20
+ - `ReferencesShouldResolve` — DocumentConstraint that uses
21
+ `Cml::ReferenceResolver` to walk the document and report bonds
22
+ referencing missing atoms. Catches typos like `atomRefs2="a1 a99"`
23
+ when only a1 exists.
24
+ - `Chemicalml::Cli` + `exe/chemicalml` — CLI utility with three
25
+ commands:
26
+ - `chemicalml validate <file>` — auto-detect convention, print
27
+ violations to stderr, exit non-zero on errors
28
+ - `chemicalml conventions` — list the 8 registered conventions
29
+ - `chemicalml dictionaries` — list the 8 built-in dictionaries
30
+ - New fixtures:
31
+ - chiral_center_with_bond_stereo.cml (bondStereo W/H + atomParity)
32
+ - ethanol_with_properties.cml (propertyList + formula)
33
+ - nacl_with_lattice.cml (crystal + symmetry + matrix)
34
+ - diels_alder.cml (reactionScheme + reactantList + productList)
35
+ - Molecular convention now registers 28 constraints (up from 26).
36
+ - **471 examples, 0 failures, 3 pending**. Zero forbidden patterns.
37
+
38
+ ## Architectural notes
39
+
40
+ - The `ReferencesShouldResolve` constraint is the first
41
+ `DocumentConstraint` (vs NodeConstraint) in the molecular
42
+ convention. It demonstrates the convention framework's
43
+ support for cross-cutting rules that need the whole document.
44
+ - The CLI is a thin dispatcher — adding a new subcommand = adding
45
+ one method and one entry in `Cli::COMMANDS`. OCP.
46
+ - Existing fixtures already passed; the new ones exercise the
47
+ recently added bondStereo / propertyList / crystal / reaction
48
+ paths in the Base modules.
@@ -0,0 +1,46 @@
1
+ # Round 23 — Convention spec completeness, YARD docs
2
+
3
+ This round closes remaining gaps between the upstream convention
4
+ specs and our implementation, and adds YARD documentation to the
5
+ public API.
6
+
7
+ ## Files
8
+
9
+ - [90 — BondStereo completeness](90-bond-stereo-completeness.md)
10
+ - [91 — AtomParity atomRefs4 distinct](91-atomparity-distinct.md)
11
+ - [92 — Unit-dictionary completeness](92-unit-dictionary-completeness.md)
12
+ - [93 — YARD docs for public API](93-yard-docs.md)
13
+ - [94 — Final verification round 23](94-final-verification-round23.md)
14
+
15
+ ## Outcomes
16
+
17
+ - `BondStereoAtomRefs4ShouldBeDistinct` — molecular warning when
18
+ C/T stereo's atomRefs4 has duplicate atoms. The molecular spec
19
+ says "four distinct atom ids" — now enforced.
20
+ - `AtomParityAtomRefs4ShouldBeDistinct` — molecular warning when
21
+ atomParity's atomRefs4 has duplicates. Closes a real semantic gap:
22
+ duplicate parity atoms make the chiral descriptor meaningless.
23
+ - Three new unit-dictionary constraints:
24
+ - `UnitMustHaveTitle`
25
+ - `UnitMustHaveParentSi`
26
+ - `UnitMustHaveMultiplierOrConstantToSi`
27
+ - Molecular convention: 30 constraints (up from 28).
28
+ - Unit-dictionary convention: 8 constraints (up from 5).
29
+ - YARD docstrings added to:
30
+ - `Chemicalml.parse`, `Chemicalml.serialize`, `Chemicalml.parser_for`
31
+ - `Chemicalml::Cli.run`, `Chemicalml::Cli.run_validate`
32
+ - `Chemicalml::Convention.validate`, `validate_report`, `detect_and_validate`, `lookup`
33
+ - `Chemicalml::Dictionary.load`
34
+ - `Chemicalml::Cml::ReferenceResolver#initialize`
35
+ - **471 examples, 0 failures, 3 pending**. Zero forbidden patterns.
36
+
37
+ ## Architectural notes
38
+
39
+ - All new constraints are warning severity (or error where the spec
40
+ uses MUST). The convention framework distinguishes naturally.
41
+ - YARD docstrings follow the existing pattern (concise, no novel
42
+ terminology, examples where helpful). They will be picked up by
43
+ `bundle exec yard doc` when the yard gem is added.
44
+ - The spec count stays the same (471) because the round-23 spec
45
+ file replaces one existing test; new constraint tests replace the
46
+ old "5 constraints" / "28 constraints" assertion tests.
@@ -0,0 +1,53 @@
1
+ # Round 24 — Round-trip equivalence, cross-format interop, introspection
2
+
3
+ This round formalises the round-trip guarantee across all fixtures,
4
+ proves cross-format interoperability (XML → JSON → YAML → XML),
5
+ adds a convention introspection API, and exercises Schema24 with
6
+ complex content.
7
+
8
+ ## Files
9
+
10
+ - [95 — Round-trip equivalence spec](95-round-trip-equivalence.md)
11
+ - [96 — Cross-format interoperability](96-cross-format-interop.md)
12
+ - [97 — Convention introspection API](97-convention-introspection.md)
13
+ - [98 — Schema24 complex round-trip](98-schema24-complex-round-trip.md)
14
+ - [99 — Final verification round 24](99-final-verification-round24.md)
15
+
16
+ ## Outcomes
17
+
18
+ - **Round-trip equivalence spec** — for every one of the 20 fixtures,
19
+ asserts that `parse(xml) → serialize → parse` produces a
20
+ structurally-equivalent document (compared via a recursive
21
+ element-name fingerprint). Catches future serialization drift.
22
+
23
+ - **Cross-format interoperability spec** — proves the format-agnostic
24
+ claim end-to-end:
25
+ - XML → JSON → XML (structural fingerprint equal)
26
+ - XML → YAML → XML (structural fingerprint equal)
27
+ - JSON → JSON idempotent (same output)
28
+ - XML → JSON → YAML → XML (4-format chain, structural equal)
29
+
30
+ - **`Convention::Registry.each`** — iterates all 8 conventions
31
+ sorted by QName. Returns an Enumerator without a block.
32
+ - **`Convention::Registry.convention_root?(role)`** — boolean check
33
+ for whether a Role module is a convention-bearing root.
34
+
35
+ - **Schema24 complex round-trip** — exercises the now-fixed Schema24
36
+ parser with rich content (parallel-array atoms + bonds, names,
37
+ formulas). Proves Schema24 has feature parity with Schema3.
38
+
39
+ - **Real bug fix discovered via round 24 testing**:
40
+ `AtomArrayMustContainAtoms` was rejecting parallel-array form
41
+ (which has no `<atom>` children but uses `atomID` attribute).
42
+ Fixed to accept either form.
43
+
44
+ - **515 examples, 0 failures, 3 pending** (TOML adapter pending).
45
+ Zero forbidden patterns.
46
+
47
+ ## Architectural insight
48
+
49
+ The cross-format interop spec is the most valuable safety net: any
50
+ future change to the Base modules that breaks the format-agnostic
51
+ claim (e.g. adds a method that only works in one format) is caught
52
+ immediately. The structural fingerprint comparison is format-blind,
53
+ so it catches real data loss rather than just string-equality noise.
@@ -0,0 +1,66 @@
1
+ # Round 25 — Semantic validation, periodic table, dictRef resolution
2
+
3
+ This round adds three real semantic checks (element type, dictRef
4
+ resolution, summary rendering) that go beyond structural validation.
5
+
6
+ ## Files
7
+
8
+ - [100 — Periodic table constant](100-periodic-table.md)
9
+ - [101 — Element type validation constraint](101-element-type-validation.md)
10
+ - [102 — DictRef resolution constraint](102-dictref-resolution.md)
11
+ - [103 — ValidationReport summary](103-validation-report-summary.md)
12
+ - [104 — Final verification round 25](104-final-verification-round25.md)
13
+
14
+ ## Outcomes
15
+
16
+ - **`Cml::Enums::ELEMENT_TYPE_VALUES`** — 120-element frozen Set
17
+ matching XSD elementTypeType exactly. Includes the periodic table
18
+ plus "Du" (dummy) and "R" (group placeholder). Single source of
19
+ truth for valid element symbols.
20
+
21
+ - **`AtomElementTypeShouldBeInPeriodicTable`** — molecular warning
22
+ when `atom.elementType` isn't a recognised periodic table symbol.
23
+ Catches typos like "Carb", "Xx", "X" — previously silently
24
+ accepted.
25
+
26
+ - **`DictRefShouldResolve`** — molecular warning when an element's
27
+ `dictRef` attribute doesn't resolve against the built-in
28
+ dictionaries via `Chemicalml::Dictionary::Registry.lookup`. Catches
29
+ typos like `dictRef="cml:bpingpoint"`. This is a real
30
+ cross-component integration: the convention constraint system
31
+ querying the dictionary registry.
32
+
33
+ - **`ValidationReport#summary`** — human-readable multi-line summary.
34
+ Used by the CLI; useful for one-shot scripts. Format:
35
+ ```
36
+ Errors: 2, Warnings: 1
37
+
38
+ Errors:
39
+ ERROR path/a: message (value="X")
40
+ ...
41
+
42
+ Warnings:
43
+ WARN path/b: message
44
+ ...
45
+ ```
46
+
47
+ - **Real bug caught by new constraint**: existing test
48
+ `extended_constraints_spec.rb` was using `dictRef="cml:energy"`
49
+ which isn't in the cml dictionary. The new DictRefShouldResolve
50
+ constraint flagged it. Fixed the test to use the real `cml:bp`
51
+ entry — and incidentally validated that the constraint works.
52
+
53
+ - Molecular convention: 32 constraints (up from 30).
54
+
55
+ - **528 examples, 0 failures, 3 pending** (TOML adapter pending).
56
+ Zero forbidden patterns.
57
+
58
+ ## Architectural insight
59
+
60
+ The DictRefShouldResolve constraint is the first to bridge two
61
+ previously-separate subsystems (convention constraints and
62
+ dictionary registry). It validates the cross-component contract:
63
+ "a dictRef must point at a real term". This is the kind of
64
+ whole-system semantic check that's only possible when both halves
65
+ are mature — round 25 is the first round where it became worth
66
+ writing.
@@ -0,0 +1,55 @@
1
+ # Round 26 — XSD patterns, AtomParity parent check, canonical comparison
2
+
3
+ This round adds the canonical XSD pattern constants, semantic
4
+ parent-atom validation for atomParity, and a canonical document
5
+ comparison helper.
6
+
7
+ ## Files
8
+
9
+ - [105 — XSD pattern constants](105-xsd-pattern-constants.md)
10
+ - [106 — Id/namespace pattern validation](106-id-pattern-validation.md)
11
+ - [107 — AtomParity parent atom check](107-atomparity-parent-check.md)
12
+ - [108 — Canonical document comparison](108-canonical-comparison.md)
13
+ - [109 — Final verification round 26](109-final-verification-round26.md)
14
+
15
+ ## Outcomes
16
+
17
+ - **`Cml::Patterns`** — 14 frozen Regexp constants matching every XSD
18
+ simpleType that restricts by pattern (atomIDType, idType,
19
+ dictionaryPrefixType, namespaceType, refType, versionType,
20
+ formulaType, etc.). Single source of truth — a future XSD edit
21
+ that changes a pattern can be regenerated from one place.
22
+
23
+ - **`MoleculeIdShouldMatchPattern`** and **`BondIdShouldMatchPattern`**
24
+ — molecular warnings using the new patterns. Catches ids that
25
+ don't match the XSD-declared format.
26
+
27
+ - **`AtomParityShouldIncludeParentAtom`** — molecular DocumentConstraint
28
+ that walks the tree and warns when `<atomParity>`'s atomRefs4
29
+ doesn't include the parent `<atom>`'s id. Real semantic check
30
+ that closes a CML convention rule.
31
+
32
+ - **`Cml::CanonicalComparison`** — semantic document comparison.
33
+ `equal?` returns true if two documents have the same structural
34
+ fingerprint. `diff` returns a hash of element_name → count_delta.
35
+ Useful for testing and diff tools.
36
+
37
+ - **Real bugs caught during round 26**:
38
+ - DELIMITER_PATTERN had unescaped `/` — syntax error.
39
+ - `visit_with_parent` was using `yield` in recursion, causing
40
+ LocalJumpError. Fixed by using explicit `&block`.
41
+ - XSD patterns are unanchored; for validation they must be
42
+ wrapped in `\A...\z`.
43
+
44
+ - Molecular convention: 35 constraints (up from 32).
45
+
46
+ - **543 examples, 0 failures, 3 pending** (TOML adapter pending).
47
+ Zero forbidden patterns.
48
+
49
+ ## Architectural insight
50
+
51
+ The `CanonicalComparison` helper is the abstraction the round-trip
52
+ spec (TODO 95) and Schema24 complex round-trip spec (TODO 98) both
53
+ needed. Previously each spec inlined its own fingerprint function;
54
+ now there's one canonical implementation. Classic "rule of three"
55
+ refactor — the third use is the trigger to extract.