docs: 完善画布、页面及测试的逻辑注释 #14

Open
codex-bot wants to merge 55 commits from codex/canvas-resource-geometry-comments into main
Showing only changes of commit bb84e8a4da - Show all commits
+6 -1
View File
@@ -28,7 +28,8 @@ const path={type:'bezier-chain',extension:{keep:true},knots:[{id:'k',mode:'corne
const target=id=>({id,incarnation:1});
// 挑出尚未解决的非上传操作,用作恢复决策集合;不要把资源上传混入文档重规划。
const pending=engine=>[...engine.getSnapshot().runtime.ledger.operations.values()].filter(record=>record.phase!=='resolved'&&record.intent.operationType!=='asset.upload');
// 默认对所有待恢复文档操作选择 keep-local;个别用例再覆盖为 discard-local。
// 测试默认对所有待恢复文档操作选择 keep-local;个别用例再覆盖为 discard-local。
// 这是 fixture 的决策辅助器,不是产品自动替用户处理冲突;keep-local 仍需在新基线上重新生成合法变化,不能覆盖整份旧 working。
const choices=engine=>new Map(pending(engine).map(record=>[record.intent.id,'keep-local']));
// 建立独立的 server、版本表、持久化 image 和 leader;默认所有提交明确 not-applied,便于触发可重规划冲突。
function fixture(original=base()){
@@ -154,6 +155,7 @@ test('an atomic frame/canvas/member creation can be kept or discarded without or
});
// 删除意图针对新基线重新规划,包含远端新加的关联边;undo 恢复远端新正文及连线,并分配新的元素代次。
// 新 undo 的 before 值来自审阅过的当前服务端内容,而非最初点击删除时的旧对象,否则会丢掉后来新增的正文或引用。
test('deletion is re-planned from current content and includes a new remote incident edge in its undo unit',async()=>{
const f=fixture(),engine=await f.open();engine.editor.dispatch({type:'element.remove',target:target('a')});await engine.settle();
f.remote([{kind:'field',target:target('a'),field:'data.text',before:'',after:'remote content',beforePresent:true,afterPresent:true},{kind:'element',id:'new-edge',before:null,after:edge('new-edge','a','b')}]);
@@ -268,6 +270,7 @@ test('an explicit end position changes the container pose while preserving intri
});
// 普通节点跨缩放分区保持投影宽度与 viewScale;自定义 resize 下限按视觉单位换算到目标 canvas 的局部宽度。
// target 的 contentScale=2.5,视觉最小宽度 80 对应局部宽度 32;不能把局部 32 误判为违反组件的 80 下限。
test('ordinary nodes keep visual style scale across moves, and resize bounds use intrinsic visual units',()=>{
const document=scaledTree(),editor=createEditor({registry,document}),before=projectCanvas(editor.getSnapshot().document,'root',registry,new Set(),()=>undefined).nodes.find(node=>node.id==='a');
editor.dispatch({type:'element.move',target:target('a'),canvasId:'target'});const current=editor.getSnapshot().document,after=projectCanvas(current,'root',registry,new Set(),()=>undefined).nodes.find(node=>node.id==='a');
@@ -551,6 +554,7 @@ test('a later confirmed undo or redo changes only history during recovery and ca
});
// 后续已确认 undo 把对象恢复到第二代时,旧历史需映射到新身份,但旧 operations 的第一代证据不能被篡改。
// 历史条目描述下一次可撤销目标,可以随恢复重建;旧操作描述当时已经发生的事实,必须保留原 incarnation,二者不是同一份记录。
test('a later confirmed undo restoration remaps older history without changing old operation incarnations',async()=>{
const f=fixture();proveFixtureReceipt(f);const engine=await f.open();f.reject=false;const old=engine.editor.dispatch({type:'element.data',target:target('a'),patch:{title:'edited'}});await engine.settle();engine.editor.dispatch({type:'element.remove',target:target('a')});await engine.settle();engine.editor.dispatch({type:'element.data',target:target('c'),patch:{title:'edited c'}});await engine.settle();f.reject=true;const pendingUndo=engine.editor.history.undo();await engine.settle();f.reject=false;const confirmed=engine.editor.history.undo();await engine.settle();assert.equal(f.server().elements.get('a').incarnation,2);
const session=await engine.prepareRecovery(),plan=session.plan(new Map([[pendingUndo.operationIds[0],'keep-local']]));await session.resolve(plan);await engine.settle();assert.equal(engine.getSnapshot().history.undo.length,1);assert.equal(engine.getSnapshot().operations.get(old.operationIds[0]).changes[0].target.incarnation,1);assert.equal(f.calls.filter(call=>JSON.parse(call.body).intent.id===confirmed.operationIds[0]).length,1);assert.equal(engine.editor.history.undo().status,'applied');await engine.settle();assert.equal(f.server().elements.get('a').data.title,'a');assert.equal(f.server().elements.get('a').incarnation,2);assert.equal(engine.editor.history.redo().status,'applied');await engine.settle();assert.equal(f.server().elements.get('a').data.title,'edited');await engine.close();
@@ -565,6 +569,7 @@ test('a later confirmed redo restoration remaps a remaining redo entry into its
// 远端覆盖导致的历史前缀剪除需作为 adjustment 保存在 adoption 证明中,重放证据应精确得到计划历史并可持久化解码。
// adoption 记录本轮“哪些意图保留、哪些历史贡献剪除”的接纳结果;下一轮需重放这些选择,不能只凭最终两个 stack 猜它们如何形成。
test('settled history adjustments in an adoption proof preserve the explicit removal of a remote-overwritten prefix',async()=>{
const f=fixture(),engine=await f.open();f.reject=false;engine.editor.dispatch({type:'element.data',target:target('a'),patch:{title:'ack'}},{groupId:'typing'});await engine.settle();f.reject=true;const edit=engine.editor.dispatch({type:'element.data',target:target('a'),patch:{title:'pending'}},{groupId:'typing'});await engine.settle();f.remote([{kind:'field',target:target('a'),field:'data.title',before:'ack',after:'remote',beforePresent:true,afterPresent:true}]);const before=engine.getSnapshot(),session=await engine.prepareRecovery(),plan=session.plan(new Map([[edit.operationIds[0],'discard-local']]));assert.equal(plan.history.entries.size,0);assert.ok(plan.audit.historyReplay.events.some(event=>event.kind==='adjustment'));assert.ok(sameHistory(replayHistoryEvidence(before.history,plan.audit.historyReplay),plan.history));await session.resolve(plan);assert.equal(decodeRecovery(f.image(),registry).history.entries.size,0);await engine.close();
});