# Structive Extension Architecture [中文](EXTENSIONS.zh-CN.md) ## 1. Extension role Extensions add domain metadata and domain interpretation without making Property Core depend on that domain. The dependency direction is: ```text Extension → Property Core Property Core -X→ Extension ``` Core supplies: - schema and property descriptors; - intrinsic readable/writable capability; - the Attribute protocol; - constraints; - synchronization metadata and managed access; - runtime structural access. Extensions add their own categories and interpretation. ## 2. Extension principle An extension should own only its domain semantics. For example, Presentation owns: ```text label description group order ``` It does not need Property Core to understand presentation. Likewise, a future persistence extension may own persistence-specific metadata, and an RPC extension may own protocol metadata. ## 3. External policy stays external Property Core has no built-in access-control mode. An extension or application layer is responsible for its own policy: ```text Should this property be visible? Should this endpoint permit a write? Should this property be persisted? Does the current user have permission? ``` An extension may inspect structural facts such as: ```text Property::readable Property::writable sensitive metadata extension-owned metadata ``` but the final policy belongs to the consumer. A `read_only` property means the Structive managed object itself has no write operation for that property. It does not mean every external system must expose it. ## 4. Current presentation extension Include: ```cpp #include ``` Link: ```cmake target_link_libraries(my_target PRIVATE structive::property_extensions) ``` Available Attributes: ```cpp presentation::label<"Temperature"> presentation::description<"Current device temperature"> presentation::group<"Environment"> presentation::order<2> ``` Example: ```cpp field<&Device::temperature>( key<"temperature">, unit<"C">, presentation::label<"Temperature">, presentation::description<"Current device temperature">, presentation::group<"Environment">, presentation::order<2> ) ``` ## 5. Presentation interpretation ```cpp auto info = presentation::describe<&Device::temperature>(device.schema()); ``` `Presentation_Info` contains: ```text key label description group order has_order ``` If no label is supplied, the presentation extension falls back to the property key. That fallback is presentation behavior, not Core behavior. ## 6. Inheritable extension Attributes An extension category may choose to be inheritable. ```cpp defaults( presentation::group<"Environment"> ) ``` Property-level metadata overrides an inheritable single-valued default from the same category. Use inheritance only for metadata whose semantics genuinely support inheritance. ## 7. Designing a new extension Attribute A simple extension Attribute can be defined as: ```cpp namespace my_extension { struct Format_Category {}; template struct Format_Attribute { using attribute_category = Format_Category; static constexpr bool single_valued = true; static constexpr bool inheritable = false; static constexpr auto value = Value; }; template inline constexpr Format_Attribute format{}; } ``` Then attach it normally: ```cpp field<&Device::temperature>( key<"temperature">, my_extension::format<"0.0 C"> ) ``` Core does not require modification. ## 8. Reading extension Attributes Descriptor-local metadata: ```cpp using Property = std::remove_cvref_t())>; static_assert(Property::template has_attribute); ``` Effective inheritable metadata can use Core's generic effective-Attribute utilities. The extension owns fallback and interpretation rules. ## 9. Multi-valued metadata If a category is not single-valued, an extension may allow multiple Attributes from that category. Do not mark a category `single_valued` unless duplicate declarations are structurally invalid. ## 10. Recommended extension boundaries Good extension domains include: - presentation and editor hints; - serialization naming and format hints; - persistence mapping metadata; - RPC/protocol naming metadata; - diagnostics and telemetry metadata; - documentation metadata. The domain implementation should remain outside Property Core. ## 11. Using intrinsic capability A consumer may use intrinsic capability as a structural fact. For example, an editor can decide that a property is only eligible for an editable widget when: ```cpp Property::writable ``` That is only eligibility. The editor may still apply additional application policy. A persistence adapter may choose not to store a property even when `Property::readable` is true. An RPC endpoint may choose not to expose a writable property at all. This separation is intentional. ## 12. Read-only optimization is a Core fact Extensions do not need to implement special locking for `read_only` stored properties. Core guarantees that such properties do not contribute lock slots or mutexes to the managed object and managed reads use the no-lock path. An extension that deliberately performs raw C++ writes bypasses that guarantee and owns synchronization itself. ## 13. Fallback behavior belongs to the consumer Core should not decide domain fallbacks such as: ```text missing label -> key missing database column -> key missing RPC name -> key ``` Those rules belong to the corresponding extension or adapter. ## 14. Avoid semantic leakage into Core Do not add a Core enum or special branch only because one extension needs it. Prefer: ```text extension-owned Attribute category + extension-owned interpretation ``` over: ```text Core learns the extension domain ``` ## 15. Linked code versus header-only metadata Metadata types can usually remain header-only. Linked extension code is appropriate when a domain needs non-template runtime behavior. The current presentation extension keeps metadata in headers and provides `make_presentation_info` in the linked target. ## 16. Extension review checklist Before adding an extension feature, ask: 1. Does Core already provide the required generic structural mechanism? 2. Can the feature be expressed as an extension-owned Attribute? 3. Is its fallback rule owned by the extension? 4. Is access/exposure policy being kept outside Core? 5. Is intrinsic `readable/writable` being treated as structure rather than authorization? 6. Does the extension avoid raw writes that would bypass managed synchronization unless intentional? 7. Does Core remain independent of the extension?