fix(snapshot): cache akkumuliert deletedCoords + timeout-kommentar

Code-review-feedback aus etappe 2.9/2.10:

1. cli.ts: deletedCoords im cache wird ab jetzt akkumuliert statt
   ersetzt. Vorher wurden bei einem run nur die aktuell von relays
   gelieferten kind:5-coords geschrieben — wenn ein relay beim
   naechsten run die alten deletions nicht mehr liefert (GC,
   relay-tausch), waere die geschichte verloren und newDeletionsCount
   im naechsten lauf wieder "neu" -> false-positive hard-fail im
   drop-check.

2. relays.ts: kommentar zum belt-and-suspenders-setTimeout neben dem
   RxJS-timeout-operator, damit der zweck (handle-cleanup falls beide
   subscribe-callbacks verschluckt werden) klar ist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jörg Lohrer 2026-04-28 08:27:12 +02:00
parent d7bb62d469
commit 2c4bceb768
2 changed files with 12 additions and 2 deletions

View File

@ -92,12 +92,17 @@ async function main(): Promise<number> {
posts: postJsons,
})
const allDeletedCoords = deletions.flatMap((d) =>
const currentDeletedCoords = deletions.flatMap((d) =>
d.tags.filter((t) => t[0] === 'a' && t[1]).map((t) => t[1] as string)
)
// Cache akkumuliert deletedCoords ueber alle bisherigen runs — nicht
// ersetzen: wenn ein relay beim naechsten run die alten kind:5-events
// nicht mehr liefert (GC, relay-tausch), wuerde sonst der vergleich
// gegen previousDeletedCoords im naechsten lauf wieder als "neu"
// werten und einen false-positive hard-fail ausloesen.
const newCache: CacheState = {
lastKnownGoodCount: filtered.length,
deletedCoords: [...new Set(allDeletedCoords)],
deletedCoords: [...new Set([...(cache?.deletedCoords ?? []), ...currentDeletedCoords])],
}
await writeCache(cachePath, newCache)

View File

@ -70,6 +70,11 @@ export const defaultEventFetcher: EventFetcher = async (relay, pubkey) => {
error: () => resolve(out),
complete: () => resolve(out),
})
// Belt-and-suspenders: falls subscribe-callback weder error noch
// complete feuert (z.B. timeout-operator wird intern verschluckt),
// schliessen wir nach timeout+1s manuell. Resolve() kommt dann nicht
// mehr durch (Promise schon settled), aber der Relay-Handle wird
// entsorgt — kein leak.
setTimeout(() => sub.unsubscribe(), 11_000)
})
}