From 5f2bf2d142d0086b27dd497804cc37965040282a Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Thu, 12 Nov 2026 14:09:25 +0800 Subject: [PATCH] docs(runtime): explain default image sizing grant lifecycle --- src/lib/canvas-runtime/default-image-size.ts | 28 +++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/lib/canvas-runtime/default-image-size.ts b/src/lib/canvas-runtime/default-image-size.ts index f1cb88d..cad7c75 100644 --- a/src/lib/canvas-runtime/default-image-size.ts +++ b/src/lib/canvas-runtime/default-image-size.ts @@ -1,7 +1,7 @@ /** * 为新建图片保留一次可恢复的自动默认尺寸授权。解码/服务元数据异步到达后,只有创建历史、 * 目标身份/类型、资源引用及初始视觉尺寸仍有效时才允许调整;实际文档/历史改写走专用 planner。 - * 用户已提交的手动 resize 撤销授权,即使以后 undo 回到初始尺寸也不自动复活。 + * 已判为用户 resize 的授权转为 revoked,正常后续 undo 不自动复活;本模块不负责执行异步 resize 或保存磁盘。 */ import type { Commit, CoreSnapshot, Id, Registry, Target } from '../canvas-core/types.ts'; import { closeNumber, unitScale } from '../canvas-core/units.ts'; @@ -9,7 +9,9 @@ import { fault, freeze, readMap } from '../canvas-core/values.ts'; import type { EngineSnapshot, RuntimeState } from './contracts.ts'; import type { ResourceRecord } from './resources.ts'; -/** 目标代次/创建entry/组件版本和初始视觉尺寸共同限定授权,status/code 描述可恢复结果。 */ +/** 以目标代次/创建 entry/组件版本和 width,height÷unitScale 的初值限定一次自动尺寸授权。 + * pending 等候元数据/调度,blocked 可由引擎显式重试,applied/revoked 不再由本检查器自动执行。 + * 这些状态不等同上传状态或另一个 undo 单元,也不单独证明用户权限/创建历史仍可用。 */ export type DefaultSizeGrant = { readonly target: Target; readonly entryId: Id; readonly componentId: string; readonly dataVersion: number; readonly initialSize: { readonly width: number; readonly height: number }; @@ -18,7 +20,9 @@ export type DefaultSizeGrant = { /** 每资源的版本化授权列表;图片副本可有多个目标,各 grant 独立判断。 */ export type DefaultImageSizing = { readonly version: 1; readonly grants: readonly DefaultSizeGrant[] }; -/** 校验解释器、目标/entry/尺寸/状态,并禁止同一 ID+incarnation 的重复 grant。 */ +/** 只验 v1、目标/entry/组件版本、正有限初始尺寸、状态/code 与单资源内目标代次唯一性。 + * 不查真实 document/history/resource,不证明所有 grant 有效,也不捕获/冻结输入或要求尺寸为整数。 + * 未知版本报解释器不可用;保留未来 opaque sizing 的兼容策略由恢复边界处理,不在此按 v1 解释。 */ export function validateDefaultImageSizing(value: unknown): asserts value is DefaultImageSizing { const state = value as DefaultImageSizing; if (!state || state.version !== 1) throw fault('default_size_interpreter_unavailable'); @@ -34,7 +38,10 @@ export function validateDefaultImageSizing(value: unknown): asserts value is Def } } -/** 从当前创建提交与关联 history 捕获授权,只针对引用该 assetId 的已知且可 resize 节点。 */ +/** 从有本 commit 操作贡献的 history 项与 commit 创建变化,匹配当前同代次、同 assetId、已知且能 resize 的 node。 + * 保存提交后 width/height÷unitScale,不取文件像素/世界坐标;此时尚不需要 stored 回执或解码尺寸。 + * entry 按“含 commit 操作 ID”筛选,不逐项证明该 entry 的 changes 恰含该目标创建;调用方须提供真实创建提交。 + * 替换 resource.sizing 为本次 grants(可为空),不合并旧 grant 或做重复校验;完整 grant 校验由发布/恢复边界负责。 */ export function captureDefaultImageSizing(resource: ResourceRecord, next: CoreSnapshot, commit: Commit, registry: Registry): ResourceRecord { const grants: DefaultSizeGrant[] = []; for (const entry of next.history.entries.values()) { @@ -54,10 +61,11 @@ export function captureDefaultImageSizing(resource: ResourceRecord, next: CoreSn return freeze({ ...resource, sizing: { version: 1, grants } }); } -/** Runs on every publication path. Revocation is durable and does not revive when - * undo happens to return to the default geometry. Preview-only gestures do not publish. - */ -/** 每条 Root 发布路径检查 pending/blocked grant;失效时持久标 revoked,未变化则复用 runtime。 */ +/** Return a revocation candidate from each publication path; the engine persists the Root. */ +/** 对 next 的 v1 pending/blocked 授权检查身份/类型/资源、创建项仍在 undo、归一化尺寸和新用户意图。 + * 失效则返回带 revoked/code 的 copy-on-write runtime,不执行 resize/网络/磁盘;未变化复用 next.runtime。 + * applied/revoked 输入直接保留,未来版本不解释;不独自阻止受信调用方手动改写这些状态,状态所有权由引擎管理。 + * 不读取 registry/手势/解码结果,真正消费 grant 的资格与尺寸计划由引擎随后复核。 */ export function prepareDefaultImageSizing(previous: EngineSnapshot, next: EngineSnapshot): RuntimeState { let resources = next.runtime.resources; for (const [id, resource] of resources) { @@ -76,7 +84,9 @@ export function prepareDefaultImageSizing(previous: EngineSnapshot, next: Engine if (!closeNumber(element.geometry.width / units, grant.initialSize.width) || !closeNumber(element.geometry.height / units, grant.initialSize.height)) code = 'user_resized'; // Detect committed resize-away-and-back transactions. Pure coordinate // conversions may alter geometry sizes and unitScale together. - // 已提交事务即使最终尺寸回原值,也检查用户 geometry changes;纯 owner/unit 转换例外。 + // 在文档变化且 operations 数量增加时扫描新 user 意图,识别 resize-away-and-back;假设操作表按正常发布追加。 + // 同一意图含 owner 字段或 unitScale 变化就整体按转换豁免此附加检查;不逐轴拆分任意混合转换/手动缩放。 + // 净归一化尺寸已改变仍会在上方撤销;纯预览不发布 operations,因此不会因 pointermove 单独触发。 if (!code && previous.document !== next.document && previous.operations.size !== next.operations.size) { for (const [operationId, intent] of next.operations) { if (previous.operations.has(operationId) || intent.origin !== 'user') continue;