An erased device stays erased: the lease dies with it, and construction leaves no trace - #117
Merged
Merged
Conversation
…on leaves no trace Issue #112's investigation, in three findings. First, the lease heartbeat's stop() handle was deliberately dropped on a lifetime argument (lease = lock = global) that holds for every ending except erasure, where the DEVICE dies before the global: destroy cleared the checkpoint debounce and the sync timers but the 5s touchLease kept firing, and ns.put on a deleted database is IndexedDB open-on-missing — the deleted database is back. The handle is kept and destroy stops it first (devstore row 65b: resurrected in 1200ms unstopped, absent stopped). Second — the negative control for the timer theory did NOT go red, because serve() closes the global one task after destroy replies, so the field flake needed another door. It found three: bootSeq's module-evaluation write meant MERELY CONSTRUCTING a SharedWorker named for an erased device recreated its database (no client call, no timer — the construction IS the resurrection); status(), reachable on a raw port before attach, recreated it with a read (indexedDB.open creates whatever the transaction mode); attach's takeLock started a lease whose first act is a put. All three now gate on the INDEX ROW — the existence oracle anchorIsLive already states in as many words — with creation order verified row-first on every constructing path, so a legitimate first boot still counts 1 (rows 11/12/14/15/56 green). Row 66's negative control: unguarded, the database is back after step ONE. Third, the harness itself committed the offence: hc-forget's page-side delete left live hosts heartbeating at deleted databases (~31 stray databases per matrix run). cleanup() now tears down through the worker (row 66b: 7s of nothing, absent; unguarded control present). Plus one non-timer hole from the audit: onTokenRefreshed's fire-and-forget writeOauth re-checks destroyed at land time, not call time. The field trigger for the CI flake remains unproven — this closes the CLASS (no constructor, RPC or teardown path can recreate an erased namespace) rather than naming the one door CI caught. If solo-erase flakes again, the remaining suspect recreates the index row itself. Gates: devstore 75 rows green (65, 65b, 66, 66b new); solo-erase, solo-persistence, solo-ephemeral x2 green; demo deno check clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #112 (the class; the CI trigger's identity is discussed honestly in the commit).
Three doors closed on one oracle:
startLease's stop handle was deliberately dropped on a lifetime argument that breaks exactly atdestroy: the 5stouchLeasekept firing afterdestroyNamespace, and IndexedDB open-on-missing brought the deleted database back. Row 65b pins it (resurrected in 1200 ms unstopped; absent stopped).bootSeq's module-evaluation write meantnew SharedWorker(url, {name: pm-device-<erased>})alone recreated the database;status()(reachable pre-attach) recreated it with a read;attach's lease start was a third. All three now gate on the index row — the existence oracleanchorIsLivealready documents — with creation order verified row-first on every constructing path (boot-counter rows stay green and meaningful). Row 66's negative control: unguarded, the database is back after construction alone,bootSeq=1, no client call, no timer.hc-forget's page-side delete of live-hosted devices strewed ~31 resurrected databases per matrix run; cleanup now tears down through the worker (row 66b).Plus
onTokenRefreshed's in-flight write now re-checksdestroyedat land time.Gates: devstore 75 rows green; solo-erase/persistence/ephemeral ×2 green; deno check clean. Full e2e rides CI.
Automerge is armed.