fix(migration): 7 critical fixes for Authority migration safety and data integrity

- Fix #2: _executeStatements fallback now batches transactions (150/batch)
  and reorders upsert-before-delete to prevent data loss on payload overflow
- Fix #3: Read/write migratedToAuthority marker in chat_metadata to prevent
  re-overwriting from legacy sources after Authority migration
- Fix #1: Add OPFS → Authority migration channel (exportOpfsSnapshotForChat,
  maybeImportLegacyOpfsSnapshotToLocalStore) inserted before IndexedDB in
  migration chain
- Fix #4: Mark runtimeVectorIndexState dirty with triviumRebuildRequired
  and trigger submitAuthorityVectorRebuildJob after all three migration paths
- Fix #5: Dual-save safety snapshots to Authority blob; rollback can now
  recover from blob when local IndexedDB snapshot is unavailable
- Fix #6: Add isEmptyCheck detail and console.warn for near-empty stores
  to help diagnose residual vs real data in store-not-empty skips
- Fix #7: Add overflow warning logs and sessionStorage persistence for
  Authority offline queue max-items/max-bytes exceeded events
This commit is contained in:
Youzini-afk
2026-04-29 01:15:37 +08:00
parent 79fbd369ba
commit d702e267d3
5 changed files with 574 additions and 11 deletions

View File

@@ -144,6 +144,18 @@ export function enqueueAuthorityOfflineMutation(state = {}, mutation = {}, setti
const nextItems = [...current.offlineQueue, item];
const nextSummary = summarizeQueue(nextItems);
if (policy.maxItems > 0 && nextSummary.items > policy.maxItems) {
console.warn(
`[ST-BME] Authority 离线队列溢出 (maxItems=${policy.maxItems}),新突变被丢弃。` +
"恢复连接后请手动同步图谱。",
{ rejectedMutation: item },
);
try {
sessionStorage.setItem("st_bme:authority:overflow:global", JSON.stringify({
overflowAt: new Date(nowMs).toISOString(),
reason: "max-items-exceeded",
lostItemCount: 1,
}));
} catch {}
const nextState = createAuthorityBrowserState({
...current,
offlineQueueOverflow: true,
@@ -153,6 +165,18 @@ export function enqueueAuthorityOfflineMutation(state = {}, mutation = {}, setti
return { accepted: false, reason: "max-items-exceeded", state: nextState };
}
if (policy.maxBytes > 0 && nextSummary.bytes > policy.maxBytes) {
console.warn(
`[ST-BME] Authority 离线队列溢出 (maxBytes=${policy.maxBytes}),新突变被丢弃。` +
"恢复连接后请手动同步图谱。",
{ rejectedMutation: item },
);
try {
sessionStorage.setItem("st_bme:authority:overflow:global", JSON.stringify({
overflowAt: new Date(nowMs).toISOString(),
reason: "max-bytes-exceeded",
lostItemCount: 1,
}));
} catch {}
const nextState = createAuthorityBrowserState({
...current,
offlineQueueOverflow: true,
@@ -176,6 +200,9 @@ export function enqueueAuthorityOfflineMutation(state = {}, mutation = {}, setti
export function clearAuthorityOfflineQueue(state = {}, settings = {}, nowMs = Date.now()) {
const current = normalizeAuthorityBrowserState(state, settings, nowMs);
try {
sessionStorage.removeItem("st_bme:authority:overflow:global");
} catch {}
return createAuthorityBrowserState({
...current,
offlineQueue: [],