fix(task-9): signed DIMTP/DIMTM, read-side arrowhead spelling, and the Task 10 handshake

Two blocking review findings on the standards data layer:

* DIMTP and DIMTM were pinned to ("float", 0.0, 1e6), refusing every signed
  deviation with a false "must be at least 0". AutoCAD documents both as
  signed and the repo already relies on it: build_dim_override writes
  dimtm=-0.022 for ISO 286 p6 and dimtp=-0.020 for f7, and
  dimension_linear(fit=...) emits exactly those. A dimension style could
  therefore never hold a double-positive or double-negative fit that the same
  server draws correctly per dimension, and an agent obeying the message
  would ship a sign-flipped tolerance. Both are now ("float", -1e6, 1e6); a
  provenance test resolves the p6/f7/H7/h6 overrides build_dim_override
  emits through resolve_dimstyle and pins the signs.

* 827719f made check_dim_value return DIMBLK/DIMBLK1/DIMBLK2 in the
  canonical _OBLIQUE spelling and added ezdxf_arrowhead without telling
  Task 10, whose plan helpers store the value verbatim and read the raw
  string back - executed as written the headless drawing raised at render
  and at doc.write, a user block passed the data layer and failed at save,
  and ezdxf's OBLIQUE-in-session / _OBLIQUE-after-reload split made an
  idempotent re-set report a change (spec section 8.3). This commit adds the
  read-side twin reported_arrowhead (never raises; a foreign name passes
  through), pins it with an in-session-equals-reloaded round trip, and edits
  the plan: Task 9 Produces and Task 10 Consumes now name ARROWHEAD_BLOCKS,
  canonical_arrowhead, ezdxf_arrowhead and reported_arrowhead; Task 10's
  _write_dimstyle_values maps through ezdxf_arrowhead, _dimstyle_value and
  _com_dimvar_for_report map through reported_arrowhead, a new
  _require_arrowhead_blocks refuses a user block absent from doc.blocks
  before dimstyle_create/modify write anything (and rewrites the name to the
  block table's own spelling, measured to be what a reload reports), and two
  headless tests witness the rendered INSERTs, the save/reopen spelling and
  the refusal. The plan's own copy of the range table is corrected to match
  the module (arrow kind, signed tolerances). The edited helper block was
  executed against ezdxf 1.4.4 before being written into the plan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
Umut CAN
2026-09-16 21:52:01 +03:00
co-authored by Claude Opus 5
parent 827719fdd0
commit 2e2cd2773d
4 changed files with 236 additions and 13 deletions
+2
View File
@@ -19,6 +19,7 @@ from engineering.standards.dimstyles import (
check_dim_value,
describe_preset,
ezdxf_arrowhead,
reported_arrowhead,
resolve_dimstyle,
validate_overrides,
)
@@ -37,6 +38,7 @@ __all__ = [
"check_dim_value",
"describe_preset",
"ezdxf_arrowhead",
"reported_arrowhead",
"resolve_dimstyle",
"resolve_font",
"resolve_mleaderstyle",
+29 -2
View File
@@ -41,6 +41,7 @@ __all__ = [
"check_dim_value",
"describe_preset",
"ezdxf_arrowhead",
"reported_arrowhead",
"resolve_dimstyle",
"validate_overrides",
]
@@ -179,8 +180,13 @@ DIM_VARIABLE_RANGES: dict[str, tuple | set] = {
"DIMSCALE": ("float", 0.0, 1e6), # 0 means "scale to the viewport"
# tolerances, rounding, fit, colours, arrowheads — the rest of the whitelist
"DIMTOL": {0, 1},
"DIMTP": ("float", 0.0, 1e6),
"DIMTM": ("float", 0.0, 1e6),
# Both signed, as AutoCAD documents them: the displayed lower deviation is
# -DIMTM, so a double-positive fit (ISO 286 p6, +0.035/+0.022) stores
# DIMTM -0.022 and a double-negative one (f7, -0.020/-0.041) stores DIMTP
# -0.020 — exactly what engineering/tolerances.py::build_dim_override emits
# per dimension; a style must be able to hold the same numbers.
"DIMTP": ("float", -1e6, 1e6),
"DIMTM": ("float", -1e6, 1e6),
"DIMTOLJ": ("int", 0, 2),
"DIMTFAC": ("float", 1e-9, 1e6),
"DIMLFAC": ("nonzero_float", -1e6, 1e6),
@@ -229,6 +235,27 @@ def canonical_arrowhead(key: str, value: Any) -> str:
return check_name(key, text, what="block name")
def reported_arrowhead(raw: Any) -> str:
"""A *stored* arrowhead name in the canonical spelling, never raising.
The read-side twin of :func:`canonical_arrowhead`: ezdxf reports the name
the writer stored (``OBLIQUE``) in-session and the block name
(``_OBLIQUE``) after a reload, so a raw read would spell one style two
ways and make re-setting a value to itself look like a change (spec §8.3).
A built-in in any spelling comes back as its block name and the closed
filled aliases as ``""``; ``None`` is ``""``; anything else — a user block,
or a foreign drawing's name the symbol-name rule would refuse — passes
through unchanged, because a read must not raise.
"""
if raw is None:
return ""
text = str(raw)
try:
return canonical_arrowhead("DIMBLK", text)
except (TypeError, ValueError):
return text
def ezdxf_arrowhead(canonical: str) -> str:
"""The name ezdxf's DIMSTYLE takes for a :func:`canonical_arrowhead` value.