forked from 1b-agent/opencadstudio-upstream
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
0206c7c30b
commit
b97d74efa4
11 files changed
+479
-15
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# OCS canvas kind coverage ledger
|
||||
|
||||
Use with [the completion plan](plugin-host-model-completion-plan.md). This ledger is current as of 20 September 2026: **27 of 43 canvas kinds have explicit geometry writes** (26 creatable, plus update-only `Insert`), **8 kinds are complete**, and 16 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`.
|
||||
Use with [the completion plan](plugin-host-model-completion-plan.md). 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.
|
||||
|
||||
@@ -33,9 +33,9 @@ Completion gate codes: **C** = create through Python document model; **R** = rea
|
||||
| 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 | Layer-only | Requires consistent grid/count fixture. |
|
||||
| PolyfaceMesh | Layer-only | Requires valid face-index fixture. |
|
||||
| Mesh | Layer-only | Requires valid topology fixture. |
|
||||
| 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. |
|
||||
|
||||
Reference in new issue
Block a user