docs(tests): explain migration retries and explicit conflict decisions

This commit is contained in:
2026-11-12 17:53:12 +08:00
parent 15a66969cd
commit 1defe9db90
2 changed files with 7 additions and 1 deletions
+3
View File
@@ -73,6 +73,7 @@ test('lost committed migration ACK is recovered by original query after reload w
// 提交前断线的 durable 请求先 query unknown,再保留原 ID 和包含额外空白的 body 精确重试,不能重序列化。
test('a durable uncommitted request queries unknown then retries only its exact original body and key',async()=>{
const f=fixture();f.failBeforeCommit=true;const first=f.make();await first.start(root,async()=>{});
// 空白不会改变 JSON 语义,却会改变请求原字节;人为补空白后检查恢复转发原字符串,不能 parse 后重新 stringify。
const original=first.read(),spaced={...original,body:' \n'+original.body+' '};f.storage.setItem(canvasMigrationStorageKey(scope),JSON.stringify(spaced));f.failBeforeCommit=false;
const recovered=f.make({createId(){assert.fail('must retain original key');}});
assert.equal((await recovered.resume()).status,'applied');
@@ -108,6 +109,7 @@ test('bare rejection and malformed or foreign success retain the frozen request
response=>({...response,body:{...response.body,identity_map:[{sourceCanvasId:child,structure:'node',sourceId:'a',elementId:id(20)}]}}),
response=>({...response,body:{...response.body,identity_map:[{sourceCanvasId:root,structure:'connection',sourceId:'a',elementId:id(20)}]}}),
]){
// alter 只破坏返回给客户端的副本;假服务已保存合法回执,所以关闭篡改后可查询同一成功请求。
const f=fixture();f.alter=alter;const migration=f.make();assert.equal((await migration.start(root,async()=>{})).status,'pending');
const frozen=migration.read();assert.equal(frozen.phase,'pending');assert.equal(migrationBlocksCanvas(frozen,root),true);
f.alter=undefined;assert.equal((await f.make().resume()).status,'applied');assert.equal(f.posts().length,1);
@@ -147,6 +149,7 @@ test('failed result retirement remains recoverable and a storage port that drops
const f=fixture(),storage={...f.storage,removeItem(){throw Error('storage unavailable');}};
await assert.rejects(()=>f.make({storage}).start(root,async()=>{}),/storage unavailable/);
assert.equal(f.records.size,1);assert.equal((await f.make().resume()).status,'applied');assert.equal(f.posts().length,1);
// setItem 不抛错但吞掉写入,读回检查仍必须发现未持久化;不能把函数返回当作落盘成功证据。
const g=fixture();await assert.rejects(()=>g.make({storage:{...g.storage,setItem(){}}}).start(root,async()=>{}),/migration_not_durable/);assert.equal(g.posts().length,0);
});