feat(logs): logs données restructurés — identité en préfixe, trace résolution/barrière, inspection outbox
Chemin données bas-niveau du polyfill rendu lisible pour diagnostiquer en session live : - Format identité-en-premier : `[<identity>][polyfill] OP shortNuri (label)` ; console.error épars (store-registry, inbox) unifiés au même préfixe. - Trace (derrière le flag debug) : issue de la barrière ensureRepoOpen (synced|timed-out + durée) et résultat sémantique de chaque étage de résolution (resolvePointer/canonicalDoc/resolveAccount/resolveShimDoc/readScopeIndex). - outbox-log.ts (nouveau) : inspection read-only de l'outbox hors-ligne au démarrage de session ; console.warn si non vide (anomalie, toujours visible), sous flag si vide. Le comptage seul est fiable (payloads BARE opaques côté JS). Pas de changement fonctionnel. bun test 126 pass ; tsc 0 erreur. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GbGgNEHRejVKoREvFuDFg
This commit is contained in:
@@ -63,6 +63,7 @@ import { docCreate, sparqlUpdate, sparqlQuery } from "./docs";
|
||||
import { getStoreRegistryDeps } from "./polyfill";
|
||||
import { ensureRepoOpen } from "./open-repo";
|
||||
import { escapeLiteral, escapeIri, assertNuri } from "./sparql";
|
||||
import { accessLogPrefix, logStage, shortNuri } from "./access-log";
|
||||
import type { Nuri, Scope } from "./types";
|
||||
|
||||
// --- sharedWalletShim model ----------------------------------------------
|
||||
@@ -248,11 +249,20 @@ function bindingValue(row: Record<string, { value: string }>, key: string): stri
|
||||
*/
|
||||
function canonicalDoc(rows: Array<Record<string, { value: string }>>, key: string): Nuri {
|
||||
let chosen = "";
|
||||
const distinct = new Set<string>();
|
||||
for (const row of rows) {
|
||||
const v = bindingValue(row, key);
|
||||
if (!v) continue;
|
||||
distinct.add(v);
|
||||
if (chosen === "" || v < chosen) chosen = v;
|
||||
}
|
||||
// Stage trace: which doc got picked, and out of how many DISTINCT candidate
|
||||
// values — >1 flags residual fork residue (see the module doc above) even
|
||||
// when resolution still converges correctly on the canonical (smallest) one.
|
||||
logStage(
|
||||
"canonicalDoc(" + key + ") → " + (chosen ? shortNuri(chosen) : "none") +
|
||||
" (" + distinct.size + (distinct.size === 1 ? " candidate)" : " candidates)"),
|
||||
);
|
||||
return chosen;
|
||||
}
|
||||
|
||||
@@ -327,15 +337,19 @@ async function resolvePointer(): Promise<Nuri> {
|
||||
try {
|
||||
const result = await sparqlQuery(s.sessionId, query, undefined, root, "resolvePointer");
|
||||
const doc = canonicalDoc(readBindings(result), "shimDoc");
|
||||
if (doc) return doc;
|
||||
if (doc) {
|
||||
logStage("resolvePointer → 1 target: " + shortNuri(doc));
|
||||
return doc;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[storeRegistry] resolvePointer read failed:", error);
|
||||
console.error(accessLogPrefix() + " resolvePointer failed:", error);
|
||||
}
|
||||
if (i < attempts - 1) {
|
||||
await sleep(step);
|
||||
step = Math.min(step * 2, maxStepMs);
|
||||
}
|
||||
}
|
||||
logStage("resolvePointer → 0 targets");
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -355,7 +369,7 @@ async function writePointer(doc: Nuri): Promise<void> {
|
||||
try {
|
||||
await sparqlUpdate(s.sessionId, update, root, "writePointer");
|
||||
} catch (error) {
|
||||
console.error("[storeRegistry] writePointer failed:", error);
|
||||
console.error(accessLogPrefix() + " writePointer failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,6 +408,7 @@ async function resolveShimDoc(): Promise<Nuri> {
|
||||
// so a cold 0 on the doc-shim is authoritative (genuinely absent), not sync-lag.
|
||||
await ensureRepoOpen(existing);
|
||||
shimDocNuri = existing;
|
||||
logStage("resolveShimDoc → " + shortNuri(existing));
|
||||
return existing;
|
||||
}
|
||||
|
||||
@@ -403,6 +418,7 @@ async function resolveShimDoc(): Promise<Nuri> {
|
||||
await writePointer(doc);
|
||||
await ensureRepoOpen(doc);
|
||||
shimDocNuri = doc;
|
||||
logStage("resolveShimDoc → " + shortNuri(doc));
|
||||
return doc;
|
||||
})();
|
||||
|
||||
@@ -456,7 +472,7 @@ export async function loadShim(): Promise<Map<string, AccountRecord>> {
|
||||
accountCache.set(key, record);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[storeRegistry] loadShim failed:", error);
|
||||
console.error(accessLogPrefix() + " loadShim failed:", error);
|
||||
}
|
||||
cache = map;
|
||||
return map;
|
||||
@@ -502,16 +518,20 @@ export async function resolveAccount(id: string): Promise<AccountRecord | null>
|
||||
try {
|
||||
const result = await sparqlQuery(s.sessionId, query, undefined, doc, "resolveAccount");
|
||||
const rows = readBindings(result);
|
||||
if (rows.length === 0) return null;
|
||||
if (rows.length === 0) {
|
||||
logStage("resolveAccount(" + key + ") → null");
|
||||
return null;
|
||||
}
|
||||
// DETERMINISTIC: a corrupted shim may return SEVERAL bindings for this one
|
||||
// account subject (duplicate scope-doc values from past forks). Pick the
|
||||
// canonical (lexicographically-smallest) doc per scope so writer and reader
|
||||
// always resolve the SAME docPublic (robustness against PAST fork residue).
|
||||
const record = recordFromRows(rows, id);
|
||||
accountCache.set(key, record);
|
||||
logStage("resolveAccount(" + key + ") → 1 record");
|
||||
return record;
|
||||
} catch (error) {
|
||||
console.error("[storeRegistry] resolveAccount failed:", error);
|
||||
console.error(accessLogPrefix() + " resolveAccount failed:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -542,7 +562,7 @@ async function writeRecord(doc: Nuri, record: AccountRecord): Promise<void> {
|
||||
try {
|
||||
await sparqlUpdate(s.sessionId, update, doc, "writeRecord");
|
||||
} catch (error) {
|
||||
console.error("[storeRegistry] writeRecord persist failed:", error);
|
||||
console.error(accessLogPrefix() + " writeRecord persist failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,7 +753,7 @@ export async function createEntityDoc(id: string, scope: Scope): Promise<Nuri> {
|
||||
"createEntityDoc",
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("[storeRegistry] createEntityDoc index append failed:", error);
|
||||
console.error(accessLogPrefix() + " createEntityDoc index append failed:", error);
|
||||
}
|
||||
return entityNuri;
|
||||
}
|
||||
@@ -765,8 +785,9 @@ async function readScopeIndex(indexDoc: Nuri): Promise<Nuri[]> {
|
||||
if (v) out.push(v);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[storeRegistry] readScopeIndex read failed:", error);
|
||||
console.error(accessLogPrefix() + " readScopeIndex failed:", error);
|
||||
}
|
||||
logStage("readScopeIndex(" + shortNuri(indexDoc) + ") → " + out.length + " entities");
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user