mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
Fix persistence pending gating and add repair actions
This commit is contained in:
49
index.js
49
index.js
@@ -13229,6 +13229,53 @@ async function onRollbackLastRestore() {
|
||||
});
|
||||
return { handledToast: true, result };
|
||||
}
|
||||
|
||||
async function onRetryPendingPersist() {
|
||||
const hadPending = graphPersistenceState.pendingPersist === true;
|
||||
const result = await retryPendingGraphPersist({
|
||||
reason: "panel-manual-persist-retry",
|
||||
scheduleRetryOnFailure: false,
|
||||
});
|
||||
refreshPanelLiveState();
|
||||
|
||||
if (result?.accepted === true) {
|
||||
toastr.success("最近一批持久化已确认");
|
||||
return { handledToast: true, result };
|
||||
}
|
||||
|
||||
if (!hadPending && String(result?.reason || "") === "no-pending-persist") {
|
||||
toastr.info("当前没有待确认的持久化批次");
|
||||
return { handledToast: true, result };
|
||||
}
|
||||
|
||||
toastr.warning(
|
||||
`持久化仍未确认: ${result?.reason || result?.loadState || "未知原因"}`,
|
||||
);
|
||||
return { handledToast: true, result };
|
||||
}
|
||||
|
||||
async function onProbeGraphLoad() {
|
||||
const result = syncGraphLoadFromLiveContext({
|
||||
source: "panel-manual-graph-probe",
|
||||
force: true,
|
||||
});
|
||||
refreshPanelLiveState();
|
||||
|
||||
if (graphPersistenceState.loadState === GRAPH_LOAD_STATES.LOADING) {
|
||||
toastr.info("已重新探测当前聊天图谱,正在等待本地持久化加载");
|
||||
return { handledToast: true, result };
|
||||
}
|
||||
|
||||
if (graphPersistenceState.loadState === GRAPH_LOAD_STATES.BLOCKED) {
|
||||
toastr.warning(
|
||||
`当前图谱仍处于保护模式: ${graphPersistenceState.reason || "metadata not ready"}`,
|
||||
);
|
||||
return { handledToast: true, result };
|
||||
}
|
||||
|
||||
toastr.success("已重新探测当前聊天图谱");
|
||||
return { handledToast: true, result };
|
||||
}
|
||||
(async function init() {
|
||||
await loadServerSettings();
|
||||
syncGraphPersistenceDebugState();
|
||||
@@ -13248,6 +13295,8 @@ async function onRollbackLastRestore() {
|
||||
summaryRollup: onManualSummaryRollup,
|
||||
rebuildSummaryState: onRebuildSummaryState,
|
||||
clearSummaryState: onClearSummaryState,
|
||||
retryPendingPersist: onRetryPendingPersist,
|
||||
probeGraphLoad: onProbeGraphLoad,
|
||||
export: onExportGraph,
|
||||
import: onImportGraph,
|
||||
rebuild: onRebuild,
|
||||
|
||||
@@ -85,9 +85,27 @@ function normalizePersistenceStateRecord(persistResult = null) {
|
||||
saved: persistResult?.saved === true,
|
||||
queued,
|
||||
blocked,
|
||||
attempted: true,
|
||||
};
|
||||
}
|
||||
|
||||
function hasMeaningfulPersistenceRecord(persistence = null) {
|
||||
if (!persistence || typeof persistence !== "object") return false;
|
||||
if (persistence.attempted === true) return true;
|
||||
const revision = Number(persistence?.revision || 0);
|
||||
if (Number.isFinite(revision) && revision > 0) return true;
|
||||
if (String(persistence?.storageTier || "").trim() && persistence.storageTier !== "none") {
|
||||
return true;
|
||||
}
|
||||
if (String(persistence?.saveMode || "").trim()) return true;
|
||||
if (String(persistence?.reason || "").trim()) return true;
|
||||
return (
|
||||
persistence.saved === true ||
|
||||
persistence.queued === true ||
|
||||
persistence.blocked === true
|
||||
);
|
||||
}
|
||||
|
||||
function cloneSerializable(value, fallback = null) {
|
||||
try {
|
||||
return JSON.parse(JSON.stringify(value));
|
||||
@@ -346,13 +364,15 @@ function getPendingPersistenceGateInfo(runtime) {
|
||||
const persistence = batchStatus?.persistence || null;
|
||||
const pendingPersist = runtime?.getGraphPersistenceState?.()?.pendingPersist === true;
|
||||
const accepted = isPersistenceRevisionAccepted(runtime, persistence);
|
||||
if (!pendingPersist && (!persistence || accepted)) {
|
||||
const attempted = hasMeaningfulPersistenceRecord(persistence);
|
||||
if (!pendingPersist && (!attempted || accepted)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
pendingPersist,
|
||||
accepted,
|
||||
attempted,
|
||||
outcome: String(persistence?.outcome || ""),
|
||||
reason: String(persistence?.reason || ""),
|
||||
revision: Number.isFinite(Number(persistence?.revision))
|
||||
@@ -387,7 +407,7 @@ function formatPendingPersistenceGateMessage(runtime, operationLabel = "当前
|
||||
Number.isFinite(Number(gate.revision)) && Number(gate.revision) > 0
|
||||
? ` · rev ${Number(gate.revision)}`
|
||||
: "";
|
||||
return `${operationLabel}已暂停:上一批持久化尚未确认,请优先重试持久化或触发恢复${revision}${reason}`;
|
||||
return `${operationLabel}已暂停:上一批持久化尚未确认,请先使用“重试持久化”或“重新探测图谱”${revision}${reason}`;
|
||||
}
|
||||
|
||||
export function resolveAutoExtractionPlanController(
|
||||
@@ -571,6 +591,15 @@ export async function executeExtractionBatchController(
|
||||
"failed",
|
||||
result?.error || "提取阶段未返回有效操作",
|
||||
);
|
||||
runtime.setBatchStageOutcome(
|
||||
batchStatus,
|
||||
"finalize",
|
||||
"failed",
|
||||
"提取阶段失败,未进入持久化",
|
||||
);
|
||||
batchStatus.persistence = null;
|
||||
batchStatus.historyAdvanceAllowed = false;
|
||||
batchStatus.historyAdvanced = false;
|
||||
runtime.finalizeBatchStatus(batchStatus, runtime.getExtractionCount());
|
||||
runtime.getCurrentGraph().historyState.lastBatchStatus = batchStatus;
|
||||
return {
|
||||
@@ -852,7 +881,7 @@ export async function onManualExtractController(runtime, options = {}) {
|
||||
syncRuntime: true,
|
||||
},
|
||||
);
|
||||
runtime.toastr.warning("上一批持久化尚未确认,请先重试持久化或执行恢复");
|
||||
runtime.toastr.warning("上一批持久化尚未确认,请先点“重试持久化”或“重新探测图谱”");
|
||||
return;
|
||||
}
|
||||
if (!(await runtime.recoverHistoryIfNeeded("manual-extract"))) return;
|
||||
|
||||
@@ -137,7 +137,7 @@ export function normalizeGraphRuntimeState(graph, chatId = "") {
|
||||
!Array.isArray(historyState.lastBatchStatus.persistence)
|
||||
? {
|
||||
outcome: String(
|
||||
historyState.lastBatchStatus.persistence.outcome || "queued",
|
||||
historyState.lastBatchStatus.persistence.outcome || "failed",
|
||||
),
|
||||
accepted:
|
||||
historyState.lastBatchStatus.persistence.accepted === true,
|
||||
@@ -161,18 +161,32 @@ export function normalizeGraphRuntimeState(graph, chatId = "") {
|
||||
historyState.lastBatchStatus.persistence.queued === true,
|
||||
blocked:
|
||||
historyState.lastBatchStatus.persistence.blocked === true,
|
||||
attempted:
|
||||
historyState.lastBatchStatus.persistence.attempted === true ||
|
||||
Number(historyState.lastBatchStatus.persistence.revision) > 0 ||
|
||||
Boolean(
|
||||
String(
|
||||
historyState.lastBatchStatus.persistence.storageTier || "",
|
||||
).trim() &&
|
||||
String(
|
||||
historyState.lastBatchStatus.persistence.storageTier || "",
|
||||
) !== "none",
|
||||
) ||
|
||||
Boolean(
|
||||
String(
|
||||
historyState.lastBatchStatus.persistence.saveMode || "",
|
||||
).trim(),
|
||||
) ||
|
||||
Boolean(
|
||||
String(
|
||||
historyState.lastBatchStatus.persistence.reason || "",
|
||||
).trim(),
|
||||
) ||
|
||||
historyState.lastBatchStatus.persistence.saved === true ||
|
||||
historyState.lastBatchStatus.persistence.queued === true ||
|
||||
historyState.lastBatchStatus.persistence.blocked === true,
|
||||
}
|
||||
: {
|
||||
outcome: "queued",
|
||||
accepted: false,
|
||||
storageTier: "none",
|
||||
reason: "",
|
||||
revision: 0,
|
||||
saveMode: "",
|
||||
saved: false,
|
||||
queued: false,
|
||||
blocked: false,
|
||||
},
|
||||
: null,
|
||||
};
|
||||
}
|
||||
if (typeof historyState.lastExtractedRegion !== "string") {
|
||||
|
||||
@@ -182,4 +182,34 @@ function createRuntime(persistResult) {
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
const runtime = createRuntime({
|
||||
saved: false,
|
||||
queued: false,
|
||||
blocked: false,
|
||||
accepted: false,
|
||||
reason: "should-not-run",
|
||||
revision: 0,
|
||||
saveMode: "",
|
||||
storageTier: "none",
|
||||
});
|
||||
runtime.extractMemories = async () => ({
|
||||
success: false,
|
||||
error: "提取 LLM 未返回有效操作",
|
||||
processedRange: [4, 4],
|
||||
});
|
||||
const result = await executeExtractionBatchController(runtime, {
|
||||
chat: [{ is_user: false, mes: "测试" }],
|
||||
startIdx: 5,
|
||||
endIdx: 5,
|
||||
settings: {},
|
||||
});
|
||||
|
||||
assert.equal(result.success, false);
|
||||
assert.equal(result.batchStatus.completed, false);
|
||||
assert.equal(result.batchStatus.stages.core.outcome, "failed");
|
||||
assert.equal(result.batchStatus.stages.finalize.outcome, "failed");
|
||||
assert.equal(runtime.graph.historyState.lastBatchStatus.persistence, null);
|
||||
}
|
||||
|
||||
console.log("extraction-persistence-gating tests passed");
|
||||
|
||||
@@ -329,6 +329,131 @@ async function testManualExtractIgnoresSupersededPendingPersistence() {
|
||||
assert.notEqual(context.lastExtractionStatus.text, "等待持久化确认");
|
||||
}
|
||||
|
||||
async function testManualExtractIgnoresFailedBatchWithoutPersistenceAttempt() {
|
||||
let executeExtractionBatchCalls = 0;
|
||||
const chat = [{ is_user: true, mes: "u" }, { is_user: false, mes: "a" }];
|
||||
const context = {
|
||||
...createBaseStatusContext(),
|
||||
isExtracting: false,
|
||||
graphPersistenceState: {
|
||||
pendingPersist: false,
|
||||
lastAcceptedRevision: 0,
|
||||
},
|
||||
currentGraph: {
|
||||
historyState: {
|
||||
lastBatchStatus: {
|
||||
outcome: "failed",
|
||||
processedRange: [1, 1],
|
||||
persistence: {
|
||||
outcome: "queued",
|
||||
accepted: false,
|
||||
revision: 0,
|
||||
reason: "",
|
||||
storageTier: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
getCurrentChatId() {
|
||||
return "chat-mobile";
|
||||
},
|
||||
getCurrentGraph() {
|
||||
return context.currentGraph;
|
||||
},
|
||||
getIsExtracting() {
|
||||
return context.isExtracting;
|
||||
},
|
||||
getGraphPersistenceState() {
|
||||
return {
|
||||
pendingPersist: false,
|
||||
lastAcceptedRevision: 0,
|
||||
};
|
||||
},
|
||||
ensureGraphMutationReady() {
|
||||
return true;
|
||||
},
|
||||
async recoverHistoryIfNeeded() {
|
||||
return true;
|
||||
},
|
||||
normalizeGraphRuntimeState(graph) {
|
||||
return graph;
|
||||
},
|
||||
setCurrentGraph(graph) {
|
||||
context.currentGraph = graph;
|
||||
},
|
||||
createEmptyGraph() {
|
||||
return {};
|
||||
},
|
||||
getContext() {
|
||||
return { chat };
|
||||
},
|
||||
getAssistantTurns() {
|
||||
return [1];
|
||||
},
|
||||
getLastProcessedAssistantFloor() {
|
||||
return 0;
|
||||
},
|
||||
clampInt(value, fallback) {
|
||||
return Number.isFinite(Number(value)) ? Number(value) : fallback;
|
||||
},
|
||||
getSettings() {
|
||||
return { extractEvery: 1 };
|
||||
},
|
||||
beginStageAbortController() {
|
||||
return { signal: {} };
|
||||
},
|
||||
async executeExtractionBatch() {
|
||||
executeExtractionBatchCalls += 1;
|
||||
return {
|
||||
success: true,
|
||||
result: {
|
||||
newNodes: 0,
|
||||
updatedNodes: 0,
|
||||
newEdges: 0,
|
||||
},
|
||||
effects: {},
|
||||
batchStatus: {
|
||||
persistence: {
|
||||
accepted: true,
|
||||
revision: 1,
|
||||
attempted: true,
|
||||
},
|
||||
},
|
||||
historyAdvanceAllowed: true,
|
||||
};
|
||||
},
|
||||
async retryPendingGraphPersist() {
|
||||
return {
|
||||
accepted: false,
|
||||
reason: "no-pending-persist",
|
||||
};
|
||||
},
|
||||
isAbortError() {
|
||||
return false;
|
||||
},
|
||||
onManualExtractController,
|
||||
finishStageAbortController() {},
|
||||
setIsExtracting(value) {
|
||||
context.isExtracting = value;
|
||||
},
|
||||
setLastExtractionStatus(text, meta, level) {
|
||||
context.lastExtractionStatus = { text, meta, level };
|
||||
context.runtimeStatus = { text, meta, level };
|
||||
},
|
||||
toastr: {
|
||||
info() {},
|
||||
success() {},
|
||||
warning() {},
|
||||
error() {},
|
||||
},
|
||||
result: null,
|
||||
};
|
||||
|
||||
await onManualExtractController(context, { drainAll: false });
|
||||
assert.equal(executeExtractionBatchCalls, 1);
|
||||
assert.notEqual(context.lastExtractionStatus.text, "等待持久化确认");
|
||||
}
|
||||
|
||||
async function testManualRebuildSetsTerminalRuntimeStatus() {
|
||||
const chat = [{ is_user: true, mes: "u" }, { is_user: false, mes: "a" }];
|
||||
const context = {
|
||||
@@ -405,6 +530,7 @@ testIndexDefinesLastProcessedAssistantFloorHelper();
|
||||
await testVectorSyncTerminalStateUpdatesRuntime();
|
||||
await testManualExtractNoBatchesDoesNotStayRunning();
|
||||
await testManualExtractIgnoresSupersededPendingPersistence();
|
||||
await testManualExtractIgnoresFailedBatchWithoutPersistenceAttempt();
|
||||
await testManualRebuildSetsTerminalRuntimeStatus();
|
||||
|
||||
console.log("mobile-status-regressions tests passed");
|
||||
|
||||
@@ -204,6 +204,20 @@
|
||||
<label>最近持久化</label>
|
||||
<div class="bme-recent-meta" id="bme-status-last-persist">—</div>
|
||||
</div>
|
||||
<div class="bme-config-row" id="bme-persist-repair-row" hidden>
|
||||
<label>持久化修复</label>
|
||||
<div class="bme-task-inline-actions">
|
||||
<button class="bme-config-secondary-btn" id="bme-act-retry-persist" type="button">
|
||||
<i class="fa-solid fa-arrows-rotate"></i>
|
||||
<span>重试持久化</span>
|
||||
</button>
|
||||
<button class="bme-config-secondary-btn" id="bme-act-probe-graph-load" type="button">
|
||||
<i class="fa-solid fa-satellite-dish"></i>
|
||||
<span>重新探测图谱</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-config-help" id="bme-persist-repair-help" hidden></div>
|
||||
<div class="bme-config-row">
|
||||
<label>最近向量</label>
|
||||
<div class="bme-recent-meta" id="bme-status-last-vector">—</div>
|
||||
|
||||
80
ui/panel.js
80
ui/panel.js
@@ -1832,6 +1832,7 @@ function _refreshDashboard() {
|
||||
_setText("bme-status-last-persist", "等待聊天图谱元数据加载");
|
||||
_setText("bme-status-last-vector", "等待聊天图谱元数据加载");
|
||||
_setText("bme-status-last-recall", "等待聊天图谱元数据加载");
|
||||
_refreshPersistenceRepairUi(loadInfo, null);
|
||||
_renderStatefulListPlaceholder(
|
||||
document.getElementById("bme-recent-extract"),
|
||||
_getGraphLoadLabel(loadInfo.loadState),
|
||||
@@ -1908,6 +1909,7 @@ function _refreshDashboard() {
|
||||
"bme-status-last-persist",
|
||||
_formatDashboardPersistMeta(loadInfo, lastBatchStatus),
|
||||
);
|
||||
_refreshPersistenceRepairUi(loadInfo, lastBatchStatus);
|
||||
_setText("bme-status-last-vector", vectorStatus.meta || "尚未执行向量任务");
|
||||
_setText("bme-status-last-recall", recallStatus.meta || "尚未执行召回");
|
||||
|
||||
@@ -3739,6 +3741,8 @@ function _bindActions() {
|
||||
"bme-act-sleep": "sleep",
|
||||
"bme-act-synopsis": "synopsis",
|
||||
"bme-act-summary-rollup": "summaryRollup",
|
||||
"bme-act-retry-persist": "retryPendingPersist",
|
||||
"bme-act-probe-graph-load": "probeGraphLoad",
|
||||
"bme-act-export": "export",
|
||||
"bme-act-import": "import",
|
||||
"bme-act-rebuild": "rebuild",
|
||||
@@ -3763,6 +3767,8 @@ function _bindActions() {
|
||||
sleep: "执行遗忘",
|
||||
synopsis: "生成小总结",
|
||||
summaryRollup: "执行总结折叠",
|
||||
retryPendingPersist: "重试持久化",
|
||||
probeGraphLoad: "重新探测图谱",
|
||||
rebuildSummaryState: "重建总结状态",
|
||||
export: "导出图谱",
|
||||
import: "导入图谱",
|
||||
@@ -9504,6 +9510,8 @@ function _formatPersistenceOutcomeLabel(outcome = "") {
|
||||
return "已保存";
|
||||
case "fallback":
|
||||
return "兜底已保存";
|
||||
case "not-attempted":
|
||||
return "未尝试";
|
||||
case "queued":
|
||||
return "已排队";
|
||||
case "blocked":
|
||||
@@ -9515,8 +9523,26 @@ function _formatPersistenceOutcomeLabel(outcome = "") {
|
||||
}
|
||||
}
|
||||
|
||||
function _hasMeaningfulPersistenceRecord(persistence = null) {
|
||||
if (!persistence || typeof persistence !== "object") return false;
|
||||
if (persistence.attempted === true) return true;
|
||||
const revision = Number(persistence?.revision || 0);
|
||||
if (Number.isFinite(revision) && revision > 0) return true;
|
||||
if (String(persistence?.storageTier || "").trim() && persistence.storageTier !== "none") {
|
||||
return true;
|
||||
}
|
||||
if (String(persistence?.saveMode || "").trim()) return true;
|
||||
if (String(persistence?.reason || "").trim()) return true;
|
||||
return (
|
||||
persistence.saved === true ||
|
||||
persistence.queued === true ||
|
||||
persistence.blocked === true
|
||||
);
|
||||
}
|
||||
|
||||
function _isPersistenceRevisionAccepted(persistence = null, loadInfo = {}) {
|
||||
if (!persistence || persistence.accepted === true) return true;
|
||||
if (!_hasMeaningfulPersistenceRecord(persistence)) return true;
|
||||
if (loadInfo?.pendingPersist === true) return false;
|
||||
const persistenceRevision = Number(persistence?.revision || 0);
|
||||
if (!Number.isFinite(persistenceRevision) || persistenceRevision <= 0) {
|
||||
@@ -9535,7 +9561,7 @@ function _isPersistenceRevisionAccepted(persistence = null, loadInfo = {}) {
|
||||
|
||||
function _formatDashboardPersistMeta(loadInfo = {}, batchStatus = null) {
|
||||
const persistence = batchStatus?.persistence || null;
|
||||
if (persistence) {
|
||||
if (_hasMeaningfulPersistenceRecord(persistence)) {
|
||||
const accepted = _isPersistenceRevisionAccepted(persistence, loadInfo);
|
||||
const parts = [
|
||||
accepted ? "已确认" : _formatPersistenceOutcomeLabel(persistence.outcome),
|
||||
@@ -9562,6 +9588,14 @@ function _formatDashboardPersistMeta(loadInfo = {}, batchStatus = null) {
|
||||
.join(" · ");
|
||||
}
|
||||
|
||||
if (loadInfo?.persistMismatchReason) {
|
||||
return `一致性异常 · ${String(loadInfo.persistMismatchReason || "")}`;
|
||||
}
|
||||
|
||||
if (String(batchStatus?.outcome || "") === "failed") {
|
||||
return "本批未进入持久化";
|
||||
}
|
||||
|
||||
return "尚未执行持久化";
|
||||
}
|
||||
|
||||
@@ -9578,7 +9612,7 @@ function _formatDashboardHistoryMeta(graph = null, loadInfo = {}, batchStatus =
|
||||
? Number(processedRange[1])
|
||||
: null;
|
||||
|
||||
if (persistence && !accepted && pendingFloor != null) {
|
||||
if (_hasMeaningfulPersistenceRecord(persistence) && !accepted && pendingFloor != null) {
|
||||
return `持久化待确认:本地已抽取到楼层 ${pendingFloor},已确认楼层 ${lastConfirmedFloor}`;
|
||||
}
|
||||
|
||||
@@ -9586,6 +9620,10 @@ function _formatDashboardHistoryMeta(graph = null, loadInfo = {}, batchStatus =
|
||||
return `持久化一致性异常:${String(loadInfo.persistMismatchReason || "")} · 已确认楼层 ${lastConfirmedFloor}`;
|
||||
}
|
||||
|
||||
if (String(batchStatus?.outcome || "") === "failed") {
|
||||
return `最近一批提取失败,已确认处理到楼层 ${lastConfirmedFloor}`;
|
||||
}
|
||||
|
||||
const dirtyFrom = graph?.historyState?.historyDirtyFrom;
|
||||
if (Number.isFinite(dirtyFrom)) {
|
||||
return `脏区从楼层 ${dirtyFrom} 开始,已确认处理到楼层 ${lastConfirmedFloor}`;
|
||||
@@ -9612,6 +9650,44 @@ function _getGraphLoadLabel(loadState = "") {
|
||||
}
|
||||
}
|
||||
|
||||
function _refreshPersistenceRepairUi(
|
||||
loadInfo = _getGraphPersistenceSnapshot(),
|
||||
batchStatus = _getLatestBatchStatusSnapshot(),
|
||||
) {
|
||||
const row = document.getElementById("bme-persist-repair-row");
|
||||
const help = document.getElementById("bme-persist-repair-help");
|
||||
if (!row || !help) return;
|
||||
|
||||
const persistence = batchStatus?.persistence || null;
|
||||
const accepted = _isPersistenceRevisionAccepted(persistence, loadInfo);
|
||||
const shouldShow =
|
||||
loadInfo?.pendingPersist === true ||
|
||||
Boolean(loadInfo?.persistMismatchReason) ||
|
||||
(_hasMeaningfulPersistenceRecord(persistence) && !accepted);
|
||||
|
||||
row.hidden = !shouldShow;
|
||||
help.hidden = !shouldShow;
|
||||
if (!shouldShow) {
|
||||
help.textContent = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (loadInfo?.pendingPersist === true) {
|
||||
help.textContent =
|
||||
"最近一批提取已经完成,但正式写回还没确认。先试“重试持久化”,如果状态没变化,再试“重新探测图谱”。";
|
||||
return;
|
||||
}
|
||||
|
||||
if (loadInfo?.persistMismatchReason) {
|
||||
help.textContent =
|
||||
`检测到持久化一致性异常:${String(loadInfo.persistMismatchReason || "")}。建议先重新探测图谱;如果仍异常,再执行重建或恢复。`;
|
||||
return;
|
||||
}
|
||||
|
||||
help.textContent =
|
||||
"最近一批持久化没有被接受。可以先重试持久化;如果宿主延迟加载了本地存储,再重新探测图谱。";
|
||||
}
|
||||
|
||||
function _canRenderGraphData(loadInfo = _getGraphPersistenceSnapshot()) {
|
||||
return (
|
||||
loadInfo.dbReady === true ||
|
||||
|
||||
@@ -142,13 +142,7 @@ export function createBatchStatusSkeleton({
|
||||
outcome: "success",
|
||||
consistency: "strong",
|
||||
completed: false,
|
||||
persistence: {
|
||||
outcome: "queued",
|
||||
accepted: false,
|
||||
storageTier: "none",
|
||||
reason: "",
|
||||
revision: 0,
|
||||
},
|
||||
persistence: null,
|
||||
historyAdvanceAllowed: false,
|
||||
warnings: [],
|
||||
errors: [],
|
||||
|
||||
Reference in New Issue
Block a user