mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-14 02:40:45 +08:00
chore: remove abandoned hard-cut v3 namespace cluster
This commit is contained in:
@@ -1,261 +0,0 @@
|
||||
// ST-BME v3 GraphHead model.
|
||||
//
|
||||
// Pure helpers only. Phase 3 introduces the v3 data shape without switching
|
||||
// storage routes. A GraphHead owns graph identity/revision/counts; replicas and
|
||||
// commit markers are pointers to that head instead of competing authorities.
|
||||
|
||||
import { isAcceptedLegacyPersistenceTier } from "../sync/legacy-persistence-repair.js";
|
||||
import { normalizeIdentityValue } from "../runtime/identity-resolver.js";
|
||||
import { getGraphStats } from "./graph.js";
|
||||
|
||||
export const GRAPH_HEAD_FORMAT_VERSION = 3;
|
||||
export const GRAPH_REPLICA_POINTER_FORMAT_VERSION = 3;
|
||||
export const GRAPH_COMMIT_MARKER_V3_FORMAT_VERSION = 3;
|
||||
|
||||
function normalizeNonNegativeInteger(value = 0) {
|
||||
const numeric = Number(value || 0);
|
||||
if (!Number.isFinite(numeric) || numeric <= 0) return 0;
|
||||
return Math.floor(numeric);
|
||||
}
|
||||
|
||||
function normalizeFloor(value = -1) {
|
||||
const numeric = Number(value);
|
||||
if (!Number.isFinite(numeric)) return -1;
|
||||
return Math.floor(numeric);
|
||||
}
|
||||
|
||||
function normalizeUpdatedAt(value = "") {
|
||||
return String(value || new Date().toISOString());
|
||||
}
|
||||
|
||||
function normalizeCounts(value = {}) {
|
||||
return {
|
||||
nodeCount: normalizeNonNegativeInteger(value.nodeCount ?? value.nodes),
|
||||
edgeCount: normalizeNonNegativeInteger(value.edgeCount ?? value.edges),
|
||||
archivedCount: normalizeNonNegativeInteger(value.archivedCount ?? value.archivedNodes),
|
||||
tombstoneCount: normalizeNonNegativeInteger(value.tombstoneCount ?? value.tombstones),
|
||||
};
|
||||
}
|
||||
|
||||
function firstIdentity(...values) {
|
||||
for (const value of values) {
|
||||
const normalized = normalizeIdentityValue(value);
|
||||
if (normalized) return normalized;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
export function normalizeGraphHead(input = null, fallback = {}) {
|
||||
const source = input && typeof input === "object" && !Array.isArray(input) ? input : {};
|
||||
const fallbackSource =
|
||||
fallback && typeof fallback === "object" && !Array.isArray(fallback) ? fallback : {};
|
||||
const counts = normalizeCounts({
|
||||
...(fallbackSource.counts || fallbackSource),
|
||||
...(source.counts || source),
|
||||
});
|
||||
const integrity = firstIdentity(source.integrity, fallbackSource.integrity);
|
||||
const chatId = firstIdentity(source.chatId, fallbackSource.chatId);
|
||||
const graphId = firstIdentity(source.graphId, fallbackSource.graphId, integrity, chatId);
|
||||
|
||||
return {
|
||||
formatVersion: GRAPH_HEAD_FORMAT_VERSION,
|
||||
graphId,
|
||||
chatId,
|
||||
hostChatId: firstIdentity(source.hostChatId, fallbackSource.hostChatId),
|
||||
integrity,
|
||||
revision: normalizeNonNegativeInteger(source.revision ?? fallbackSource.revision),
|
||||
schemaVersion: normalizeNonNegativeInteger(
|
||||
source.schemaVersion ?? fallbackSource.schemaVersion,
|
||||
),
|
||||
lastProcessedAssistantFloor: normalizeFloor(
|
||||
source.lastProcessedAssistantFloor ?? fallbackSource.lastProcessedAssistantFloor,
|
||||
),
|
||||
extractionCount: normalizeNonNegativeInteger(
|
||||
source.extractionCount ?? fallbackSource.extractionCount,
|
||||
),
|
||||
counts,
|
||||
updatedAt: normalizeUpdatedAt(source.updatedAt || fallbackSource.updatedAt),
|
||||
reason: String(source.reason || fallbackSource.reason || ""),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildGraphHeadFromGraph(
|
||||
graph = null,
|
||||
{
|
||||
graphId = "",
|
||||
chatId = "",
|
||||
hostChatId = "",
|
||||
integrity = "",
|
||||
revision = 0,
|
||||
reason = "",
|
||||
updatedAt = "",
|
||||
} = {},
|
||||
) {
|
||||
const stats = graph ? getGraphStats(graph) : null;
|
||||
const historyState = graph?.historyState || {};
|
||||
return normalizeGraphHead({
|
||||
graphId,
|
||||
chatId: firstIdentity(chatId, historyState.chatId),
|
||||
hostChatId,
|
||||
integrity,
|
||||
revision,
|
||||
schemaVersion: graph?.version,
|
||||
lastProcessedAssistantFloor: Number.isFinite(Number(historyState.lastProcessedAssistantFloor))
|
||||
? Number(historyState.lastProcessedAssistantFloor)
|
||||
: Number.isFinite(Number(stats?.lastProcessedSeq))
|
||||
? Number(stats.lastProcessedSeq)
|
||||
: -1,
|
||||
extractionCount: historyState.extractionCount,
|
||||
counts: {
|
||||
nodeCount: stats?.activeNodes,
|
||||
edgeCount: stats?.totalEdges,
|
||||
archivedCount: stats?.archivedNodes,
|
||||
tombstoneCount: stats?.tombstones,
|
||||
},
|
||||
updatedAt,
|
||||
reason,
|
||||
});
|
||||
}
|
||||
|
||||
export function normalizeReplicaPointer(input = null, fallback = {}) {
|
||||
const source = input && typeof input === "object" && !Array.isArray(input) ? input : {};
|
||||
const fallbackSource =
|
||||
fallback && typeof fallback === "object" && !Array.isArray(fallback) ? fallback : {};
|
||||
const storageTier = String(source.storageTier || fallbackSource.storageTier || "none")
|
||||
.trim()
|
||||
.toLowerCase() || "none";
|
||||
const revision = normalizeNonNegativeInteger(source.revision ?? fallbackSource.revision);
|
||||
const graphId = firstIdentity(source.graphId, fallbackSource.graphId);
|
||||
const chatId = firstIdentity(source.chatId, fallbackSource.chatId);
|
||||
const integrity = firstIdentity(source.integrity, fallbackSource.integrity);
|
||||
const accepted =
|
||||
source.accepted === true &&
|
||||
revision > 0 &&
|
||||
Boolean(graphId) &&
|
||||
isAcceptedLegacyPersistenceTier(storageTier);
|
||||
|
||||
return {
|
||||
formatVersion: GRAPH_REPLICA_POINTER_FORMAT_VERSION,
|
||||
graphId,
|
||||
revision,
|
||||
storageTier,
|
||||
accepted,
|
||||
chatId,
|
||||
integrity,
|
||||
persistedAt: String(source.persistedAt || source.updatedAt || fallbackSource.persistedAt || ""),
|
||||
source: String(source.source || fallbackSource.source || ""),
|
||||
reason: String(source.reason || fallbackSource.reason || ""),
|
||||
};
|
||||
}
|
||||
|
||||
export function isReplicaAccepted(pointer = null) {
|
||||
return normalizeReplicaPointer(pointer).accepted === true;
|
||||
}
|
||||
|
||||
export function buildCommitMarkerV3({ head = null, replica = null, reason = "", persistedAt = "" } = {}) {
|
||||
const normalizedHead = normalizeGraphHead(head);
|
||||
const normalizedReplica = normalizeReplicaPointer(replica, {
|
||||
graphId: normalizedHead.graphId,
|
||||
revision: normalizedHead.revision,
|
||||
chatId: normalizedHead.chatId,
|
||||
integrity: normalizedHead.integrity,
|
||||
reason,
|
||||
persistedAt,
|
||||
});
|
||||
const replicaMatchesHead =
|
||||
normalizedReplica.accepted === true &&
|
||||
normalizedReplica.graphId === normalizedHead.graphId &&
|
||||
normalizedReplica.revision === normalizedHead.revision;
|
||||
return {
|
||||
formatVersion: GRAPH_COMMIT_MARKER_V3_FORMAT_VERSION,
|
||||
graphId: normalizedHead.graphId,
|
||||
revision: normalizedHead.revision,
|
||||
accepted: replicaMatchesHead,
|
||||
storageTier: normalizedReplica.storageTier,
|
||||
chatId: normalizedHead.chatId || normalizedReplica.chatId,
|
||||
hostChatId: normalizedHead.hostChatId,
|
||||
integrity: normalizedHead.integrity || normalizedReplica.integrity,
|
||||
nodeCount: normalizedHead.counts.nodeCount,
|
||||
edgeCount: normalizedHead.counts.edgeCount,
|
||||
archivedCount: normalizedHead.counts.archivedCount,
|
||||
tombstoneCount: normalizedHead.counts.tombstoneCount,
|
||||
lastProcessedAssistantFloor: normalizedHead.lastProcessedAssistantFloor,
|
||||
extractionCount: normalizedHead.extractionCount,
|
||||
persistedAt: normalizedReplica.persistedAt || persistedAt || normalizedHead.updatedAt,
|
||||
reason: String(reason || normalizedReplica.reason || normalizedHead.reason || ""),
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeCommitMarkerV3(marker = null) {
|
||||
if (!marker || typeof marker !== "object" || Array.isArray(marker)) return null;
|
||||
const head = normalizeGraphHead({
|
||||
graphId: marker.graphId,
|
||||
chatId: marker.chatId,
|
||||
hostChatId: marker.hostChatId,
|
||||
integrity: marker.integrity,
|
||||
revision: marker.revision,
|
||||
lastProcessedAssistantFloor: marker.lastProcessedAssistantFloor,
|
||||
extractionCount: marker.extractionCount,
|
||||
counts: marker,
|
||||
updatedAt: marker.persistedAt,
|
||||
reason: marker.reason,
|
||||
});
|
||||
const replica = normalizeReplicaPointer({
|
||||
graphId: head.graphId,
|
||||
revision: head.revision,
|
||||
storageTier: marker.storageTier,
|
||||
accepted: marker.accepted,
|
||||
chatId: head.chatId,
|
||||
integrity: head.integrity,
|
||||
persistedAt: marker.persistedAt,
|
||||
reason: marker.reason,
|
||||
});
|
||||
return buildCommitMarkerV3({ head, replica, reason: marker.reason, persistedAt: marker.persistedAt });
|
||||
}
|
||||
|
||||
export function graphHeadFromLegacyPersistenceMeta({ meta = null, graph = null } = {}) {
|
||||
const legacyMeta = meta && typeof meta === "object" && !Array.isArray(meta) ? meta : {};
|
||||
return buildGraphHeadFromGraph(graph, {
|
||||
graphId: legacyMeta.graphId,
|
||||
chatId: legacyMeta.chatId,
|
||||
integrity: legacyMeta.integrity,
|
||||
revision: legacyMeta.revision,
|
||||
reason: legacyMeta.reason,
|
||||
updatedAt: legacyMeta.updatedAt,
|
||||
});
|
||||
}
|
||||
|
||||
export function graphHeadFromLegacyCommitMarker(marker = null) {
|
||||
return normalizeGraphHead({
|
||||
graphId: marker?.graphId,
|
||||
chatId: marker?.chatId,
|
||||
integrity: marker?.integrity,
|
||||
revision: marker?.revision,
|
||||
lastProcessedAssistantFloor: marker?.lastProcessedAssistantFloor,
|
||||
extractionCount: marker?.extractionCount,
|
||||
counts: marker,
|
||||
updatedAt: marker?.persistedAt,
|
||||
reason: marker?.reason,
|
||||
});
|
||||
}
|
||||
|
||||
// Test/importer/diagnostic bridge only. Do not use this in v3 runtime hot paths;
|
||||
// v3 storage routes should write v3 GraphHead/ReplicaPointer directly.
|
||||
export function commitMarkerV3ToLegacyMarker(marker = null) {
|
||||
const normalized = normalizeCommitMarkerV3(marker);
|
||||
if (!normalized) return null;
|
||||
return {
|
||||
revision: normalized.revision,
|
||||
lastProcessedAssistantFloor: normalized.lastProcessedAssistantFloor,
|
||||
extractionCount: normalized.extractionCount,
|
||||
nodeCount: normalized.nodeCount,
|
||||
edgeCount: normalized.edgeCount,
|
||||
archivedCount: normalized.archivedCount,
|
||||
persistedAt: normalized.persistedAt,
|
||||
storageTier: normalized.storageTier,
|
||||
accepted: normalized.accepted,
|
||||
reason: normalized.reason,
|
||||
chatId: normalized.chatId,
|
||||
integrity: normalized.integrity,
|
||||
};
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
// ST-BME v3 hard-cut namespace constants.
|
||||
//
|
||||
// These constants intentionally do not alias legacy st_bme/st-bme/STBME keys.
|
||||
// Phase 6 introduces the namespace contract only; live routes are ported later.
|
||||
|
||||
export const GRAPH_V3_NAMESPACE_VERSION = 3;
|
||||
export const GRAPH_V3_MODULE_NAME = "st_bme_v3";
|
||||
|
||||
export const GRAPH_V3_METADATA_KEY = `${GRAPH_V3_MODULE_NAME}_graph`;
|
||||
export const GRAPH_V3_HEAD_KEY = `${GRAPH_V3_MODULE_NAME}_graph_head`;
|
||||
export const GRAPH_V3_COMMIT_MARKER_KEY = `${GRAPH_V3_MODULE_NAME}_commit_marker`;
|
||||
export const GRAPH_V3_CHAT_STATE_NAMESPACE = `${GRAPH_V3_MODULE_NAME}_graph_state`;
|
||||
export const GRAPH_V3_LUKER_MANIFEST_NAMESPACE = `${GRAPH_V3_MODULE_NAME}_graph_manifest`;
|
||||
export const GRAPH_V3_LUKER_JOURNAL_NAMESPACE = `${GRAPH_V3_MODULE_NAME}_graph_journal`;
|
||||
export const GRAPH_V3_LUKER_CHECKPOINT_NAMESPACE = `${GRAPH_V3_MODULE_NAME}_graph_checkpoint`;
|
||||
export const GRAPH_V3_SHADOW_SNAPSHOT_STORAGE_PREFIX = `${GRAPH_V3_MODULE_NAME}:graph-shadow:`;
|
||||
export const GRAPH_V3_IDENTITY_ALIAS_STORAGE_KEY = `${GRAPH_V3_MODULE_NAME}:chat-identity-aliases`;
|
||||
|
||||
export const GRAPH_V3_INDEXEDDB_NAME_PREFIX = "ST_BME_V3";
|
||||
export const GRAPH_V3_OPFS_ROOT_DIRECTORY_NAME = "stbme-v3";
|
||||
export const GRAPH_V3_AUTHORITY_TABLES = Object.freeze({
|
||||
meta: `${GRAPH_V3_MODULE_NAME}_graph_meta`,
|
||||
nodes: `${GRAPH_V3_MODULE_NAME}_graph_nodes`,
|
||||
edges: `${GRAPH_V3_MODULE_NAME}_graph_edges`,
|
||||
tombstones: `${GRAPH_V3_MODULE_NAME}_graph_tombstones`,
|
||||
});
|
||||
|
||||
export const GRAPH_LEGACY_NAMESPACE_VALUES = Object.freeze([
|
||||
"st_bme",
|
||||
"st_bme_graph",
|
||||
"st_bme_commit_marker",
|
||||
"st_bme_graph_state",
|
||||
"st_bme_graph_manifest",
|
||||
"st_bme_graph_journal",
|
||||
"st_bme_graph_checkpoint",
|
||||
"st_bme:graph-shadow:",
|
||||
"st_bme:chat-identity-aliases",
|
||||
"STBME_",
|
||||
"st-bme",
|
||||
"st_bme_graph_meta",
|
||||
"st_bme_graph_nodes",
|
||||
"st_bme_graph_edges",
|
||||
"st_bme_graph_tombstones",
|
||||
]);
|
||||
|
||||
function normalizeNamespaceSegment(value = "") {
|
||||
return String(value ?? "")
|
||||
.trim()
|
||||
.replace(/[^a-zA-Z0-9_-]+/g, "_")
|
||||
.replace(/^_+|_+$/g, "") || "default";
|
||||
}
|
||||
|
||||
export function buildGraphV3IndexedDbName(chatId = "") {
|
||||
return `${GRAPH_V3_INDEXEDDB_NAME_PREFIX}_${normalizeNamespaceSegment(chatId)}`;
|
||||
}
|
||||
|
||||
export function buildGraphV3OpfsChatPath(chatId = "") {
|
||||
return `${GRAPH_V3_OPFS_ROOT_DIRECTORY_NAME}/chats/${normalizeNamespaceSegment(chatId)}`;
|
||||
}
|
||||
|
||||
export function buildGraphV3AuthorityPartition(graphId = "") {
|
||||
return `${GRAPH_V3_MODULE_NAME}:${normalizeNamespaceSegment(graphId)}`;
|
||||
}
|
||||
|
||||
export function listGraphV3NamespaceValues() {
|
||||
return Object.freeze([
|
||||
GRAPH_V3_MODULE_NAME,
|
||||
GRAPH_V3_METADATA_KEY,
|
||||
GRAPH_V3_HEAD_KEY,
|
||||
GRAPH_V3_COMMIT_MARKER_KEY,
|
||||
GRAPH_V3_CHAT_STATE_NAMESPACE,
|
||||
GRAPH_V3_LUKER_MANIFEST_NAMESPACE,
|
||||
GRAPH_V3_LUKER_JOURNAL_NAMESPACE,
|
||||
GRAPH_V3_LUKER_CHECKPOINT_NAMESPACE,
|
||||
GRAPH_V3_SHADOW_SNAPSHOT_STORAGE_PREFIX,
|
||||
GRAPH_V3_IDENTITY_ALIAS_STORAGE_KEY,
|
||||
GRAPH_V3_INDEXEDDB_NAME_PREFIX,
|
||||
GRAPH_V3_OPFS_ROOT_DIRECTORY_NAME,
|
||||
...Object.values(GRAPH_V3_AUTHORITY_TABLES),
|
||||
]);
|
||||
}
|
||||
|
||||
export function validateGraphV3NamespaceIsolation(legacyValues = GRAPH_LEGACY_NAMESPACE_VALUES) {
|
||||
const legacy = new Set((Array.isArray(legacyValues) ? legacyValues : []).map((value) => String(value)));
|
||||
const conflicts = listGraphV3NamespaceValues().filter((value) => legacy.has(String(value)));
|
||||
const unsafePrefixConflicts = [];
|
||||
if (GRAPH_V3_INDEXEDDB_NAME_PREFIX.startsWith("STBME_")) {
|
||||
unsafePrefixConflicts.push({ surface: "indexeddb", legacyPrefix: "STBME_" });
|
||||
}
|
||||
if (GRAPH_V3_OPFS_ROOT_DIRECTORY_NAME.startsWith("st-bme")) {
|
||||
unsafePrefixConflicts.push({ surface: "opfs", legacyPrefix: "st-bme" });
|
||||
}
|
||||
return {
|
||||
isolated: conflicts.length === 0 && unsafePrefixConflicts.length === 0,
|
||||
conflicts,
|
||||
unsafePrefixConflicts,
|
||||
namespaceVersion: GRAPH_V3_NAMESPACE_VERSION,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user