From 4ba0539496540f43a309badd7a17e4a543585d7b Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 11:13:16 +0100 Subject: [PATCH 01/22] Start scene viewer visualisation initiative --- .../scene-viewer-visualisation/README.md | 19 ++ .../decisions/001-ownership-boundaries.md | 70 ++++ .../decisions/002-indexed-buffer-geometry.md | 72 +++++ .../003-viewer-state-and-selection.md | 70 ++++ .../decisions/004-transform-refresh-undo.md | 74 +++++ .../decisions/005-annotations-and-overlays.md | 70 ++++ .../006-viewer-integration-facade.md | 75 +++++ .../decisions/007-scope-and-verification.md | 78 +++++ .../decisions/README.md | 14 + .../scene-viewer-visualisation/handoff.md | 78 +++++ .../implementation-plan.md | 112 +++++++ .../scene-viewer-visualisation/inventory.md | 146 +++++++++ .../scene-viewer-visualisation/objective.md | 104 ++++++ .../scene-viewer-visualisation/proposal.md | 306 ++++++++++++++++++ 14 files changed, 1288 insertions(+) create mode 100644 initiatives/scene-viewer-visualisation/README.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/README.md create mode 100644 initiatives/scene-viewer-visualisation/handoff.md create mode 100644 initiatives/scene-viewer-visualisation/implementation-plan.md create mode 100644 initiatives/scene-viewer-visualisation/inventory.md create mode 100644 initiatives/scene-viewer-visualisation/objective.md create mode 100644 initiatives/scene-viewer-visualisation/proposal.md diff --git a/initiatives/scene-viewer-visualisation/README.md b/initiatives/scene-viewer-visualisation/README.md new file mode 100644 index 0000000..accc09d --- /dev/null +++ b/initiatives/scene-viewer-visualisation/README.md @@ -0,0 +1,19 @@ +# Scene, Viewer, and Visualisation + +This initiative aligns backend-neutral scene infrastructure, viewer rendering +and interaction, and model-to-scene integration across the COMPAS framework. + +Current phase: **architecture proposal complete and awaiting approval; no +package source changes authorized**. + +- [Objective](objective.md) +- [Inventory](inventory.md) +- [Proposal](proposal.md) +- [Architecture decisions](decisions/README.md) +- [Implementation plan](implementation-plan.md) +- [Current handoff](handoff.md) + +The proposed initial package scope is `compas`, `compas_viewer`, +`compas_model`, and `compas_framework`. Session persistence, notebook +visualisation, and CAD-host adapters are compatibility-review consumers until +an approved decision admits them to implementation scope. diff --git a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md new file mode 100644 index 0000000..0fb0bc9 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md @@ -0,0 +1,70 @@ +# ADR 001: Ownership and State Boundaries + +## Status + +Proposed. + +## Context + +Core scene objects currently combine durable content with context-adapter +state, while Viewer selection, GPU identity, configuration, tool state, and UI +refresh paths are distributed across objects, renderer, commands, and widgets. +Moving everything into core would make Qt/rendering concerns framework +dependencies; leaving ownership implicit perpetuates coupling. + +## Options + +1. Keep core responsible for durable scene content and place renderer and + interaction state in Viewer. +2. Add rendering, selection, and reactive application state to core Scene. +3. Keep all current ownership and coordinate behavior through conventions. +4. Move durable scene content into Viewer and reduce core Scene to adapters. + +## Recommendation + +Choose option 1. + +- Core owns scene items, hierarchy, scene-object GUIDs, local transformations, + visibility, durable appearance, and serialization. +- Viewer configuration owns persistent application preferences. +- Viewer session state owns selection, hover, tools, gestures, and transient + results. +- Viewer rendering owns indexed buffers, pick IDs, GPU resources, and refresh. +- Domain packages own authoritative domain hierarchies and caches and project + them into core scenes through public Viewer operations. + +GUIDs connect durable scene objects to Viewer state. Pick IDs and transient +state are never serialized. Do not add Qt signals or GPU contracts to core. + +## Consequences + +- Core remains usable by notebook and host adapters without Viewer. +- Selection and tools stop leaking into serialized scene-object settings. +- Viewer must provide explicit public state and synchronization operations. +- Domain packages retain their own data authority rather than duplicating it + in a generic application store. +- Existing Viewer code that reaches its singleton, renderer, or widgets must + migrate gradually after the public boundary exists. + +## Compatibility + +Core serialized scene contracts remain authoritative. Removing transient +Viewer fields from scene-object settings may change Viewer-specific serialized +data and requires fixture inspection and migration documentation. + +## Verification + +- Round-trip core scenes without Viewer installed. +- Prove Viewer selection, hover, tools, and pick IDs are absent from scene + serialization. +- Verify domain objects resolve through stable scene-object GUIDs after UI + rebuilds. + +## Affected packages + +`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. + +## Dependencies + +- Geometry-tessellation ADRs 022 and 024 +- Plugin-implementations ADR 002 diff --git a/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md b/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md new file mode 100644 index 0000000..3de74b7 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md @@ -0,0 +1,72 @@ +# ADR 002: Indexed Viewer Buffer Geometry + +## Status + +Proposed. + +## Context + +Viewer can batch geometry efficiently but its general `BufferGeometry` +requires expanded line and triangle vertices. This duplicates arrays and makes +callers manually expand vertices plus edges or triangles. Core numerical APIs +already accept structural Python and NumPy buffers, and Viewer-specific GPU +layout should not become a compulsory core geometry representation. + +## Options + +1. Add one Viewer-owned shared-vertex indexed `BufferGeometry` contract and + convenience constructors. +2. Put a GPU-oriented buffer type in core. +3. Require `Tessellation`, `PolygonalSurface`, or `Mesh` for every input. +4. Preserve expanded arrays and add only helper functions that duplicate them. + +## Recommendation + +Choose option 1. Use shared `vertices` plus optional point, edge, and triangle +index channels. Provide: + +```python +BufferGeometry.from_points(vertices) +BufferGeometry.from_vertices_and_edges(vertices, edges) +BufferGeometry.from_vertices_and_triangles(vertices, triangles) +``` + +Accept structural Python sequences and NumPy arrays. Normalize once to Viewer +dtypes and check rank, column count, and index bounds. Preserve indices through +the buffer manager and do not create one scene object per primitive. + +Keep styling on scene objects. Do not add a universal render geometry to core +or make this contract an input to geometry algorithms. + +## Consequences + +- Large edge and triangle datasets avoid Python-object and vertex-expansion + overhead. +- Viewer adapters gain one common path for indexed geometry. +- Geometry with independent point/line/triangle vertex pools must combine + them into one vertex table with offset indices at the Viewer boundary. +- Per-channel or per-primitive color arrays beyond current behavior require + evidence and a separate refinement rather than speculative fields. + +## Compatibility + +The existing expanded `points`, `lines`, and `faces` constructor is replaced +in a coordinated Viewer change. Examples and adapters migrate together; no +parallel deprecated constructor is proposed. + +## Verification + +- Test list and NumPy inputs, exact shapes/dtypes, bounds, empty channels, and + input non-mutation. +- Assert indices remain indexed in CPU/GPU assembly. +- Exercise large input without per-edge or per-triangle scene objects. +- Compare rendering semantics with current points, lines, and faces. + +## Affected packages + +`compas_viewer`, `compas_model`, and `compas_framework`. + +## Dependencies + +- [ADR 001](001-ownership-boundaries.md) +- Accepted structural numerical-input decisions from typing alignment diff --git a/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md b/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md new file mode 100644 index 0000000..eb54681 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md @@ -0,0 +1,70 @@ +# ADR 003: Viewer State and Object Selection + +## Status + +Proposed. + +## Context + +Selection currently lives in mutable `ViewerSceneObject.is_selected` flags. +Viewport commands, tree widgets, shaders, and domain controllers mutate or +poll those flags and then trigger imperative refreshes. `ViewerState` observes +persistent configuration but not selection or tool state. + +## Options + +1. Add one Viewer-owned observable object-selection model and separate + persistent configuration from transient state. +2. Keep scene-object flags and add selection-change signals around them. +3. Put selection into core Scene and serialize it. +4. Adopt a generic third-party reactive state store for all Viewer data. + +## Recommendation + +Choose option 1. + +`Viewer.state.selection` stores ordered scene-object GUIDs and provides +replace, add, remove, toggle, clear, membership, and ordered-resolution +operations. It emits one batched change notification per operation. Viewport, +rectangle selection, scene tree, commands, shaders, and domain controllers use +this model exclusively. + +Keep `Viewer.config` for persistent preferences. Keep hover, active tool, +gesture, and temporary tool values in small explicit Viewer state fields. Use a +Qt-neutral Python model with a Qt bridge. Remove `is_selected` rather than +retaining a second writable authority. + +Initial selection is scene-object-level only. Do not invent a generic vertex, +edge, face, or domain-component token until an approved editing workflow +requires it. + +## Consequences + +- Tree, viewport, code, renderer, and model integration observe one mutation + path. +- Selection no longer participates in scene serialization. +- Batch changes avoid repeated renderer/UI updates. +- Existing selection APIs and tests require a coordinated breaking migration. +- Sub-object selection remains explicitly unsupported in the initial wave. + +## Compatibility + +Remove Viewer `is_selected` constructor/settings behavior. Replace public model +selection implementations with the shared model while preserving their +user-facing selected-element results. + +## Verification + +- Exercise replace/add/remove/toggle/clear from viewport, rectangle, tree, and + programmatic paths. +- Assert one notification and one render/UI synchronization per batch. +- Verify stable ordering, removed-object cleanup, and serialization exclusion. +- Preserve model-order selection results where `compas_model` promises them. + +## Affected packages + +`compas_viewer`, `compas_model`, and `compas_framework`. + +## Dependencies + +- [ADR 001](001-ownership-boundaries.md) diff --git a/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md b/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md new file mode 100644 index 0000000..7ab0ebd --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md @@ -0,0 +1,74 @@ +# ADR 004: Transformations, Refresh, and Undo + +## Status + +Proposed. + +## Context + +Core already owns local/world transformations and Viewer can update transform +buffers efficiently, but there is no public multi-object transformation +operation, gizmo contract, or undo behavior. Geometry, selection, sidebar, and +renderer refreshes are invoked through concrete internals. A universal core +event bus would make every mutable property observable before its semantics are +known. + +## Options + +1. Add explicit Viewer transform transactions, undo/redo, and categorized + refresh operations while retaining core transformations. +2. Add a generic observable mutation/event system to core Scene. +3. Mutate scene objects directly and require callers to refresh internals. +4. Move transformations and history entirely into Viewer state. + +## Recommendation + +Choose option 1. + +Expose `viewer.transform_objects(objects, transformation, space="world")`. +Apply one world-space delta to each pre-operation world transformation and +derive each new local transformation through its parent. Reject requests that +contain both an ancestor and its descendant in the initial version. Validate +the entire request before mutation and leave all objects unchanged on failure. + +Record before/after local transformations as one reversible Viewer +transaction. Add a small undo/redo stack for explicit reversible Viewer +transactions; do not absorb general session or domain history. + +Expose explicit geometry, appearance, transform, and hierarchy refresh +operations. Do not add a core scene event bus in this wave. Direct external +mutation requires the matching Viewer refresh call. + +## Consequences + +- Code, commands, and a future gizmo use identical transformation semantics. +- Atomic transactions provide predictable undo and efficient transform-buffer + updates. +- Ancestor/descendant simultaneous transforms remain unsupported until their + intended group semantics are decided. +- Arbitrary item mutation is not magically detected; synchronization remains + explicit and testable. + +## Compatibility + +Existing direct transformation mutation remains a core operation, but Viewer +consumers migrate to the public transaction when they require refresh or undo. +Existing callback commands remain valid and simply do not enter history unless +they produce a reversible transaction. + +## Verification + +- Test world/local conversion under transformed parents. +- Test multiple independent objects, atomic validation failure, ancestor/ + descendant rejection, undo, redo, and redo invalidation after new work. +- Assert transform-only refresh does not rebuild geometry buffers. +- Verify failed commands do not create history entries. + +## Affected packages + +`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. + +## Dependencies + +- [ADR 001](001-ownership-boundaries.md) +- [ADR 003](003-viewer-state-and-selection.md) diff --git a/initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md b/initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md new file mode 100644 index 0000000..e738eb9 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md @@ -0,0 +1,70 @@ +# ADR 005: Annotations, Measurements, and Overlays + +## Status + +Proposed. + +## Context + +Viewer has concrete `Tag` and `ArrowOverlay` rendering paths but no general +measurement, dimension, scale, or legend behavior. Treating every visual aid +as a scene item would serialize view-dependent UI; treating every annotation +as an overlay would lose world anchoring and durable intent. + +## Options + +1. Separate durable world annotations from transient screen overlays. +2. Make every annotation and overlay a core scene item. +3. Keep every visual aid as a renderer-special-cased Viewer class. +4. Add a framework-wide overlay plugin registry before adding features. + +## Recommendation + +Choose option 1. + +- World text annotations and distance dimensions are serializable scene items + with Viewer adapters. Distance dimensions store two anchors, unit, + precision, and optional label override; distance is derived. +- Scale indicators and legends are transient screen-space Viewer overlays and + are not serialized or picked initially. +- Measurement preview state belongs to the active Viewer tool. Completing the + tool creates a durable distance dimension; cancelling creates nothing. + +Align current Tag/Arrow behavior with these paths. Use one Viewer overlay layer +for the approved screen types and ordinary scene adapter registration for +world annotations. Do not add a general overlay registry. + +## Consequences + +- Persistence follows user intent rather than rendering technique. +- World annotations participate in hierarchy and transformations. +- View-dependent overlays remain independent of scene files. +- Current concrete renderer checks can be consolidated behind the two paths. +- Editing, snapping, angular dimensions, and arbitrary overlay plugins remain + later requirements. + +## Compatibility + +Inspect existing serialized Tag/Arrow fixtures before choosing a migration. +Do not reinterpret ambiguous old data silently. Keep equivalent visible +behavior where the old type maps exactly; otherwise document removal and the +new construction path. + +## Verification + +- Test distance derivation, units, precision, label override, transformed + parents, serialization, and reload. +- Test measurement preview/cancel/complete state transitions. +- Assert scale and legend overlays are absent from scene serialization. +- Verify renderer ordering, resize behavior, and no concrete type checks in + the main render loop for approved types. + +## Affected packages + +`compas`, `compas_viewer`, and `compas_framework`. + +## Dependencies + +- [ADR 001](001-ownership-boundaries.md) +- [ADR 002](002-indexed-buffer-geometry.md) +- [ADR 003](003-viewer-state-and-selection.md) diff --git a/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md b/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md new file mode 100644 index 0000000..3821fba --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md @@ -0,0 +1,75 @@ +# ADR 006: Public Viewer Integration Facade + +## Status + +Proposed. + +## Context + +`compas_model.ModelViewer` currently reaches into concrete renderer and sidebar +objects. Viewer has command and menu composition but no equally clear public +dock or synchronization boundary. Optional consoles or assistants should not +force shell, network, or credential behavior into the Viewer core. + +## Options + +1. Expose a small public Viewer facade for scene, state, refresh, history, + commands, docks, annotations, and overlays. +2. Let integrations continue using renderer and widget internals. +3. Define a large abstract Viewer/controller framework for every domain. +4. Move model navigation and inspectors into `compas_viewer`. + +## Recommendation + +Choose option 1. Provide public operations for: + +- scene access and GUID resolution; +- selection and transient state; +- categorized refresh; +- transform transactions and undo/redo; +- command registration and menu placement; +- dock addition/removal; and +- annotation and overlay addition/removal. + +`compas_model` retains its authoritative tree, projections, inspectors, +contacts, quality settings, and render cache. It consumes the facade and stops +accessing private/concrete Viewer renderer and sidebar paths. Do not create a +generic controller base class. + +A future console, terminal, or assistant may use a dock and registered command +API. Arbitrary Python/shell execution, subprocesses, credentials, network +transport, and assistant policy require a separate security ADR and are not +implemented in this wave. + +## Consequences + +- Domain packages gain a stable, testable integration surface. +- Viewer internals can change without coordinated domain rewrites. +- Public API growth is limited to demonstrated model and feature needs. +- Dock content remains Viewer/Qt-specific; core stays UI-independent. +- Console/chat presentation becomes possible without prematurely authorizing + execution or remote services. + +## Compatibility + +Preserve `ModelViewer` user-facing hierarchy, selection, visibility, quality, +cache, and inspection behavior. Internal direct renderer/sidebar access is +removed after facade coverage exists. + +## Verification + +- Test facade behavior with a lightweight fake UI/renderer boundary. +- Forbid private renderer/sidebar access in model integration tests. +- Verify dock and command registration/removal and duplicate-ID failures. +- Verify plugin discovery imports no Qt/OpenGL/model implementation modules. + +## Affected packages + +`compas_viewer`, `compas_model`, and `compas_framework`. + +## Dependencies + +- [ADR 001](001-ownership-boundaries.md) +- [ADR 003](003-viewer-state-and-selection.md) +- [ADR 004](004-transform-refresh-undo.md) +- [ADR 005](005-annotations-and-overlays.md) diff --git a/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md b/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md new file mode 100644 index 0000000..6c6269b --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md @@ -0,0 +1,78 @@ +# ADR 007: Initial Scope and Verification + +## Status + +Proposed. + +## Context + +Core Scene is consumed by Viewer, model, notebook, session, and CAD-host +packages. Expanding the first implementation across every backend would mix +runtime-specific migrations and make completion evidence unavailable. Package +tests alone do not prove installed cross-package behavior. + +## Options + +1. Implement an initial core/Viewer/model/framework wave and compatibility- + review adjacent consumers. +2. Migrate every visualisation and host package in one wave. +3. Change Viewer only and defer core/model alignment. +4. Accept package-local source tests as completion evidence. + +## Recommendation + +Choose option 1. + +Initial implementation packages are `compas`, `compas_viewer`, +`compas_model`, and `compas_framework`. Review `compas_session`, +`compas_notebook`, Rhino, Grasshopper, and Blender for compatibility with core +changes, but do not modify them without a scope amendment and approval. + +Require: + +- focused and full applicable local tests, Ruff, Pyright, and strict docs; +- clean package CI and built-wheel checks at exact heads; +- framework CI installing exact candidates and exercising plugin discovery, + scene/model construction, indexed buffers, selection, transformations, + annotations, serialization, and graphics-free discovery; and +- candidate-artifact CI for claims about independently built distributable + compatibility. + +Coordinate the plugin initiative's installed model/viewer registry gate rather +than creating a second competing test. + +## Consequences + +- The first wave remains verifiable on ordinary CI with offscreen Viewer + support. +- Host-specific behavior remains unverified and unmodified, not implicitly + passed. +- Core compatibility risks are still inspected before implementation. +- Later session, notebook, host, sub-object selection, advanced transform, + and console/assistant waves require explicit decisions. + +## Compatibility + +Any approved core change must preserve current public scene contracts for +compatibility-only consumers or identify a concrete blocker and return for +scope/compatibility approval before implementation proceeds. + +## Verification + +- Record local, package, framework-integration, and candidate-artifact + evidence separately in the handoff. +- Pin exact commit and artifact identities. +- Treat unavailable required runtime evidence as unverified, not passing. +- Keep generated files in isolated temporary directories. + +## Affected packages + +Initial: `compas`, `compas_viewer`, `compas_model`, and `compas_framework`. + +Compatibility review only: `compas_session`, `compas_notebook`, Rhino, +Grasshopper, and Blender scene adapters. + +## Dependencies + +- [ADRs 001–006](README.md) +- Plugin-implementations ADR 005 diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md new file mode 100644 index 0000000..b2f57a7 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -0,0 +1,14 @@ +# Scene, Viewer, and Visualisation Decisions + +All decisions are Proposed. None authorizes package source changes until the +user explicitly accepts it. + +| ADR | Decision | Status | Dependencies | +|---|---|---|---| +| 001 | [Ownership and state boundaries](001-ownership-boundaries.md) | Proposed | Geometry 022/024; Plugin 002 | +| 002 | [Indexed Viewer buffer geometry](002-indexed-buffer-geometry.md) | Proposed | 001; Typing structural inputs | +| 003 | [Viewer state and object selection](003-viewer-state-and-selection.md) | Proposed | 001 | +| 004 | [Transformations, refresh, and undo](004-transform-refresh-undo.md) | Proposed | 001, 003 | +| 005 | [Annotations, measurements, and overlays](005-annotations-and-overlays.md) | Proposed | 001, 002, 003 | +| 006 | [Public Viewer integration facade](006-viewer-integration-facade.md) | Proposed | 001, 003, 004, 005 | +| 007 | [Initial scope and verification](007-scope-and-verification.md) | Proposed | 001–006; Plugin 005 | diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md new file mode 100644 index 0000000..fc23b6e --- /dev/null +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -0,0 +1,78 @@ +# Scene, Viewer, and Visualisation Handoff + +Last updated: 2026-11-07 + +## Resume here + +Current phase: `architecture` + +Status: Cross-package reconnaissance and the architecture proposal are +complete. ADRs 001–007 are Proposed and awaiting explicit approval; no package +source changes are authorized. + +Read next: + +1. `objective.md` +2. `inventory.md` +3. `proposal.md` +4. `decisions/README.md` + +## Decisions and approvals + +- Accepted: none for this initiative. +- Proposed or unresolved: [ADRs 001–007](decisions/README.md) require explicit + approval. +- Scope boundary: notebook and CAD hosts are compatibility consumers; + `compas_session` requires an explicit inclusion decision. Do not modify + package source, merge, or publish without the corresponding approval. + +## Working state + +| Repository | Branch | Exact head | Pull request | Status | +|---|---|---|---|---| +| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `` | None | Local initiative documents | +| `compas-dev/compas` | `remove-future` | `99b82a6673ff7d05c1c323c8921135c274993f11` | None | Clean; inspected only | +| `compas-dev/compas_viewer` | `c3-upgrade` | `cf5a5195bda840a511319d6b7201978af68c15e3` | None | Clean; inspected only | +| `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Clean; inspected only | + +## Completed at this checkpoint + +- Inventoried core scene ownership, transformations, serialization, context + dispatch, tests, and documentation gaps. +- Inventoried Viewer rendering, indexed-buffer limitations, selection, + transforms, overlays, state, commands, and extension points. +- Inventoried model projection, render geometry, caching, selection, tests, + documentation, and Viewer coupling. +- Identified initial and compatibility-only package boundaries. +- Produced the architecture proposal, seven independent Proposed ADRs, and a + dependency-ordered implementation plan. + +## Next tasks + +1. Review and approve or revise ADRs 001–007. +2. After approval, create package initiative branches from the recorded bases. +3. Begin Phase 1 compatibility review and indexed-buffer implementation. + +## Blockers and approval gates + +- Package source implementation is blocked on proposal and ADR approval. +- Adding session, notebook, or host packages to implementation scope requires + explicit approval. + +## Verification + +Evidence by layer: + +| Layer | Status | Evidence | +|---|---|---| +| Local focused checks | Passed | Core 53 tests and Viewer 35 tests passed during reconnaissance; inventory documents the commands and warning scope. | +| Package CI | Not run | No package branches changed. | +| Framework integration CI | Not run | No implementation exists yet. | +| Candidate-artifact CI | Not applicable | Architecture documents only. | + +Run next: + +```text +git diff --check +/Users/vanmelet/miniforge3/envs/compas3/bin/python -m mkdocs build --strict +``` diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md new file mode 100644 index 0000000..74814a3 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -0,0 +1,112 @@ +# Scene, Viewer, and Visualisation Implementation Plan + +## Status + +Proposed architecture only. No implementation task below is authorized until +its governing ADRs are explicitly Accepted. + +## Dependency graph + +```text +ADRs 001 and 002 + | \ + v v +ADR 003 --> ADR 004 + | | + v v +ADR 005 ADR 006 + \ / + v v + ADR 007 +``` + +## Phase 1 — Boundaries and indexed geometry + +Governing ADRs: 001, 002, and 007. + +1. Audit compatibility-only consumers for affected core scene contracts and + stop for approval if a required core change would break them. +2. Implement indexed `BufferGeometry` and convenience constructors in Viewer. +3. Migrate Viewer adapters and buffer assembly without expanding indexed data. +4. Pass model render arrays to Viewer without intermediate Python-list + expansion while retaining model-owned quality and cache policy. +5. Add performance-regression assertions based on buffer/object counts rather + than unstable wall-clock thresholds. + +Exit gate: package-local source, typing, artifact, rendering-semantic, and +large-indexed-input evidence passes at exact candidate heads. + +## Phase 2 — State, selection, and transforms + +Governing ADRs: 001, 003, 004, and 007. + +1. Separate persistent Viewer configuration from transient Viewer state. +2. Implement the object-selection model and migrate viewport, rectangle, tree, + commands, renderer settings, and model integration. +3. Remove `is_selected` as a second authority and update serialization/tests. +4. Add atomic multi-object transform transactions, categorized refresh, and + the reversible transaction stack. +5. Add a minimal transform interaction only after command/programmatic + semantics pass; visual gizmo design may be a follow-up if it requires new + choices. + +Exit gate: all selection paths share one model; transform/undo tests cover +parents, batches, failures, and buffer-update scope. + +## Phase 3 — Annotations and overlays + +Governing ADRs: 001–005 and 007. + +1. Inspect current Tag/Arrow serialized behavior and document the exact + migration. +2. Implement world text annotation and distance dimension scene items/adapters. +3. Implement measurement tool preview, cancel, and completion. +4. Implement scale and legend screen overlays through one Viewer overlay layer. +5. Remove concrete approved-type checks from the main render loop. + +Exit gate: durable annotation round trips, transient overlays do not serialize, +and visual behavior passes offscreen and package artifact tests. + +## Phase 4 — Public integration facade and model alignment + +Governing ADRs: 001, 003–007. + +1. Add public refresh, history, command/menu, dock, annotation, and overlay + operations required by the approved features and model integration. +2. Migrate `ModelViewer` from direct renderer/sidebar access while preserving + its hierarchy, projections, selection results, contacts, inspectors, units, + quality, and cache behavior. +3. Add direct script examples for indexed buffers, selection, transforms, + measurements, overlays, and one custom dock. +4. Update core, Viewer, and model documentation using repository skills and + current MkDocs-compatible NumPy style. + +Exit gate: model integration uses only public Viewer APIs and package-local +tests/docs/artifacts pass. + +## Phase 5 — Framework integration and review + +Governing ADR: 007. + +1. Extend the existing coordinated model/viewer plugin lifecycle gate rather + than duplicating it. +2. Install exact candidate revisions and exercise the approved cross-package + runtime and typing contracts. +3. Run package and framework CI, candidate-artifact verification where + applicable, and independent code/documentation review. +4. Resolve findings, update the handoff with evidence by layer, and request + explicit merge approval. + +Exit gate: all applicable verification layers pass at recorded exact heads; +required unavailable evidence remains an explicit blocker. + +## Deferred work requiring new approval + +- sub-object or domain-component selection; +- ancestor/descendant group-transform semantics and advanced gizmos; +- angular, radial, area, or snapping measurement systems; +- a general overlay/plugin registry; +- console, terminal, Python/shell execution, assistant services, credentials, + or remote transports; +- `compas_session` reactive-state integration; and +- notebook, Rhino, Grasshopper, Blender, or other backend migrations. diff --git a/initiatives/scene-viewer-visualisation/inventory.md b/initiatives/scene-viewer-visualisation/inventory.md new file mode 100644 index 0000000..e6a1a97 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/inventory.md @@ -0,0 +1,146 @@ +# Scene, Viewer, and Visualisation Inventory + +Inventory date: 2026-11-07. + +## Audited checkpoints + +| Repository | Branch | Exact head | State | +|---|---|---|---| +| `compas-dev/compas` | `remove-future` | `99b82a6673ff7d05c1c323c8921135c274993f11` | Clean | +| `compas-dev/compas_viewer` | `c3-upgrade` | `cf5a5195bda840a511319d6b7201978af68c15e3` | Clean | +| `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | Clean | +| `compas-dev/compas_session` | `c3-upgrade` | `e0bdd02aa8490248c6f2f36042651d8ebfc4442b` | Clean | +| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | Based on `e797d49f77ac32b65371497a21925a02b7d048d8` | Clean before initiative documents | + +## Core scene infrastructure + +`compas.scene.Scene` owns a serializable tree, item and scene-object stores, +context selection, hierarchy mutation, drawing traversal, and glTF conversion. +`SceneObject` combines serializable visual configuration with context-adapter +factory dispatch, local/world transformations, renderer identifiers, and +manual cache invalidation. + +The global context registry maps item types to adapter classes and uses plugin +registration. Its lifecycle offers `clear`, `before_draw`, and `after_draw`, +but no renderer capability, event, change-notification, reverse-picking, or +incremental-update contract. Core has no common indexed render-buffer type. + +Core tests cover context registration, hierarchy, transformations, +serialization, glTF conversion, and scene ownership. They do not cover +selection, interaction state, undo, incremental redraw, overlays, or batched +render data. The visualisation introduction is stale in its use of `data`, its +transformation explanation, and its assumptions about available adapters. + +## Viewer architecture + +`Viewer` coordinates the Qt application, `ViewerScene`, renderer, +`ViewerState`, commands, events, and UI as a singleton. `ViewerScene` fixes the +context to `"Viewer"`, maps picking colors, and directly coordinates renderer +and sidebar updates. `ViewerSceneObject` converts items into point, line, +front-face, and back-face channels and reaches the active viewer through that +singleton. + +`BufferManager` efficiently batches ordinary objects into shared GPU-oriented +buffers and can update transforms without rebuilding topology. However, +`BufferGeometry` accepts expanded point, line-vertex, and triangle-vertex +arrays rather than shared vertices plus edge or triangle indices. Examples and +several adapters therefore duplicate vertices manually. `TessellationObject` +and `PolygonalSurfaceObject` already demonstrate indexed paths, but there is no +uniform public convenience layer. + +Viewport and scene-tree multi-selection exist. Selection is stored as mutable +`is_selected` flags on scene objects and synchronized by imperative refresh +calls. There is no separate observable selection model, selection-change +event, complete rectangle-deselection path, or common programmatic mutation +contract. + +Programmatic transforms and efficient transform-buffer updates exist, but +there is no object gizmo, transformation command, multi-object transform UI, +or defined undo contract. `Tag` and `ArrowOverlay` provide useful text and +arrow primitives, but the renderer special-cases their concrete classes. No +measurement, dimension, scale-bar, legend, or general overlay contract exists. + +`ViewerState` provides observable dotted-path access to persistent +configuration. Selection, active tools, gestures, scene mutations, and command +execution live elsewhere. Commands and UI definitions offer useful extension +points, but there is no comparable public dock composition API and no console, +terminal, assistant, or safe execution boundary. + +## Model integration + +`compas_model` owns backend-neutral model scene adapters, Viewer-specific +adapters, a `ModelViewer` controller, NumPy-based `RenderGeometry`, quality +settings, a revision-aware CPU cache, hierarchy projections, selection, +inspectors, and contact layers. + +The authoritative `Model.tree` and rendered `Scene` hierarchy intentionally +remain separate. `ModelViewer` constructs and indexes the scene projection, +but reaches into concrete viewer sidebar and renderer APIs. Structural changes +are reconciled through explicit rebuilds rather than an observed projection +contract. + +Model render geometry preserves separate indexed filled triangles and visible +line segments, but Viewer-specific adapters expand some arrays back to Python +lists. This makes buffer ownership and reusable conversion responsibilities +unclear. Package tests and documentation cover the current controller well, +including multi-selection, visibility, caching, contacts, and offscreen viewer +integration. + +## Adjacent packages + +`compas_session` persists a generic core scene, data, settings, and undo/redo +history, but it is not a reactive viewer/UI state store. Notebook and CAD-host +packages consume core scene contracts under different runtime constraints. +They should be checked for compatibility with approved core changes, but +implementation migration would broaden the initial initiative materially. + +## Framework evidence + +Package-local core, viewer, and model tests provide substantial evidence. The +framework repository currently has no installed cross-package scene/viewer +test. The plugin initiative separately requires a coordinated installed +model/viewer registry and lifecycle test; this initiative should coordinate +that gate rather than duplicate it. + +Focused reconnaissance results: + +- Core scene/plugin/glTF suite: 53 passed; one non-authoritative cache-write + warning because the checkout cache directory was not writable. +- Viewer selection/state/tessellation/tag/overlay suite: 35 passed offscreen. +- Model integration behavior was inspected from its existing tests and build + workflow; no new model tests were run during this inventory. + +## Principal gaps and risks + +1. Durable scene state, persistent configuration, and transient interaction + state do not have explicit ownership boundaries. +2. Renderer identity has no common reverse mapping to scene objects or domain + elements. +3. Scene mutations, selection, renderer updates, and UI refreshes use + distributed imperative paths. +4. Raw indexed buffers lack a uniform public input and batching contract. +5. Overlay rendering is coupled to concrete Viewer classes. +6. Model controllers depend on private or concrete viewer structure. +7. Core appearance serialization and glTF export do not cover all visual + settings consistently. +8. Per-object pickability conflicts with batching for large auxiliary data. +9. Singleton coupling makes state, commands, rendering, and scene behavior + harder to test independently. +10. Scope can expand rapidly across notebook and host adapters unless initial + and compatibility-only packages are explicit. + +## Architecture questions + +1. Does core own only scene hierarchy and transformations, or also neutral + render primitives and change events? +2. Where do indexed buffers, picking identities, and reverse lookup live? +3. What observable state model unifies viewport, tree, and programmatic + selection without making UI state serializable scene data? +4. What change categories allow transform-only, style-only, geometry, and + hierarchy updates to remain efficient? +5. Which annotation and overlay objects are durable, transient, or both? +6. How should domain controllers depend on public viewer capabilities rather + than widget and renderer internals? +7. What is the smallest safe extension boundary for docks, consoles, and + optional assistant integrations? +8. Which scene appearance semantics must serialization and glTF preserve? diff --git a/initiatives/scene-viewer-visualisation/objective.md b/initiatives/scene-viewer-visualisation/objective.md new file mode 100644 index 0000000..0c36cb1 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/objective.md @@ -0,0 +1,104 @@ +# Scene, Viewer, and Visualisation Initiative + +## Objective + +Establish a simple, coherent, and scalable visualisation architecture across +COMPAS core scenes, `compas_viewer`, and domain integrations such as +`compas_model`. Users should be able to visualise large indexed datasets, +select and transform objects consistently, add measurements and annotations, +and extend the viewer UI without coupling durable scene data to a particular +renderer or Qt widget hierarchy. + +The initiative should clarify ownership before adding features. Core scene +data, renderer-facing geometry, persistent configuration, transient tool and +selection state, and domain-specific controllers must each have one clear +home and contract. + +## Questions to resolve + +1. Which data and behavior belong to backend-neutral `compas.scene`, the + viewer renderer, viewer application state, and package-specific adapters? +2. What indexed point, line, and triangle buffer contract supports efficient + visualisation without requiring heavyweight core geometry objects? +3. How should selection, element picking, hover, and multi-selection be shared + by the viewport, scene graph, and programmatic consumers? +4. What mutation and undo contract supports single- and multi-object + transformations? +5. Which annotations, measurements, scale indicators, legends, and overlays + are durable scene data, and which are transient tool or UI state? +6. How should persistent configuration be separated from reactive session, + tool, and UI state? +7. Which stable extension boundary can support docks, consoles, terminals, or + optional assistants without embedding those concerns in core scene data? +8. How should `compas_model` and future domain packages project authoritative + domain hierarchies into scenes without depending on private viewer widgets? +9. Which local, package, framework-integration, and artifact evidence is + required for each approved wave? + +## Design principles + +- Keep core scene infrastructure backend-neutral. +- Preserve indexed data and batch rendering where possible; do not expand a + large edge or triangle set into one Python object per primitive. +- Keep raw NumPy-compatible buffers valid inputs without forcing conversion + through COMPAS geometry or data objects. +- Separate durable scene state, persistent viewer configuration, and transient + interaction state. +- Provide one observable selection path for viewport, scene graph, and code. +- Prefer explicit, small data contracts over renderer-specific base classes or + speculative extension frameworks. +- Keep plugin discovery graphics-free and optional UI/runtime imports lazy. +- Reuse accepted tessellation, typing, plugin, and repository-modernisation + contracts rather than duplicating them. +- Make high-level convenience APIs simple while keeping ownership and + performance costs visible. + +## Proposed initial scope + +- `compas`: scene hierarchy, scene-object identity and transformations, and + any approved backend-neutral contracts. +- `compas_viewer`: render buffers, GPU lifecycle, viewport interaction, + selection, overlays, commands, and UI state. +- `compas_model`: domain-tree projection and public viewer integration. +- `compas_framework`: installed cross-package verification. + +## Deliverables + +1. A verified cross-package inventory and approved architecture decisions. +2. Clear ownership and state boundaries across core, viewer, and domain + integrations. +3. Efficient convenience APIs for indexed points, edges, and triangles. +4. Consistent observable selection and transformation contracts. +5. An extensible annotation, measurement, and overlay foundation. +6. Public integration boundaries for domain controllers and optional UI + extensions. +7. Package-local and framework-level tests, examples, and documentation. + +## Non-goals without a later scope decision + +- Replacing the core plugin manager or accepted geometry conversion APIs. +- Making Qt, OpenGL, or viewer-specific state a core COMPAS dependency. +- Implementing a chatbot service, shell execution engine, or remote transport + before the UI extension and security boundaries are approved. +- Migrating notebook, Rhino, Grasshopper, or Blender adapters in the initial + wave. +- Turning `compas_session` into a general reactive application store without + a separate persistence decision. +- Adding modeling functionality to the viewer or duplicating domain data + structures in the scene graph. + +## Dependencies + +- Geometry-tessellation ADRs 022 and 024 govern transfer-oriented + `Tessellation`, producer conversions, and representation-preserving mesh + triangulation. +- Typing-alignment decisions govern structural NumPy-compatible inputs. +- Plugin-implementations decisions govern lightweight Viewer-context + registration and leave coordinated model/viewer lifecycle evidence open. +- Repository-modernisation decisions govern package workflows and artifact + verification. + +## Current status + +Reconnaissance is complete. Architecture and ADRs are not yet approved. No +package source changes are authorized. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md new file mode 100644 index 0000000..ff44abd --- /dev/null +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -0,0 +1,306 @@ +# Scene, Viewer, and Visualisation Proposal + +## Summary + +Keep `compas.scene` responsible for durable, backend-neutral scene content and +hierarchy. Put indexed render buffers, picking, selection, transient state, +tools, overlays, GPU synchronization, and UI composition in `compas_viewer`. +Let domain packages such as `compas_model` project their authoritative data +through a small public Viewer facade rather than renderer or widget internals. + +The first implementation wave should establish these boundaries and deliver +object selection, efficient indexed geometry, multi-object transforms, +measurements, annotations, scale/legend overlays, and public dock/command +composition. It should not attempt a universal renderer API, a generic reactive +framework, sub-object editing, a shell, or host-application migration. + +## Recommended architecture + +### Durable scene content + +Core `Scene` remains the serializable hierarchy. Core `SceneObject` continues +to own item references, local transformations, hierarchy, visibility, and +durable appearance. Core does not gain Qt signals, GPU buffers, picking IDs, +selection state, tool state, or viewer commands. + +Scene-object GUIDs are the stable boundary between durable content and viewer +state. Viewer and domain controllers refer to scene objects by GUID and resolve +them through the scene when needed. Renderer-specific pick IDs remain short- +lived Viewer mappings and are never serialized. + +### Indexed render geometry + +`compas_viewer` owns one public indexed `BufferGeometry` contract: + +```python +geometry = BufferGeometry( + vertices=vertices, + points=point_indices, + edges=edge_indices, + triangles=triangle_indices, +) +``` + +Vertices accept the approved structural numerical input, including Python +sequences and NumPy arrays. Index channels are optional and retain their +connectivity. Convenience constructors cover the common direct cases: + +```python +BufferGeometry.from_points(vertices) +BufferGeometry.from_vertices_and_edges(vertices, edges) +BufferGeometry.from_vertices_and_triangles(vertices, triangles) +``` + +Construction normalizes each supplied channel once to the Viewer's required +NumPy dtype and validates only rank, column count, and index bounds. It does +not create `Mesh`, `PolygonalSurface`, `Tessellation`, or one object per +primitive. Styling stays on the scene object; a separate color-buffer decision +is required only when current uniform/per-item styling proves insufficient. + +Existing Viewer adapters should return indexed channels to the buffer manager +instead of expanding geometry. `compas_model.RenderGeometry` should either use +this contract directly or remain a domain cache whose arrays pass to it without +list expansion. Geometry producers continue to use their approved +`to_tessellation` and `to_polygonal_surface` APIs; this Viewer contract does +not become a geometry-algorithm input. + +### Viewer state and selection + +Separate three state classes: + +| State | Owner | Persistence | +|---|---|---| +| Scene items, hierarchy, local transformations, durable appearance | `compas.scene` | Scene serialization | +| Viewer defaults, appearance, key bindings, layout preferences | `Viewer.config` | Viewer configuration | +| Selection, hover, active tool, gestures, and transient tool results | `Viewer.state` | Session-only | + +`Viewer.state.selection` is the one object-selection model. It stores ordered +scene-object GUIDs and exposes replace, add, remove, toggle, clear, and query +operations plus one change notification. Viewport picking, rectangle +selection, the scene tree, commands, and `compas_model` all mutate this model. +The current mutable and serialized `ViewerSceneObject.is_selected` path is +removed rather than retained as a second authority. + +Initial selection is object-level. The architecture reserves no generic +component-token schema; vertex, edge, face, or domain-element selection should +be proposed when a concrete editing workflow requires it. + +The state implementation should be a small Python model with a Qt bridge, not +a generic observable dictionary or third-party reactive framework. The +renderer reads selection state when updating its per-object settings buffer. + +### Transformations and undo + +Core transformations remain authoritative. Viewer exposes one public +multi-object transformation operation and uses it from code, commands, and a +future gizmo: + +```python +viewer.transform_objects(objects, transformation, space="world") +``` + +The initial operation applies one world-space delta to every selected object's +pre-operation world transformation. For each object, Viewer derives the new +local transformation from its parent world transformation. Ancestor/descendant +pairs in one request are rejected initially because applying the same delta to +both is ambiguous. Invalid targets leave all objects unchanged. + +Every successful call is one transaction containing the before and after local +transformations. A small Viewer undo stack handles these explicit reversible +transactions. Existing callback commands remain valid; only mutating commands +that implement the reversible transaction contract enter history. This does +not move general application/session history into Viewer or `compas_session`. + +Viewer retains explicit refresh operations for geometry, appearance, +transform, and hierarchy changes. The initial wave does not add a generic core +scene event bus: direct external mutation still requires the corresponding +public Viewer refresh call. This keeps synchronization costs explicit and +avoids making all core scene properties observable. + +### Annotations and overlays + +Use two explicit paths: + +- World-anchored annotations are serializable scene items with Viewer scene + adapters. The initial types are text annotation and distance dimension. A + distance dimension stores its two world anchors, display unit/precision, and + optional label override; its measured value is derived, not duplicated. +- Screen-space overlays are transient Viewer UI objects. The initial types are + scale indicator and legend. They are not scene items and do not participate + in scene serialization or picking unless a later requirement says so. + +Existing `Tag` and `ArrowOverlay` should be aligned with these two paths rather +than leaving concrete-class checks in the renderer. Do not introduce a +framework-wide overlay registry. One Viewer-owned world-annotation adapter +path and one Viewer overlay layer are sufficient for the approved types. + +The measurement tool owns temporary pointer/preview state in `Viewer.state`. +Completing a measurement creates a durable distance-dimension scene item; +cancelling it leaves no scene mutation. + +### Public Viewer facade + +Expose the small set of operations domain integrations need without giving +them renderer or widget internals: + +- `viewer.scene` for durable content; +- `viewer.state.selection` for selection; +- `viewer.refresh_geometry`, `refresh_appearance`, `refresh_transform`, and + `refresh_hierarchy` for explicit synchronization; +- `viewer.transform_objects` and undo/redo; +- public command registration and menu placement; +- public dock addition/removal using Viewer component/widget content; and +- public annotation and overlay addition. + +`compas_model.ModelViewer` keeps `Model.tree` authoritative, retains its +domain-specific render cache and projections, and migrates from direct +`viewer.renderer` and `viewer.ui.sidebar` access to this facade. The initiative +does not create a generic model-controller base class or duplicate the model +tree in application state. + +A console, terminal, or assistant can later occupy a public dock and invoke +registered commands, but arbitrary code execution, shell access, credentials, +remote transports, and assistant policy are explicitly outside this wave and +require a security decision. + +## Alternatives and tradeoffs + +### Put render buffers in core + +Rejected for the initial wave. Core would gain renderer-oriented dtype, +channel, and update assumptions while notebook and host backends have not +demonstrated a shared contract. Structural geometry inputs and `Tessellation` +already cover neutral transfer needs; GPU-ready batching belongs to Viewer. + +### Use scene-object flags as selection state + +Rejected. It makes transient interaction state serializable, requires every UI +to poll/mutate objects, and leaves viewport, tree, domain controller, and +renderer synchronization distributed. + +### Add a universal reactive store and scene event bus + +Rejected for the initial wave. It adds a second application framework and +forces observability into core without established semantics for arbitrary +item mutation. Explicit state models and refresh categories satisfy current +requirements more transparently. + +### Make all annotations screen overlays + +Rejected. Measurements and world labels need world anchors, scene hierarchy, +transformations, and persistence. Conversely, scale indicators and legends are +view-dependent and should not become durable geometry. + +### Standardize every visualisation backend now + +Rejected. Notebook and CAD hosts are important compatibility consumers, but +their runtime and rendering models differ. The first wave should avoid breaking +their core scene contracts and record follow-up work only after the Viewer +design is proven. + +## Compatibility implications + +- Removing `ViewerSceneObject.is_selected` is a deliberate Viewer API break. + Commands, tree widgets, shaders, tests, and model integrations migrate in one + coordinated change; no writable compatibility alias remains. +- `BufferGeometry` construction changes from expanded channel vertices to + shared indexed vertices. Current examples and adapters migrate together. + A deprecated parallel constructor is not proposed. +- Existing core scene serialization remains valid because Viewer transient + state is removed from scene-object settings rather than added to core. +- Current `Tag` and `ArrowOverlay` data may require a documented migration to + the accepted annotation/overlay types. Exact compatibility should be checked + against serialized fixtures before implementation; do not silently reinterpret + ambiguous old data. +- `compas_model` keeps its public domain behavior, hierarchy, quality policy, + and cache semantics while changing only its Viewer integration boundary. +- Viewer plugin discovery remains graphics-free and function-local under the + accepted plugin ADRs. + +## Affected packages + +| Package | Responsibility | +|---|---| +| `compas` | Preserve scene identity, hierarchy, transformations, durable appearance, and serialization; clarify stale documentation. | +| `compas_viewer` | Implement indexed buffers, state/selection, transforms/history, annotations, overlays, facade, rendering, and UI. | +| `compas_model` | Consume indexed geometry and the public Viewer facade while preserving the authoritative model tree and cache. | +| `compas_framework` | Pin exact candidates and verify installed cross-package scene, plugin, selection, transform, and buffer behavior. | + +`compas_session`, `compas_notebook`, Rhino, Grasshopper, and Blender are +compatibility-reviewed but not implementation targets in the initial wave. + +## Tests and examples + +### Core + +- Preserve scene serialization, shared-item identity, hierarchy, and local/ + world transformation tests. +- Add regression coverage proving transient Viewer state is absent from core + scene data and serialization. +- Correct and test the core scene/visualisation guide against current APIs. + +### Viewer + +- Accept list and NumPy vertices/indices; verify shapes, bounds, dtypes, + non-mutation, and retained indices. +- Compare large indexed edge/triangle input with expected buffer counts and + assert it does not create one scene object per primitive. +- Exercise selection replacement/add/remove/toggle from viewport, tree, and + code through the same observable model. +- Verify renderer picking IDs resolve to scene GUIDs and are not serialized. +- Test world-space multi-object transforms, parent conversion, atomic failure, + undo/redo, and ancestor/descendant rejection. +- Test distance derivation, unit/precision formatting, tool cancel/complete, + annotation serialization, and transient overlay non-serialization. +- Test public dock/command composition without importing optional integrations + during plugin discovery. + +### Model and framework + +- Preserve model hierarchy, selection, visibility, cache invalidation, and + render-quality tests while forbidding private renderer/sidebar access. +- Add an installed exact-candidate test that discovers Viewer/model plugins, + builds a model scene, selects multiple elements, updates one indexed geometry + buffer, transforms objects, and round-trips durable scene content. +- Keep candidate-artifact evidence separate from source-build integration. + +Examples remain direct scripts and demonstrate, in order: + +1. vertices and edges; +2. vertices and triangles; +3. shared indexed geometry with selection; +4. multi-object transformation and undo; +5. distance measurement and world annotation; and +6. scale/legend overlays and a custom dock. + +## Dependency order + +```text +ADRs 001 and 002 + | \ + v v +ADR 003 --> ADR 004 + | | + v v +ADR 005 ADR 006 + \ / + v v + ADR 007 +``` + +Core geometry, typing, plugin, and repository-modernisation decisions remain +upstream constraints. Implementation starts only after all ADRs required for a +wave are Accepted. + +## Decisions requiring approval + +1. [ADR 001 — Ownership and state boundaries](decisions/001-ownership-boundaries.md) +2. [ADR 002 — Indexed Viewer buffer geometry](decisions/002-indexed-buffer-geometry.md) +3. [ADR 003 — Viewer state and object selection](decisions/003-viewer-state-and-selection.md) +4. [ADR 004 — Transformations, refresh, and undo](decisions/004-transform-refresh-undo.md) +5. [ADR 005 — Annotations, measurements, and overlays](decisions/005-annotations-and-overlays.md) +6. [ADR 006 — Public Viewer integration facade](decisions/006-viewer-integration-facade.md) +7. [ADR 007 — Initial scope and verification](decisions/007-scope-and-verification.md) + +No package source changes should begin before the governing decisions are +explicitly approved. From ac5d5559945db9c858d272952b9c4595814df462 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 15:56:40 +0100 Subject: [PATCH 02/22] Accept scene viewer visualisation ADRs --- .../scene-viewer-visualisation/README.md | 4 ++-- .../decisions/001-ownership-boundaries.md | 2 +- .../decisions/002-indexed-buffer-geometry.md | 2 +- .../decisions/003-viewer-state-and-selection.md | 2 +- .../decisions/004-transform-refresh-undo.md | 2 +- .../decisions/005-annotations-and-overlays.md | 2 +- .../decisions/006-viewer-integration-facade.md | 2 +- .../decisions/007-scope-and-verification.md | 2 +- .../decisions/README.md | 17 ++++++++--------- .../scene-viewer-visualisation/handoff.md | 16 ++++++++-------- .../implementation-plan.md | 4 ++-- .../scene-viewer-visualisation/objective.md | 4 ++-- 12 files changed, 29 insertions(+), 30 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/README.md b/initiatives/scene-viewer-visualisation/README.md index accc09d..72647f2 100644 --- a/initiatives/scene-viewer-visualisation/README.md +++ b/initiatives/scene-viewer-visualisation/README.md @@ -3,8 +3,8 @@ This initiative aligns backend-neutral scene infrastructure, viewer rendering and interaction, and model-to-scene integration across the COMPAS framework. -Current phase: **architecture proposal complete and awaiting approval; no -package source changes authorized**. +Current phase: **architecture approved; implementation may begin in dependency +order**. - [Objective](objective.md) - [Inventory](inventory.md) diff --git a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md index 0fb0bc9..e8552ed 100644 --- a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md +++ b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context diff --git a/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md b/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md index 3de74b7..febaf00 100644 --- a/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md +++ b/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context diff --git a/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md b/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md index eb54681..4dc6b91 100644 --- a/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md +++ b/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context diff --git a/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md b/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md index 7ab0ebd..2981127 100644 --- a/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md +++ b/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context diff --git a/initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md b/initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md index e738eb9..9dbf1ad 100644 --- a/initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md +++ b/initiatives/scene-viewer-visualisation/decisions/005-annotations-and-overlays.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context diff --git a/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md b/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md index 3821fba..480625d 100644 --- a/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md +++ b/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context diff --git a/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md b/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md index 6c6269b..9447371 100644 --- a/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md +++ b/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index b2f57a7..1ef655f 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -1,14 +1,13 @@ # Scene, Viewer, and Visualisation Decisions -All decisions are Proposed. None authorizes package source changes until the -user explicitly accepts it. +All decisions are Accepted. The user approved ADRs 001–007 on 2026-11-07. | ADR | Decision | Status | Dependencies | |---|---|---|---| -| 001 | [Ownership and state boundaries](001-ownership-boundaries.md) | Proposed | Geometry 022/024; Plugin 002 | -| 002 | [Indexed Viewer buffer geometry](002-indexed-buffer-geometry.md) | Proposed | 001; Typing structural inputs | -| 003 | [Viewer state and object selection](003-viewer-state-and-selection.md) | Proposed | 001 | -| 004 | [Transformations, refresh, and undo](004-transform-refresh-undo.md) | Proposed | 001, 003 | -| 005 | [Annotations, measurements, and overlays](005-annotations-and-overlays.md) | Proposed | 001, 002, 003 | -| 006 | [Public Viewer integration facade](006-viewer-integration-facade.md) | Proposed | 001, 003, 004, 005 | -| 007 | [Initial scope and verification](007-scope-and-verification.md) | Proposed | 001–006; Plugin 005 | +| 001 | [Ownership and state boundaries](001-ownership-boundaries.md) | Accepted | Geometry 022/024; Plugin 002 | +| 002 | [Indexed Viewer buffer geometry](002-indexed-buffer-geometry.md) | Accepted | 001; Typing structural inputs | +| 003 | [Viewer state and object selection](003-viewer-state-and-selection.md) | Accepted | 001 | +| 004 | [Transformations, refresh, and undo](004-transform-refresh-undo.md) | Accepted | 001, 003 | +| 005 | [Annotations, measurements, and overlays](005-annotations-and-overlays.md) | Accepted | 001, 002, 003 | +| 006 | [Public Viewer integration facade](006-viewer-integration-facade.md) | Accepted | 001, 003, 004, 005 | +| 007 | [Initial scope and verification](007-scope-and-verification.md) | Accepted | 001–006; Plugin 005 | diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index fc23b6e..d3b3c92 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -4,11 +4,11 @@ Last updated: 2026-11-07 ## Resume here -Current phase: `architecture` +Current phase: `implementation` -Status: Cross-package reconnaissance and the architecture proposal are -complete. ADRs 001–007 are Proposed and awaiting explicit approval; no package -source changes are authorized. +Status: Cross-package reconnaissance and architecture are complete. The user +accepted ADRs 001–007 on 2026-11-07; implementation may begin in dependency +order within the approved initial scope. Read next: @@ -19,12 +19,12 @@ Read next: ## Decisions and approvals -- Accepted: none for this initiative. -- Proposed or unresolved: [ADRs 001–007](decisions/README.md) require explicit - approval. +- Accepted: [ADRs 001–007](decisions/README.md). +- Proposed or unresolved: none. - Scope boundary: notebook and CAD hosts are compatibility consumers; `compas_session` requires an explicit inclusion decision. Do not modify - package source, merge, or publish without the corresponding approval. + package source outside the initial scope, merge, or publish without the + corresponding approval. ## Working state diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 74814a3..09b9497 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,8 +2,8 @@ ## Status -Proposed architecture only. No implementation task below is authorized until -its governing ADRs are explicitly Accepted. +Architecture approved. ADRs 001–007 are Accepted; implementation may proceed +in dependency order within the approved initial scope. ## Dependency graph diff --git a/initiatives/scene-viewer-visualisation/objective.md b/initiatives/scene-viewer-visualisation/objective.md index 0c36cb1..51be96e 100644 --- a/initiatives/scene-viewer-visualisation/objective.md +++ b/initiatives/scene-viewer-visualisation/objective.md @@ -100,5 +100,5 @@ home and contract. ## Current status -Reconnaissance is complete. Architecture and ADRs are not yet approved. No -package source changes are authorized. +Reconnaissance and architecture are complete. ADRs 001–007 are Accepted and +implementation is authorized for the approved initial scope. From b0b76f1a89b45f1d1374c0d7f4a453ef7d168298 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 16:11:46 +0100 Subject: [PATCH 03/22] Revisit scene state architecture --- .../scene-viewer-visualisation/README.md | 9 +- .../decisions/001-ownership-boundaries.md | 10 ++ .../008-scene-nodes-and-runtime-adapters.md | 158 ++++++++++++++++++ .../decisions/009-scene-state-fields.md | 101 +++++++++++ .../decisions/README.md | 13 +- .../scene-viewer-visualisation/handoff.md | 26 ++- .../implementation-plan.md | 51 ++++-- .../scene-viewer-visualisation/inventory.md | 31 ++++ .../scene-viewer-visualisation/proposal.md | 86 +++++++--- 9 files changed, 434 insertions(+), 51 deletions(-) create mode 100644 initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md diff --git a/initiatives/scene-viewer-visualisation/README.md b/initiatives/scene-viewer-visualisation/README.md index 72647f2..95d999c 100644 --- a/initiatives/scene-viewer-visualisation/README.md +++ b/initiatives/scene-viewer-visualisation/README.md @@ -3,8 +3,7 @@ This initiative aligns backend-neutral scene infrastructure, viewer rendering and interaction, and model-to-scene integration across the COMPAS framework. -Current phase: **architecture approved; implementation may begin in dependency -order**. +Current phase: **architecture amendment proposed; implementation paused**. - [Objective](objective.md) - [Inventory](inventory.md) @@ -13,7 +12,11 @@ order**. - [Implementation plan](implementation-plan.md) - [Current handoff](handoff.md) -The proposed initial package scope is `compas`, `compas_viewer`, +ADRs 001–007 are Accepted. Verified round-trip failures exposed an unresolved +scene-node/runtime-adapter and serialization boundary. Proposed ADRs 008–009 +must be approved before Phase 1 begins. + +The approved initial package scope is `compas`, `compas_viewer`, `compas_model`, and `compas_framework`. Session persistence, notebook visualisation, and CAD-host adapters are compatibility-review consumers until an approved decision admits them to implementation scope. diff --git a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md index e8552ed..6c607f9 100644 --- a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md +++ b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md @@ -68,3 +68,13 @@ data and requires fixture inspection and migration documentation. - Geometry-tessellation ADRs 022 and 024 - Plugin-implementations ADR 002 + +## Pending amendments + +Verified round-trip failures show that this decision did not distinguish the +durable scene node/state from the context-specific runtime `SceneObject` +adapter precisely enough. Implementation of the core ownership, GUID, context, +and serialization clauses is blocked by Proposed +[ADR 008](008-scene-nodes-and-runtime-adapters.md) and +[ADR 009](009-scene-state-fields.md). This note does not change ADR 001's +Accepted status or approve either amendment. diff --git a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md new file mode 100644 index 0000000..5005d55 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md @@ -0,0 +1,158 @@ +# ADR 008: Serializable Scene Nodes and Runtime Adapters + +## Status + +Proposed. + +## Context + +ADR 001 correctly separates durable scene content from Viewer interaction and +renderer state, but it still treats `SceneObject` as both durable node and +context-specific runtime adapter. Current serialization stores an item's GUID +plus `sceneobject.settings`, then calls `Scene.add(..., **settings)` during +load. Factory dispatch chooses a runtime subclass and executes its constructor +before that object is attached to the reconstructed hierarchy. + +Two verified regressions expose the consequences: + +1. A Viewer Box/ShapeObject with local translation `[2, 0, 0]` reloads with + `transformation is None` because `ViewerSceneObject.settings` replaces + rather than extends core settings. In a headless ShapeObject case, `u=7`, + `v=9`, and a face color reload as the defaults `16`, `16`, and the default + face color. +2. A `ModelViewer` scene cannot reload. The controller originally creates + `ModelObject(add_elements=False)` and `ElementObject(add_children=False)`, + but those construction controls are absent from serialized settings. + Reload dispatches `ModelObject` with `add_elements=True`; its constructor + calls `self.add(...)` before attachment and raises `RuntimeError: A detached + scene object cannot own child objects.` Render caches are transient and + should not be serialized, but hierarchy reconstruction must not depend on + them or on constructor side effects. + +The shared item store already preserves identity when multiple nodes reference +one item GUID. Scene-object/node GUIDs are not preserved across round trips. +Context also determines which runtime subclass is constructed, even though a +serialized scene should remain loadable without that backend. + +## Options + +1. Separate a serializable scene-owned node/state value from context-specific + runtime adapters and reconstruct them in two phases. +2. Keep `SceneObject` as both node and adapter and expand every subclass's + `settings` property until current tests pass. +3. Serialize complete runtime adapter objects, including their concrete class + and context. +4. Serialize only items and hierarchy and discard all per-node appearance and + transformations. + +## Recommendation + +Choose option 1. + +`Scene` owns a serializable node/state record for every hierarchy entry. The +closed base record contains: + +- a durable node GUID; +- node kind (`item` or `group`); +- optional item GUID; +- name; +- local transformation; +- visibility, opacity, and base appearance; and +- explicitly declared extension state governed by ADR 009. + +The item store remains separate and keyed by item GUID, preserving shared item +identity. Node GUIDs are serialized and restored so selection references, +domain indexes, and external scene references have durable identity. Runtime +adapter instances are not durable identities. + +Deserialize in two phases: + +1. validate and create the item store, nodes, state, GUIDs, and complete + hierarchy without context dispatch or adapter constructors; +2. bind adapters for an explicitly requested or detected runtime context only + after the scene is structurally complete, either eagerly for drawing or + lazily on first use. + +`SceneObject` becomes the runtime adapter bound to a scene, node, and optional +item. Its constructor must not populate hierarchy or own serialized state. +Domain projection such as `ModelViewer` creates nodes explicitly through a +controller; adapter binding never recreates children. + +Scene context is runtime binding configuration, not authoritative serialized +content. A scene may record a non-binding context hint for user experience, +but loading must not require that context or silently select a different one. +Drawing without a usable context raises a precise runtime error after the +backend-neutral scene has loaded. + +Known extension fields are activated only by a compatible adapter. Unknown +extension namespaces and fields are preserved losslessly as inactive node +state and written back unchanged. Unknown required base schema versions fail +validation; unknown adapter state is not passed blindly to constructors. + +## Refinement of ADR 001 + +This ADR preserves ADR 001's package boundaries but refines these clauses: + +- "Core owns scene items, hierarchy, scene-object GUIDs..." becomes: core + owns items plus durable node/state GUIDs; runtime adapter identity is not + serialized. +- "GUIDs connect durable scene objects to Viewer state" becomes: durable node + GUIDs connect scene content to Viewer state and domain indexes. +- Core still owns transformations, visibility, durable appearance, and + serialization, but those values live on node state rather than being + discovered from a runtime adapter's constructor/settings implementation. + +Implementation of ADR 001's durable identity and serialization boundary is +blocked until this amendment and ADR 009 are approved. + +## Consequences + +- Scenes load without Viewer, model adapters, or another visualization backend. +- Runtime constructors no longer execute hierarchy-building side effects during + deserialization. +- Switching or omitting runtime contexts does not destroy durable node state. +- Shared item identity and durable node identity have separate, explicit GUIDs. +- Core Scene/SceneObject APIs require a coordinated redesign and compatibility + review; this is larger than patching two `settings` properties. +- Adapter binding and lifecycle need focused tests, but no universal renderer + abstraction or event bus is introduced. + +## Compatibility + +The existing serialized scene shape requires an explicit one-way loader into +the new node schema. Old files have no durable node GUID, so the loader +generates one deterministically only where the legacy hierarchy supplies a +stable path; otherwise it generates and documents a new identity. It preserves +known legacy settings and rejects ambiguous state rather than guessing. + +Existing public code may continue to receive a `SceneObject` adapter from +`Scene.add`, but code that treats adapter identity or constructor side effects +as durable must migrate. Exact compatibility is part of the Phase 1 audit. + +## Verification + +- Reproduce both verified regressions as tests before implementation. +- Round-trip local transformations, `u=7`, `v=9`, face color, shared items, + node GUIDs, groups, and hierarchy without a visualization backend installed. +- Load the model scene without calling adapter hierarchy constructors, then + bind Viewer adapters after the hierarchy is complete. +- Load and re-save unknown extension state without loss or constructor use. +- Verify missing/unknown context permits load but produces a precise binding or + draw error. +- Verify duplicate item or node GUIDs and unsupported base schema versions fail + atomically. + +## Affected packages + +`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. + +Compatibility review only: `compas_session`, `compas_notebook`, and CAD-host +scene adapters. + +## Dependencies + +- [ADR 001](001-ownership-boundaries.md), refined by this decision + +ADR 009 supplies the serialization field policy required to implement this +decision. The two Proposed amendments must be approved together, but ADR 008 +defines the ownership boundary first. diff --git a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md new file mode 100644 index 0000000..4c33f5b --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md @@ -0,0 +1,101 @@ +# ADR 009: Explicit Scene-State Serialization Fields + +## Status + +Proposed. + +## Context + +Current scene serialization depends on each runtime adapter's `settings` +property and reconstructs state by replaying that mapping as constructor +arguments. Subclasses can accidentally replace base settings, as demonstrated +by the lost transformation regression. Required subclass state can be omitted, +as demonstrated by lost ShapeObject resolution and face color. Conversely, +serializing `__dict__`, every property, annotations, or constructor parameters +would capture caches, renderer handles, item/scene backreferences, derived +values, and construction commands such as `add_elements`. + +The durable node proposed by ADR 008 needs an explicit field policy that +supports inheritance without treating Python introspection as persistence. + +## Options + +1. Use a closed base node-state schema plus explicit MRO-composed extension + field declarations. +2. Serialize every entry in `__dict__` except a growing denylist. +3. Serialize every public property, type annotation, or constructor parameter + discovered through introspection. +4. Require every subclass to replace and manually merge a free-form + `settings` dictionary. +5. Allow only the closed base schema and prohibit all adapter/domain extension + state. + +## Recommendation + +Choose option 1. + +Base node state is a closed value-object schema owned by core. A class that +owns additional durable scene state declares only its local fields through an +explicit class-level declaration. The serializer composes declarations across +the MRO from base to subclass, rejects duplicate or incompatible declarations, +and stores extension values under a stable owning namespace. + +Declarations specify the serialized name, expected value contract, default or +required status, and whether omission is allowed. They do not execute arbitrary +getters during schema discovery. The implementation may use annotations, +constructor signatures, descriptors, and properties only to validate a +declaration or generate editor/documentation metadata; introspection never +decides that a field is persistent. + +Unrestricted `__dict__`, public-property, constructor-parameter, or annotation +serialization is forbidden. Derived values, scene/item backreferences, +renderer/GPU handles, pick IDs, caches, selection, hover, tools, and command +history are not durable fields. `ModelObject.add_elements` and +`ElementObject.add_children` are construction commands, not state. Model render +caches are transient. Shape resolution and durable colors are serialized only +through explicit declarations. + +Deserialization validates the closed base state and known declarations without +passing a free-form mapping to adapter constructors. Unknown namespaced +extension values remain inactive and round-trip unchanged under ADR 008. + +## Consequences + +- Base transformations and subclass fields cannot disappear because a + subclass forgot `super().settings`. +- Persistence changes are visible in code review and independently testable. +- Runtime caches and constructor side effects are excluded by default. +- Subclasses must deliberately declare every durable field and migration. +- Editor tooling can reuse schema metadata without becoming the source of + truth for persistence. +- A small schema/version and migration mechanism is required for renamed or + removed fields; it remains data-focused rather than adapter-constructor + compatibility code. + +## Compatibility + +Legacy `settings` mappings are accepted only by the legacy scene loader and +mapped into declared base/extension fields. Unknown unnamespaced legacy keys +cannot be assigned safely and must be reported; they are not passed to +constructors. Once migrated, only the explicit schema is written. + +## Verification + +- Assert MRO composition preserves base transformation plus declared subclass + `u`, `v`, and face color. +- Assert duplicate field declarations, invalid values, missing required fields, + and unknown base fields fail with precise paths. +- Prove caches, Viewer handles, pick IDs, selection, and construction commands + are absent from serialized state. +- Prove unknown namespaced extension state round-trips byte-for-value without + importing or constructing its adapter. +- Use introspection-based validation tests to detect a declaration that names a + missing/incompatible attribute, without auto-serializing undeclared members. + +## Affected packages + +`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. + +## Dependencies + +- [ADR 008](008-scene-nodes-and-runtime-adapters.md) diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index 1ef655f..759b275 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -1,6 +1,8 @@ # Scene, Viewer, and Visualisation Decisions -All decisions are Accepted. The user approved ADRs 001–007 on 2026-11-07. +ADRs 001–007 are Accepted. New round-trip evidence requires two Proposed +amendments before implementation starts. ADRs 008–009 refine, but do not +silently rewrite, the accepted ownership boundary. | ADR | Decision | Status | Dependencies | |---|---|---|---| @@ -11,3 +13,12 @@ All decisions are Accepted. The user approved ADRs 001–007 on 2026-11-07. | 005 | [Annotations, measurements, and overlays](005-annotations-and-overlays.md) | Accepted | 001, 002, 003 | | 006 | [Public Viewer integration facade](006-viewer-integration-facade.md) | Accepted | 001, 003, 004, 005 | | 007 | [Initial scope and verification](007-scope-and-verification.md) | Accepted | 001–006; Plugin 005 | +| 008 | [Serializable scene nodes and runtime adapters](008-scene-nodes-and-runtime-adapters.md) | Proposed | 001; verified round-trip regressions | +| 009 | [Explicit scene-state serialization fields](009-scene-state-fields.md) | Proposed | 008 | + +Phase 1 is blocked until ADRs 008–009 are explicitly approved. ADR 008 refines +ADR 001's statement that core owns durable scene content: the durable object is +a scene-owned node/state record, not the context-specific runtime +`SceneObject` adapter. ADR 009 replaces the implicit `settings`/constructor +replay mechanism with an explicit schema. The remaining accepted decisions +retain their intent but must be implemented against the amended boundary. diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index d3b3c92..a6d3a93 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -4,11 +4,11 @@ Last updated: 2026-11-07 ## Resume here -Current phase: `implementation` +Current phase: `architecture` -Status: Cross-package reconnaissance and architecture are complete. The user -accepted ADRs 001–007 on 2026-11-07; implementation may begin in dependency -order within the approved initial scope. +Status: ADRs 001–007 are Accepted, but two verified scene round-trip +regressions require Proposed amendment ADRs 008–009. Phase 1 implementation is +paused pending explicit approval. Read next: @@ -20,7 +20,10 @@ Read next: ## Decisions and approvals - Accepted: [ADRs 001–007](decisions/README.md). -- Proposed or unresolved: none. +- Proposed or unresolved: + [ADR 008](decisions/008-scene-nodes-and-runtime-adapters.md) and + [ADR 009](decisions/009-scene-state-fields.md); both require approval before + package source changes. - Scope boundary: notebook and CAD hosts are compatibility consumers; `compas_session` requires an explicit inclusion decision. Do not modify package source outside the initial scope, merge, or publish without the @@ -46,16 +49,21 @@ Read next: - Identified initial and compatibility-only package boundaries. - Produced the architecture proposal, seven independent Proposed ADRs, and a dependency-ordered implementation plan. +- Verified that Viewer ShapeObject state and ModelViewer scene reconstruction + do not round-trip under the current constructor/settings mechanism. +- Proposed separate serializable node state, runtime adapter binding, durable + node GUIDs, and explicit serialization fields in ADRs 008–009. ## Next tasks -1. Review and approve or revise ADRs 001–007. -2. After approval, create package initiative branches from the recorded bases. -3. Begin Phase 1 compatibility review and indexed-buffer implementation. +1. Review and approve or revise ADRs 008–009. +2. After approval, refresh package branches and add the verified regressions as + tests. +3. Complete Phase 0 before indexed-buffer implementation begins. ## Blockers and approval gates -- Package source implementation is blocked on proposal and ADR approval. +- Package source implementation is blocked on ADRs 008–009. - Adding session, notebook, or host packages to implementation scope requires explicit approval. diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 09b9497..f775220 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,27 +2,50 @@ ## Status -Architecture approved. ADRs 001–007 are Accepted; implementation may proceed -in dependency order within the approved initial scope. +Architecture amendment required. ADRs 001–007 are Accepted, but verified +round-trip regressions block implementation. Proposed ADRs 008–009 must be +approved before Phase 1 or package source work begins. ## Dependency graph ```text -ADRs 001 and 002 - | \ - v v -ADR 003 --> ADR 004 - | | - v v -ADR 005 ADR 006 - \ / - v v - ADR 007 +ADR 001 --> ADR 008 --> ADR 009 + | + +--------> ADR 002 + +--------> ADR 003 --> ADR 004 + +ADRs 001–003 ----------> ADR 005 +ADRs 001, 003–005 -----> ADR 006 +ADRs 001–009 ----------> ADR 007 rollout gate ``` +## Phase 0 — Scene ownership and serialization amendment + +Governing ADRs: 001, 008, and 009. + +Status: blocked on approval of ADRs 008–009. + +1. Add the two verified round-trip regressions as failing tests without + changing package behavior. +2. Audit Scene, SceneObject, Group, Viewer adapters, model adapters, and + compatibility-only consumers against the proposed node/adapter split. +3. Implement the closed scene node/state schema, durable node GUIDs, separate + item store, and two-phase deserialize/bind lifecycle. +4. Implement explicit MRO-composed extension field declarations and the legacy + settings loader; preserve unknown namespaced extension state. +5. Migrate core, Viewer, and model adapters without serializing caches, + selection, construction commands, or runtime handles. + +Exit gate: both regressions pass; shared item identity and durable node identity +round-trip separately; scenes load without a visualization backend; model +adapters bind only after the complete hierarchy exists; local/package quality, +typing, docs, and artifact checks pass. + ## Phase 1 — Boundaries and indexed geometry -Governing ADRs: 001, 002, and 007. +Governing ADRs: 001, 002, 007, 008, and 009. + +Status: paused until Phase 0 and its approval gate are complete. 1. Audit compatibility-only consumers for affected core scene contracts and stop for approval if a required core change would break them. @@ -38,7 +61,7 @@ large-indexed-input evidence passes at exact candidate heads. ## Phase 2 — State, selection, and transforms -Governing ADRs: 001, 003, 004, and 007. +Governing ADRs: 001, 003, 004, 007, 008, and 009. 1. Separate persistent Viewer configuration from transient Viewer state. 2. Implement the object-selection model and migrate viewport, rectangle, tree, diff --git a/initiatives/scene-viewer-visualisation/inventory.md b/initiatives/scene-viewer-visualisation/inventory.md index e6a1a97..27a0367 100644 --- a/initiatives/scene-viewer-visualisation/inventory.md +++ b/initiatives/scene-viewer-visualisation/inventory.md @@ -129,6 +129,37 @@ Focused reconnaissance results: 10. Scope can expand rapidly across notebook and host adapters unless initial and compatibility-only packages are explicit. +## Scene state and serialization follow-up + +The current scene format is not ordinary `SceneObject` serialization. `Scene` +stores every domain item once by GUID and writes hierarchy nodes as an optional +item GUID, a free-form `settings` mapping, and children. Loading replays those +settings through `Scene.add`, which selects and constructs a runtime adapter +before the reconstructed hierarchy is complete. Multiple nodes can correctly +share one item, but node/adapter GUIDs are not preserved. + +Two regressions were reproduced at the audited heads: + +- a Viewer Box/ShapeObject translated by `[2, 0, 0]` reloads without its + transformation because `ViewerSceneObject.settings` replaces the base + mapping; `u=7`, `v=9`, and face color also reload as defaults; +- a `ModelViewer` scene fails to load because constructor replay uses + `ModelObject(add_elements=True)` before attachment, causing its child + creation to raise `RuntimeError: A detached scene object cannot own child + objects.` + +Unrestricted serialization introspection is unsafe. Concrete COMPAS objects +contain cycles, scene/item backreferences, GPU and picking identifiers, native +handles, lazy caches, derived NumPy buffers, and constructor commands. Public +properties can be computed or side-effecting, while persistent descriptor +values are often stored privately. Constructor signatures also lose inherited +state behind `**kwargs`. + +Introspection remains useful when applied to a closed declared schema: it can +validate readable fields, constructor compatibility, and editor metadata. It +cannot safely determine persistence from `__dict__`, public names, +annotations, properties, or constructor parameters alone. + ## Architecture questions 1. Does core own only scene hierarchy and transformations, or also neutral diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index ff44abd..74281c8 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -14,19 +14,52 @@ measurements, annotations, scale/legend overlays, and public dock/command composition. It should not attempt a universal renderer API, a generic reactive framework, sub-object editing, a shell, or host-application migration. +Implementation is paused. Verified scene round-trip regressions show that the +accepted ownership boundary requires the Proposed ADRs 008–009 before Phase 1 +can begin. + +## New evidence requiring amendment + +- A Viewer Box/ShapeObject local translation `[2, 0, 0]` reloads as + `transformation is None` because `ViewerSceneObject.settings` replaces core + settings. A headless ShapeObject with `u=7`, `v=9`, and a face color reloads + with resolution defaults `16`, `16`, and the default face color. +- A ModelViewer scene fails while loading. Runtime factory dispatch constructs + `ModelObject` with its default `add_elements=True`; it calls `self.add` + before attachment and raises `RuntimeError: A detached scene object cannot + own child objects.` The original controller deliberately used + `add_elements=False` and `add_children=False`. Render settings and caches are + absent too, but caches are transient and should stay out of scene files. +- Shared item identity survives through the item GUID store. Scene-object GUIDs + do not survive, so they cannot yet serve as the durable identity assumed by + ADR 001. + ## Recommended architecture -### Durable scene content +### Durable scene content and runtime adapters + +Core `Scene` remains the backend-neutral serializable hierarchy, but its +durable entries become scene-owned node/state value objects rather than runtime +`SceneObject` adapters. Nodes preserve their own GUID, optional item GUID, +local transformation, hierarchy, visibility, base appearance, and explicitly +declared extension state. The separate item store continues to preserve shared +item identity. + +Runtime `SceneObject` instances bind a complete node and item to a chosen +visualization context. They are not serialized identities and may be created +only after deserialization has rebuilt the full item store and hierarchy. +Their constructors do not populate hierarchy. Scene context is runtime binding +configuration; absence of a backend cannot prevent loading durable content. -Core `Scene` remains the serializable hierarchy. Core `SceneObject` continues -to own item references, local transformations, hierarchy, visibility, and -durable appearance. Core does not gain Qt signals, GPU buffers, picking IDs, -selection state, tool state, or viewer commands. +Durable node GUIDs are the stable boundary between scene content and Viewer +state. Renderer pick IDs remain short-lived Viewer mappings and are never +serialized. Unknown namespaced adapter state remains inactive but round-trips +without importing that adapter. -Scene-object GUIDs are the stable boundary between durable content and viewer -state. Viewer and domain controllers refer to scene objects by GUID and resolve -them through the scene when needed. Renderer-specific pick IDs remain short- -lived Viewer mappings and are never serialized. +Base node state uses a closed core schema. Additional durable fields use +explicit MRO-composed declarations. Introspection may validate declarations +and support editors, but `__dict__`, public properties, annotations, and +constructor parameters never define persistence automatically. ### Indexed render geometry @@ -206,8 +239,9 @@ design is proven. - `BufferGeometry` construction changes from expanded channel vertices to shared indexed vertices. Current examples and adapters migrate together. A deprecated parallel constructor is not proposed. -- Existing core scene serialization remains valid because Viewer transient - state is removed from scene-object settings rather than added to core. +- Existing core scene serialization is not sufficient for the approved + architecture. ADRs 008–009 define a legacy loader and a new explicit node + schema; implementation is blocked pending their approval. - Current `Tag` and `ArrowOverlay` data may require a documented migration to the accepted annotation/overlay types. Exact compatibility should be checked against serialized fixtures before implementation; do not silently reinterpret @@ -235,6 +269,10 @@ compatibility-reviewed but not implementation targets in the initial wave. - Preserve scene serialization, shared-item identity, hierarchy, and local/ world transformation tests. +- Add the verified Viewer transformation/ShapeObject settings regression and + ModelViewer detached-child failure before changing implementation. +- Preserve durable node GUIDs separately from shared item GUIDs and round-trip + unknown namespaced extension state without its runtime adapter. - Add regression coverage proving transient Viewer state is absent from core scene data and serialization. - Correct and test the core scene/visualisation guide against current APIs. @@ -276,23 +314,21 @@ Examples remain direct scripts and demonstrate, in order: ## Dependency order ```text -ADRs 001 and 002 - | \ - v v -ADR 003 --> ADR 004 - | | - v v -ADR 005 ADR 006 - \ / - v v - ADR 007 +ADR 001 --> ADR 008 --> ADR 009 + | + +--------> ADR 002 + +--------> ADR 003 --> ADR 004 + +ADRs 001–003 ----------> ADR 005 +ADRs 001, 003–005 -----> ADR 006 +ADRs 001–009 ----------> ADR 007 rollout gate ``` Core geometry, typing, plugin, and repository-modernisation decisions remain upstream constraints. Implementation starts only after all ADRs required for a wave are Accepted. -## Decisions requiring approval +## Decision record 1. [ADR 001 — Ownership and state boundaries](decisions/001-ownership-boundaries.md) 2. [ADR 002 — Indexed Viewer buffer geometry](decisions/002-indexed-buffer-geometry.md) @@ -301,6 +337,8 @@ wave are Accepted. 5. [ADR 005 — Annotations, measurements, and overlays](decisions/005-annotations-and-overlays.md) 6. [ADR 006 — Public Viewer integration facade](decisions/006-viewer-integration-facade.md) 7. [ADR 007 — Initial scope and verification](decisions/007-scope-and-verification.md) +8. [ADR 008 — Serializable scene nodes and runtime adapters](decisions/008-scene-nodes-and-runtime-adapters.md) +9. [ADR 009 — Explicit scene-state serialization fields](decisions/009-scene-state-fields.md) -No package source changes should begin before the governing decisions are -explicitly approved. +ADRs 001–007 are Accepted. No package source changes should begin until the +Proposed amendment ADRs 008–009 are explicitly approved. From 79f4081f20552300aae5418d041a0de7b5ab1c8c Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 16:24:05 +0100 Subject: [PATCH 04/22] Decouple scene architecture from ModelViewer draft --- .../scene-viewer-visualisation/README.md | 13 +++-- .../decisions/001-ownership-boundaries.md | 9 ++- .../decisions/002-indexed-buffer-geometry.md | 5 +- .../003-viewer-state-and-selection.md | 22 +++++--- .../decisions/004-transform-refresh-undo.md | 4 +- .../006-viewer-integration-facade.md | 41 +++++++++----- .../decisions/007-scope-and-verification.md | 23 ++++++-- .../008-scene-nodes-and-runtime-adapters.md | 18 ++++-- .../decisions/009-scene-state-fields.md | 4 +- .../scene-viewer-visualisation/handoff.md | 21 ++++--- .../implementation-plan.md | 56 ++++++++++--------- .../scene-viewer-visualisation/inventory.md | 26 +++++---- .../scene-viewer-visualisation/objective.md | 25 +++++---- .../scene-viewer-visualisation/proposal.md | 55 +++++++++--------- 14 files changed, 194 insertions(+), 128 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/README.md b/initiatives/scene-viewer-visualisation/README.md index 95d999c..020b1c8 100644 --- a/initiatives/scene-viewer-visualisation/README.md +++ b/initiatives/scene-viewer-visualisation/README.md @@ -1,7 +1,7 @@ # Scene, Viewer, and Visualisation -This initiative aligns backend-neutral scene infrastructure, viewer rendering -and interaction, and model-to-scene integration across the COMPAS framework. +This initiative aligns backend-neutral scene infrastructure with Viewer +rendering, interaction, state, and UI composition. Current phase: **architecture amendment proposed; implementation paused**. @@ -16,7 +16,8 @@ ADRs 001–007 are Accepted. Verified round-trip failures exposed an unresolved scene-node/runtime-adapter and serialization boundary. Proposed ADRs 008–009 must be approved before Phase 1 begins. -The approved initial package scope is `compas`, `compas_viewer`, -`compas_model`, and `compas_framework`. Session persistence, notebook -visualisation, and CAD-host adapters are compatibility-review consumers until -an approved decision admits them to implementation scope. +The refined initial package scope is `compas`, `compas_viewer`, and +`compas_framework`. The current `compas_model.ModelViewer` is draft evidence +and a later redesign consumer, not a behavior contract. Session persistence, +notebook visualisation, and CAD-host adapters are compatibility-review +consumers until an approved decision admits them to implementation scope. diff --git a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md index 6c607f9..b23eb13 100644 --- a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md +++ b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md @@ -62,7 +62,9 @@ data and requires fixture inspection and migration documentation. ## Affected packages -`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. +Initial implementation: `compas`, `compas_viewer`, and `compas_framework`. + +Later redesign/regression consumer: `compas_model`. ## Dependencies @@ -78,3 +80,8 @@ and serialization clauses is blocked by Proposed [ADR 008](008-scene-nodes-and-runtime-adapters.md) and [ADR 009](009-scene-state-fields.md). This note does not change ADR 001's Accepted status or approve either amendment. + +The generic principle that domain packages retain their own data authority +does not preserve the current draft `ModelViewer` controller, projections, +selection behavior, or cache shape. Explicit user correction moves that draft +to a later redesign phase. diff --git a/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md b/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md index febaf00..cf552f3 100644 --- a/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md +++ b/initiatives/scene-viewer-visualisation/decisions/002-indexed-buffer-geometry.md @@ -64,7 +64,10 @@ parallel deprecated constructor is proposed. ## Affected packages -`compas_viewer`, `compas_model`, and `compas_framework`. +Initial implementation: `compas_viewer` and `compas_framework`. + +Later redesign consumer: `compas_model`; its current render-cache shape is not +preserved by this decision. ## Dependencies diff --git a/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md b/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md index 4dc6b91..de0febb 100644 --- a/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md +++ b/initiatives/scene-viewer-visualisation/decisions/003-viewer-state-and-selection.md @@ -7,7 +7,7 @@ Accepted. ## Context Selection currently lives in mutable `ViewerSceneObject.is_selected` flags. -Viewport commands, tree widgets, shaders, and domain controllers mutate or +Viewport commands, tree widgets, shaders, and programmatic consumers mutate or poll those flags and then trigger imperative refreshes. `ViewerState` observes persistent configuration but not selection or tool state. @@ -26,7 +26,7 @@ Choose option 1. `Viewer.state.selection` stores ordered scene-object GUIDs and provides replace, add, remove, toggle, clear, membership, and ordered-resolution operations. It emits one batched change notification per operation. Viewport, -rectangle selection, scene tree, commands, shaders, and domain controllers use +rectangle selection, scene tree, commands, shaders, and programmatic consumers use this model exclusively. Keep `Viewer.config` for persistent preferences. Keep hover, active tool, @@ -40,7 +40,7 @@ requires it. ## Consequences -- Tree, viewport, code, renderer, and model integration observe one mutation +- Tree, viewport, code, and renderer observe one mutation path. - Selection no longer participates in scene serialization. - Batch changes avoid repeated renderer/UI updates. @@ -49,9 +49,8 @@ requires it. ## Compatibility -Remove Viewer `is_selected` constructor/settings behavior. Replace public model -selection implementations with the shared model while preserving their -user-facing selected-element results. +Remove Viewer `is_selected` constructor/settings behavior. Later integrations +may consume the selection model but do not define its contract. ## Verification @@ -59,12 +58,19 @@ user-facing selected-element results. programmatic paths. - Assert one notification and one render/UI synchronization per batch. - Verify stable ordering, removed-object cleanup, and serialization exclusion. -- Preserve model-order selection results where `compas_model` promises them. ## Affected packages -`compas_viewer`, `compas_model`, and `compas_framework`. +`compas_viewer` and `compas_framework`. `compas_model` is a later redesign +consumer. ## Dependencies - [ADR 001](001-ownership-boundaries.md) + +## Refinement after acceptance + +The current `compas_model.ModelViewer` is a draft and does not promise a +model-order selection contract that this ADR must preserve. The accepted +decision remains one Viewer-owned selection model; model-specific preservation +language has been removed by explicit user correction. diff --git a/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md b/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md index 2981127..fa49950 100644 --- a/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md +++ b/initiatives/scene-viewer-visualisation/decisions/004-transform-refresh-undo.md @@ -66,7 +66,9 @@ they produce a reversible transaction. ## Affected packages -`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. +Initial implementation: `compas`, `compas_viewer`, and `compas_framework`. + +Later redesign consumer: `compas_model`. ## Dependencies diff --git a/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md b/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md index 480625d..597fd63 100644 --- a/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md +++ b/initiatives/scene-viewer-visualisation/decisions/006-viewer-integration-facade.md @@ -6,7 +6,7 @@ Accepted. ## Context -`compas_model.ModelViewer` currently reaches into concrete renderer and sidebar +Viewer-owned commands and components reach into concrete renderer and widget objects. Viewer has command and menu composition but no equally clear public dock or synchronization boundary. Optional consoles or assistants should not force shell, network, or credential behavior into the Viewer core. @@ -17,7 +17,7 @@ force shell, network, or credential behavior into the Viewer core. commands, docks, annotations, and overlays. 2. Let integrations continue using renderer and widget internals. 3. Define a large abstract Viewer/controller framework for every domain. -4. Move model navigation and inspectors into `compas_viewer`. +4. Design the facade around the current draft `ModelViewer` controller. ## Recommendation @@ -31,10 +31,10 @@ Choose option 1. Provide public operations for: - dock addition/removal; and - annotation and overlay addition/removal. -`compas_model` retains its authoritative tree, projections, inspectors, -contacts, quality settings, and render cache. It consumes the facade and stops -accessing private/concrete Viewer renderer and sidebar paths. Do not create a -generic controller base class. +The facade is defined only by approved Viewer-owned tools, commands, state, +annotations, overlays, refresh, and UI composition. Do not create a generic +controller base class or add operations solely to match a current external +consumer. A future console, terminal, or assistant may use a dock and registered command API. Arbitrary Python/shell execution, subprocesses, credentials, network @@ -43,29 +43,33 @@ implemented in this wave. ## Consequences -- Domain packages gain a stable, testable integration surface. +- Viewer-owned components gain a stable, testable integration surface that + later consumers may reuse. - Viewer internals can change without coordinated domain rewrites. -- Public API growth is limited to demonstrated model and feature needs. +- Public API growth is limited to demonstrated Viewer feature needs. - Dock content remains Viewer/Qt-specific; core stays UI-independent. - Console/chat presentation becomes possible without prematurely authorizing execution or remote services. ## Compatibility -Preserve `ModelViewer` user-facing hierarchy, selection, visibility, quality, -cache, and inspection behavior. Internal direct renderer/sidebar access is -removed after facade coverage exists. +The current draft `ModelViewer` has no compatibility requirements under this +ADR. Its later redesign may consume the proven facade but may not enlarge it +without a demonstrated requirement and approval. ## Verification - Test facade behavior with a lightweight fake UI/renderer boundary. -- Forbid private renderer/sidebar access in model integration tests. +- Forbid private renderer/widget access in Viewer-owned command, tool, and + component tests. - Verify dock and command registration/removal and duplicate-ID failures. -- Verify plugin discovery imports no Qt/OpenGL/model implementation modules. +- Verify plugin discovery imports no Qt/OpenGL or optional-consumer + implementation modules. ## Affected packages -`compas_viewer`, `compas_model`, and `compas_framework`. +`compas_viewer` and `compas_framework`. `compas_model` is a later redesign +consumer. ## Dependencies @@ -73,3 +77,12 @@ removed after facade coverage exists. - [ADR 003](003-viewer-state-and-selection.md) - [ADR 004](004-transform-refresh-undo.md) - [ADR 005](005-annotations-and-overlays.md) + +## Refinement after acceptance + +The original context and compatibility clauses relied too heavily on the +current `compas_model.ModelViewer`. Explicit user correction establishes that +controller as a draft that may be redesigned freely. The accepted decision is +therefore narrowed to a small Viewer-owned public boundary justified by +Viewer's own approved capabilities; no ModelViewer behavior or controller +shape is preserved. diff --git a/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md b/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md index 9447371..97ea306 100644 --- a/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md +++ b/initiatives/scene-viewer-visualisation/decisions/007-scope-and-verification.md @@ -13,18 +13,18 @@ tests alone do not prove installed cross-package behavior. ## Options -1. Implement an initial core/Viewer/model/framework wave and compatibility- +1. Implement an initial core/Viewer/framework wave and compatibility- review adjacent consumers. 2. Migrate every visualisation and host package in one wave. -3. Change Viewer only and defer core/model alignment. +3. Change Viewer only and defer core scene alignment. 4. Accept package-local source tests as completion evidence. ## Recommendation Choose option 1. -Initial implementation packages are `compas`, `compas_viewer`, -`compas_model`, and `compas_framework`. Review `compas_session`, +Initial implementation packages are `compas`, `compas_viewer`, and +`compas_framework`. Review `compas_model`, `compas_session`, `compas_notebook`, Rhino, Grasshopper, and Blender for compatibility with core changes, but do not modify them without a scope amendment and approval. @@ -33,7 +33,7 @@ Require: - focused and full applicable local tests, Ruff, Pyright, and strict docs; - clean package CI and built-wheel checks at exact heads; - framework CI installing exact candidates and exercising plugin discovery, - scene/model construction, indexed buffers, selection, transformations, + scene and Viewer construction, indexed buffers, selection, transformations, annotations, serialization, and graphics-free discovery; and - candidate-artifact CI for claims about independently built distributable compatibility. @@ -67,7 +67,9 @@ scope/compatibility approval before implementation proceeds. ## Affected packages -Initial: `compas`, `compas_viewer`, `compas_model`, and `compas_framework`. +Initial: `compas`, `compas_viewer`, and `compas_framework`. + +Later redesign consumer and regression evidence: `compas_model`. Compatibility review only: `compas_session`, `compas_notebook`, Rhino, Grasshopper, and Blender scene adapters. @@ -76,3 +78,12 @@ Grasshopper, and Blender scene adapters. - [ADRs 001–006](README.md) - Plugin-implementations ADR 005 + +## Refinement after acceptance + +The initial package list previously included `compas_model` as though the +current `ModelViewer` behavior constrained this initiative. Explicit user +correction moves it to a later redesign phase. Its current serialization +failure remains valid evidence for core scene reconstruction, but its +hierarchy projections, selection behavior, cache, controller shape, and facade +usage are not initial-wave completion criteria. diff --git a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md index 5005d55..0931751 100644 --- a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md +++ b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md @@ -75,8 +75,10 @@ Deserialize in two phases: `SceneObject` becomes the runtime adapter bound to a scene, node, and optional item. Its constructor must not populate hierarchy or own serialized state. -Domain projection such as `ModelViewer` creates nodes explicitly through a -controller; adapter binding never recreates children. +Application/domain projection creates nodes explicitly through an owning +controller; adapter binding never recreates children. The current draft +`ModelViewer` is evidence of why constructor-driven hierarchy creation fails, +not a controller contract to preserve. Scene context is runtime binding configuration, not authoritative serialized content. A scene may record a non-binding context hint for user experience, @@ -131,11 +133,13 @@ as durable must migrate. Exact compatibility is part of the Phase 1 audit. ## Verification -- Reproduce both verified regressions as tests before implementation. +- Reproduce the Viewer regression as a focused test and retain the draft + ModelViewer failure as evidence. - Round-trip local transformations, `u=7`, `v=9`, face color, shared items, node GUIDs, groups, and hierarchy without a visualization backend installed. -- Load the model scene without calling adapter hierarchy constructors, then - bind Viewer adapters after the hierarchy is complete. +- Use a minimal test adapter with constructor-side-effect behavior to prove + hierarchy deserialization never invokes runtime construction; redesign and + test the actual ModelViewer later. - Load and re-save unknown extension state without loss or constructor use. - Verify missing/unknown context permits load but produces a precise binding or draw error. @@ -144,7 +148,9 @@ as durable must migrate. Exact compatibility is part of the Phase 1 audit. ## Affected packages -`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. +Initial implementation: `compas`, `compas_viewer`, and `compas_framework`. + +Later redesign/regression consumer: `compas_model`. Compatibility review only: `compas_session`, `compas_notebook`, and CAD-host scene adapters. diff --git a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md index 4c33f5b..d1d4e9e 100644 --- a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md +++ b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md @@ -94,7 +94,9 @@ constructors. Once migrated, only the explicit schema is written. ## Affected packages -`compas`, `compas_viewer`, `compas_model`, and `compas_framework`. +Initial implementation: `compas`, `compas_viewer`, and `compas_framework`. + +Later redesign/regression consumer: `compas_model`. ## Dependencies diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index a6d3a93..2112490 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -24,10 +24,10 @@ Read next: [ADR 008](decisions/008-scene-nodes-and-runtime-adapters.md) and [ADR 009](decisions/009-scene-state-fields.md); both require approval before package source changes. -- Scope boundary: notebook and CAD hosts are compatibility consumers; - `compas_session` requires an explicit inclusion decision. Do not modify - package source outside the initial scope, merge, or publish without the - corresponding approval. +- Scope boundary: `compas_model`, notebook, and CAD hosts are later or + compatibility consumers; `compas_session` requires an explicit inclusion + decision. Do not modify package source outside the initial scope, merge, or + publish without the corresponding approval. ## Working state @@ -53,19 +53,22 @@ Read next: do not round-trip under the current constructor/settings mechanism. - Proposed separate serializable node state, runtime adapter binding, durable node GUIDs, and explicit serialization fields in ADRs 008–009. +- Recorded that the current `compas_model.ModelViewer` is a draft and only + regression/coupling evidence, not a public contract to preserve. ## Next tasks 1. Review and approve or revise ADRs 008–009. -2. After approval, refresh package branches and add the verified regressions as - tests. -3. Complete Phase 0 before indexed-buffer implementation begins. +2. After approval, refresh core/Viewer branches, add the Viewer regression, and + cover the draft ModelViewer failure mode with a minimal core adapter test. +3. Complete Phase 0 before indexed-buffer implementation begins; defer + `compas_model` controller redesign to a later approved phase. ## Blockers and approval gates - Package source implementation is blocked on ADRs 008–009. -- Adding session, notebook, or host packages to implementation scope requires - explicit approval. +- Adding model, session, notebook, or host packages to initial implementation + scope requires explicit approval. ## Verification diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index f775220..05a2bb8 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -25,21 +25,24 @@ Governing ADRs: 001, 008, and 009. Status: blocked on approval of ADRs 008–009. -1. Add the two verified round-trip regressions as failing tests without - changing package behavior. -2. Audit Scene, SceneObject, Group, Viewer adapters, model adapters, and - compatibility-only consumers against the proposed node/adapter split. +1. Add the verified Viewer round-trip regression and a minimal core adapter + test covering the constructor-before-attachment failure. Keep the actual + draft ModelViewer failure as evidence for its later redesign. +2. Audit Scene, SceneObject, Group, Viewer adapters, the draft model adapters, + and compatibility-only consumers against the proposed node/adapter split. 3. Implement the closed scene node/state schema, durable node GUIDs, separate item store, and two-phase deserialize/bind lifecycle. 4. Implement explicit MRO-composed extension field declarations and the legacy settings loader; preserve unknown namespaced extension state. -5. Migrate core, Viewer, and model adapters without serializing caches, - selection, construction commands, or runtime handles. +5. Migrate core and Viewer adapters without serializing caches, selection, + construction commands, or runtime handles. Use the draft ModelViewer failure + as external regression evidence, not as behavior to preserve. -Exit gate: both regressions pass; shared item identity and durable node identity -round-trip separately; scenes load without a visualization backend; model -adapters bind only after the complete hierarchy exists; local/package quality, -typing, docs, and artifact checks pass. +Exit gate: the Viewer and minimal-adapter regressions pass; shared item +identity and durable node identity round-trip separately; scenes load without +a visualization backend; runtime adapters bind only after the complete +hierarchy exists; local/package quality, typing, docs, and artifact checks +pass. ## Phase 1 — Boundaries and indexed geometry @@ -51,9 +54,7 @@ Status: paused until Phase 0 and its approval gate are complete. stop for approval if a required core change would break them. 2. Implement indexed `BufferGeometry` and convenience constructors in Viewer. 3. Migrate Viewer adapters and buffer assembly without expanding indexed data. -4. Pass model render arrays to Viewer without intermediate Python-list - expansion while retaining model-owned quality and cache policy. -5. Add performance-regression assertions based on buffer/object counts rather +4. Add performance-regression assertions based on buffer/object counts rather than unstable wall-clock thresholds. Exit gate: package-local source, typing, artifact, rendering-semantic, and @@ -65,7 +66,7 @@ Governing ADRs: 001, 003, 004, 007, 008, and 009. 1. Separate persistent Viewer configuration from transient Viewer state. 2. Implement the object-selection model and migrate viewport, rectangle, tree, - commands, renderer settings, and model integration. + commands, renderer settings, and programmatic Viewer APIs. 3. Remove `is_selected` as a second authority and update serialization/tests. 4. Add atomic multi-object transform transactions, categorized refresh, and the reversible transaction stack. @@ -90,29 +91,34 @@ Governing ADRs: 001–005 and 007. Exit gate: durable annotation round trips, transient overlays do not serialize, and visual behavior passes offscreen and package artifact tests. -## Phase 4 — Public integration facade and model alignment +## Phase 4 — Public Viewer operations Governing ADRs: 001, 003–007. 1. Add public refresh, history, command/menu, dock, annotation, and overlay - operations required by the approved features and model integration. -2. Migrate `ModelViewer` from direct renderer/sidebar access while preserving - its hierarchy, projections, selection results, contacts, inspectors, units, - quality, and cache behavior. -3. Add direct script examples for indexed buffers, selection, transforms, + operations required by approved Viewer-owned features. +2. Add direct script examples for indexed buffers, selection, transforms, measurements, overlays, and one custom dock. -4. Update core, Viewer, and model documentation using repository skills and +3. Update core and Viewer documentation using repository skills and current MkDocs-compatible NumPy style. -Exit gate: model integration uses only public Viewer APIs and package-local -tests/docs/artifacts pass. +Exit gate: Viewer-owned tools and components use public Viewer operations and +package-local tests/docs/artifacts pass. + +## Later phase — compas_model redesign + +The current `ModelViewer` is a draft and is not migrated as a compatibility +exercise. A later approved design may replace its controller, hierarchy +projections, selection, caching, and UI composition. It should consume proven +core Scene and Viewer contracts where they fit, and propose additions only for +new demonstrated requirements. ## Phase 5 — Framework integration and review Governing ADR: 007. -1. Extend the existing coordinated model/viewer plugin lifecycle gate rather - than duplicating it. +1. Verify installed core Scene and Viewer behavior at exact candidates; keep + the separate plugin initiative's model/viewer lifecycle gate independent. 2. Install exact candidate revisions and exercise the approved cross-package runtime and typing contracts. 3. Run package and framework CI, candidate-artifact verification where diff --git a/initiatives/scene-viewer-visualisation/inventory.md b/initiatives/scene-viewer-visualisation/inventory.md index 27a0367..358c566 100644 --- a/initiatives/scene-viewer-visualisation/inventory.md +++ b/initiatives/scene-viewer-visualisation/inventory.md @@ -66,25 +66,26 @@ execution live elsewhere. Commands and UI definitions offer useful extension points, but there is no comparable public dock composition API and no console, terminal, assistant, or safe execution boundary. -## Model integration +## Draft model integration evidence `compas_model` owns backend-neutral model scene adapters, Viewer-specific adapters, a `ModelViewer` controller, NumPy-based `RenderGeometry`, quality settings, a revision-aware CPU cache, hierarchy projections, selection, inspectors, and contact layers. -The authoritative `Model.tree` and rendered `Scene` hierarchy intentionally +The draft treats `Model.tree` and rendered `Scene` hierarchy as separate. remain separate. `ModelViewer` constructs and indexes the scene projection, but reaches into concrete viewer sidebar and renderer APIs. Structural changes are reconciled through explicit rebuilds rather than an observed projection contract. -Model render geometry preserves separate indexed filled triangles and visible +Draft model render geometry preserves separate indexed filled triangles and visible line segments, but Viewer-specific adapters expand some arrays back to Python lists. This makes buffer ownership and reusable conversion responsibilities -unclear. Package tests and documentation cover the current controller well, +unclear. Package tests and documentation describe the current controller, including multi-selection, visibility, caching, contacts, and offscreen viewer -integration. +integration. They establish implementation evidence, not public behavior that +this initiative must preserve. ## Adjacent packages @@ -96,7 +97,8 @@ implementation migration would broaden the initial initiative materially. ## Framework evidence -Package-local core, viewer, and model tests provide substantial evidence. The +Package-local core and Viewer tests provide substantial evidence. Draft model +tests provide additional coupling and regression evidence. The framework repository currently has no installed cross-package scene/viewer test. The plugin initiative separately requires a coordinated installed model/viewer registry and lifecycle test; this initiative should coordinate @@ -107,8 +109,9 @@ Focused reconnaissance results: - Core scene/plugin/glTF suite: 53 passed; one non-authoritative cache-write warning because the checkout cache directory was not writable. - Viewer selection/state/tessellation/tag/overlay suite: 35 passed offscreen. -- Model integration behavior was inspected from its existing tests and build - workflow; no new model tests were run during this inventory. +- Draft model integration behavior was inspected from its existing tests and + build workflow; no new model tests were run and those tests are not treated + as preservation requirements. ## Principal gaps and risks @@ -120,7 +123,8 @@ Focused reconnaissance results: distributed imperative paths. 4. Raw indexed buffers lack a uniform public input and batching contract. 5. Overlay rendering is coupled to concrete Viewer classes. -6. Model controllers depend on private or concrete viewer structure. +6. The draft model controller demonstrates coupling to private or concrete + Viewer structure, but its shape is not an architectural constraint. 7. Core appearance serialization and glTF export do not cover all visual settings consistently. 8. Per-object pickability conflicts with batching for large auxiliary data. @@ -170,8 +174,8 @@ annotations, properties, or constructor parameters alone. 4. What change categories allow transform-only, style-only, geometry, and hierarchy updates to remain efficient? 5. Which annotation and overlay objects are durable, transient, or both? -6. How should domain controllers depend on public viewer capabilities rather - than widget and renderer internals? +6. Which Viewer capabilities should be public because Viewer-owned tools and + components require them, independently of a draft domain controller? 7. What is the smallest safe extension boundary for docks, consoles, and optional assistant integrations? 8. Which scene appearance semantics must serialization and glTF preserve? diff --git a/initiatives/scene-viewer-visualisation/objective.md b/initiatives/scene-viewer-visualisation/objective.md index 51be96e..a06f881 100644 --- a/initiatives/scene-viewer-visualisation/objective.md +++ b/initiatives/scene-viewer-visualisation/objective.md @@ -3,8 +3,7 @@ ## Objective Establish a simple, coherent, and scalable visualisation architecture across -COMPAS core scenes, `compas_viewer`, and domain integrations such as -`compas_model`. Users should be able to visualise large indexed datasets, +COMPAS core scenes and `compas_viewer`. Users should be able to visualise large indexed datasets, select and transform objects consistently, add measurements and annotations, and extend the viewer UI without coupling durable scene data to a particular renderer or Qt widget hierarchy. @@ -30,8 +29,8 @@ home and contract. tool, and UI state? 7. Which stable extension boundary can support docks, consoles, terminals, or optional assistants without embedding those concerns in core scene data? -8. How should `compas_model` and future domain packages project authoritative - domain hierarchies into scenes without depending on private viewer widgets? +8. Which public Viewer operations are required by its own tools, UI components, + and independent future consumers? 9. Which local, package, framework-integration, and artifact evidence is required for each approved wave? @@ -53,25 +52,24 @@ home and contract. - Make high-level convenience APIs simple while keeping ownership and performance costs visible. -## Proposed initial scope +## Refined initial scope - `compas`: scene hierarchy, scene-object identity and transformations, and any approved backend-neutral contracts. - `compas_viewer`: render buffers, GPU lifecycle, viewport interaction, selection, overlays, commands, and UI state. -- `compas_model`: domain-tree projection and public viewer integration. - `compas_framework`: installed cross-package verification. ## Deliverables 1. A verified cross-package inventory and approved architecture decisions. -2. Clear ownership and state boundaries across core, viewer, and domain - integrations. +2. Clear ownership and state boundaries across core scene and Viewer runtime + concerns. 3. Efficient convenience APIs for indexed points, edges, and triangles. 4. Consistent observable selection and transformation contracts. 5. An extensible annotation, measurement, and overlay foundation. -6. Public integration boundaries for domain controllers and optional UI - extensions. +6. Public integration boundaries for Viewer tools, components, and optional + UI extensions. 7. Package-local and framework-level tests, examples, and documentation. ## Non-goals without a later scope decision @@ -84,6 +82,8 @@ home and contract. wave. - Turning `compas_session` into a general reactive application store without a separate persistence decision. +- Preserving the current draft `compas_model.ModelViewer` controller shape or + behavior. It is a later redesign consumer, not an architectural constraint. - Adding modeling functionality to the viewer or duplicating domain data structures in the scene graph. @@ -100,5 +100,6 @@ home and contract. ## Current status -Reconnaissance and architecture are complete. ADRs 001–007 are Accepted and -implementation is authorized for the approved initial scope. +Reconnaissance is complete. ADRs 001–007 are Accepted, but Proposed amendment +ADRs 008–009 block implementation pending approval. The current draft +`ModelViewer` is evidence and a later redesign target, not a contract. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index 74281c8..34c51db 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -5,8 +5,8 @@ Keep `compas.scene` responsible for durable, backend-neutral scene content and hierarchy. Put indexed render buffers, picking, selection, transient state, tools, overlays, GPU synchronization, and UI composition in `compas_viewer`. -Let domain packages such as `compas_model` project their authoritative data -through a small public Viewer facade rather than renderer or widget internals. +Expose only the public operations required by Viewer-owned tools and UI +components. Future integrations may consume that boundary after it is proven. The first implementation wave should establish these boundaries and deliver object selection, efficient indexed geometry, multi-object transforms, @@ -91,9 +91,7 @@ primitive. Styling stays on the scene object; a separate color-buffer decision is required only when current uniform/per-item styling proves insufficient. Existing Viewer adapters should return indexed channels to the buffer manager -instead of expanding geometry. `compas_model.RenderGeometry` should either use -this contract directly or remain a domain cache whose arrays pass to it without -list expansion. Geometry producers continue to use their approved +instead of expanding geometry. Geometry producers continue to use their approved `to_tessellation` and `to_polygonal_surface` APIs; this Viewer contract does not become a geometry-algorithm input. @@ -110,7 +108,8 @@ Separate three state classes: `Viewer.state.selection` is the one object-selection model. It stores ordered scene-object GUIDs and exposes replace, add, remove, toggle, clear, and query operations plus one change notification. Viewport picking, rectangle -selection, the scene tree, commands, and `compas_model` all mutate this model. +selection, the scene tree, commands, and programmatic consumers all mutate +this model. The current mutable and serialized `ViewerSceneObject.is_selected` path is removed rather than retained as a second authority. @@ -171,10 +170,10 @@ The measurement tool owns temporary pointer/preview state in `Viewer.state`. Completing a measurement creates a durable distance-dimension scene item; cancelling it leaves no scene mutation. -### Public Viewer facade +### Public Viewer operations -Expose the small set of operations domain integrations need without giving -them renderer or widget internals: +Expose the small set of operations that Viewer-owned commands, tools, and UI +components need without coupling them to renderer or widget internals: - `viewer.scene` for durable content; - `viewer.state.selection` for selection; @@ -185,11 +184,10 @@ them renderer or widget internals: - public dock addition/removal using Viewer component/widget content; and - public annotation and overlay addition. -`compas_model.ModelViewer` keeps `Model.tree` authoritative, retains its -domain-specific render cache and projections, and migrates from direct -`viewer.renderer` and `viewer.ui.sidebar` access to this facade. The initiative -does not create a generic model-controller base class or duplicate the model -tree in application state. +These operations are justified and tested inside Viewer. They are not designed +around the current draft `compas_model.ModelViewer`. That controller may be +redesigned freely in a later consumer phase, at which point it can use the +small proven Viewer boundary or motivate a separately approved addition. A console, terminal, or assistant can later occupy a public dock and invoke registered commands, but arbitrary code execution, shell access, credentials, @@ -234,8 +232,8 @@ design is proven. ## Compatibility implications - Removing `ViewerSceneObject.is_selected` is a deliberate Viewer API break. - Commands, tree widgets, shaders, tests, and model integrations migrate in one - coordinated change; no writable compatibility alias remains. + Commands, tree widgets, shaders, and tests migrate in one coordinated change; + no writable compatibility alias remains. - `BufferGeometry` construction changes from expanded channel vertices to shared indexed vertices. Current examples and adapters migrate together. A deprecated parallel constructor is not proposed. @@ -246,8 +244,10 @@ design is proven. the accepted annotation/overlay types. Exact compatibility should be checked against serialized fixtures before implementation; do not silently reinterpret ambiguous old data. -- `compas_model` keeps its public domain behavior, hierarchy, quality policy, - and cache semantics while changing only its Viewer integration boundary. +- The current draft `compas_model.ModelViewer` behavior, hierarchy projections, + selection behavior, controller shape, and cache arrangement are not + compatibility requirements. Its failure remains evidence for the scene + reconstruction problem, and its redesign is deferred. - Viewer plugin discovery remains graphics-free and function-local under the accepted plugin ADRs. @@ -257,7 +257,7 @@ design is proven. |---|---| | `compas` | Preserve scene identity, hierarchy, transformations, durable appearance, and serialization; clarify stale documentation. | | `compas_viewer` | Implement indexed buffers, state/selection, transforms/history, annotations, overlays, facade, rendering, and UI. | -| `compas_model` | Consume indexed geometry and the public Viewer facade while preserving the authoritative model tree and cache. | +| `compas_model` | Later redesign consumer and regression evidence; no current draft controller behavior is preserved by this wave. | | `compas_framework` | Pin exact candidates and verify installed cross-package scene, plugin, selection, transform, and buffer behavior. | `compas_session`, `compas_notebook`, Rhino, Grasshopper, and Blender are @@ -269,8 +269,10 @@ compatibility-reviewed but not implementation targets in the initial wave. - Preserve scene serialization, shared-item identity, hierarchy, and local/ world transformation tests. -- Add the verified Viewer transformation/ShapeObject settings regression and - ModelViewer detached-child failure before changing implementation. +- Add the verified Viewer transformation/ShapeObject settings regression. + Preserve the ModelViewer detached-child failure as evidence and cover its + core failure mode with a minimal adapter whose constructor must not run + during hierarchy deserialization; the draft controller itself is deferred. - Preserve durable node GUIDs separately from shared item GUIDs and round-trip unknown namespaced extension state without its runtime adapter. - Add regression coverage proving transient Viewer state is absent from core @@ -293,13 +295,12 @@ compatibility-reviewed but not implementation targets in the initial wave. - Test public dock/command composition without importing optional integrations during plugin discovery. -### Model and framework +### Framework and later consumers -- Preserve model hierarchy, selection, visibility, cache invalidation, and - render-quality tests while forbidding private renderer/sidebar access. -- Add an installed exact-candidate test that discovers Viewer/model plugins, - builds a model scene, selects multiple elements, updates one indexed geometry - buffer, transforms objects, and round-trips durable scene content. +- Use the current draft ModelViewer load failure as regression evidence for + two-phase scene reconstruction, not as a public behavior suite. +- Add an installed exact-candidate test for core Scene and Viewer contracts. +- Redesign and verify model integration only in a later approved consumer phase. - Keep candidate-artifact evidence separate from source-build integration. Examples remain direct scripts and demonstrate, in order: From 1e25f10ea94ffde5ac4de02129f6cb2961a3acd8 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 16:27:14 +0100 Subject: [PATCH 05/22] Drop legacy scene loader proposal --- .../decisions/001-ownership-boundaries.md | 6 +++--- .../decisions/008-scene-nodes-and-runtime-adapters.md | 10 +++++----- .../decisions/009-scene-state-fields.md | 8 ++++---- .../scene-viewer-visualisation/implementation-plan.md | 4 ++-- initiatives/scene-viewer-visualisation/proposal.md | 5 +++-- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md index b23eb13..5ca2c43 100644 --- a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md +++ b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md @@ -48,9 +48,9 @@ state are never serialized. Do not add Qt signals or GPU contracts to core. ## Compatibility -Core serialized scene contracts remain authoritative. Removing transient -Viewer fields from scene-object settings may change Viewer-specific serialized -data and requires fixture inspection and migration documentation. +ADR 008 proposes replacing the current incomplete scene serialization without +a compatibility loader. Removing transient Viewer fields and introducing the +new scene-node schema therefore form a deliberate C3 serialization break. ## Verification diff --git a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md index 0931751..59f15c2 100644 --- a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md +++ b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md @@ -121,11 +121,11 @@ blocked until this amendment and ADR 009 are approved. ## Compatibility -The existing serialized scene shape requires an explicit one-way loader into -the new node schema. Old files have no durable node GUID, so the loader -generates one deterministically only where the legacy hierarchy supplies a -stable path; otherwise it generates and documents a new identity. It preserves -known legacy settings and rejects ambiguous state rather than guessing. +The new node schema replaces the existing serialized scene shape. The initial +implementation does not include a compatibility loader because current files +omit required state and cannot be migrated reliably without guessing. If +concrete legacy files later require recovery, migration tooling needs separate +evidence, scope, and approval. Existing public code may continue to receive a `SceneObject` adapter from `Scene.add`, but code that treats adapter identity or constructor side effects diff --git a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md index d1d4e9e..96bb9f5 100644 --- a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md +++ b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md @@ -74,10 +74,10 @@ extension values remain inactive and round-trip unchanged under ADR 008. ## Compatibility -Legacy `settings` mappings are accepted only by the legacy scene loader and -mapped into declared base/extension fields. Unknown unnamespaced legacy keys -cannot be assigned safely and must be reported; they are not passed to -constructors. Once migrated, only the explicit schema is written. +Legacy `settings` mappings are not accepted by the new serializer. They are +incomplete, unversioned, and cannot be mapped into declared base/extension +fields reliably. The new implementation reads and writes only the explicit +schema. Any later recovery tool remains separate from runtime serialization. ## Verification diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 05a2bb8..e04c734 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -32,8 +32,8 @@ Status: blocked on approval of ADRs 008–009. and compatibility-only consumers against the proposed node/adapter split. 3. Implement the closed scene node/state schema, durable node GUIDs, separate item store, and two-phase deserialize/bind lifecycle. -4. Implement explicit MRO-composed extension field declarations and the legacy - settings loader; preserve unknown namespaced extension state. +4. Implement explicit MRO-composed extension field declarations; preserve + unknown namespaced extension state within the new schema. 5. Migrate core and Viewer adapters without serializing caches, selection, construction commands, or runtime handles. Use the draft ModelViewer failure as external regression evidence, not as behavior to preserve. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index 34c51db..9e21c62 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -238,8 +238,9 @@ design is proven. shared indexed vertices. Current examples and adapters migrate together. A deprecated parallel constructor is not proposed. - Existing core scene serialization is not sufficient for the approved - architecture. ADRs 008–009 define a legacy loader and a new explicit node - schema; implementation is blocked pending their approval. + architecture. ADRs 008–009 define a new explicit node schema without a + compatibility loader for existing scene files; implementation is blocked + pending their approval. - Current `Tag` and `ArrowOverlay` data may require a documented migration to the accepted annotation/overlay types. Exact compatibility should be checked against serialized fixtures before implementation; do not silently reinterpret From 441609e9a04e358aad07eaf6e93f3b7890c05230 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 16:36:40 +0100 Subject: [PATCH 06/22] Separate scene descriptions from session data --- .../scene-viewer-visualisation/README.md | 6 +- .../decisions/001-ownership-boundaries.md | 11 +- .../008-scene-nodes-and-runtime-adapters.md | 38 +++-- .../decisions/009-scene-state-fields.md | 8 +- ...010-scene-description-and-item-bundling.md | 133 ++++++++++++++++++ .../decisions/README.md | 21 ++- .../scene-viewer-visualisation/handoff.md | 20 +-- .../implementation-plan.md | 29 ++-- .../scene-viewer-visualisation/objective.md | 11 +- .../scene-viewer-visualisation/proposal.md | 53 +++++-- 10 files changed, 261 insertions(+), 69 deletions(-) create mode 100644 initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md diff --git a/initiatives/scene-viewer-visualisation/README.md b/initiatives/scene-viewer-visualisation/README.md index 020b1c8..789d32c 100644 --- a/initiatives/scene-viewer-visualisation/README.md +++ b/initiatives/scene-viewer-visualisation/README.md @@ -12,9 +12,9 @@ Current phase: **architecture amendment proposed; implementation paused**. - [Implementation plan](implementation-plan.md) - [Current handoff](handoff.md) -ADRs 001–007 are Accepted. Verified round-trip failures exposed an unresolved -scene-node/runtime-adapter and serialization boundary. Proposed ADRs 008–009 -must be approved before Phase 1 begins. +ADRs 001–009 are Accepted. Proposed ADR 010 keeps Scene reference-only and +places optional aggregation behind a separate future Session design. It must +be approved before implementation begins. The refined initial package scope is `compas`, `compas_viewer`, and `compas_framework`. The current `compas_model.ModelViewer` is draft evidence diff --git a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md index 5ca2c43..80cf562 100644 --- a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md +++ b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md @@ -73,13 +73,12 @@ Later redesign/regression consumer: `compas_model`. ## Pending amendments -Verified round-trip failures show that this decision did not distinguish the +Verified round-trip failures showed that this decision did not distinguish the durable scene node/state from the context-specific runtime `SceneObject` -adapter precisely enough. Implementation of the core ownership, GUID, context, -and serialization clauses is blocked by Proposed -[ADR 008](008-scene-nodes-and-runtime-adapters.md) and -[ADR 009](009-scene-state-fields.md). This note does not change ADR 001's -Accepted status or approve either amendment. +adapter precisely enough. Accepted [ADR 008](008-scene-nodes-and-runtime-adapters.md) +and [ADR 009](009-scene-state-fields.md) amend that boundary. Proposed +[ADR 010](010-scene-description-and-item-bundling.md) still blocks +implementation until item ownership and packaging are explicit. The generic principle that domain packages retain their own data authority does not preserve the current draft `ModelViewer` controller, projections, diff --git a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md index 59f15c2..6e22f9a 100644 --- a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md +++ b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context @@ -60,15 +60,17 @@ closed base record contains: - visibility, opacity, and base appearance; and - explicitly declared extension state governed by ADR 009. -The item store remains separate and keyed by item GUID, preserving shared item -identity. Node GUIDs are serialized and restored so selection references, -domain indexes, and external scene references have durable identity. Runtime -adapter instances are not durable identities. +Items remain separate and keyed by item GUID, preserving shared item identity. +Whether a serialized scene description embeds those items or only references +them is intentionally refined by Proposed ADR 010. Node GUIDs are serialized +and restored so selection references, domain indexes, and external scene +references have durable identity. Runtime adapter instances are not durable +identities. Deserialize in two phases: -1. validate and create the item store, nodes, state, GUIDs, and complete - hierarchy without context dispatch or adapter constructors; +1. validate and create nodes, state, GUIDs, and the complete hierarchy without + requiring item bindings, context dispatch, or adapter constructors; 2. bind adapters for an explicitly requested or detected runtime context only after the scene is structurally complete, either eagerly for drawing or lazily on first use. @@ -96,16 +98,18 @@ validation; unknown adapter state is not passed blindly to constructors. This ADR preserves ADR 001's package boundaries but refines these clauses: - "Core owns scene items, hierarchy, scene-object GUIDs..." becomes: core - owns items plus durable node/state GUIDs; runtime adapter identity is not - serialized. + owns durable node/state GUIDs and stable item references; runtime adapter + identity is not serialized. Proposed ADR 010 decides the non-owning runtime + binding boundary for items. - "GUIDs connect durable scene objects to Viewer state" becomes: durable node GUIDs connect scene content to Viewer state and domain indexes. - Core still owns transformations, visibility, durable appearance, and serialization, but those values live on node state rather than being discovered from a runtime adapter's constructor/settings implementation. -Implementation of ADR 001's durable identity and serialization boundary is -blocked until this amendment and ADR 009 are approved. +ADR 001's durable identity and serialization boundary is amended by this +Accepted decision and ADR 009. Item ownership and packaging remain blocked on +Proposed ADR 010. ## Consequences @@ -160,5 +164,13 @@ scene adapters. - [ADR 001](001-ownership-boundaries.md), refined by this decision ADR 009 supplies the serialization field policy required to implement this -decision. The two Proposed amendments must be approved together, but ADR 008 -defines the ownership boundary first. +decision. ADR 010 separately decides that referenced items remain external to +Scene and defines the boundary for later Session aggregation. + +## Decision + +Accepted on 2026-11-07. The user additionally required a separate decision +ensuring that independently serializable `Data` objects are not forced to live +inside a scene. That unresolved packaging refinement is Proposed ADR 010 and +blocks implementation without changing this decision's accepted node/adapter +separation. diff --git a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md index 96bb9f5..68666be 100644 --- a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md +++ b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context @@ -101,3 +101,9 @@ Later redesign/regression consumer: `compas_model`. ## Dependencies - [ADR 008](008-scene-nodes-and-runtime-adapters.md) + +## Decision + +Accepted on 2026-11-07. Persistent fields use the closed base schema and +explicit MRO-composed declarations described above. Item ownership and +serialization packaging are decided separately by Proposed ADR 010. diff --git a/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md b/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md new file mode 100644 index 0000000..4d38b2f --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md @@ -0,0 +1,133 @@ +# ADR 010: Scene Description, Item Bindings, and Aggregation Boundary + +## Status + +Proposed. + +## Context + +ADRs 008–009 separate durable scene node state from runtime adapters and define +its serialization fields. They do not yet decide whether referenced domain +items must be embedded in a serialized scene. + +A geometry or other `Data` object may need to be serialized independently for +later algorithmic processing while also being referenced by one or more scene +nodes. It must not be forced to live inside the scene or require extraction +from a scene file before ordinary data processing. Conversely, users sometimes +need an aggregate containing data, one or more scenes, settings, and history. + +The current item table preserves shared identity inside one scene file, but +conflates a scene description, runtime bindings, and packaging. + +## Options + +1. Keep Scene reference-only and treat a redesigned Session as the likely + optional aggregate under a separate decision and scope. +2. Always embed every referenced item in the scene serialization. +3. Add a dedicated `SceneBundle` containing one scene plus its items. +4. Introduce a general asset catalog with URIs, search paths, network loading, + and resolver plugins. + +## Recommendation + +Choose option 1. + +Define one Scene role, its runtime bindings, and one later aggregation boundary: + +- `Scene` is the durable, backend-neutral visual description from ADRs 008–009. + Its serialized node hierarchy contains stable item GUID references only. + At runtime it may hold a nonserialized binding table from those GUIDs to + already loaded `Data` objects. A binding is a reference, not ownership; the + same object remains independently usable and serializable. +- A redesigned `compas_session.Session` is the likely optional aggregate for + independently serialized data, one or more scene descriptions, settings, + history, and their shared identity. Its exact schema, ownership, and loading + behavior require a separate dependent decision and explicit scope approval. + Do not add Session implementation to the current wave. + +The intended runtime operations are conceptually: + +```python +scene = Scene.from_json(...) +scene.bind(item) +scene.bind_many(items) +``` + +Exact method naming may follow established core conventions during +implementation. Scene serialization remains reference-only; it is not +controlled by an `include_items` boolean. + +Loading a Scene succeeds when item references are unresolved. Hierarchy, +node state, and reference inspection remain available. Binding an item uses +its existing GUID. Binding the same instance again is idempotent; binding a +different object with the same GUID is rejected. All nodes referencing one +GUID resolve to the same bound object instance. + +Drawing, adapter binding, or another operation that requires an +unresolved item raises a precise error containing the node GUID and item GUID. +The caller may bind the item later and retry. Serialization and inspection of +the reference-bearing description do not require bindings. + +Do not add URIs, filesystem lookup, network loading, an asset registry, or a +resolver plugin. Callers load `Data` objects through existing serialization and +bind them explicitly. A concrete external-resource requirement would need a +separate decision. + +## Refinement of ADR 008 + +ADR 008's separate item store is refined into a runtime binding table. Core +owns the Scene description and stable references, but it does not claim +exclusive ownership of bound `Data` objects. Aggregation belongs outside Scene; +a future Session design may package objects without making that aggregate their +only valid serialization path. + +## Consequences + +- Domain data remains independently serializable and directly available for + algorithms. +- Scenes can be stored, compared, or transmitted without + duplicating large items. +- A future self-contained aggregate can support multiple scenes, settings, and + history without introducing a redundant one-scene bundle type now. +- Shared identity is deterministic within a runtime Scene and must remain so + in any future approved Session aggregate. +- Unresolved references become a normal, inspectable state with precise + failure at item-dependent operations. +- Cross-file discovery remains the caller's responsibility; no speculative + asset system is introduced. + +## Compatibility + +The new Scene format is reference-only. Existing `Data` serialization remains +unchanged. A future Session aggregate and any legacy recovery tooling remain +outside Scene runtime serialization and require separate approval. + +## Verification + +- Serialize and load one `Data` object independently, bind it to a separately + loaded Scene, and run an algorithm on the original/bound object + without extraction or copying. +- Round-trip a reference-only Scene while items remain unresolved. +- Bind later and prove every node sharing one item GUID resolves to the same + object instance. +- Reject a different object with a duplicate GUID atomically. +- Raise precise node/item errors for draw and adapter operations that + require unresolved items. +- Prove description serialization needs no bound items and no URI/network + resolver is invoked. +- In a separate future Session decision, verify data and multiple scenes share + identity without requiring extraction from Scene. + +## Affected packages + +Initial implementation: `compas` and `compas_framework`. + +Consumer: `compas_viewer`. + +Separate later design/scope: `compas_session`, followed by `compas_model`, +notebook, and CAD-host integrations as applicable. + +## Dependencies + +- [ADR 008](008-scene-nodes-and-runtime-adapters.md) +- [ADR 009](009-scene-state-fields.md) diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index 759b275..db8fbfb 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -1,8 +1,8 @@ # Scene, Viewer, and Visualisation Decisions -ADRs 001–007 are Accepted. New round-trip evidence requires two Proposed -amendments before implementation starts. ADRs 008–009 refine, but do not -silently rewrite, the accepted ownership boundary. +ADRs 001–009 are Accepted. ADR 010 is a Proposed follow-up required by the +approval of ADRs 008–009 and blocks implementation until item ownership and +serialization packaging are explicit. | ADR | Decision | Status | Dependencies | |---|---|---|---| @@ -13,12 +13,11 @@ silently rewrite, the accepted ownership boundary. | 005 | [Annotations, measurements, and overlays](005-annotations-and-overlays.md) | Accepted | 001, 002, 003 | | 006 | [Public Viewer integration facade](006-viewer-integration-facade.md) | Accepted | 001, 003, 004, 005 | | 007 | [Initial scope and verification](007-scope-and-verification.md) | Accepted | 001–006; Plugin 005 | -| 008 | [Serializable scene nodes and runtime adapters](008-scene-nodes-and-runtime-adapters.md) | Proposed | 001; verified round-trip regressions | -| 009 | [Explicit scene-state serialization fields](009-scene-state-fields.md) | Proposed | 008 | +| 008 | [Serializable scene nodes and runtime adapters](008-scene-nodes-and-runtime-adapters.md) | Accepted | 001; verified round-trip regressions | +| 009 | [Explicit scene-state serialization fields](009-scene-state-fields.md) | Accepted | 008 | +| 010 | [Scene description, item bindings, and aggregation boundary](010-scene-description-and-item-bundling.md) | Proposed | 008, 009 | -Phase 1 is blocked until ADRs 008–009 are explicitly approved. ADR 008 refines -ADR 001's statement that core owns durable scene content: the durable object is -a scene-owned node/state record, not the context-specific runtime -`SceneObject` adapter. ADR 009 replaces the implicit `settings`/constructor -replay mechanism with an explicit schema. The remaining accepted decisions -retain their intent but must be implemented against the amended boundary. +ADRs 008–009 were accepted on 2026-11-07. ADR 010 refines ADR 008's item store +into non-owning runtime bindings and keeps aggregation outside Scene. A +redesigned Session is the likely aggregate under separate future approval. No +package source implementation begins until ADR 010 is explicitly approved. diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 2112490..9669a48 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -6,9 +6,9 @@ Last updated: 2026-11-07 Current phase: `architecture` -Status: ADRs 001–007 are Accepted, but two verified scene round-trip -regressions require Proposed amendment ADRs 008–009. Phase 1 implementation is -paused pending explicit approval. +Status: ADRs 001–009 are Accepted. Proposed ADR 010 must keep Scene +reference-only while defining the boundary for a separate future Session +aggregate before implementation begins. Read next: @@ -19,11 +19,11 @@ Read next: ## Decisions and approvals -- Accepted: [ADRs 001–007](decisions/README.md). +- Accepted: [ADRs 001–009](decisions/README.md), including ADRs 008–009 on + 2026-11-07. - Proposed or unresolved: - [ADR 008](decisions/008-scene-nodes-and-runtime-adapters.md) and - [ADR 009](decisions/009-scene-state-fields.md); both require approval before - package source changes. + [ADR 010](decisions/010-scene-description-and-item-bundling.md); approval is + required before package source changes. - Scope boundary: `compas_model`, notebook, and CAD hosts are later or compatibility consumers; `compas_session` requires an explicit inclusion decision. Do not modify package source outside the initial scope, merge, or @@ -53,12 +53,14 @@ Read next: do not round-trip under the current constructor/settings mechanism. - Proposed separate serializable node state, runtime adapter binding, durable node GUIDs, and explicit serialization fields in ADRs 008–009. +- Accepted ADRs 008–009 and proposed reference-only scene descriptions plus a + separate future Session aggregation boundary in ADR 010. - Recorded that the current `compas_model.ModelViewer` is a draft and only regression/coupling evidence, not a public contract to preserve. ## Next tasks -1. Review and approve or revise ADRs 008–009. +1. Review and approve or revise ADR 010. 2. After approval, refresh core/Viewer branches, add the Viewer regression, and cover the draft ModelViewer failure mode with a minimal core adapter test. 3. Complete Phase 0 before indexed-buffer implementation begins; defer @@ -66,7 +68,7 @@ Read next: ## Blockers and approval gates -- Package source implementation is blocked on ADRs 008–009. +- Package source implementation is blocked on ADR 010. - Adding model, session, notebook, or host packages to initial implementation scope requires explicit approval. diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index e04c734..8ec0e51 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,51 +2,54 @@ ## Status -Architecture amendment required. ADRs 001–007 are Accepted, but verified -round-trip regressions block implementation. Proposed ADRs 008–009 must be -approved before Phase 1 or package source work begins. +Architecture follow-up required. ADRs 001–009 are Accepted, but Proposed ADR +010 must be approved before Phase 0, Phase 1, or package source work begins. ## Dependency graph ```text -ADR 001 --> ADR 008 --> ADR 009 +ADR 001 --> ADR 008 --> ADR 009 --> ADR 010 | +--------> ADR 002 +--------> ADR 003 --> ADR 004 ADRs 001–003 ----------> ADR 005 ADRs 001, 003–005 -----> ADR 006 -ADRs 001–009 ----------> ADR 007 rollout gate +ADRs 001–010 ----------> ADR 007 rollout gate ``` ## Phase 0 — Scene ownership and serialization amendment -Governing ADRs: 001, 008, and 009. +Governing ADRs: 001, 008, 009, and 010. -Status: blocked on approval of ADRs 008–009. +Status: blocked on approval of ADR 010. 1. Add the verified Viewer round-trip regression and a minimal core adapter test covering the constructor-before-attachment failure. Keep the actual draft ModelViewer failure as evidence for its later redesign. 2. Audit Scene, SceneObject, Group, Viewer adapters, the draft model adapters, and compatibility-only consumers against the proposed node/adapter split. -3. Implement the closed scene node/state schema, durable node GUIDs, separate - item store, and two-phase deserialize/bind lifecycle. +3. Implement the closed scene node/state schema, durable node GUIDs, + reference-only descriptions, runtime item bindings, and two-phase + deserialize/bind lifecycle. 4. Implement explicit MRO-composed extension field declarations; preserve unknown namespaced extension state within the new schema. 5. Migrate core and Viewer adapters without serializing caches, selection, construction commands, or runtime handles. Use the draft ModelViewer failure as external regression evidence, not as behavior to preserve. +6. Document the separate future Session aggregation boundary without adding a + `SceneBundle`, URI resolver, asset registry, or Session implementation. Exit gate: the Viewer and minimal-adapter regressions pass; shared item identity and durable node identity round-trip separately; scenes load without a visualization backend; runtime adapters bind only after the complete -hierarchy exists; local/package quality, typing, docs, and artifact checks -pass. +hierarchy exists; independently loaded items bind without copying; unresolved +references follow ADR 010; local/package quality, typing, docs, and artifact +checks pass. ## Phase 1 — Boundaries and indexed geometry -Governing ADRs: 001, 002, 007, 008, and 009. +Governing ADRs: 001, 002, 007, 008, 009, and 010. Status: paused until Phase 0 and its approval gate are complete. @@ -138,4 +141,6 @@ required unavailable evidence remains an explicit blocker. - console, terminal, Python/shell execution, assistant services, credentials, or remote transports; - `compas_session` reactive-state integration; and +- `compas_session` aggregation of data, one or more scenes, settings, and + history; - notebook, Rhino, Grasshopper, Blender, or other backend migrations. diff --git a/initiatives/scene-viewer-visualisation/objective.md b/initiatives/scene-viewer-visualisation/objective.md index a06f881..00cd78d 100644 --- a/initiatives/scene-viewer-visualisation/objective.md +++ b/initiatives/scene-viewer-visualisation/objective.md @@ -33,6 +33,8 @@ home and contract. and independent future consumers? 9. Which local, package, framework-integration, and artifact evidence is required for each approved wave? +10. How can scene nodes reference independently serialized `Data` objects while + leaving optional aggregation to a separately designed Session? ## Design principles @@ -41,6 +43,8 @@ home and contract. large edge or triangle set into one Python object per primitive. - Keep raw NumPy-compatible buffers valid inputs without forcing conversion through COMPAS geometry or data objects. +- Keep referenced `Data` independently serializable and algorithm-ready; keep + optional Session aggregation separate from Scene. - Separate durable scene state, persistent viewer configuration, and transient interaction state. - Provide one observable selection path for viewport, scene graph, and code. @@ -71,6 +75,9 @@ home and contract. 6. Public integration boundaries for Viewer tools, components, and optional UI extensions. 7. Package-local and framework-level tests, examples, and documentation. +8. Reference-only scene descriptions with deterministic GUID binding and + unresolved-reference behavior, plus a clear boundary for a separately + approved Session aggregate. ## Non-goals without a later scope decision @@ -100,6 +107,6 @@ home and contract. ## Current status -Reconnaissance is complete. ADRs 001–007 are Accepted, but Proposed amendment -ADRs 008–009 block implementation pending approval. The current draft +Reconnaissance is complete. ADRs 001–009 are Accepted, but Proposed ADR 010 +blocks implementation pending approval. The current draft `ModelViewer` is evidence and a later redesign target, not a contract. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index 9e21c62..367daad 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -14,9 +14,9 @@ measurements, annotations, scale/legend overlays, and public dock/command composition. It should not attempt a universal renderer API, a generic reactive framework, sub-object editing, a shell, or host-application migration. -Implementation is paused. Verified scene round-trip regressions show that the -accepted ownership boundary requires the Proposed ADRs 008–009 before Phase 1 -can begin. +Implementation is paused. ADRs 008–009 are Accepted, but their approval +requires Proposed ADR 010 to clarify independent item serialization and the +boundary for later Session aggregation before Phase 1 can begin. ## New evidence requiring amendment @@ -42,12 +42,13 @@ Core `Scene` remains the backend-neutral serializable hierarchy, but its durable entries become scene-owned node/state value objects rather than runtime `SceneObject` adapters. Nodes preserve their own GUID, optional item GUID, local transformation, hierarchy, visibility, base appearance, and explicitly -declared extension state. The separate item store continues to preserve shared -item identity. +declared extension state. Runtime item bindings preserve shared identity +without making Scene the owner or serialization container of those items. Runtime `SceneObject` instances bind a complete node and item to a chosen visualization context. They are not serialized identities and may be created -only after deserialization has rebuilt the full item store and hierarchy. +only after deserialization has rebuilt the hierarchy and resolved the required +item bindings. Their constructors do not populate hierarchy. Scene context is runtime binding configuration; absence of a backend cannot prevent loading durable content. @@ -61,6 +62,29 @@ explicit MRO-composed declarations. Introspection may validate declarations and support editors, but `__dict__`, public properties, annotations, and constructor parameters never define persistence automatically. +### Scene descriptions, item bindings, and aggregation + +Durable scene nodes reference items by stable item GUID. Serialized `Scene` +contains the visual node hierarchy and state but does not require referenced +`Data` objects to live inside it. At runtime Scene binds already loaded objects +to those GUIDs without taking exclusive ownership; the same object remains +independently serializable and directly usable by algorithms. + +A separately loaded description may contain unresolved references. Its +hierarchy and node state remain inspectable, and callers can bind items later. +All nodes sharing one GUID resolve to the same bound instance. Item-dependent +adapter, draw, and packaging operations fail precisely when the required GUID +is unresolved. + +A redesigned `compas_session.Session` is the likely optional aggregate for +independently serialized data, one or more scene descriptions, settings, +history, and their shared identity. Its design and implementation require a +separate dependent decision and scope approval; this initiative does not add a +redundant one-scene `SceneBundle`. Scene remains usable without Session. + +Do not add URI resolution, filesystem search, network loading, or an asset +registry without a concrete future requirement. + ### Indexed render geometry `compas_viewer` owns one public indexed `BufferGeometry` contract: @@ -239,8 +263,9 @@ design is proven. A deprecated parallel constructor is not proposed. - Existing core scene serialization is not sufficient for the approved architecture. ADRs 008–009 define a new explicit node schema without a - compatibility loader for existing scene files; implementation is blocked - pending their approval. + compatibility loader for existing scene files. ADR 010 separates + reference-only descriptions from a possible future Session aggregate; + implementation is blocked pending its approval. - Current `Tag` and `ArrowOverlay` data may require a documented migration to the accepted annotation/overlay types. Exact compatibility should be checked against serialized fixtures before implementation; do not silently reinterpret @@ -276,6 +301,9 @@ compatibility-reviewed but not implementation targets in the initial wave. during hierarchy deserialization; the draft controller itself is deferred. - Preserve durable node GUIDs separately from shared item GUIDs and round-trip unknown namespaced extension state without its runtime adapter. +- Load independently serialized items, bind them to reference-only scene + descriptions, preserve shared identity, and verify unresolved-reference + behavior without Session. - Add regression coverage proving transient Viewer state is absent from core scene data and serialization. - Correct and test the core scene/visualisation guide against current APIs. @@ -316,14 +344,14 @@ Examples remain direct scripts and demonstrate, in order: ## Dependency order ```text -ADR 001 --> ADR 008 --> ADR 009 +ADR 001 --> ADR 008 --> ADR 009 --> ADR 010 | +--------> ADR 002 +--------> ADR 003 --> ADR 004 ADRs 001–003 ----------> ADR 005 ADRs 001, 003–005 -----> ADR 006 -ADRs 001–009 ----------> ADR 007 rollout gate +ADRs 001–010 ----------> ADR 007 rollout gate ``` Core geometry, typing, plugin, and repository-modernisation decisions remain @@ -341,6 +369,7 @@ wave are Accepted. 7. [ADR 007 — Initial scope and verification](decisions/007-scope-and-verification.md) 8. [ADR 008 — Serializable scene nodes and runtime adapters](decisions/008-scene-nodes-and-runtime-adapters.md) 9. [ADR 009 — Explicit scene-state serialization fields](decisions/009-scene-state-fields.md) +10. [ADR 010 — Scene description, item bindings, and aggregation boundary](decisions/010-scene-description-and-item-bundling.md) -ADRs 001–007 are Accepted. No package source changes should begin until the -Proposed amendment ADRs 008–009 are explicitly approved. +ADRs 001–009 are Accepted. No package source changes should begin until +Proposed ADR 010 is explicitly approved. From 5c95c1a572f5af5b15890bb62e8609467f076ceb Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 16:40:48 +0100 Subject: [PATCH 07/22] Accept scene data reference boundary --- .../scene-viewer-visualisation/README.md | 5 ++-- .../decisions/001-ownership-boundaries.md | 6 ++--- .../008-scene-nodes-and-runtime-adapters.md | 15 ++++++------ .../decisions/009-scene-state-fields.md | 2 +- ...010-scene-description-and-item-bundling.md | 7 +++++- .../decisions/README.md | 12 ++++------ .../scene-viewer-visualisation/handoff.md | 23 +++++++++---------- .../implementation-plan.md | 8 +++---- .../scene-viewer-visualisation/objective.md | 6 ++--- .../scene-viewer-visualisation/proposal.md | 9 ++++---- 10 files changed, 46 insertions(+), 47 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/README.md b/initiatives/scene-viewer-visualisation/README.md index 789d32c..cdc18f3 100644 --- a/initiatives/scene-viewer-visualisation/README.md +++ b/initiatives/scene-viewer-visualisation/README.md @@ -12,9 +12,8 @@ Current phase: **architecture amendment proposed; implementation paused**. - [Implementation plan](implementation-plan.md) - [Current handoff](handoff.md) -ADRs 001–009 are Accepted. Proposed ADR 010 keeps Scene reference-only and -places optional aggregation behind a separate future Session design. It must -be approved before implementation begins. +ADRs 001–010 are Accepted. Scene is reference-only and optional aggregation is +reserved for a separate future Session design. The refined initial package scope is `compas`, `compas_viewer`, and `compas_framework`. The current `compas_model.ModelViewer` is draft evidence diff --git a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md index 80cf562..5c81733 100644 --- a/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md +++ b/initiatives/scene-viewer-visualisation/decisions/001-ownership-boundaries.md @@ -76,9 +76,9 @@ Later redesign/regression consumer: `compas_model`. Verified round-trip failures showed that this decision did not distinguish the durable scene node/state from the context-specific runtime `SceneObject` adapter precisely enough. Accepted [ADR 008](008-scene-nodes-and-runtime-adapters.md) -and [ADR 009](009-scene-state-fields.md) amend that boundary. Proposed -[ADR 010](010-scene-description-and-item-bundling.md) still blocks -implementation until item ownership and packaging are explicit. +and [ADR 009](009-scene-state-fields.md) amend that boundary. Accepted +[ADR 010](010-scene-description-and-item-bundling.md) defines item ownership +and the later Session aggregation boundary. The generic principle that domain packages retain their own data authority does not preserve the current draft `ModelViewer` controller, projections, diff --git a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md index 6e22f9a..321ed04 100644 --- a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md +++ b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md @@ -61,8 +61,8 @@ closed base record contains: - explicitly declared extension state governed by ADR 009. Items remain separate and keyed by item GUID, preserving shared item identity. -Whether a serialized scene description embeds those items or only references -them is intentionally refined by Proposed ADR 010. Node GUIDs are serialized +Accepted ADR 010 requires a serialized scene description to reference those +items without embedding them. Node GUIDs are serialized and restored so selection references, domain indexes, and external scene references have durable identity. Runtime adapter instances are not durable identities. @@ -99,7 +99,7 @@ This ADR preserves ADR 001's package boundaries but refines these clauses: - "Core owns scene items, hierarchy, scene-object GUIDs..." becomes: core owns durable node/state GUIDs and stable item references; runtime adapter - identity is not serialized. Proposed ADR 010 decides the non-owning runtime + identity is not serialized. Accepted ADR 010 defines the non-owning runtime binding boundary for items. - "GUIDs connect durable scene objects to Viewer state" becomes: durable node GUIDs connect scene content to Viewer state and domain indexes. @@ -108,8 +108,8 @@ This ADR preserves ADR 001's package boundaries but refines these clauses: discovered from a runtime adapter's constructor/settings implementation. ADR 001's durable identity and serialization boundary is amended by this -Accepted decision and ADR 009. Item ownership and packaging remain blocked on -Proposed ADR 010. +Accepted decision and ADR 009. Accepted ADR 010 defines item ownership and +packaging. ## Consequences @@ -171,6 +171,5 @@ Scene and defines the boundary for later Session aggregation. Accepted on 2026-11-07. The user additionally required a separate decision ensuring that independently serializable `Data` objects are not forced to live -inside a scene. That unresolved packaging refinement is Proposed ADR 010 and -blocks implementation without changing this decision's accepted node/adapter -separation. +inside a scene. Accepted ADR 010 records that packaging refinement without +changing this decision's accepted node/adapter separation. diff --git a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md index 68666be..e2a0600 100644 --- a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md +++ b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md @@ -106,4 +106,4 @@ Later redesign/regression consumer: `compas_model`. Accepted on 2026-11-07. Persistent fields use the closed base schema and explicit MRO-composed declarations described above. Item ownership and -serialization packaging are decided separately by Proposed ADR 010. +serialization packaging are decided separately by Accepted ADR 010. diff --git a/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md b/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md index 4d38b2f..048538a 100644 --- a/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md +++ b/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context @@ -45,6 +45,11 @@ Define one Scene role, its runtime bindings, and one later aggregation boundary: behavior require a separate dependent decision and explicit scope approval. Do not add Session implementation to the current wave. +A later Viewer/Session integration may provide convenient new, open, and save +operations. Viewer remains a client of Session persistence: it does not own the +aggregate format, and session support remains optional and lazily loaded. The +exact convenience API follows the separately approved Session redesign. + The intended runtime operations are conceptually: ```python diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index db8fbfb..920458f 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -1,8 +1,7 @@ # Scene, Viewer, and Visualisation Decisions -ADRs 001–009 are Accepted. ADR 010 is a Proposed follow-up required by the -approval of ADRs 008–009 and blocks implementation until item ownership and -serialization packaging are explicit. +ADRs 001–010 are Accepted. ADR 010 records the scene/data serialization and +future Session aggregation boundary approved on 2026-11-07. | ADR | Decision | Status | Dependencies | |---|---|---|---| @@ -15,9 +14,8 @@ serialization packaging are explicit. | 007 | [Initial scope and verification](007-scope-and-verification.md) | Accepted | 001–006; Plugin 005 | | 008 | [Serializable scene nodes and runtime adapters](008-scene-nodes-and-runtime-adapters.md) | Accepted | 001; verified round-trip regressions | | 009 | [Explicit scene-state serialization fields](009-scene-state-fields.md) | Accepted | 008 | -| 010 | [Scene description, item bindings, and aggregation boundary](010-scene-description-and-item-bundling.md) | Proposed | 008, 009 | +| 010 | [Scene description, item bindings, and aggregation boundary](010-scene-description-and-item-bundling.md) | Accepted | 008, 009 | -ADRs 008–009 were accepted on 2026-11-07. ADR 010 refines ADR 008's item store +ADRs 008–010 were accepted on 2026-11-07. ADR 010 refines ADR 008's item store into non-owning runtime bindings and keeps aggregation outside Scene. A -redesigned Session is the likely aggregate under separate future approval. No -package source implementation begins until ADR 010 is explicitly approved. +redesigned Session is the likely aggregate under separate future approval. diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 9669a48..646d918 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -6,9 +6,9 @@ Last updated: 2026-11-07 Current phase: `architecture` -Status: ADRs 001–009 are Accepted. Proposed ADR 010 must keep Scene -reference-only while defining the boundary for a separate future Session -aggregate before implementation begins. +Status: ADRs 001–010 are Accepted. Scene is reference-only and a separate +future Session redesign may aggregate data, scenes, settings, and history. +Implementation may proceed within the approved initial scope. Read next: @@ -19,11 +19,9 @@ Read next: ## Decisions and approvals -- Accepted: [ADRs 001–009](decisions/README.md), including ADRs 008–009 on +- Accepted: [ADRs 001–010](decisions/README.md), including ADRs 008–010 on 2026-11-07. -- Proposed or unresolved: - [ADR 010](decisions/010-scene-description-and-item-bundling.md); approval is - required before package source changes. +- Proposed or unresolved: none. - Scope boundary: `compas_model`, notebook, and CAD hosts are later or compatibility consumers; `compas_session` requires an explicit inclusion decision. Do not modify package source outside the initial scope, merge, or @@ -60,15 +58,16 @@ Read next: ## Next tasks -1. Review and approve or revise ADR 010. -2. After approval, refresh core/Viewer branches, add the Viewer regression, and - cover the draft ModelViewer failure mode with a minimal core adapter test. -3. Complete Phase 0 before indexed-buffer implementation begins; defer +1. Refresh core/Viewer branches, add the Viewer regression, and cover the draft + ModelViewer failure mode with a minimal core adapter test. +2. Complete Phase 0 before indexed-buffer implementation begins; defer `compas_model` controller redesign to a later approved phase. +3. Run the Phase 0 package and framework verification gates. ## Blockers and approval gates -- Package source implementation is blocked on ADR 010. +- Package source implementation is authorized within the accepted initial + scope. - Adding model, session, notebook, or host packages to initial implementation scope requires explicit approval. diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 8ec0e51..15bf0b3 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,8 +2,8 @@ ## Status -Architecture follow-up required. ADRs 001–009 are Accepted, but Proposed ADR -010 must be approved before Phase 0, Phase 1, or package source work begins. +Architecture approved. ADRs 001–010 are Accepted; implementation may proceed +in dependency order within the approved initial scope. ## Dependency graph @@ -22,7 +22,7 @@ ADRs 001–010 ----------> ADR 007 rollout gate Governing ADRs: 001, 008, 009, and 010. -Status: blocked on approval of ADR 010. +Status: authorized. 1. Add the verified Viewer round-trip regression and a minimal core adapter test covering the constructor-before-attachment failure. Keep the actual @@ -142,5 +142,5 @@ required unavailable evidence remains an explicit blocker. or remote transports; - `compas_session` reactive-state integration; and - `compas_session` aggregation of data, one or more scenes, settings, and - history; + history, including optional Viewer new/open/save conveniences; - notebook, Rhino, Grasshopper, Blender, or other backend migrations. diff --git a/initiatives/scene-viewer-visualisation/objective.md b/initiatives/scene-viewer-visualisation/objective.md index 00cd78d..19ee8da 100644 --- a/initiatives/scene-viewer-visualisation/objective.md +++ b/initiatives/scene-viewer-visualisation/objective.md @@ -107,6 +107,6 @@ home and contract. ## Current status -Reconnaissance is complete. ADRs 001–009 are Accepted, but Proposed ADR 010 -blocks implementation pending approval. The current draft -`ModelViewer` is evidence and a later redesign target, not a contract. +Reconnaissance and architecture are complete. ADRs 001–010 are Accepted and +implementation may proceed within the approved initial scope. The current +draft `ModelViewer` is evidence and a later redesign target, not a contract. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index 367daad..b7d4a65 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -14,9 +14,9 @@ measurements, annotations, scale/legend overlays, and public dock/command composition. It should not attempt a universal renderer API, a generic reactive framework, sub-object editing, a shell, or host-application migration. -Implementation is paused. ADRs 008–009 are Accepted, but their approval -requires Proposed ADR 010 to clarify independent item serialization and the -boundary for later Session aggregation before Phase 1 can begin. +ADRs 001–010 are Accepted. Implementation may proceed in dependency order +within the approved initial scope; Session redesign and Viewer/Session +convenience operations remain later work. ## New evidence requiring amendment @@ -371,5 +371,4 @@ wave are Accepted. 9. [ADR 009 — Explicit scene-state serialization fields](decisions/009-scene-state-fields.md) 10. [ADR 010 — Scene description, item bindings, and aggregation boundary](decisions/010-scene-description-and-item-bundling.md) -ADRs 001–009 are Accepted. No package source changes should begin until -Proposed ADR 010 is explicitly approved. +ADRs 001–010 are Accepted. From ee8c4d8317c71544eca2bd2b609adc4df6302c2f Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 17:11:07 +0100 Subject: [PATCH 08/22] Record scene phase zero checkpoint --- .../scene-viewer-visualisation/handoff.md | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 646d918..5cddc0b 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -4,11 +4,11 @@ Last updated: 2026-11-07 ## Resume here -Current phase: `architecture` +Current phase: `implementation` -Status: ADRs 001–010 are Accepted. Scene is reference-only and a separate -future Session redesign may aggregate data, scenes, settings, and history. -Implementation may proceed within the approved initial scope. +Status: ADRs 001–010 are Accepted. Phase 0 core and Viewer source changes are +implemented and independently approved locally; clean hosted package CI remains +to be collected before the Phase 0 exit gate is complete. Read next: @@ -31,9 +31,9 @@ Read next: | Repository | Branch | Exact head | Pull request | Status | |---|---|---|---|---| -| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `` | None | Local initiative documents | -| `compas-dev/compas` | `remove-future` | `99b82a6673ff7d05c1c323c8921135c274993f11` | None | Clean; inspected only | -| `compas-dev/compas_viewer` | `c3-upgrade` | `cf5a5195bda840a511319d6b7201978af68c15e3` | None | Clean; inspected only | +| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `5c95c1a` plus this handoff checkpoint | None | Clean; local | +| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `f878cd102e87e7859030af96c7871a5b3345cf7d` | None | Clean; local, unpushed | +| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `18c87acac907c6d749d95a0e8f56ae2abd021ed2` | None | Clean; local, unpushed | | `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Clean; inspected only | ## Completed at this checkpoint @@ -55,14 +55,17 @@ Read next: separate future Session aggregation boundary in ADR 010. - Recorded that the current `compas_model.ModelViewer` is a draft and only regression/coupling evidence, not a public contract to preserve. +- Implemented durable reference-only core scene nodes, explicit item binding, + two-phase runtime-adapter binding, and validated MRO-composed state fields. +- Adapted Viewer durable state, removed legacy settings persistence, fixed + transient picking-cache lifecycle, and documented separate data binding. +- Resolved all independent core and Viewer review findings. ## Next tasks -1. Refresh core/Viewer branches, add the Viewer regression, and cover the draft - ModelViewer failure mode with a minimal core adapter test. -2. Complete Phase 0 before indexed-buffer implementation begins; defer - `compas_model` controller redesign to a later approved phase. -3. Run the Phase 0 package and framework verification gates. +1. Push core and Viewer initiative branches and collect clean package CI. +2. Add the smallest framework installed-candidate Phase 0 gate. +3. Close the Phase 0 exit gate, then begin indexed-buffer implementation. ## Blockers and approval gates @@ -77,14 +80,14 @@ Evidence by layer: | Layer | Status | Evidence | |---|---|---| -| Local focused checks | Passed | Core 53 tests and Viewer 35 tests passed during reconnaissance; inventory documents the commands and warning scope. | -| Package CI | Not run | No package branches changed. | -| Framework integration CI | Not run | No implementation exists yet. | -| Candidate-artifact CI | Not applicable | Architecture documents only. | +| Local focused checks | Passed | Core scene/glTF: 61 passed, Ruff passed, Pyright 0; Viewer focused: 50 passed, Ruff passed, Pyright 0; independent reviews approved both exact heads. | +| Package CI | Not run | Branches are committed locally and ready to push. | +| Framework integration CI | Not run | Installed exact-candidate gate is the next task. | +| Candidate-artifact CI | Not run | Required only before claims about independently built artifacts. | Run next: ```text -git diff --check -/Users/vanmelet/miniforge3/envs/compas3/bin/python -m mkdocs build --strict +gh pr checks --repo compas-dev/compas +gh pr checks --repo compas-dev/compas_viewer ``` From 666e98bdfc59a02b493427732c45067b869898df Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 17:12:30 +0100 Subject: [PATCH 09/22] Record scene phase zero draft PRs --- initiatives/scene-viewer-visualisation/handoff.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 5cddc0b..f293d00 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -31,9 +31,9 @@ Read next: | Repository | Branch | Exact head | Pull request | Status | |---|---|---|---|---| -| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `5c95c1a` plus this handoff checkpoint | None | Clean; local | -| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `f878cd102e87e7859030af96c7871a5b3345cf7d` | None | Clean; local, unpushed | -| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `18c87acac907c6d749d95a0e8f56ae2abd021ed2` | None | Clean; local, unpushed | +| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `ee8c4d8` plus this handoff checkpoint | [7](https://github.com/compas-dev/compas_framework/pull/7) | Clean; pushed draft | +| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `f878cd102e87e7859030af96c7871a5b3345cf7d` | [1540](https://github.com/compas-dev/compas/pull/1540) | Clean; pushed draft | +| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `18c87acac907c6d749d95a0e8f56ae2abd021ed2` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Clean; pushed draft | | `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Clean; inspected only | ## Completed at this checkpoint @@ -63,7 +63,7 @@ Read next: ## Next tasks -1. Push core and Viewer initiative branches and collect clean package CI. +1. Collect clean package CI on core PR 1540 and Viewer PR 233. 2. Add the smallest framework installed-candidate Phase 0 gate. 3. Close the Phase 0 exit gate, then begin indexed-buffer implementation. @@ -81,8 +81,8 @@ Evidence by layer: | Layer | Status | Evidence | |---|---|---| | Local focused checks | Passed | Core scene/glTF: 61 passed, Ruff passed, Pyright 0; Viewer focused: 50 passed, Ruff passed, Pyright 0; independent reviews approved both exact heads. | -| Package CI | Not run | Branches are committed locally and ready to push. | -| Framework integration CI | Not run | Installed exact-candidate gate is the next task. | +| Package CI | Pending | Viewer PR 233 workflows are running; core PR 1540 initially reports no checks. | +| Framework integration CI | Pending | Framework PR 7 contract check is running; installed exact-candidate gate is the next task. | | Candidate-artifact CI | Not run | Required only before claims about independently built artifacts. | Run next: From 8c7b4a1a94ec898dc1badfaa376a4d8542a8e52f Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 17:17:06 +0100 Subject: [PATCH 10/22] Add scene candidate integration gate --- .github/scene-candidates/requirements.txt | 2 + .../test_scene_integration.py | 109 ++++++++++++++++++ .../workflows/scene-candidate-integration.yml | 49 ++++++++ tests/test_package.py | 12 ++ 4 files changed, 172 insertions(+) create mode 100644 .github/scene-candidates/requirements.txt create mode 100644 .github/scene-candidates/test_scene_integration.py create mode 100644 .github/workflows/scene-candidate-integration.yml diff --git a/.github/scene-candidates/requirements.txt b/.github/scene-candidates/requirements.txt new file mode 100644 index 0000000..b951621 --- /dev/null +++ b/.github/scene-candidates/requirements.txt @@ -0,0 +1,2 @@ +compas @ git+https://github.com/compas-dev/compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d +compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@18c87acac907c6d749d95a0e8f56ae2abd021ed2 diff --git a/.github/scene-candidates/test_scene_integration.py b/.github/scene-candidates/test_scene_integration.py new file mode 100644 index 0000000..742f1c2 --- /dev/null +++ b/.github/scene-candidates/test_scene_integration.py @@ -0,0 +1,109 @@ +import json +import os +import subprocess +import sys +from importlib.metadata import distribution + +import pytest +from compas.colors import Color +from compas.geometry import Box +from compas.geometry import Translation +from compas.scene import Scene +from compas.scene import SceneItemNotBoundError +from compas_viewer import Viewer +from compas_viewer.scene import ViewerScene + +CORE_COMMIT = "f878cd102e87e7859030af96c7871a5b3345cf7d" +VIEWER_COMMIT = "18c87acac907c6d749d95a0e8f56ae2abd021ed2" + + +def _installed_commit(distribution_name: str) -> str: + direct_url = distribution(distribution_name).read_text("direct_url.json") + assert direct_url is not None + metadata = json.loads(direct_url) + return metadata["vcs_info"]["commit_id"] + + +def test_exact_source_candidates_are_installed(): + if os.environ.get("COMPAS_SCENE_SOURCE_CHECKOUTS") == "1": + pytest.skip("Direct-source local check; exact installed revisions are verified by framework CI.") + assert _installed_commit("compas") == CORE_COMMIT + assert _installed_commit("compas_viewer") == VIEWER_COMMIT + + +def test_plugin_discovery_does_not_import_graphics_modules(): + code = """ +import sys + +from compas.plugins import PluginManager + +manager = PluginManager() +manager.load_plugins() +modules = tuple(sys.modules) +assert "compas_viewer.plugins" in modules +assert not any(name == "PySide6" or name.startswith("PySide6.") for name in modules) +assert not any(name == "OpenGL" or name.startswith("OpenGL.") for name in modules) +""" + environment = os.environ.copy() + if os.environ.get("COMPAS_SCENE_SOURCE_CHECKOUTS") != "1": + environment.pop("PYTHONPATH", None) + subprocess.run([sys.executable, "-c", code], check=True, env=environment) + + +def test_reference_scene_roundtrip_and_explicit_binding(tmp_path): + viewer = Viewer() + viewer.running = False + viewer.scene.clear(clear_context=False) + + box = Box(1.0) + transformation = Translation.from_vector([2.0, 0.0, 0.0]) + original = viewer.scene.add( + box, + name="Box", + is_selected=True, + show_faces=False, + facecolor=Color.red(), + transformation=transformation, + u=7, + use_rgba=True, + v=9, + ) + original.background = True + + scene_path = tmp_path / "scene.json" + item_path = tmp_path / "box.json" + viewer.scene.to_json(scene_path) + box.to_json(item_path) + + payload = scene_path.read_text() + assert str(box.guid) in payload + assert "compas.geometry/Box" not in payload + assert "is_selected" not in payload + assert "instance_color" not in payload + + restored_scene = Scene.from_json(scene_path) + restored_box = Box.from_json(item_path) + assert isinstance(restored_scene, ViewerScene) + assert restored_box.guid == box.guid + assert restored_box.volume() == box.volume() + + node = restored_scene.find_node_by_name("Box") + assert node is not None + assert node.guid == original.node.guid + assert node.item_guid == restored_box.guid + with pytest.raises(SceneItemNotBoundError, match=str(restored_box.guid)): + restored_scene.bind_context("Viewer") + + restored_scene.bind(restored_box) + restored_scene.bind_context("Viewer") + restored = restored_scene.objects[0] + + assert restored.node.transformation == transformation + assert restored.show_faces is False + assert restored.facecolor == Color.red() + assert restored.u == 7 + assert restored.use_rgba is True + assert restored.v == 9 + assert restored.background is True + assert restored.is_selected is False + assert restored_scene.instance_colors == {} diff --git a/.github/workflows/scene-candidate-integration.yml b/.github/workflows/scene-candidate-integration.yml new file mode 100644 index 0000000..4cf8840 --- /dev/null +++ b/.github/workflows/scene-candidate-integration.yml @@ -0,0 +1,49 @@ +name: scene-candidate-integration + +on: + pull_request: + branches: [c3-upgrade] + paths: + - .github/scene-candidates/** + - .github/workflows/scene-candidate-integration.yml + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: scene-candidate-integration-${{ github.ref }} + cancel-in-progress: true + +jobs: + source-installed-candidates: + runs-on: ubuntu-24.04 + env: + PYTHONDONTWRITEBYTECODE: "1" + QT_QPA_PLATFORM: offscreen + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.12" + - uses: astral-sh/setup-uv@ae62891fec2bb8e7d6c99fc78c9fec3a63790f8d # v10.0.0 + with: + version: "0.12.7" + - name: Install test tools and exact source candidates + run: | + uv venv + uv pip install --python .venv/bin/python pytest==9.0.2 pyright==1.1.414 + uv pip install --python .venv/bin/python --requirements .github/scene-candidates/requirements.txt + - name: Check installed scene typing boundary + run: >- + uv run --no-sync pyright + --pythonversion 3.12 + .github/scene-candidates/test_scene_integration.py + - name: Exercise installed scene and Viewer behavior + run: >- + uv run --no-sync pytest + --basetemp "${RUNNER_TEMP}/scene-candidate-pytest" + -o cache_dir="${RUNNER_TEMP}/scene-candidate-cache" + .github/scene-candidates/test_scene_integration.py diff --git a/tests/test_package.py b/tests/test_package.py index b877fbd..0563ea8 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -57,6 +57,18 @@ def test_native_candidate_integration_runs_from_the_protected_initiative_branch( assert "inputs.manifest_path || '.github/candidates/native-linux-py312.json'" in workflow +def test_scene_candidate_integration_pins_exact_source_revisions(): + source = Path(__file__).parents[1] + requirements = (source / ".github" / "scene-candidates" / "requirements.txt").read_text() + workflow = (source / ".github" / "workflows" / "scene-candidate-integration.yml").read_text() + + assert "compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d" in requirements + assert "compas_viewer.git@18c87acac907c6d749d95a0e8f56ae2abd021ed2" in requirements + assert "branches: [c3-upgrade]" in workflow + assert "requirements.txt" in workflow + assert "source-installed-candidates" in workflow + + def test_framework_examples_page_is_link_oriented(): page = (Path(__file__).parents[1] / "docs" / "examples.md").read_text() From c8ba171cb41d41e2bc7b867f8828c9a38697d8f6 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 17:22:28 +0100 Subject: [PATCH 11/22] Install scene candidates without dependency re-resolution --- .github/workflows/scene-candidate-integration.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/scene-candidate-integration.yml b/.github/workflows/scene-candidate-integration.yml index 4cf8840..e58ae38 100644 --- a/.github/workflows/scene-candidate-integration.yml +++ b/.github/workflows/scene-candidate-integration.yml @@ -35,7 +35,12 @@ jobs: run: | uv venv uv pip install --python .venv/bin/python pytest==9.0.2 pyright==1.1.414 - uv pip install --python .venv/bin/python --requirements .github/scene-candidates/requirements.txt + uv pip install --python .venv/bin/python compas_viewer==2.0.2 + uv pip install \ + --python .venv/bin/python \ + --no-deps \ + --reinstall \ + --requirements .github/scene-candidates/requirements.txt - name: Check installed scene typing boundary run: >- uv run --no-sync pyright From 245aab90f993bd17e83d6ce37de187f3bc892d43 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 17:24:24 +0100 Subject: [PATCH 12/22] Resolve scene candidate dependencies in stages --- .github/scene-candidates/core-requirements.txt | 1 + .../{requirements.txt => viewer-requirements.txt} | 1 - .github/workflows/scene-candidate-integration.yml | 6 +++++- tests/test_package.py | 11 +++++++---- 4 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 .github/scene-candidates/core-requirements.txt rename .github/scene-candidates/{requirements.txt => viewer-requirements.txt} (53%) diff --git a/.github/scene-candidates/core-requirements.txt b/.github/scene-candidates/core-requirements.txt new file mode 100644 index 0000000..f644eb4 --- /dev/null +++ b/.github/scene-candidates/core-requirements.txt @@ -0,0 +1 @@ +compas @ git+https://github.com/compas-dev/compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d diff --git a/.github/scene-candidates/requirements.txt b/.github/scene-candidates/viewer-requirements.txt similarity index 53% rename from .github/scene-candidates/requirements.txt rename to .github/scene-candidates/viewer-requirements.txt index b951621..61b6673 100644 --- a/.github/scene-candidates/requirements.txt +++ b/.github/scene-candidates/viewer-requirements.txt @@ -1,2 +1 @@ -compas @ git+https://github.com/compas-dev/compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@18c87acac907c6d749d95a0e8f56ae2abd021ed2 diff --git a/.github/workflows/scene-candidate-integration.yml b/.github/workflows/scene-candidate-integration.yml index e58ae38..05a2765 100644 --- a/.github/workflows/scene-candidate-integration.yml +++ b/.github/workflows/scene-candidate-integration.yml @@ -36,11 +36,15 @@ jobs: uv venv uv pip install --python .venv/bin/python pytest==9.0.2 pyright==1.1.414 uv pip install --python .venv/bin/python compas_viewer==2.0.2 + uv pip install \ + --python .venv/bin/python \ + --reinstall \ + --requirements .github/scene-candidates/core-requirements.txt uv pip install \ --python .venv/bin/python \ --no-deps \ --reinstall \ - --requirements .github/scene-candidates/requirements.txt + --requirements .github/scene-candidates/viewer-requirements.txt - name: Check installed scene typing boundary run: >- uv run --no-sync pyright diff --git a/tests/test_package.py b/tests/test_package.py index 0563ea8..c08ffef 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -59,13 +59,16 @@ def test_native_candidate_integration_runs_from_the_protected_initiative_branch( def test_scene_candidate_integration_pins_exact_source_revisions(): source = Path(__file__).parents[1] - requirements = (source / ".github" / "scene-candidates" / "requirements.txt").read_text() + core_requirements = (source / ".github" / "scene-candidates" / "core-requirements.txt").read_text() + viewer_requirements = (source / ".github" / "scene-candidates" / "viewer-requirements.txt").read_text() workflow = (source / ".github" / "workflows" / "scene-candidate-integration.yml").read_text() - assert "compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d" in requirements - assert "compas_viewer.git@18c87acac907c6d749d95a0e8f56ae2abd021ed2" in requirements + assert "compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d" in core_requirements + assert "compas_viewer.git@18c87acac907c6d749d95a0e8f56ae2abd021ed2" in viewer_requirements assert "branches: [c3-upgrade]" in workflow - assert "requirements.txt" in workflow + assert "core-requirements.txt" in workflow + assert "viewer-requirements.txt" in workflow + assert "--no-deps" in workflow assert "source-installed-candidates" in workflow From e0e98919c68deaa01d6fd35b9219929e4630c1a1 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 17:25:37 +0100 Subject: [PATCH 13/22] Provision graphics runtime for scene integration --- .github/workflows/scene-candidate-integration.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/scene-candidate-integration.yml b/.github/workflows/scene-candidate-integration.yml index 05a2765..77ab49c 100644 --- a/.github/workflows/scene-candidate-integration.yml +++ b/.github/workflows/scene-candidate-integration.yml @@ -25,6 +25,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false + - name: Install Linux EGL/OpenGL runtime + run: | + sudo apt-get update + sudo apt-get install --yes libegl1 python3-opengl - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" From dbeabbeb10f7c7b6bf1c63e262e92aa3a1721a8a Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 17:29:57 +0100 Subject: [PATCH 14/22] Refresh scene candidate checkpoint --- .../scene-candidates/core-requirements.txt | 2 +- .../test_scene_integration.py | 4 +-- .../scene-candidates/viewer-requirements.txt | 2 +- .../scene-viewer-visualisation/handoff.md | 25 +++++++++++-------- tests/test_package.py | 4 +-- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.github/scene-candidates/core-requirements.txt b/.github/scene-candidates/core-requirements.txt index f644eb4..27bdb96 100644 --- a/.github/scene-candidates/core-requirements.txt +++ b/.github/scene-candidates/core-requirements.txt @@ -1 +1 @@ -compas @ git+https://github.com/compas-dev/compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d +compas @ git+https://github.com/compas-dev/compas.git@38d2457861ba7122f91d2107ce11e85053105165 diff --git a/.github/scene-candidates/test_scene_integration.py b/.github/scene-candidates/test_scene_integration.py index 742f1c2..69e2f38 100644 --- a/.github/scene-candidates/test_scene_integration.py +++ b/.github/scene-candidates/test_scene_integration.py @@ -13,8 +13,8 @@ from compas_viewer import Viewer from compas_viewer.scene import ViewerScene -CORE_COMMIT = "f878cd102e87e7859030af96c7871a5b3345cf7d" -VIEWER_COMMIT = "18c87acac907c6d749d95a0e8f56ae2abd021ed2" +CORE_COMMIT = "38d2457861ba7122f91d2107ce11e85053105165" +VIEWER_COMMIT = "a0d46d4810aad1143c1af936ee98933b93f7a1b7" def _installed_commit(distribution_name: str) -> str: diff --git a/.github/scene-candidates/viewer-requirements.txt b/.github/scene-candidates/viewer-requirements.txt index 61b6673..266d97b 100644 --- a/.github/scene-candidates/viewer-requirements.txt +++ b/.github/scene-candidates/viewer-requirements.txt @@ -1 +1 @@ -compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@18c87acac907c6d749d95a0e8f56ae2abd021ed2 +compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@a0d46d4810aad1143c1af936ee98933b93f7a1b7 diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index f293d00..b3cb9be 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -7,8 +7,9 @@ Last updated: 2026-11-07 Current phase: `implementation` Status: ADRs 001–010 are Accepted. Phase 0 core and Viewer source changes are -implemented and independently approved locally; clean hosted package CI remains -to be collected before the Phase 0 exit gate is complete. +implemented and independently approved. Viewer package CI and the exact-source +framework integration gate are green; core CI is rerunning after focused patch +coverage tests were added. Read next: @@ -31,9 +32,9 @@ Read next: | Repository | Branch | Exact head | Pull request | Status | |---|---|---|---|---| -| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `ee8c4d8` plus this handoff checkpoint | [7](https://github.com/compas-dev/compas_framework/pull/7) | Clean; pushed draft | -| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `f878cd102e87e7859030af96c7871a5b3345cf7d` | [1540](https://github.com/compas-dev/compas/pull/1540) | Clean; pushed draft | -| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `18c87acac907c6d749d95a0e8f56ae2abd021ed2` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Clean; pushed draft | +| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | this handoff checkpoint | [7](https://github.com/compas-dev/compas_framework/pull/7) | Exact-source gate green before latest candidate-pin refresh | +| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `38d2457861ba7122f91d2107ce11e85053105165` | [1540](https://github.com/compas-dev/compas/pull/1540) | Full matrix green; patch coverage rerunning | +| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `a0d46d4810aad1143c1af936ee98933b93f7a1b7` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | All hosted checks green | | `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Clean; inspected only | ## Completed at this checkpoint @@ -60,12 +61,16 @@ Read next: - Adapted Viewer durable state, removed legacy settings persistence, fixed transient picking-cache lifecycle, and documented separate data binding. - Resolved all independent core and Viewer review findings. +- Added focused coverage for invalid closed Scene and SceneNode schemas. +- Added and passed an installed exact-source framework gate covering plugin + discovery, reference-only round trips, explicit rebinding, and transient + Viewer state exclusion. ## Next tasks -1. Collect clean package CI on core PR 1540 and Viewer PR 233. -2. Add the smallest framework installed-candidate Phase 0 gate. -3. Close the Phase 0 exit gate, then begin indexed-buffer implementation. +1. Confirm core patch coverage and the refreshed exact-source gate are green. +2. Close the Phase 0 exit gate. +3. Begin the Phase 1 compatibility audit and indexed-buffer implementation. ## Blockers and approval gates @@ -81,8 +86,8 @@ Evidence by layer: | Layer | Status | Evidence | |---|---|---| | Local focused checks | Passed | Core scene/glTF: 61 passed, Ruff passed, Pyright 0; Viewer focused: 50 passed, Ruff passed, Pyright 0; independent reviews approved both exact heads. | -| Package CI | Pending | Viewer PR 233 workflows are running; core PR 1540 initially reports no checks. | -| Framework integration CI | Pending | Framework PR 7 contract check is running; installed exact-candidate gate is the next task. | +| Package CI | Partial | Viewer PR 233 is fully green. Core PR 1540 has a green full OS/Python matrix, coverage, changelog, metadata, and project coverage; patch coverage is rerunning after ten additional schema-validation paths were covered. | +| Framework integration CI | Passed; refresh pending | Framework PR 7 passed contracts and the installed exact-candidate gate; the gate is rerunning against the latest test/workflow-only package heads. | | Candidate-artifact CI | Not run | Required only before claims about independently built artifacts. | Run next: diff --git a/tests/test_package.py b/tests/test_package.py index c08ffef..b626be9 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -63,8 +63,8 @@ def test_scene_candidate_integration_pins_exact_source_revisions(): viewer_requirements = (source / ".github" / "scene-candidates" / "viewer-requirements.txt").read_text() workflow = (source / ".github" / "workflows" / "scene-candidate-integration.yml").read_text() - assert "compas.git@f878cd102e87e7859030af96c7871a5b3345cf7d" in core_requirements - assert "compas_viewer.git@18c87acac907c6d749d95a0e8f56ae2abd021ed2" in viewer_requirements + assert "compas.git@38d2457861ba7122f91d2107ce11e85053105165" in core_requirements + assert "compas_viewer.git@a0d46d4810aad1143c1af936ee98933b93f7a1b7" in viewer_requirements assert "branches: [c3-upgrade]" in workflow assert "core-requirements.txt" in workflow assert "viewer-requirements.txt" in workflow From a3cf910594de27363744ed904ffac7f517cb90d4 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 18:45:55 +0100 Subject: [PATCH 15/22] Gate indexed Viewer candidate --- .../test_scene_integration.py | 20 ++++++++++++++++++- .../scene-candidates/viewer-requirements.txt | 2 +- .../scene-viewer-visualisation/handoff.md | 13 ++++++++---- tests/test_package.py | 2 +- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/scene-candidates/test_scene_integration.py b/.github/scene-candidates/test_scene_integration.py index 69e2f38..453a63d 100644 --- a/.github/scene-candidates/test_scene_integration.py +++ b/.github/scene-candidates/test_scene_integration.py @@ -6,15 +6,18 @@ import pytest from compas.colors import Color +from compas.data import json_dumps +from compas.data import json_loads from compas.geometry import Box from compas.geometry import Translation from compas.scene import Scene from compas.scene import SceneItemNotBoundError from compas_viewer import Viewer +from compas_viewer.scene import BufferGeometry from compas_viewer.scene import ViewerScene CORE_COMMIT = "38d2457861ba7122f91d2107ce11e85053105165" -VIEWER_COMMIT = "a0d46d4810aad1143c1af936ee98933b93f7a1b7" +VIEWER_COMMIT = "0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5" def _installed_commit(distribution_name: str) -> str: @@ -50,6 +53,21 @@ def test_plugin_discovery_does_not_import_graphics_modules(): subprocess.run([sys.executable, "-c", code], check=True, env=environment) +def test_indexed_buffer_geometry_stays_indexed_and_roundtrips(): + geometry = BufferGeometry.from_vertices_and_triangles( + [[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]], + [[0, 1, 2], [1, 3, 2]], + ) + + restored = json_loads(json_dumps(geometry)) + + assert isinstance(restored, BufferGeometry) + assert restored.vertices.shape == (4, 3) + assert restored.triangles is not None + assert restored.triangles.shape == (2, 3) + assert restored.triangles.tolist() == [[0, 1, 2], [1, 3, 2]] + + def test_reference_scene_roundtrip_and_explicit_binding(tmp_path): viewer = Viewer() viewer.running = False diff --git a/.github/scene-candidates/viewer-requirements.txt b/.github/scene-candidates/viewer-requirements.txt index 266d97b..ee4bfd9 100644 --- a/.github/scene-candidates/viewer-requirements.txt +++ b/.github/scene-candidates/viewer-requirements.txt @@ -1 +1 @@ -compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@a0d46d4810aad1143c1af936ee98933b93f7a1b7 +compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5 diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index b3cb9be..b238cc4 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -34,7 +34,7 @@ Read next: |---|---|---|---|---| | `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | this handoff checkpoint | [7](https://github.com/compas-dev/compas_framework/pull/7) | Exact-source gate green before latest candidate-pin refresh | | `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `38d2457861ba7122f91d2107ce11e85053105165` | [1540](https://github.com/compas-dev/compas/pull/1540) | Full matrix green; patch coverage rerunning | -| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `a0d46d4810aad1143c1af936ee98933b93f7a1b7` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | All hosted checks green | +| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Phase 1 indexed-buffer candidate pushed; CI running | | `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Clean; inspected only | ## Completed at this checkpoint @@ -65,12 +65,17 @@ Read next: - Added and passed an installed exact-source framework gate covering plugin discovery, reference-only round trips, explicit rebinding, and transient Viewer state exclusion. +- Implemented and independently approved indexed `BufferGeometry`, convenience + constructors, closed JSON persistence, preserved buffer indices, and + complete-triangle transparency partitioning. +- Reverified 36 `compas_model` Viewer/controller/plugin compatibility tests + against the Phase 1 Viewer source without modifying model code. ## Next tasks -1. Confirm core patch coverage and the refreshed exact-source gate are green. -2. Close the Phase 0 exit gate. -3. Begin the Phase 1 compatibility audit and indexed-buffer implementation. +1. Collect clean Viewer CI and exact-source framework CI for the Phase 1 head. +2. Close the Phase 1 indexed-buffer exit gate. +3. Begin Phase 2 Viewer state and selection work in dependency order. ## Blockers and approval gates diff --git a/tests/test_package.py b/tests/test_package.py index b626be9..8ab37b9 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -64,7 +64,7 @@ def test_scene_candidate_integration_pins_exact_source_revisions(): workflow = (source / ".github" / "workflows" / "scene-candidate-integration.yml").read_text() assert "compas.git@38d2457861ba7122f91d2107ce11e85053105165" in core_requirements - assert "compas_viewer.git@a0d46d4810aad1143c1af936ee98933b93f7a1b7" in viewer_requirements + assert "compas_viewer.git@0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5" in viewer_requirements assert "branches: [c3-upgrade]" in workflow assert "core-requirements.txt" in workflow assert "viewer-requirements.txt" in workflow From d9c72ff1d7b94a5ebcf41ad645899ac72735f212 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 19:10:11 +0100 Subject: [PATCH 16/22] Propose node-first scene architecture --- .../011-node-first-scene-adapters.md | 102 ++++++++++++++++++ .../012-explicit-node-backed-adapter-state.md | 79 ++++++++++++++ .../decisions/README.md | 7 +- .../scene-viewer-visualisation/handoff.md | 18 ++-- .../implementation-plan.md | 13 ++- .../scene-viewer-visualisation/proposal.md | 39 ++++++- 6 files changed, 242 insertions(+), 16 deletions(-) create mode 100644 initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md diff --git a/initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md b/initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md new file mode 100644 index 0000000..7954787 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md @@ -0,0 +1,102 @@ +# ADR 011: Node-First Scene Construction and Adapter Lifetime + +## Status + +Proposed. + +## Context + +ADR 008 correctly separates durable scene nodes from runtime adapters, but its +first implementation still constructs a detached `SceneObject` before creating +the node. The adapter temporarily owns the item reference, GUID, name, +transformation, appearance, and extension values. Binding then changes those +properties to read from the node. + +This creates two object modes, duplicate storage, and identity whose meaning +changes after binding. Verified probes show that removal can expose stale +provisional values and a different GUID. Context rebinding replaces adapters +and leaves external references detached with the same stale fallback state. +The implementation therefore contradicts ADR 008's requirement that an +adapter constructor must not own serialized state. + +## Options + +1. Create the node first and construct a permanently node-bound runtime + adapter from `(scene, node)`. +2. Retain detached and bound adapter modes while hiding the transition behind + additional helpers. +3. Put runtime drawing behavior directly on `SceneNode`. +4. Preserve detached adapters through a compatibility wrapper. + +## Recommendation + +Choose option 1. + +`SceneNode` remains the sole durable authority for identity, hierarchy, item +GUID, name, local transformation, appearance, visibility, and extension state. +`SceneObject` becomes a plain runtime adapter rather than a `Data` object. It +is constructed only from an existing scene and node and owns only context +handles, derived caches, drawing behavior, and invalidation. + +Keep the convenient public call: + +```python +sceneobject = scene.add(mesh, color=Color.red(), show=True) +``` + +Internally, `Scene.add` resolves the adapter type, validates node and extension +arguments, creates and attaches the node, records the item binding, and only +then creates `adapter_type(scene, node)`. Failure rolls back the node and item +binding atomically. + +Deserialization remains node-only. `Scene.bind_context` constructs a complete +replacement adapter table after hierarchy and required items exist, then swaps +it in atomically. Adapter construction never creates hierarchy or durable +state. + +Remove detached adapter construction, `Scene.add(sceneobject)`, adapter +serialization, adapter-owned temporary GUIDs and presentation fallbacks, and +constructor-driven child creation. Registry dispatch moves from +`SceneObject.__new__` to `Scene`. + +Removed or context-replaced adapters become invalid runtime references. They +do not transition to a detached reusable mode. Re-adding content means adding +the `Data` item or retaining and explicitly rebinding an existing node. + +## Compatibility + +This intentionally breaks direct `SceneObject(item, ...)`, +`Scene.add(sceneobject)`, reusable removed adapters, and one-shot +`SceneObject(item).draw()`. Core and Viewer tests migrate to `Scene.add`. +GhPython one-shot conversion requires a small explicit context helper or local +scene. CAD-host adapters require audit before their later migration. + +`Scene.add(data, ...)`, registry/context dispatch, durable node GUIDs, +reference-only serialization, unresolved loading, explicit item binding, and +shared item identity remain public behavior. + +Direct `Group(...)` construction and arbitrary group constructor keywords as +future child defaults are removed. `scene.add_group(...)` creates the node +first; callers pass child presentation explicitly. + +## Verification + +- Prove the node exists before adapter construction. +- Prove adapter constructors receive only scene and node. +- Prove construction and context-binding failures roll back atomically. +- Prove GUID meaning and durable property storage never switch. +- Prove removed and replaced adapters fail precisely. +- Prove deserialization and unknown extension round trips need no adapters. +- Preserve Viewer round trips and `compas_model` compatibility through the + public `Scene.add(data, ...)` path. + +## Dependencies + +- Supersedes the construction, adapter identity, and compatibility clauses of + Accepted [ADR 008](008-scene-nodes-and-runtime-adapters.md). +- Preserves Accepted [ADR 010](010-scene-description-and-item-bundling.md). +- Works with Proposed [ADR 012](012-explicit-node-backed-adapter-state.md). + +## Decision + +Pending explicit user approval. diff --git a/initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md b/initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md new file mode 100644 index 0000000..61fae33 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md @@ -0,0 +1,79 @@ +# ADR 012: Explicit Node-Backed Adapter State + +## Status + +Proposed. + +## Context + +ADR 009 correctly requires a closed base schema and explicit namespaced +extension declarations. Its implementation, however, uses +`SceneObject.__getattribute__` and `__setattr__` to scan declarations and +redirect attributes dynamically. Other durable fields use individual +node-or-local properties, and color uses a special descriptor. The result is +three different state-routing mechanisms whose behavior changes when an +adapter binds to a node. + +The declarations should define persistence and validation, not invisibly +change normal Python attribute access. + +## Options + +1. Keep declarations as schema metadata and implement ordinary explicit + node-backed adapter properties. +2. Replace interception with a general descriptor or state-proxy framework. +3. Store durable adapter state in a third state object. +4. Keep the current interception and add documentation. + +## Recommendation + +Choose option 1. + +Keep `SceneStateField`-style declarations only for stable names, namespaces, +types, defaults, required fields, validation, and preservation of unknown +extension state. `Scene.add` validates declared keyword arguments and writes +them directly to `SceneNode.extensions`. Deserialization validates known state +without constructing adapters. + +Adapters expose ordinary properties whose implementation visibly reads and +writes the node. A small typed `SceneNode.extension(namespace, field)` and +`set_extension(...)` helper may remove repetitive mapping access. Do not add a +general descriptor, proxy, reflection layer, or global attribute interception. +Property setters perform required invalidation explicitly. + +Remove extension capture/apply operations, declaration-driven +`__getattribute__`/`__setattr__`, detached attribute validation, and all local +durable fallbacks. Base properties such as name, transformation, color, +opacity, and visibility are likewise direct node-backed properties on an +always-bound adapter. + +## Consequences + +- Durable state has one storage location and one visible access path. +- Persistence remains explicit and reviewable. +- Adapter classes contain some repetitive properties, which is preferable to + hidden control flow. +- Unknown namespaced state remains serializable without importing its adapter. +- Constructor signatures no longer double as persistence or editor schemas. + +## Verification + +- Prove each declared property reads and writes its node extension. +- Prove setters trigger their documented cache invalidation. +- Reject unknown, missing, duplicate, and invalid declared fields precisely. +- Preserve unknown namespaces without adapter imports. +- Prove caches, selection, context handles, and construction commands are not + durable. +- Assert no runtime adapter class uses persistence interception or capture. + +## Dependencies + +- Supersedes the runtime interception and capture mechanism introduced under + Accepted [ADR 009](009-scene-state-fields.md), while retaining its closed + schema and explicit declarations. +- Depends on Proposed [ADR 011](011-node-first-scene-adapters.md). +- Preserves Accepted [ADR 010](010-scene-description-and-item-bundling.md). + +## Decision + +Pending explicit user approval. diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index 920458f..d3beb85 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -1,7 +1,8 @@ # Scene, Viewer, and Visualisation Decisions -ADRs 001–010 are Accepted. ADR 010 records the scene/data serialization and -future Session aggregation boundary approved on 2026-11-07. +ADRs 001–010 are Accepted. ADRs 011–012 are Proposed architecture corrections +after the Phase 0 implementation exposed a dual adapter lifecycle and hidden +state routing that conflict with the initiative's simplicity rule. | ADR | Decision | Status | Dependencies | |---|---|---|---| @@ -15,6 +16,8 @@ future Session aggregation boundary approved on 2026-11-07. | 008 | [Serializable scene nodes and runtime adapters](008-scene-nodes-and-runtime-adapters.md) | Accepted | 001; verified round-trip regressions | | 009 | [Explicit scene-state serialization fields](009-scene-state-fields.md) | Accepted | 008 | | 010 | [Scene description, item bindings, and aggregation boundary](010-scene-description-and-item-bundling.md) | Accepted | 008, 009 | +| 011 | [Node-first scene construction and adapter lifetime](011-node-first-scene-adapters.md) | Proposed | Supersedes parts of 008; preserves 010 | +| 012 | [Explicit node-backed adapter state](012-explicit-node-backed-adapter-state.md) | Proposed | 011; supersedes implementation mechanism of 009 | ADRs 008–010 were accepted on 2026-11-07. ADR 010 refines ADR 008's item store into non-owning runtime bindings and keeps aggregation outside Scene. A diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index b238cc4..9116b44 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -4,12 +4,12 @@ Last updated: 2026-11-07 ## Resume here -Current phase: `implementation` +Current phase: `architecture correction` -Status: ADRs 001–010 are Accepted. Phase 0 core and Viewer source changes are -implemented and independently approved. Viewer package CI and the exact-source -framework integration gate are green; core CI is rerunning after focused patch -coverage tests were added. +Status: ADRs 001–010 are Accepted; ADRs 011–012 are Proposed. Phase 1 indexed +buffers are complete and green. Phase 2 is paused because implementation +evidence showed that the current detached/bound adapter lifecycle and dynamic +state interception violate the clean, simple, transparent design rule. Read next: @@ -22,7 +22,7 @@ Read next: - Accepted: [ADRs 001–010](decisions/README.md), including ADRs 008–010 on 2026-11-07. -- Proposed or unresolved: none. +- Proposed: ADR 011 node-first adapters and ADR 012 explicit node-backed state. - Scope boundary: `compas_model`, notebook, and CAD hosts are later or compatibility consumers; `compas_session` requires an explicit inclusion decision. Do not modify package source outside the initial scope, merge, or @@ -73,9 +73,9 @@ Read next: ## Next tasks -1. Collect clean Viewer CI and exact-source framework CI for the Phase 1 head. -2. Close the Phase 1 indexed-buffer exit gate. -3. Begin Phase 2 Viewer state and selection work in dependency order. +1. Obtain explicit decisions on Proposed ADRs 011–012. +2. If accepted, implement and independently verify the architecture correction. +3. Resume Phase 2 Viewer state and selection work only after that gate passes. ## Blockers and approval gates diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 15bf0b3..7af60ec 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,8 +2,9 @@ ## Status -Architecture approved. ADRs 001–010 are Accepted; implementation may proceed -in dependency order within the approved initial scope. +Architecture correction pending. ADRs 001–010 are Accepted; ADRs 011–012 are +Proposed after implementation evidence exposed a dual adapter lifecycle and +hidden state routing. Phase 2 is paused pending explicit approval. ## Dependency graph @@ -22,7 +23,8 @@ ADRs 001–010 ----------> ADR 007 rollout gate Governing ADRs: 001, 008, 009, and 010. -Status: authorized. +Status: implemented, but subject to the Proposed ADR 011–012 correction before +Phase 2 proceeds. 1. Add the verified Viewer round-trip regression and a minimal core adapter test covering the constructor-before-attachment failure. Keep the actual @@ -51,7 +53,7 @@ checks pass. Governing ADRs: 001, 002, 007, 008, 009, and 010. -Status: paused until Phase 0 and its approval gate are complete. +Status: implemented and verified. 1. Audit compatibility-only consumers for affected core scene contracts and stop for approval if a required core change would break them. @@ -67,6 +69,9 @@ large-indexed-input evidence passes at exact candidate heads. Governing ADRs: 001, 003, 004, 007, 008, and 009. +Status: paused until ADRs 011–012 are resolved and the approved scene +architecture correction is implemented and verified. + 1. Separate persistent Viewer configuration from transient Viewer state. 2. Implement the object-selection model and migrate viewport, rectangle, tree, commands, renderer settings, and programmatic Viewer APIs. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index b7d4a65..99c9f9a 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -358,6 +358,41 @@ Core geometry, typing, plugin, and repository-modernisation decisions remain upstream constraints. Implementation starts only after all ADRs required for a wave are Accepted. +## Architecture correction after Phase 1 + +Implementation evidence invalidates the detached/bound adapter mechanism used +for the first implementation of ADRs 008–009. The separation between durable +nodes and runtime adapters remains correct, but constructing an adapter before +its node creates duplicate provisional state, changes GUID meaning at binding, +and requires hidden attribute interception. Removal and context replacement +can expose stale provisional values on old adapter references. + +The proposed correction keeps the public convenience of +`scene.add(data, ...)` but changes its internal order: + +1. resolve the adapter class; +2. validate base and explicitly declared extension arguments; +3. create and attach the durable node; +4. bind the independently owned data item; and +5. construct a plain runtime adapter from `(scene, node)`. + +The adapter never exists detached, never owns durable fallbacks, never changes +identity, and is not a `Data` object. Explicit ordinary properties access node +state. Field declarations remain persistence/validation metadata but do not +intercept Python attribute access. Context rebinding atomically replaces the +adapter table; stale adapters become invalid rather than transitioning into a +second reusable mode. + +This deliberately removes direct `SceneObject(item, ...)`, +`Scene.add(sceneobject)`, reusable removed adapters, direct `Group(...)`, +arbitrary group child defaults, and constructor-driven hierarchy. CAD-host +one-shot drawing and registered adapter constructors require later migration, +but the primary `Scene.add(data, ...)` path remains. + +Proposed ADR 011 records construction and lifetime. Proposed ADR 012 records +explicit node-backed state. Phase 2 remains paused until both decisions are +resolved and, if accepted, implemented and verified. + ## Decision record 1. [ADR 001 — Ownership and state boundaries](decisions/001-ownership-boundaries.md) @@ -370,5 +405,7 @@ wave are Accepted. 8. [ADR 008 — Serializable scene nodes and runtime adapters](decisions/008-scene-nodes-and-runtime-adapters.md) 9. [ADR 009 — Explicit scene-state serialization fields](decisions/009-scene-state-fields.md) 10. [ADR 010 — Scene description, item bindings, and aggregation boundary](decisions/010-scene-description-and-item-bundling.md) +11. [ADR 011 — Node-first scene construction and adapter lifetime](decisions/011-node-first-scene-adapters.md) +12. [ADR 012 — Explicit node-backed adapter state](decisions/012-explicit-node-backed-adapter-state.md) -ADRs 001–010 are Accepted. +ADRs 001–010 are Accepted. ADRs 011–012 are Proposed. From d50d7b63bcbe5381c4c116eff30d90519fd70938 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 19:27:58 +0100 Subject: [PATCH 17/22] Propose stable scene objects and operation plugins --- ...hierarchy-nodes-and-stable-sceneobjects.md | 123 +++++++++++++++++ .../014-context-keyed-scene-operations.md | 126 ++++++++++++++++++ .../decisions/README.md | 7 +- .../scene-viewer-visualisation/handoff.md | 15 ++- .../implementation-plan.md | 11 +- .../scene-viewer-visualisation/proposal.md | 68 +++++----- 6 files changed, 305 insertions(+), 45 deletions(-) create mode 100644 initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md diff --git a/initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md b/initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md new file mode 100644 index 0000000..d00e32e --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md @@ -0,0 +1,123 @@ +# ADR 013: Hierarchy-Only Nodes and Stable Scene Objects + +## Status + +Proposed. + +## Context + +Accepted ADR 008 separated durable scene nodes from runtime adapters, but the +implementation duplicated state across detached and bound adapter modes. +Proposed ADR 011 removes that dual lifecycle, but still makes `SceneNode` own +both hierarchy and all durable visual state while `SceneObject` is only a +runtime projection. This leaves two public concepts that appear to describe +the same scene entry and makes backend-specific replacement classes central to +ordinary object access. + +A simpler separation is possible: nodes describe only hierarchy; stable scene +objects describe everything durable about a visualized item; backends provide +operations rather than replacement object classes. + +## Options + +1. Use hierarchy-only nodes and durable, stable scene objects. +2. Keep durable state on nodes and make scene objects always-bound adapters as + proposed by ADRs 011–012. +3. Merge hierarchy and durable state back into one tree-node class. +4. Keep the implemented detached/bound adapter model. + +## Recommendation + +Choose option 1. + +`SceneObject` is a backend-neutral `Data` object with a stable Python type and +GUID. It owns: + +- the referenced item GUID, if any; +- name and local transformation; +- visibility, opacity, and durable backend-neutral appearance; and +- stable semantic type-specific state. + +Stable subclasses such as `GroupObject`, `GeometryObject`, `ShapeObject`, +`MeshObject`, `GraphObject`, and `VolMeshObject` express durable semantics. +Installing Viewer, Rhino, Blender, or another backend never changes an +object's class. + +`SceneNode` owns only ordered parent/child relationships and a reference to one +scene-object GUID. Enforce exactly one node per scene object in one scene. +Instancing is not included. Multiple appearances of one data item use multiple +scene objects referencing the same item GUID. + +Do not serialize a second durable node GUID. The scene-object GUID is the +hierarchy key. The root is an ordinary `GroupObject` with a corresponding root +node rather than a special identity model. + +`Scene` owns separate object and hierarchy stores. `scene.add(item, **state)` +creates the stable semantic scene object, attaches its hierarchy node, and +returns the object. `scene.add_object(sceneobject, parent=...)` explicitly +attaches an existing durable scene object; `Scene.add` is not overloaded with +runtime adapters. + +Scene serialization contains a version, name, stable scene-object records, +and a hierarchy of scene-object GUID references. Referenced `Data` items remain +external under ADR 010. Loading requires no visualization backend and leaves +item references unresolved until explicitly bound. + +Durable type-specific state follows ADR 009's useful rule: a closed base schema +plus explicit fields. State lives as ordinary `SceneObject` attributes, not in +node extensions and not behind attribute interception. Unknown namespaced +state may be retained solely for lossless forward round trips. Backend plugins +may not add durable fields. + +Selection, picking, UI state, renderer configuration, generated buffers, +handles, and caches remain runtime/application state outside `SceneObject`. + +## Consequences + +- Nodes, scene objects, represented data, and backend operations have distinct + and explainable roles. +- Scene-object type and GUID remain stable through attachment, removal, + serialization, and context changes. +- A durable scene object may exist detached without acquiring a second storage + mode; attachment adds only a nonserialized scene backreference. +- Removing and explicitly reattaching an object never reveals stale fallback + values or changes identity. +- The scene schema changes from nested stateful nodes to object records plus a + hierarchy of references. +- Backend-specific replacement classes are removed under ADR 014. + +## Compatibility + +Preserve `scene.add(data, ...)`, shared item identity, unresolved scene loading, +explicit item binding, stable object GUIDs, and hierarchy operations through +returned scene objects. + +Remove backend adapter serialization, constructor-driven child creation, and +implicit group child defaults. `GroupObject` is durable and backend-neutral. +`compas_model`'s maintained controller path already uses `scene.add`; its custom +scene-object redesign remains a later phase. + +## Verification + +- Prove nodes serialize only hierarchy references. +- Prove one node per scene object and reject accidental instancing. +- Preserve scene-object GUIDs through add, move, remove, reattach, reload, and + visualization-context changes. +- Prove durable state has one storage location. +- Load, inspect, edit, and serialize a scene without backend plugins. +- Bind independently loaded items with shared identity. +- Round-trip multiple scene objects referencing one item. +- Exclude selection, handles, buffers, caches, and context from serialization. + +## Dependencies + +- Intended to supersede Accepted ADR 008 and ADR 009's placement of extension + state if approved. +- Retains ADR 009's closed-schema principle. +- Preserves Accepted ADR 010, with item references moving from nodes to scene + objects. +- Works with Proposed [ADR 014](014-context-keyed-scene-operations.md). + +## Decision + +Pending explicit user approval. diff --git a/initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md b/initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md new file mode 100644 index 0000000..6a2c3eb --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md @@ -0,0 +1,126 @@ +# ADR 014: Context-Keyed Scene Operation Plugins + +## Status + +Proposed. + +## Context + +Current visualization plugins register replacement `SceneObject` subclasses by +represented item type and context. `SceneObject.__new__` may therefore return a +Viewer, Rhino, Blender, Grasshopper, or Notebook subclass. This changes object +type based on installed plugins and mixes durable scene semantics with backend +runtime behavior. + +The general COMPAS pluggable dispatcher identifies extension points globally +by domain, category, and function name. It does not select an implementation +from a call's explicit context or represented object type. Directly registering +multiple `draw` plugins would therefore conflict when several backends are +installed. + +## Options + +1. Register operation functions in a small scene-specific registry keyed by + context, stable scene-object type, and operation. +2. Extend the general plugin manager with argument-aware dispatch. +3. Use one global backend plugin that switches internally on context and type. +4. Retain backend-specific replacement classes. + +## Recommendation + +Choose option 1. + +Backend packages expose lightweight registration plugins that register +functions rather than classes: + +```python +register_scene_operation( + context="Viewer", + sceneobject_type=MeshObject, + operation="draw", + implementation=draw_meshobject, +) +``` + +Lookup is deterministic by `(context, scene-object type MRO, operation)`. +Duplicate registrations for one exact key fail clearly. Heavy Qt, OpenGL, +Rhino, Blender, or other host imports remain inside operation bodies. + +The initial public operation surface is only: + +- `draw`; +- `clear`. + +Backend-private buffer extraction, host-object creation, component drawing, +refresh strategies, and cache structures do not become speculative public +operations. Additional operations require demonstrated cross-backend need and +approval. + +Conceptually: + +```python +scene.draw(context="Viewer", runtime=viewer) +meshobject.draw(context="Viewer", runtime=viewer) +``` + +The selected implementation receives the owning scene, stable scene object, +and optional transient backend runtime. It may return opaque handles. Runtime +resources live in a nonserialized context store keyed by context and +scene-object GUID, never on the durable object. + +There is no adapter-binding phase. Changing context selects different +operations and resources without replacing scene objects. Automatic context +selection is permitted only when exactly one compatible context is available. +Missing operations report context, scene-object type, and operation. + +Keep the general COMPAS plugin manager unchanged. Its existing lightweight +`register_scene_objects` pattern may be renamed or replaced by +`register_scene_operations`, but discovery must remain graphics-free. + +## Consequences + +- Several visualization backends can coexist without class or plugin + conflicts. +- Backend implementations become ordinary functions with explicit inputs. +- Stable scene-object classes remain backend-neutral. +- Runtime ownership is explicit and serialization-safe. +- Viewer requires a coordinated migration because its renderer currently + consumes concrete `ViewerSceneObject` buffer APIs rather than only `draw`. +- CAD, notebook, robots, and domain backends require later coordinated + migrations before they are admitted as compatible C3 candidates. + +## Compatibility + +Remove context-specific scene-object class registration, +`SceneObject(item, context=...)` factory substitution, `sceneobject_type=`, +`Scene.bind_context`, and direct one-shot `SceneObject(item).draw()`. + +Preserve explicit context selection, automatic selection when unambiguous, +graphics-free plugin discovery, `scene.add(data, ...)`, and deterministic +resource clearing. + +The initial coordinated implementation remains core, Viewer, and framework. +Other backends are recorded as incompatible until migrated; no compatibility +factory should retain type substitution. + +## Verification + +- Install Viewer and a fake second backend simultaneously and select each + explicitly. +- Verify deterministic MRO fallback and duplicate-registration errors. +- Verify missing-operation diagnostics. +- Prove discovery imports no graphics modules. +- Prove context changes never replace or mutate durable scene objects. +- Prove draw/clear resource handling does not enter serialized state. +- Preserve indexed Viewer buffers, picking by stable scene-object GUID, and + exact-candidate framework integration. + +## Dependencies + +- Depends on Proposed [ADR 013](013-hierarchy-nodes-and-stable-sceneobjects.md). +- Replaces context-specific class registration if approved. +- Leaves the general plugin dispatcher unchanged. + +## Decision + +Pending explicit user approval. diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index d3beb85..4293194 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -1,8 +1,9 @@ # Scene, Viewer, and Visualisation Decisions ADRs 001–010 are Accepted. ADRs 011–012 are Proposed architecture corrections -after the Phase 0 implementation exposed a dual adapter lifecycle and hidden -state routing that conflict with the initiative's simplicity rule. +to the implemented node/adapter split. ADRs 013–014 are the newer preferred +alternative: hierarchy-only nodes, stable durable scene objects, and +context-keyed operation plugins instead of backend replacement classes. | ADR | Decision | Status | Dependencies | |---|---|---|---| @@ -18,6 +19,8 @@ state routing that conflict with the initiative's simplicity rule. | 010 | [Scene description, item bindings, and aggregation boundary](010-scene-description-and-item-bundling.md) | Accepted | 008, 009 | | 011 | [Node-first scene construction and adapter lifetime](011-node-first-scene-adapters.md) | Proposed | Supersedes parts of 008; preserves 010 | | 012 | [Explicit node-backed adapter state](012-explicit-node-backed-adapter-state.md) | Proposed | 011; supersedes implementation mechanism of 009 | +| 013 | [Hierarchy-only nodes and stable scene objects](013-hierarchy-nodes-and-stable-sceneobjects.md) | Proposed, preferred | Intended to supersede 008/009 placement; preserves 010 | +| 014 | [Context-keyed scene operation plugins](014-context-keyed-scene-operations.md) | Proposed, preferred | 013; replaces backend class registration | ADRs 008–010 were accepted on 2026-11-07. ADR 010 refines ADR 008's item store into non-owning runtime bindings and keeps aggregation outside Scene. A diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 9116b44..5067749 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -6,10 +6,10 @@ Last updated: 2026-11-07 Current phase: `architecture correction` -Status: ADRs 001–010 are Accepted; ADRs 011–012 are Proposed. Phase 1 indexed -buffers are complete and green. Phase 2 is paused because implementation -evidence showed that the current detached/bound adapter lifecycle and dynamic -state interception violate the clean, simple, transparent design rule. +Status: ADRs 001–010 are Accepted. ADRs 011–012 remain unresolved alternatives; +ADRs 013–014 are the preferred Proposed correction. Phase 1 indexed buffers +are complete and green. Phase 2 is paused because the current design duplicates +state and lets installed backends change scene-object types. Read next: @@ -22,7 +22,9 @@ Read next: - Accepted: [ADRs 001–010](decisions/README.md), including ADRs 008–010 on 2026-11-07. -- Proposed: ADR 011 node-first adapters and ADR 012 explicit node-backed state. +- Proposed alternatives: ADRs 011–012. +- Proposed and preferred: ADR 013 hierarchy-only nodes and stable scene objects; + ADR 014 context-keyed operation plugins. - Scope boundary: `compas_model`, notebook, and CAD hosts are later or compatibility consumers; `compas_session` requires an explicit inclusion decision. Do not modify package source outside the initial scope, merge, or @@ -73,7 +75,8 @@ Read next: ## Next tasks -1. Obtain explicit decisions on Proposed ADRs 011–012. +1. Obtain explicit decisions on preferred Proposed ADRs 013–014 and their + disposition of ADRs 008–009 and 011–012. 2. If accepted, implement and independently verify the architecture correction. 3. Resume Phase 2 Viewer state and selection work only after that gate passes. diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 7af60ec..0ee7be3 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,9 +2,10 @@ ## Status -Architecture correction pending. ADRs 001–010 are Accepted; ADRs 011–012 are -Proposed after implementation evidence exposed a dual adapter lifecycle and -hidden state routing. Phase 2 is paused pending explicit approval. +Architecture correction pending. ADRs 001–010 are Accepted. ADRs 011–012 are +unresolved alternatives; ADRs 013–014 are the preferred Proposed correction +after implementation evidence exposed duplicate ownership, hidden state +routing, and backend-dependent object types. Phase 2 is paused. ## Dependency graph @@ -23,7 +24,7 @@ ADRs 001–010 ----------> ADR 007 rollout gate Governing ADRs: 001, 008, 009, and 010. -Status: implemented, but subject to the Proposed ADR 011–012 correction before +Status: implemented, but subject to the Proposed ADR 013–014 correction before Phase 2 proceeds. 1. Add the verified Viewer round-trip regression and a minimal core adapter @@ -69,7 +70,7 @@ large-indexed-input evidence passes at exact candidate heads. Governing ADRs: 001, 003, 004, 007, 008, and 009. -Status: paused until ADRs 011–012 are resolved and the approved scene +Status: paused until ADRs 013–014 are resolved and the approved scene architecture correction is implemented and verified. 1. Separate persistent Viewer configuration from transient Viewer state. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index 99c9f9a..e3d6079 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -361,37 +361,38 @@ wave are Accepted. ## Architecture correction after Phase 1 Implementation evidence invalidates the detached/bound adapter mechanism used -for the first implementation of ADRs 008–009. The separation between durable -nodes and runtime adapters remains correct, but constructing an adapter before -its node creates duplicate provisional state, changes GUID meaning at binding, -and requires hidden attribute interception. Removal and context replacement -can expose stale provisional values on old adapter references. - -The proposed correction keeps the public convenience of -`scene.add(data, ...)` but changes its internal order: - -1. resolve the adapter class; -2. validate base and explicitly declared extension arguments; -3. create and attach the durable node; -4. bind the independently owned data item; and -5. construct a plain runtime adapter from `(scene, node)`. - -The adapter never exists detached, never owns durable fallbacks, never changes -identity, and is not a `Data` object. Explicit ordinary properties access node -state. Field declarations remain persistence/validation metadata but do not -intercept Python attribute access. Context rebinding atomically replaces the -adapter table; stale adapters become invalid rather than transitioning into a -second reusable mode. - -This deliberately removes direct `SceneObject(item, ...)`, -`Scene.add(sceneobject)`, reusable removed adapters, direct `Group(...)`, -arbitrary group child defaults, and constructor-driven hierarchy. CAD-host -one-shot drawing and registered adapter constructors require later migration, -but the primary `Scene.add(data, ...)` path remains. - -Proposed ADR 011 records construction and lifetime. Proposed ADR 012 records -explicit node-backed state. Phase 2 remains paused until both decisions are -resolved and, if accepted, implemented and verified. +for the first implementation of ADRs 008–009. It duplicates provisional and +node state, changes GUID meaning at binding, and requires hidden attribute +interception. Removal and context replacement can expose stale values on old +adapter references. Backend class substitution adds another ambiguity: the +type returned for one scene entry depends on which visualization plugins are +installed and selected. + +The preferred correction assigns one purpose to each concept: + +- `SceneNode` stores only ordered hierarchy through a scene-object GUID; +- stable backend-neutral `SceneObject` values own item references, identity, + transformation, appearance, visibility, and semantic type-specific state; +- independently serialized `Data` items remain external and bind by GUID; and +- visualization backends register context-keyed `draw` and `clear` functions + rather than replacement scene-object classes. + +`scene.add(data, ...)` remains the primary convenience path and returns the +stable scene object. One node is allowed per scene object; repeated appearances +of one item use multiple scene objects. The scene-object GUID is the hierarchy +key, so there is no second durable node identity. A scene serializes stable +object records plus a hierarchy of GUID references and loads without any +backend installed. + +The general COMPAS plugin dispatcher cannot select a `draw` implementation +from an invocation's explicit visualization context. The preferred design does +not complicate it. Lightweight discovery plugins populate a small scene +operation registry keyed by `(context, scene-object type, operation)`. Runtime +buffers, host handles, picking state, and caches live outside durable objects. + +Proposed ADRs 011–012 record the first node-first alternative. Proposed ADRs +013–014 record this newer preferred design. Phase 2 remains paused until the +preferred decisions are resolved and, if accepted, implemented and verified. ## Decision record @@ -407,5 +408,8 @@ resolved and, if accepted, implemented and verified. 10. [ADR 010 — Scene description, item bindings, and aggregation boundary](decisions/010-scene-description-and-item-bundling.md) 11. [ADR 011 — Node-first scene construction and adapter lifetime](decisions/011-node-first-scene-adapters.md) 12. [ADR 012 — Explicit node-backed adapter state](decisions/012-explicit-node-backed-adapter-state.md) +13. [ADR 013 — Hierarchy-only nodes and stable scene objects](decisions/013-hierarchy-nodes-and-stable-sceneobjects.md) +14. [ADR 014 — Context-keyed scene operation plugins](decisions/014-context-keyed-scene-operations.md) -ADRs 001–010 are Accepted. ADRs 011–012 are Proposed. +ADRs 001–010 are Accepted. ADRs 011–014 are Proposed; ADRs 013–014 are the +preferred alternative. From 009301081a4c328e99d1ca3d57b43d8928099cf2 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 21:50:06 +0100 Subject: [PATCH 18/22] Accept stable scene architecture --- .../scene-viewer-visualisation/README.md | 7 ++++--- .../008-scene-nodes-and-runtime-adapters.md | 7 ++++++- .../decisions/009-scene-state-fields.md | 6 +++++- ...010-scene-description-and-item-bundling.md | 6 ++++++ .../011-node-first-scene-adapters.md | 4 ++-- .../012-explicit-node-backed-adapter-state.md | 4 ++-- ...hierarchy-nodes-and-stable-sceneobjects.md | 6 ++++-- .../014-context-keyed-scene-operations.md | 6 ++++-- .../decisions/README.md | 20 +++++++++---------- .../scene-viewer-visualisation/handoff.md | 19 +++++++++--------- .../implementation-plan.md | 13 ++++++------ .../scene-viewer-visualisation/objective.md | 7 ++++--- .../scene-viewer-visualisation/proposal.md | 16 +++++++-------- 13 files changed, 70 insertions(+), 51 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/README.md b/initiatives/scene-viewer-visualisation/README.md index cdc18f3..6a949d4 100644 --- a/initiatives/scene-viewer-visualisation/README.md +++ b/initiatives/scene-viewer-visualisation/README.md @@ -3,7 +3,7 @@ This initiative aligns backend-neutral scene infrastructure with Viewer rendering, interaction, state, and UI composition. -Current phase: **architecture amendment proposed; implementation paused**. +Current phase: **architecture correction approved; implementation pending**. - [Objective](objective.md) - [Inventory](inventory.md) @@ -12,8 +12,9 @@ Current phase: **architecture amendment proposed; implementation paused**. - [Implementation plan](implementation-plan.md) - [Current handoff](handoff.md) -ADRs 001–010 are Accepted. Scene is reference-only and optional aggregation is -reserved for a separate future Session design. +ADRs 013–014 are Accepted and define hierarchy-only nodes, stable durable scene +objects, and context-keyed operation plugins. Scene remains reference-only and +optional aggregation is reserved for a separate future Session design. The refined initial package scope is `compas`, `compas_viewer`, and `compas_framework`. The current `compas_model.ModelViewer` is draft evidence diff --git a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md index 321ed04..ea845f3 100644 --- a/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md +++ b/initiatives/scene-viewer-visualisation/decisions/008-scene-nodes-and-runtime-adapters.md @@ -2,7 +2,7 @@ ## Status -Accepted. +Superseded by ADRs 013–014. ## Context @@ -173,3 +173,8 @@ Accepted on 2026-11-07. The user additionally required a separate decision ensuring that independently serializable `Data` objects are not forced to live inside a scene. Accepted ADR 010 records that packaging refinement without changing this decision's accepted node/adapter separation. + +Superseded on 2026-11-07 after implementation exposed duplicate detached/bound +state and backend-dependent object types. Accepted ADRs 013–014 retain +backend-independent loading and reference-only data binding while assigning +durable state to stable scene objects and backend behavior to operations. diff --git a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md index e2a0600..93752df 100644 --- a/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md +++ b/initiatives/scene-viewer-visualisation/decisions/009-scene-state-fields.md @@ -2,7 +2,7 @@ ## Status -Accepted. +Superseded in part by ADR 013. ## Context @@ -107,3 +107,7 @@ Later redesign/regression consumer: `compas_model`. Accepted on 2026-11-07. Persistent fields use the closed base schema and explicit MRO-composed declarations described above. Item ownership and serialization packaging are decided separately by Accepted ADR 010. + +Superseded in part on 2026-11-07. Accepted ADR 013 retains the closed-schema, +explicit-field principle but moves durable state from node extensions onto +ordinary stable scene-object attributes and rejects attribute interception. diff --git a/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md b/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md index 048538a..0b7fe72 100644 --- a/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md +++ b/initiatives/scene-viewer-visualisation/decisions/010-scene-description-and-item-bundling.md @@ -136,3 +136,9 @@ notebook, and CAD-host integrations as applicable. - [ADR 008](008-scene-nodes-and-runtime-adapters.md) - [ADR 009](009-scene-state-fields.md) + +## Amendment + +Accepted ADR 013 amended this decision on 2026-11-07: item GUID references live +on stable scene objects rather than hierarchy nodes. Items remain independently +serializable, explicitly bound, and outside the serialized scene description. diff --git a/initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md b/initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md index 7954787..8980f81 100644 --- a/initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md +++ b/initiatives/scene-viewer-visualisation/decisions/011-node-first-scene-adapters.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Superseded by ADRs 013–014 before acceptance. ## Context @@ -99,4 +99,4 @@ first; callers pass child presentation explicitly. ## Decision -Pending explicit user approval. +Not accepted. Superseded on 2026-11-07 by Accepted ADRs 013–014. diff --git a/initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md b/initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md index 61fae33..3f41682 100644 --- a/initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md +++ b/initiatives/scene-viewer-visualisation/decisions/012-explicit-node-backed-adapter-state.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Superseded by ADR 013 before acceptance. ## Context @@ -76,4 +76,4 @@ always-bound adapter. ## Decision -Pending explicit user approval. +Not accepted. Superseded on 2026-11-07 by Accepted ADR 013. diff --git a/initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md b/initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md index d00e32e..c57b732 100644 --- a/initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md +++ b/initiatives/scene-viewer-visualisation/decisions/013-hierarchy-nodes-and-stable-sceneobjects.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context @@ -120,4 +120,6 @@ scene-object redesign remains a later phase. ## Decision -Pending explicit user approval. +Accepted on 2026-11-07. The user approved hierarchy-only nodes, stable durable +scene objects, one-to-one node/object cardinality without instancing, and the +scene-object GUID as the sole durable hierarchy key. diff --git a/initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md b/initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md index 6a2c3eb..6e50e8a 100644 --- a/initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md +++ b/initiatives/scene-viewer-visualisation/decisions/014-context-keyed-scene-operations.md @@ -2,7 +2,7 @@ ## Status -Proposed. +Accepted. ## Context @@ -123,4 +123,6 @@ factory should retain type substitution. ## Decision -Pending explicit user approval. +Accepted on 2026-11-07. The user approved context-keyed operation functions, +the initial `draw`/`clear` surface, backend-neutral durable state, and +coordinated later migration of visualization hosts. diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index 4293194..9bce4cc 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -1,9 +1,9 @@ # Scene, Viewer, and Visualisation Decisions -ADRs 001–010 are Accepted. ADRs 011–012 are Proposed architecture corrections -to the implemented node/adapter split. ADRs 013–014 are the newer preferred -alternative: hierarchy-only nodes, stable durable scene objects, and -context-keyed operation plugins instead of backend replacement classes. +ADRs 013–014 are Accepted and supersede the implemented node/runtime-adapter +model of ADR 008, part of ADR 009, and the unaccepted alternatives in ADRs +011–012. ADR 010 remains Accepted with item references moved to stable scene +objects. | ADR | Decision | Status | Dependencies | |---|---|---|---| @@ -14,13 +14,13 @@ context-keyed operation plugins instead of backend replacement classes. | 005 | [Annotations, measurements, and overlays](005-annotations-and-overlays.md) | Accepted | 001, 002, 003 | | 006 | [Public Viewer integration facade](006-viewer-integration-facade.md) | Accepted | 001, 003, 004, 005 | | 007 | [Initial scope and verification](007-scope-and-verification.md) | Accepted | 001–006; Plugin 005 | -| 008 | [Serializable scene nodes and runtime adapters](008-scene-nodes-and-runtime-adapters.md) | Accepted | 001; verified round-trip regressions | -| 009 | [Explicit scene-state serialization fields](009-scene-state-fields.md) | Accepted | 008 | +| 008 | [Serializable scene nodes and runtime adapters](008-scene-nodes-and-runtime-adapters.md) | Superseded by 013–014 | 001; verified round-trip regressions | +| 009 | [Explicit scene-state serialization fields](009-scene-state-fields.md) | Superseded in part by 013 | 008 | | 010 | [Scene description, item bindings, and aggregation boundary](010-scene-description-and-item-bundling.md) | Accepted | 008, 009 | -| 011 | [Node-first scene construction and adapter lifetime](011-node-first-scene-adapters.md) | Proposed | Supersedes parts of 008; preserves 010 | -| 012 | [Explicit node-backed adapter state](012-explicit-node-backed-adapter-state.md) | Proposed | 011; supersedes implementation mechanism of 009 | -| 013 | [Hierarchy-only nodes and stable scene objects](013-hierarchy-nodes-and-stable-sceneobjects.md) | Proposed, preferred | Intended to supersede 008/009 placement; preserves 010 | -| 014 | [Context-keyed scene operation plugins](014-context-keyed-scene-operations.md) | Proposed, preferred | 013; replaces backend class registration | +| 011 | [Node-first scene construction and adapter lifetime](011-node-first-scene-adapters.md) | Superseded before acceptance | 008; 010 | +| 012 | [Explicit node-backed adapter state](012-explicit-node-backed-adapter-state.md) | Superseded before acceptance | 011 | +| 013 | [Hierarchy-only nodes and stable scene objects](013-hierarchy-nodes-and-stable-sceneobjects.md) | Accepted | Supersedes 008/009 placement; preserves 010 | +| 014 | [Context-keyed scene operation plugins](014-context-keyed-scene-operations.md) | Accepted | 013; replaces backend class registration | ADRs 008–010 were accepted on 2026-11-07. ADR 010 refines ADR 008's item store into non-owning runtime bindings and keeps aggregation outside Scene. A diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 5067749..b3d533f 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -6,10 +6,10 @@ Last updated: 2026-11-07 Current phase: `architecture correction` -Status: ADRs 001–010 are Accepted. ADRs 011–012 remain unresolved alternatives; -ADRs 013–014 are the preferred Proposed correction. Phase 1 indexed buffers -are complete and green. Phase 2 is paused because the current design duplicates -state and lets installed backends change scene-object types. +Status: ADRs 013–014 are Accepted. ADRs 008–009 and the unaccepted alternatives +011–012 are superseded as recorded in the decision index. Phase 1 indexed +buffers are complete and green. Phase 2 is paused until stable scene objects +and context-keyed operation plugins are implemented and verified. Read next: @@ -22,9 +22,9 @@ Read next: - Accepted: [ADRs 001–010](decisions/README.md), including ADRs 008–010 on 2026-11-07. -- Proposed alternatives: ADRs 011–012. -- Proposed and preferred: ADR 013 hierarchy-only nodes and stable scene objects; - ADR 014 context-keyed operation plugins. +- Accepted: ADR 013 hierarchy-only nodes and stable scene objects; ADR 014 + context-keyed operation plugins. +- Superseded: ADR 008, part of ADR 009, and unaccepted ADRs 011–012. - Scope boundary: `compas_model`, notebook, and CAD hosts are later or compatibility consumers; `compas_session` requires an explicit inclusion decision. Do not modify package source outside the initial scope, merge, or @@ -75,9 +75,8 @@ Read next: ## Next tasks -1. Obtain explicit decisions on preferred Proposed ADRs 013–014 and their - disposition of ADRs 008–009 and 011–012. -2. If accepted, implement and independently verify the architecture correction. +1. Implement and independently verify Accepted ADRs 013–014 in core and Viewer. +2. Update exact-candidate framework and compatibility gates. 3. Resume Phase 2 Viewer state and selection work only after that gate passes. ## Blockers and approval gates diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 0ee7be3..6b5ff10 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,10 +2,9 @@ ## Status -Architecture correction pending. ADRs 001–010 are Accepted. ADRs 011–012 are -unresolved alternatives; ADRs 013–014 are the preferred Proposed correction -after implementation evidence exposed duplicate ownership, hidden state -routing, and backend-dependent object types. Phase 2 is paused. +Architecture correction approved. ADRs 013–014 are Accepted and supersede the +implemented adapter model. Phase 2 remains paused until the correction is +implemented and verified. ## Dependency graph @@ -24,7 +23,7 @@ ADRs 001–010 ----------> ADR 007 rollout gate Governing ADRs: 001, 008, 009, and 010. -Status: implemented, but subject to the Proposed ADR 013–014 correction before +Status: implemented, but subject to the Accepted ADR 013–014 correction before Phase 2 proceeds. 1. Add the verified Viewer round-trip regression and a minimal core adapter @@ -70,8 +69,8 @@ large-indexed-input evidence passes at exact candidate heads. Governing ADRs: 001, 003, 004, 007, 008, and 009. -Status: paused until ADRs 013–014 are resolved and the approved scene -architecture correction is implemented and verified. +Status: paused until the Accepted ADR 013–014 scene architecture correction is +implemented and verified. 1. Separate persistent Viewer configuration from transient Viewer state. 2. Implement the object-selection model and migrate viewport, rectangle, tree, diff --git a/initiatives/scene-viewer-visualisation/objective.md b/initiatives/scene-viewer-visualisation/objective.md index 19ee8da..f1e0231 100644 --- a/initiatives/scene-viewer-visualisation/objective.md +++ b/initiatives/scene-viewer-visualisation/objective.md @@ -107,6 +107,7 @@ home and contract. ## Current status -Reconnaissance and architecture are complete. ADRs 001–010 are Accepted and -implementation may proceed within the approved initial scope. The current -draft `ModelViewer` is evidence and a later redesign target, not a contract. +Reconnaissance and architecture are complete. ADRs 013–014 are Accepted and +the scene architecture correction may proceed within the approved initial +scope before Phase 2 resumes. The current draft `ModelViewer` is evidence and +a later redesign target, not a contract. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index e3d6079..4b6ab50 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -14,9 +14,9 @@ measurements, annotations, scale/legend overlays, and public dock/command composition. It should not attempt a universal renderer API, a generic reactive framework, sub-object editing, a shell, or host-application migration. -ADRs 001–010 are Accepted. Implementation may proceed in dependency order -within the approved initial scope; Session redesign and Viewer/Session -convenience operations remain later work. +ADRs 013–014 are Accepted and the architecture correction may proceed before +Phase 2. Session redesign and Viewer/Session convenience operations remain +later work. ## New evidence requiring amendment @@ -390,9 +390,9 @@ not complicate it. Lightweight discovery plugins populate a small scene operation registry keyed by `(context, scene-object type, operation)`. Runtime buffers, host handles, picking state, and caches live outside durable objects. -Proposed ADRs 011–012 record the first node-first alternative. Proposed ADRs -013–014 record this newer preferred design. Phase 2 remains paused until the -preferred decisions are resolved and, if accepted, implemented and verified. +ADRs 011–012 record the unaccepted first node-first alternative. Accepted ADRs +013–014 record the selected design. Phase 2 remains paused until it is +implemented and verified. ## Decision record @@ -411,5 +411,5 @@ preferred decisions are resolved and, if accepted, implemented and verified. 13. [ADR 013 — Hierarchy-only nodes and stable scene objects](decisions/013-hierarchy-nodes-and-stable-sceneobjects.md) 14. [ADR 014 — Context-keyed scene operation plugins](decisions/014-context-keyed-scene-operations.md) -ADRs 001–010 are Accepted. ADRs 011–014 are Proposed; ADRs 013–014 are the -preferred alternative. +ADRs 013–014 are Accepted. ADRs 008–009 and 011–012 are superseded as recorded +in the decision index; ADR 010 remains Accepted with amended terminology. From 0fe8f4a451512b18c45e30f61cbda645958f2766 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 23:17:46 +0100 Subject: [PATCH 19/22] Refresh stable scene integration gate --- .../scene-candidates/core-requirements.txt | 2 +- .../test_scene_integration.py | 90 ++++++++------ .../scene-candidates/viewer-requirements.txt | 2 +- .../scene-viewer-visualisation/handoff.md | 117 +++++------------- tests/test_package.py | 4 +- 5 files changed, 89 insertions(+), 126 deletions(-) diff --git a/.github/scene-candidates/core-requirements.txt b/.github/scene-candidates/core-requirements.txt index 27bdb96..2f6e9fa 100644 --- a/.github/scene-candidates/core-requirements.txt +++ b/.github/scene-candidates/core-requirements.txt @@ -1 +1 @@ -compas @ git+https://github.com/compas-dev/compas.git@38d2457861ba7122f91d2107ce11e85053105165 +compas @ git+https://github.com/compas-dev/compas.git@d43db206afec36450efbe76b53306ce3bd468076 diff --git a/.github/scene-candidates/test_scene_integration.py b/.github/scene-candidates/test_scene_integration.py index 453a63d..2873d6a 100644 --- a/.github/scene-candidates/test_scene_integration.py +++ b/.github/scene-candidates/test_scene_integration.py @@ -5,19 +5,20 @@ from importlib.metadata import distribution import pytest -from compas.colors import Color from compas.data import json_dumps from compas.data import json_loads from compas.geometry import Box from compas.geometry import Translation from compas.scene import Scene from compas.scene import SceneItemNotBoundError -from compas_viewer import Viewer +from compas.scene import SceneObject +from compas.scene import ShapeObject +from compas.scene import register_scene_operation from compas_viewer.scene import BufferGeometry from compas_viewer.scene import ViewerScene -CORE_COMMIT = "38d2457861ba7122f91d2107ce11e85053105165" -VIEWER_COMMIT = "0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5" +CORE_COMMIT = "d43db206afec36450efbe76b53306ce3bd468076" +VIEWER_COMMIT = "a72b61b777bc3fd448c3d471c48ef7f65334b319" def _installed_commit(distribution_name: str) -> str: @@ -68,60 +69,73 @@ def test_indexed_buffer_geometry_stays_indexed_and_roundtrips(): assert restored.triangles.tolist() == [[0, 1, 2], [1, 3, 2]] -def test_reference_scene_roundtrip_and_explicit_binding(tmp_path): - viewer = Viewer() - viewer.running = False - viewer.scene.clear(clear_context=False) - +def test_stable_scene_roundtrip_operations_and_explicit_binding(): box = Box(1.0) transformation = Translation.from_vector([2.0, 0.0, 0.0]) - original = viewer.scene.add( + scene = ViewerScene() + original = scene.add( box, name="Box", is_selected=True, - show_faces=False, - facecolor=Color.red(), + show=False, transformation=transformation, u=7, - use_rgba=True, v=9, ) - original.background = True - scene_path = tmp_path / "scene.json" - item_path = tmp_path / "box.json" - viewer.scene.to_json(scene_path) - box.to_json(item_path) + assert type(original) is ShapeObject + assert original.node.object_guid == original.guid + assert original.node.__data__ == {"object": str(original.guid), "children": []} + + calls = [] + runtime = object() + + def draw(scene, sceneobject, active_runtime): + calls.append(("draw", sceneobject, active_runtime)) + return ["opaque-handle"] + + def clear(scene, sceneobject, active_runtime, resources): + calls.append(("clear", sceneobject, active_runtime, resources)) + + register_scene_operation("FrameworkIntegration", SceneObject, "draw", draw) + register_scene_operation("FrameworkIntegration", SceneObject, "clear", clear) + original.show = True + assert original.draw(context="FrameworkIntegration", runtime=runtime) == ["opaque-handle"] + assert scene.object(original.guid) is original + assert type(original) is ShapeObject - payload = scene_path.read_text() + payload = scene.to_jsonstring() assert str(box.guid) in payload assert "compas.geometry/Box" not in payload + assert "opaque-handle" not in payload + assert "FrameworkIntegration" not in payload assert "is_selected" not in payload - assert "instance_color" not in payload + assert "render_objects" not in payload + assert "instance_colors" not in payload - restored_scene = Scene.from_json(scene_path) - restored_box = Box.from_json(item_path) + restored_scene = Scene.from_jsonstring(payload) + restored_box = Box.from_jsonstring(box.to_jsonstring()) assert isinstance(restored_scene, ViewerScene) assert restored_box.guid == box.guid assert restored_box.volume() == box.volume() - node = restored_scene.find_node_by_name("Box") - assert node is not None - assert node.guid == original.node.guid - assert node.item_guid == restored_box.guid + restored = restored_scene.find_by_name("Box") + assert type(restored) is ShapeObject + assert restored.guid == original.guid + assert restored.item_guid == restored_box.guid + assert restored.transformation == transformation + assert restored.show is True + assert (restored.u, restored.v) == (7, 9) + assert restored_scene.item_store == {} + assert not restored_scene.is_selected(restored) with pytest.raises(SceneItemNotBoundError, match=str(restored_box.guid)): - restored_scene.bind_context("Viewer") + _ = restored.item restored_scene.bind(restored_box) - restored_scene.bind_context("Viewer") - restored = restored_scene.objects[0] - - assert restored.node.transformation == transformation - assert restored.show_faces is False - assert restored.facecolor == Color.red() - assert restored.u == 7 - assert restored.use_rgba is True - assert restored.v == 9 - assert restored.background is True - assert restored.is_selected is False + assert restored.item is restored_box + original.clear(context="FrameworkIntegration") + assert calls == [ + ("draw", original, runtime), + ("clear", original, runtime, ("opaque-handle",)), + ] assert restored_scene.instance_colors == {} diff --git a/.github/scene-candidates/viewer-requirements.txt b/.github/scene-candidates/viewer-requirements.txt index ee4bfd9..66a6b95 100644 --- a/.github/scene-candidates/viewer-requirements.txt +++ b/.github/scene-candidates/viewer-requirements.txt @@ -1 +1 @@ -compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5 +compas_viewer @ git+https://github.com/compas-dev/compas_viewer.git@a72b61b777bc3fd448c3d471c48ef7f65334b319 diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index b3d533f..40617b8 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -4,102 +4,51 @@ Last updated: 2026-11-07 ## Resume here -Current phase: `architecture correction` +Current phase: `integration verification` -Status: ADRs 013–014 are Accepted. ADRs 008–009 and the unaccepted alternatives -011–012 are superseded as recorded in the decision index. Phase 1 indexed -buffers are complete and green. Phase 2 is paused until stable scene objects -and context-keyed operation plugins are implemented and verified. +ADRs 013–014 are implemented and independently approved in core and Viewer. +They replace the earlier adapter design with hierarchy-only nodes, stable +backend-neutral scene objects, and context-keyed `draw`/`clear` operations. +Phase 2 remains paused until the refreshed exact-candidate framework gate is +green. Read next: -1. `objective.md` -2. `inventory.md` -3. `proposal.md` -4. `decisions/README.md` +1. [Implementation plan](implementation-plan.md) +2. [Decision index](decisions/README.md) +3. [Proposal](proposal.md) -## Decisions and approvals - -- Accepted: [ADRs 001–010](decisions/README.md), including ADRs 008–010 on - 2026-11-07. -- Accepted: ADR 013 hierarchy-only nodes and stable scene objects; ADR 014 - context-keyed operation plugins. -- Superseded: ADR 008, part of ADR 009, and unaccepted ADRs 011–012. -- Scope boundary: `compas_model`, notebook, and CAD hosts are later or - compatibility consumers; `compas_session` requires an explicit inclusion - decision. Do not modify package source outside the initial scope, merge, or - publish without the corresponding approval. - -## Working state +## Exact candidates | Repository | Branch | Exact head | Pull request | Status | |---|---|---|---|---| -| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | this handoff checkpoint | [7](https://github.com/compas-dev/compas_framework/pull/7) | Exact-source gate green before latest candidate-pin refresh | -| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `38d2457861ba7122f91d2107ce11e85053105165` | [1540](https://github.com/compas-dev/compas/pull/1540) | Full matrix green; patch coverage rerunning | -| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Phase 1 indexed-buffer candidate pushed; CI running | -| `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Clean; inspected only | - -## Completed at this checkpoint - -- Inventoried core scene ownership, transformations, serialization, context - dispatch, tests, and documentation gaps. -- Inventoried Viewer rendering, indexed-buffer limitations, selection, - transforms, overlays, state, commands, and extension points. -- Inventoried model projection, render geometry, caching, selection, tests, - documentation, and Viewer coupling. -- Identified initial and compatibility-only package boundaries. -- Produced the architecture proposal, seven independent Proposed ADRs, and a - dependency-ordered implementation plan. -- Verified that Viewer ShapeObject state and ModelViewer scene reconstruction - do not round-trip under the current constructor/settings mechanism. -- Proposed separate serializable node state, runtime adapter binding, durable - node GUIDs, and explicit serialization fields in ADRs 008–009. -- Accepted ADRs 008–009 and proposed reference-only scene descriptions plus a - separate future Session aggregation boundary in ADR 010. -- Recorded that the current `compas_model.ModelViewer` is a draft and only - regression/coupling evidence, not a public contract to preserve. -- Implemented durable reference-only core scene nodes, explicit item binding, - two-phase runtime-adapter binding, and validated MRO-composed state fields. -- Adapted Viewer durable state, removed legacy settings persistence, fixed - transient picking-cache lifecycle, and documented separate data binding. -- Resolved all independent core and Viewer review findings. -- Added focused coverage for invalid closed Scene and SceneNode schemas. -- Added and passed an installed exact-source framework gate covering plugin - discovery, reference-only round trips, explicit rebinding, and transient - Viewer state exclusion. -- Implemented and independently approved indexed `BufferGeometry`, convenience - constructors, closed JSON persistence, preserved buffer indices, and - complete-triangle transparency partitioning. -- Reverified 36 `compas_model` Viewer/controller/plugin compatibility tests - against the Phase 1 Viewer source without modifying model code. - -## Next tasks +| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | current working tree | [7](https://github.com/compas-dev/compas_framework/pull/7) | Gate refresh pending commit and CI | +| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `d43db206afec36450efbe76b53306ce3bd468076` | [1540](https://github.com/compas-dev/compas/pull/1540) | Stable scene architecture pushed; local checks and independent review passed | +| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `a72b61b777bc3fd448c3d471c48ef7f65334b319` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Stable operation/runtime migration pushed; 161 applicable tests, Ruff, Pyright, and independent review passed | +| `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Compatibility consumer only; no source changes authorized | -1. Implement and independently verify Accepted ADRs 013–014 in core and Viewer. -2. Update exact-candidate framework and compatibility gates. -3. Resume Phase 2 Viewer state and selection work only after that gate passes. +## Verification evidence -## Blockers and approval gates - -- Package source implementation is authorized within the accepted initial - scope. -- Adding model, session, notebook, or host packages to initial implementation - scope requires explicit approval. +| Layer | Status | Evidence | +|---|---|---| +| Local package checks | Passed with one local-policy exclusion | Core focused scene/glTF checks, Ruff, Pyright, strict docs, and independent review passed. Viewer passed 161 applicable tests, Ruff, Pyright, strict docs, and independent review. Viewer’s ignored local `docs/examples/__temp` directory remains the sole excluded repository-policy assertion. | +| Framework integration | Local source gate passed; hosted gate pending | The refreshed gate covers exact revisions, graphics-free discovery, stable semantic types and GUIDs, hierarchy-only nodes, external item rebinding, context-keyed operations without class substitution, transient runtime exclusion, and indexed-buffer round trips. Local source execution passed 3 tests with the exact-install assertion skipped by design. | +| Package CI | Pending refreshed heads | Check PRs 1540 and 233 after the framework gate is pushed. | +| Candidate artifacts | Not run | Required before independently built artifact compatibility is claimed. | -## Verification +The broader `tests/test_package.py` run is locally unavailable because the +active `compas3` editable-import hook resolves `compas_cgal` from +`/private/tmp/compas-cgal-typing-adr017` instead of its checked-out sibling. +This is an environment provenance failure, not a scene-gate failure. -Evidence by layer: +## Next tasks -| Layer | Status | Evidence | -|---|---|---| -| Local focused checks | Passed | Core scene/glTF: 61 passed, Ruff passed, Pyright 0; Viewer focused: 50 passed, Ruff passed, Pyright 0; independent reviews approved both exact heads. | -| Package CI | Partial | Viewer PR 233 is fully green. Core PR 1540 has a green full OS/Python matrix, coverage, changelog, metadata, and project coverage; patch coverage is rerunning after ten additional schema-validation paths were covered. | -| Framework integration CI | Passed; refresh pending | Framework PR 7 passed contracts and the installed exact-candidate gate; the gate is rerunning against the latest test/workflow-only package heads. | -| Candidate-artifact CI | Not run | Required only before claims about independently built artifacts. | +1. Commit and push the refreshed framework exact-candidate gate, then verify PR 7. +2. Verify package PR checks for the exact core and Viewer heads and record results by layer. +3. Resume Phase 2 Viewer state and selection only after framework integration is green. -Run next: +## Approval gates -```text -gh pr checks --repo compas-dev/compas -gh pr checks --repo compas-dev/compas_viewer -``` +- The accepted initial implementation scope is core, Viewer, and framework. +- Adding model, session, notebook, or host packages requires explicit approval. +- Do not merge or publish without explicit approval. diff --git a/tests/test_package.py b/tests/test_package.py index 8ab37b9..f623f6f 100644 --- a/tests/test_package.py +++ b/tests/test_package.py @@ -63,8 +63,8 @@ def test_scene_candidate_integration_pins_exact_source_revisions(): viewer_requirements = (source / ".github" / "scene-candidates" / "viewer-requirements.txt").read_text() workflow = (source / ".github" / "workflows" / "scene-candidate-integration.yml").read_text() - assert "compas.git@38d2457861ba7122f91d2107ce11e85053105165" in core_requirements - assert "compas_viewer.git@0fd73e9d17481bfcd2d69cf08c4db757a3ab16a5" in viewer_requirements + assert "compas.git@d43db206afec36450efbe76b53306ce3bd468076" in core_requirements + assert "compas_viewer.git@a72b61b777bc3fd448c3d471c48ef7f65334b319" in viewer_requirements assert "branches: [c3-upgrade]" in workflow assert "core-requirements.txt" in workflow assert "viewer-requirements.txt" in workflow From f2976d1695b5b8554f238b063701ded9301a2976 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 23:19:42 +0100 Subject: [PATCH 20/22] Record stable scene integration evidence --- .../scene-viewer-visualisation/handoff.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 40617b8..715dc70 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -22,9 +22,9 @@ Read next: | Repository | Branch | Exact head | Pull request | Status | |---|---|---|---|---| -| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | current working tree | [7](https://github.com/compas-dev/compas_framework/pull/7) | Gate refresh pending commit and CI | -| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `d43db206afec36450efbe76b53306ce3bd468076` | [1540](https://github.com/compas-dev/compas/pull/1540) | Stable scene architecture pushed; local checks and independent review passed | -| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `a72b61b777bc3fd448c3d471c48ef7f65334b319` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Stable operation/runtime migration pushed; 161 applicable tests, Ruff, Pyright, and independent review passed | +| `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `0fe8f4a` plus this evidence update | [7](https://github.com/compas-dev/compas_framework/pull/7) | Exact-source contracts and installed-candidate gate passed | +| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `d43db206afec36450efbe76b53306ce3bd468076` | [1540](https://github.com/compas-dev/compas/pull/1540) | Full OS/Python matrix and project coverage passed; Codecov patch coverage remains red | +| `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `a72b61b777bc3fd448c3d471c48ef7f65334b319` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Complete hosted matrix passed | | `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Compatibility consumer only; no source changes authorized | ## Verification evidence @@ -32,8 +32,8 @@ Read next: | Layer | Status | Evidence | |---|---|---| | Local package checks | Passed with one local-policy exclusion | Core focused scene/glTF checks, Ruff, Pyright, strict docs, and independent review passed. Viewer passed 161 applicable tests, Ruff, Pyright, strict docs, and independent review. Viewer’s ignored local `docs/examples/__temp` directory remains the sole excluded repository-policy assertion. | -| Framework integration | Local source gate passed; hosted gate pending | The refreshed gate covers exact revisions, graphics-free discovery, stable semantic types and GUIDs, hierarchy-only nodes, external item rebinding, context-keyed operations without class substitution, transient runtime exclusion, and indexed-buffer round trips. Local source execution passed 3 tests with the exact-install assertion skipped by design. | -| Package CI | Pending refreshed heads | Check PRs 1540 and 233 after the framework gate is pushed. | +| Framework integration | Passed | The refreshed gate covers exact revisions, graphics-free discovery, stable semantic types and GUIDs, hierarchy-only nodes, external item rebinding, context-keyed operations without class substitution, transient runtime exclusion, and indexed-buffer round trips. Local source execution passed 3 tests with the exact-install assertion skipped by design; hosted contracts and source-installed candidates passed. | +| Package CI | Viewer passed; core patch coverage unresolved | Viewer build, coverage, policy, distribution, and all nine OS/Python quality jobs passed. Core's full OS/Python matrix, project coverage, changelog, metadata, and NumPy checks passed; Codecov patch coverage is still red. | | Candidate artifacts | Not run | Required before independently built artifact compatibility is claimed. | The broader `tests/test_package.py` run is locally unavailable because the @@ -43,9 +43,9 @@ This is an environment provenance failure, not a scene-gate failure. ## Next tasks -1. Commit and push the refreshed framework exact-candidate gate, then verify PR 7. -2. Verify package PR checks for the exact core and Viewer heads and record results by layer. -3. Resume Phase 2 Viewer state and selection only after framework integration is green. +1. Resolve or explicitly disposition core PR 1540's Codecov patch-coverage failure. +2. Resume Phase 2 Viewer state and selection work from the verified stable-scene foundation. +3. Run candidate-artifact verification before claiming independently built artifact compatibility. ## Approval gates From 84b1a95e013cc551154f22d081ee7b974cd6f34e Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 23:28:18 +0100 Subject: [PATCH 21/22] Record core patch coverage recovery --- initiatives/scene-viewer-visualisation/handoff.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 715dc70..347de8c 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -23,7 +23,7 @@ Read next: | Repository | Branch | Exact head | Pull request | Status | |---|---|---|---|---| | `compas-dev/compas_framework` | `initiative/scene-viewer-visualisation` | `0fe8f4a` plus this evidence update | [7](https://github.com/compas-dev/compas_framework/pull/7) | Exact-source contracts and installed-candidate gate passed | -| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | `d43db206afec36450efbe76b53306ce3bd468076` | [1540](https://github.com/compas-dev/compas/pull/1540) | Full OS/Python matrix and project coverage passed; Codecov patch coverage remains red | +| `compas-dev/compas` | `initiative/scene-viewer-visualisation` | runtime candidate `d43db206afec36450efbe76b53306ce3bd468076`; test-only head `41e51713352` | [1540](https://github.com/compas-dev/compas/pull/1540) | Codecov patch/project, coverage, build, and NumPy checks passed; remaining matrix rerun pending | | `compas-dev/compas_viewer` | `initiative/scene-viewer-visualisation` | `a72b61b777bc3fd448c3d471c48ef7f65334b319` | [233](https://github.com/compas-dev/compas_viewer/pull/233) | Complete hosted matrix passed | | `BlockResearchGroup/compas_model` | `c3-upgrade` | `83df4167f7ba1539ae205a837e0238afecc0a36b` | None | Compatibility consumer only; no source changes authorized | @@ -33,7 +33,7 @@ Read next: |---|---|---| | Local package checks | Passed with one local-policy exclusion | Core focused scene/glTF checks, Ruff, Pyright, strict docs, and independent review passed. Viewer passed 161 applicable tests, Ruff, Pyright, strict docs, and independent review. Viewer’s ignored local `docs/examples/__temp` directory remains the sole excluded repository-policy assertion. | | Framework integration | Passed | The refreshed gate covers exact revisions, graphics-free discovery, stable semantic types and GUIDs, hierarchy-only nodes, external item rebinding, context-keyed operations without class substitution, transient runtime exclusion, and indexed-buffer round trips. Local source execution passed 3 tests with the exact-install assertion skipped by design; hosted contracts and source-installed candidates passed. | -| Package CI | Viewer passed; core patch coverage unresolved | Viewer build, coverage, policy, distribution, and all nine OS/Python quality jobs passed. Core's full OS/Python matrix, project coverage, changelog, metadata, and NumPy checks passed; Codecov patch coverage is still red. | +| Package CI | Viewer passed; core rerun in progress | Viewer build, coverage, policy, distribution, and all nine OS/Python quality jobs passed. Core's Codecov patch/project, coverage, build, and NumPy checks passed after focused closed-schema tests raised expected patch coverage from 85.59% to 86.10%; the remaining matrix jobs are rerunning. | | Candidate artifacts | Not run | Required before independently built artifact compatibility is claimed. | The broader `tests/test_package.py` run is locally unavailable because the @@ -43,7 +43,7 @@ This is an environment provenance failure, not a scene-gate failure. ## Next tasks -1. Resolve or explicitly disposition core PR 1540's Codecov patch-coverage failure. +1. Confirm the remaining core PR 1540 matrix rerun completes green. 2. Resume Phase 2 Viewer state and selection work from the verified stable-scene foundation. 3. Run candidate-artifact verification before claiming independently built artifact compatibility. From 9d0513826ac0ea73b30177b33f3d5493b6a82387 Mon Sep 17 00:00:00 2001 From: tomvanmele Date: Sat, 7 Nov 2026 23:34:37 +0100 Subject: [PATCH 22/22] Propose contextual scene form contributions --- ...015-contextual-scene-form-contributions.md | 114 ++++++++++++++++++ .../016-scene-form-field-bindings.md | 106 ++++++++++++++++ .../decisions/README.md | 5 +- .../scene-viewer-visualisation/handoff.md | 15 ++- .../implementation-plan.md | 30 ++++- .../scene-viewer-visualisation/proposal.md | 46 ++++++- 6 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 initiatives/scene-viewer-visualisation/decisions/015-contextual-scene-form-contributions.md create mode 100644 initiatives/scene-viewer-visualisation/decisions/016-scene-form-field-bindings.md diff --git a/initiatives/scene-viewer-visualisation/decisions/015-contextual-scene-form-contributions.md b/initiatives/scene-viewer-visualisation/decisions/015-contextual-scene-form-contributions.md new file mode 100644 index 0000000..fb5654f --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/015-contextual-scene-form-contributions.md @@ -0,0 +1,114 @@ +# ADR 015: Contextual Scene Form Contributions + +## Status + +Proposed. + +## Context + +Viewer's object-settings form currently decides which controls to show through +hardcoded attribute checks on private render helpers. This couples the form to +renderer aliases, makes capability exceptions such as face-less graph objects +ad hoc, and gives external packages no supported way to expose a specific +stable scene-object attribute or represented-item parameter. + +The accepted scene architecture keeps durable `SceneObject` types stable and +backend-neutral. ADR 014 deliberately limits core's context-keyed scene +operation registry to `draw` and `clear`. Forms, controls, layout, and refresh +behavior are Viewer UI concerns and must not become serialized scene state. + +## Options + +1. Add a Viewer-owned registry of declarative form contributions. +2. Let plugins construct and return arbitrary Viewer or Qt components. +3. Add form operations to core's context-keyed scene operation registry. +4. Store form annotations on durable scene-object classes or instances. +5. Retain hardcoded `hasattr`-based form construction. + +## Recommendation + +Choose option 1. + +`compas_viewer` owns a runtime registry keyed by: + +```text +(context, form, stable scene-object type, contribution ID) +``` + +The initial public form identifier is only `object-settings`. Registration is +lightweight and may occur during ordinary plugin discovery without importing +Qt, OpenGL, or another graphics runtime. A provider is called only when that +form is populated. It receives the stable scene object and the explicit +transient Viewer/runtime context, and returns declarative field links governed +by ADR 016. + +Applicable contributions are collected through the stable scene-object MRO, +from general types to specific types. Fields are sorted deterministically by +`(field.order, general-to-specific MRO rank, contribution_id, +provider-return sequence)`. Registering the same exact registry key twice is +an error. Producing the same final field ID twice is also an error; a more +specific provider does not silently replace another provider's field. + +If a provider raises, Viewer aborts population of the complete form and +reports the context, form identifier, stable scene-object type, and +contribution ID. It never silently omits a failed contribution or exposes a +partially rebuilt form. + +The Viewer creates the controls, applies its consistent layout and lifecycle, +and performs mutations through one binding path. Providers do not return +ready-made widgets. By contract, a provider must not mutate the scene object +or represented item while describing the form. + +The built-in object-settings controls migrate to built-in contributions. +Unsupported capabilities are omitted rather than inferred from renderer +attributes. For example, a graph contributes no face field, while mesh and +shape contributions may do so. The current private face-capability workaround +can then be removed. + +## Consequences + +- Packages can expose only the fields appropriate for a particular form and + Viewer context without replacing scene-object classes. +- Stable scene objects remain free of Viewer-specific form metadata. +- Plugin discovery remains graphics-free and control construction stays + consistent. +- The registry is intentionally a Viewer extension point, not a universal + form or schema framework. +- Arbitrary widgets, nested layouts, conditional schema languages, and other + form identifiers require demonstrated needs and separate approval. + +## Compatibility + +The first implementation replaces the hardcoded object-settings population +path without adding durable fields or changing scene serialization. The +existing general represented-item `ParameterForm` remains available. Explicit +item-parameter contributions may coexist with it; replacing the general dialog +is not part of this decision. + +## Verification + +- Compose general and specific contributions in the complete deterministic + order defined above. +- Reject duplicate exact registrations and duplicate final field IDs. +- Verify a provider exception reports the complete registry context, aborts + population, and leaves no partially rebuilt form. +- Verify Graph omits face controls while Mesh and Shape retain them. +- Verify providers are invoked only while the requested form is populated. +- Prove plugin discovery imports no graphics or UI modules. +- Verify built-in providers leave scene objects, represented items, and their + serialized data unchanged while describing a form. +- Verify two contexts can contribute different fields for the same stable + scene-object type. + +## Dependencies + +- Depends on Accepted ADR 013 for stable scene-object types. +- Respects ADR 014's restricted `draw`/`clear` operation surface and does not + extend the core scene operation registry. +- Its implementation depends on Proposed ADR 016 for the declarative field and + mutation contract; the Viewer ownership decision can be approved + independently. + +## Decision + +Pending explicit user approval. diff --git a/initiatives/scene-viewer-visualisation/decisions/016-scene-form-field-bindings.md b/initiatives/scene-viewer-visualisation/decisions/016-scene-form-field-bindings.md new file mode 100644 index 0000000..410b259 --- /dev/null +++ b/initiatives/scene-viewer-visualisation/decisions/016-scene-form-field-bindings.md @@ -0,0 +1,106 @@ +# ADR 016: Scene Form Field Bindings + +## Status + +Proposed. + +## Context + +ADR 015 requires one small declarative contract that links a form field to its +actual owner. The initial use cases need to edit either stable presentation +state on a `SceneObject` or a supported parameter on its externally bound +represented item. The contract must make ownership, mutation, refresh, and +failure behavior explicit without growing into a general form language. + +## Options + +1. Use flat, named attribute bindings with a fixed initial editor and refresh + vocabulary. +2. Accept arbitrary getters, setters, callbacks, validators, and refresh + functions on every field. +3. Resolve dotted paths dynamically from arbitrary runtime objects. +4. Infer editable fields from annotations, constructor signatures, or + `hasattr` checks. + +## Recommendation + +Choose option 1. + +Each field declares only: + +- a form-unique `id`; +- a user-facing `label`; +- `target`, either `sceneobject` or `item`; +- one flat named `attribute`; +- `editor`, initially `boolean`, `number`, `text`, or `color`; +- `refresh`, either `draw` or `geometry`; +- an explicit numeric `order`; and +- an optional flat `section` label. + +`sceneobject` targets bind a named public attribute of the stable scene object. +`item` targets bind a named writable attribute or supported parameter of the +explicitly bound represented item. Dotted paths, implicit item loading, nested +schemas, arbitrary widget factories, and per-field executable callbacks are +outside the initial contract. + +Before displaying an editable control, Viewer resolves the complete binding +and verifies that the target and attribute are available and writable. An +unresolved external item never triggers loading or lookup beyond the scene's +existing binding. Its item-targeted fields are omitted from the form. + +Mutation uses `setattr` on stable scene-object attributes. Item parameters +reuse the existing represented-item parameter mutation and rollback behavior +where it applies. A failed setter restores the previous value and control, +reports the original exception, and performs no refresh. + +After a successful mutation: + +- `draw` refreshes the object's appearance using existing render data; +- `geometry` rebuilds the object's render data and then redraws it. + +Form descriptors, resolved bindings, control values, validation errors, and +refresh state are transient Viewer state and are never serialized with a scene +or represented item. + +## Consequences + +- Ownership is visible at every field rather than inferred from similarly + named attributes. +- All contextual fields share one mutation, failure, and refresh path. +- The initial editor vocabulary matches existing Viewer controls. +- More complex editors or bindings require evidence and an amendment rather + than hidden escape hatches. +- The API may later gain narrowly justified metadata without revisiting the + Viewer ownership decision in ADR 015. + +## Compatibility + +Built-in object-settings controls map to equivalent declarative fields. The +general represented-item parameter dialog remains a separate explicit command +during the initial migration. No serialized scene format or represented-item +format changes. + +## Verification + +- Mutate a stable scene-object attribute and the intended represented-item + parameter through separate fields. +- Verify `draw` and `geometry` invoke only their specified refresh behavior. +- Verify read-only or missing attributes do not produce an editable binding. +- Verify a failed setter restores the old object and control values, reports + the failure, and does not redraw. +- Verify unresolved external items omit item-targeted fields without loading + data implicitly. +- Verify supported Boolean, numeric, text, and color fields use the existing + Viewer controls consistently. +- Prove field and binding state is absent from scene and item serialization. + +## Dependencies + +- Depends on Proposed ADR 015 for contribution registration, lookup, and + lifecycle. +- Reuses accepted stable scene-object and external item-binding semantics from + ADRs 010 and 013. + +## Decision + +Pending explicit user approval. diff --git a/initiatives/scene-viewer-visualisation/decisions/README.md b/initiatives/scene-viewer-visualisation/decisions/README.md index 9bce4cc..af671c4 100644 --- a/initiatives/scene-viewer-visualisation/decisions/README.md +++ b/initiatives/scene-viewer-visualisation/decisions/README.md @@ -3,7 +3,8 @@ ADRs 013–014 are Accepted and supersede the implemented node/runtime-adapter model of ADR 008, part of ADR 009, and the unaccepted alternatives in ADRs 011–012. ADR 010 remains Accepted with item references moved to stable scene -objects. +objects. ADRs 015–016 propose a Viewer-owned mechanism for contextual +object-settings fields; they are not approved for implementation. | ADR | Decision | Status | Dependencies | |---|---|---|---| @@ -21,6 +22,8 @@ objects. | 012 | [Explicit node-backed adapter state](012-explicit-node-backed-adapter-state.md) | Superseded before acceptance | 011 | | 013 | [Hierarchy-only nodes and stable scene objects](013-hierarchy-nodes-and-stable-sceneobjects.md) | Accepted | Supersedes 008/009 placement; preserves 010 | | 014 | [Context-keyed scene operation plugins](014-context-keyed-scene-operations.md) | Accepted | 013; replaces backend class registration | +| 015 | [Contextual scene form contributions](015-contextual-scene-form-contributions.md) | Proposed | 013; respects 014 | +| 016 | [Scene form field bindings](016-scene-form-field-bindings.md) | Proposed | 015; 010 and 013 semantics | ADRs 008–010 were accepted on 2026-11-07. ADR 010 refines ADR 008's item store into non-owning runtime bindings and keeps aggregation outside Scene. A diff --git a/initiatives/scene-viewer-visualisation/handoff.md b/initiatives/scene-viewer-visualisation/handoff.md index 347de8c..4ecefab 100644 --- a/initiatives/scene-viewer-visualisation/handoff.md +++ b/initiatives/scene-viewer-visualisation/handoff.md @@ -9,8 +9,12 @@ Current phase: `integration verification` ADRs 013–014 are implemented and independently approved in core and Viewer. They replace the earlier adapter design with hierarchy-only nodes, stable backend-neutral scene objects, and context-keyed `draw`/`clear` operations. -Phase 2 remains paused until the refreshed exact-candidate framework gate is -green. +The refreshed exact-candidate framework gate is green, so the accepted Phase 2 +work may resume independently of the proposed contextual form extension. + +ADRs 015–016 now propose contextual object-settings contributions and explicit +field binding/mutation semantics. No implementation is authorized until both +are explicitly approved. Read next: @@ -43,12 +47,13 @@ This is an environment provenance failure, not a scene-gate failure. ## Next tasks -1. Confirm the remaining core PR 1540 matrix rerun completes green. -2. Resume Phase 2 Viewer state and selection work from the verified stable-scene foundation. -3. Run candidate-artifact verification before claiming independently built artifact compatibility. +1. Review and approve or revise Proposed ADRs 015–016. +2. Confirm the remaining core PR 1540 matrix rerun completes green. +3. Resume Phase 2 from the verified stable-scene foundation after its approval gates are clear. ## Approval gates - The accepted initial implementation scope is core, Viewer, and framework. - Adding model, session, notebook, or host packages requires explicit approval. +- Contextual form implementation requires explicit approval of ADRs 015–016. - Do not merge or publish without explicit approval. diff --git a/initiatives/scene-viewer-visualisation/implementation-plan.md b/initiatives/scene-viewer-visualisation/implementation-plan.md index 6b5ff10..d8a5119 100644 --- a/initiatives/scene-viewer-visualisation/implementation-plan.md +++ b/initiatives/scene-viewer-visualisation/implementation-plan.md @@ -2,9 +2,9 @@ ## Status -Architecture correction approved. ADRs 013–014 are Accepted and supersede the -implemented adapter model. Phase 2 remains paused until the correction is -implemented and verified. +Architecture correction implemented and verified. ADRs 013–014 are Accepted +and supersede the adapter model. Phase 2 may resume. Contextual form work is +blocked on Proposed ADRs 015–016. ## Dependency graph @@ -69,8 +69,7 @@ large-indexed-input evidence passes at exact candidate heads. Governing ADRs: 001, 003, 004, 007, 008, and 009. -Status: paused until the Accepted ADR 013–014 scene architecture correction is -implemented and verified. +Status: ready on the implemented and verified ADR 013–014 scene foundation. 1. Separate persistent Viewer configuration from transient Viewer state. 2. Implement the object-selection model and migrate viewport, rectangle, tree, @@ -85,6 +84,27 @@ implemented and verified. Exit gate: all selection paths share one model; transform/undo tests cover parents, batches, failures, and buffer-update scope. +## Proposed contextual object-settings work + +Governing ADRs: 013, 014, 015, and 016. + +Status: blocked pending explicit approval of ADRs 015–016. + +1. Add the lightweight Viewer-owned contribution registry and deterministic + MRO composition. +2. Add the flat field descriptor and the two explicit binding targets, + editor sets, and refresh modes. +3. Migrate built-in object-settings controls and remove attribute-driven + capability inference. +4. Add package contributions only for demonstrated fields; keep plugin + discovery free of Qt and graphics imports. +5. Verify mutation, rollback, unresolved-item behavior, refresh scope, + provider failure atomicity, serialization exclusion, and multiple contexts. + +Exit gate: object-settings fields are explicit and contextual; stable scene +objects and external items retain their accepted ownership and serialization; +all applicable Viewer package and framework integration checks pass. + ## Phase 3 — Annotations and overlays Governing ADRs: 001–005 and 007. diff --git a/initiatives/scene-viewer-visualisation/proposal.md b/initiatives/scene-viewer-visualisation/proposal.md index 4b6ab50..50e28cc 100644 --- a/initiatives/scene-viewer-visualisation/proposal.md +++ b/initiatives/scene-viewer-visualisation/proposal.md @@ -14,9 +14,11 @@ measurements, annotations, scale/legend overlays, and public dock/command composition. It should not attempt a universal renderer API, a generic reactive framework, sub-object editing, a shell, or host-application migration. -ADRs 013–014 are Accepted and the architecture correction may proceed before -Phase 2. Session redesign and Viewer/Session convenience operations remain -later work. +ADRs 013–014 are Accepted, implemented, and verified. Session redesign and +Viewer/Session convenience operations remain later work. + +ADRs 015–016 propose a later Viewer-owned contextual form mechanism. They are +not approved for implementation. ## New evidence requiring amendment @@ -391,8 +393,37 @@ operation registry keyed by `(context, scene-object type, operation)`. Runtime buffers, host handles, picking state, and caches live outside durable objects. ADRs 011–012 record the unaccepted first node-first alternative. Accepted ADRs -013–014 record the selected design. Phase 2 remains paused until it is -implemented and verified. +013–014 record the selected design, which is now implemented and verified. + +## Proposed contextual object-settings contributions + +Viewer's object-settings form currently selects controls through hardcoded +attribute checks on private render helpers. This confuses renderer-facing +aliases with editable UI capabilities and provides no supported extension +point for packages that need to expose a particular stable scene-object +attribute or represented-item parameter. + +The proposed correction is deliberately Viewer-owned. Lightweight plugins +register declarative contributions by context, form identifier, stable +scene-object type, and contribution ID. Providers are invoked only when the +form is populated, compose through the stable type MRO, and describe flat +field links. Viewer remains responsible for controls, layout, mutation, +failure handling, and refresh. Field ordering is deterministic across explicit +order, MRO rank, contribution ID, and provider-return sequence. A provider +failure aborts form population with a contextual diagnostic; it does not leave +a partial form. + +The initial scope is only `object-settings`, with Boolean, numeric, text, and +color editors. A field explicitly targets either a stable scene-object +attribute or an attribute/parameter of its already bound represented item. +Successful changes request either a draw-only or geometry rebuild refresh. +Fields for unresolved items are omitted without implicit loading, and failed +setters restore the prior value without refreshing. + +This mechanism does not extend core's `draw`/`clear` registry, attach UI +metadata to durable objects, return arbitrary Qt controls from plugins, or +introduce a general form-schema framework. The existing general parameter +dialog remains available during the initial migration. ## Decision record @@ -410,6 +441,9 @@ implemented and verified. 12. [ADR 012 — Explicit node-backed adapter state](decisions/012-explicit-node-backed-adapter-state.md) 13. [ADR 013 — Hierarchy-only nodes and stable scene objects](decisions/013-hierarchy-nodes-and-stable-sceneobjects.md) 14. [ADR 014 — Context-keyed scene operation plugins](decisions/014-context-keyed-scene-operations.md) +15. [ADR 015 — Contextual scene form contributions](decisions/015-contextual-scene-form-contributions.md) +16. [ADR 016 — Scene form field bindings](decisions/016-scene-form-field-bindings.md) ADRs 013–014 are Accepted. ADRs 008–009 and 011–012 are superseded as recorded -in the decision index; ADR 010 remains Accepted with amended terminology. +in the decision index; ADR 010 remains Accepted with amended terminology. ADRs +015–016 remain Proposed and block contextual form implementation.