From 46c5a69a7afb8283e8d5f90c7858fe179e66f261 Mon Sep 17 00:00:00 2001 From: Kinneyzhang Date: Wed, 26 Aug 2026 11:56:34 +0800 Subject: [PATCH] docs: converge target module boundaries --- docs/proposals/module-boundaries.en.md | 377 +++++++++------- docs/proposals/module-boundaries.zh.md | 601 ++++++++++--------------- 2 files changed, 456 insertions(+), 522 deletions(-) diff --git a/docs/proposals/module-boundaries.en.md b/docs/proposals/module-boundaries.en.md index c11986b..b1c9621 100644 --- a/docs/proposals/module-boundaries.en.md +++ b/docs/proposals/module-boundaries.en.md @@ -1,220 +1,281 @@ # ETAF Module Responsibilities and Target Architecture (Unimplemented Proposal) -> Status: design proposal. This is not the current public API or a delivered -> implementation. The current contract remains [`architecture.en.md`](../architecture.en.md), -> [`user-guide.en.md`](../user-guide.en.md), and the passing tests. +> 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 proposal defines clean-slate ownership boundaries for ETAF, Ebox, ECSS, -TP, `etaf-ui`, `etaf-sqlite`, the performance recorder, and both Playgrounds. It -describes the target architecture; current compatibility names are not treated as -the architecture itself. +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. -The target parts below are not delivered API until code, tests, and real benchmarks -prove them. This proposal does not change the current Host registry, View grammar, -or package dependencies. - -## 1. Minimal stable model - -ETAF has four representations: +## 1. Final model ```text Component semantics and ownership ↓ -Text / Box View structure +View: Text / Box / Fragment ↓ -Ebox geometry and render plan +Ebox: measurement, layout, geometry patches ↓ -TP / Emacs final submission +TP + Emacs adapter: paint and final submission ``` -The public concepts are: +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. -| Concept | Owns | Does not own | -| --- | --- | --- | -| `Text` | text content, typography, inline properties, wrapping input | subtree layout, business state, lifecycle | -| `Box` | size, surface, children, and layout | Component identity, Data, Actions | -| `Component` | reusable semantics, props, slots, state, Context, Actions, lifecycle | pixel measurement and layout algorithms | +The complete normalized View shape is: -`Host` is an internal Renderer term for a primitive lowered to a backend. It is not a -third public visual taxonomy. An `Ebox Node` is a lower-level geometry/render object. +```text +View = Text + | Box + | Fragment + | ComponentCall + | RawEbox +``` -ETAF should keep two orthogonal Box properties instead of turning these concepts into -Components: +`expr` and `slot` are computation/projection mechanisms, not visual nodes. `RawEbox` +is an opaque low-level escape and does not inherit normal View semantics. + +## 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` describes how the Box participates in its parent's ordinary layout; -`:layout` describes how the Box arranges its own children. `normal` is the clearer -user-facing name for ordinary content layout; the Renderer may lower it to Ebox's -internal ordinary-content path. - -The target View model is: - -```text -View = Text(content, typography) - | Box(layout, surface, children) - | ComponentCall(props, slots) -``` - -The Box inner-layout modes exposed by the target ETAF API are a closed set: - -```text -normal | row | column | flex | grid -``` - -A plain Box defaults to `:outer 'block :layout 'normal`; it does not silently become a -column. Use `:layout 'column` for vertical stacking, or choose `row`, `flex`, or `grid` -explicitly. Text defaults to inline content in normal layout and owns text measurement, -wrapping, and inline runs. - -The mapping is: - -| CSS meaning | Target ETAF expression | -| --- | --- | -| ordinary block content | `(box :outer 'block :layout 'normal ...)` | -| ordinary inline content | `(box :outer 'inline :layout 'normal ...)` | -| vertical stacking | `(box :layout 'column ...)` | -| horizontal layout | `(box :layout 'row ...)` | -| flex container | `(box :layout 'flex ...)` | -| grid container | `(box :layout 'grid ...)` | - -`inline-flex` is the direct orthogonal combination: +`: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 ...) ``` -A Component call has no fixed `:outer` or `:layout`; its root Text/Box output decides -how it participates in the parent. A transparent Component may return siblings and -therefore has no single outer Box. +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. -`(box "text")` is shorthand for `(box (text "text"))`. ETAF must not expose -`(box :content "text")`; `:content` remains an Ebox backend field. +### 2.3 Bounded normal layout -ETAF also does not define a public `spacer` type. A Box with no children is an empty -Box; Ebox may use an empty-node representation or private helper, but users do not -need another visual category. +Normal layout supports only: -Box properties remain grouped by owner rather than becoming one unconstrained plist: +- 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. -| Group | Properties | Purpose | +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 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.6 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 | | --- | --- | --- | -| structure | `:outer`, `:layout`, `:key` | participation, child layout, identity | -| geometry/surface | `:width`, `:height`, min/max, `:margin`, `:padding`, `:border`, `:box-sizing`, `:overflow` | size and surface | -| text | `:face`, `:color`, `:bgcolor`, `:wrap-mode`, `:text-align` | typography and text paint | -| flex item | `:order`, `:flex-grow`, `:flex-shrink`, `:flex-basis`, `:align-self` | valid under a Flex parent | -| grid item | `:grid-row`, `:grid-column`, spans | valid under a Grid parent | -| semantics/interaction | `:class`, `:id`, `:role`, `:ref`, `:aria-*`, `:on-*`, `:use` | Runtime events, Behaviors, and queries | +| 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 | -`:outer` and `:layout` are geometry/structure properties, not TP paint slots. ECSS may -resolve them, but Ebox validates the final combination and owns the layout result. +Key rules: -Ebox may keep an outer/inner display representation internally; the public split is -the explicit `:outer` and `:layout` contract. +- `: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. -## 2. Module responsibilities +## 4. Module owners ### ETAF Core -`etaf-view` owns the View grammar, Text/Box/Component-call normalization, property -and slot shape validation, expression boundaries, and Component registration. It does -not measure pixels, lay out nodes, write buffers, or implement business data. +`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 `etaf-define-component`, `:view`, `:setup`, `:styles`, and -definition validation. It does not own Runtime scheduling or Ebox nodes. +`etaf-component` owns Component props and `:view`/`:setup`/`:styles` definitions. It +does not schedule Runtime or call Ebox. -`etaf-runtime` owns retained identity, reactive refs/computed/effects/watchers, Scope -cleanup, Context/Theme, Actions, Behaviors, Data, Resources, lifecycle, invalidation, -transactions, commit, and rollback. It does not own pixel layout or Ebox private state. +`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 boundary. It translates Text, Box, -and Component output to public Ebox constructors and carries resolved style/paint -contributions downstream. It does not own Component lifecycle or data requests. +`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 is the layout and rendering engine, not the ETAF Component Runtime. It owns text -measurement, wrapping, row/column/flex/grid geometry, -surface/scroll geometry, -stable layout snapshots, and render/paint plans. It does not know Components, slots, -Context, Actions, Behaviors, Data, or Resources. +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. -Logically it has two boundaries: +Logical boundaries: ```text -ebox-core pure measurement, layout, snapshots, and render plans -ebox-emacs font/window capabilities and Emacs buffer submission +ebox-core pure measurement, layout, snapshots, structural patches +ebox-emacs font/window capabilities, buffer positions, structural submission ``` -They need not be separate distribution packages immediately, but geometry and Emacs -side effects must not become one responsibility. +These need not become separate distribution packages immediately, but must remain +independently testable. -### ECSS and TP +### ECSS -ECSS owns selectors, declarations, cascade, inheritance, and computed styles. It does -not own Runtime state, layout, or buffer writes. +ECSS owns selectors, cascade, inheritance, and computed properties. Its output retains +structure/geometry/paint impact. ECSS does not run layout or write buffers. -TP owns layered Emacs text-property/paint slots, priority merging, atomic application, -journaling, and rollback. It does not parse selectors, measure layout, or execute -Components. +### TP and commit boundary -### Optional/application packages - -`etaf-ui` owns reusable Button, Checkbox, Label, Panel, Number input, DataGrid, and -Pagination Components. It does not implement another Runtime or layout engine. - -`etaf-sqlite` owns SQLite connections, schema/query/mutation validation, paging, and -Data Source disposal. It does not own Data Controller state or UI. - -The performance recorder owns application-neutral operation/stage records, summaries, -environment context, and export. It observes public boundaries and never embeds a -Playground name or changes the measured render path. - -`ebox-playground` only validates public Ebox layout APIs. `etaf-playground` validates -ETAF composition and may optionally load `etaf-ui` and `etaf-sqlite`; neither Playground -owns framework protocols. A static `.etaf` manifest belongs to the Playground unless a -future compiler lowers it to the same Text/Box/Component contract. - -## 3. Dependency direction +TP owns paint-contribution priority, paint-operation merging, Emacs text-property +journaling, application, and rollback. ```text -etaf-ui ───────▶ ETAF Core ───────▶ Ebox public layout port -etaf-sqlite ──▶ ETAF Data contract -etaf-playground ─▶ ETAF + optional UI/SQLite -ebox-playground ─▶ Ebox public API only -performance ───▶ public probes only +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 never depends upward on ETAF. TP never parses View trees. ECSS never writes -buffers. UI never calls private Ebox functions. SQLite never knows UI. Playgrounds -never inject example protocols into core. +Ebox does not own TP priority, TP does not own layout, and neither participant may +promote a Runtime generation. -## 4. Rust and Elisp split +### Upper packages -Rust is for deterministic, environment-independent computation: normalized Render IR, -keyed diff/patch, ECSS cascade, text measurement/wrapping, ordinary Box/flex/grid layout, -geometry snapshots, and paint-contribution merging. +| 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 | -Elisp/Emacs owns user Component execution, refs, Context, Actions, Data, Resources, -lifecycle callbacks, Emacs events/windows/fonts, and final patch submission. Elisp must -not reimplement Rust layout/cascade/diff; Rust must not read Emacs buffers or understand -Component slots. +`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. Invariants and evolution +## 5. Dependency direction -One transaction materializes stable identity, dependencies, layout snapshots, and paint -contributions once. Text paint changes do not rerun unrelated Components or layout. -Box geometry changes affect only the required layout owner. Component state/slot/list -changes affect only the owner of that structure. Failed Ebox/TP candidates preserve the -last committed result. +```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 -The clean public direction is `Text + Box(layout) + Component`. If concise syntax is -needed, `row`/`column`/`flex`/`grid` may be introduced as new compiler sugar, but they -are not compatibility aliases and must not become Runtime Components. `fragment` is -transparent structure. `spacer` and `flow` are not public ETAF types; the target Ebox -may replace the current `(block flow)` marker with ordinary Box/Text paths instead of -retaining a separate flow branch. The redesign does not preserve the old Host registry -names or add a compatibility layer. This target is not implemented merely by documenting it. +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`. Target `box`, `:outer`, and `:layout 'normal` are not +implemented. + +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 ...)`; +- 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. diff --git a/docs/proposals/module-boundaries.zh.md b/docs/proposals/module-boundaries.zh.md index be4fe76..a1d1d80 100644 --- a/docs/proposals/module-boundaries.zh.md +++ b/docs/proposals/module-boundaries.zh.md @@ -1,122 +1,138 @@ # ETAF 模块职责与目标架构(设计提案,未实现) -> 状态:设计提案。本文不是当前公共 API 或已交付实现的规范;当前可用契约仍以 +> 状态:设计提案。本文不描述当前已交付 API。当前行为仍以 > [`architecture.zh.md`](../architecture.zh.md)、[`user-guide.zh.md`](../user-guide.zh.md) -> 和实际测试为准。 +> 和通过的测试为准。 -本文把 ETAF、Ebox、ECSS、TP、`etaf-ui`、`etaf-sqlite`、性能工具和两个 -Playground 的职责收敛成一份待评审的边界提案。它描述的是从零设计时应保持的 -模型,不是把当前实现中的每个文件名当成架构真相。 +本文只定义目标模型、模块 owner、依赖方向和完成条件。实现顺序属于单独的 +实施计划;历史名称和兼容策略不参与目标架构设计。 -文中标有“目标”的部分是后续演进方向;除非代码、测试和基准同时完成,不能 -把目标 API 描述成已经交付的功能。提案没有自动授权实现,也不改变当前 Host -注册表、View 语法或包依赖。 +## 1. 最终模型 -## 1. 最小稳定模型 - -ETAF 需要区分四种表示,而不是把它们都叫作“组件”或“box”: +ETAF 的表示链只有四层: ```text Component 语义与所有权 ↓ -Text / Box View 结构 +View:Text / Box / Fragment ↓ -Ebox 几何与渲染计划 +Ebox:测量、布局、几何 patch ↓ -TP / Emacs 最终提交 +TP + Emacs adapter:paint 与最终提交 ``` -### 1.1 公共概念 +用户需要理解的主要概念只有 `Text`、`Box` 和 `Component`。`Fragment` 是高级 +结构语法;`Host` 是 Renderer 内部术语;`Ebox Node` 是后端对象,都不构成第二套 +组件模型。 -用户只需要学习三个主要概念: +规范化 View 的完整形状是: -| 概念 | 稳定职责 | 不负责的事情 | -| --- | --- | --- | -| `Text` | 文本内容、字体、inline text properties、换行入口 | 子树布局、业务状态、生命周期 | -| `Box` | 尺寸、背景、边框、padding、子节点和布局 | Component identity、Data、Action | -| `Component` | 可复用语义、props、slot、状态、Context、Action、生命周期 | 像素测量和布局算法 | +```text +View = Text + | Box + | Fragment + | ComponentCall + | RawEbox +``` -`Host` 是 Renderer 内部用于称呼可直接降低到后端的原语,不是用户需要额外 -学习的第三套视觉分类。`Ebox Node` 则是更底层的几何/渲染对象;它可以由一个 -`Text`、一个 `Box`,或一棵 Component 子树产生。 +`expr` 和 `slot` 是计算/投影机制,不是视觉节点。`RawEbox` 是明确的低层出口, +不获得正常 View 的样式、事件或增量语义。 -### 1.2 Text 与 Box 的关系 +## 2. Text、Box 与 Fragment -CSS 中所有最终可见元素都会产生 box,但 CSS 生成的 box、ETAF 的 View 原语和 -Ebox 的后端节点不是同一棵树。`inline` 和 `block` 描述盒子参与父布局的方式; -`flex` 和 `grid` 描述盒子内部如何排列子节点。 +### 2.1 Text -因此 ETAF 不应该把这些概念做成 Component,而应在 Box 上保留两个正交属性: +`Text` 是文本叶子,负责: + +- 字符串和 inline Text runs; +- 字体、前景/背景、下划线等文本 paint; +- 文字测量、换行和文本对齐的输入; +- 可选 identity、语义和事件属性。 + +`Text` 默认 `:outer 'inline`。它不能拥有 Box、Component 或任意布局子节点,也 +不能建立 `row`、`column`、`flex` 或 `grid` 上下文。需要 padding、border、尺寸 +或子布局时,在外层使用 `Box`。 + +### 2.2 Box 的两个正交轴 + +`Box` 同时拥有一个外部参与方式和一个内部布局方式: ```text :outer = inline | block :layout = normal | row | column | flex | grid ``` -`:outer` 表示这个 Box 如何参与父级的普通布局;`:layout` 表示这个 Box 如何 -排列自己的子节点。`normal` 是 ETAF 用户层对普通内容布局的名称,Renderer -可以把它降低为 Ebox 内部的普通内容路径。 +- `:outer`:这个 Box 如何参与父级的 `normal` 布局; +- `:layout`:这个 Box 如何排列自己的子节点。 -目标公共模型是: +默认值是: ```text -View = Text(content, typography) - | Box(layout, surface, children) - | ComponentCall(props, slots) +Box :outer block :layout normal +Text :outer inline ``` -目标中 ETAF 对用户暴露的 Box 内部布局模式是封闭集合: - -```text -normal | row | column | flex | grid -``` - -普通 `Box` 默认是 `:outer 'block :layout 'normal`,不会隐式变成 `column`。 -需要纵向堆叠时明确写 `:layout 'column`;需要横向、Flex 或 Grid 时明确选择 -对应模式。`Text` 默认作为 inline content 参与 normal 布局,但自身负责文字 -测量、换行和 inline runs。 - -语义映射大致为: - -| CSS 语义 | ETAF 目标表达 | -| --- | --- | -| inline text/run | `text` | -| 普通 block 内容 | `(box :outer 'block :layout 'normal ...)` | -| 普通 inline 内容 | `(box :outer 'inline :layout 'normal ...)` | -| 纵向排列 | `(box :layout 'column ...)` | -| horizontal layout | `(box :layout 'row ...)` | -| flex container | `(box :layout 'flex ...)` | -| grid container | `(box :layout 'grid ...)` | - -`inline-flex` 是两个属性的正交组合: +`inline-flex` 是两个轴的组合,不是新的节点类型: ```elisp (box :outer 'inline :layout 'flex ...) ``` -Component call 自身没有固定的 `:outer` 或 `:layout`;它的根 Text/Box 输出决定 -它如何参与父级布局。透明 Component 可以输出多个兄弟节点,因此不能假定每个 -Component 都有一个外部盒子。 +公开 API 使用 `:outer` 和 `:layout`。不公开 `:inner`,也不要求用户写 Ebox 的 +`(:display (block flow))` 一类后端表示。 -### 1.3 属性分组 +### 2.3 normal 的明确范围 -Box 的属性按 owner 分组,不能做成一个无约束的大 plist: +`normal` 是一个真实但刻意收敛的布局上下文: -| 分组 | 属性 | 作用 | -| --- | --- | --- | -| 外部/内部结构 | `:outer`、`:layout`、`:key` | 参与方式、子布局、稳定 identity | -| 几何和表面 | `:width`、`:height`、min/max、`:margin`、`:padding`、`:border`、`:box-sizing`、`:overflow` | 尺寸、表面和可见区域 | -| 文本 | `:face`、`:color`、`:bgcolor`、`:wrap-mode`、`:text-align` | Text 或普通内容的排版/绘制 | -| Flex 子项 | `:order`、`:flex-grow`、`:flex-shrink`、`:flex-basis`、`:align-self` | 只在 Flex 父级中有效 | -| Grid 子项 | `:grid-row`、`:grid-column`、span | 只在 Grid 父级中有效 | -| 语义和交互 | `:class`、`:id`、`:role`、`:ref`、`:aria-*`、`:on-*`、`:use` | Runtime 事件、Behavior 和查询 | +- 连续的 inline `Text` 或 inline `Box` 进入同一行流并按可用宽度换行; +- block `Box` 从新行开始并形成独立块; +- block 前后的 inline 行会在块边界结束; +- 子节点顺序保持稳定。 -`:outer` 和 `:layout` 是结构/几何属性,变化会触发布局 owner;它们不是 TP -paint slot。ECSS 可以参与解析它们,但最终合法性和布局仍由 Ebox 契约验证。 +目标不实现完整浏览器 CSS:没有 float、table、absolute/fixed positioning、 +run-in、list-item 或任意匿名盒规则。Ebox 可以把 `normal` 映射为内部 flow +算法,但 `flow` 不是 ETAF 公共词汇。 -### 1.4 子节点与后端 content +当父级 `:layout` 是 `row`、`column`、`flex` 或 `grid` 时,父算法直接拥有子项 +位置;子项的 `:outer` 不改变排列顺序。`:outer` 只决定节点进入 `normal` 父级时 +是 inline 还是 block。 -目标 ETAF 语法只保留一个内容模型:子节点。 +### 2.4 其他布局模式 + +| 模式 | 职责 | +| --- | --- | +| `row` | 简单水平顺序布局,不执行 Flex 空间分配 | +| `column` | 简单垂直顺序布局,不执行 Flex 空间分配 | +| `flex` | Flex sizing、direction、wrap、alignment 和 gap | +| `grid` | 二维轨道、放置、跨度和 gap | + +这些都是 `Box` 的 layout mode,不是 Component,也不注册 `row`、`column`、 +`flex` 或 `grid` 的第二套 Runtime 节点名称。目标 API 只有规范写法: + +```elisp +(box :layout 'row ...) +(box :layout 'column ...) +(box :layout 'flex ...) +(box :layout 'grid ...) +``` + +### 2.5 Fragment + +`Fragment` 是无视觉 wrapper 的结构 Range: + +- 可以承载零个、一个或多个兄弟 View; +- 不产生 Box、尺寸、背景或布局上下文; +- Runtime 可以为其保留稳定 Range identity 并局部替换; +- 只接受子节点和可选稳定 `:key`,不接受视觉/事件属性。 + +Component call 本身没有 `:outer` 或 `:layout`。它的根 Text/Box 决定如何参与父级 +布局;返回 Fragment 的透明 Component 可以产生多个兄弟节点,因此不存在单一的 +“Component 外部盒子”。 + +### 2.6 字符串、content 与空 Box + +Box 子节点中的字符串规范化为 Text: ```elisp (box "this is text") @@ -128,348 +144,205 @@ paint slot。ECSS 可以参与解析它们,但最终合法性和布局仍由 E (box (text "this is text")) ``` -需要文本属性时显式写 `text`: +ETAF 不提供 `(box :content "...")`。`:content` 只属于 Ebox 后端构造器;暴露它 +会制造 content 与 children 两套结构模型。 -```elisp -(box - :padding '(1 2) - (text :face 'bold "Title")) -``` +ETAF 也不提供 `spacer` 类型。没有子节点的 Box 就是空 Box。 -ETAF 公共语法不增加 `(box :content "...")`。`:content` 是 Ebox 后端构造器 -(例如 `ebox-create`)的内部字段;Renderer 可以把 `text` 降低为后端 content, -但不能把后端字段反向暴露成第二套 ETAF 子树模型。这样可以自然混合字符串、 -Text、Box、Component 和 slot,也不会产生 content 与 children 的优先级歧义。 +## 3. 属性契约 -ETAF 公共模型也不定义 `spacer`。没有子节点的 `Box` 就是空 Box;Ebox 可以在 -内部使用空内容节点或私有 helper 表示它,但这不是用户需要学习的独立视觉类型。 +属性是闭集,并按 owner 验证;未知属性和不适用组合必须报错。 -## 2. 模块职责 +| Owner | 属性类别 | 代表属性 | +| --- | --- | --- | +| Text | 外部参与 | `:outer` | +| Text | 文本/paint | `:face`、`:color`、`:bgcolor`、`:wrap-mode`、`:text-align` | +| Box | 外部/内部布局 | `:outer`、`:layout` | +| Box | 几何/表面 | `:width`、`:height`、`:min-*`、`:max-*`、`:margin`、`:padding`、`:border`、`:box-sizing`、`:overflow` | +| Flex container | 布局 | `:flex-direction`、`:flex-wrap`、`:justify-content`、`:align-items`、`:align-content`、`:gap` | +| Flex item | 父级参与 | `:order`、`:flex-grow`、`:flex-shrink`、`:flex-basis`、`:align-self` | +| Grid container | 布局 | track templates、auto flow、gap、item/content alignment | +| Grid item | 父级参与 | `:grid-row`、`:grid-column`、row/column span | +| Text/Box | identity/语义 | `:key`、`:ref`、`:class`、`:id`、`:role`、`:aria-*`、`:on-*`、`:use` | -下面的边界是“谁拥有完整规则”的判断标准。调用别的模块的公开契约不等于拥有 -那个模块的职责。 +规则: -### 2.1 ETAF Core +- `:key` 是 identity metadata,不是视觉属性; +- `:outer`、`:layout` 和 layout-specific 属性属于 structure/geometry impact; +- color、background、typography 等属于 paint impact; +- ECSS 可以解析上述属性,但必须保留 impact 分类; +- TP 只消费已经解析的 paint contribution,不判断布局合法性; +- 结构属性变化必须事务性重建对应布局上下文,不能走 paint-only 快速路径。 -#### `etaf-view` +## 4. 模块 owner -拥有: +### 4.1 ETAF Core -- `Text`、`Box`、Component call、Fragment 的结构语法和规范化 View 值; -- 属性优先解析和 `expr :value` 求值边界; -- props、`key` 和 slot 的静态形状验证; -- Component 注册表与 View 名称解析。 +`etaf-view`: -不拥有: +- 定义并规范化 Text、Box、Fragment、ComponentCall 和 RawEbox; +- 将字符串规范化为 Text; +- 验证属性闭集、slot、`:key` 和表达式边界; +- 不测量、不布局、不写 buffer。 -- 字宽、像素、布局、滚动和 buffer 写入; -- Component 生命周期和 Runtime 调度; -- 业务数据、数据库、UI 控件实现。 +`etaf-component`: -#### `etaf-component` +- 定义 Component props、`:view`、`:setup`、`:styles`; +- 不调度 Runtime,不调用 Ebox。 -拥有: +`etaf-runtime`: -- `etaf-define-component`; -- `:view`、`:setup`、`:styles` 定义边界; -- props 和静态 Component style 的声明验证。 +- 拥有 Component/Fragment/Range identity、响应式依赖、Context、Theme、Action、 + Behavior、Data、Resource 和 lifecycle; +- 拥有 candidate generation、事务、提交授权、回滚和释放; +- 决定变化影响哪个 Component、Range、结构属性或 paint contribution; +- 不计算像素和布局。 -不拥有: +`etaf-renderer`: -- Ebox 私有节点; -- Data 请求、数据库连接或全局 UI 控件目录。 +- 是唯一 ETAF → Ebox 的 lowering adapter; +- 把规范化 View 和 computed properties 转换为 Ebox 输入; +- 不执行 Component lifecycle,不访问 Ebox 私有状态。 -#### `etaf-runtime` +Theme 的语义 token 和继承属于 ETAF Context。TP 不拥有“暗色主题”等业务意义。 -拥有: +### 4.2 Ebox -- Component identity、`:key`、retained instance; -- ref、computed、effect、watch 和 Scope cleanup; -- Context、Theme、Action、Behavior、Data、Resource 的生命周期; -- 依赖失效、候选 generation、提交、回滚和调度; -- 将变化定位到 Component、Range、Host 属性或 Paint contribution。 +Ebox 拥有: -不拥有: +- Text 测量、换行和行布局; +- `normal`、`row`、`column`、`flex`、`grid` 几何算法; +- width/height、box model、overflow、scroll、viewport; +- 稳定 Ebox node identity、geometry snapshot 和结构 patch plan。 -- 字体测量、flex/grid 算法、像素布局; -- Ebox 私有状态; -- SQLite、HTTP 或某个示例的业务规则。 +Ebox 不理解 Component、slot、Context、Action、Behavior、Data 或 Resource,也不 +决定 paint contribution 的优先级。 -#### `etaf-renderer` - -拥有: - -- 唯一的 ETAF View → Ebox 公共 lowering 边界; -- Text、Box、Component 输出到 Ebox 公共构造器的转换; -- 把已解析的 style/theme/property contribution 传给下游; -- 明确的 `raw-ebox` 低层出口。 - -不拥有: - -- Component setup/lifecycle 的所有权; -- Ebox 的测量和布局实现; -- Data 查询或应用 Action。 - -### 2.2 Ebox - -Ebox 是布局和渲染引擎,不是 ETAF Component Runtime。 - -拥有: - -- 文本测量、字宽、换行和内容高度; -- Text 内容测量和换行,以及 row、column、flex、grid 的几何算法; -- padding、border、surface、overflow、scroll 和 viewport 几何; -- 稳定的布局快照、节点 identity、增量几何更新; -- 从布局结果到后端可提交 Render/Paint plan 的转换。 - -不拥有: - -- Component、props、slot、Context、Action、Behavior、Data、Resource; -- 应用语义或 UI 控件分类; -- ETAF 的响应式依赖图。 - -`row`、`column`、`flex`、`grid` 即使在 ETAF 目标 API 中统一为 -`box :layout ...`,Ebox 内部仍然可以保留不同的布局上下文和算法。统一的是 -上层表达,不是把不同几何问题硬塞进一个无差别函数。 - -逻辑上可以继续拆为两个边界: +逻辑边界: ```text -ebox-core 纯测量、布局、快照和 Render plan -ebox-emacs 字体/窗口能力、Ebox Node 到 Emacs buffer 的提交适配 +ebox-core 纯测量、布局、快照和结构 patch +ebox-emacs 字体/窗口能力、buffer 位置和结构提交 ``` -这两个边界不一定现在就变成两个发行包,但不能让布局算法和 Emacs buffer 副作用 -混在同一个职责中。 +这不要求立即拆成两个发行包,但纯布局和 Emacs 副作用必须能独立测试。 -### 2.3 ECSS +### 4.3 ECSS -拥有: +ECSS 拥有 selector、cascade、继承和 computed properties。输出必须携带属性的 +structure/geometry/paint impact;ECSS 不执行布局,也不写 buffer。 -- selector 解析和匹配; -- style declaration、cascade、继承和 computed style; -- 把静态规则转换为可复用、可验证的样式中间产物。 +### 4.4 TP 与提交边界 -不拥有: +TP 拥有: -- Component state、slot、Action; -- 字宽、布局或 Ebox Node; -- Emacs text property 的提交和回滚。 +- Theme、Component style、state、inline 等 paint contribution 的优先级; +- paint operation 合并; +- Emacs text property journal、apply 和 rollback。 -ECSS 决定“某个结构节点应该得到哪些样式值”,不决定“这些像素如何排布”。 - -### 2.4 TP - -拥有: - -- Emacs text property / paint slot 的分层; -- Theme、Component、state、inline 等 Paint contribution 的优先级合并; -- 原子应用、journal、rollback 和已提交层的复用。 - -不拥有: - -- CSS selector/cascade; -- 布局测量、祖先证明或文字换行; -- Component 和 Data。 - -TP 应接收精确的 Paint operations,不应该为了换一个背景色重新推导整棵 View -或重新执行所有 Component。 - -### 2.5 `etaf-ui` - -拥有官方可复用 Component,例如: - -- Button; -- Checkbox; -- Label; -- Panel; -- Number input; -- DataGrid; -- Pagination。 - -这些控件使用 ETAF 的 props、slot、事件、Behavior、Theme 和 Data 契约。它们 -不是第二套 Widget/Control/Component 模型,也不应该实现自己的 Runtime 或布局 -引擎。 - -### 2.6 `etaf-sqlite` - -拥有: - -- SQLite 连接、schema、查询、分页和 mutation; -- 参数和标识符校验; -- 具体 Data Source 的事务和 dispose 边界。 - -不拥有: - -- ETAF Data Controller 状态机; -- View、Component、DataGrid 或 playground UI。 - -其他数据库、REST、文件和 ORM 集成也应实现同一个具体 Data Source capability, -但使用各自明确的包名,不引入一个笼统的 `etaf-adapters` 层。 - -### 2.7 性能工具 - -性能记录器必须是应用无关的逻辑模块(当前可以先作为 ETAF 中的独立子模块, -未来再决定是否单独发行)。它拥有: - -- operation、stage、父子关系和 generation 记录; -- p50/p95/max、GC、环境信息和跨包阶段关联; -- 公共 Event、Action、mount、flush、Data、Resource、viewport 边界的探针; -- 报告、复制和导出。 - -它不拥有: - -- Research Shelf 或任何示例名称; -- 应用状态或布局规则; -- 为了采样而改变正常渲染路径。 - -Playground 只能展示这个工具,不能定义它的核心协议。 - -### 2.8 两个 Playground - -`ebox-playground`: - -- 只验证 Ebox 的布局、测量、重排和性能; -- 只依赖 Ebox 公共 API; -- 不加载 ETAF、Component、Data Controller 或 UI 目录。 - -`etaf-playground`: - -- 验证 ETAF 的 Component、Runtime、Data、UI 和交互组合; -- 可以选择加载 `etaf-ui` 和 `etaf-sqlite`; -- 提供 `.etaf` 示例加载、快捷键和状态展示; -- 不拥有 ETAF 的核心语法、Runtime 或性能记录协议。 - -`.etaf` 静态文件如果只是 Playground manifest,就属于 Playground;它不是 ETAF -Core 的 Runtime 入口。未来若增加通用 `.etaf` compiler,compiler 必须把结果 -降低到同一套 Text/Box/Component 契约,不能创建第二套 Runtime。 - -## 3. 依赖方向 - -目标依赖图如下: +一次更新的权限顺序固定为: ```text - ┌──────────────┐ - │ etaf-performance │ - │ optional observer│ - └──────┬───────┘ - │ public probes only - ▼ -┌────────────┐ ┌────────────────────┐ ┌──────────────┐ -│ etaf-ui │──────▶│ ETAF Core │──────▶│ Ebox public │ -└────────────┘ │ View/Component/RT │ │ layout port │ - └─────────┬──────────┘ └──────┬───────┘ - │ │ - ┌─────────▼─────────┐ ┌──────▼───────┐ - │ ECSS / TP adapters│ │ Ebox backend │ - └───────────────────┘ │ / Emacs │ - └──────────────┘ - -etaf-sqlite ─────▶ ETAF Data Source contract -etaf-playground ─▶ ETAF + optional etaf-ui + optional etaf-sqlite -ebox-playground ─▶ Ebox public API only +ETAF Runtime 创建 candidate 并拥有提交授权 + ↓ +Ebox stage 结构/几何 patch + ↓ +TP stage paint patch + ↓ +Emacs adapter 原子应用两个 patch + ↓ +ETAF Runtime 提升 generation;失败则回滚参与者 ``` -约束: +Ebox 不拥有 TP paint 优先级;TP 不拥有节点布局;两者都不能自行提升 Runtime +generation。 -- Ebox 不向上依赖 ETAF; -- TP 不解析 View,也不调用 Component; -- ECSS 不写 buffer; -- `etaf-ui` 不调用 Ebox 私有函数; -- `etaf-sqlite` 不知道任何 UI; -- Playground 不向 core 反向注入示例协议; -- 性能工具通过公开边界观察各包,不让被测包依赖某个示例。 +### 4.5 上层包 -## 4. Rust 与 Elisp 的切分 +| 包 | 拥有 | 不拥有 | +| --- | --- | --- | +| `etaf-ui` | Button、Checkbox、Label、Panel、DataGrid 等普通 Component | 第二套 Widget Runtime、布局引擎 | +| `etaf-sqlite` | SQLite Data Source、查询、mutation、事务和 dispose | Data Controller、View、UI | +| `etaf-performance` | 应用无关 operation/stage、环境、统计和报告 | 示例语义、布局规则、调度权限 | +| `ebox-playground` | Ebox 公共布局 API 示例与验证 | ETAF | +| `etaf-playground` | ETAF/UI/SQLite 组合示例、加载命令和状态展示 | Core 语法、Runtime、性能协议 | -目标不是把所有代码机械地翻译成 Rust,而是把确定性计算和环境副作用分开。 +`etaf-performance` 是独立可选包。ETAF、Ebox、TP 和 SQLite 不依赖它;它只通过 +公开边界观察和关联阶段。 -适合 Rust 纯计算核心的内容: +Playground 的 `.etaf` manifest 属于 Playground。未来通用 compiler 若存在,必须 +降低到同一套 View/Component 契约,不得创建第二套 Runtime。 -- Text/Box Render IR 的验证和规范化; -- keyed diff、identity matching 和 patch batch; -- ECSS selector/cascade/computed-style 计算; -- 字符宽度、换行、普通 Box/flex/grid 测量和布局; -- geometry snapshot、layout impact 和 paint contribution merge。 - -保留在 Elisp/Emacs 适配层的内容: - -- 执行用户定义的 Component 函数; -- ref、Context、Action、Data、Resource 和 lifecycle callback; -- Emacs 事件、窗口、字体能力和 buffer 提交; -- 调用 Rust 核心并提交返回的 patch/paint plan。 - -Elisp 不应再次实现 Rust 已经计算过的布局、cascade、diff 或文字扫描;Rust 也不 -应读取 Emacs buffer 或理解 Component slot 语义。 - -## 5. 性能与正确性不变量 - -模块增加不能把一次局部变化升级成多次全量遍历。必须保持: - -- 一次事务中的稳定 identity、依赖、布局快照和 Paint contribution 只 materialize - 一次; -- Text paint 改变不重新执行无关 Component,不重新做布局; -- Box 几何改变只触发受影响的布局 owner; -- Component 状态/slot/列表拓扑改变只执行拥有该结构的 Component; -- Ebox 失败或 TP 提交失败时保留上一代已提交结果; -- 快速路径必须是普通正确路径的严格子集,并且能验证失败后精确回退; -- 性能工具本身不能改变被测应用的调度和布局路径。 - -真实 GUI 场景仍然是最终证据。固定场景在功能、文本属性、identity、生命周期和 -回滚语义不缩水的前提下,p95 和 max 都必须满足项目的 50ms 目标;单独的微基准 -不能替代跨包验证。 - -## 6. 当前实现与目标模型的关系 - -当前 ETAF Core 的 Host 注册表仍包含: +## 5. 依赖方向 ```text -text · fragment · container · row · column · stack · flex · grid · spacer +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 ``` -当前 Renderer 直接把这些名称映射到 Ebox 构造器;Ebox Playground 也直接使用 -自己的布局 API。这只是现状记录,不是目标 API,也不构成必须保留的兼容表面。 -`spacer` 和 `flow` 都不属于目标公共词汇;目标 Ebox 可以用普通 Box/Text 路径 -替代当前的 `flow` 标记,不为它保留独立布局分支。 +禁止反向依赖:Ebox 不依赖 ETAF;TP 不解析 View;ECSS 不写 buffer;UI 不调用 +Ebox 私有函数;SQLite 不知道 UI;Playground 不向 Core 注入协议。 -目标演进方向是: +## 6. Rust 与 Elisp + +模块边界先于实现语言。只有接口和等价性测试冻结后,确定性计算才迁移到 Rust: ```text -Text + Box(layout) - ↑ -如果确实需要短写法,row/column/flex/grid 只能作为新语法糖 +Rust 候选: + 规范化 View 的验证与结构 diff(只处理 opaque stable IDs) + ECSS cascade + Text 测量输入处理与 Ebox 布局 + geometry/paint patch 的纯数据计算 + +Elisp / Emacs: + 执行用户 Component、ref、Context、Action、Data、Resource、lifecycle + 数据库和外部 I/O + Emacs 事件、字体/窗口能力和最终提交 ``` -这些简写不能通过 `etaf-define-component` 实现,否则每个布局节点都会被迫获得 -Component 的 identity、scope、slot 和调度边界。它们应直接降低为 Ebox 布局节点。 -不保留 `container`、`stack`、`spacer` 或旧 Host 注册名的兼容别名。 +Component identity、依赖所有权、TP 优先级和 generation authority 不因 Rust 化而 +转移。Elisp 不重复 Rust 已经完成的 diff、cascade、布局或文字扫描。 -目标模型尚未交付前,不得修改现有 Host 语法后再把未验证的 `box` 描述成已完成。 +## 7. 正确性与性能不变量 -## 7. 有边界的演进顺序 +- 同一事务中的 View、computed properties、geometry snapshot 和 paint contribution + 各 materialize 一次; +- Text paint 改变不执行无关 Component,也不运行布局; +- `:outer`、`:layout` 或几何改变只运行受影响的布局 owner; +- Fragment/slot/list 变化只替换对应 Range; +- Ebox/TP/Emacs 任一 participant 失败时保留上一代已提交状态; +- resize 使用当前窗口事实立即重排,不以隐藏 debounce 改变交互语义; +- 性能记录器不改变被测路径。 -如果开始实现目标模型,只做下面这个最小顺序: +最终门禁必须覆盖: -1. 增加 `Box` 的规范化 View 形状和字符串子节点规则; -2. 只验证 `layout='column` 的 `box` 到 Ebox lowering; -3. 决定是否提供 `row`、`column`、`flex`、`grid` 的新语法糖,并直接降低到 Box; -4. 分别验证 `flex` 和 `grid` 的模式属性、布局结果和增量路径; -5. 保留旧名称兼容,并用 Research Shelf 与 Flex reference 做 GUI 回归; -6. 只有全部公共测试和真实性能门禁通过,才更新用户指南为 `text + box`。 +- Text/Box/Fragment 结构等价; +- `outer × layout` 合法组合和失败组合; +- normal inline/block、row、column、flex、grid 的 GUI 行为; +- Component root 与透明 Fragment 的布局参与; +- style/Theme/TP 优先级和事务回滚; +- Research Shelf 与 Flex reference 的连续 resize; +- 固定真实场景 p95 和 max 均不超过 50ms。 -任何一步不能证明结果等价或性能收益,就删除该实验,不继续堆下一层抽象。 +## 8. 当前实现差距与非目标 -这是一次干净重设计,不要求旧 `.el`、`.etaf` 文件或旧 Host 名称继续运行。迁移 -由明确的源码更新完成,不通过长期兼容层隐藏模型变化。 +当前代码仍注册 `text`、`fragment`、`container`、`row`、`column`、`stack`、 +`flex`、`grid` 和 `spacer`;目标 `box`、`:outer`、`:layout 'normal` 尚未实现。 -## 8. 明确不做的事情 +这是干净重设计,不要求旧 Host 名称或旧 `.etaf` 文件继续运行,也不增加长期 +兼容层。实现完成前,正式架构和用户指南不得把目标语法描述成当前 API。 -- 不把 `button`、`panel`、`data-grid` 等业务控件塞进 Ebox; -- 不把 `row`、`column`、`flex`、`grid` 做成 Runtime Component; -- 不把 `spacer` 或 `flow` 暴露成 ETAF 公共视觉类型; -- 不在 ETAF 公共层引入 `box :content` 第二套内容模型; -- 不让 TP 重新扫描布局或重新调和所有颜色; -- 不让 Playground 拥有通用框架协议; -- 不为了“预编译”而新增没有长编译时间和真实运行时收益的中间产物; -- 不为了减少名词而合并 Component、Text、Box、Ebox Node、Paint slot 等不同所有权 - 和生命周期概念。 +非目标: + +- 不实现完整浏览器 CSS; +- 不提供 `spacer`、公共 `flow` 或 `(box :content ...)`; +- 不把布局模式做成 Component 或第二套 Runtime 节点; +- 不在 Core 中保留旧 Host alias 或可选短写法; +- 不让 Playground、UI 或数据库包拥有 Core 协议; +- 不在没有真实编译成本和运行时收益前增加 App 预编译产物。