diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 8f839bb..9ea5867 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -21,7 +21,7 @@ on: # branch-protection required check (cla/cla-assistant.yml) reports against. permissions: contents: read - pull-requests: read + pull-requests: write issues: write statuses: write diff --git a/app/[locale]/play/page.tsx b/app/[locale]/play/page.tsx index 9f047ab..0604cd8 100644 --- a/app/[locale]/play/page.tsx +++ b/app/[locale]/play/page.tsx @@ -902,10 +902,11 @@ function PlayInner() { lastSavedFingerprintRef.current = ""; } }) - // Defensive: saveStory is contracted never to throw, but if a future edit - // to this callback ever does, an unhandled rejection here would poison the - // chain and freeze ALL subsequent saves. Swallow to keep the chain alive. - .catch(() => {}); + .catch(() => { + if (lastSavedFingerprintRef.current === fingerprint) { + lastSavedFingerprintRef.current = ""; + } + }); }, [session]); useEffect(() => { currentSceneRef.current = currentScene; diff --git a/lib/persistence/types.ts b/lib/persistence/types.ts index 240d945..010ea4e 100644 --- a/lib/persistence/types.ts +++ b/lib/persistence/types.ts @@ -19,12 +19,13 @@ export const STORY_SCHEMA_VERSION = 1; * crosses a storage/serialization boundary and could arrive as a non-number, * guarding against the historical `t.getTime is not a function` white-screen. */ export function coerceEpoch(value: unknown, fallback: number): number { + if (value == null) return fallback; // Number.isFinite (not just !isNaN) so ±Infinity also falls through to the // fallback — new Date(Infinity).getTime() is NaN, not a usable epoch. if (typeof value === "number" && Number.isFinite(value)) return value; const d = value instanceof Date ? value : new Date(value as string | number); const t = d.getTime(); - return Number.isNaN(t) ? fallback : t; + return Number.isFinite(t) ? t : fallback; } /** local-first sync state of a record.