draftwright 0.4.8__tar.gz → 0.4.10__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 (274) hide show
  1. draftwright-0.4.10/.gitignore +28 -0
  2. {draftwright-0.4.8 → draftwright-0.4.10}/CHANGELOG.md +241 -35
  3. {draftwright-0.4.8 → draftwright-0.4.10}/PKG-INFO +8 -2
  4. {draftwright-0.4.8 → draftwright-0.4.10}/README.md +6 -0
  5. {draftwright-0.4.8 → draftwright-0.4.10}/docs/adr/README.md +4 -3
  6. {draftwright-0.4.8 → draftwright-0.4.10}/docs/reference/recogniser-capabilities.md +26 -10
  7. draftwright-0.4.10/docs/reference/sheet.md +71 -0
  8. {draftwright-0.4.8 → draftwright-0.4.10}/pyproject.toml +4 -2
  9. {draftwright-0.4.8 → draftwright-0.4.10}/skills/SKILL.md +15 -2
  10. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/__init__.py +7 -0
  11. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/_core.py +86 -17
  12. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/_geometry.py +420 -1
  13. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/analysis.py +173 -3
  14. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/_common.py +208 -22
  15. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/balloons.py +83 -52
  16. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/from_model.py +836 -205
  17. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/holes.py +71 -11
  18. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/leaders.py +338 -23
  19. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/orchestrator.py +265 -7
  20. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/sections.py +298 -108
  21. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/builder.py +460 -34
  22. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/compose.py +270 -50
  23. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/drawing.py +425 -100
  24. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/evaluation/step_analysis.py +227 -6
  25. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/__init__.py +12 -1
  26. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/coverage.py +44 -2
  27. draftwright-0.4.10/src/draftwright/linting/evidence.py +423 -0
  28. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/hole_coverage.py +92 -20
  29. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/pmi_coverage.py +63 -4
  30. draftwright-0.4.10/src/draftwright/linting/quality.py +680 -0
  31. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/structural.py +246 -111
  32. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/model/__init__.py +5 -0
  33. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/model/callout.py +26 -0
  34. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/model/compiled.py +220 -29
  35. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/model/declare.py +114 -13
  36. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/model/detect.py +81 -19
  37. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/model/ir.py +37 -8
  38. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/model/planner.py +544 -39
  39. draftwright-0.4.10/src/draftwright/model/pmi_lowering.py +276 -0
  40. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/projection.py +222 -28
  41. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/recogniser_contract.py +183 -15
  42. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/repair.py +7 -0
  43. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/sheet.py +558 -27
  44. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/sheet_emit.py +45 -5
  45. draftwright-0.4.10/src/draftwright/view_plan.py +710 -0
  46. {draftwright-0.4.8 → draftwright-0.4.10}/tests/conftest.py +73 -0
  47. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/bracket_section.json +11 -1
  48. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/centered_rebate.json +4 -0
  49. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/chamfered.json +40 -36
  50. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/filleted.json +40 -36
  51. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/flange_dense.json +4 -0
  52. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/grid_plate.json +9 -0
  53. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/grooved_shaft.json +9 -0
  54. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/hex_bar.json +4 -0
  55. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/holed_slot.json +4 -0
  56. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/pocketed.json +11 -1
  57. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/prismatic_ladder.json +44 -40
  58. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/scattered_plate.json +9 -0
  59. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/side_drilled.json +4 -0
  60. {draftwright-0.4.8 → draftwright-0.4.10}/tests/refactor_golden/turned_stepped.json +4 -0
  61. draftwright-0.4.10/tests/test_adr0018_arrangement_gate.py +383 -0
  62. draftwright-0.4.10/tests/test_adr0018_view_routing.py +115 -0
  63. draftwright-0.4.10/tests/test_adr0018_view_selection.py +566 -0
  64. draftwright-0.4.10/tests/test_architecture_docs.py +25 -0
  65. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_audit_differential.py +13 -9
  66. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_compiled_plan_boundary.py +7 -7
  67. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_detect_registry.py +36 -2
  68. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_drawing_encapsulation.py +11 -0
  69. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_e2e_standards.py +37 -16
  70. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_flat_completeness.py +14 -8
  71. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_flat_stock_identity.py +10 -16
  72. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_import_boundaries.py +13 -1
  73. draftwright-0.4.10/tests/test_iso_nts_caption_placement.py +611 -0
  74. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1073_cross_body_patterns.py +19 -7
  75. draftwright-0.4.10/tests/test_issue_1116_ap242_hole_tolerance_lowering.py +395 -0
  76. draftwright-0.4.10/tests/test_issue_1130_view_planning_evidence.py +211 -0
  77. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1143_hole_completeness.py +40 -1
  78. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1144_transactional_hole_table.py +34 -11
  79. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1146_scale_completeness.py +46 -4
  80. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1147_legibility_pair_aggregation.py +15 -2
  81. draftwright-0.4.10/tests/test_issue_1153_contradictory_dimensions.py +292 -0
  82. draftwright-0.4.10/tests/test_issue_1154_one_owner_per_measurement.py +584 -0
  83. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1166_cross_pass_feature_leaders.py +33 -20
  84. draftwright-0.4.10/tests/test_issue_1176_quality_fidelity.py +988 -0
  85. draftwright-0.4.10/tests/test_issue_1177_angular_dimensions.py +518 -0
  86. draftwright-0.4.10/tests/test_issue_1187_unroutable_leaders.py +111 -0
  87. draftwright-0.4.10/tests/test_issue_1188_per_view_assignment.py +109 -0
  88. draftwright-0.4.10/tests/test_issue_1190_section_decision.py +253 -0
  89. draftwright-0.4.10/tests/test_issue_1196_deterministic_view_names.py +422 -0
  90. draftwright-0.4.10/tests/test_issue_1202_observed_drawing_consumer.py +625 -0
  91. draftwright-0.4.10/tests/test_issue_1204_multiscale_view_issues.py +335 -0
  92. draftwright-0.4.10/tests/test_issue_1215_envelope_tolerance.py +326 -0
  93. draftwright-0.4.10/tests/test_issue_1215_no_approved_tolerance_is_dropped.py +913 -0
  94. draftwright-0.4.10/tests/test_issue_1216_callout_reservation_measures_ink.py +167 -0
  95. draftwright-0.4.10/tests/test_issue_1216_pairwise_across_scale_groups.py +125 -0
  96. draftwright-0.4.10/tests/test_issue_1217_claimed_representations.py +490 -0
  97. draftwright-0.4.10/tests/test_issue_1217_the_facility_is_shared.py +422 -0
  98. draftwright-0.4.10/tests/test_issue_1219_location_claims_its_own_axis.py +268 -0
  99. draftwright-0.4.10/tests/test_issue_1229_ledger_member_keying.py +177 -0
  100. draftwright-0.4.10/tests/test_issue_1240_iso_above_strip_visibility.py +413 -0
  101. draftwright-0.4.10/tests/test_issue_1254_turned_chamfers.py +159 -0
  102. draftwright-0.4.10/tests/test_issue_1260_view_constraints.py +462 -0
  103. draftwright-0.4.10/tests/test_issue_1276_turned_leader_targets.py +332 -0
  104. draftwright-0.4.10/tests/test_issue_1281_turned_fillets.py +113 -0
  105. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_676_polygonal_boss.py +11 -7
  106. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_740_leader_assignment.py +6 -1
  107. draftwright-0.4.10/tests/test_issue_798_floor_cardinality.py +202 -0
  108. draftwright-0.4.10/tests/test_issue_798_material_field.py +495 -0
  109. draftwright-0.4.10/tests/test_issue_798_silhouette_lint.py +312 -0
  110. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_916_pocket_leader.py +5 -1
  111. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_917_open_channel.py +4 -1
  112. draftwright-0.4.10/tests/test_issue_924_zero_length_shoulders.py +118 -0
  113. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_958_cross_solid_recognition.py +7 -1
  114. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_label_provenance.py +10 -5
  115. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_layout_hypothesis.py +1 -0
  116. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_lint_structural.py +20 -81
  117. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_make_drawing.py +193 -85
  118. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_pitch_dim_footprint.py +36 -2
  119. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_pmi.py +92 -29
  120. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_private_test_attr_reads.py +5 -0
  121. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_private_test_imports.py +32 -2
  122. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_quality_components.py +41 -1
  123. draftwright-0.4.10/tests/test_recogniser_adoption.py +43 -0
  124. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_recogniser_capabilities.py +259 -40
  125. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_recognition.py +20 -4
  126. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_recognition_manifest.py +148 -22
  127. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_recognition_result.py +22 -148
  128. draftwright-0.4.10/tests/test_refactor_golden.py +432 -0
  129. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_render_seam.py +136 -17
  130. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_sheet_emit.py +9 -1
  131. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_sheet_gdt.py +2 -1
  132. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_sheet_identity_invariant.py +61 -7
  133. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_sheet_notes.py +4 -2
  134. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_slanted_blind_step.py +8 -1
  135. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_slot_completeness.py +12 -6
  136. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_strip_layout.py +28 -10
  137. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_suppression_ledger.py +11 -1
  138. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_tolerances.py +278 -18
  139. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_two_repository_workflow.py +72 -3
  140. draftwright-0.4.10/tests/test_view_plan.py +572 -0
  141. draftwright-0.4.8/.gitignore +0 -16
  142. draftwright-0.4.8/docs/reference/sheet.md +0 -35
  143. draftwright-0.4.8/src/draftwright/linting/quality.py +0 -340
  144. draftwright-0.4.8/tests/test_architecture_docs.py +0 -43
  145. draftwright-0.4.8/tests/test_refactor_golden.py +0 -261
  146. {draftwright-0.4.8 → draftwright-0.4.10}/LICENSE +0 -0
  147. {draftwright-0.4.8 → draftwright-0.4.10}/docs/research/1062-repeating-radial-profile-evidence.md +0 -0
  148. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/_pmi_part21.py +0 -0
  149. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/_warnings.py +0 -0
  150. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotate.py +0 -0
  151. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/__init__.py +0 -0
  152. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/annotations/gears.py +0 -0
  153. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/audit.py +0 -0
  154. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/cli.py +0 -0
  155. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/evaluation/__init__.py +0 -0
  156. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/export.py +0 -0
  157. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/fits.py +0 -0
  158. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/fonts/IBMPlexMono-Regular.ttf +0 -0
  159. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/fonts/IBMPlexSansCondensed-Regular.ttf +0 -0
  160. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/fonts/LICENSE-IBMPlexMono-OFL.txt +0 -0
  161. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +0 -0
  162. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/fonts/__init__.py +0 -0
  163. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/intents.py +0 -0
  164. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/layout.py +0 -0
  165. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/channel_coverage.py +0 -0
  166. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/flat_coverage.py +0 -0
  167. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/gear_coverage.py +0 -0
  168. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/issues.py +0 -0
  169. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/polygonal_stock_coverage.py +0 -0
  170. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/profiled_bore_coverage.py +0 -0
  171. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/slot_coverage.py +0 -0
  172. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/linting/suggest.py +0 -0
  173. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/make_drawing.py +0 -0
  174. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/pmi.py +0 -0
  175. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/py.typed +0 -0
  176. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/recognition/__init__.py +0 -0
  177. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/recognition_cache.py +0 -0
  178. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/registry.py +0 -0
  179. {draftwright-0.4.8 → draftwright-0.4.10}/src/draftwright/score.py +0 -0
  180. {draftwright-0.4.8 → draftwright-0.4.10}/tests/_kernel.py +0 -0
  181. {draftwright-0.4.8 → draftwright-0.4.10}/tests/_layout_sig.py +0 -0
  182. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/evaluation/README.md +0 -0
  183. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/evaluation/ambiguous-open-semicircle.step +0 -0
  184. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/evaluation/blind-hole.step +0 -0
  185. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/evaluation/corpus-v1.json +0 -0
  186. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/evaluation/plain-block.step +0 -0
  187. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/evaluation/topology-a.step +0 -0
  188. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/evaluation/topology-b.step +0 -0
  189. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/grm03_thumbwheel_drive_screw.step +0 -0
  190. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/if_step_flat_across_cylinder.step +0 -0
  191. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/issue_1058_wheel_rh.step +0 -0
  192. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/issue_909_basic_part_design_017_body.step +0 -0
  193. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/issue_915_case_study_2.step +0 -0
  194. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_01_asme1_ap203.stp +0 -0
  195. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_01_asme1_ap242.stp +0 -0
  196. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_02_asme1_ap203.stp +0 -0
  197. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_02_asme1_ap242.stp +0 -0
  198. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_03_asme1_ap203.stp +0 -0
  199. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_03_asme1_ap242.stp +0 -0
  200. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_04_asme1_ap203.stp +0 -0
  201. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_04_asme1_ap242.stp +0 -0
  202. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_05_asme1_ap203.stp +0 -0
  203. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/nist_ctc_05_asme1_ap242.stp +0 -0
  204. {draftwright-0.4.8 → draftwright-0.4.10}/tests/fixtures/tuner_jig_blind_obround_pockets.step +0 -0
  205. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_add_dimension.py +0 -0
  206. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_agents_guide.py +0 -0
  207. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_api_docs.py +0 -0
  208. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_balloon_ring_standoff.py +0 -0
  209. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_carve_free_position_callers.py +0 -0
  210. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_counting_calls.py +0 -0
  211. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_cross_repository_delivery_protocol.py +0 -0
  212. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_declare.py +0 -0
  213. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_declared_recognition_gate.py +0 -0
  214. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_dense_sheet_canary.py +0 -0
  215. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_deprecation_dates.py +0 -0
  216. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_detect_once.py +0 -0
  217. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_dimension_role_vocabulary.py +0 -0
  218. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_e2e_slice.py +0 -0
  219. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_export_dxf_curves.py +0 -0
  220. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_export_dxf_zoom.py +0 -0
  221. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_external_recognition_boundary.py +0 -0
  222. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_fillets_adjacency.py +0 -0
  223. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_fits.py +0 -0
  224. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_flat_stock_opposition.py +0 -0
  225. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_gdt_placement.py +0 -0
  226. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_grid_lattice_convention.py +0 -0
  227. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1000_envelope_reuse.py +0 -0
  228. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1058_wheel_profile.py +0 -0
  229. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1082_polygonal_stock.py +0 -0
  230. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1086_declared_gears.py +0 -0
  231. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_1142_hole_leader_labels.py +0 -0
  232. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_367_leader_ink.py +0 -0
  233. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_676_polygonal_boss_declare.py +0 -0
  234. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_885_prismatic_coverage.py +0 -0
  235. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_909_sloped_profile.py +0 -0
  236. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_915_dense_case.py +0 -0
  237. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_issue_955_height_contingency.py +0 -0
  238. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_layout.py +0 -0
  239. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_layout_cleanliness.py +0 -0
  240. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_layout_property.py +0 -0
  241. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_leader_footprint.py +0 -0
  242. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_lint_box_cache.py +0 -0
  243. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_lint_reconciliation.py +0 -0
  244. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_linting.py +0 -0
  245. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_location_vocabulary.py +0 -0
  246. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_note_verb.py +0 -0
  247. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_object_aspects.py +0 -0
  248. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_occupancy_boxes.py +0 -0
  249. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_parameter_id.py +0 -0
  250. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_part_model.py +0 -0
  251. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_pmi_datum_lowering.py +0 -0
  252. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_pmi_gtol_lowering.py +0 -0
  253. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_pmi_part21.py +0 -0
  254. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_pocket_pattern.py +0 -0
  255. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_pocket_pattern_recognition.py +0 -0
  256. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_principal_profile_classifier.py +0 -0
  257. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_recogniser_contract.py +0 -0
  258. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_registry.py +0 -0
  259. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_repack_geometry_seam.py +0 -0
  260. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_score.py +0 -0
  261. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_script_detail_parity.py +0 -0
  262. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_shared_box_memo.py +0 -0
  263. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_sheet_of.py +0 -0
  264. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_sheet_section.py +0 -0
  265. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_sheet_tables.py +0 -0
  266. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_slot_pattern.py +0 -0
  267. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_slot_pattern_recognition.py +0 -0
  268. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_soft_deprecation.py +0 -0
  269. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_solve_trace.py +0 -0
  270. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_step_analysis_evaluation.py +0 -0
  271. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_suppression_marks.py +0 -0
  272. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_turned_steps.py +0 -0
  273. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_witness_label_reconciliation.py +0 -0
  274. {draftwright-0.4.8 → draftwright-0.4.10}/tests/test_workflows.py +0 -0
@@ -0,0 +1,28 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ .venv/
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .pytest_cache/
9
+ testenv/
10
+ .coverage
11
+ .coverage.*
12
+ coverage.xml
13
+ coverage*.json
14
+ htmlcov/
15
+ site/
16
+ .DS_Store
17
+
18
+ # Drawing exports. `Drawing.export()` writes wherever the calling script runs from, so
19
+ # ad-hoc scripts drop artefacts in the repo root — `bracket.pdf` and `grm01.pdf` were
20
+ # swept into a commit that way. These are build products, never sources.
21
+ #
22
+ # PDF and DXF have no tracked instances, so they are ignored anywhere. SVG and PNG DO
23
+ # (docs/images/), so only the repo root is ignored — the one place throwaway scripts
24
+ # write to — rather than hiding a legitimate new docs image.
25
+ *.pdf
26
+ *.dxf
27
+ /*.svg
28
+ /*.png
@@ -1,51 +1,210 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## v0.4.10 — 2026-08-22
4
+
5
+ **A view-set-aware planning and turned-edge-treatment patch.** Authored view constraints now
6
+ compile into an explicit resolved plan, automatic drawings fail closed when required content is
7
+ lost, AP242 hole tolerances reach their semantic feature owners, and the exact
8
+ `b123d-recognisers` 0.3.0 release supplies turned chamfer and fillet evidence through truthful
9
+ profile-view callouts.
4
10
 
5
11
  ### Added
6
12
 
7
- - Recogniser co-development now has a one-command, wheel-based two-checkout check; an exact
8
- registry-release evidence record; automated dependency PR preparation; and documented landing,
9
- compatibility, deprecation, rollback, ownership, and CI-budget rules. Dependency PRs retain the
10
- canonical coverage/Codecov gate while avoiding four duplicate platform suites and the slow tier
11
- (#1170).
12
- - A versioned, independently authored STEP-analysis corpus and evaluator now report detection
13
- recall/false positives, parameter fidelity, and downstream usefulness as separate evidence
14
- layers. Hash-pinned positive, negative, ambiguous, compound, and topology-order-variant fixtures,
15
- per-layer diagnostics, and an anti-self-validation mutation prevent recogniser output from
16
- defining its own denominator (#1169).
17
- - Draftwright now validates the released `b123d-recognisers` 0.2.0 capability manifest against
18
- an exhaustive consumer-owned declaration of IR, DSL, generated-code, drawing, completeness,
19
- and documentation states. Unknown families, stale implementations, record-schema drift, and
20
- unevidenced state transitions fail closed; intentionally geometry-only repeating-profile
21
- evidence remains usable without acquiring invented drafting semantics.
13
+ - `Sheet` can now author a complete or augmenting semantic view set with `authored_views()`,
14
+ `auto_views()`, `view()`, `section_view()`, `detail_view()`, and their `add_*` forms. Fluent
15
+ view handles declare relationships, alignment, scale, and whole-view pins without exposing
16
+ annotation coordinates; unsupported or infeasible constraints fail at their declaration
17
+ source instead of being silently relaxed. `sheet.view_constraints` exposes the immutable
18
+ request and `drawing.view_plan` the distinct resolved result (#1260).
19
+ - Drawings now retain their resolved view topology, per-view requirement coverage, and
20
+ arrangement decision as inspectable values. The engine can build and semantically compare
21
+ alternative arrangements and requested view sets while keeping projection and page placement
22
+ derived from the same plan (#1130).
22
23
 
23
24
  ### Changed
24
25
 
25
- - Updated the exact `b123d-recognisers` production lock from 0.2.0 to 0.2.1.
26
- The immutable PyPI wheel/sdist hashes and capability-manifest digest
27
- `383a196329ed6a3d1bf88f18ae4ff75613c032f35d40f2b53302b6744da4d19e` are
26
+ - Dimension planning is now aware of the selected principal view set. Requirements supported by
27
+ another planned view are re-homed before projection; an unsupported set raises one aggregated
28
+ `ViewPlanIncomplete` naming every unmet requirement rather than failing late or producing a
29
+ plausible-looking drawing with missing dimensions (#1259).
30
+ - Three sparse corpus drawings now use a `stacked-iso` arrangement and fit A4 instead of A3 at
31
+ the same scale, with identical annotations, labels, and build issues. An alternative may only
32
+ compact the scale already selected by the default arrangement and must survive a real compile
33
+ without semantic loss; otherwise the default is retained (#1130).
34
+ - Updated the exact `b123d-recognisers` production lock from 0.2.9 to 0.3.0.
35
+ The immutable PyPI wheel/sdist hashes and capability-manifest digest `6645def94cbabaca7b9676fdb029b02e467266d1f020ea536e903b7d86b52685` are
28
36
  recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
29
37
  normal consumer gates run on the generated PR.
38
+ - Accepted the additive Chamfer and Fillet schema-2 recogniser contract alongside schema 1 for
39
+ the `b123d-recognisers` 0.3.0 cutover; all other record schemas remain fail-closed at version 1
40
+ (#1276).
41
+
42
+ - Updated the exact `b123d-recognisers` production lock from 0.2.6 to 0.2.9.
43
+ The immutable PyPI wheel/sdist hashes and capability-manifest digest `805876905d548fd0ef1301e2cf24427a86d34bc2e592b8d2d0cb43db94e1d3bd` are
44
+ recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
45
+ normal consumer gates run on the generated PR. The aggregate now inventories chamfers and
46
+ fillets on turned parts, and the fixed coaxial-post slot regression retires its downstream
47
+ strict xfail.
48
+
49
+ ### Fixed
50
+
51
+ - Automatic builds now apply the same required-outcome gate as explicit-scale builds. A settled
52
+ drawing that lost required placement outcomes records `plan_incomplete`, reports an
53
+ `incomplete` scale decision, preserves measurement/hole/source provenance, and fails lint
54
+ rather than presenting a diagnostic drawing as complete (#1250).
55
+
56
+ - Supported AP242 diameter tolerances now correlate with their canonical hole or pattern owner at
57
+ the completed IR boundary and round-trip through emitted `Sheet` declarations with source
58
+ provenance. Unmatched, ambiguous, conflicting, partial-pattern, and unsupported requirements
59
+ fail closed to provenance-preserving measured dimensions rather than being duplicated or lost
60
+ (#1116).
61
+
62
+ - A declared step shoulder coincident with its datum is now pruned before rendering instead of
63
+ sending identical endpoints to the border-dimension helper and raising `ValueError`. Valid
64
+ siblings remain, while the omission is recorded in `Drawing.suppressions()` and reported as
65
+ `step_position_coincident_with_datum` (#924).
66
+
67
+ - Turned chamfer and fillet leaders now read in a shaft profile view and land on their physical
68
+ edge-treatment sites instead of collapsing axial stations in the end view. Cylindrical
69
+ feature notes, knurl callouts, and surface finishes likewise derive a model-space surface
70
+ target rather than pointing at the shaft axis; all continue through the shared placement
71
+ solves, with X/Y/Z parity and declared Sheet round-trip (#1276).
72
+
73
+ - Toroidal fillets returned for turned parts by the shared recognition inventory now lower into
74
+ the existing one-feature-per-round IR and render through the common leader solve. Equal radii
75
+ share one `n× R` callout carrying every physical fillet's measurement provenance, and emitted
76
+ Sheet programs preserve the full inventory without rescanning geometry (#1281).
77
+
78
+ - Turned chamfers returned by the shared recognition inventory now lower into the same
79
+ one-feature-per-edge-treatment IR as prismatic chamfers. Equal specifications render as one
80
+ `n×` callout carrying every member's measurement provenance; different chamfer forms do not
81
+ collapse merely because their first legs match, and distinct tolerances split into truthful
82
+ requirements instead of being lost or applied to untoleranced siblings (#1254).
83
+
84
+ - Recogniser dependency automation now starts a fresh `Unreleased` section when the previous
85
+ Draftwright release has finalized the changelog, so a published recogniser can enter through
86
+ the documented immutable update workflow instead of failing before it opens a PR (#1279).
87
+
88
+ ## v0.4.9 — 2026-08-21
89
+
90
+ ### Added
91
+
92
+ - Lint now verifies that an annotation claiming to carry a measurement actually renders it
93
+ (#1217). Coverage checks read provenance riders the annotations carry about themselves and
94
+ believed them; nothing checked the claim against what the annotation draws. Four new codes —
95
+ `claimed_value_absent`, `claimed_measurement_not_compiled`, and two that report an
96
+ unverifiable claim rather than passing it — and `Drawing.add_table` now keeps the rows it
97
+ draws so a table's claims are readable back. Measured over all 21 STEP fixtures: 1,081
98
+ claims, 1,078 confirmed, and three findings — all instances of one genuine provenance
99
+ defect, see #1219.
100
+
101
+ - `lint_summary()["quality"]` gains a fourth component, `fidelity`: whether what the drawing
102
+ says is TRUE. The existing three ask whether required content landed (completeness),
103
+ whether there is too much of it (restraint), and whether a reader can make it out
104
+ (legibility) — none asked whether it is correct, so a drawing labelled 99 over a 16 mm
105
+ path reported a perfect score on every component available to it. Also covers a callout
106
+ drawn for a feature the part does not have, and a gear data table stating a tooth count
107
+ the geometry contradicts — the last of which reports `passed: True` and zero errors, so
108
+ the only existing channel that names it is `by_code`. Completeness, restraint and fidelity
109
+ report `available: False` with a `reason` rather than a flattering number when they have no
110
+ evidence, and every lint code the engine emits is classified onto exactly one component,
111
+ an explicit unscored register, or a register of codes whose component depends on the
112
+ issue's `outcome_stage`. `quality["unscored"]` reports the findings that reached no
113
+ component at all and flags any whose classification nobody made — `section_dropped` was
114
+ found scoring on nothing while a comment beside its emission said the opposite, and eleven
115
+ more `*_dropped` codes reach the engine as `drop_code` data with the same shape (#1176).
116
+
117
+ ### Changed
118
+
119
+ - Updated the exact `b123d-recognisers` production lock from 0.2.4 to 0.2.6.
120
+ The immutable PyPI wheel/sdist hashes and capability-manifest digest `aa52bc04216cd1eccc05796d2262547c7f476b80a3ec77334a77b9d8e3241a58` are
121
+ recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
122
+ normal consumer gates run on the generated PR.
123
+ - `HoleRequirementOutcome` gains `members` and `features`, `ClaimOutcome` gains `measurement`,
124
+ and `linting.hole_coverage.canonical_hole_sites` is public (#1217). A consumer attributing a
125
+ requirement outcome to a specific recognised hole needs the evidence the outcome accounts
126
+ for, and needs to key into the canonical space the ledger publishes it in — a through hole's
127
+ own-axis coordinate is zeroed there.
128
+ - The STEP-analysis benchmark's `drawing_consumer` boundary now consumes
129
+ `hole_requirement_outcomes` instead of a second correspondence implementation of its own
130
+ (#1206), and follows the ledger's pointer through `linting.evidence` rather than trusting it.
131
+ Holes the ledger reports `unverifiable` now score `unknown` where the duplicate credited them
132
+ by guessing: 26 holes, five on each CTC-03 fixture and eight on each CTC-04 fixture. The
133
+ five-case evaluation corpus is unchanged, and one lint message on CTC-03 now reports its
134
+ coordinates in the ledger's own canonical space.
135
+
136
+ - `Drawing.suppressions()` rows gain a `conveyed_by` key: the dimension that states a
137
+ withheld measurement instead, or `None` when nothing takes the fact over (#1154). It is not
138
+ a synonym for the existing `authored` flag — that says whose decision it was, this says
139
+ where the measurement went.
140
+
141
+ - Updated the exact `b123d-recognisers` production lock from 0.2.2 to 0.2.4.
142
+ The immutable PyPI wheel/sdist hashes and capability-manifest digest `d0023d30e583c03abc55f09dfeaaa56fddf56334afa0417818480b2fa2ce3f0f` are
143
+ recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
144
+ normal consumer gates run on the generated PR.
145
+ - Updated the exact `b123d-recognisers` production lock from 0.2.1 to 0.2.2.
146
+ The immutable PyPI wheel/sdist hashes and capability-manifest digest `7985befc8572bfe6d1c0805dfdf690d74a5a4a5f14d5988cc29c366315ff04ca` are
147
+ recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
148
+ normal consumer gates run on the generated PR.
149
+
150
+ ### Fixed
151
+
152
+ - An authored tolerance the compiler approved now reaches the sheet wherever the measurement
153
+ is drawn (#1215, #1216). `build123d_drafting` resolves a dimension's text as
154
+ `label if label is not None else _number_with_units(measured, tolerance)`, and every
155
+ dimension this engine emits passes a label — so a forwarded `tolerance=` rendered nothing
156
+ while type-checking and reading back correctly from `Dimension.label`. Ten render paths
157
+ discarded the band that way: envelope extents, the height ladder, the turned-step chain, two
158
+ public `Drawing` verbs, the deferred corridor route, the detail-view redraw, the short-rise
159
+ escape, step shoulders, pattern pitch, compound-callout recess terms, grid pitch, and both
160
+ hole tables. A general guard now decorates every parameter of every feature across a corpus,
161
+ through both `decorations=` key shapes, and joins what the compiler approved against what the
162
+ claiming annotation renders.
163
+
164
+ - Collapsed `N×` marks no longer state a tolerance their members do not share (#1216). A
165
+ pattern's pitch claimed the authored band of every gap although the recogniser admits 2%
166
+ jitter — holes at −30, −10, 10.3, 30 printed `3× 20 ±0.1` over a 20.3 mm gap — and fillet and
167
+ flat collapses took the "first-authored" band, so one of four fillets at ±0.1 printed
168
+ `4× R5 ±0.1`. Equality is now judged at the drawn precision, and a withheld band is reported
169
+ (`pattern_pitch_tolerance_withheld`, `collapsed_tolerance_withheld`) rather than dropped
170
+ silently.
171
+
172
+ - An approved dimension that cannot be placed is now reported instead of vanishing (#1216).
173
+ The overall extents' corridor candidate carried a no-op drop handler — the only drop in the
174
+ engine that recorded nothing — and the step ladder's legibility floor skipped rungs without
175
+ incrementing any counter. Both now record against the measurement they concern, and a
176
+ withholding is withdrawn if a later pass draws the measurement after all.
177
+
178
+ - A feature leader filling a view's below corridor no longer costs the part its overall extent
179
+ (#1236). The mandatory width or depth now retries on the view's above strip after every
180
+ corridor has drained, the fallthrough starved slot and plate dimensions already use. Live on
181
+ three NIST CTC fixtures, which drew no overall width.
182
+
183
+ - The iso view and the above strips are no longer invisible to each other (#1240). Strip
184
+ placement never saw the iso, and the iso fit re-scaled after annotation without consulting
185
+ what had been placed — so growth could invade dimension ink, which it did on CTC-01. The fit
186
+ is now capped by measured re-projection rather than by a linear model of it: the projected
187
+ bbox translates as it scales, by up to 7.35 mm on a part carrying a Location, which no
188
+ prediction about the page centre can express.
189
+
190
+
191
+ - A part whose feature-local extent runs between the same two faces as an overall extent
192
+ is no longer dimensioned twice (#1154). GRM-04's drive plate printed `4.5` twice — once
193
+ as the hub's height and once as the overall thickness — because two detected records
194
+ claim one physical fact. The overall extent keeps it; the feature-local one is withheld
195
+ and records which dimension the reader finds it on. Reconciliation is by exact
196
+ support-plane coincidence, never by value: a square part's two equal extents run between
197
+ different faces and remain two facts (#997). A measurement is handed over only when the
198
+ extent receiving it is actually drawn — by the planner's rules, by the compiler's
199
+ overall-height rules, and by an authored set — and never when the yielding dimension
200
+ carries a tolerance, since a toleranced dimension and an untoleranced one are not the same
201
+ requirement. (A tolerance on the *receiving* extent is the same requirement on the same two
202
+ faces, and does not prevent the consolidation.)
203
+
204
+ ## v0.4.8 — 2026-08-16
30
205
 
31
206
  ### Fixed
32
207
 
33
- - Stable release and TestPyPI snapshot builds now update package metadata and the independently
34
- validated Draftwright consumer-contract identity atomically. This prevents stripped `.dev0`
35
- and numbered development artifacts from failing their own capability-contract validation.
36
- - Installed wheels validate every portable recogniser-contract property without requiring the
37
- repository-only behavior-test files whose existence remains a strict source/CI gate. This keeps
38
- the packaged STEP-analysis evaluator usable without weakening evidence checks in development.
39
- - Post-release development-version bumps now update the consumer-contract identity on a branch,
40
- open a protected PR, and dispatch the narrow maintenance gate instead of attempting a rejected
41
- direct push to protected `main` (#1170).
42
- - Machined-feature leader callouts now collect all clear alternatives within each
43
- post-drain pass and use a bounded maximum-cardinality, minimum-leader-length
44
- assignment instead of taking corners greedily in feature order (#740). If a
45
- deterministic alternative-count, pass-size, candidate-pair, or search budget is
46
- reached, placement retains the legacy greedy result or a result no worse than it
47
- rather than losing additional callouts. Pre-drain diameter clearance ranking and
48
- its Policy-B fallback remain unchanged.
49
208
  - Compatible automatic/deferred sparse ordinary side/plan hole and post-drain
50
209
  machined-feature callouts now share one bounded same-view leader inventory
51
210
  (#1166). Pattern, profiled-bore, and dense table-eligible hole queues retain
@@ -87,6 +246,53 @@
87
246
  refinement status, and competing blockers; live
88
247
  single-callout edits remain immediate.
89
248
 
249
+ ## v0.4.7 — 2026-08-16
250
+
251
+ ### Added
252
+
253
+ - Recogniser co-development now has a one-command, wheel-based two-checkout check; an exact
254
+ registry-release evidence record; automated dependency PR preparation; and documented landing,
255
+ compatibility, deprecation, rollback, ownership, and CI-budget rules. Dependency PRs retain the
256
+ canonical coverage/Codecov gate while avoiding four duplicate platform suites and the slow tier
257
+ (#1170).
258
+ - A versioned, independently authored STEP-analysis corpus and evaluator now report detection
259
+ recall/false positives, parameter fidelity, and downstream usefulness as separate evidence
260
+ layers. Hash-pinned positive, negative, ambiguous, compound, and topology-order-variant fixtures,
261
+ per-layer diagnostics, and an anti-self-validation mutation prevent recogniser output from
262
+ defining its own denominator (#1169).
263
+ - Draftwright now validates the released `b123d-recognisers` 0.2.0 capability manifest against
264
+ an exhaustive consumer-owned declaration of IR, DSL, generated-code, drawing, completeness,
265
+ and documentation states. Unknown families, stale implementations, record-schema drift, and
266
+ unevidenced state transitions fail closed; intentionally geometry-only repeating-profile
267
+ evidence remains usable without acquiring invented drafting semantics.
268
+
269
+ ### Changed
270
+
271
+ - Updated the exact `b123d-recognisers` production lock from 0.2.0 to 0.2.1.
272
+ The immutable PyPI wheel/sdist hashes and capability-manifest digest
273
+ `383a196329ed6a3d1bf88f18ae4ff75613c032f35d40f2b53302b6744da4d19e` are
274
+ recorded in `.github/recogniser-release.json`; focused compatibility evidence and the
275
+ normal consumer gates run on the generated PR.
276
+
277
+ ### Fixed
278
+
279
+ - Stable release and TestPyPI snapshot builds now update package metadata and the independently
280
+ validated Draftwright consumer-contract identity atomically. This prevents stripped `.dev0`
281
+ and numbered development artifacts from failing their own capability-contract validation.
282
+ - Installed wheels validate every portable recogniser-contract property without requiring the
283
+ repository-only behavior-test files whose existence remains a strict source/CI gate. This keeps
284
+ the packaged STEP-analysis evaluator usable without weakening evidence checks in development.
285
+ - Post-release development-version bumps now update the consumer-contract identity on a branch,
286
+ open a protected PR, and dispatch the narrow maintenance gate instead of attempting a rejected
287
+ direct push to protected `main` (#1170).
288
+ - Machined-feature leader callouts now collect all clear alternatives within each
289
+ post-drain pass and use a bounded maximum-cardinality, minimum-leader-length
290
+ assignment instead of taking corners greedily in feature order (#740). If a
291
+ deterministic alternative-count, pass-size, candidate-pair, or search budget is
292
+ reached, placement retains the legacy greedy result or a result no worse than it
293
+ rather than losing additional callouts. Pre-drain diameter clearance ranking and
294
+ its Policy-B fallback remain unchanged.
295
+
90
296
  ## v0.4.6 — 2026-08-15
91
297
 
92
298
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: draftwright
3
- Version: 0.4.8
3
+ Version: 0.4.10
4
4
  Summary: Automated technical-drawing generation for build123d
5
5
  Project-URL: Homepage, https://github.com/pzfreo/draftwright
6
6
  Project-URL: Repository, https://github.com/pzfreo/draftwright
@@ -684,7 +684,7 @@ Classifier: Programming Language :: Python :: 3.14
684
684
  Classifier: Topic :: Scientific/Engineering
685
685
  Requires-Python: <3.15,>=3.10
686
686
  Requires-Dist: antlr4-python3-runtime<4.10
687
- Requires-Dist: b123d-recognisers==0.2.1
687
+ Requires-Dist: b123d-recognisers==0.3.0
688
688
  Requires-Dist: build123d-drafting-helpers>=0.14.1
689
689
  Requires-Dist: build123d<0.11,>=0.9.0; python_full_version < '3.13'
690
690
  Requires-Dist: build123d<0.12,>=0.11; python_full_version >= '3.13'
@@ -937,6 +937,12 @@ assert completeness["scope"] == "audited_recognized_requirements"
937
937
  completeness["excludes"] # what the denominator cannot see
938
938
  completeness["unrecognised_geometry_reports"] # a floor on that gap, never a measure
939
939
  legibility = crit["quality"]["legibility"]
940
+ # `quality` also carries `fidelity` (#1176): is what the drawing says TRUE? A drawing can
941
+ # be complete, restrained and legible and still assert a measurement the part lacks.
942
+ fidelity = crit["quality"]["fidelity"]
943
+ # …and `unscored`, the findings no component priced, so four components reading "fine"
944
+ # cannot conceal that some of the critique was scored by nothing.
945
+ unscored = crit["quality"]["unscored"]
940
946
  # Raw pair findings remain available and keep the original count semantics.
941
947
  legibility["warnings"], legibility["by_code"], crit["issues"]
942
948
  # The legibility scalar uses primary issues: one affected annotation/failure mechanism even
@@ -237,6 +237,12 @@ assert completeness["scope"] == "audited_recognized_requirements"
237
237
  completeness["excludes"] # what the denominator cannot see
238
238
  completeness["unrecognised_geometry_reports"] # a floor on that gap, never a measure
239
239
  legibility = crit["quality"]["legibility"]
240
+ # `quality` also carries `fidelity` (#1176): is what the drawing says TRUE? A drawing can
241
+ # be complete, restrained and legible and still assert a measurement the part lacks.
242
+ fidelity = crit["quality"]["fidelity"]
243
+ # …and `unscored`, the findings no component priced, so four components reading "fine"
244
+ # cannot conceal that some of the critique was scored by nothing.
245
+ unscored = crit["quality"]["unscored"]
240
246
  # Raw pair findings remain available and keep the original count semantics.
241
247
  legibility["warnings"], legibility["by_code"], crit["issues"]
242
248
  # The legibility scalar uses primary issues: one affected annotation/failure mechanism even
@@ -32,9 +32,10 @@ architecture** table; open retired or superseded records only for design history
32
32
  | [0013](0013-uniform-recognition-and-shared-package.md) | A uniform recogniser/feature contract and shared `b123d-recognisers` deployment | Enforce the geometry-only contract in the shared package and consume it through Draftwright's record→IR boundary. | Accepted; Phases 1–2 deployed | `test_external_recognition_boundary.py`, `test_detect_registry.py`, package semantic goldens |
33
33
  | [0014](0014-collect-then-solve-annotation-placement.md) | Collect-then-solve annotation placement (as built) | Collect, select, assign, and deterministically solve annotations per corridor before rendering; compatible sparse ordinary side/plan hole and post-drain machined leaders share one bounded late inventory. | Accepted; supersedes 0009; #740 Amendment 1; #1166 Amendment 2 | `test_carve_free_position_callers.py`, `test_strip_layout.py`, `test_layout_property.py`, `test_issue_740_leader_assignment.py`, `test_issue_1166_cross_pass_feature_leaders.py`, `test_import_boundaries.py` |
34
34
  | [0015](0015-part-drawing-compiler-as-built.md) | The part-drawing compiler, as built | Use one detected-or-declared feature IR and planner-fed dimension groups as the compiler waist. | Accepted; supersedes 0008 | `test_part_model.py`, `test_detect_once.py`, `test_import_boundaries.py` |
35
- | [0016](0016-declared-dimensioning-intent.md) | Declared dimensioning intent: capture what to measure, let the engine place it | Declare which measurements matter as scale-independent intent routed through the planner and corridor solve; never hardcode dimension geometry. | Accepted; epic #867 complete; phase 6 landed (#940) | `test_compiled_plan_boundary.py`, `test_label_provenance.py`, `test_sheet_emit.py`, `test_add_dimension.py` |
35
+ | [0016](0016-declared-dimensioning-intent.md) | Declared dimensioning intent: capture what to measure, let the engine place it | Declare which measurements matter as scale-independent intent routed through the planner and corridor solve; never hardcode dimension geometry. | Accepted; epic #867 complete; phase 6 landed (#940) | `test_compiled_plan_boundary.py`, `test_issue_1215_no_approved_tolerance_is_dropped.py`, `test_label_provenance.py`, `test_sheet_emit.py`, `test_add_dimension.py` |
36
36
  | [0017](0017-recognition-inventory-correspondence-and-measurement-provenance.md) | One recognition result per run; correspondence is evidence-gated | Produce one external immutable recognition result held by Draftwright's per-run cache; require vertical-slice evidence before generalising correspondence, identity, requirements, outcomes, or reconciliation. | Accepted; external cache ownership clarified, extensions gated by #1018 | `test_external_recognition_boundary.py`, `test_recognition_manifest.py`, `test_declared_recognition_gate.py` |
37
- | [0018](0018-requirement-driven-view-planning-and-editable-sheet-layout.md) | Requirement-driven view planning and editable sheet layout | Use one `ViewSpec` vocabulary and planner with distinct authored `ViewConstraints` and immutable `ResolvedViewPlan`; jointly validate views, typography, convention, scale, paper and layout against requirement survival. If accepted, supersedes ADR 0004's fixed-topology assumption while retaining compose-then-pack. | Proposed; tracked by #1130 | Required guards are listed in the ADR |
37
+ | [0018](0018-requirement-driven-view-planning-and-editable-sheet-layout.md) | Requirement-driven view planning and editable sheet layout | Use one `ViewSpec` vocabulary and planner with distinct authored `ViewConstraints` and immutable `ResolvedViewPlan`; jointly validate views, typography, convention, scale, paper and layout against requirement survival. Supersedes ADR 0004's fixed-topology assumption while retaining compose-then-pack. | Accepted 2026-08-16; partially implemented (`ViewSpec`, `ResolvedViewPlan`, `ViewCoverage`, arrangement choice and requirement gate); tracked by #1130/#1259-#1262 | Required guards are listed in the ADR |
38
+ | [0019](0019-display-complete-labels-and-dimension-outcomes.md) | Display-complete labels and a dimension-outcome ledger | The compiled plan carries the full label text (tolerance and collapse wording included) so renderers render and never compose; dimension outcomes reconcile at one seam on both build routes; ladder rungs get per-mark identity. Finishes the ADR 0016 Amdt 1 boundary; supersedes Amdt 6's enforcement mechanism. | Proposed | `test_issue_1215_no_approved_tolerance_is_dropped.py` reduces to plan-equality when implemented |
38
39
 
39
40
  ## Historical records
40
41
 
@@ -49,7 +50,7 @@ architecture** table; open retired or superseded records only for design history
49
50
  - Compiler and state ownership: 0001 → 0005 → 0015.
50
51
  - Recognition and public declaration: 0007 → 0013 → 0011 → 0015.
51
52
  - Layout and placement: 0004 → 0014 → 0012 → 0018.
52
- - Declared intent and the editable surface: 0001 → 0011 → 0012 → 0016 → 0018.
53
+ - Declared intent and the editable surface: 0001 → 0011 → 0012 → 0016 → 0018 → 0019.
53
54
  - Quality and correction: 0002, with provenance from 0010.
54
55
  - Recognition correspondence and completeness: 0007 → 0013 → 0015 → 0017.
55
56
 
@@ -15,11 +15,20 @@ library.
15
15
 
16
16
  Validation fails closed and names the family and boundary whenever possible:
17
17
 
18
- - **family inventory mismatch** — the installed package added, removed, or renamed a family.
19
- Update the package pin deliberately, add or remove the Draftwright declaration, and provide the
20
- downstream behavior or an explicit non-supported state.
18
+ - **family inventory mismatch (`stale=`)** — Draftwright declares a family the installed package
19
+ no longer ships, so a declared adapter would call a recogniser that is gone. Remove or repoint
20
+ the declaration.
21
+
22
+ The opposite direction does **not** fail this validation. A family the package ships and
23
+ Draftwright has not declared cannot reach any Draftwright code path, and blocking on it made the
24
+ package unreleasable until its consumer caught up. It is reported by
25
+ `pending_family_declarations` and fails `tests/test_recogniser_adoption.py` in Draftwright's own
26
+ CI instead — adoption is still required, and is enforced where the decision is made. Provide the
27
+ downstream behavior or an explicit non-supported state as before.
21
28
  - **record schema mismatch** — a consumed record schema changed. Review the record fields and
22
- compatibility notes, update the relevant adapter and tests, then pin the accepted schema version.
29
+ compatibility notes, update the relevant adapter and tests, then explicitly list the accepted
30
+ schema version. A bounded dual-readable list may name the current and next additive schemas
31
+ during a provider-first release; it is never an open-ended range.
23
32
  - **stale implementation** — a declared adapter, `Sheet` method, emitter, renderer, or completeness
24
33
  function no longer resolves. Repair the implementation reference and its independent behavior
25
34
  evidence; do not merely rename the string.
@@ -40,12 +49,19 @@ Validation fails closed and names the family and boundary whenever possible:
40
49
 
41
50
  ## Adding or changing a recogniser
42
51
 
43
- Land the package record, independent geometry evidence, manifest update, and compatible package
44
- release first. Then update Draftwright against that immutable release. For each applicable stage,
45
- add the adapter, declaration, emitted-Sheet round trip, drawing behavior, and completeness evidence;
46
- for an inapplicable or deferred stage, state why and link its tracking issue. The contract test
47
- derives package record outputs, converter registries, live `Sheet` methods, and emitter branches
48
- independently, so copying a new name into the declaration alone cannot make CI pass.
52
+ For an additive field that increments an existing record schema, first land a narrow Draftwright
53
+ declaration accepting both the installed schema and the named candidate schema. The existing adapter
54
+ must remain valid when the new field is ignored, and tests must prove the next schema is accepted
55
+ only by that explicit declaration while later schemas still fail. The package canary then proves
56
+ the real candidate wheel against that committed consumer point. After the package release, the
57
+ Draftwright dependency/behavior PR locks the immutable artifact, adopts the field, and narrows the
58
+ declaration to the new schema.
59
+
60
+ For each applicable stage, add the adapter, declaration, emitted-Sheet round trip, drawing behavior,
61
+ and completeness evidence; for an inapplicable or deferred stage, state why and link its tracking
62
+ issue. The contract test derives package record outputs, converter registries, live `Sheet` methods,
63
+ and emitter branches independently, so copying a new name into the declaration alone cannot make CI
64
+ pass.
49
65
 
50
66
  `bosses` is the fully consumed reference family. `repeating-radial-profiles` is the opposite
51
67
  reference: it remains geometry-only critique evidence for a separately authored gear declaration,
@@ -0,0 +1,71 @@
1
+ # Sheet and fluent handles
2
+
3
+ `Sheet` is the declared authoring façade. Feature verbs return fluent handles; those handles
4
+ are documented here because they are part of normal use even though their Python names begin
5
+ with an underscore.
6
+
7
+ ## Sheet
8
+
9
+ ::: draftwright.sheet.Sheet
10
+ options:
11
+ filters: public
12
+
13
+ ### Authored views and layout
14
+
15
+ View declarations are semantic constraints. They name projections, relationships and whole-view
16
+ anchors; the layout solve owns the resulting page positions. Authored views must be paired with
17
+ authored dimensions so a deliberately omitted view cannot strand planner-selected annotations:
18
+
19
+ ```python
20
+ s = Sheet(part).authored_dimensions().authored_views()
21
+ front = s.view("front")
22
+ plan = s.view("plan").above(front, gap=4).align_x(front)
23
+ s.view("iso").scale(0.75)
24
+
25
+ section = s.section_view("A", through=hole)
26
+ detail = s.detail_view("B", around=hole).scale(2)
27
+ dwg = s.build()
28
+ ```
29
+
30
+ `view(...)`, `section_view(...)` and `detail_view(...)` define complete authored sets;
31
+ omission suppresses a view. `add_view(...)`, `add_section_view(...)` and
32
+ `add_detail_view(...)` augment an explicitly selected `auto_views()` source. `row(...)` and
33
+ `column(...)` are shorthand for whole-view relations. A principal-view handle's `pin((x, y))`
34
+ anchors its projection origin in page millimetres; it never positions an annotation.
35
+
36
+ Principal orthographic views share the sheet scale and reject `.scale(...)`. Detail and
37
+ isometric handles may carry an independent positive factor. Infeasible relations, scales and
38
+ pins raise with their declaration source; unsupported pins on derived or pictorial views are
39
+ refused at declaration and constraints are never silently relaxed. The immutable authored
40
+ snapshot is available as `sheet.view_constraints`, while `drawing.view_plan` is the distinct
41
+ resolved result.
42
+
43
+ ## View handle
44
+
45
+ ::: draftwright.sheet._View
46
+ options:
47
+ filters: public
48
+
49
+ ## Hole handle
50
+
51
+ ::: draftwright.sheet._Hole
52
+ options:
53
+ filters: public
54
+
55
+ ## Diameter and step handle
56
+
57
+ ::: draftwright.sheet._Dim
58
+ options:
59
+ filters: public
60
+
61
+ ## Multi-parameter handle
62
+
63
+ ::: draftwright.sheet._Params
64
+ options:
65
+ filters: public
66
+
67
+ ## GD&T control builder
68
+
69
+ ::: draftwright.sheet._Control
70
+ options:
71
+ filters: public
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "draftwright"
7
- version = "0.4.8"
7
+ version = "0.4.10"
8
8
  description = "Automated technical-drawing generation for build123d"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -18,7 +18,7 @@ dependencies = [
18
18
  "build123d>=0.9.0,<0.11 ; python_full_version < '3.13'",
19
19
  "build123d>=0.11,<0.12 ; python_full_version >= '3.13'",
20
20
  "build123d-drafting-helpers>=0.14.1",
21
- "b123d-recognisers==0.2.1",
21
+ "b123d-recognisers==0.3.0",
22
22
  "numpy>=1.24",
23
23
  # PNG raster export (SVG→PDF→PNG). Both permissively licensed (Pillow HPND; pypdfium2
24
24
  # Apache-2.0 wrapping Google PDFium BSD-3) and ship pre-built wheels with NO native system
@@ -89,6 +89,7 @@ timeout = 300
89
89
  markers = [
90
90
  "slow: heavy end-to-end CTC fixture builds (deselected by default)",
91
91
  "smoke: curated build-light subset for a fast local check (~30 s)",
92
+ "unit: pure-logic inner-loop tier — constructs NO OCC geometry (enforced by conftest, #656)",
92
93
  ]
93
94
  # `SoftDeprecationWarning` marks a surface that is discouraged but SUPPORTED and not going
94
95
  # away (#1043). The suite exercises `Sheet.auto_dimensions()` in ~170 places, deliberately —
@@ -164,6 +165,7 @@ dev = [
164
165
  "mypy>=2.1.0",
165
166
  "pytest>=8",
166
167
  "pytest-cov>=5",
168
+ "pytest-split>=0.8",
167
169
  "pytest-timeout>=2",
168
170
  "pytest-xdist>=3",
169
171
  "ruff>=0.4",
@@ -281,9 +281,22 @@ dwg = build_drawing(part)
281
281
 
282
282
  # 1. Critique — the machine channel. JSON-friendly aggregate of lint().
283
283
  crit = dwg.lint_summary()
284
- # {"passed": bool, "score": 0..1, "errors": n, "warnings": n, "infos": n,
285
- # "by_code": {code: n}, "issues": [{code, severity, message, suggestion?}, ...]}
284
+ # {"passed": bool, "score": 0..1, "diagnostic_score": 0..1,
285
+ # "errors": n, "warnings": n, "infos": n, "by_code": {code: n},
286
+ # "issues": [{code, severity, message, suggestion?}, ...],
287
+ # "quality": {"completeness": …, "restraint": …, "legibility": …, "fidelity": …,
288
+ # "unscored": {"available": True, "score": None, "issues": n,
289
+ # "by_code": {…}, "unclassified": [...], "reason": …}}}
286
290
  # Gate on the severity/code COUNTS, not the scalar score.
291
+ #
292
+ # The four `quality` components answer four different questions and none substitutes for
293
+ # another: did required content land, is there too much of it, can a reader make it out,
294
+ # and — `fidelity` — is what it says TRUE. Completeness, restraint and fidelity report
295
+ # `available: False` with a `reason` rather than a flattering number when they have no
296
+ # evidence, so read `available` first. (Legibility is always available: an empty sheet
297
+ # genuinely IS legible, which is not the same kind of 1.0 as an empty sheet being truthful.)
298
+ # `quality["unscored"]` lists the findings none of the four priced; a non-empty
299
+ # `unclassified` there means a lint code reached no component and nobody decided it should.
287
300
 
288
301
  # 2. Each issue names the problem in DOMAIN terms and (when computable) carries a
289
302
  # ready-to-apply suggestion — a domain-API call you paste in, not page maths.
@@ -36,6 +36,9 @@ _LAZY = {
36
36
  "extract_pmi": "draftwright.pmi",
37
37
  "extract_pmi_report": "draftwright.pmi",
38
38
  "choose_scale": "draftwright.compose",
39
+ "ViewPlanIncomplete": "draftwright.view_plan",
40
+ "ViewConstraints": "draftwright.view_plan",
41
+ "ViewSpec": "draftwright.view_plan",
39
42
  # A warning category users are told to filter must be importable without reaching into a
40
43
  # private module (#1043 review) — and without paying for the CAD kernel. It lives in the
41
44
  # dependency-free `_warnings` leaf for that second reason: defined in `_core` it cost ~6 s
@@ -91,6 +94,7 @@ if TYPE_CHECKING: # static analysers / IDEs — no runtime import, no kernel co
91
94
  extract_pmi_report,
92
95
  )
93
96
  from draftwright.sheet import Sheet
97
+ from draftwright.view_plan import ViewConstraints, ViewPlanIncomplete, ViewSpec
94
98
 
95
99
 
96
100
  def __dir__():
@@ -110,6 +114,9 @@ __all__ = [
110
114
  "Sheet",
111
115
  "ScaleIncompatibilityError",
112
116
  "ScaleCompletenessWarning",
117
+ "ViewPlanIncomplete",
118
+ "ViewConstraints",
119
+ "ViewSpec",
113
120
  "build_drawing",
114
121
  "choose_scale",
115
122
  "extract_pmi",