Refresh Python host model handoff documentation

This commit is contained in:
Felix Riestra committed 2026-09-20 09:43:47 +02:00
1 parent 8648225ac5
commit a8dd3640b3
3 files changed
+76 -29

No files matched your search

+53 -13
View File
@@ -4,31 +4,51 @@
Build a general Python document model over the OCS host API for all **43 canvas kinds**. A kind is **complete** only after the per-kind gate below passes. Merely appearing in a converter or allowing a `layer` edit is partial coverage. Keep a property-level record of read/write, read-only, snapshot-only, and unsupported fields in the [43-kind coverage ledger](plugin-host-model-coverage-ledger.md). Do not resume the separate Lisp-to-Python conversion work.
As of 19 September 2026, the current Hatch increment is OCS commit `98b56ef6` on `plugin/host-model-api` and PandoraBox commit `a9b5de8` on `main`. Host API is v7. The Python feature has explicit writes for **22 of 43** canvas kinds: 21 are creatable and `Insert` remains update-only. This is **not** 22 completed kinds: Tolerance, Shape, AttributeEntity and Hatch pass every completion gate. AttributeDefinition passes its host and real IPC lifecycle but remains short of `Complete` because the pinned acadrust DXF reader drops optional ATTDEF fields. The other 21 canvas kinds have only `layer` writes through the document model. All 43 have raw typed snapshots. There are three internal records and two opaque fallbacks outside the 43 canvas kinds.
As of 20 September 2026, the working branch is `plugin/host-model-api` at
`8648225a`, published as draft PR
[#1391](https://github.com/HakanSeven12/OpenCADStudio/pull/1391). Host API is
v7. The Python feature has explicit writes for **22 of 43** canvas kinds: 21
are creatable and `Insert` remains update-only. This is **not** 22 completed
kinds: Tolerance, Shape, AttributeEntity and Hatch pass every completion gate.
AttributeDefinition passes its host and real IPC lifecycle but remains short of
`Complete` because the previously pinned CAD codec dropped optional ATTDEF
fields during DXF reads; revalidate that blocker against the current
`acadrust` revision `7ea4247`. The other 21 canvas kinds have only `layer`
writes through the document model. All 43 have raw typed snapshots. There are
three internal records and two opaque fallbacks outside the 43 canvas kinds.
Repositories:
- OCS host: `/Users/felix/Documents/MacApps/OpenCADStudio`
- Python adapter: `/Users/felix/Documents/MacApps/opencad-python/plugins/opencad-python`
- Bundled Python adapter: `/Users/felix/Documents/MacApps/OpenCADStudio/plugins/opencad-python`
- Host coverage policy: `crates/ocs_plugin_api/entity_coverage_policy.json`
- Host coverage/validation: `crates/ocs_plugin_api/src/entity_coverage.rs` and `build.rs`
- Adapter mapping: `entity_manifest.json`, `build/generate.rs`, `src/ocs_module.rs`, `src/document_model.py`
- Adapter mapping: `plugins/opencad-python/entity_manifest.json`,
`plugins/opencad-python/build/generate.rs`,
`plugins/opencad-python/src/ocs_module.rs`, and
`plugins/opencad-python/src/document_model.py`
- Host design notes: `docs/plugin-host-model.md`
Preserve unrelated untracked files in both repositories. Push OCS changes only to the `felixriestra/OpenCADStudio` fork, not H7 upstream; do not open a PR without asking. The prior user approved pushing work to the existing OCS and PandoraBox repositories, but verify remote branch tips before each push.
Preserve unrelated untracked files. Host and adapter changes now live in the
same OCS repository and commit. Push the feature branch only to the
`felixriestra/OpenCADStudio` fork; PR #1391 updates automatically. Never push a
feature commit directly to H7's `main`. Verify both upstream `main` and the fork
branch before each push.
## First: complete the originally agreed Phase 8
The earlier Phase 8 was **integration and compatibility**, not a new entity kind. `Insert` was added afterward as a separate coverage increment. Before marking any kind complete, establish an executable integration harness that exercises the actual plugin runner and IPC, not only direct Rust conversion helpers:
1. Stage the development v7 plugin with `bash plugins/opencad-python/tools/stage-host-model.sh <OCS checkout> <stage directory> [--debug]`. Verify the staged `plugin.toml` says API v7 and its acadrust source matches OCS. Keep checked-in PandoraBox `plugin.toml` and `Cargo.lock` on H7 API v5; keep `Cargo.toml` free of machine-local paths.
1. Stage the in-tree v7 plugin with `bash plugins/opencad-python/tools/stage-bundled.sh <stage directory> [--debug]`. Verify the staged `plugin.toml` says API v7 and its acadrust source and Rust compiler match OCS. Keep the repository-relative `ocs_plugin_api` path; never check in a machine-local path.
2. Through real IPC, create, inspect, edit, and delete a representative entity. Verify an invalid multi-entity transaction changes nothing, a valid transaction produces one undo entry, and undo **and redo** restore the expected geometry and references.
3. In the running GUI, exercise a real point pick, entity pick, cancellation/Escape, and plugin command cancellation. Verify drawing/selection/command notifications, including overflow recovery.
4. Repeat an input request and event poll across two tabs; verify token and notification isolation and cleanup when a tab closes.
5. Save and reopen representative edits as **DWG and DXF**, verifying the actual geometry and preserved unmapped fields. Use a real viewport/canvas check where the entity has visible geometry; a converter round trip alone does not satisfy this.
6. Record platform, OCS/acadrust revisions, fixture files, commands, results, and any engine limitation. Keep repeatable tests in the relevant repositories.
Phase 8 is complete only when these checks pass without weakening the portable v5 build. If a test is blocked by OCS or acadrust behavior, record the specific failure and leave Phase 8 open.
Phase 8 is complete only when these checks pass through the bundled plugin and
real runner boundary. If a test is blocked by OCS or acadrust behavior, record
the specific failure and leave Phase 8 open.
## Per-kind completion gate
@@ -40,7 +60,10 @@ Use one checklist row per kind in a coverage ledger. Status values: `unstarted`,
4. **Delete and history:** Delete the created entity through the Python interface. Prove create, edit, and delete have defined undo/redo behavior in the host, including grouped writes and failure rollback. Record any transaction API extension and bump the host API version if its ABI changes; keep older plugin compatibility.
5. **Real IPC and canvas:** Run the above through the staged plugin and actual OCS IPC. Verify visibility/geometry in the canvas and selection or picking in the GUI. For nonvisual entities, verify their observable document or layout behavior and explain the oracle.
6. **Persistence:** Save/reopen DWG **and** DXF fixtures. Compare kind, geometry, important metadata, handles/references, and preserved fields after reopen; edit again after reopen. Test at least one valid edge case for that kind. Do not count a JSON or in-memory round trip as file persistence.
7. **Portable build:** Run feature tests with a command-line Cargo patch to the OCS fork, restore PandoraBox `Cargo.lock`, then run `cargo check --locked` against the checked-in H7 v5 dependency. Never check in a local Cargo path or v7 portable manifest.
7. **Packaged build:** Run the in-tree adapter tests with `--locked`, stage the
plugin with `stage-bundled.sh`, and load it from the macOS application
resources through the separate runner process. The staged manifest must
match the host's Rust compiler and acadrust source.
If OCS/acadrust cannot create or serialize a kind reliably, mark it **blocked**, add a regression test or fixture demonstrating the failure, and move to the next independent kind. An explicit unsupported status is honest progress, not completion.
@@ -88,18 +111,35 @@ The last five may require new engine capabilities rather than only Python conver
1. Inspect the acadrust entity struct, constructors, private fields, serializer, drawing path, and linked tables/objects. Record the intended editable/read-only/unmapped properties first.
2. Put generic validation and transaction behavior in the OCS fork. Keep the Python adapter thin; add a manifest override only when the generator cannot safely express a field.
3. Add focused host validation, adapter conversion, document-model, real transaction/undo/redo, IPC, GUI, and DWG/DXF fixture checks. Record test evidence in the ledger, including which checks were manual.
4. Run `cargo test -p ocs_plugin_api --features host --lib` and relevant app host tests in OCS. For the adapter, use `cargo test --features experimental-host-model --config 'patch."https://github.com/HakanSeven12/OpenCADStudio".ocs_plugin_api.path="/Users/felix/Documents/MacApps/OpenCADStudio/crates/ocs_plugin_api"' --lib`, run its Python tests, restore `Cargo.lock`, then run `cargo check --locked`.
5. Check both `git diff --check` and repository status. Stage only task files, preserve unrelated untracked files, commit coherent host/adapter changes, and push only to the two established `felixriestra` remotes if still authorized. Record the resulting commits and next unfinished gate in the ledger.
4. Run `cargo test -p ocs_plugin_api --features host --lib` and the relevant
app host tests. Run
`cargo test --locked --features experimental-host-model --manifest-path plugins/opencad-python/Cargo.toml`
plus
`python3 -m unittest discover -s plugins/opencad-python/tests -v`.
5. Check `git diff --check` and repository status. Stage only task files,
preserve unrelated untracked files, commit host and adapter changes
together, push `plugin/host-model-api` to the Felix fork, and record the
resulting commit and next unfinished gate in the ledger.
## Handoff start point
Continue with **Leader**. Build a valid vertex path and annotation-linked fixture, map geometry separately from annotation/object handles, and verify path rendering, selection, reference preservation, deletion, undo/redo and both file formats through real IPC. AttributeDefinition remains mapped and integration-tested but open at W: pinned acadrust `568a12c` loses optional ATTDEF fields such as width factor on DXF read. Do not mark it complete until that dependency is fixed and the full property state passes DXF save/reopen. Keep the exact queue above and update statuses with evidence after each increment.
Continue with **Leader**. Build a valid vertex path and annotation-linked
fixture, map geometry separately from annotation/object handles, and verify
path rendering, selection, reference preservation, deletion, undo/redo and
both file formats through real IPC. AttributeDefinition remains mapped and
integration-tested but open at W. First rerun its DXF regression against
current acadrust `7ea4247`; do not mark it complete until the full optional
property state passes DXF save/reopen. Keep the exact queue above and update
statuses with evidence after each increment.
## Phase 8 progress log
- Added a V4 local-socket nested-request test for `UpdateEntitiesTransaction` using a simulated runner peer and a recording host. This proves the request and response cross the V4 IPC framing and reach `HostApi`; it does **not** prove the actual Python plugin runs through IPC.
- Extended the OCS app-host Point batch test to assert redo after undo. This proves the real app history path for those edits; creation/deletion history remains untested by this case.
- Staged the actual debug Python cdylib with `stage-host-model.sh`. Its generated manifest declares API v7 and the OCS acadrust source; the checked-in PandoraBox manifest and lockfile remain on H7 v5, and `cargo check --locked` passes.
- Staged the actual debug Python cdylib with `stage-bundled.sh`. Its generated
manifest declares API v7 and the exact OCS acadrust and Rust compiler
fingerprints. The plugin now builds from `plugins/opencad-python` in this
repository and ships from the macOS application resources.
- The opt-in `staged_python_plugin_line_lifecycle_over_real_ipc` app test passed with the staged v7 Python plugin and built OCS executable. It creates, edits, and deletes a Line through Python over the actual runner IPC; confirms three undo entries and undo/redo; and writes/reopens the edited Line as DWG and DXF. It does not exercise GUI picking, multiple tabs, or cancellation. Re-run with `OCS_TEST_PYTHON_PLUGIN=<staged dylib> OCS_PLUGIN_RUNNER_EXE=<built OpenCADStudio executable> cargo test app::plugin_host::tests::staged_python_plugin_line_lifecycle_over_real_ipc --lib -- --test-threads=1 --nocapture` from the OCS checkout.
- The same Line test now also sends a duplicate-handle batch through Python and confirms the host rejects it without changing geometry or creating an undo entry.
- The opt-in `staged_python_point_pick_and_cancel_over_real_ipc` test passes with the same runner. It requests point and entity picks through Python, drives the app's active-command point/object-pick callbacks, polls the returned tokens through a later Python run, and verifies Enter cancellation. The callbacks are invoked by the test harness, not by a physical GUI pointer event; live GUI verification remains open.
@@ -111,8 +151,8 @@ Continue with **Leader**. Build a valid vertex path and annotation-linked fixtur
- `staged_python_shape_lifecycle_over_real_ipc` passes C/R/E/D/U/I/W/V/P through the actual runner, checks the real SHX linework before and after DWG/DXF reopen, and proves that invalid size/style edits remain atomic. The DXF renderer fallback now searches named `is_shape_file` styles as well as legacy unnamed styles. Shape is **Complete**; the queue now continues with `AttributeDefinition`.
- Added creation-time `owner_handle` to the generated document-model adapter. It is present in snapshots and accepted by `doc.create_entity`, but rejected after creation; host transactions independently reject owner changes. Generic host validation now requires a non-null canvas owner to resolve to a block record, except `AttributeEntity`, whose owner may be an `Insert`.
- Mapped stable AttributeDefinition fields and validated tag, placement, normal, height, width, angles, text style, line count and block ownership. `embedded_mtext` stays snapshot-readable but unmapped so partial Python edits preserve its linked R2018+ layout payload.
- `staged_python_attribute_definition_lifecycle_over_real_ipc` passes the real create/read/edit/delete/undo/selection/render/validation/portable-build path using a structurally valid block and linked Insert. Full DWG state and core DXF geometry survive reopen; deletion stays absent after both formats. OCS also stopped double-converting ATTDEF/ATTRIB DXF rotation already converted by acadrust.
- AttributeDefinition remains **Integration-tested / DXF blocked**, not Complete: acadrust `568a12c`'s ATTDEF DXF reader does not restore optional AcDbText fields including width factor. The real test and ledger record that exact W-gate gap. The queue now continues with `AttributeEntity`.
- `staged_python_attribute_definition_lifecycle_over_real_ipc` passes the real create/read/edit/delete/undo/selection/render/validation/packaged-build path using a structurally valid block and linked Insert. Full DWG state and core DXF geometry survive reopen; deletion stays absent after both formats. OCS also stopped double-converting ATTDEF/ATTRIB DXF rotation already converted by acadrust.
- AttributeDefinition remains **Integration-tested / DXF blocked**, not Complete: acadrust `568a12c`'s ATTDEF DXF reader did not restore optional AcDbText fields including width factor. Revalidate this recorded failure against the currently merged `7ea4247` revision before keeping or clearing the W-gate blocker.
- Closed `AttributeEntity` without flattening canonical drawing storage. V4 views and IPC snapshots expose each nested child by handle, while host create/update/delete and transactions rewrite the owning Insert so rendering, serialization and undo remain consistent.
- `staged_python_attribute_entity_lifecycle_over_real_ipc` passes C/R/E/D/U/I/W/V/P with the actual v7 adapter. It creates a linked attribute from its block's ATTDEF, reads and edits value/placement/rotation, selects the parent Insert, renders text, rejects invalid tag/height/owner edits atomically, reopens edited and deleted state in DWG and DXF, and proves three-step undo/redo. AttributeEntity is **Complete**; the queue now continues with `Hatch`.
- Completed `Hatch` with full solid/pattern definitions and typed nested boundary paths. The adapter generator now handles single-payload tagged enums as `{kind, value}` dictionaries, which covers every Hatch edge variant and is reusable by later nested entity models. Unknown adapter properties are rejected instead of being silently ignored.
+8 -4
View File
@@ -1,8 +1,8 @@
# OCS canvas kind coverage ledger
Use with [the completion plan](plugin-host-model-completion-plan.md). This ledger is current as of 19 September 2026: **22 of 43 canvas kinds have explicit geometry writes** (21 creatable, plus update-only `Insert`), **4 kinds are complete**, and 21 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: **22 of 43 canvas kinds have explicit geometry writes** (21 creatable, plus update-only `Insert`), **4 kinds are complete**, and 21 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** = portable H7 v5 build. 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.
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 |
|---|---|---|
@@ -25,7 +25,7 @@ Completion gate codes: **C** = create through Python document model; **R** = rea
| 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 blocked** | Host commit `5b854bd1` and adapter commit `bb259ff` map 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, render 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** because pinned acadrust `568a12c` drops optional ATTDEF fields including width factor while reading DXF; the regression test keeps this limitation explicit. `embedded_mtext` mutation also remains unsupported pending linked-layout validation. |
| 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 | Layer-only | Requires annotation-linked fixture. |
@@ -50,4 +50,8 @@ Completion gate codes: **C** = create through Python document model; **R** = rea
| 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, OCS and PandoraBox commit hashes, and any manual GUI result. If a gate is untested, leave it pending. Do not raise the headline completion count from converter coverage alone.
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.
+15 -12
View File
@@ -35,7 +35,7 @@ attached attribute and sequence records. Those fields report `transaction_geomet
catalog. All 43 canvas kinds also support nonempty `layer` changes through
the same undoable transaction; internal and opaque variants remain read-only
through the document model. The adapter accepts only `layer` patches for
canvas kinds outside its 17 geometry converters. Other writable properties
canvas kinds outside its 22 geometry converters. Other writable properties
still report `type_conversion_only`; broader CAD range and cross-property
checks remain outstanding.
The host's `entity_snapshot` helper serializes any typed entity as a detached
@@ -46,20 +46,23 @@ write path for them. The Python adapter exposes its variant payload through
It is an inspection view: JSON converts non-finite floating-point values to
null and cannot be used as a lossless replacement entity.
The separate PandoraBox adapter currently maps these entity kinds to Python
dictionaries: Point, Line, Circle, Arc, Ellipse, Polyline, Polyline2D,
Polyline3D, LwPolyline, Spline, Text, MText, Ray, XLine, Solid, Face3D, and
Insert. Insert is update-only: the block name is readable but cannot be
changed, and Python creation is withheld until block-table references can be
established safely. Attached attributes remain available in the raw snapshot.
The authoritative per-field mapping
is `plugins/opencad-python/entity_manifest.json` in PandoraBox. The generated
The bundled first-party adapter under `plugins/opencad-python` currently maps
these entity kinds to Python dictionaries: Point, Line, Circle, Arc, Ellipse,
Polyline, Polyline2D, Polyline3D, LwPolyline, Spline, Text, MText, Ray, XLine,
Solid, Face3D, Insert, Tolerance, Shape, AttributeDefinition,
AttributeEntity, and Hatch. Insert is update-only: the block name is readable
but cannot be changed, and Python creation is withheld until block-table
references can be established safely. Attached attributes remain available in
the raw snapshot. The authoritative per-field mapping is
`plugins/opencad-python/entity_manifest.json`. The generated
mapping excludes fields it cannot represent, including common color, line
weight, transparency, Polyline3D smooth type, and MText background color.
Absent geometry fields are not editable through the Python document model.
A feature test compares the generated Python keys with the
host catalog. The adapter's `experimental-host-model` feature requires API
v7; its portable default remains pinned to H7's v5 contract.
v7 and builds against the repository-relative `ocs_plugin_api`. RustPython is
loaded inside the separate plugin runner process; OCS does not link the Python
runtime into the editor executable.
API v7 also exposes a synchronous, ordered selection query and an atomic
selection replacement scoped to the session tab. All handles must exist before
@@ -74,7 +77,7 @@ noninteractive command that starts and finishes within one message does not
produce an active-state transition.
The host's existing `InteractiveCommand` machinery collects either a point or
an entity pick. PandoraBox's v7 adapter now exposes a token-based request and
an entity pick. The bundled v7 adapter exposes a token-based request and
poll API because `PY_RUN` uses a fresh Python interpreter per invocation; a
script cannot suspend in place while the user clicks. Enter and command
cancellation report a cancelled result. The host releases the runner's pick
@@ -88,7 +91,7 @@ Input tokens are bound to the drawing tab that requested the pick. Polling a
token from another tab returns no result and does not consume it.
Python `doc.entities[handle]` returns a descriptor for every entity. For kinds
outside the 17-kind generated schema it contains only handle, kind, and layer;
outside the 22-kind generated schema it contains only handle, kind, and layer;
`layer` is editable on canvas kinds. `doc.coverage()` enumerates the
catalog; `doc.coverage("Line")` and `line.coverage` return one entry. For
covered kinds, the coverage object lists actual readable and editable