From ec30126b2d9b21c1615b7bea2c43d9efa78f1d23 Mon Sep 17 00:00:00 2001 From: Kinneyzhang Date: Thu, 6 Aug 2026 01:33:08 +0800 Subject: [PATCH] docs(architecture): make TP runtime target standalone Add self-contained Chinese and English TP 1.0 contracts for objects, bindings, anchors, computed values, transactions, and public API levels without requiring a sibling Ebox checkout. Verification: make doctest EMACS=/Applications/Emacs.app/Contents/MacOS/Emacs LOAD_EXTRA=-L\\ /Users/geekinney/IPARA/3-RESOURCES/emacs/config/github/test/libs; git diff --check; local Markdown link check. --- docs/ARCHITECTURE.md | 2 +- ...retained-runtime-target-architecture-en.md | 194 ++++++++++++++++++ docs/retained-runtime-target-architecture.md | 194 ++++++++++++++++++ 3 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 docs/retained-runtime-target-architecture-en.md create mode 100644 docs/retained-runtime-target-architecture.md diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 458264b..fb60d7c 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,6 +1,6 @@ # tp 代码架构文档 -> 未来主版本目标:TP 将重构为独立 retained/reactive text runtime,并作为 Ebox 的通用底层执行器。已批准但尚未实现的跨包架构合同与执行计划分别见 sibling Ebox 仓库的 [TP / Ebox Retained Text Runtime 目标架构](../../emacs-box/docs/architecture/tp-ebox-retained-text-runtime-architecture.zh.md) 和 [重构开发计划](../../emacs-box/docs/development/plans/2026-08-06-tp-ebox-retained-runtime-refactor.zh.md)。本文在最终切换完成前仍只描述 TP 0.3.x 当前实现。 +> 未来主版本目标:TP 将重构为独立 retained/reactive text runtime,并可作为 Ebox 等高级 consumer 的通用底层执行器。TP 自身完整、可独立阅读的已批准目标见 [TP Retained/Reactive Text Runtime 目标架构](retained-runtime-target-architecture.md)([English](retained-runtime-target-architecture-en.md));它不依赖 sibling Ebox checkout。本文在最终切换完成前仍只描述 TP 0.3.x 当前实现。 本文档描述 tp 库的模块分层结构与函数调用层次,从底层基础模块到上层功能模块的分层组织。 diff --git a/docs/retained-runtime-target-architecture-en.md b/docs/retained-runtime-target-architecture-en.md new file mode 100644 index 0000000..8fc50a2 --- /dev/null +++ b/docs/retained-runtime-target-architecture-en.md @@ -0,0 +1,194 @@ +# TP Retained/Reactive Text Runtime Target Architecture + +Chinese version: [TP Retained/Reactive Text Runtime 目标架构](retained-runtime-target-architecture.md). + +Status: approved TP 1.0 target, not yet implemented. [ARCHITECTURE.md](ARCHITECTURE.md) and [API-SEMANTICS.md](API-SEMANTICS.md) remain authoritative for TP 0.3.x current behavior. + +## 1. Product position + +TP 1.0 is an independently installable, testable, releasable, and usable retained/reactive text runtime for Emacs. It projects declarative properties, reactive data, and stable text objects onto strings and buffers while owning final text-property diff, marker/index state, transactions, and buffer publication. + +TP does not depend on Ebox and contains no spatial concepts such as Box, Flex, Grid, padding, layout owners, or Ebox regions. Ebox, ETAF, dashboards, diagnostics, interactive lists, and ordinary buffer annotations can all consume the same public TP APIs. + +The boundary in one sentence is: + +> TP owns objects, dependencies, positions, changes, and publication; an upper consumer owns business meaning and the desired display result. + +## 2. Design invariants + +- TP source, tests, examples, and package metadata neither require, detect, nor name Ebox. +- One property, binding, surface, mount, diff, and transaction core serves every live use; there is no embedded mode. +- TP is the sole final buffer committer. Producer and consumer prepare phases produce candidate values only. +- One live object has one TP identity. A consumer may store its opaque handle but cannot maintain a parallel identity requiring long-term synchronization. +- Signal updates travel from source to binding and object to marker-backed mount. Normal hot paths never scan `buffer-list` or search text by `tp-name`/`tp-layers`. +- `tp-name`, `tp-layers`, and `tp-meta` are not a live runtime database. Definitions, provenance, identity, dependencies, and mount metadata live in side state. +- Capabilities have exactly two values, `content` and `properties`. They share one compute and commit semantics and differ only in write permission. +- Ordinary function values are literal. Only an explicit `tp-computed` value source executes and records dependencies. +- Signal sources, bindings, plans, marker/index state, and opaque client state use one transaction revision and roll back together. + +## 3. Independent data flow + +```text +application state / theme / host edit + │ + ▼ + signals + bindings + │ exact dependency graph + ▼ + TP prepare context + │ candidate objects/bindings/anchors + ▼ + ordinary or client producer + │ object → schema/rules/cascade + │ → generic keyed surface plan + ▼ + reconcile + prepare diff + │ prepared text/property operations + ▼ + atomic multi-surface publication + │ + ▼ + strings / Emacs buffers +``` + +Prepare creates candidate state without publication. A producer returns an ordinary surface plan plus optional opaque client state. TP never interprets client state but promotes it atomically with the plan, dependencies, mounts, and revision. + +## 4. Properties, cascade, and value sources + +### 4.1 Property schema + +`tp-define-property` registers initial value, inheritance, normalizer, validator, equality, merge, projector, and optional shorthand expansion for a namespaced property id. A schema may project a computed value to Emacs text properties or expose it only to a consumer. + +TP provides a complete deterministic cascade over registered properties: origin/importance, layers, specificity, scope/source order, CSS-wide values, inheritance, custom properties/variables, shorthands, explicit nil versus absence, and schema-defined normalization/equality. TP does not claim browser CSS properties or spatial layout. + +### 4.2 Literal and computed values + +Every ordinary Elisp value is literal, including function objects. TP never invokes a help-echo function, keymap command, or callback implicitly. + +A declaration that must be evaluated uses `tp-computed` to wrap a compute function. It executes in the owning object's binding during prepare; `tp-signal-read` and `tp-binding-read` record dependencies automatically. The result then passes through normalization and validation and is treated as a literal, with no implicit second invocation. Errors abort the whole candidate transaction, and equal results produce no surface change. + +An upper DSL may accept evaluable Elisp, but its constructor/compiler boundary must distinguish quoted lists, literal functions, and computed sources and compile reactive computation to `tp-computed` rather than creating a second watcher. + +## 5. Stable objects and prepare contexts + +Object identity is valid in one surface and retained by parent identity, sibling key, and opaque kind. Explicit keys are unique under one parent. An unkeyed object may retain identity only by position plus kind. Handles never cross surfaces. + +TP creates a short-lived prepare context at the start of mount/update. A producer calls: + +```elisp +(tp-object-ensure context parent key kind) +``` + +A matching live object returns its retained handle. A new object exists only in candidate state. Duplicate keys, stale parents, orphan objects, and cross-surface handles fail during prepare. Candidate identity becomes live only after successful publication; a failed handle is permanently unresolvable. + +`tp-surface-materialize-string` gives a producer the same semantics through an ephemeral context. Its objects and bindings exist only for that pure computation, are released after the string returns, and never enter a live registry. + +`tp-object-resolve` performs read-only lookup of a live handle by surface and key path for public selection/interaction entry points. It never creates an object. + +## 6. Bindings and real reactive dependencies + +A definition is a reusable recipe; a binding is a concrete computation installed on one object. `tp-bind` installs idempotently by object handle plus caller-namespaced binding key and stores at least compute, last successful value, dependencies, dirty state, revision, and lifecycle policy. + +`tp-binding-read` returns another binding's memoized value while registering a binding-to-binding dependency. Signals, computed properties, measurements, and ordinary derived values can therefore form a real dependency graph rather than scanning a buffer after variables change. + +Before recomputation TP removes old dependencies; after success the actual set read this time becomes authoritative, so conditional branches release unused sources. A transaction dirty queue deduplicates invalidations and recomputes one binding at most once per batch. Cycles report the complete path. + +Prepare records touched objects and bindings. Removing an object cleans up its bindings, subscriptions, anchors, and mounts in the same publication. A surviving binding omitted from the current declaration is removed by default unless an explicit lifecycle policy retains it. Ordinary bindings may return arbitrary client values; only designated producer bindings return plans or subplans. + +## 7. Surface plans + +A surface plan is immutable-semantic pure data with these node fields: + +| Field | Contract | +| --- | --- | +| `key` | Sibling-local stable key | +| `kind` | Opaque comparable discriminator | +| `text` | Optional plain/propertized string leaf | +| `props` | Final direct Emacs text properties | +| `children` | Ordered child plans | +| `tags` | Opaque side metadata indexed but not interpreted by TP | +| `capability` | `content` or `properties` | + +A plan contains no marker, buffer position, patch operation, producer closure, binding closure, or client continuation. Valid keymap/help-echo/callback functions may remain final property values, and reconciliation never invokes them. + +Public constructors defensively copy caller-owned plists/strings or otherwise provide immutable semantics. Mutating the original after commit cannot change a published surface. + +## 8. Mounts, range anchors, and property ownership + +### 8.1 Content capability + +A `content` mount owns text and properties in its span. It may insert, delete, move, or replace text and update properties. It serves dashboards, menus, special UI buffers, and advanced renderer output. + +### 8.2 Properties capability + +A `properties` mount contributes declared properties without changing host text. `tp-range-anchor-create` constructs an opaque marker-backed anchor from buffer, start/end, and marker insertion policy. During prepare the producer calls `tp-object-attach-range` to attach an object to that anchor. The plan itself still contains no position. + +For every anchor/property interval, TP side state records the host baseline, every TP contribution, and the last published value. Overlapping contributions from one surface compose through schema merge/cascade. + +If external code changes the same property to a value different from TP's last publication, the next prepare raises `tp-property-conflict` by default. TP neither overwrites the external value nor restores an old snapshot; the caller explicitly invokes `tp-range-rebase` or unmounts. Unmount removes only the TP contribution: it restores the baseline only while the current value still equals TP's last publication, otherwise preserving the external value and recording the conflict. + +Live markers follow host text editing. An edit crossing or deleting an anchor boundary follows an explicit shorten/remove/stale policy; TP never scans nearby text to guess a new location. + +## 9. Reconciliation and transactions + +TP reconciles object identity by parent/key and computes child insert/remove/reorder, text diff, and property-run diff between old and new plans. A normal update resolves ranges directly through the object-to-mount index. + +A transaction freezes candidate signal writes; creates prepare contexts; prepares every actually affected surface; validates capabilities, conflicts, and lifecycle; creates per-surface operations and inverse journals; publishes in stable surface-id order; then atomically swaps source values, bindings, plans, indexes, client state, and revisions. Observers run only after every surface succeeds. + +One global signal may reach several surfaces. TP prepares all before publishing any. If a compute, buffer write, marker/index step, or transaction participant fails, TP rolls back already published surfaces and restores signal values, binding values/dependencies, dirty queues, and revisions. An observer failure occurs after commit and is reported without rollback. + +If a buffer is killed during publication, kill-buffer teardown is authoritative and irreversible. TP rolls back other surfaces and source state and never resurrects the killed buffer. + +## 10. Public API levels + +### 10.1 Simple one-shot properties + +```elisp +(tp-propertize string declarations) +(tp-apply buffer start end declarations) +``` + +Both use the same schema/cascade/projector core without identity, bindings, or live mounts. Existing `tp-set`, `tp-reset`, `tp-add`, `tp-remove`, lookup, and search APIs reuse the same lower semantics. + +### 10.2 Reactive existing text + +```elisp +(tp-watch buffer start end compute) +``` + +`tp-watch` creates a properties range anchor, surface object, and binding. COMPUTE returns declarations, and the result is an opaque update/unmount handle. Ordinary users do not manually build objects, bindings, or surfaces. + +### 10.3 Complete retained UI + +```elisp +(tp-surface-mount buffer plan-or-producer options) +(tp-surface-update surface plan-or-producer) +(tp-surface-unmount surface) +``` + +The full API also includes `tp-computed`, signals, prepare/object operations, bindings, range anchors, transactions, materialize-string, and at-point/inspect/report diagnostics. TP adds no overlapping `tp-mount`/`tp-update` aliases and exposes no raw marker, patch, change-set, or `:impact` API. + +## 11. Standalone acceptance scenarios + +With no Ebox on `load-path`, TP 1.0 continuously verifies: + +1. static string/buffer properties: nested faces, keymaps, help-echo functions, and explicit nil; +2. reactive status: `tp-watch` and a retained content producer, conditional/binding dependencies, and batching; +3. retained dashboard: keyed add/remove/reorder, buttons, theme cascade, and rollback; +4. existing-text diagnostics: range anchors, host edits, overlap, external property conflict/rebase/unmount; +5. two-buffer producer: isolated identity/state plus global-signal multi-surface atomicity; +6. performance: sparse updates proportional to the actual dependency closure, zero buffer operations for equal values, and no marker/subscription/weak-reference leaks after unmount. + +## 12. Compatibility, versioning, and deletion + +TP 1.0 is a major-version transition. Stateless public APIs that map directly to the unified core remain. Managed behavior that requires the inline `tp-layers`/`tp-meta` database or scan renderer is explicitly removed or replaced rather than retained in a hidden compatibility engine. + +An explicit one-shot legacy import may scan historical propertized text and construct a surface. Normal signal/style/update hot paths never invoke it automatically. + +The final system deletes the layer-to-buffer registry, scan-driven refresh hooks, old inline managed codec, duplicate transactions, and old batch renderer. TP 1.0 package, tests, examples, and this document all work without an Ebox repository. + +## 13. Contracts frozen before implementation + +Executable contract tests must define prepare-context/object timing; binding identity and lifecycle; literal/computed values; range anchors and property conflicts; single/multi-surface rollback; the three convenience levels; error taxonomy; report shape; explicit nil versus absence; and read-only, undo, narrowing, indirect-buffer, and kill-buffer behavior before implementation begins. + +If implementation requires an Ebox-specific branch, post-commit identity scan, raw position/closure in a plan, a second renderer, or cannot safely remove a properties contribution, integration stops for ownership review rather than adding an adapter mode. diff --git a/docs/retained-runtime-target-architecture.md b/docs/retained-runtime-target-architecture.md new file mode 100644 index 0000000..6769e43 --- /dev/null +++ b/docs/retained-runtime-target-architecture.md @@ -0,0 +1,194 @@ +# TP Retained/Reactive Text Runtime 目标架构 + +英文版见 [TP Retained/Reactive Text Runtime Target Architecture](retained-runtime-target-architecture-en.md)。 + +状态:TP 1.0 已批准目标,尚未实现。TP 0.3.x 当前事实仍以 [ARCHITECTURE.md](ARCHITECTURE.md) 和 [API-SEMANTICS.md](API-SEMANTICS.md) 为准。 + +## 1. 产品定位 + +TP 1.0 是一个可独立安装、测试、发布和使用的 Emacs retained/reactive text runtime:它把声明式属性、响应式数据和稳定文本对象投影到 string 与 buffer,并拥有最终文本属性 diff、marker/index、事务和 buffer publication。 + +TP 不依赖 Ebox,也不包含 Box、Flex、Grid、padding、layout owner 或 Ebox region 等空间布局概念。Ebox、ETAF、dashboard、diagnostics、交互列表和普通 buffer 标注都可以通过同一 TP public API 使用它。 + +一句话边界是: + +> TP 负责对象、依赖、位置、变化和提交;上层 consumer 负责这些对象的业务含义以及期望显示结果。 + +## 2. 设计不变量 + +- TP source、tests、examples 和 package metadata 不 require、检测或命名 Ebox。 +- live runtime 只有一套 property、binding、surface、mount、diff 和 transaction core,不增加 embedded mode。 +- TP 是唯一最终 buffer committer;producer 和 consumer 的 prepare 阶段只能产生候选值。 +- 一个 live object 只有一个 TP identity;consumer 可以保存 opaque handle,但不能建立需要长期同步的平行 identity。 +- signal update 从 source 直达 binding,再从 object 直达 marker-backed mount;正常热路径不扫描 `buffer-list` 或按 `tp-name`/`tp-layers` 搜索文本。 +- `tp-name`、`tp-layers`、`tp-meta` 不是 live runtime 数据库;definition、provenance、identity、dependencies 和 mount metadata 都在 side state。 +- capability 只有 `content` 与 `properties` 两种;它们共享同一计算和提交语义,只是写权限不同。 +- 普通函数值是 literal;只有显式 `tp-computed` value source 会执行并收集依赖。 +- signal source、bindings、plans、markers/indexes 和 opaque client state 在 transaction 中使用同一 revision,失败时共同回滚。 + +## 3. 独立数据流 + +```text +application state / theme / host edit + │ + ▼ + signals + bindings + │ exact dependency graph + ▼ + TP prepare context + │ candidate objects/bindings/anchors + ▼ + ordinary or client producer + │ object → schema/rules/cascade + │ → generic keyed surface plan + ▼ + reconcile + prepare diff + │ prepared text/property operations + ▼ + atomic multi-surface publication + │ + ▼ + strings / Emacs buffers +``` + +prepare 只产生 candidate state。producer 返回普通 surface plan 和可选 opaque client state。TP 不解释 client state,但把它与 plan、dependencies、mounts 和 revision 一起原子晋升。 + +## 4. 属性、cascade 与 value source + +### 4.1 Property schema + +`tp-define-property` 为 namespaced property id 注册 initial value、inheritance、normalizer、validator、equality、merge、projector 和 optional shorthand expander。schema 可以把 computed value 投影为 Emacs text properties,也可以只把值暴露给 consumer。 + +TP 对已注册属性域提供完整、确定的 cascade:origin/importance、layer、specificity、scope/source order、CSS-wide values、inheritance、custom properties/variables、shorthand、显式 nil 与 absent,以及 schema-defined normalization/equality。TP 不声称实现浏览器 CSS 属性或空间布局。 + +### 4.2 Literal 与 computed + +普通 Elisp value 永远是 literal,包括 function object。`help-echo` function、keymap command 和 callback 不会被 TP 隐式调用。 + +需要求值的声明必须使用 `tp-computed` 包装 compute function。compute 在所属 object binding 的 prepare context 中运行;`tp-signal-read` 和 `tp-binding-read` 自动登记依赖。返回值随后 normalize/validate,并按 literal 处理,不隐式调用第二次。错误终止整个 candidate transaction;相等结果不产生 surface change。 + +上层 DSL 可以接受可求值 Elisp,但必须在 constructor/compiler 边界明确区分 quoted list、literal function 和 computed source,并把响应式计算编译到 `tp-computed`,不能建立第二套 watcher。 + +## 5. Stable object 与 prepare context + +每个 object 的 identity 只在一个 surface 中有效,由 parent identity、sibling key 和 opaque kind 保留。显式 key 在同一 parent 下唯一;unkeyed object 只能按 position+kind 保留;handle 不能跨 surface 使用。 + +TP 在 mount/update prepare 开始时创建短生命周期 prepare context。producer 调用: + +```elisp +(tp-object-ensure context parent key kind) +``` + +匹配的 live object 返回原 handle;新增 object 只存在于 candidate state。duplicate key、stale parent、orphan object 或 cross-surface handle 在 prepare 中失败。只有成功 publication 才把 candidate identity 变成 live identity;失败 handle 必须不可解析。 + +`tp-surface-materialize-string` 给 producer 提供相同语义的 ephemeral context。object/binding 只在这次纯计算中存在,string 返回后全部释放,不进入 live registry。 + +`tp-object-resolve` 只读地按 surface 与 key path 解析 live handle,用于公开选择/交互入口,不创建对象。 + +## 6. Binding 与真正的响应式依赖 + +definition 是可复用配方,binding 是安装在一个 object 上的具体计算。`tp-bind` 以 object handle 加 caller-namespaced binding key 幂等安装,至少保存 compute、last successful value、dependencies、dirty state、revision 和 lifecycle policy。 + +`tp-binding-read` 读取另一个 binding 的 memoized value并登记 binding→binding dependency。因此 signal、computed property、measurement 或普通 derived value 可以组成真实依赖图,而不是在变量变化后扫描 buffer。 + +重新计算前撤销旧依赖,成功后以本次实际读取集合替换。conditional branch 因而会自动断开不再使用的 source。transaction dirty queue 去重,同一 binding 每批最多重算一次;循环报告完整路径。 + +每次 prepare 记录 touched object/binding。删除 object 时同步清理 bindings、subscriptions、anchors 和 mounts;仍存在但本次未声明的 binding 默认删除,只有显式 lifecycle policy 才能保留。普通 binding 可返回任意 client value,只有 designated producer binding 返回 plan/subplan。 + +## 7. Surface plan + +surface plan 是不可变语义的纯数据,节点字段为: + +| Field | Contract | +| --- | --- | +| `key` | sibling-local stable key | +| `kind` | opaque comparable discriminator | +| `text` | optional plain/propertized string leaf | +| `props` | final direct Emacs text properties | +| `children` | ordered child plans | +| `tags` | opaque side metadata indexed but not interpreted by TP | +| `capability` | `content` or `properties` | + +plan 不携带 marker、buffer position、patch op、producer closure、binding closure 或 client continuation。合法的 keymap/help-echo/callback function 可以作为最终 property value 保留,reconciler 永不调用它们。 + +public constructor 对 caller-owned plist/string 做 defensive copy 或提供 immutable semantics;commit 后修改原值不能改变已发布 surface。 + +## 8. Mount、range anchor 与属性所有权 + +### 8.1 Content capability + +`content` mount 拥有其 span 的文本和属性,可以插入、删除、移动、替换文字以及修改属性。它适合 dashboard、menu、special UI buffer 和高级 renderer output。 + +### 8.2 Properties capability + +`properties` mount 只能贡献声明的属性,不能修改 host text。`tp-range-anchor-create` 从 buffer、start/end 和 marker insertion policy 创建 opaque marker-backed anchor;producer 在 prepare 中调用 `tp-object-attach-range` 把 object 绑定到 anchor。plan 本身仍没有位置。 + +TP side state 为每个 anchor/property interval 保存 host baseline、各 TP contribution 和最后一次 published value。同一 surface 的重叠 contribution 通过 schema merge/cascade 合成。 + +外部代码把同一 property 改成不同于 TP 最后发布值时,下一次 prepare 默认报 `tp-property-conflict`。TP 不覆盖外部值,也不恢复旧 snapshot;调用者显式 `tp-range-rebase` 或 unmount。unmount 只撤销 TP contribution:当前值仍等于 TP 最后发布值时恢复 baseline,否则保留外部值并在 report 中记录 conflict。 + +host text 编辑由 live markers 跟随。跨越或删除 anchor 边界时按显式 shorten/remove/stale policy 处理;TP 不扫描附近文本猜测新位置。 + +## 9. Reconcile 与 transaction + +TP 按 parent/key reconcile object identity,并对 old/new plan 计算 child insert/remove/reorder、text diff 和 property-run diff。normal update 从 object→mount index 直接取得范围。 + +transaction 顺序是:冻结 candidate signal writes;建立 prepare contexts;准备所有实际受影响 surfaces;验证 capability/conflict/lifecycle;生成 per-surface operations 与 inverse journals;按稳定 surface id publish;最后原子切换 source values、bindings、plans、indexes、client state 和 revisions;全部成功后才运行 observers。 + +一个 global signal 可以触达多个 surfaces。TP 必须先全部 prepare,再逐 surface publish;任一 compute、buffer write、marker/index step 或 transaction participant 失败时,回滚已经发布的 surfaces,并恢复 signal values、binding values/dependencies、dirty queues 和 revisions。observer failure 发生在成功 commit 后,只记录而不回滚。 + +若 publish 中 buffer 被 kill,kill-buffer teardown 是不可逆权威结果;其他 surface 与 source state 回滚,TP 不复活 killed buffer。 + +## 10. Public API 层级 + +### 10.1 简单的一次性属性 + +```elisp +(tp-propertize string declarations) +(tp-apply buffer start end declarations) +``` + +二者使用相同 schema/cascade/projector core,不建立 identity、binding 或 live mount。现有 `tp-set`、`tp-reset`、`tp-add`、`tp-remove`、lookup/search APIs 继续复用这些底层语义。 + +### 10.2 响应式已有文本 + +```elisp +(tp-watch buffer start end compute) +``` + +`tp-watch` 创建 properties range anchor、surface object 和 binding,COMPUTE 返回 declarations,结果是可 update/unmount 的 opaque handle。普通用户不需要手工创建 object、binding 或 surface。 + +### 10.3 完整 retained UI + +```elisp +(tp-surface-mount buffer plan-or-producer options) +(tp-surface-update surface plan-or-producer) +(tp-surface-unmount surface) +``` + +完整 API 还包括 `tp-computed`、signals、prepare/object、bindings、range anchors、transactions、materialize-string、at-point/inspect/report。TP 不增加含义重叠的 `tp-mount`/`tp-update` aliases,也不公开 raw marker/patch/change-set/`:impact` APIs。 + +## 11. 独立验收场景 + +TP 1.0 在没有 Ebox load-path 时必须长期通过: + +1. static string/buffer properties:nested face、keymap、help-echo function、explicit nil; +2. reactive status:`tp-watch` 与 retained content producer、conditional/binding dependency、batch; +3. retained dashboard:keyed add/remove/reorder、button、theme cascade、rollback; +4. existing-text diagnostics:range anchor、host edit、overlap、external property conflict/rebase/unmount; +5. two-buffer producer:identity/state 隔离与 global-signal multi-surface atomicity; +6. performance:sparse update 与实际 dependency closure 成正比,equal value 零 buffer op,unmount 后无 marker/subscription/weak-reference 泄漏。 + +## 12. 兼容、版本与删除 + +TP 1.0 是主版本切换。能直接映射到统一 core 的静态 public API 保留;依赖 inline `tp-layers`/`tp-meta` database 和扫描式 renderer 才能工作的 managed behavior 必须明确删除或替换,不保留 hidden compatibility engine。 + +允许显式 one-shot legacy import 扫描历史 propertized text 并建立 surface;normal signal/style/update 热路径禁止自动调用它。 + +最终删除 layer→buffer registry、scan-driven refresh hooks、旧 inline managed codec、重复 transaction 和旧 batch renderer。TP 1.0 package、tests、examples 和本文档都能在没有 Ebox repository 的环境中独立工作。 + +## 13. 实施前必须冻结的合同 + +实现开始前的 executable contract tests 必须确定:prepare-context/object 时序;binding identity/lifecycle;literal/computed value;range anchor 和 property conflict;single/multi-surface rollback;三层便利 API;error taxonomy;report shape;explicit nil/absence;read-only、undo、narrowing、indirect-buffer 和 kill-buffer 行为。 + +任何实现若要求 Ebox-specific branch、post-commit identity scan、plan 中的 raw position/closure、第二套 renderer 或无法安全撤销 properties contribution,应停止接入并重新评审 ownership model,而不是增加 adapter mode。