docs(runtime): clarify planning checkpoints and scope evidence

This commit is contained in:
2026-11-12 13:23:33 +08:00
parent 17c14c85e8
commit 896e6a0656
2 changed files with 27 additions and 8 deletions
+10 -4
View File
@@ -8,7 +8,9 @@ import {fault} from '../canvas-core/values.ts';
/** Snapshot-bound direct membership counts, including nodes and connections. */
/** 当前捕获快照的直属数量,包含节点和边;不是递归子树大小或 DOM 已挂载数量。 */
export type CanvasElementCounts=Readonly<Record<Id,number>>;
/** 要求 counts 精确覆盖 canvasIds、每项非负安全整数,且总和等于声明 total。 */
/** 检查自有可枚举键数量及 canvasIds 的每个键存在,计数为非负安全整数,总和安全且等于 total。
* canvasIds 须由调用方保证唯一;此函数不单独去重,重复声明会破坏“键数量相同即覆盖相同”的前提。
* 只验证声明内部一致,不读取真实元素、认证服务或证明后续 payload 已齐;输入也不在此捕获/冻结。 */
export function validateCanvasElementCounts(value:unknown,canvasIds:readonly Id[],total:number):asserts value is CanvasElementCounts {
if(!value||typeof value!=='object'||Array.isArray(value))throw fault('invalid_model_coverage');
const counts=value as Record<Id,unknown>,keys=Object.keys(counts);let sum=0;
@@ -20,7 +22,9 @@ export function validateCanvasElementCounts(value:unknown,canvasIds:readonly Id[
/** All active IDs in the capture, including records not yet received. */
/** 完整活 ID 命名空间,即使部分记录尚未传到客户端,也预先知道其直接 owner。 */
export type ElementOwners=Readonly<Record<Id,Id>>;
/** 核验每个活 ID 的 owner 合法,并按 owner 反算数量与 counts 一致,不靠已读前缀猜完整性。 */
/** 要求声明恰有 total 个自有可枚举活 ID,每个非空 ID 的 owner 是 counts 中已有键,再反算数量。
* counts 应先经计数校验;此处不独立验证其值域,也不与已读 document 比较 ID/owner 是否对应。
* 只做同步声明一致性检查,不捕获/冻结输入;实际 payload 到达后还需匹配这份源快照身份表。 */
export function validateElementOwners(value:unknown,counts:CanvasElementCounts,total:number):asserts value is ElementOwners {
if(!value||typeof value!=='object'||Array.isArray(value)||Object.keys(value).length!==total)throw fault('invalid_model_identity');
// 无原型计数表避免特殊 owner 键污染计数;空 canvas 由缺省 0 与 counts 比较。
@@ -30,8 +34,10 @@ export function validateElementOwners(value:unknown,counts:CanvasElementCounts,t
}
/** Full captured topology, independent of which entry payloads have arrived. */
/** 用完整 topology+owner 证明验证单根、父存在、入口唯一/归属正确和无环。
* 此时入口记录可能尚未收到,入口是否确为 node 仍需 payload 到达后的文档校验。 */
/** 用源 canvas 表和已验证 owners 声明检查唯一根=projectId、父存在、入口唯一/归属与无环。
* 不是完整 CanvasRecord/payload schema 校验;未收到入口时不能证明其为 node、组件可用或实际拥有关系一致。
* 每个子 canvas 重新走父链,深树会反复访问共享祖先;同步检查无预算/取消,应由捕获规模约束成本。
* 不捕获输入或标记文档已完整;加载器另需核对已收到树/元素与此声明,再建立 owner 的覆盖状态。 */
export function validateCanvasTopology(canvases:readonly import('../canvas-core/types.ts').CanvasRecord[],owners:ElementOwners,projectId:Id):void {
if(!Array.isArray(canvases)||!canvases.length)throw fault('invalid_model_topology');
const table=new Map(canvases.map(canvas=>[canvas?.id,canvas]));if(table.size!==canvases.length||!table.has(projectId))throw fault('invalid_model_topology');