From d1b8fc93f50db2c0785ae4be5f35289ab3036e62 Mon Sep 17 00:00:00 2001
From: Sebastian <106036+schoeller@users.noreply.github.com>
Date: Sun, 6 Sep 2026 16:34:39 +0200
Subject: [PATCH] ocs_doc_api: convert architecture flow diagram to readable
text format
Replace the mermaid flowchart (hard to read raw) with a clean ASCII/text diagram
tracing the same flow from the single source of truth (spec/entities.toml +
layouts.json) through codegen, facade, wire, transport, executor, and the host
backend/Scene, plus a layer-by-layer legend.
---
crates/ocs_doc_api/ARCHITECTURE.md | 138 ++++++++++++-----------------
1 file changed, 58 insertions(+), 80 deletions(-)
diff --git a/crates/ocs_doc_api/ARCHITECTURE.md b/crates/ocs_doc_api/ARCHITECTURE.md
index d5cfd1888..b06bd34e8 100644
--- a/crates/ocs_doc_api/ARCHITECTURE.md
+++ b/crates/ocs_doc_api/ARCHITECTURE.md
@@ -43,95 +43,73 @@ every entity family, its construction ops, geometric actions, and queries, and
their kernel/acadrust mapping. Everything downstream derives from it. The full
flow from spec to a committed document change:
-```mermaid
-flowchart TD
- subgraph SRC["Single source of truth"]
- SPEC["spec/entities.toml
families · constructors · methods · kernel map"]
- LAYOUTS["src/gen/layouts.json
Operation/Query wire layouts"]
- end
-
- subgraph GEN["build.rs codegen (cargo build, CI drift-checked)"]
- OPS["src/gen/ops_gen.rs
Operation enum (append-only)"]
- QRY["src/gen/query_gen.rs
Query enum (append-only)"]
- APIREF["src/gen/api_reference.md"]
- SCHEMA["src/gen/binding_schema.json
(object model + layouts inlined)"]
- end
-
- subgraph FACADE["Facade (facade.rs) — plugin-facing, object-centric"]
- API["DocApi (root)"]
- DOC["Document (per tab)"]
- COLL["collections: solids() / curves() / entities()"]
- HND["typed handles: Solid · Line · ArcCurve · Text · ...
methods build ops (intersect, transform, create_*)"]
- end
-
- subgraph WIRE["Wire (envelope/ops/query)"]
- ENV["DocApiEnvelope
Op(Operation) | Queries(Vec)"]
- REC["Receipt: outcome + query_results + new_revision"]
- end
-
- subgraph TRANS["Transport (the only plugin↔host boundary)"]
- INP["InProcess (host / tests)"]
- IPC["OcsPluginApiIpc (plugin)
PluginRequest::DocApiRequest{tab_id, bytes}"]
- end
-
- subgraph EXEC["Executor (executor.rs) — crate-owned, one impl"]
- AO["apply_op: validate+compute → push_undo → mutate → finalize_op"]
- AQ["apply_queries: read-only batch (capped)"]
- end
-
- subgraph HOST["Host backend (src/app/doc_api.rs — HostSession)"]
- BE["DocApiBackend impl
resolve_body · store_solid · transform · add_* · bounds · volume · centroid"]
- TAB["tab auth: reject tab_id ≠ bound tab"]
- SCN["Scene (per tab)
solid_models · meshes · erase_entities
geometry_epoch · doc_api_mass_cache · doc_api_cold_tess_used"]
- CAD["CadDocument (acadrust)
entities · block_records · handles"]
- end
-
- SPEC -->|spec → enum names + mapping| OPS
- SPEC -->|spec → enum names + mapping| QRY
- SPEC -->|spec → reference| APIREF
- SPEC -->|spec → schema| SCHEMA
- LAYOUTS -->|layouts inlined| SCHEMA
-
- API --> DOC --> COLL --> HND
- HND -->|method → Operation / Query| ENV
- ENV --> INP
- ENV --> IPC
- INP --> AO
- IPC -->|bincode → host routes DocApiRequest| AO
- AO --> TAB
- AQ --> TAB
- TAB --> BE
- BE --> SCN
- BE --> CAD
- SCN --> REC
- CAD --> REC
- REC -->|deserialized| HND
-
- classDef truth fill:#1f6feb,stroke:#0b3d91,color:#fff
- classDef gen fill:#2da44e,stroke:#14532d,color:#fff
- classDef hot fill:#bf8700,stroke:#7a5200,color:#fff
- class SPEC,LAYOUTS truth
- class OPS,QRY,APIREF,SCHEMA gen
- class AO,AQ,TAB,SCN hot
+```
+SINGLE SOURCE OF TRUTH
+ spec/entities.toml families · constructors · methods · kernel map
+ src/gen/layouts.json Operation/Query wire layouts
+ │
+ ▼ (build.rs codegen — cargo build, CI drift-checked)
+CODEGEN OUTPUT
+ src/gen/ops_gen.rs Operation enum (append-only)
+ src/gen/query_gen.rs Query enum (append-only)
+ src/gen/api_reference.md
+ src/gen/binding_schema.json (object model + layouts inlined)
+ │
+ ▼
+FACADE (facade.rs — what a plugin writes)
+ DocApi ──► Document ──► collections (solids()/curves()/entities())
+ │
+ ▼
+ typed handles (Solid · Line · ArcCurve · Text · …)
+ method call → builds an Operation or Query
+ │
+ ▼
+WIRE (envelope/ops/query)
+ DocApiEnvelope = Op(Operation) | Queries(Vec) ──► request
+ Receipt = outcome + query_results + new_revision ◄── response
+ │
+ ▼
+TRANSPORT (the ONLY plugin↔host boundary)
+ InProcess (host / built-in plugins / tests)
+ OcsPluginApiIpc (plugin) PluginRequest::DocApiRequest{tab_id, bytes}
+ │ │
+ └────────────┬───────────────────────┘
+ ▼
+EXECUTOR (executor.rs — crate-owned, ONE implementation)
+ apply_op validate+compute → push_undo → mutate → finalize_op
+ apply_queries read-only batch (capped)
+ │
+ ▼
+HOST BACKEND (src/app/doc_api.rs — HostSession)
+ tab authorization reject tab_id ≠ bound tab
+ DocApiBackend impl resolve_body · store_solid · transform · add_*
+ bounds · volume · centroid · can_remove
+ │
+ ├──► Scene (per tab) solid_models · meshes · erase_entities
+ │ geometry_epoch · doc_api_mass_cache
+ │ doc_api_cold_tess_used
+ └──► CadDocument (acadrust) entities · block_records · handles
+ │
+ ▼ produce
+ Receipt ──► facade turns it into a typed result (Solid, Aabb, f64, …)
```
-**How to read it:**
+**How to read it (top to bottom = the path of a request):**
-- **Blue (source of truth)** — `spec/entities.toml` + `layouts.json`. Change
+- **SINGLE SOURCE OF TRUTH** — `spec/entities.toml` + `layouts.json`. Change
*these* to change the API surface; everything else regenerates or maps onto them.
-- **Green (codegen)** — `build.rs` derives the wire enums, the human reference,
+- **CODEGEN OUTPUT** — `build.rs` derives the wire enums, the human reference,
and the binding handover schema. The `Operation`/`Query` enums are the canonical
append-only wire vocabulary; the spec's `op`/`query` names must map to them
(enforced by `spec_wire_consistency` tests).
-- **Facade → wire → transport** — a plugin's `solid.intersect(&other)` becomes an
+- **FACADE → WIRE → TRANSPORT** — a plugin's `solid.intersect(&other)` becomes an
`Operation`, wrapped in a `DocApiEnvelope`, and shipped via the one `Transport`
(in-process or IPC). Identical request either way.
-- **Amber (hot paths)** — the executor's per-op invariant and the host's tab
- authorization + per-tab `Scene` state (solid cache, geometry epoch, the
- persistent cold-tessellation budget). This is where atomicity and the DoS
- boundaries live.
-- **Response** — the host produces a `Receipt` (outcome + query results + new
- geometry revision) that the facade turns back into a typed result (`Solid`,
+- **EXECUTOR + HOST BACKEND** — the hot paths: the executor's per-op invariant,
+ tab authorization, and the per-tab `Scene` state (solid cache, geometry epoch,
+ the persistent cold-tessellation budget). Atomicity and the DoS boundaries live here.
+- **Receipt (response)** — the host produces a `Receipt` (outcome + query results
+ + new geometry revision) that the facade turns back into a typed result (`Solid`,
`Aabb`, `f64`, …).
## Per-op execution model (the load-bearing invariant)