- plugin-architecture.md: new "Entity class display labels (API v10)"
section documenting the split (stable identity keys in XDATA, display
labels in the plugin declaration), the live-loaded-plugin gating (missing,
disabled, cap-excluded, failed, removed, or dead → bare native type), the
"<Label> (<Native>)" display rule, that raw schema fields (`type`,
`dxf_name`, `record_type`) and LIST are unchanged, and that the label is
display-only. `plugin.toml` deliberately does not carry the table: it is
the pre-load discovery file and labels must activate on live manifests.
- Template v2 demonstrates the whole convention: declares
`SURVEY-CLASS:POINT -> "Survey Point"` and stamps the identity key in
MARK_FIRST_SURVEY_POINT, so marked points show as "Survey Point (Point)"
while the plugin is loaded. plugin.toml's api_version is bumped to 10 (keep
in sync with ApiVersion::CURRENT) with a NOTE on where the class table
lives. DESIGN.md documents the flow.
- Template v2's stale `acadrust` pin (8a28c21, predating the host's codec
bump to 278c49a) is realigned with the host's pin: without it the template
no longer compiles on main — its `acadrust::EntityType` and the host
re-exports are distinct types when the revisions disagree (verified the
same four type errors occur before and after this feature's template edit).
- changelogs/unreleased.md entry (Plugins section).
Found while building an out-of-tree scripting plugin from scratch against
this doc and the actual ocs_plugin_api/host source. Two categories:
Fixed outright (docs/examples didn't match the real code):
- The worked CadModule example returned Vec<RibbonGroup> from
ribbon_groups(); the real trait requires &[RibbonGroup] - the example
wouldn't compile. Fixed with the OnceLock pattern the host's own
benchmark code already uses.
- Reconciled a contradiction between "process isolation removes the need
for a shared Rust ABI" and the exact-rustc_version requirement described
a few paragraphs earlier in the same doc.
- The roadmap's "Next" list still had external automation as unstarted;
--mcp/--serve are real and operational (src/cli.rs, src/mcp.rs).
- Added the missing plugin.toml to docs/plugin-template-v2 (its own
DESIGN.md already claimed one could be installed).
- Documented that plugin-template's CI floats rust-toolchain@stable, which
doesn't guarantee matching the host's exact rustc - added acadrust_source
to both templates' plugin.toml plus the release.yml step that fills it
from Cargo.lock's resolved acadrust source, alongside the existing
rustc_version fill.
Flagging for your call, not fixed here (found the behavior, not sure it's
the intended one, prefer to ask than guess at a fix):
- acadrust_compatible()'s ABI gate only runs at all if plugin.toml declares
acadrust_source - an undeclared field is silently treated as compatible,
unlike rustc_version (undeclared = incompatible). The same shortcut
appears in two places: ExternalPlugin::acadrust_compatible
(src/plugin/external.rs) and the inline check inside fetch_release_info
(src/plugin/marketplace.rs). If this is deliberate (e.g. back-compat with
manifests from before the field existed), no action needed beyond a
comment; if not, both call sites need the same fix.
- The command line still uppercases typed/pasted input even with the `>`
literal-spaces prefix (Message::CommandInput, src/app/update/mod.rs) -
`>` only stops a space from auto-submitting the line, it doesn't skip
`s.to_uppercase()`. A plugin command needing a case-sensitive typed
argument has no escape today short of automation.
- fetch_release_info (src/plugin/marketplace.rs) returns every release
under a linked repo with no filter on the manifest's own id field (which
it already parses to build ReleaseInfo) - a repo hosting more than one
plugin under tag-namespaced releases surfaces all of them mixed
together in one plugin's version list.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>