Files
OneCAD-Draft/docs/plugin-host-model-coverage-ledger.md
T
Felix RiestraandClaude Sonnet 5 b97d74efa4 Complete PolygonMesh, PolyfaceMesh and Mesh host model coverage
Maps all three mesh kinds with host validation of grid counts, face indices
and edge topology, and skips sub-record common data in the generator.
A shared run_mesh_lifecycle driver passes the full gate for each kind,
including DWG and DXF reopen with re-edit.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-20 14:42:42 +02:00

19 KiB
Raw Blame History

OCS canvas kind coverage ledger

Use with the completion plan. This ledger is current as of 20 September 2026: 30 of 43 canvas kinds have explicit geometry writes (29 creatable, plus update-only Insert), 11 kinds are complete, and 13 remain layer-only. Mapped means at least one non-layer field is exposed for Python writes; it does not mean the kind passes the completion gate. Update-only means Python creation is unavailable. Layer-only means raw inspection and canvas layer edits exist, but geometry is not mapped. Record actual evidence or a blocking issue before changing any status to Complete.

Completion gate codes: C = create through Python document model; R = read; E = edit defining geometry and another property; D = delete; U = undo/redo and atomic failure; I = real IPC plus GUI/canvas pick or observable behavior; W = DWG and DXF save/reopen; V = invalid-input checks and untouched-field/reference preservation; P = build and load the in-tree bundled plugin with a manifest matching the host toolchain and acadrust source. A kind is Complete only when C/R/E/D/U/I/W/V/P all pass and its property catalog matches implementation. Blocked requires a specific dependency or failing fixture.

Kind Baseline Gate evidence / blocker
Point Mapped Host transaction test now checks invalid batch rollback, grouped edit undo, and redo; creation/deletion history, real plugin execution, GUI, and DWG/DXF gates remain pending.
Line Integration-tested High-level document-model create/delete and transaction edit pass through the actual staged-plugin IPC runner; three undo entries, undo/redo, duplicate-handle and nonfinite-coordinate rejection, full typed-entity preservation, Line object-pick routing, and edited DWG/DXF reopen pass. A second editable property outside defining endpoint geometry still needs integration coverage before this row is complete.
Circle Mapped Full gate pending.
Arc Mapped Full gate pending.
Ellipse Mapped Existing focused DWG conversion test; full gate pending.
Polyline Mapped Full gate pending.
Polyline2D Mapped Full gate pending.
Polyline3D Mapped Full gate pending.
LwPolyline Mapped Full gate pending.
Spline Mapped Full gate pending.
Text Mapped Full gate pending.
MText Mapped Full gate pending.
Ray Mapped Focused DWG round trip; full gate pending.
XLine Mapped Focused DWG round trip; full gate pending.
Solid Mapped Focused DWG round trip; full gate pending.
Face3D Mapped Focused DWG round trip; full gate pending.
Insert Update-only Transform transaction and undo tested; Python creation, deletion, real IPC/GUI and DWG/DXF gates pending.
Tolerance Complete staged_python_tolerance_lifecycle_over_real_ipc passes C/R/E/D/U/I/W/V/P with the staged API v7 plugin: high-level create/read/transaction edit/delete; insertion, direction, and text edits; live canvas selection; grouped undo/redo; invalid direction and missing style atomic rollback; exact untouched common/style/private-field preservation; and edited DWG plus DXF reopen. Host-owned coverage exposes placement, direction, normal, text, style name, height and gap; style handle is read-only and the undocumented DWG short remains unmapped. tolerance_geometry_and_style_references_are_validated and the existing Tolerance tessellation tests cover reference and rendered-frame behavior.
Shape Complete staged_python_shape_lifecycle_over_real_ipc passes C/R/E/D/U/I/W/V/P with a generated parser-valid SHX file and a real shape-file TextStyle: high-level create/read/transaction edit/delete; insertion, size, rotation and width-factor edits; live canvas selection; grouped undo/redo; invalid size and missing style rollback; exact identity/style/common-field preservation; and DWG plus DXF reopen. Each live and reopened document renders the three-point SHX glyph rather than the placeholder. Host-owned reference binding writes the stable style handle needed by DWG. The DXF fallback now searches all is_shape_file styles, preserving named-style glyph resolution after reopen.
AttributeDefinition Integration-tested / DXF blocker pending revalidation Host commit 5b854bd1 maps block ownership plus every stable ATTDEF field except the nested embedded_mtext payload, which is snapshot-readable and preserved untouched. staged_python_attribute_definition_lifecycle_over_real_ipc passes C/R/E/D/U/I/V/P with a real block record, Block/BlockEnd markers and linked Insert: high-level creation inside the block, readback, grouped placement/default/rotation/width edits, selection, rendered text, atomic tag/height/style/owner rejection, deletion persistence, and three-step undo/redo. DWG reopens with the full edited state. DXF reopens identity, ownership, tag, prompt, value, placement, height and rotation, and OCS no longer double-converts ATTDEF/ATTRIB rotation. W remains open: acadrust 568a12c dropped optional ATTDEF fields including width factor while reading DXF. Rerun the regression against the currently merged 7ea4247 revision and update this row with the result. embedded_mtext mutation remains unsupported pending linked-layout validation.
AttributeEntity Complete OCS commit cf2a9235 and adapter commit 9c6b5c3 make nested ATTRIB records addressable by handle while retaining canonical storage in Insert.attributes. Host validation binds tag to a definition in the Insert's block, validates placement/text geometry and style references, keeps owner and definition handles read-only, and preserves embedded MTEXT. staged_python_attribute_entity_lifecycle_over_real_ipc passes C/R/E/D/U/I/W/V/P with a real block, ATTDEF and Insert: high-level create/read/transaction edit/delete, parent selection, rendered text, atomic invalid tag/height/owner rejection, edited and deleted DWG/DXF reopen, and three-step undo/redo. nested_insert_attribute_crud_uses_parent_storage_and_undo additionally proves the child never becomes an orphan flat entity in the host document.
Hatch Complete OCS commit 98b56ef6 and adapter commit a9b5de8 expose solid and patterned Hatches with elevation/normal, complete pattern definitions, pattern controls, style, association state, boundary paths and seed points. Nested tagged boundary edges use the reusable {kind, value} adapter form. Host validation requires closed finite loops, validates line/arc/ellipse/polyline/spline payloads and stored pattern lines, resolves associative boundary handles, and preserves gradient and MPOLYGON payloads as explicitly unsupported. staged_python_hatch_lifecycle_over_real_ipc passes C/R/E/D/U/I/W/V/P: Python solid creation, patterned boundary edit, live render-model pattern/boundary checks, selection, atomic invalid scale/association/open-loop/unmapped-property rejection, edited and deleted DWG/DXF reopen, post-reopen edits, and three-step undo/redo.
Leader Integration-tested / blocked at W by acadrust Fields mapped writable: vertices (≥2 finite points, not all coincident), annotation_handle, creation_type, path_type, dimension_style, arrow_enabled, hookline_enabled, hookline_direction, text_height, text_width, normal, horizontal_direction, block_offset, annotation_offset. Read-only: origin, dimension_gap, arrowhead_type, arrow_size, byblock_color. override_color is writable through the new generator Color form ({'kind': 'Rgb', 'value': {'r','g','b'}}, Index, ByLayer, ByBlock, None). Unmapped but preserved on edit: the dwg_unknown_* fields. Host reference binding validates that annotation_handle exists, is not the leader itself, matches creation_type (Text/MText, Tolerance, Insert; NoAnnotation forbids a handle) and that dimension_style exists; nothing is silently defaulted. staged_python_leader_lifecycle_over_real_ipc passes C/R/E/D/U/I/V/P against acadrust 7ea4247: linked Text annotation, path/height/arrow/offset transaction edit with untouched-field preservation, GUI pick grouping (scripted selection stays exact), seven single-edit rejections plus a cross-entity atomic rollback, four-step undo/redo, real render linework, DWG and DXF reopen and re-edit. Erasing a leader also erases its annotation (scene leader grouping); undo restores both. W blockers (engine, recorded as canary assertions in the test): (1) the DXF writer never emits group 340, so a DXF save unlinks the annotation; (2) DXF reads drop annotation_offset (group 213 is written but not reassembled); (3) DWG R2010+ does not store text_height, text_width or hookline_enabled (acadrust writes them only for R13–R2007 / R13–R14); (4) neither writer stores override_color, so it reopens as ByLayer in DWG and DXF. Not Complete until the engine round-trips (1) and (2); (3) needs a decision to document or make read-only.
MLine Complete Writable: vertices (raw vertex dicts; a script may pass only position), flags (integer, unknown bits rejected), justification, normal, scale_factor, style_name. Read-only: start_point, style_handle, style_element_count. Host validation requires ≥2 finite non-coincident vertices, ≥3 for a closed multiline, a finite nonzero scale and normal, an existing non-empty MLineStyle, and per-vertex segments that are either empty or match the style element count. Vertex direction/miter, segment layout and per-element miter offsets (justification and scale included) are host-derived by normalize_scripted_mline on every scripted create or edit, reusing the drawing command's rebuild_mline_geometry/sync_mline_element_parameters; dash and fill cuts survive an edit unless a vertex moves. staged_python_mline_lifecycle_over_real_ipc passes C/R/E/D/U/I/W/V/P: create against the Standard style, a three-vertex/scale/justification transaction edit with untouched-field preservation, corner miter widening and element offsets checked, real mline_lines linework before and after DWG and DXF reopen, nine single-edit rejections plus a cross-entity atomic rollback, re-edit after reopen in both formats, deletion, and three-step undo/redo. Known limit: switching to a style with a different element count is rejected until the script also clears the vertices' segments; only the rejection is covered by the integration test.
Dimension Complete (all 9 subtypes) EntityType::Dimension wraps a nine-variant enum, so the adapter uses a hand-written flat model (dimension_model.rs.inc, wired in through the manifest's manual_kinds) and the coverage catalog lists its properties through the policy's synthetic section. Python sees subtype (fixed at creation), the shared base fields (text, style_name, normal, text_middle_point, attachment_point, text_rotation, horizontal_direction, flip_arrow1/2, text_user_positioned) and only the fields of that subtype; a field from another subtype is rejected, not ignored. actual_measurement and the base definition point are host-derived (normalize_scripted_dimension, the same recompute grip edits use). Unmapped but preserved: user_text, insertion_point, block_name, version and DWG flags, style overrides in XDATA. Per-subtype status, all verified by staged_python_dimension_lifecycle_over_real_ipc (C/R/E/D/U/I/W/V/P; measurement and canvas wires checked for each, DWG and DXF reopen recorded per subtype): Linear (10), Aligned (5), Radius (5), Diameter (10), Angular3Pt (90°), Angular2Ln (90°), Ordinate (5), Arc (5·π/2), LargeRadial (6) — every one creates, reads, derives the right measurement, renders wires, and keeps its measurement through DWG and DXF. Edits (Linear second point/text/attachment, Radius definition point) update the measurement, nine rejection cases plus a cross-entity atomic rollback and three create-time rejections leave the document untouched, and post-reopen re-edit passes in both formats. Not covered: text formatting overrides, arrowheads and other DIMSTYLE overrides stored in XDATA, the anonymous *D block. The subtype-specific field meanings for the angular subtypes follow the DXF group-code layout rather than the acadrust convenience constructors.
MultiLeader Complete Mapped through the generic generator, which gained support for Color, LineWeight, mixed unit/payload enums, fixed [f64; N] arrays, bitflags-2 newtypes and per-type module paths for this kind. Writable: content_type, path_type, line_color, line_weight, enable_landing, enable_dogleg, dogleg_length, arrowhead_size, text_color, text_frame, the four text attachments, attachment direction/point, text_alignment, text_angle_type, text_direction_negative, scale_factor, enable_annotation_scale, extend_leader_to_text, block content fields, the reference handles (style_handle, text_style_handle, arrowhead_handle, line_type_handle, block_content_handle) and context, which merges as a patch so a script can change text_string without resetting leader roots. Read-only: dwg_version, property_override_flags, text_align_in_ipe and the entity-level text_height (neither writer stores it; set context.text_height). Excluded but preserved: arrowhead_overrides, block_attributes. Host validation checks finite/positive scale, height, dogleg and arrow sizes, finite context geometry and transform, non-empty leader lines, content-type/context consistency, and that every referenced handle exists as the right object kind. staged_python_multileader_lifecycle_over_real_ipc passes C/R/E/D/U/I/W/V/P: MText creation with a three-point leader root, a partial-context edit that replaces the path (four points), text, text location, dogleg and colour while preserving scale/content/common fields, canvas wires, eleven rejection cases plus a duplicate-handle atomic rollback, DWG and DXF reopen (text, path, dogleg, context.text_height, colour) with post-reopen re-edit, and three-step undo/redo. Not covered: block-content MultiLeaders (no block fixture yet), tolerance content, and style-defined defaults.
Table Complete Mapped through the generic generator (now also handling tuples and usize, with the generic LegacyBorderOverrides<T> fields excluded and preserved). Writable: insertion_point, horizontal_direction, normal, table_style_handle, rows, columns, merged_ranges, break_spacing, break_flow_direction, break_options. Read-only: block_name, block_record_handle, data_version, value_flags, the override flags, name, description, field_handles, base_style, break_data, break_ranges, legacy_style_override. Creation yields the engine default 3x3 grid; scripts read rows/columns, modify or extend them and assign them back (rows and columns replace wholesale, so copy an existing row dict when adding one). Host validation requires a non-empty grid, positive finite row heights and column widths, every row to have exactly one cell per column, finite cell and content geometry, merged ranges inside the grid and non-overlapping, and existing table-style, cell text-style and cell block handles. normalize_scripted_table mirrors merged_ranges onto the origin cell's merge_width/height on every scripted change to the ranges. staged_python_table_lifecycle_over_real_ipc passes C/R/E/D/U/I/W/V/P: default-grid creation, a row append, column-width edit, a text cell, a three-column merge and break spacing in one transaction with untouched rows/columns/style/common fields preserved, canvas wires, ten rejection cases plus an atomic rollback, DWG and DXF reopen (row count, width, cell text, insertion) with re-edit, and three-step undo/redo. Format notes: DWG restores merged_ranges but not per-cell merge dimensions; DXF restores the cell dimensions but its reader does not rebuild merged_ranges (recorded by a canary assertion); both keep the merge. Not covered: the anonymous table block is not regenerated, cell styles and formats beyond text, linked data and field content.
PolygonMesh Complete Writable: flags, m_vertex_count, n_vertex_count, m_smooth_density, n_smooth_density, smooth_type, elevation, normal, vertices (each {location, flags}; a vertex's own common data is not scripted and defaults). Host validation requires M and N of at least 2, exactly M×N vertices, non-negative densities, finite elevation and locations, and a nonzero normal, so inconsistent counts are refused before any mutation. staged_python_polygon_mesh_lifecycle_over_real_ipc (shared run_mesh_lifecycle) passes C/R/E/D/U/I/W/V/P: a 3×3 grid, a vertex move plus density and cubic smoothing in one transaction, canvas wires, seven rejection cases plus an atomic rollback, DWG and DXF reopen with re-edit, and three-step undo/redo.
PolyfaceMesh Complete Writable: elevation, flags, normal, start_width, end_width, smooth_surface, thickness, vertices (location, flags, bulge, widths, tangent, id) and faces (four indices, flags, optional colour). seqend_handle is read-only and preserved. Host validation requires at least 3 finite vertices and 1 face, every face index within the vertex count (a negative index hides that edge, 0 marks an unused corner), at least 3 indices per face, and finite widths, thickness and elevation. staged_python_polyface_mesh_lifecycle_over_real_ipc passes the full gate: two triangles, a vertex move plus a new vertex and a hidden-edge face in one transaction, canvas wires, six rejection cases plus an atomic rollback, DWG and DXF reopen with re-edit, and three-step undo/redo.
Mesh Complete Writable: blend_crease, subdivision_level, vertices, faces, edges (start, end, optional crease), override_option; version is read-only. Host validation requires at least 3 finite vertices, faces of at least 3 in-range indices, edges with distinct in-range endpoints and a finite non-negative crease, and a non-negative subdivision level, so out-of-range topology is rejected before mutation. staged_python_mesh_lifecycle_over_real_ipc passes the full gate: a quad with a creased edge, an added vertex and triangle plus subdivision level 1 in one transaction, canvas wires, seven rejection cases plus an atomic rollback, DWG and DXF reopen with re-edit, and three-step undo/redo.
Helix Layer-only Requires valid derived-spline fixture.
RasterImage Layer-only Requires image definition and file fixture.
Wipeout Layer-only Requires clip and image-definition fixture.
Underlay Layer-only Requires external definition/file fixture.
Viewport Layer-only Requires layout and view-state fixture.
ViewBorder Layer-only Requires linked view records.
SectionSymbol Layer-only Requires section-view style and point records.
Light Layer-only Requires position/target and photometric-state fixture.
Region Layer-only Requires valid ACIS region payload.
Body Layer-only Requires valid ACIS body payload.
Solid3D Layer-only Requires valid ACIS solid payload.
Surface Layer-only Requires valid surface payload.
Ole2Frame Layer-only Requires valid embedded-object storage.

After each increment, update the row with test names, fixture paths, exact passing commands, the OCS commit hash, and any manual GUI result. Host and adapter changes now share the same repository commit. If a gate is untested, leave it pending. Do not raise the headline completion count from converter coverage alone.