feat(authority): add consistency repair actions

This commit is contained in:
Youzini-afk
2026-04-28 17:48:34 +08:00
parent c733394398
commit dc76d1ea4c
3 changed files with 129 additions and 0 deletions

View File

@@ -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({
config = null,
range = null,
@@ -21404,6 +21494,12 @@ async function onRunAuthorityConsistencyAudit() {
});
}
async function onWriteAuthorityCheckpoint() {
return await writeAuthorityCheckpointFromCurrentGraph({
reason: "panel-authority-checkpoint-write",
});
}
async function onRestoreAuthorityCheckpoint() {
return await restoreAuthorityCheckpointFromBlob({
reason: "panel-authority-checkpoint-restore",
@@ -21996,6 +22092,7 @@ async function onCompactLukerSidecar() {
requeueAuthorityJob: async (jobId) => await requeueAuthorityJob(jobId),
refreshAuthorityJobs: onRefreshAuthorityJobs,
runAuthorityConsistencyAudit: onRunAuthorityConsistencyAudit,
writeAuthorityCheckpoint: onWriteAuthorityCheckpoint,
restoreAuthorityCheckpoint: onRestoreAuthorityCheckpoint,
captureAuthorityPerformanceBaseline: onCaptureAuthorityPerformanceBaseline,
reembedDirect: onReembedDirect,

View File

@@ -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 === "vector-dirty"));
assert.ok(auditDrift.actions.includes("rebuild-authority-trivium"));
assert.ok(auditDrift.actions.includes("write-authority-checkpoint"));
console.log("authority-consistency tests passed");

View File

@@ -3248,13 +3248,27 @@ function _refreshTaskPersistence() {
["诊断包时间", authorityBundleUpdatedLabel],
["诊断包原因", 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 = [
typeof _actionHandlers.runAuthorityConsistencyAudit === "function"
? `<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"
? `<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"
? `<button class="bme-config-secondary-btn" type="button" data-authority-persistence-action="baseline">捕获 Perf Baseline</button>`
: "",
@@ -3321,6 +3335,15 @@ function _refreshTaskPersistence() {
} else {
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") {
if (typeof _actionHandlers.restoreAuthorityCheckpoint !== "function") return;
toastr.info("Authority Checkpoint 恢复中…", "ST-BME", { timeOut: 2000 });
@@ -3330,6 +3353,10 @@ function _refreshTaskPersistence() {
} else {
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") {
if (typeof _actionHandlers.captureAuthorityPerformanceBaseline !== "function") return;
const result = await _actionHandlers.captureAuthorityPerformanceBaseline();
@@ -3349,6 +3376,10 @@ function _refreshTaskPersistence() {
toastr.error(
action === "restore"
? `Authority Checkpoint 恢复失败: ${error?.message || error}`
: action === "checkpoint"
? `Authority Checkpoint 写入失败: ${error?.message || error}`
: action === "rebuild-trivium"
? `Authority Trivium 重建失败: ${error?.message || error}`
: action === "baseline"
? `Authority Perf Baseline 捕获失败: ${error?.message || error}`
: `Authority 审计失败: ${error?.message || error}`,