Add canonical query semantics, managed metadata and transactions, overlay-aware lookup, reproducible benchmarks, and synchronized API documentation.
67 lines
3.9 KiB
Markdown
67 lines
3.9 KiB
Markdown
# API 语义收敛阶段 1:属性所有权必须先于便利重载
|
||
|
||
## 背景
|
||
|
||
仓库审计发现的错误并非彼此独立的条件遗漏。`tp-text` 属性扩散、层重定义残留、显式 nil 丢失、搜索 nil 分裂、隐藏层覆盖外部编辑,都来自同一个更深的问题:
|
||
|
||
> 调用者、内嵌字符串、普通 Emacs 属性、层定义和 managed stack 对同一属性键的所有权没有统一表达。
|
||
|
||
继续为每个入口增加特殊分支会扩大语义分裂,因此本阶段先冻结 `docs/API-SEMANTICS.md`,再在拥有状态的层修复。
|
||
|
||
## 决策
|
||
|
||
### 1. presence 是数据,不是真值
|
||
|
||
属性缺失与 present-nil 必须使用 `plist-member` 一类 presence-aware 判断区分。搜索中 VALUE 省略不能再借用 nil 表达,因而增加唯一哨兵 `tp-any-value`。选择唯一对象而不是某个普通符号,是为了避免与合法属性值冲突。
|
||
|
||
### 2. `tp-text` 的属性所有者是 interval
|
||
|
||
内嵌字符串的位置 0 不能代表整串。初次应用与响应式更新都按每个真实 property interval 计算,外部 props 在每段上覆盖内嵌 props,显式 nil 也参与覆盖。
|
||
|
||
逐段算出待写属性后仍必须执行调用者选择的操作语义:`tp-set` 覆盖指定键,`tp-reset` 替换完整属性集合,`tp-add` 合并 face-family 和嵌套 plist。实现中一度让“属性已逐段应用”的返回标志绕过了这一步,导致文本内容相同时 reset 留下旧键、add 覆盖而不合并。最终把 operation 传到唯一的逐段写入点,并为字符串/缓冲区和 `tp-text nil` 初始化路径加入回归断言。
|
||
|
||
### 3. 层重定义必须拿到 old 与 new
|
||
|
||
只传 layer name 会让渲染器无法判断哪些键应删除。定义入口在替换注册表前保存 old props,渲染器随后执行:
|
||
|
||
1. 仅删除仍等于旧值的旧层键;
|
||
2. 保留无关键和已经被外部改写的值;
|
||
3. 写入新定义;
|
||
4. 同步 direct render 与 buried/hidden stack entry。
|
||
|
||
这比完整 `set-text-properties` 更安全,因为后者会错误取得整个区间的所有权。
|
||
|
||
### 4. 隐藏层冲突默认失败
|
||
|
||
隐藏层存在时,直接属性只是 managed stack 的渲染缓存。外部直接写入无法可靠归属到某一层。三个候选方案中:
|
||
|
||
- 静默覆盖会丢用户数据;
|
||
- 自动收编为匿名层会凭空改变 stack 结构;
|
||
- 明确失败能保留双方状态并暴露所有权冲突。
|
||
|
||
因此选择 `tp-layer-conflict`,并保证在 managed write 前检查。
|
||
|
||
### 5. NOERROR 只处理可预期的解析失败
|
||
|
||
增加 `tp-unresolved-layer`,NOERROR 仅捕获这一类型。层 body、compute、transform 和内部不变量错误不属于“未找到”,必须传播。
|
||
|
||
### 6. 业务计算与 observer 分开
|
||
|
||
transform/compute 决定渲染结果,失败后继续会产生貌似有效的陈旧输出,因此错误传播。watcher 是副作用观察者,单个失败不应阻断 managed update;错误以结构化 plist 记录在 `tp-reactive-observer-errors`,同时保留用户可见消息。
|
||
|
||
## 有意延期
|
||
|
||
参数化 mounted layer entry 没有保存调用实参,重定义时无法重新求值。为避免猜测参数或引入兼容包装,本阶段明确不自动刷新参数化实例。后续应让 managed entry 保存参数和定义版本,再设计迁移。
|
||
|
||
字符串/缓冲区搜索返回结构、复制/原地修改策略和 stack mutator 的 run-count 返回值也仍有历史差异;它们属于 canonical façade 阶段,不能混入正确性补丁。
|
||
|
||
## 验证标准
|
||
|
||
本阶段以以下证据作为停止条件:
|
||
|
||
- 每个确认问题先有失败回归测试;
|
||
- 聚焦测试覆盖字符串/缓冲区、present-nil、静态/响应式重定义和 hidden conflict;
|
||
- warning-as-error 字节编译通过;
|
||
- 全量 ERT、固定种子乱序 ERT 与 README doctest 通过;
|
||
- 中英文 README、docstring、架构文档和 changelog 与规范同步。
|