fix(authority): route graph persistence by storage readiness

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Sisyphus
2026-05-07 04:13:54 +00:00
parent 54ea001b8c
commit 39355459a6
2 changed files with 201 additions and 7 deletions

View File

@@ -6967,7 +6967,6 @@ function shouldUseAuthorityGraphStore(settings = getSettings(), capability = aut
normalizedSettings.sqlPrimary &&
normalizedSettings.storageMode !== "local-primary" &&
normalizedSettings.storageMode !== "off" &&
normalizedCapability.serverPrimaryReady &&
normalizedCapability.storagePrimaryReady
);
}
@@ -14394,7 +14393,7 @@ function buildBatchPersistenceRecordFromPersistResult(persistResult = null) {
if (
accepted &&
["indexeddb", "opfs", "luker-chat-state"].includes(
["indexeddb", "opfs", "authority-sql", "luker-chat-state"].includes(
String(persistResult?.storageTier || ""),
)
) {
@@ -14449,6 +14448,7 @@ async function persistGraphToConfiguredDurableTier(
if (
persistenceEnvironment.hostProfile === "luker" &&
persistenceEnvironment.primaryStorageTier === "luker-chat-state" &&
canUseHostGraphChatStatePersistence(context)
) {
const chatStateResult = await persistGraphToHostChatState(context, {

View File

@@ -482,6 +482,19 @@ async function createGraphPersistenceHarness({
imported: importResult.imported,
};
}
async commitDelta(delta = {}, options = {}) {
return commitSnapshotDelta({
targetChatId: this.chatId,
delta,
options,
getSnapshot: getAuthoritySnapshotForChat,
setSnapshot: setAuthoritySnapshotForChat,
metaPatch: {
storagePrimary: AUTHORITY_GRAPH_STORE_KIND,
storageMode: AUTHORITY_GRAPH_STORE_MODE,
},
});
}
async isEmpty() {
const snapshot = getAuthoritySnapshotForChat(this.chatId);
const nodes = Array.isArray(snapshot?.nodes) ? snapshot.nodes.length : 0;
@@ -517,9 +530,17 @@ async function createGraphPersistenceHarness({
}
}
function commitIndexedDbDelta(targetChatId = "", delta = {}, options = {}) {
function commitSnapshotDelta({
targetChatId = "",
delta = {},
options = {},
getSnapshot,
setSnapshot,
metaPatch = {},
} = {}) {
const normalizedChatId = String(targetChatId || "");
const currentSnapshot = getIndexedDbSnapshotForChat(normalizedChatId);
const currentSnapshot =
typeof getSnapshot === "function" ? getSnapshot(normalizedChatId) : null;
const now = Date.now();
const nodeMap = new Map(
@@ -580,6 +601,7 @@ async function createGraphPersistenceHarness({
meta: {
...(currentSnapshot?.meta || {}),
...runtimeMetaPatch,
...(metaPatch && typeof metaPatch === "object" ? structuredClone(metaPatch) : {}),
chatId: normalizedChatId,
revision: nextRevision,
lastModified: now,
@@ -598,9 +620,9 @@ async function createGraphPersistenceHarness({
state: nextState,
};
setIndexedDbSnapshotForChat(normalizedChatId, nextSnapshot);
runtimeContext.__indexedDbSnapshot =
getIndexedDbSnapshotForChat(normalizedChatId);
if (typeof setSnapshot === "function") {
setSnapshot(normalizedChatId, nextSnapshot);
}
return {
revision: nextRevision,
@@ -620,6 +642,20 @@ async function createGraphPersistenceHarness({
};
}
function commitIndexedDbDelta(targetChatId = "", delta = {}, options = {}) {
const result = commitSnapshotDelta({
targetChatId,
delta,
options,
getSnapshot: getIndexedDbSnapshotForChat,
setSnapshot: setIndexedDbSnapshotForChat,
});
runtimeContext.__indexedDbSnapshot = getIndexedDbSnapshotForChat(
String(targetChatId || ""),
);
return result;
}
const runtimeContext = {
console,
Date,
@@ -1608,6 +1644,7 @@ result = {
retryPendingGraphPersist,
persistExtractionBatchResult,
shouldUseAuthorityJobs,
shouldUseAuthorityGraphStore,
onRebuildLocalCacheFromLukerSidecar,
saveGraphToIndexedDb,
cloneGraphForPersistence,
@@ -4093,6 +4130,81 @@ result = {
);
}
{
const harness = await createGraphPersistenceHarness({
chatId: "chat-authority-sql-storage-only",
globalChatId: "chat-authority-sql-storage-only",
});
harness.runtimeContext.extension_settings[MODULE_NAME] = {
authorityEnabled: "on",
authorityPrimaryWhenAvailable: true,
authorityStorageMode: "server-primary",
authoritySqlPrimary: true,
};
const capability = harness.api.setAuthorityCapabilityState({
installed: true,
healthy: true,
sessionReady: true,
permissionReady: true,
features: ["sql.query", "sql.mutation"],
reason: "missing-required-features",
lastProbeAt: Date.now(),
});
assert.equal(
capability.serverPrimaryReady,
false,
"缺少 jobs/blob/trivium 时整体 Authority server-primary 应保持降级显示",
);
assert.equal(
capability.storagePrimaryReady,
true,
"SQL 存储能力已就绪时图谱主存储应可用",
);
assert.equal(
harness.api.shouldUseAuthorityGraphStore(
harness.runtimeContext.extension_settings[MODULE_NAME],
capability,
),
true,
"Authority SQL 图谱主存储不应被 jobs/blob/trivium 附属能力误伤",
);
assert.equal(
harness.api.shouldUseAuthorityJobs({ mode: "authority", source: "authority-trivium" }),
false,
"jobs 不可用时 Authority job 提交仍应被禁用",
);
harness.api.setCurrentGraph(
stampPersistedGraph(
createMeaningfulGraph("chat-authority-sql-storage-only", "authority-sql-storage-only"),
{
revision: 6,
integrity: "chat-authority-sql-storage-only",
chatId: "chat-authority-sql-storage-only",
reason: "authority-sql-storage-only-seed",
},
),
);
const persistResult = await harness.api.persistExtractionBatchResult({
reason: "authority-sql-storage-only-persist",
lastProcessedAssistantFloor: 6,
});
assert.equal(persistResult.accepted, true);
assert.equal(persistResult.storageTier, "authority-sql");
assert.equal(persistResult.acceptedBy, "authority-sql");
assert.equal(
Number(
harness.api.getAuthoritySnapshotForChat("chat-authority-sql-storage-only")?.meta
?.revision || 0,
),
persistResult.revision,
"SQL-only Authority capability should still perform accepted Authority SQL graph persistence",
);
}
{
const harness = await createGraphPersistenceHarness({
chatId: "chat-b",
@@ -4587,6 +4699,88 @@ result = {
);
}
{
const chatId = "chat-luker-authority-sql-primary";
const persistenceChatId = "meta-luker-authority-sql-primary";
const harness = await createGraphPersistenceHarness({
chatId,
globalChatId: chatId,
characterId: "char-luker-authority-sql",
chatMetadata: {
integrity: persistenceChatId,
},
});
harness.runtimeContext.Luker = {
getContext() {
return harness.runtimeContext.__chatContext;
},
};
harness.runtimeContext.extension_settings[MODULE_NAME] = {
authorityEnabled: "on",
authorityPrimaryWhenAvailable: true,
authorityStorageMode: "server-primary",
authoritySqlPrimary: true,
authorityBrowserCacheMode: "minimal",
};
harness.api.setAuthorityCapabilityState({
installed: true,
healthy: true,
sessionReady: true,
permissionReady: true,
minimumFeatureSetReady: true,
serverPrimaryReady: true,
storagePrimaryReady: true,
triviumPrimaryReady: true,
jobsReady: true,
blobReady: true,
features: [
"sql.query",
"sql.mutation",
"trivium.search",
"jobs",
"blob",
],
supportedJobTypes: ["delay"],
supportedJobTypesKnown: true,
reason: "ok",
lastProbeAt: Date.now(),
});
harness.api.setCurrentGraph(
stampPersistedGraph(
createMeaningfulGraph(chatId, "luker-authority-sql"),
{
revision: 9,
integrity: persistenceChatId,
chatId,
reason: "luker-authority-sql-seed",
},
),
);
const result = await harness.api.persistExtractionBatchResult({
reason: "luker-authority-sql-persist",
lastProcessedAssistantFloor: 9,
});
assert.equal(result.accepted, true);
assert.equal(result.storageTier, "authority-sql");
assert.equal(result.acceptedBy, "authority-sql");
assert.equal(result.primaryTier, "authority-sql");
assert.equal(result.cacheTier, "none");
assert.equal(
await harness.runtimeContext.__chatContext.getChatState(
LUKER_GRAPH_MANIFEST_NAMESPACE,
),
null,
"Authority SQL primary in Luker must not be preempted by Luker sidecar manifest",
);
assert.equal(
Number(harness.api.getAuthoritySnapshotForChat(persistenceChatId)?.meta?.revision || 0),
result.revision,
"Authority SQL snapshot should receive the accepted persist revision",
);
}
{
const chatId = "chat-luker-no-authority-primary";
const harness = await createGraphPersistenceHarness({