mdka 2.2.2__tar.gz → 2.3.0__tar.gz

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 (218) hide show
  1. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/ci.yaml +43 -8
  2. mdka-2.3.0/.github/workflows/crates-package-gate.yaml +103 -0
  3. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/docs-example-gate.yaml +8 -4
  4. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/docs.yaml +6 -1
  5. mdka-2.3.0/.github/workflows/pypi-published-gate.yaml +114 -0
  6. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-pypi.yaml +80 -4
  7. mdka-2.3.0/.github/workflows/scripts/check-docs-examples.py +794 -0
  8. mdka-2.3.0/.github/workflows/scripts/check-wheel-matrix.py +245 -0
  9. mdka-2.3.0/CHANGELOG.md +760 -0
  10. {mdka-2.2.2 → mdka-2.3.0}/Cargo.lock +25 -7
  11. {mdka-2.2.2 → mdka-2.3.0}/Cargo.toml +7 -2
  12. mdka-2.2.2/README.md → mdka-2.3.0/PKG-INFO +57 -15
  13. mdka-2.2.2/PKG-INFO → mdka-2.3.0/README.md +39 -28
  14. {mdka-2.2.2 → mdka-2.3.0}/ROADMAP.md +174 -20
  15. {mdka-2.2.2 → mdka-2.3.0}/docs/book.toml +7 -0
  16. {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/core.md +20 -14
  17. {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/elements.md +73 -14
  18. {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/errors.md +5 -2
  19. {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/options.md +20 -3
  20. mdka-2.3.0/docs/src/api/text-processing.md +127 -0
  21. mdka-2.3.0/docs/src/design/architecture.md +120 -0
  22. {mdka-2.2.2 → mdka-2.3.0}/docs/src/design/performance-characteristics.md +17 -0
  23. mdka-2.3.0/docs/src/getting-started/installation.md +104 -0
  24. {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-cli.md +6 -0
  25. {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-nodejs.md +55 -8
  26. {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-python.md +38 -4
  27. {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage-rust.md +20 -14
  28. {mdka-2.2.2 → mdka-2.3.0}/pyproject.toml +9 -2
  29. {mdka-2.2.2 → mdka-2.3.0}/python/Cargo.toml +2 -2
  30. {mdka-2.2.2 → mdka-2.3.0}/python/README.md +39 -15
  31. {mdka-2.2.2 → mdka-2.3.0}/python/src/lib.rs +8 -2
  32. {mdka-2.2.2 → mdka-2.3.0}/python/test_mdka.py +17 -2
  33. mdka-2.3.0/python/wheel-matrix.toml +27 -0
  34. {mdka-2.2.2 → mdka-2.3.0}/rfcs/README.md +13 -15
  35. mdka-2.3.0/rfcs/done/010-escaping-and-text-round-trip.md +182 -0
  36. {mdka-2.2.2/rfcs/accepted → mdka-2.3.0/rfcs/done}/024-inline-composition-output-sink.md +92 -1
  37. {mdka-2.2.2/rfcs/accepted → mdka-2.3.0/rfcs/done}/025-output-validity-harness.md +57 -1
  38. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/026-consumer-artifact-gates.md +61 -0
  39. {mdka-2.2.2/rfcs/accepted → mdka-2.3.0/rfcs/done}/028-emphasis-around-block-content.md +89 -8
  40. mdka-2.3.0/rfcs/done/029-published-surface-documentation-repair.md +126 -0
  41. mdka-2.3.0/rfcs/done/030-crates-package-gate-workspace-resolution.md +199 -0
  42. mdka-2.3.0/rfcs/done/031-docs-gate-must-model-mdbook.md +229 -0
  43. mdka-2.3.0/rfcs/done/032-gates-report-everything-and-execute-examples.md +127 -0
  44. mdka-2.3.0/rfcs/done/033-published-docs-source-is-what-the-reader-gets.md +232 -0
  45. mdka-2.3.0/rfcs/done/034-pypi-declared-wheel-matrix.md +327 -0
  46. mdka-2.3.0/rfcs/done/035-block-structure-inside-containers.md +131 -0
  47. mdka-2.3.0/rfcs/handoffs/010-escaping-and-text-round-trip/implementation-handoff.md +152 -0
  48. mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024b.md +107 -0
  49. mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024c.md +78 -0
  50. mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024d.md +72 -0
  51. mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/addendum-024e.md +65 -0
  52. mdka-2.3.0/rfcs/handoffs/024-inline-composition-output-sink/implementation-handoff.md +147 -0
  53. mdka-2.3.0/rfcs/handoffs/025-output-validity-harness/addendum-025c.md +121 -0
  54. mdka-2.3.0/rfcs/handoffs/025-output-validity-harness/implementation-handoff.md +285 -0
  55. mdka-2.3.0/rfcs/handoffs/028-emphasis-around-block-content/addendum-028b.md +82 -0
  56. mdka-2.3.0/rfcs/handoffs/028-emphasis-around-block-content/implementation-handoff.md +201 -0
  57. mdka-2.3.0/rfcs/handoffs/029-published-surface-documentation-repair/implementation-handoff.md +195 -0
  58. mdka-2.3.0/rfcs/handoffs/030-crates-package-gate-workspace-resolution/implementation-handoff.md +159 -0
  59. mdka-2.3.0/rfcs/handoffs/031-docs-gate-must-model-mdbook/followup-031b.md +156 -0
  60. mdka-2.3.0/rfcs/handoffs/031-docs-gate-must-model-mdbook/implementation-handoff.md +215 -0
  61. mdka-2.3.0/rfcs/handoffs/032-gates-report-everything-and-execute-examples/implementation-handoff.md +182 -0
  62. mdka-2.3.0/rfcs/handoffs/033-published-docs-source-is-what-the-reader-gets/implementation-handoff.md +189 -0
  63. mdka-2.3.0/rfcs/handoffs/034-pypi-declared-wheel-matrix/followup-034b.md +85 -0
  64. mdka-2.3.0/rfcs/handoffs/034-pypi-declared-wheel-matrix/implementation-handoff.md +252 -0
  65. mdka-2.3.0/rfcs/handoffs/035-block-structure-inside-containers/implementation-handoff.md +127 -0
  66. {mdka-2.2.2 → mdka-2.3.0}/src/lib.rs +5 -4
  67. {mdka-2.2.2 → mdka-2.3.0}/src/options.rs +10 -7
  68. mdka-2.3.0/src/renderer/escape/tests.rs +164 -0
  69. mdka-2.3.0/src/renderer/escape.rs +402 -0
  70. mdka-2.3.0/src/renderer/sink/tests.rs +133 -0
  71. mdka-2.3.0/src/renderer/sink.rs +752 -0
  72. mdka-2.3.0/src/renderer.rs +597 -0
  73. mdka-2.3.0/src/traversal.rs +283 -0
  74. mdka-2.3.0/src/utils/tests.rs +147 -0
  75. mdka-2.3.0/src/utils.rs +175 -0
  76. {mdka-2.2.2 → mdka-2.3.0}/tests/anchor_drift_guard.rs +8 -8
  77. {mdka-2.2.2 → mdka-2.3.0}/tests/block_elements.rs +53 -1
  78. {mdka-2.2.2 → mdka-2.3.0}/tests/hr_newline_reset.rs +4 -1
  79. mdka-2.3.0/tests/inline_around_blocks.rs +292 -0
  80. mdka-2.3.0/tests/inline_composition.rs +160 -0
  81. mdka-2.3.0/tests/output_validity/block_in_container.rs +56 -0
  82. mdka-2.3.0/tests/output_validity/block_in_inline.rs +75 -0
  83. mdka-2.3.0/tests/output_validity/code_context.rs +77 -0
  84. mdka-2.3.0/tests/output_validity/corpus/README.md +16 -0
  85. mdka-2.3.0/tests/output_validity/corpus.rs +96 -0
  86. mdka-2.3.0/tests/output_validity/corpus_proof/linked_inline.html +3 -0
  87. mdka-2.3.0/tests/output_validity/corpus_proof/valid.html +2 -0
  88. mdka-2.3.0/tests/output_validity/corpus_proof/violating.html +1 -0
  89. mdka-2.3.0/tests/output_validity/escaping.rs +134 -0
  90. mdka-2.3.0/tests/output_validity/field_reports.rs +32 -0
  91. mdka-2.3.0/tests/output_validity/gfm.rs +28 -0
  92. mdka-2.3.0/tests/output_validity/harness/properties.rs +728 -0
  93. mdka-2.3.0/tests/output_validity/harness/structure.rs +221 -0
  94. mdka-2.3.0/tests/output_validity/harness.rs +254 -0
  95. mdka-2.3.0/tests/output_validity/inline_in_container.rs +110 -0
  96. mdka-2.3.0/tests/output_validity/main.rs +59 -0
  97. mdka-2.3.0/tests/output_validity/proofs.rs +640 -0
  98. mdka-2.3.0/tests/output_validity/runner_fixtures/article.html +32 -0
  99. mdka-2.3.0/tests/output_validity/runner_fixtures/word-style-fragment.html +9 -0
  100. mdka-2.3.0/tests/output_validity/well_formedness.rs +44 -0
  101. {mdka-2.2.2 → mdka-2.3.0}/tests/preserve_ids_anchors.rs +8 -7
  102. mdka-2.2.2/.github/workflows/crates-package-gate.yaml +0 -78
  103. mdka-2.2.2/.github/workflows/scripts/check-docs-examples.py +0 -307
  104. mdka-2.2.2/CHANGELOG.md +0 -394
  105. mdka-2.2.2/docs/src/api/text-processing.md +0 -57
  106. mdka-2.2.2/docs/src/design/architecture.md +0 -78
  107. mdka-2.2.2/docs/src/getting-started/installation.md +0 -53
  108. mdka-2.2.2/rfcs/handoffs/024-inline-composition-output-sink/implementation-handoff.md +0 -152
  109. mdka-2.2.2/rfcs/handoffs/025-output-validity-harness/implementation-handoff.md +0 -147
  110. mdka-2.2.2/rfcs/handoffs/028-emphasis-around-block-content/implementation-handoff.md +0 -217
  111. mdka-2.2.2/src/renderer.rs +0 -455
  112. mdka-2.2.2/src/traversal.rs +0 -100
  113. mdka-2.2.2/src/utils/tests.rs +0 -93
  114. mdka-2.2.2/src/utils.rs +0 -147
  115. {mdka-2.2.2 → mdka-2.3.0}/.gitattributes +0 -0
  116. {mdka-2.2.2 → mdka-2.3.0}/.github/CODE_OF_CONDUCT.md +0 -0
  117. {mdka-2.2.2 → mdka-2.3.0}/.github/CONTRIBUTING.md +0 -0
  118. {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  119. {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  120. {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  121. {mdka-2.2.2 → mdka-2.3.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  122. {mdka-2.2.2 → mdka-2.3.0}/.github/SECURITY.md +0 -0
  123. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/create-release.yaml +0 -0
  124. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/npm-install-gate.yaml +0 -0
  125. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/pypi-wheel-gate.yaml +0 -0
  126. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-crates.yaml +0 -0
  127. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-executable.yaml +0 -0
  128. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/release-npm.yaml +0 -0
  129. {mdka-2.2.2 → mdka-2.3.0}/.github/workflows/scripts/install-rust.sh +0 -0
  130. {mdka-2.2.2 → mdka-2.3.0}/.gitignore +0 -0
  131. {mdka-2.2.2 → mdka-2.3.0}/.vscode/extensions.json +0 -0
  132. {mdka-2.2.2 → mdka-2.3.0}/.vscode/settings.json +0 -0
  133. {mdka-2.2.2 → mdka-2.3.0}/LICENSE +0 -0
  134. {mdka-2.2.2 → mdka-2.3.0}/NOTICE +0 -0
  135. {mdka-2.2.2 → mdka-2.3.0}/benches/bench_common.rs +0 -0
  136. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/deep_nest.html +0 -0
  137. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/flat.html +0 -0
  138. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/large.html +0 -0
  139. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/malformed.html +0 -0
  140. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/medium.html +0 -0
  141. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/scale_500k.html +0 -0
  142. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/scale_50k.html +0 -0
  143. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/scale_5m.html +0 -0
  144. {mdka-2.2.2 → mdka-2.3.0}/benches/benchdata/small.html +0 -0
  145. {mdka-2.2.2 → mdka-2.3.0}/benches/convert.rs +0 -0
  146. {mdka-2.2.2 → mdka-2.3.0}/benches/memory.rs +0 -0
  147. {mdka-2.2.2 → mdka-2.3.0}/benches/parallel.rs +0 -0
  148. {mdka-2.2.2 → mdka-2.3.0}/benches/scaling.rs +0 -0
  149. {mdka-2.2.2 → mdka-2.3.0}/cargo-publish.sh +0 -0
  150. {mdka-2.2.2 → mdka-2.3.0}/docs/src/SUMMARY.md +0 -0
  151. {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/index.md +0 -0
  152. {mdka-2.2.2 → mdka-2.3.0}/docs/src/api/modes.md +0 -0
  153. {mdka-2.2.2 → mdka-2.3.0}/docs/src/assets/logo.png +0 -0
  154. {mdka-2.2.2 → mdka-2.3.0}/docs/src/design/features.md +0 -0
  155. {mdka-2.2.2 → mdka-2.3.0}/docs/src/design/philosophy.md +0 -0
  156. {mdka-2.2.2 → mdka-2.3.0}/docs/src/getting-started/usage.md +0 -0
  157. {mdka-2.2.2 → mdka-2.3.0}/docs/src/introduction.md +0 -0
  158. {mdka-2.2.2 → mdka-2.3.0}/examples/measure_mem.rs +0 -0
  159. {mdka-2.2.2 → mdka-2.3.0}/examples/quick_bench.rs +0 -0
  160. {mdka-2.2.2 → mdka-2.3.0}/examples/quick_compare.rs +0 -0
  161. {mdka-2.2.2 → mdka-2.3.0}/examples/quick_mem.rs +0 -0
  162. {mdka-2.2.2 → mdka-2.3.0}/mdka/__init__.py +0 -0
  163. {mdka-2.2.2 → mdka-2.3.0}/python/example.py +0 -0
  164. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/000-rfc-lifecycle-policy.md +0 -0
  165. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/001-ci-quality-gates.md +0 -0
  166. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/002-governance-artifacts.md +0 -0
  167. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/003-architecture-doc-reconciliation.md +0 -0
  168. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/004-preprocessor-disposition.md +0 -0
  169. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/005-conversion-options-semantics.md +0 -0
  170. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/006-option-docs-and-binding-parity.md +0 -0
  171. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/007-english-only-public-surface.md +0 -0
  172. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/014-release-time-ci-verification.md +0 -0
  173. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/015-release-tooling-completion.md +0 -0
  174. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/016-hr-newline-reset.md +0 -0
  175. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/017-pre-fence-newline-reset.md +0 -0
  176. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/018-readme-prebuilt-binaries.md +0 -0
  177. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/019-release-creation-via-dispatch.md +0 -0
  178. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/020-npm-distribution-repair.md +0 -0
  179. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/021-bulk-output-collision-safety.md +0 -0
  180. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/022-cli-allocator-and-jemalloc.md +0 -0
  181. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/023-getting-started-doc-reconciliation.md +0 -0
  182. {mdka-2.2.2 → mdka-2.3.0}/rfcs/done/027-verification-discipline.md +0 -0
  183. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/001-ci-quality-gates/implementation-handoff.md +0 -0
  184. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/002-governance-artifacts/implementation-handoff.md +0 -0
  185. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/003-architecture-doc-reconciliation/implementation-handoff.md +0 -0
  186. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/004-preprocessor-disposition/implementation-handoff.md +0 -0
  187. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/005-conversion-options-semantics/implementation-handoff.md +0 -0
  188. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/005-conversion-options-semantics/slice-b1-placement-correction-handoff.md +0 -0
  189. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/005-conversion-options-semantics/slices-bc-handoff.md +0 -0
  190. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/006-option-docs-and-binding-parity/implementation-handoff.md +0 -0
  191. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/007-english-only-public-surface/implementation-handoff.md +0 -0
  192. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/014-release-time-ci-verification/implementation-handoff.md +0 -0
  193. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/015-release-tooling-completion/amendment-handoff.md +0 -0
  194. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/015-release-tooling-completion/implementation-handoff.md +0 -0
  195. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/015-release-tooling-completion/restore-handoff.md +0 -0
  196. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/016-hr-newline-reset/implementation-handoff.md +0 -0
  197. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/017-pre-fence-newline-reset/implementation-handoff.md +0 -0
  198. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/018-readme-prebuilt-binaries/implementation-handoff.md +0 -0
  199. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/019-release-creation-via-dispatch/implementation-handoff.md +0 -0
  200. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/020-npm-distribution-repair/implementation-handoff.md +0 -0
  201. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/021-bulk-output-collision-safety/implementation-handoff.md +0 -0
  202. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/022-cli-allocator-and-jemalloc/alloc-counter-deprecation-handoff.md +0 -0
  203. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/022-cli-allocator-and-jemalloc/implementation-handoff.md +0 -0
  204. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/023-getting-started-doc-reconciliation/implementation-handoff.md +0 -0
  205. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/026-consumer-artifact-gates/implementation-handoff.md +0 -0
  206. {mdka-2.2.2 → mdka-2.3.0}/rfcs/handoffs/027-verification-discipline/implementation-handoff.md +0 -0
  207. {mdka-2.2.2 → mdka-2.3.0}/src/alloc_counter.rs +0 -0
  208. {mdka-2.2.2 → mdka-2.3.0}/src/traversal/tests.rs +0 -0
  209. {mdka-2.2.2 → mdka-2.3.0}/tests/characterisation_attributes.rs +0 -0
  210. {mdka-2.2.2 → mdka-2.3.0}/tests/characterisation_elements.rs +0 -0
  211. {mdka-2.2.2 → mdka-2.3.0}/tests/characterisation_structural.rs +0 -0
  212. {mdka-2.2.2 → mdka-2.3.0}/tests/common.rs +0 -0
  213. {mdka-2.2.2 → mdka-2.3.0}/tests/compat.rs +0 -0
  214. {mdka-2.2.2 → mdka-2.3.0}/tests/file_conversion.rs +0 -0
  215. {mdka-2.2.2 → mdka-2.3.0}/tests/inline_elements.rs +0 -0
  216. {mdka-2.2.2 → mdka-2.3.0}/tests/pre_fence_newline_reset.rs +0 -0
  217. {mdka-2.2.2 → mdka-2.3.0}/tests/robustness.rs +0 -0
  218. {mdka-2.2.2 → mdka-2.3.0}/version.sh +0 -0
@@ -46,14 +46,20 @@ jobs:
46
46
  - name: cargo fmt --check
47
47
  run: cargo fmt --check
48
48
 
49
+ # --keep-going (RFC 032): report every crate's lint failures, not just the
50
+ # first crate's. clippy --help does not list it, but clippy passes it to
51
+ # cargo check and it was seen to change the output. Keep it before `--`.
49
52
  - name: cargo clippy
50
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
53
+ run: cargo clippy --workspace --all-targets --all-features --keep-going -- -D warnings
51
54
 
55
+ # --no-fail-fast (RFC 032): without it the first failing test binary stops
56
+ # the rest, so a failure in one binary hides failures in all later ones.
52
57
  - name: cargo test
53
- run: cargo test --workspace --all-features --locked
58
+ run: cargo test --workspace --all-features --locked --no-fail-fast
54
59
 
60
+ # --keep-going (RFC 032): report every target that fails to compile.
55
61
  - name: cargo build
56
- run: cargo build --workspace --locked
62
+ run: cargo build --workspace --locked --keep-going
57
63
 
58
64
  msrv:
59
65
  runs-on: ubuntu-latest
@@ -87,8 +93,10 @@ jobs:
87
93
  # --all-targets is deliberately omitted: bench dev-dependencies require a
88
94
  # newer toolchain and are advisory only, not part of the published MSRV.
89
95
  # --locked verifies the same dependency set the `rust` job saw.
96
+ # --keep-going (RFC 032): report every crate that fails to check on the
97
+ # MSRV toolchain, not just the first. Verified on 1.88.
90
98
  - name: cargo check
91
- run: cargo check --workspace --locked
99
+ run: cargo check --workspace --locked --keep-going
92
100
 
93
101
  node:
94
102
  runs-on: ubuntu-latest
@@ -136,6 +144,14 @@ jobs:
136
144
  python:
137
145
  runs-on: ubuntu-latest
138
146
  timeout-minutes: 20
147
+ strategy:
148
+ fail-fast: false
149
+ matrix:
150
+ # RFC 034: the declared floor (python/wheel-matrix.toml python-floor)
151
+ # and the newest stable CPython. The floor entry is asserted equal to
152
+ # python-floor below. When CI can no longer install the floor, this
153
+ # job goes red -- that is trigger 1 for raising it.
154
+ python: ["3.10", "3.x"]
139
155
 
140
156
  steps:
141
157
  - name: Checkout repository
@@ -144,7 +160,7 @@ jobs:
144
160
  - name: Setup Python
145
161
  uses: actions/setup-python@v6
146
162
  with:
147
- python-version: 3.x
163
+ python-version: ${{ matrix.python }}
148
164
 
149
165
  - name: Cache cargo dependencies and build
150
166
  uses: actions/cache@v5
@@ -153,9 +169,9 @@ jobs:
153
169
  ~/.cargo/registry
154
170
  ~/.cargo/git
155
171
  target
156
- key: ${{ runner.os }}-cargo-python-${{ hashFiles('**/Cargo.lock') }}
172
+ key: ${{ runner.os }}-cargo-python-${{ matrix.python }}-${{ hashFiles('**/Cargo.lock') }}
157
173
  restore-keys: |
158
- ${{ runner.os }}-cargo-python-
174
+ ${{ runner.os }}-cargo-python-${{ matrix.python }}-
159
175
 
160
176
  # python/pyproject.toml declares readme = "README.md" but the README lives
161
177
  # at the repository root. Required — omitting this fails the build (see
@@ -166,9 +182,27 @@ jobs:
166
182
  - name: Install uv
167
183
  uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
168
184
 
185
+ # The script needs Python >= 3.11 (tomllib), so uv supplies one
186
+ # separately from the interpreter under test.
187
+ - name: Declared floor matches this matrix and the manifests
188
+ run: |
189
+ set -euo pipefail
190
+ check() {
191
+ uv run --no-project --python 3.13 --with packaging -- \
192
+ python .github/workflows/scripts/check-wheel-matrix.py "$@"
193
+ }
194
+ if [ "${{ matrix.python }}" != "3.x" ]; then
195
+ check floor-equals "ci.yaml python matrix" "${{ matrix.python }}"
196
+ fi
197
+ check floor-manifests
198
+
199
+ # `uv venv` alone may pick a different interpreter than the matrix one;
200
+ # name it explicitly and print what the venv actually runs.
169
201
  - name: Install maturin and pytest
170
202
  run: |
171
- uv venv
203
+ uv venv --python "$(python -c 'import sys; print(sys.executable)')"
204
+ source .venv/bin/activate
205
+ python --version
172
206
  uv pip install maturin pytest
173
207
 
174
208
  - name: maturin develop
@@ -181,4 +215,5 @@ jobs:
181
215
  working-directory: python
182
216
  run: |
183
217
  source ../.venv/bin/activate
218
+ python --version
184
219
  python -m pytest test_mdka.py
@@ -0,0 +1,103 @@
1
+ name: crates package gate
2
+
3
+ # RFC 026 §4.2. The `rust` job in ci.yaml runs `cargo test` in-workspace,
4
+ # where every path dependency resolves and every file is present. It cannot
5
+ # see a crate that compiles here and fails standalone -- through a missing
6
+ # `include`, a path dependency with no version, or a file absent from the
7
+ # packaged .crate.
8
+ #
9
+ # `cargo package` (without --no-verify) packages each crate and then builds
10
+ # from the extracted package, where path dependencies are stripped. That is
11
+ # the consumer's build.
12
+ #
13
+ # RFC 030: this is ONE `--workspace` invocation, not four per-crate steps,
14
+ # and that is deliberate. Packaging the dependents separately makes each
15
+ # resolve `mdka` from crates.io -- but on main the workspace version is the
16
+ # NEXT version, which is not published yet, so mdka-cli failed with
17
+ # "failed to select a version for the requirement mdka = ^X.Y.Z" at every
18
+ # release commit. Worse, that failure skipped mdka-node and mdka-python
19
+ # entirely, so the red masked the gate's own coverage: across 2.2.2 and
20
+ # 2.2.3 nothing verified that those two package and build standalone.
21
+ #
22
+ # `--workspace` builds a temporary local registry from the packaged members
23
+ # (target/package/tmp-registry/) and resolves the dependents against it, so
24
+ # it works whether or not the version is published. Do not "simplify" this
25
+ # back into four steps.
26
+ #
27
+ # Its own workflow file, not ci.yaml -- see RFC 026 §3.5 and RFC 020's
28
+ # correction record.
29
+
30
+ on:
31
+ push:
32
+ branches: [main]
33
+ pull_request:
34
+ branches: [main]
35
+ workflow_dispatch:
36
+
37
+ permissions:
38
+ contents: read
39
+
40
+ concurrency:
41
+ group: ${{ github.workflow }}-${{ github.ref }}
42
+ cancel-in-progress: true
43
+
44
+ defaults:
45
+ run:
46
+ shell: bash
47
+
48
+ jobs:
49
+ crates-package-gate:
50
+ runs-on: ubuntu-latest
51
+ timeout-minutes: 30
52
+
53
+ steps:
54
+ - name: Checkout repository
55
+ uses: actions/checkout@v6
56
+
57
+ - name: Cache cargo dependencies and build
58
+ uses: actions/cache@v5
59
+ with:
60
+ path: |
61
+ ~/.cargo/registry
62
+ ~/.cargo/git
63
+ target
64
+ key: ${{ runner.os }}-cargo-package-gate-${{ hashFiles('**/Cargo.lock') }}
65
+ restore-keys: |
66
+ ${{ runner.os }}-cargo-package-gate-
67
+
68
+ # No --no-verify anywhere. Packaging without building the result would
69
+ # check that the tarball can be produced, not that it works -- which is
70
+ # the distinction this whole milestone is about.
71
+ #
72
+ # No --keep-going either, deliberately (RFC 032). cargo package --help
73
+ # lists it, but it changed nothing when tested: package verifies members
74
+ # one after another, and the flag only continues within a single build.
75
+ # A second broken crate is still reported only after the first is fixed.
76
+ - name: cargo package --workspace
77
+ run: cargo package --workspace --locked
78
+
79
+ # Scoped to the workspace's current version, and asserts there are four
80
+ # of them. target/ is restored from the cache, so an unfiltered glob
81
+ # lists every version packaged since the cache was last cold -- twelve
82
+ # .crate files across three versions, at the time of writing -- which
83
+ # reads as though this run produced them all. The count check also turns
84
+ # the listing from decoration into an assertion that every member was
85
+ # packaged.
86
+ - name: Show what each package actually contains
87
+ run: |
88
+ set -euo pipefail
89
+ version=$(cargo metadata --format-version 1 --no-deps \
90
+ | python3 -c 'import json,sys; print(next(p["version"] for p in json.load(sys.stdin)["packages"] if p["name"] == "mdka"))')
91
+ echo "workspace version: $version"
92
+
93
+ mapfile -t crates < <(ls target/package/*-"$version".crate)
94
+ if [ "${#crates[@]}" -ne 4 ]; then
95
+ echo "::error::expected 4 .crate files at $version, found ${#crates[@]}"
96
+ printf ' %s\n' "${crates[@]}"
97
+ exit 1
98
+ fi
99
+
100
+ for crate in "${crates[@]}"; do
101
+ echo "=== $crate"
102
+ tar -tzf "$crate" | sed 's/^/ /'
103
+ done
@@ -60,9 +60,13 @@ jobs:
60
60
  restore-keys: |
61
61
  ${{ runner.os }}-cargo-docs-gate-
62
62
 
63
- # The TypeScript examples are checked against the generated
64
- # declarations, so those must exist and be current.
65
- - name: Generate the TypeScript declarations
63
+ # Builds the native binding as well as the declarations, and BOTH are
64
+ # used: TypeScript examples type-check against index.d.ts, and JavaScript
65
+ # examples are EXECUTED against the built binding (RFC 031) -- a syntax
66
+ # check alone passed an example that failed at load. Without this step
67
+ # every JS example is reported as a failure ("no built binding"), so the
68
+ # gate goes red rather than quietly skipping execution.
69
+ - name: Build the Node binding and its TypeScript declarations
66
70
  working-directory: node
67
71
  run: |
68
72
  npm ci
@@ -88,7 +92,7 @@ jobs:
88
92
  python -m venv "$RUNNER_TEMP/docs-venv"
89
93
  "$RUNNER_TEMP/docs-venv/bin/pip" install --no-index "$RUNNER_TEMP"/wheels/mdka-*.whl
90
94
 
91
- - name: Check every runnable example in docs/src/
95
+ - name: Check every runnable example in docs/src/ and README.md
92
96
  run: |
93
97
  python .github/workflows/scripts/check-docs-examples.py \
94
98
  --python "$RUNNER_TEMP/docs-venv/bin/python"
@@ -31,8 +31,13 @@ jobs:
31
31
  id: pages
32
32
  uses: actions/configure-pages@v6
33
33
 
34
+ # Pinned exactly (RFC 033). The docs example gate models this mdBook: its
35
+ # wrapping of Rust examples, its hidden-line rule, and its copy button,
36
+ # which omits hidden lines. Before moving the pin, re-check all three in
37
+ # .github/workflows/scripts/check-docs-examples.py. 0.5.4 is what `^0.5`
38
+ # resolved to when pinned.
34
39
  - name: Install mdBook
35
- run: cargo install mdbook --no-default-features --features search --vers "^0.5" --locked
40
+ run: cargo install mdbook --no-default-features --features search --vers "=0.5.4" --locked
36
41
 
37
42
  - name: Build book
38
43
  run: mdbook build
@@ -0,0 +1,114 @@
1
+ name: pypi published gate
2
+
3
+ # RFC 034 §4.4. Checks what PyPI actually serves for the latest release, the
4
+ # way the npm install gate checks npm:
5
+ #
6
+ # 1. the published file set equals python/wheel-matrix.toml -- the same
7
+ # script release-pypi.yaml runs before upload, so the two cannot disagree;
8
+ # 2. the release installs FROM PyPI, wheel only, at the declared floor and
9
+ # at the newest stable CPython, and converts;
10
+ # 3. installation.md states the declared floor.
11
+ #
12
+ # Its own workflow file, not ci.yaml: the release workflows gate on ci.yaml's
13
+ # conclusion, so a gate there can block the release that would make it pass
14
+ # (RFC 020's correction record).
15
+ #
16
+ # `pypi wheel gate` is a different check: it installs a wheel BUILT FROM THE
17
+ # TREE. This one reports on the LAST PUBLISHED release, so it lags the tree --
18
+ # a published artifact cannot be verified before it is published.
19
+
20
+ on:
21
+ push:
22
+ branches: [main]
23
+ pull_request:
24
+ branches: [main]
25
+ workflow_dispatch:
26
+ schedule:
27
+ # Catch a registry-side change even when nobody pushes.
28
+ - cron: '0 6 * * 1'
29
+
30
+ permissions:
31
+ contents: read
32
+
33
+ defaults:
34
+ run:
35
+ shell: bash
36
+
37
+ jobs:
38
+ file-set:
39
+ runs-on: ubuntu-latest
40
+ timeout-minutes: 10
41
+ outputs:
42
+ version: ${{ steps.pypi.outputs.version }}
43
+ floor: ${{ steps.floor.outputs.floor }}
44
+
45
+ steps:
46
+ - name: Checkout repository
47
+ uses: actions/checkout@v6
48
+
49
+ - name: Setup Python
50
+ uses: actions/setup-python@v6
51
+ with:
52
+ python-version: 3.x
53
+
54
+ - name: Install packaging
55
+ run: python -m pip install packaging
56
+
57
+ - name: Read the latest release from PyPI
58
+ id: pypi
59
+ run: |
60
+ set -euo pipefail
61
+ curl -fsSL https://pypi.org/pypi/mdka/json -o "$RUNNER_TEMP/pypi.json"
62
+ version=$(python -c "import json,sys; print(json.load(open(sys.argv[1]))['info']['version'])" "$RUNNER_TEMP/pypi.json")
63
+ echo "version=$version" >> "$GITHUB_OUTPUT"
64
+
65
+ - name: Read the declared floor
66
+ id: floor
67
+ run: echo "floor=$(python .github/workflows/scripts/check-wheel-matrix.py floor)" >> "$GITHUB_OUTPUT"
68
+
69
+ # Before applies-from this prints a ::notice:: and passes: the policy
70
+ # never governed that release. It is not silent, and it ends by itself
71
+ # when the first release under the policy publishes.
72
+ - name: Published file set equals the declared matrix
73
+ run: python .github/workflows/scripts/check-wheel-matrix.py published "$RUNNER_TEMP/pypi.json"
74
+
75
+ - name: installation.md states the declared floor
76
+ run: python .github/workflows/scripts/check-wheel-matrix.py floor-doc docs/src/getting-started/installation.md
77
+
78
+ install:
79
+ needs: [file-set]
80
+ runs-on: ubuntu-latest
81
+ timeout-minutes: 10
82
+ strategy:
83
+ fail-fast: false
84
+ matrix:
85
+ # The declared floor comes from wheel-matrix.toml via file-set; "3.x"
86
+ # is the newest stable CPython.
87
+ python: [floor, "3.x"]
88
+
89
+ steps:
90
+ - name: Setup Python
91
+ uses: actions/setup-python@v6
92
+ with:
93
+ python-version: ${{ matrix.python == 'floor' && needs.file-set.outputs.floor || matrix.python }}
94
+
95
+ # --only-binary :all: is the point of this step. The runner has a Rust
96
+ # toolchain: without the flag a missing wheel falls back to building
97
+ # the sdist, the install succeeds, and the gate passes on exactly the
98
+ # defect it exists to catch.
99
+ - name: Install the published wheel from PyPI and convert
100
+ env:
101
+ VERSION: ${{ needs.file-set.outputs.version }}
102
+ run: |
103
+ set -euo pipefail
104
+ python -m venv "$RUNNER_TEMP/venv"
105
+ source "$RUNNER_TEMP/venv/bin/activate"
106
+ python --version
107
+ cd "$RUNNER_TEMP"
108
+ python -m pip install --only-binary :all: --no-cache-dir "mdka==${VERSION}"
109
+ python -c "
110
+ import mdka
111
+ out = mdka.html_to_markdown('<h1>x</h1>')
112
+ assert '# x' in out, repr(out)
113
+ print('OK: mdka', mdka.version(), 'installs from a wheel and converts:', repr(out))
114
+ "
@@ -78,10 +78,24 @@ jobs:
78
78
  with:
79
79
  working-directory: python
80
80
  target: ${{ matrix.platform.target }}
81
- args: --release --out dist --find-interpreter
81
+ # RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
82
+ # cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
83
+ # exactly one wheel instead of one per interpreter the runner happens
84
+ # to carry. The declared set is python/wheel-matrix.toml.
85
+ args: --release --out dist
82
86
  sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
83
87
  manylinux: auto
84
88
 
89
+ - name: Require exactly one wheel
90
+ run: |
91
+ set -euo pipefail
92
+ ls -la python/dist
93
+ count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
94
+ if [ "$count" -ne 1 ]; then
95
+ echo "::error::expected exactly 1 wheel in python/dist, found $count"
96
+ exit 1
97
+ fi
98
+
85
99
  - name: Upload wheels
86
100
  uses: actions/upload-artifact@v7
87
101
  with:
@@ -126,10 +140,24 @@ jobs:
126
140
  with:
127
141
  working-directory: python
128
142
  target: ${{ matrix.platform.target }}
129
- args: --release --out dist --find-interpreter
143
+ # RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
144
+ # cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
145
+ # exactly one wheel instead of one per interpreter the runner happens
146
+ # to carry. The declared set is python/wheel-matrix.toml.
147
+ args: --release --out dist
130
148
  sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
131
149
  manylinux: musllinux_1_2
132
150
 
151
+ - name: Require exactly one wheel
152
+ run: |
153
+ set -euo pipefail
154
+ ls -la python/dist
155
+ count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
156
+ if [ "$count" -ne 1 ]; then
157
+ echo "::error::expected exactly 1 wheel in python/dist, found $count"
158
+ exit 1
159
+ fi
160
+
133
161
  - name: Upload wheels
134
162
  uses: actions/upload-artifact@v7
135
163
  with:
@@ -173,9 +201,23 @@ jobs:
173
201
  with:
174
202
  working-directory: python
175
203
  target: ${{ matrix.platform.target }}
176
- args: --release --out dist --find-interpreter
204
+ # RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
205
+ # cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
206
+ # exactly one wheel instead of one per interpreter the runner happens
207
+ # to carry. The declared set is python/wheel-matrix.toml.
208
+ args: --release --out dist
177
209
  sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
178
210
 
211
+ - name: Require exactly one wheel
212
+ run: |
213
+ set -euo pipefail
214
+ ls -la python/dist
215
+ count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
216
+ if [ "$count" -ne 1 ]; then
217
+ echo "::error::expected exactly 1 wheel in python/dist, found $count"
218
+ exit 1
219
+ fi
220
+
179
221
  - name: Upload wheels
180
222
  uses: actions/upload-artifact@v7
181
223
  with:
@@ -218,9 +260,23 @@ jobs:
218
260
  with:
219
261
  working-directory: python
220
262
  target: ${{ matrix.platform.target }}
221
- args: --release --out dist --find-interpreter
263
+ # RFC 034: no --find-interpreter. PyO3's abi3-py310 feature makes one
264
+ # cp310-abi3 wheel valid on every CPython >= 3.10, so each job builds
265
+ # exactly one wheel instead of one per interpreter the runner happens
266
+ # to carry. The declared set is python/wheel-matrix.toml.
267
+ args: --release --out dist
222
268
  sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
223
269
 
270
+ - name: Require exactly one wheel
271
+ run: |
272
+ set -euo pipefail
273
+ ls -la python/dist
274
+ count=$(find python/dist -maxdepth 1 -name '*.whl' | wc -l)
275
+ if [ "$count" -ne 1 ]; then
276
+ echo "::error::expected exactly 1 wheel in python/dist, found $count"
277
+ exit 1
278
+ fi
279
+
224
280
  - name: Upload wheels
225
281
  uses: actions/upload-artifact@v7
226
282
  with:
@@ -263,6 +319,10 @@ jobs:
263
319
  contents: read
264
320
 
265
321
  steps:
322
+ # For python/wheel-matrix.toml, pyproject.toml and the check script.
323
+ # Checked out before the download, so it cannot clean the artifacts away.
324
+ - uses: actions/checkout@v6
325
+
266
326
  - name: Install uv
267
327
  uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
268
328
 
@@ -279,6 +339,22 @@ jobs:
279
339
  find artifacts -type f \( -name '*.whl' -o -name '*.tar.gz' \) -exec cp -f {} dist/ \;
280
340
  ls -la dist
281
341
 
342
+ # RFC 034 §4.3. The last point where a wrong file set can be prevented:
343
+ # a PyPI filename can never be re-uploaded. Runs on tags AND on
344
+ # workflow_dispatch, so a dry run exercises it. `cp -f` above would let a
345
+ # same-named file from one job overwrite another's; with one wheel per
346
+ # job that cannot happen, and if it ever does it shows up here as a
347
+ # missing file. The published gate runs the same script after upload.
348
+ - name: Check distributables against the declared wheel matrix
349
+ env:
350
+ TAG: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || '' }}
351
+ run: |
352
+ set -euo pipefail
353
+ tag_args=()
354
+ if [ -n "$TAG" ]; then tag_args=(--tag "$TAG"); fi
355
+ uv run --no-project --python 3.13 --with packaging -- \
356
+ python .github/workflows/scripts/check-wheel-matrix.py files --dir dist "${tag_args[@]}"
357
+
282
358
  - name: Publish to PyPI
283
359
  if: ${{ startsWith(github.ref, 'refs/tags/') }}
284
360
  run: uv publish dist/*