docs(tests): explain size history traversal and recovery capture semantics

This commit is contained in:
2026-11-12 17:57:51 +08:00
parent 93f14af667
commit 05a41813f3
2 changed files with 7 additions and 3 deletions
+4 -2
View File
@@ -61,7 +61,7 @@ test('cooperative sealing captures unknown values before yielding and retains ex
assert.deepEqual(calls,['getter','left','right']);
mutable.title='outside';current='outside';
const image=await pending;
// A second uncached table below exercises the work ceiling with a coarse clock.
// 下方另造未预热的大表,用静止时钟隔离工作量上限;即使时间预算不增长也必须让出。
assert.ok(yields>0);assert.deepEqual(image,expected);assert.equal(isSealedRecoveryImage(image),true);
assert.equal(sealedRecoveryByteLength(image),new TextEncoder().encode(JSON.stringify(image)).byteLength);
const beforeCoarse=yields;
@@ -82,6 +82,7 @@ test('cooperative preparation evaluates every unsafe occurrence and rejects erro
await assert.rejects(sealRecoveryImageAsync(17,1,1,dataArray(Array.from({length:1000},(_,i)=>i)),{now:()=>ticks++,frameBudgetMs:1,yieldTask:async()=>{throw Error('yield_failed');}}),/yield_failed/);
// 异步深度检查使用内部 dataRecord 包装;省略的对象字段和变成 null 的数组项占用深度不同。
const nested=(n,leaf)=>{for(let i=0;i<n;i++)leaf=dataRecord({child:leaf});return leaf;};
// 预热 leaf 只允许复用编码内容,不能把它的高度从外层深度预算中抹去。
const leaf=freeze({value:1});encodeRecoveryValue(leaf);
await assert.rejects(sealRecoveryImageAsync(17,1,1,nested(64,leaf)),/invalid_recovery_payload/);
await assert.rejects(sealRecoveryImageAsync(17,1,1,nested(64,dataArray([undefined]))),/invalid_recovery_payload/);
@@ -126,7 +127,7 @@ test('repeated owned containers reuse facts assembled earlier in the same asynch
assert.ok(yields>0);assert.equal(image.payload.left,image.payload.right);
assert.equal(image.payload.left.length,1000);assert.equal(image.payload.left[999].index,999);
assert.equal(sealedRecoveryByteLength(image),new TextEncoder().encode(JSON.stringify(image)).byteLength);
// Unsafe descendants still need independent values for every occurrence.
// 相同容器身份不代表后代 getter 安全;每次出现仍需独立捕获,递增值必须依次为 1、2。
let n=0;const unsafe=dataRecord({getValue:Object.freeze({get value(){return ++n;}})});
const captured=await sealRecoveryImageAsync(17,1,1,dataArray([unsafe,unsafe]));
assert.deepEqual(captured.payload,[{getValue:{value:1}},{getValue:{value:2}}]);
@@ -171,6 +172,7 @@ test('unknown callbacks invalidate the detached JSON environment without changin
// left 先捕获,bridge getter 改写数组 toJSON,right 后捕获;同一 image 内顺序变化必须与同步 codec 一致。
const make=async()=>dataRecord({left:await ownedRecord(),bridge:{get value(){Object.defineProperty(Array.prototype,'toJSON',{configurable:true,value(){return ['changed-by-callback'];}});return 'bridge';}},right:await ownedRecord()});
try{
// 同步参照也会改写原型,先 cleanup 再构造异步输入,保证两次捕获从相同环境开始。
const expected=sealRecoveryImage(17,1,1,await make());cleanup();
const payload=await make();let tick=0,yields=0;
const pending=sealRecoveryImageAsync(17,1,1,payload,{now:()=>tick++,frameBudgetMs:1,yieldTask:async()=>{yields++;}});