diff --git a/src/mirror-review/index.ts b/src/mirror-review/index.ts index 94cca54e61..87b321c756 100644 --- a/src/mirror-review/index.ts +++ b/src/mirror-review/index.ts @@ -1,4 +1,5 @@ export { reviewDraftForCanon } from "./review_engine.js"; +export type { MirrorReviewObservability } from "./review_engine.js"; export { MIRROR_REVIEW_RULES } from "./review_rules.js"; export { detectCanonConflicts } from "./canon_conflict.js"; export { detectNarrativeSimilarity } from "./narrative_similarity.js"; diff --git a/src/mirror-review/review_engine.ts b/src/mirror-review/review_engine.ts index f553b91510..26c1881576 100644 --- a/src/mirror-review/review_engine.ts +++ b/src/mirror-review/review_engine.ts @@ -1,4 +1,7 @@ -import { incrementMetric, logMirrorEvent } from "../mirror-observability/index.js"; +import { + getCurrentMirrorObservabilityContext, + type MirrorObservabilityContext, +} from "../mirror-observability/index.js"; import { retrieveCanonicalScrolls } from "../mirror/lore_retrieval/index.js"; import { detectCanonConflicts } from "./canon_conflict.js"; import { detectNarrativeSimilarity } from "./narrative_similarity.js"; @@ -6,6 +9,11 @@ import { MIRROR_REVIEW_RULES } from "./review_rules.js"; import type { MirrorCanonReviewResult, MirrorReviewStatus } from "./review_types.js"; import { validateDraftSymbols } from "./symbol_validation.js"; +export type MirrorReviewObservability = Pick< + MirrorObservabilityContext, + "incrementMetric" | "logEvent" +>; + function deriveStatus(params: { conflicts: MirrorCanonReviewResult["conflicts"]; similarities: MirrorCanonReviewResult["similarities"]; @@ -31,10 +39,14 @@ function deriveStatus(params: { return "approved"; } -export async function reviewDraftForCanon(params: { - loreDir: string; - draftContent: string; -}): Promise { +export async function reviewDraftForCanon( + params: { + loreDir: string; + draftContent: string; + }, + deps: { observability?: MirrorReviewObservability } = {}, +): Promise { + const observability = deps.observability ?? getCurrentMirrorObservabilityContext(); const retrieval = await retrieveCanonicalScrolls(params.draftContent, { loreDir: params.loreDir, limit: 5, @@ -58,9 +70,9 @@ export async function reviewDraftForCanon(params: { }); if (status === "conflict_detected") { - incrementMetric("review_conflicts"); + observability.incrementMetric("review_conflicts"); } - logMirrorEvent("review.decision", { + observability.logEvent("review.decision", { status, conflicts: conflicts.length, similarities: similarities.length, diff --git a/src/mirror/skills/commit_scroll/commit_scroll.ts b/src/mirror/skills/commit_scroll/commit_scroll.ts index 483a320b80..7b577db6f8 100644 --- a/src/mirror/skills/commit_scroll/commit_scroll.ts +++ b/src/mirror/skills/commit_scroll/commit_scroll.ts @@ -1,7 +1,12 @@ import crypto from "node:crypto"; import fs from "node:fs/promises"; import path from "node:path"; -import { reviewDraftForCanon, type MirrorCanonReviewResult } from "../../../mirror-review/index.js"; +import { getCurrentMirrorObservabilityContext } from "../../../mirror-observability/index.js"; +import { + reviewDraftForCanon, + type MirrorCanonReviewResult, + type MirrorReviewObservability, +} from "../../../mirror-review/index.js"; import { resolveLoreRetrievalRoot } from "../../lore_retrieval/index.js"; import { ensureScrollIndexUpToDate } from "../../lore_sources/scroll_index.js"; import { @@ -225,6 +230,7 @@ async function writeCanonicalFileAtomically(finalPath: string, content: string): } export async function commitScroll(input: CommitScrollInput): Promise { + const observability: MirrorReviewObservability = getCurrentMirrorObservabilityContext(); const params = validateInput(input); const family = input.family_override ?? @@ -260,10 +266,15 @@ export async function commitScroll(input: CommitScrollInput): Promise 0) { return {