@@ -134,12 +134,18 @@ type OwnedSessionFileWrite = {
134134 fingerprint : SessionFileFingerprint ;
135135} ;
136136
137+ type TrustedSessionFileState = {
138+ generation : number ;
139+ fingerprint : SessionFileFingerprint ;
140+ } ;
141+
137142// Controllers in the same OpenClaw process can legitimately take turns writing
138143// the same session file while another attempt is released for model I/O. Track
139144// only fingerprints that changed while OpenClaw held the write lock so the
140145// takeover fence can distinguish those locked in-process writes from unowned
141146// external file changes.
142147const ownedSessionFileWrites = new Map < string , OwnedSessionFileWrite > ( ) ;
148+ const trustedSessionFileStates = new Map < string , TrustedSessionFileState > ( ) ;
143149let ownedSessionFileWriteGeneration = 0 ;
144150
145151function resolveSessionFileFenceKey ( sessionFile : string ) : string {
@@ -151,13 +157,41 @@ function recordOwnedSessionFileWrite(
151157 fingerprint : SessionFileFingerprint ,
152158) : number {
153159 ownedSessionFileWriteGeneration += 1 ;
154- ownedSessionFileWrites . set ( sessionFileKey , {
160+ const state = {
161+ generation : ownedSessionFileWriteGeneration ,
162+ fingerprint,
163+ } ;
164+ ownedSessionFileWrites . set ( sessionFileKey , state ) ;
165+ trustedSessionFileStates . set ( sessionFileKey , state ) ;
166+ return ownedSessionFileWriteGeneration ;
167+ }
168+
169+ function trustSessionFileState (
170+ sessionFileKey : string ,
171+ fingerprint : SessionFileFingerprint ,
172+ ) : number | undefined {
173+ const trusted = trustedSessionFileStates . get ( sessionFileKey ) ;
174+ if ( trusted ) {
175+ return sameSessionFileFingerprint ( trusted . fingerprint , fingerprint )
176+ ? trusted . generation
177+ : undefined ;
178+ }
179+ ownedSessionFileWriteGeneration += 1 ;
180+ trustedSessionFileStates . set ( sessionFileKey , {
155181 generation : ownedSessionFileWriteGeneration ,
156182 fingerprint,
157183 } ) ;
158184 return ownedSessionFileWriteGeneration ;
159185}
160186
187+ function isTrustedSessionFileState (
188+ sessionFileKey : string ,
189+ fingerprint : SessionFileFingerprint ,
190+ ) : boolean {
191+ const trusted = trustedSessionFileStates . get ( sessionFileKey ) ;
192+ return ! ! trusted && sameSessionFileFingerprint ( trusted . fingerprint , fingerprint ) ;
193+ }
194+
161195async function readSessionFileFingerprint ( sessionFile : string ) : Promise < SessionFileFingerprint > {
162196 try {
163197 const stat = await fs . stat ( sessionFile , { bigint : true } ) ;
@@ -347,6 +381,9 @@ export async function createEmbeddedAttemptSessionLockController(params: {
347381 if ( sameSessionFileFingerprint ( beforeWrite , fingerprint ) ) {
348382 return null ;
349383 }
384+ if ( ! isTrustedSessionFileState ( sessionFileFenceKey , beforeWrite ) ) {
385+ return null ;
386+ }
350387 const generation = recordOwnedSessionFileWrite ( sessionFileFenceKey , fingerprint ) ;
351388 return { fingerprint, generation } ;
352389 }
@@ -390,11 +427,12 @@ export async function createEmbeddedAttemptSessionLockController(params: {
390427 heldLock = undefined ;
391428 const fingerprint = await readSessionFileFingerprint ( params . lockOptions . sessionFile ) ;
392429 const ownedWrite = ownedSessionFileWrites . get ( sessionFileFenceKey ) ;
430+ const trustedGeneration = trustSessionFileState ( sessionFileFenceKey , fingerprint ) ;
393431 fenceFingerprint = fingerprint ;
394432 fenceGeneration =
395433 ownedWrite && sameSessionFileFingerprint ( ownedWrite . fingerprint , fingerprint )
396434 ? ownedWrite . generation
397- : fenceGeneration ;
435+ : ( trustedGeneration ?? fenceGeneration ) ;
398436 fenceActive = true ;
399437 await lock . release ( ) ;
400438 } ,
0 commit comments