# ETAF 开发约束 本文件适用于 ETAF 及其联调范围内的 `etaf-ui`、`ebox`、`tp`、 `etaf-sqlite`、`etaf-playground`。实现与性能优化必须从最终产品目标倒推, 不得用局部完成、容易通过的替代目标缩小原始范围。 ## 项目自动化入口 - GUI 与性能自动化先查 `scripts/README.md`、`scripts/emacs-gui-verifier.el` 及既有 Makefile 入口;公共机制归 `scripts/`,具体业务场景归示例仓库。 - 连续 resize 使用 `scripts/benchmark-ebox-resize.el` 的 `ebox-resize-benchmark-start`,适用于现有 ETAF 或独立 Ebox buffer。 按 README 选择范围、轮数和新证据文件;先验证前台与已加载版本,保留全部样本, 检查 `:valid` 与 `:within-limit`,同时比较内容规模,不能只比较 p95。 - 遇到重复的渲染、交互、resize 或验证需求,优先扩展已登记入口。稳定的通用 操作应主动固化为带参数、验证和说明的仓库工具,随后更新工具索引及本节路由。 - `.omx/` 中的临时诊断是历史调查材料,不是日常运行入口。不要从中复制新的 示例专用脚本,也不要把项目逻辑放进通用 Emacs 技能。 ## 最终目标驱动 开始工作前先明确最终可观察结果、硬性指标、不可牺牲的功能、权威验证方式 和停止条件。架构、算法、缓存、预编译与局部优化都只是达到目标的手段,不能 反过来成为交付物本身。 ETAF 当前性能工作的最终结果是:通用性能工具能解释每次操作跨包各阶段的 耗时;固定真实场景在功能、文本属性、身份、生命周期和回滚语义不缩水的前提 下,p95 与 max 都不超过 50ms。 ## 架构与抽象准则 - 先从复杂现象中识别最小、稳定、可命名的领域模型及其不变量,再写代码; 不把偶然的调用顺序、示例名称或当前数据形状伪装成抽象。 - 一个模块只拥有一项完整职责,并为这项职责提供少量、精确、正交的接口。 接口之间通过明确数据契约组合,不读取彼此的内部状态,不复制彼此的规则。 - 用户心智成本是公共 API 的硬指标。同一能力只能有一个规范名称和一条推荐路径; 内部算法、后端节点、兼容别名和便捷 wrapper 不得伪装成并列公共概念。常用路径 只要求学习最小模型,高级能力通过逐层展开获得,不能让用户先理解包内部实现。 - 区分语义身份、视觉槽位、布局坐标、绘制层和发布权限。只有模型本身允许时 才能合并概念;不能为了减少代码把不同生命周期的身份混在一起。 - 复杂系统通过小模块的组合与复用逐步形成。新增能力应优先扩展已有模型的 输入域或组合方式,不平行创建第二套状态、第二条渲染链或只服务一个例子的 特殊协议。 - 架构必须满足性能可组合性。每层只处理变化集合,成本应为 `O(changed)` 或有 明确上界的小常数;模块增加时,总成本应接近各层小常数之和,不能因每层都 重新扫描 `O(all)` 而相乘。 - 上一层输出的稳定身份、坐标、依赖、布局证书和绘制贡献就是下一层的输入。 下游不得丢弃这些中间产物后重新推导;一次事务中的同一全量遍历最多发生 一次,多个模块应组合在同一遍历或直接消费保留状态。 - 数据只 materialize 一次。跨层优先传递不可变中间产物、稳定句柄或精确操作 批次;重复建树、重复复制文本、重复合并属性和重复证明都必须有独立收益证据。 - 每个模块都要有独立性能预算和基准。模块单独合格但组合后超标,说明接口 泄漏了重复工作,必须修正边界,不能把额外耗时解释为“架构层数的正常代价”。 - 每条快速路径都必须是普通正确路径的严格子集:入口条件可判定、保留状态可 验证、失败可精确回退、提交与回滚仍由原有权限边界控制。 - 代码量不是进度。没有清晰模型、独立测试和真实收益的辅助层、兼容分支、 预留接口、重复证明与缓存都属于 slop,应删除而不是继续包装。 ## 纵向最小可运行版本 面对架构级任务,先选择一个真实、代表性强、可以端到端运行的最小切片。这个 切片必须同时经过“输入 → 核心机制 → 运行时消费 → 用户可见结果 → 验证”, 不能只交付数据结构、接口空壳、设计文档或与真实应用脱节的玩具示例。 例如 App 预编译应先打通一个真实 View:编译阶段产生中间 blueprint,运行时 只填动态洞,不支持的语法精确回退,真实应用实际使用该产物。只有这个闭环 可运行、结果等价且确有性能收益,才扩展语法和覆盖面。 ## 最小验证循环 每个实现假设都采用下面的短循环: 1. 写出本次最小假设以及它应改善的一个可测指标。 2. 只实现证明该假设所需的最小代码,不提前铺设后续层次。 3. 立即运行最小但有判定力的验证:可运行、结果等价、目标指标改善。 4. 验证通过才保留并扩展;失败则先定位原因,无法证明价值的实验立即完整撤掉。 5. 每次只扩大一个维度,例如一种语法、一个组件或一个缓存层,然后重复验证。 最小验证不能偷换最终目标。微基准只能证明局部机制;真实跨包场景和完整门禁 仍是最终证据。 ## 可验证的小赌注与反馈控制环 不要把一次无法控制、无法快速证伪的“大赌注”当作工程推进方式。任何跨包、 跨阶段或“国民级应用”尺度的大 gap,都必须拆成一组彼此有清晰因果关系、能够 独立验证和独立回退的小 gap。每个小 gap 只承载一个主要假设,并在扩大范围前 得到新鲜证据。 这不是三条孤立技巧,而是一条完整的反馈控制环: - **拆解**缩短因果距离:一次只改变一个可命名机制,使失败能直接指向假设, 不让多个变量同时变化后再靠猜测定位; - **验证**限制错误传播:定向测试、静态编译、CI、事务回滚和真实 GUI 门禁必须 放在对应边界上,不能等到最终集成时才第一次发现问题; - **迭代**提高反馈频率:小步实现、立即运行最小有判定力的检查,通过后才扩大 一个维度,并在完整子目标证明后及时提交 Git 基线。 工程目标不是假装“零错误”,而是让错误出现得早、扩散得不远、定位有证据、 回退代价低。一个实验若不能快速回答“假设是否成立”,就说明切片仍然过大; 一个门禁若失败后不能指出责任边界,就说明验证粒度仍然过粗。不得用继续堆代码、 增加兼容分支或推迟集成来掩盖反馈环已经失效。 凡目标涉及用户可观察的 Emacs 界面、文本属性、交互或性能,只有在目标版本的 真实 GUI Emacs 中实际渲染并执行对应操作所得的视觉结果、动态过程和耗时数据, 才称为反馈。batch ERT、静态编译、CI、mock、结构检查和微基准只是进入 GUI 前的 预检或定位工具,不能替代 GUI 反馈,也不能据此宣称功能正确、视觉合格或性能收敛。 GUI 反馈失败时,以 GUI 为当前事实,回到最小假设重新定位;不得用逻辑测试绿色 反驳用户实测。 ## 控制变更规模 - 避免一次编写大段跨层代码后才首次运行测试。 - 优先提交或保留小而完整的纵向切片;每个切片都应可独立解释、回退和验证。 - 新抽象必须服务于当前已验证的下一步,不为尚未证明的未来需求预建框架。 - 不因已有方案投入较多就继续扩建;数据否定假设时及时收缩或删除。 - 同一轮不要同时改变编译协议、Runtime 语义、Ebox 发布算法和 TP 权限边界, 除非最小闭环确实无法拆分,并且有逐层验证点。 ## Git 基线与完成提交 - 每个完整目标在新鲜验证通过后、开始下一个目标前,必须提交所有受影响仓库, 让已证明正确的状态成为可比较、可回退的基线;工作树中“已经完成但未提交” 不算真正收敛。 - 提交只包含当前已经完成并验证通过的目标。下一目标的失败测试、实验代码、 临时诊断和未验证实现必须与基线提交分离,不能为了清空工作树混进同一提交。 - 多仓库目标按依赖顺序分别提交,每个仓库使用与其实际改动相符的 message; 不用 `update`、`changes`、`work` 一类无法说明结果的含糊描述。 - commit message 应以可观察结果或稳定的架构能力为中心,例如 `perf: retain native frame updates across ETAF commits`,而不是罗列实现步骤。 - 提交前至少运行该目标约定的定向测试、静态检查和最终门禁;验证失败时继续修复, 不得通过提交把失败状态包装成完成。 - 完成汇报列出各仓库 commit hash、验证证据和仍未提交的下一目标改动,确保后续 性能对比能够明确指出基准版本。 ## 性能优化纪律 - 先用通用记录面板确认真实热区,再选择架构或算法改动。 - 一次优化只绑定一个主要瓶颈和一个预期收益,记录优化前后的相同口径数据。 - 不用示例名称或业务概念污染通用工具、编译器和底层包协议。 - 不以关闭校验、减少功能、弱化文本属性、破坏身份或回滚语义换取数字。 - 缓存和预编译提示不能自行授权快速路径;运行时仍负责验证和精确回退。 - 如果最小切片没有改善真实目标场景,不继续实现持久化、原生后端或更复杂缓存。 ## 每轮汇报格式 进度更新应明确说明:最终目标、当前最小切片、已经验证的证据、未通过的指标、 下一次只准备验证的一个假设。不得把普通字节编译、局部优化或设计计划描述成 尚未实现的 App 预编译能力。 ## 完成条件 只有当前工作树中的真实实现和新鲜验证同时证明最终要求,任务才算完成。计划、 部分测试、单个微基准、一次偶然的低耗时或“没有发现错误”都不是完成证据。