mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-13 18:31:16 +08:00
feat(authority): add consistency repair actions
This commit is contained in:
97
index.js
97
index.js
@@ -2840,6 +2840,96 @@ async function restoreAuthorityCheckpointFromBlob(options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function writeAuthorityCheckpointFromCurrentGraph(options = {}) {
|
||||||
|
const settings = getSettings();
|
||||||
|
const { capability } = getAuthorityRuntimeSnapshot(settings);
|
||||||
|
const updatedAt = new Date().toISOString();
|
||||||
|
const chatId = normalizeChatIdCandidate(
|
||||||
|
options.chatId || getCurrentChatId() || graphPersistenceState.chatId || currentGraph?.chatId,
|
||||||
|
);
|
||||||
|
if (!chatId) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "missing-chat-id",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!capability.blobReady || !shouldUseAuthorityBlobCheckpoint()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "Authority Blob unavailable",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureCurrentGraphRuntimeState();
|
||||||
|
if (!currentGraph) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "Authority runtime graph unavailable",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const revision = Math.max(
|
||||||
|
1,
|
||||||
|
Number(options.revision || 0),
|
||||||
|
Number(currentGraph?.meta?.revision || 0),
|
||||||
|
Number(getGraphPersistedRevision(currentGraph) || 0),
|
||||||
|
Number(graphPersistenceState.revision || 0),
|
||||||
|
);
|
||||||
|
const integrity =
|
||||||
|
normalizeChatIdCandidate(options.integrity) ||
|
||||||
|
normalizeChatIdCandidate(getGraphPersistenceMeta(currentGraph)?.integrity) ||
|
||||||
|
getChatMetadataIntegrity(getContext()) ||
|
||||||
|
graphPersistenceState.metadataIntegrity;
|
||||||
|
const reason = String(options.reason || "manual-authority-checkpoint");
|
||||||
|
const checkpoint = buildLukerGraphCheckpointV2(currentGraph, {
|
||||||
|
revision,
|
||||||
|
chatId,
|
||||||
|
integrity,
|
||||||
|
reason,
|
||||||
|
storageTier: "authority-sql-primary",
|
||||||
|
persistedAt: updatedAt,
|
||||||
|
});
|
||||||
|
if (!checkpoint) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "Authority checkpoint payload unavailable",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const writeResult = await writeAuthorityLukerCheckpointBlob(checkpoint, {
|
||||||
|
chatId,
|
||||||
|
reason,
|
||||||
|
signal: options.signal,
|
||||||
|
});
|
||||||
|
if (!writeResult?.ok) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error:
|
||||||
|
writeResult?.error?.message ||
|
||||||
|
writeResult?.reason ||
|
||||||
|
"authority-blob-checkpoint-write-failed",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auditResult = await runAuthorityConsistencyAudit({
|
||||||
|
chatId,
|
||||||
|
collectionId:
|
||||||
|
normalizeChatIdCandidate(options.collectionId) ||
|
||||||
|
normalizeChatIdCandidate(currentGraph?.vectorIndexState?.collectionId) ||
|
||||||
|
buildVectorCollectionId(chatId),
|
||||||
|
}).catch(() => null);
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
result: {
|
||||||
|
path: writeResult.path,
|
||||||
|
revision,
|
||||||
|
checkpointRevision: Number(checkpoint.revision || revision || 0),
|
||||||
|
auditSummary: auditResult?.audit?.summary || null,
|
||||||
|
auditActions: auditResult?.audit?.actions || [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function submitAuthorityVectorRebuildJob({
|
async function submitAuthorityVectorRebuildJob({
|
||||||
config = null,
|
config = null,
|
||||||
range = null,
|
range = null,
|
||||||
@@ -21404,6 +21494,12 @@ async function onRunAuthorityConsistencyAudit() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onWriteAuthorityCheckpoint() {
|
||||||
|
return await writeAuthorityCheckpointFromCurrentGraph({
|
||||||
|
reason: "panel-authority-checkpoint-write",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function onRestoreAuthorityCheckpoint() {
|
async function onRestoreAuthorityCheckpoint() {
|
||||||
return await restoreAuthorityCheckpointFromBlob({
|
return await restoreAuthorityCheckpointFromBlob({
|
||||||
reason: "panel-authority-checkpoint-restore",
|
reason: "panel-authority-checkpoint-restore",
|
||||||
@@ -21996,6 +22092,7 @@ async function onCompactLukerSidecar() {
|
|||||||
requeueAuthorityJob: async (jobId) => await requeueAuthorityJob(jobId),
|
requeueAuthorityJob: async (jobId) => await requeueAuthorityJob(jobId),
|
||||||
refreshAuthorityJobs: onRefreshAuthorityJobs,
|
refreshAuthorityJobs: onRefreshAuthorityJobs,
|
||||||
runAuthorityConsistencyAudit: onRunAuthorityConsistencyAudit,
|
runAuthorityConsistencyAudit: onRunAuthorityConsistencyAudit,
|
||||||
|
writeAuthorityCheckpoint: onWriteAuthorityCheckpoint,
|
||||||
restoreAuthorityCheckpoint: onRestoreAuthorityCheckpoint,
|
restoreAuthorityCheckpoint: onRestoreAuthorityCheckpoint,
|
||||||
captureAuthorityPerformanceBaseline: onCaptureAuthorityPerformanceBaseline,
|
captureAuthorityPerformanceBaseline: onCaptureAuthorityPerformanceBaseline,
|
||||||
reembedDirect: onReembedDirect,
|
reembedDirect: onReembedDirect,
|
||||||
|
|||||||
@@ -145,5 +145,6 @@ assert.equal(auditDrift.summary.level, "warning");
|
|||||||
assert.ok(auditDrift.issues.some((issue) => issue.code === "sql-runtime-revision-drift"));
|
assert.ok(auditDrift.issues.some((issue) => issue.code === "sql-runtime-revision-drift"));
|
||||||
assert.ok(auditDrift.issues.some((issue) => issue.code === "vector-dirty"));
|
assert.ok(auditDrift.issues.some((issue) => issue.code === "vector-dirty"));
|
||||||
assert.ok(auditDrift.actions.includes("rebuild-authority-trivium"));
|
assert.ok(auditDrift.actions.includes("rebuild-authority-trivium"));
|
||||||
|
assert.ok(auditDrift.actions.includes("write-authority-checkpoint"));
|
||||||
|
|
||||||
console.log("authority-consistency tests passed");
|
console.log("authority-consistency tests passed");
|
||||||
|
|||||||
31
ui/panel.js
31
ui/panel.js
@@ -3248,13 +3248,27 @@ function _refreshTaskPersistence() {
|
|||||||
["诊断包时间", authorityBundleUpdatedLabel],
|
["诊断包时间", authorityBundleUpdatedLabel],
|
||||||
["诊断包原因", ps.authorityDiagnosticsBundleReason || "—"],
|
["诊断包原因", ps.authorityDiagnosticsBundleReason || "—"],
|
||||||
];
|
];
|
||||||
|
const authorityAuditActions = Array.isArray(ps.authorityConsistencyAudit?.actions)
|
||||||
|
? ps.authorityConsistencyAudit.actions.map((value) => String(value || "").trim()).filter(Boolean)
|
||||||
|
: [];
|
||||||
|
const showAuthorityCheckpointWriteAction =
|
||||||
|
authorityAuditActions.includes("write-authority-checkpoint") ||
|
||||||
|
(!ps.authorityBlobCheckpointPath && ps.authorityBlobReady);
|
||||||
|
const showAuthorityTriviumRebuildAction =
|
||||||
|
authorityAuditActions.includes("rebuild-authority-trivium");
|
||||||
const authorityActionButtons = [
|
const authorityActionButtons = [
|
||||||
typeof _actionHandlers.runAuthorityConsistencyAudit === "function"
|
typeof _actionHandlers.runAuthorityConsistencyAudit === "function"
|
||||||
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="audit">执行 Authority 审计</button>`
|
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="audit">执行 Authority 审计</button>`
|
||||||
: "",
|
: "",
|
||||||
|
showAuthorityCheckpointWriteAction && typeof _actionHandlers.writeAuthorityCheckpoint === "function"
|
||||||
|
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="checkpoint">写入当前 Checkpoint</button>`
|
||||||
|
: "",
|
||||||
typeof _actionHandlers.restoreAuthorityCheckpoint === "function"
|
typeof _actionHandlers.restoreAuthorityCheckpoint === "function"
|
||||||
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="restore">从 Checkpoint 恢复</button>`
|
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="restore">从 Checkpoint 恢复</button>`
|
||||||
: "",
|
: "",
|
||||||
|
showAuthorityTriviumRebuildAction && typeof _actionHandlers.rebuildVectorIndex === "function"
|
||||||
|
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="rebuild-trivium">重建 Authority Trivium</button>`
|
||||||
|
: "",
|
||||||
typeof _actionHandlers.captureAuthorityPerformanceBaseline === "function"
|
typeof _actionHandlers.captureAuthorityPerformanceBaseline === "function"
|
||||||
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="baseline">捕获 Perf Baseline</button>`
|
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="baseline">捕获 Perf Baseline</button>`
|
||||||
: "",
|
: "",
|
||||||
@@ -3321,6 +3335,15 @@ function _refreshTaskPersistence() {
|
|||||||
} else {
|
} else {
|
||||||
toastr.warning(`Authority 审计失败:${result?.error || "unknown"}`, "ST-BME");
|
toastr.warning(`Authority 审计失败:${result?.error || "unknown"}`, "ST-BME");
|
||||||
}
|
}
|
||||||
|
} else if (action === "checkpoint") {
|
||||||
|
if (typeof _actionHandlers.writeAuthorityCheckpoint !== "function") return;
|
||||||
|
toastr.info("Authority Checkpoint 写入中…", "ST-BME", { timeOut: 2000 });
|
||||||
|
const result = await _actionHandlers.writeAuthorityCheckpoint();
|
||||||
|
if (result?.success) {
|
||||||
|
toastr.success(`Authority Checkpoint 已写入:rev ${Number(result?.result?.checkpointRevision || result?.result?.revision || 0) || "?"}`, "ST-BME");
|
||||||
|
} else {
|
||||||
|
toastr.warning(`Authority Checkpoint 写入失败:${result?.error || "unknown"}`, "ST-BME");
|
||||||
|
}
|
||||||
} else if (action === "restore") {
|
} else if (action === "restore") {
|
||||||
if (typeof _actionHandlers.restoreAuthorityCheckpoint !== "function") return;
|
if (typeof _actionHandlers.restoreAuthorityCheckpoint !== "function") return;
|
||||||
toastr.info("Authority Checkpoint 恢复中…", "ST-BME", { timeOut: 2000 });
|
toastr.info("Authority Checkpoint 恢复中…", "ST-BME", { timeOut: 2000 });
|
||||||
@@ -3330,6 +3353,10 @@ function _refreshTaskPersistence() {
|
|||||||
} else {
|
} else {
|
||||||
toastr.warning(`Authority Checkpoint 恢复失败:${result?.error || "unknown"}`, "ST-BME");
|
toastr.warning(`Authority Checkpoint 恢复失败:${result?.error || "unknown"}`, "ST-BME");
|
||||||
}
|
}
|
||||||
|
} else if (action === "rebuild-trivium") {
|
||||||
|
if (typeof _actionHandlers.rebuildVectorIndex !== "function") return;
|
||||||
|
await _actionHandlers.rebuildVectorIndex();
|
||||||
|
return;
|
||||||
} else if (action === "baseline") {
|
} else if (action === "baseline") {
|
||||||
if (typeof _actionHandlers.captureAuthorityPerformanceBaseline !== "function") return;
|
if (typeof _actionHandlers.captureAuthorityPerformanceBaseline !== "function") return;
|
||||||
const result = await _actionHandlers.captureAuthorityPerformanceBaseline();
|
const result = await _actionHandlers.captureAuthorityPerformanceBaseline();
|
||||||
@@ -3349,6 +3376,10 @@ function _refreshTaskPersistence() {
|
|||||||
toastr.error(
|
toastr.error(
|
||||||
action === "restore"
|
action === "restore"
|
||||||
? `Authority Checkpoint 恢复失败: ${error?.message || error}`
|
? `Authority Checkpoint 恢复失败: ${error?.message || error}`
|
||||||
|
: action === "checkpoint"
|
||||||
|
? `Authority Checkpoint 写入失败: ${error?.message || error}`
|
||||||
|
: action === "rebuild-trivium"
|
||||||
|
? `Authority Trivium 重建失败: ${error?.message || error}`
|
||||||
: action === "baseline"
|
: action === "baseline"
|
||||||
? `Authority Perf Baseline 捕获失败: ${error?.message || error}`
|
? `Authority Perf Baseline 捕获失败: ${error?.message || error}`
|
||||||
: `Authority 审计失败: ${error?.message || error}`,
|
: `Authority 审计失败: ${error?.message || error}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user