Yield recovery container encoding without changing durable cuts

This commit is contained in:
2026-11-11 04:04:24 +08:00
parent 57dab91a9c
commit b4c40d3087
7 changed files with 195 additions and 18 deletions
+24
View File
@@ -348,3 +348,27 @@ test('a failed final publication keeps the raw receipt and waiting claim instead
test('receipt compaction is optional and invalid codecs cannot block a valid ACK or discard its raw payload',async()=>{
for(const compactResolvedReceipt of [undefined,()=>{throw Error('compact failed');},()=>undefined]){const storage=storageFixture(),port=persistenceFixture(compactResolvedReceipt?{compactResolvedReceipt}:{}),{engine,errors}=await open(storage,port);try{engine.editor.dispatch({type:'element.data',target,patch:{title:'keep raw'}});await engine.settle();const request=[...engine.getSnapshot().runtime.ledger.requests.values()][0];assert.equal(request.phase,'resolved');assert.deepEqual(engine.getSnapshot().runtime.receipts.get(request.id),{receipt:request.id});assert.equal(engine.getSnapshot().runtime.conflicts.size,0);assert.equal(errors.length,compactResolvedReceipt?1:0);}finally{await engine.close();}}
});
test('encoding yields preserve the captured Root, ordered durable prefix and send barrier', {timeout:15000},async()=>{
const previous=Object.getOwnPropertyDescriptor(globalThis,'scheduler'),entered=deferred(),resume=deferred();let hold=false,paused=false,yields=0;
Object.defineProperty(globalThis,'scheduler',{configurable:true,value:{async yield(){yields++;if(hold&&!paused){paused=true;entered.resolve();await resume.promise;}}}});
let engine;
try{
const rows=Array.from({length:17000},(_,i)=>({...original.elements.get('a'),id:i===0?'a':`encoding-${i}`}));
const document=createDocument('project',[{id:'canvas',parent:null}],rows),storage=storageFixture(),port=persistenceFixture({async submit(request){port.calls.push(['submit',request]);const stored=storage.image();assert.ok(stored.payload.runtime.ledger.requests.some(([id,row])=>id===request.id&&row.body===request.body&&row.phase==='dispatch-marked'));return{outcome:'unresolved'};}});
({engine}=await open(storage,port,{document,clock:idleClock()}));await engine.persist();
const start=engine.getSnapshot().rootRevision,saved=storage.saved.length;hold=true;
assert.equal(engine.editor.dispatch({type:'element.data',target,patch:{title:'captured-first'}}).status,'applied');
const captured=engine.getSnapshot(),first=engine.persist();await entered.promise;
assert.equal(storage.saved.length,saved);assert.equal(port.calls.length,0);
assert.equal(engine.editor.dispatch({type:'element.data',target,patch:{title:'edited-during-yield'}}).status,'applied');
const second=engine.persist();assert.equal(engine.getSnapshot().document.elements.get('a').data.title,'edited-during-yield');
resume.resolve();await Promise.all([first,second]);
const cuts=storage.saved.slice(saved);assert.ok(yields>0);
assert.deepEqual(cuts.map(cut=>cut.rootRevision),Array.from({length:cuts.length},(_,i)=>start+i+1));
assert.deepEqual(cuts[0],encodeRecovery(captured));
assert.equal(cuts[0].payload.document.elements.find(row=>row.id==='a').data.title,'captured-first');
assert.equal(storage.image().payload.document.elements.find(row=>row.id==='a').data.title,'edited-during-yield');
assert.equal(engine.getDurability().durableRootRevision,engine.getSnapshot().rootRevision);
}finally{resume.resolve();if(engine)await engine.close();if(previous)Object.defineProperty(globalThis,'scheduler',previous);else delete globalThis.scheduler;}
});