This commit is contained in:
33333-33333 2026-08-01 16:06:14 +09:00
commit 4c4e767ec6
73 changed files with 3502 additions and 741 deletions

View file

@ -16,18 +16,18 @@ assert(!initialSource.includes('loadRecoveryCoverage('),
'Startup still performs the recovery coverage read in a second transaction');
assert(replaceSource.includes('await preserveRecoveryDurably('),
'World replacement does not await a verified recovery backup');
assert(functionSource('retryRecovery').includes('readRecoveryEnvelope')&&functionSource('retryRecovery').includes('stageRecoverySnapshotV2')&&functionSource('retryRecovery').includes("kind:'recovery'"),
'Recovery backup is not restored through the validated staged-world path');
assert(functionSource('runStatusRetry').includes('statusRetryAction')&&!app.includes('復元用バックアップがありません。'),
'The shared-server retry button still attempts obsolete local-backup recovery');
assert(clearSource.includes("activateReadyWorldV2({epoch:newEpoch,expected,world},{kind:'reset'})"),
'Fresh-world reset does not use atomic epoch activation');
assert(!app.includes('worldMutationLockDepth')&&functionSource('withWorldMutationLock').includes("mode:'exclusive'"),
'World mutation locking still bypasses unrelated asynchronous callers');
assert(functionSource('persistNow').includes('if(options.lockHeld===true)return run()')&&functionSource('expandMetaNow').includes('lockHeld:true'),
'Nested expansion persistence can deadlock behind a queued lock waiter');
assert(app.includes('if(!worldInitReady){deferredWorldSignals.push(signal)'),
'Cross-tab messages are not buffered until initialization is complete');
assert(functionSource('initCloudSync').includes('if(cloudApiEnabled&&!cloudOutboxReady)'),
'Cloud synchronization is not fail-closed when IndexedDB health is uncertain');
assert(!app.includes('worldInitReady')&&!app.includes('deferredWorldSignals')&&!app.includes('BroadcastChannel'),
'Retired cross-tab board synchronization remains');
assert(functionSource('fetchCurrentSharedWorldStatus').includes("status.singleWorld===true")&&functionSource('initCloudSync').includes('resetClientToSingleSharedWorld()'),
'Startup does not require and adopt the single server-authoritative world');
const request=result=>({result});
function memoryStore(initial=[],keyOf=row=>row.id){
@ -176,28 +176,6 @@ function verifyGlobalMerge(){
'Global timestamped records, encounter memory, or retired combo data were merged incorrectly');
}
async function verifySignalRetry(){
const timers=[];let attempts=0,remembered=0;
const context={
console:{warn:()=>{}},sessionId:'self',worldInitReady:false,deferredWorldSignals:[],
seenWorldCommitIds:new Set(),pendingWorldCommitIds:new Set(),syncQueue:Promise.resolve(),
worldCommitId:signal=>signal.commitId||'',applyWorldSignal:async()=>{attempts++;if(attempts===1)throw new Error('transient')},
rememberWorldCommit:()=>remembered++,
setTimeout:callback=>{timers.push(callback);return timers.length}
};
vm.createContext(context);
vm.runInContext(`${functionSource('queueWorldSignal')}\n${functionSource('drainWorldSignals')}\nthis.queueWorldSignal=queueWorldSignal;this.drainWorldSignals=drainWorldSignals;`,context);
const signal={commitId:'remote:1',sessionId:'remote'};
context.queueWorldSignal(signal);
assert(context.deferredWorldSignals.length===1&&attempts===0,'A startup signal ran before initialization');
context.drainWorldSignals();context.queueWorldSignal(signal);
await context.syncQueue;
assert(attempts===1&&remembered===0&&timers.length===1,
'A failed signal was deduplicated as if it had succeeded');
timers.shift()();await Promise.resolve();await context.syncQueue;
assert(attempts===2&&remembered===1,'A transient signal failure was not retried and committed once');
}
async function verifyDurableBackup(){
const source=functionSource('preserveRecoveryDurably');
const failing={
@ -231,7 +209,6 @@ function verifyRevisionSeed(){
(async()=>{
await verifyPersistenceConflicts();
verifyGlobalMerge();
await verifySignalRetry();
await verifyDurableBackup();
verifyRevisionSeed();
console.log('Concurrency and replacement safety test passed');