fix: harden mobile local store recovery flow

This commit is contained in:
Youzini-afk
2026-04-15 12:43:13 +08:00
parent 4846f1587b
commit 05d3fe3fbd
3 changed files with 515 additions and 12 deletions

View File

@@ -883,7 +883,9 @@ async function createGraphPersistenceHarness({
buildSnapshotFromGraph,
evaluatePersistNativeDeltaGate,
buildBmeDbName,
BME_GRAPH_LOCAL_STORAGE_MODE_AUTO: "auto",
BME_GRAPH_LOCAL_STORAGE_MODE_INDEXEDDB: "indexeddb",
BME_GRAPH_LOCAL_STORAGE_MODE_OPFS_PRIMARY: "opfs-primary",
BME_GRAPH_LOCAL_STORAGE_MODE_OPFS_SHADOW: "opfs-shadow",
detectOpfsSupport: async () => ({
available: false,
@@ -1089,6 +1091,7 @@ result = {
writeGraphShadowSnapshot,
removeGraphShadowSnapshot,
maybeCaptureGraphShadowSnapshot,
buildPanelOpenLocalStoreRefreshPlan,
loadGraphFromChat,
loadGraphFromIndexedDb,
saveGraphToChat,
@@ -1129,6 +1132,13 @@ result = {
getGraphPersistenceState() {
return graphPersistenceState;
},
setLocalStoreCapabilitySnapshot(patch = {}) {
bmeLocalStoreCapabilitySnapshot = {
...bmeLocalStoreCapabilitySnapshot,
...(patch || {}),
};
return bmeLocalStoreCapabilitySnapshot;
},
setChatContext(nextContext) {
globalThis.__chatContext = nextContext;
return globalThis.__chatContext;
@@ -1848,6 +1858,84 @@ result = {
assert.equal(result.reason, "no-sync-needed");
}
{
const harness = await createGraphPersistenceHarness({
chatId: "chat-panel-open-healthy",
globalChatId: "chat-panel-open-healthy",
chatMetadata: {
integrity: "chat-panel-open-healthy-integrity",
},
});
harness.runtimeContext.extension_settings[MODULE_NAME] = {
graphLocalStorageMode: "auto",
};
harness.api.setLocalStoreCapabilitySnapshot({
checked: true,
opfsAvailable: true,
reason: "ok",
});
harness.api.setGraphPersistenceState({
loadState: "loaded",
chatId: "chat-panel-open-healthy",
reason: "healthy",
dbReady: true,
writesBlocked: false,
pendingPersist: false,
indexedDbLastError: "",
resolvedLocalStore: "opfs:opfs-primary",
storagePrimary: "opfs",
storageMode: "opfs-primary",
});
const plan = harness.api.buildPanelOpenLocalStoreRefreshPlan();
assert.equal(
plan.shouldRefresh,
false,
"健康态的面板打开不应每次都强刷本地引擎绑定",
);
assert.equal(Array.isArray(plan.reasons), true);
assert.equal(plan.reasons.length, 0);
}
{
const harness = await createGraphPersistenceHarness({
chatId: "chat-panel-open-pending",
globalChatId: "chat-panel-open-pending",
chatMetadata: {
integrity: "chat-panel-open-pending-integrity",
},
});
harness.runtimeContext.extension_settings[MODULE_NAME] = {
graphLocalStorageMode: "auto",
};
harness.api.setLocalStoreCapabilitySnapshot({
checked: true,
opfsAvailable: true,
reason: "ok",
});
harness.api.setGraphPersistenceState({
loadState: "blocked",
chatId: "chat-panel-open-pending",
reason: "persist-queued",
dbReady: false,
writesBlocked: true,
pendingPersist: true,
indexedDbLastError: "opfs-write-failed",
resolvedLocalStore: "indexeddb:indexeddb",
storagePrimary: "indexeddb",
storageMode: "indexeddb",
});
const plan = harness.api.buildPanelOpenLocalStoreRefreshPlan();
assert.equal(plan.shouldRefresh, true);
assert.equal(plan.forceCapabilityRefresh, true);
assert.equal(plan.reopenCurrentDb, true);
assert.equal(plan.reasons.includes("pending-persist"), true);
assert.equal(plan.reasons.includes("resolved-store-mismatch"), true);
}
{
const harness = await createGraphPersistenceHarness({
chatId: "chat-luker-panel-open",