# ETAF Module Responsibilities and Target Architecture (Unimplemented Proposal) > Status: design proposal. This is not the delivered API. Current behavior remains > defined by [`architecture.en.md`](../architecture.en.md), > [`user-guide.en.md`](../user-guide.en.md), and passing tests. This document defines only the target model, module owners, dependency direction, and completion criteria. Delivery sequencing belongs in a separate implementation plan; historical names and compatibility do not shape the target architecture. User mental cost is a hard constraint: one capability has one canonical name and one recommended spelling. Internal algorithms, backend nodes, wrappers, and compatibility aliases never become peer public concepts. Ordinary applications learn Text, Box, and Component first; Fragment, layout detail, and lower packages are progressively disclosed. ## 1. Final model ```text Component semantics and ownership ↓ View: Text / Box / Fragment ↓ Ebox: measurement, layout, geometry patches ↓ TP + Emacs adapter: paint and final submission ``` The main public concepts are `Text`, `Box`, and `Component`. `Fragment` is advanced structure, `Host` is an internal Renderer term, and an Ebox Node is a backend object. The complete normalized View shape is: ```text View = Text | Box | Fragment | ComponentCall ``` `expr` and `slot` are computation/projection mechanisms, not visual nodes. The target public View does not accept raw Ebox Nodes. Missing rendering capability must become a typed View/Ebox feature with explicit identity and impact contracts rather than an opaque escape. ## 2. Text, Box, and Fragment ### 2.1 Text Text is a leaf that owns strings and inline Text runs, typography/paint, text measurement and wrapping input, and optional identity/semantic/event properties. Text defaults to `:outer 'inline`. It cannot own Box/Component children or establish row, column, flex, or grid layout. Use an outer Box for padding, border, dimensions, or child layout. ### 2.2 Box axes ```text :outer = inline | block :layout = normal | row | column | flex | grid ``` `:outer` controls participation in a parent normal layout. `:layout` controls child layout. Defaults are `Box: block/normal` and `Text: inline`. ```elisp (box :outer 'inline :layout 'flex ...) ``` This is inline-flex: an orthogonal combination, not another node type. ETAF exposes `:outer` and `:layout`, not `:inner` or Ebox's raw display-pair representation. ### 2.3 Bounded normal layout Normal layout supports only: - consecutive inline Text/Box nodes in one wrapping line flow; - block Boxes starting a new independent block; - stable child order and block boundaries ending adjacent inline lines. It does not implement full browser CSS: no floats, tables, absolute/fixed positioning, run-in, list-item, or arbitrary anonymous-box rules. Ebox may map `normal` to an internal flow algorithm; `flow` is not ETAF vocabulary. For row, column, flex, or grid parents, the parent algorithm owns item placement and a child's `:outer` does not change ordering. `:outer` is consumed only by a normal parent. ### 2.4 Other layout modes | Mode | Responsibility | | --- | --- | | `row` | simple horizontal order without Flex distribution | | `column` | simple vertical order without Flex distribution | | `flex` | Flex sizing, direction, wrapping, alignment, and gaps | | `grid` | two-dimensional tracks, placement, spans, and gaps | They are Box modes, not Components or alternate Runtime node names. The only canonical surface is `(box :layout 'MODE ...)`; core provides no layout-name aliases. ### 2.5 Ebox DSL primitives and sugar ETAF View and Ebox DSL are different layers: ETAF has Text/Box/Fragment/Component, while Ebox receives lowered content and layout. The target Ebox DSL has one structural tag: ```elisp (box :layout MODE ...) ``` An Ebox box may be a content leaf or own children and a layout context. A Range descriptor is an incremental backend protocol, not an authoring node. A bare string is content-literal shorthand, not a node type. Current tags classify as follows: | Current tag | Classification | Target expression | | --- | --- | --- | | `ebox` | compatibility alias for `box` | remove; use `box` | | `spacer` | empty-Box convenience sugar | remove; use a childless `box` | | `row` | layout-tag sugar | `(box :layout 'row ...)` | | `column` | layout-tag sugar | `(box :layout 'column ...)` | | `flex` | layout-tag sugar | `(box :layout 'flex ...)` | | `grid` | layout-tag sugar | `(box :layout 'grid ...)` | | `item` | Flex-child participation sugar | put flex/order/align-self properties on the child Box | | `grid-item` | Grid-child placement sugar | put grid placement properties on the child Box | Item wrappers are therefore unnecessary. Parent-participation properties belong to the child Box and are validated by the parent layout mode: ```elisp (box :layout 'flex (box :flex-grow 1 :content "A")) (box :layout 'grid (box :grid-column '(1 :span 2) :content "Header")) ``` These are low-level Ebox examples, so Ebox `:content` is valid. ETAF View continues to use Text/children and does not expose `:content`. The target Ebox DSL retains none of those aliases or sugar tags. Ebox still implements the layout algorithms independently, but algorithm kinds are not authoring node kinds. ### 2.6 Fragment Fragment is a nonvisual structural Range. It may contain zero, one, or many sibling Views, creates no Box or layout context, and may carry only a stable `:key` plus children. Runtime may retain and replace its Range independently. A Component call has no fixed outer/layout properties. Its root Text/Box determines participation. A transparent Component returning a Fragment may have multiple roots. ### 2.7 Strings, content, and empty Boxes Strings under a Box normalize to Text, so `(box "text")` equals `(box (text "text"))`. ETAF does not expose `(box :content ...)`; `:content` remains an Ebox backend field. ETAF also has no spacer type: a childless Box is an empty Box. ## 3. Property contract Properties form closed, owner-specific schemas. Unknown or inapplicable combinations fail explicitly. | Owner | Category | Representative properties | | --- | --- | --- | | Text | outer participation | `:outer` | | Text | text/paint | `:face`, `:color`, `:bgcolor`, `:wrap-mode`, `:text-align` | | Box | outer/inner layout | `:outer`, `:layout` | | Box | geometry/surface | width/height/min/max, margin, padding, border, box sizing, overflow | | Flex container/item | layout/participation | direction, wrap, alignment, gap, grow/shrink/basis/order | | Grid container/item | layout/participation | tracks, auto flow, placement, spans, alignment, gap | | Text/Box | identity/semantics | `:key`, `:ref`, class/id/role/ARIA/events/Behaviors | Key rules: - `:key` is identity metadata, not paint; - outer/layout/layout-specific properties have structure/geometry impact; - color/background/typography have paint impact; - ECSS preserves that impact classification; - TP consumes resolved paint contributions only; - structural changes transactionally replace the required layout context. ## 4. Module owners ### ETAF Core `etaf-view` owns normalized View shapes, string-to-Text normalization, closed property schemas, slots, keys, and expression boundaries. It does not measure, lay out, or write buffers. `etaf-component` owns Component props and `:view`/`:setup`/`:styles` definitions. It does not schedule Runtime or call Ebox. `etaf-runtime` owns Component/Fragment/Range identity, reactive dependencies, Context, Theme, Actions, Behaviors, Data, Resources, lifecycle, candidate generations, commit authority, rollback, and disposal. It does not compute pixels. `etaf-renderer` is the only ETAF-to-Ebox lowering adapter. It consumes normalized View and computed properties without accessing Ebox private state. Theme token meaning and inheritance belong to ETAF Context, not TP. ### Ebox Ebox owns Text measurement/wrapping/line layout, normal/row/column/flex/grid geometry, the box model, overflow/scroll/viewport behavior, stable Ebox node identity, geometry snapshots, and structural patch plans. It does not know Component semantics or paint contribution priority. Logical boundaries: ```text ebox-core pure measurement, layout, snapshots, structural patches ebox-emacs font/window capabilities, buffer positions, structural submission ``` These need not become separate distribution packages immediately, but must remain independently testable. ### ECSS ECSS owns selectors, cascade, inheritance, and computed properties. Its output retains structure/geometry/paint impact. ECSS does not run layout or write buffers. ### TP and commit boundary TP owns paint-contribution priority, paint-operation merging, Emacs text-property journaling, application, and rollback. ```text ETAF Runtime creates a candidate and owns commit authority ↓ Ebox stages structural/geometry patches ↓ TP stages paint patches ↓ Emacs adapter atomically applies both ↓ ETAF Runtime promotes the generation; failure rolls participants back ``` Ebox does not own TP priority, TP does not own layout, and neither participant may promote a Runtime generation. ### Upper packages | Package | Owns | Does not own | | --- | --- | --- | | `etaf-ui` | ordinary reusable Components | another Runtime or layout engine | | `etaf-sqlite` | SQLite Data Source and its transactions/disposal | Data Controller or UI | | `etaf-performance` | application-neutral operations/stages/statistics/reports | example semantics or scheduling authority | | `ebox-playground` | public Ebox examples/verification | ETAF | | `etaf-playground` | ETAF/UI/SQLite composition examples and tooling | core protocols | `etaf-performance` is a separate optional package. No measured package depends on it; it observes only public boundaries. A Playground `.etaf` manifest belongs to the Playground. Any future general compiler must lower to the same View/Component contract. ## 5. Dependency direction ```text etaf-ui ─────────────▶ ETAF Core ─────────────▶ Ebox public port etaf-sqlite ─────────▶ ETAF Data contract etaf-playground ─────▶ ETAF + optional UI/SQLite ebox-playground ─────▶ Ebox only etaf-performance ────▶ public observation boundaries only ETAF Renderer ───────▶ ECSS computed properties ETAF Runtime ───────▶ Ebox/TP transaction participants ``` Reverse dependencies are forbidden: Ebox never depends on ETAF, TP never parses View, ECSS never writes buffers, UI never calls Ebox private APIs, SQLite never knows UI, and Playgrounds never inject protocols into core. ## 6. Rust and Elisp Boundaries precede implementation language. Deterministic kernels may move to Rust only after contracts and equivalence tests are stable: ```text Rust candidates: normalized View validation and structural diff over opaque stable IDs ECSS cascade Text-measurement input processing and Ebox layout pure geometry/paint patch computation Elisp / Emacs: user Components, refs, Context, Actions, Data, Resources, lifecycle database and external I/O Emacs events, font/window capabilities, and final submission ``` Component identity, dependency ownership, TP priority, and generation authority do not move merely because a kernel is written in Rust. Elisp must not repeat Rust diff, cascade, layout, or text scans. ## 7. Correctness and performance invariants - View, computed properties, geometry snapshots, and paint contributions materialize once per transaction; - Text paint changes do not execute unrelated Components or layout; - outer/layout/geometry changes affect only the required layout owner; - Fragment/slot/list changes replace only their Range; - Ebox/TP/Emacs participant failure preserves the last committed generation; - resize uses current window facts immediately, without hidden debouncing semantics; - instrumentation does not change the measured path. Final gates cover structural equivalence, legal/illegal outer-layout combinations, normal inline/block behavior, row/column/flex/grid GUI behavior, Component roots and Fragments, style/Theme/TP priority and rollback, continuous Research Shelf/Flex reference resize, and p95/max at or below 50ms in fixed real scenarios. ## 8. Current gap and non-goals Current code still registers `text`, `fragment`, `container`, `row`, `column`, `stack`, `flex`, `grid`, and `spacer`, and exposes `raw-ebox`. Target `box`, `:outer`, and `:layout 'normal` are not implemented, and the target public View does not retain `raw-ebox`. Current Ebox DSL still accepts `box`, `ebox`, `row`, `column`, `flex`, `item`, `grid`, `grid-item`, and `spacer`. The target Ebox DSL keeps only `box`; all other tags are removed or represented as Box properties according to the table above. This is a clean redesign: old Host names and old `.etaf` sources need not continue to run, and no long-lived compatibility layer is added. Formal architecture/user docs must not present target syntax as delivered before implementation is complete. Non-goals: - full browser CSS; - spacer, public flow, or `(box :content ...)`; - injecting raw Ebox Nodes into View; - layout modes as Components or alternate Runtime nodes; - old Host aliases or optional layout shorthand in core; - core protocols owned by Playground/UI/database packages; - App precompilation without measured compile cost and runtime benefit.