HTML5: token durability inside the IDBFS flush window #20

Closed
opened 2026-08-19 14:58:40 +00:00 by yuris · 0 comments
Owner

#17 proved identity survives a page reload on HTML5. It did not prove the token is durable immediately after sys.save returns, and there is a specific reason to expect it is not.

The gap

On HTML5, sys.save writes to Emscripten's IDBFS: an in-memory filesystem that flushes to IndexedDB asynchronously. The bytes are in memory when sys.save returns; they reach IndexedDB some time later.

The harness in #17 reloads roughly 15 seconds after the save, so it demonstrates the flush happens — not that it is prompt. The untested window is a player who closes the tab, or navigates away, in the second or so between first connect and the flush. They come back as a brand-new identity, having lost whatever the game associated with the old one.

The failure mode is the nasty one this SDK has hit twice before (#8's dropped Authorization header, #17's negative control): nothing errors. A fresh anonymous identity connects perfectly happily, so the player is silently someone else and no log line anywhere says why.

Work

  • Determine whether Defold's sys.save on HTML5 already calls FS.syncfs, or whether it only writes to the MEMFS layer. This decides whether there is anything to fix at all — check the engine's sys.save implementation for the HTML5 target rather than inferring from behaviour
  • If it does not sync: flush explicitly after saving the token, via html5.run("FS.syncfs(false, function(){})") behind M.is_html5(), in stdb.sys_storage's save
  • Alternatively store the token in localStorage on HTML5, which is synchronous and needs no flush — but changes where the token lives, so it must be a deliberate decision rather than a side effect
  • Extend dev/tools/html5-conformance.mjs to reload immediately on SMOKE: identity, rather than waiting for the full phase sequence, so the harness actually covers the narrow window

Acceptance

The harness reloads within a few hundred milliseconds of the identity being saved and still recovers the same identity. If Defold already syncs and this turns out to be a non-issue, close it with the engine source that proves so — the README currently warns about a caveat, and an unnecessary warning should be deleted rather than left to spook people.

Priority

Low. It needs a real player closing a tab inside a one-second window on their very first connect, and the cost is one lost anonymous identity, not corruption. Worth doing before anyone ships a game where identity carries progress; not worth blocking anything on.

Documented meanwhile in the README's identity-persistence section, which states the limit instead of claiming durability nobody measured.

#17 proved identity survives a page reload on HTML5. It did not prove the token is durable *immediately* after `sys.save` returns, and there is a specific reason to expect it is not. ## The gap On HTML5, `sys.save` writes to Emscripten's IDBFS: an in-memory filesystem that flushes to IndexedDB **asynchronously**. The bytes are in memory when `sys.save` returns; they reach IndexedDB some time later. The harness in #17 reloads roughly 15 seconds after the save, so it demonstrates the flush happens — not that it is prompt. The untested window is a player who closes the tab, or navigates away, in the second or so between first connect and the flush. They come back as a brand-new identity, having lost whatever the game associated with the old one. The failure mode is the nasty one this SDK has hit twice before (#8's dropped `Authorization` header, #17's negative control): **nothing errors**. A fresh anonymous identity connects perfectly happily, so the player is silently someone else and no log line anywhere says why. ## Work - [ ] Determine whether Defold's `sys.save` on HTML5 already calls `FS.syncfs`, or whether it only writes to the MEMFS layer. This decides whether there is anything to fix at all — check the engine's `sys.save` implementation for the HTML5 target rather than inferring from behaviour - [ ] If it does not sync: flush explicitly after saving the token, via `html5.run("FS.syncfs(false, function(){})")` behind `M.is_html5()`, in `stdb.sys_storage`'s `save` - [ ] Alternatively store the token in `localStorage` on HTML5, which is synchronous and needs no flush — but changes where the token lives, so it must be a deliberate decision rather than a side effect - [ ] Extend `dev/tools/html5-conformance.mjs` to reload immediately on `SMOKE: identity`, rather than waiting for the full phase sequence, so the harness actually covers the narrow window ## Acceptance The harness reloads within a few hundred milliseconds of the identity being saved and still recovers the same identity. If Defold already syncs and this turns out to be a non-issue, close it with the engine source that proves so — the README currently warns about a caveat, and an unnecessary warning should be deleted rather than left to spook people. ## Priority Low. It needs a real player closing a tab inside a one-second window on their very first connect, and the cost is one lost anonymous identity, not corruption. Worth doing before anyone ships a game where identity carries progress; not worth blocking anything on. Documented meanwhile in the README's identity-persistence section, which states the limit instead of claiming durability nobody measured.
yuris closed this issue 2026-08-20 15:03:21 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/spacetimedb-defold#20
No description provided.