@openclawbrain/openclaw 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +3 -1
  2. package/dist/extension/index.js +9 -1
  3. package/dist/extension/index.js.map +1 -1
  4. package/dist/extension/runtime-guard.js +6 -1
  5. package/dist/extension/runtime-guard.js.map +1 -1
  6. package/dist/src/cli.d.ts +18 -6
  7. package/dist/src/cli.js +1991 -293
  8. package/dist/src/cli.js.map +1 -1
  9. package/dist/src/daemon.d.ts +42 -1
  10. package/dist/src/daemon.js +360 -50
  11. package/dist/src/daemon.js.map +1 -1
  12. package/dist/src/index.d.ts +65 -1
  13. package/dist/src/index.js +627 -56
  14. package/dist/src/index.js.map +1 -1
  15. package/dist/src/learning-spine.d.ts +3 -1
  16. package/dist/src/learning-spine.js +1 -0
  17. package/dist/src/learning-spine.js.map +1 -1
  18. package/dist/src/local-session-passive-learning.js +6 -1
  19. package/dist/src/local-session-passive-learning.js.map +1 -1
  20. package/dist/src/openclaw-home-layout.d.ts +17 -0
  21. package/dist/src/openclaw-home-layout.js +182 -0
  22. package/dist/src/openclaw-home-layout.js.map +1 -0
  23. package/dist/src/provider-config.d.ts +36 -0
  24. package/dist/src/provider-config.js +181 -25
  25. package/dist/src/provider-config.js.map +1 -1
  26. package/dist/src/resolve-activation-root.d.ts +3 -3
  27. package/dist/src/resolve-activation-root.js +21 -26
  28. package/dist/src/resolve-activation-root.js.map +1 -1
  29. package/dist/src/semantic-metadata.d.ts +4 -0
  30. package/dist/src/semantic-metadata.js +41 -0
  31. package/dist/src/semantic-metadata.js.map +1 -0
  32. package/dist/src/session-store.js +16 -5
  33. package/dist/src/session-store.js.map +1 -1
  34. package/dist/src/session-tail.d.ts +2 -0
  35. package/dist/src/session-tail.js +68 -16
  36. package/dist/src/session-tail.js.map +1 -1
  37. package/dist/src/shadow-extension-proof.js +4 -0
  38. package/dist/src/shadow-extension-proof.js.map +1 -1
  39. package/extension/index.ts +17 -0
  40. package/extension/runtime-guard.ts +7 -1
  41. package/package.json +7 -7
package/dist/src/index.js CHANGED
@@ -3,11 +3,12 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, wri
3
3
  import path from "node:path";
4
4
  import process from "node:process";
5
5
  import { compileRuntimeFromActivation } from "@openclawbrain/compiler";
6
- import { CONTRACT_IDS, buildNormalizedEventExport, canonicalJson, checksumJsonPayload, createFeedbackEvent, createInteractionEvent, sortNormalizedEvents, validateKernelSurface, validateNormalizedEventExport } from "@openclawbrain/contracts";
6
+ import { CONTRACT_IDS, buildEventSemanticSurface, buildNormalizedEventExport, canonicalJson, checksumJsonPayload, createFeedbackEvent, createInteractionEvent, sortNormalizedEvents, validateKernelSurface, validateNormalizedEventExport } from "@openclawbrain/contracts";
7
7
  import { classifyFeedbackSignalContent, describeNormalizedEventExportObservability } from "@openclawbrain/event-export";
8
8
  import { DEFAULT_TEACHER_SUPERVISION_STALE_AFTER_MS, advanceAlwaysOnLearningRuntime, buildTeacherSupervisionArtifactsFromNormalizedEventExport, createAlwaysOnLearningRuntimeState, describeAlwaysOnLearningRuntimeState, materializeAlwaysOnLearningCandidatePack, materializeCandidatePackFromNormalizedEventExport } from "@openclawbrain/learner";
9
9
  import { LEARNING_SPINE_LOG_LAYOUT, activatePack, describeActivationObservability, describeActivationTarget, describePackCompileTarget, inspectActivationState, loadPackFromActivation, promoteCandidatePack, readLearningSpineLogEntries, rollbackActivePack, stageCandidatePack } from "@openclawbrain/pack-format";
10
10
  import { appendLearningUpdateLogs, appendServeTimeRouteDecisionLog } from "./learning-spine.js";
11
+ import { buildFeedbackSemanticMetadata, buildInteractionSemanticMetadata } from "./semantic-metadata.js";
11
12
  import { createTeacherLabeler } from "./teacher-labeler.js";
12
13
  export { createHttpOllamaTeacherLabelerClient, createOllamaTeacherLabeler, createTeacherLabeler } from "./teacher-labeler.js";
13
14
  const DEFAULT_AGENT_ID = "openclaw-runtime";
@@ -19,6 +20,7 @@ const RECORDED_SESSION_BUNDLE_CONTRACT = "recorded_session_replay_bundle.v1";
19
20
  const RUNTIME_EVENT_EXPORT_BUNDLE_CONTRACT = "normalized_event_export_bundle.v1";
20
21
  const DEFAULT_ATTACH_STATUS_MESSAGE = "openclaw attach status probe";
21
22
  const DEFAULT_ATTACH_STATUS_RUNTIME_HINTS = ["attach", "status", "probe"];
23
+ const BRAIN_SERVE_HOT_PATH_TIMING_DETAIL = "Measured inside compileRuntimeContext before serve-route logging; includes serve-path normalization, active-pack lookup, structural-budget resolution, route/candidate selection, and prompt assembly when run; excludes background scanner/embedder/teacher work, promotion, and runtime event-export writes.";
22
24
  export const RUNTIME_EVENT_EXPORT_BUNDLE_LAYOUT = {
23
25
  manifest: "manifest.json",
24
26
  payload: "normalized-event-export.json"
@@ -1058,6 +1060,7 @@ export function resolveAsyncTeacherLiveLoopSnapshotPath(activationRoot) {
1058
1060
  export const WATCH_STATE_DIRNAME = "watch";
1059
1061
  export const WATCH_SESSION_TAIL_CURSOR_BASENAME = "session-tail-cursor.json";
1060
1062
  export const WATCH_TEACHER_SNAPSHOT_BASENAME = "teacher-snapshot.json";
1063
+ export const DEFAULT_WATCH_POLL_INTERVAL_SECONDS = 30;
1061
1064
  function isAsyncTeacherLiveLoopSnapshot(value) {
1062
1065
  if (value === null || typeof value !== "object") {
1063
1066
  return false;
@@ -1092,6 +1095,94 @@ function cloneWatchTeacherSnapshotFailure(value) {
1092
1095
  at: value.at
1093
1096
  };
1094
1097
  }
1098
+ function buildUnavailableLastObservedDelta(explanation) {
1099
+ return {
1100
+ available: false,
1101
+ observedAt: null,
1102
+ exported: null,
1103
+ labeled: null,
1104
+ promoted: null,
1105
+ served: null,
1106
+ latestPackTransition: null,
1107
+ explanation
1108
+ };
1109
+ }
1110
+ function cloneLastObservedDelta(value) {
1111
+ if (value === null || value === undefined || typeof value !== "object") {
1112
+ return buildUnavailableLastObservedDelta("last observed delta is unavailable");
1113
+ }
1114
+ const transition = value.latestPackTransition;
1115
+ const latestPackTransition = transition !== null &&
1116
+ transition !== undefined &&
1117
+ (transition.kind === "staged_candidate" || transition.kind === "promoted_active") &&
1118
+ typeof transition.toPackId === "string" &&
1119
+ transition.toPackId.length > 0 &&
1120
+ (transition.fromPackId === null || (typeof transition.fromPackId === "string" && transition.fromPackId.length > 0))
1121
+ ? {
1122
+ kind: transition.kind,
1123
+ fromPackId: transition.fromPackId,
1124
+ toPackId: transition.toPackId
1125
+ }
1126
+ : null;
1127
+ const available = value.available === true;
1128
+ return {
1129
+ available,
1130
+ observedAt: typeof value.observedAt === "string" ? value.observedAt : null,
1131
+ exported: available && typeof value.exported === "boolean" ? value.exported : null,
1132
+ labeled: available && typeof value.labeled === "boolean" ? value.labeled : null,
1133
+ promoted: available && typeof value.promoted === "boolean" ? value.promoted : null,
1134
+ served: available && typeof value.served === "boolean" ? value.served : null,
1135
+ latestPackTransition,
1136
+ explanation: typeof value.explanation === "string" && value.explanation.trim().length > 0
1137
+ ? value.explanation
1138
+ : "last observed delta is unavailable"
1139
+ };
1140
+ }
1141
+ function cloneWatchEmbedInstrumentationPoint(value) {
1142
+ if (value === null || value === undefined || typeof value !== "object") {
1143
+ return null;
1144
+ }
1145
+ const candidate = value;
1146
+ if (candidate.slot !== null &&
1147
+ candidate.slot !== "candidate" &&
1148
+ candidate.slot !== "active") {
1149
+ return null;
1150
+ }
1151
+ return {
1152
+ slot: candidate.slot ?? null,
1153
+ packId: typeof candidate.packId === "string" ? candidate.packId : null,
1154
+ runtimeEmbedderPresent: candidate.runtimeEmbedderPresent === true,
1155
+ runtimeEmbedderModel: typeof candidate.runtimeEmbedderModel === "string" ? candidate.runtimeEmbedderModel : null,
1156
+ vectorEntryCount: typeof candidate.vectorEntryCount === "number" ? candidate.vectorEntryCount : null,
1157
+ numericEmbeddingEntryCount: typeof candidate.numericEmbeddingEntryCount === "number" ? candidate.numericEmbeddingEntryCount : null,
1158
+ embeddingModels: Array.isArray(candidate.embeddingModels)
1159
+ ? candidate.embeddingModels.filter((model) => typeof model === "string")
1160
+ : [],
1161
+ error: typeof candidate.error === "string" ? candidate.error : null
1162
+ };
1163
+ }
1164
+ function cloneWatchEmbedInstrumentationTrace(value) {
1165
+ if (value === null || value === undefined || typeof value !== "object") {
1166
+ return null;
1167
+ }
1168
+ const candidate = value;
1169
+ const beforeCandidateMaterialization = cloneWatchEmbedInstrumentationPoint(candidate.beforeCandidateMaterialization);
1170
+ if (beforeCandidateMaterialization === null || typeof candidate.observedAt !== "string") {
1171
+ return null;
1172
+ }
1173
+ return {
1174
+ observedAt: candidate.observedAt,
1175
+ candidatePackId: typeof candidate.candidatePackId === "string" ? candidate.candidatePackId : null,
1176
+ promotionAllowed: typeof candidate.promotionAllowed === "boolean" ? candidate.promotionAllowed : null,
1177
+ promotionFindings: Array.isArray(candidate.promotionFindings)
1178
+ ? candidate.promotionFindings.filter((finding) => typeof finding === "string")
1179
+ : [],
1180
+ beforeCandidateMaterialization,
1181
+ afterCandidateMaterialization: cloneWatchEmbedInstrumentationPoint(candidate.afterCandidateMaterialization),
1182
+ afterStage: cloneWatchEmbedInstrumentationPoint(candidate.afterStage),
1183
+ afterPromote: cloneWatchEmbedInstrumentationPoint(candidate.afterPromote)
1184
+ };
1185
+ }
1095
1186
  function cloneRuntimeEventExportScannerCheckpoint(value) {
1096
1187
  return structuredClone(value);
1097
1188
  }
@@ -1159,6 +1250,11 @@ function normalizeWatchTeacherSnapshotFromValue(value, snapshot, sourcePath) {
1159
1250
  : typeof value.updatedAt === "string"
1160
1251
  ? value.updatedAt
1161
1252
  : snapshot.diagnostics.lastProcessedAt ?? new Date(0).toISOString(),
1253
+ pollIntervalSeconds: typeof value.pollIntervalSeconds === "number" &&
1254
+ Number.isInteger(value.pollIntervalSeconds) &&
1255
+ value.pollIntervalSeconds > 0
1256
+ ? value.pollIntervalSeconds
1257
+ : DEFAULT_WATCH_POLL_INTERVAL_SECONDS,
1162
1258
  scanRoot: typeof value.scanRoot === "string" ? value.scanRoot : defaultScanRoot,
1163
1259
  sessionTailCursorPath: typeof value.sessionTailCursorPath === "string"
1164
1260
  ? value.sessionTailCursorPath
@@ -1193,6 +1289,8 @@ function normalizeWatchTeacherSnapshotFromValue(value, snapshot, sourcePath) {
1193
1289
  teacher: value.teacher ?? buildWatchTeacherSnapshotTeacherSummary(snapshot),
1194
1290
  learning: value.learning ?? buildWatchTeacherSnapshotLearningSummary(snapshot, typeof value.lastHandledMaterializationPackId === "string" ? value.lastHandledMaterializationPackId : null),
1195
1291
  labeling: value.labeling ?? buildWatchTeacherSnapshotLabelingSummary(snapshot),
1292
+ lastObservedDelta: cloneLastObservedDelta(value.lastObservedDelta),
1293
+ embedInstrumentation: cloneWatchEmbedInstrumentationTrace(value.embedInstrumentation),
1196
1294
  failure: cloneWatchTeacherSnapshotFailure(value.failure),
1197
1295
  snapshot
1198
1296
  };
@@ -1250,6 +1348,8 @@ export function loadWatchTeacherSnapshotState(snapshotPath) {
1250
1348
  if (!existsSync(resolvedPath)) {
1251
1349
  return {
1252
1350
  lastHandledMaterializationPackId: null,
1351
+ lastObservedDelta: buildUnavailableLastObservedDelta("no watch teacher snapshot is visible for the latest observed cycle"),
1352
+ embedInstrumentation: null,
1253
1353
  snapshot: null,
1254
1354
  error: null
1255
1355
  };
@@ -1261,6 +1361,8 @@ export function loadWatchTeacherSnapshotState(snapshotPath) {
1261
1361
  catch (error) {
1262
1362
  return {
1263
1363
  lastHandledMaterializationPackId: null,
1364
+ lastObservedDelta: buildUnavailableLastObservedDelta("watch teacher snapshot could not be loaded"),
1365
+ embedInstrumentation: null,
1264
1366
  snapshot: null,
1265
1367
  error: error instanceof Error ? error.message : String(error)
1266
1368
  };
@@ -1268,6 +1370,8 @@ export function loadWatchTeacherSnapshotState(snapshotPath) {
1268
1370
  if (isWatchTeacherSnapshot(parsed)) {
1269
1371
  return {
1270
1372
  lastHandledMaterializationPackId: parsed.lastHandledMaterializationPackId,
1373
+ lastObservedDelta: cloneLastObservedDelta(parsed.lastObservedDelta),
1374
+ embedInstrumentation: cloneWatchEmbedInstrumentationTrace(parsed.embedInstrumentation),
1271
1375
  snapshot: loadAsyncTeacherLiveLoopSnapshotFromValue(parsed.snapshot),
1272
1376
  error: null
1273
1377
  };
@@ -1275,12 +1379,16 @@ export function loadWatchTeacherSnapshotState(snapshotPath) {
1275
1379
  if (isAsyncTeacherLiveLoopSnapshot(parsed)) {
1276
1380
  return {
1277
1381
  lastHandledMaterializationPackId: null,
1382
+ lastObservedDelta: buildUnavailableLastObservedDelta("raw async teacher snapshots do not record the last observed export/label/promotion delta"),
1383
+ embedInstrumentation: null,
1278
1384
  snapshot: loadAsyncTeacherLiveLoopSnapshotFromValue(parsed),
1279
1385
  error: null
1280
1386
  };
1281
1387
  }
1282
1388
  return {
1283
1389
  lastHandledMaterializationPackId: null,
1390
+ lastObservedDelta: buildUnavailableLastObservedDelta("watch teacher snapshot is invalid"),
1391
+ embedInstrumentation: null,
1284
1392
  snapshot: null,
1285
1393
  error: `watch teacher snapshot is invalid: ${resolvedPath}`
1286
1394
  };
@@ -1293,6 +1401,7 @@ export function persistWatchTeacherSnapshot(snapshotPath, input) {
1293
1401
  runtimeOwner: "openclaw",
1294
1402
  updatedAt: persistedAt,
1295
1403
  lastRunAt: input.lastRunAt,
1404
+ pollIntervalSeconds: input.pollIntervalSeconds,
1296
1405
  scanRoot: path.resolve(input.scanRoot),
1297
1406
  sessionTailCursorPath: path.resolve(input.sessionTailCursorPath),
1298
1407
  sessionTailCursorUpdatedAt: input.sessionTailCursorUpdatedAt,
@@ -1311,6 +1420,8 @@ export function persistWatchTeacherSnapshot(snapshotPath, input) {
1311
1420
  teacher: buildWatchTeacherSnapshotTeacherSummary(canonicalSnapshot),
1312
1421
  learning: buildWatchTeacherSnapshotLearningSummary(canonicalSnapshot, input.lastHandledMaterializationPackId),
1313
1422
  labeling: buildWatchTeacherSnapshotLabelingSummary(canonicalSnapshot),
1423
+ lastObservedDelta: cloneLastObservedDelta(input.lastObservedDelta),
1424
+ embedInstrumentation: cloneWatchEmbedInstrumentationTrace(input.embedInstrumentation),
1314
1425
  failure: cloneWatchTeacherSnapshotFailure(input.failure),
1315
1426
  snapshot: canonicalSnapshot
1316
1427
  };
@@ -1383,7 +1494,12 @@ export function buildRuntimeEventExportBundleManifest(input) {
1383
1494
  interactionCount: input.normalizedEventExport.provenance.interactionCount,
1384
1495
  feedbackCount: input.normalizedEventExport.provenance.feedbackCount,
1385
1496
  sourceStreams: [...input.normalizedEventExport.provenance.sourceStreams],
1386
- contracts: [...input.normalizedEventExport.provenance.contracts]
1497
+ contracts: [...input.normalizedEventExport.provenance.contracts],
1498
+ semanticSurface: structuredClone(input.normalizedEventExport.provenance.semanticSurface ??
1499
+ buildEventSemanticSurface([
1500
+ ...input.normalizedEventExport.interactionEvents,
1501
+ ...input.normalizedEventExport.feedbackEvents
1502
+ ]))
1387
1503
  },
1388
1504
  ...(input.scanner !== undefined ? { scanner: cloneScannerExportManifestOrNull(input.scanner) } : {})
1389
1505
  };
@@ -1426,7 +1542,8 @@ export function validateRuntimeEventExportBundleManifest(value, normalizedEventE
1426
1542
  if (rebuilt.payloadDigest !== value.payloadDigest) {
1427
1543
  errors.push("event export bundle payloadDigest does not match the supplied normalized event export");
1428
1544
  }
1429
- if (canonicalJson(rebuilt.summary) !== canonicalJson(value.summary)) {
1545
+ const expectedSummary = value.summary.semanticSurface === undefined ? { ...rebuilt.summary, semanticSurface: undefined } : rebuilt.summary;
1546
+ if (canonicalJson(expectedSummary) !== canonicalJson(value.summary)) {
1430
1547
  errors.push("event export bundle summary does not match the supplied normalized event export");
1431
1548
  }
1432
1549
  if (canonicalJson(rebuilt.scanner ?? null) !== canonicalJson(value.scanner ?? null)) {
@@ -1542,8 +1659,14 @@ export function buildNormalizedEventExportFromScannedEvents(input) {
1542
1659
  };
1543
1660
  }
1544
1661
  const normalizedEventExport = buildNormalizedEventExport({
1545
- interactionEvents: [...input.interactionEvents],
1546
- feedbackEvents: [...input.feedbackEvents]
1662
+ interactionEvents: input.interactionEvents.map((event) => ({
1663
+ ...event,
1664
+ semantic: event.semantic ?? buildInteractionSemanticMetadata("scanner_export", event.kind)
1665
+ })),
1666
+ feedbackEvents: input.feedbackEvents.map((event) => ({
1667
+ ...event,
1668
+ semantic: event.semantic ?? buildFeedbackSemanticMetadata("scanner_export", event.kind)
1669
+ }))
1547
1670
  });
1548
1671
  const exportErrors = validateNormalizedEventExport(normalizedEventExport);
1549
1672
  if (exportErrors.length > 0) {
@@ -2396,17 +2519,53 @@ export function formatPromptContext(compileResponse) {
2396
2519
  function resolveActivationRootForFailure(value) {
2397
2520
  return path.resolve(normalizeOptionalString(value) ?? ".");
2398
2521
  }
2399
- function failOpenCompileResult(error, activationRoot) {
2522
+ function monotonicClockNs() {
2523
+ return process.hrtime.bigint();
2524
+ }
2525
+ function elapsedMsFrom(startedAtNs, endedAtNs = monotonicClockNs()) {
2526
+ return Number(endedAtNs - startedAtNs) / 1_000_000;
2527
+ }
2528
+ function roundHotPathTimingMs(value) {
2529
+ return Math.round(value * 1_000) / 1_000;
2530
+ }
2531
+ function buildUnavailableBrainServeHotPathTiming(detail) {
2532
+ return {
2533
+ scope: "brain_serve_hot_path_only",
2534
+ totalMs: null,
2535
+ routeSelectionMs: null,
2536
+ promptAssemblyMs: null,
2537
+ otherMs: null,
2538
+ backgroundWorkIncluded: false,
2539
+ detail
2540
+ };
2541
+ }
2542
+ function buildBrainServeHotPathTiming(input) {
2543
+ const totalMs = roundHotPathTimingMs(input.totalMs);
2544
+ const routeSelectionMs = input.routeSelectionMs === null ? null : roundHotPathTimingMs(input.routeSelectionMs);
2545
+ const promptAssemblyMs = input.promptAssemblyMs === null ? null : roundHotPathTimingMs(input.promptAssemblyMs);
2546
+ const otherMs = roundHotPathTimingMs(Math.max(0, input.totalMs - (input.routeSelectionMs ?? 0) - (input.promptAssemblyMs ?? 0)));
2547
+ return {
2548
+ scope: "brain_serve_hot_path_only",
2549
+ totalMs,
2550
+ routeSelectionMs,
2551
+ promptAssemblyMs,
2552
+ otherMs,
2553
+ backgroundWorkIncluded: false,
2554
+ detail: BRAIN_SERVE_HOT_PATH_TIMING_DETAIL
2555
+ };
2556
+ }
2557
+ function failOpenCompileResult(error, activationRoot, timing = buildUnavailableBrainServeHotPathTiming("serve-path timing was unavailable")) {
2400
2558
  return {
2401
2559
  ok: false,
2402
2560
  fallbackToStaticContext: true,
2403
2561
  hardRequirementViolated: false,
2404
2562
  activationRoot: path.resolve(activationRoot),
2405
2563
  error: toErrorMessage(error),
2406
- brainContext: ""
2564
+ brainContext: "",
2565
+ timing
2407
2566
  };
2408
2567
  }
2409
- function classifyCompileFailure(error, activationRoot) {
2568
+ function classifyCompileFailure(error, activationRoot, timing = buildUnavailableBrainServeHotPathTiming("serve-path timing was unavailable")) {
2410
2569
  const resolvedActivationRoot = path.resolve(activationRoot);
2411
2570
  try {
2412
2571
  const inspection = inspectActivationState(resolvedActivationRoot);
@@ -2419,14 +2578,15 @@ function classifyCompileFailure(error, activationRoot) {
2419
2578
  hardRequirementViolated: true,
2420
2579
  activationRoot: resolvedActivationRoot,
2421
2580
  error: `Learned-routing hotpath hard requirement violated for active pack ${active.packId} (routerIdentity=${active.routerIdentity ?? "null"}): ${failureReason}`,
2422
- brainContext: ""
2581
+ brainContext: "",
2582
+ timing
2423
2583
  };
2424
2584
  }
2425
2585
  }
2426
2586
  catch {
2427
- return failOpenCompileResult(error, resolvedActivationRoot);
2587
+ return failOpenCompileResult(error, resolvedActivationRoot, timing);
2428
2588
  }
2429
- return failOpenCompileResult(error, resolvedActivationRoot);
2589
+ return failOpenCompileResult(error, resolvedActivationRoot, timing);
2430
2590
  }
2431
2591
  function uniqueNotes(notes) {
2432
2592
  return [...new Set(notes.filter((note) => note.length > 0))];
@@ -2480,6 +2640,11 @@ function appendCompileServeRouteDecisionLog(input) {
2480
2640
  if (input.compileInput._suppressServeLog) {
2481
2641
  return;
2482
2642
  }
2643
+ if (!input.compileResult.ok && input.userMessage.length === 0) {
2644
+ // Invalid/partial invocation envelopes should fail open without paying for
2645
+ // serve-time route log writes on the live compile hot path.
2646
+ return;
2647
+ }
2483
2648
  const recordedAt = new Date().toISOString();
2484
2649
  const sessionId = normalizeServeRouteChannel(input.compileInput.sessionId) ?? `ext-compile-${Date.now()}`;
2485
2650
  const channel = normalizeServeRouteChannel(input.compileInput.channel) ?? "extension";
@@ -2751,6 +2916,7 @@ export function resolveActivePackForCompile(activationRoot) {
2751
2916
  };
2752
2917
  }
2753
2918
  export function compileRuntimeContext(input) {
2919
+ const totalStartedAtNs = monotonicClockNs();
2754
2920
  const fallbackActivationRoot = resolveActivationRootForFailure(input.activationRoot);
2755
2921
  let activationRoot = fallbackActivationRoot;
2756
2922
  let agentId = process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
@@ -2759,6 +2925,10 @@ export function compileRuntimeContext(input) {
2759
2925
  let userMessage = "";
2760
2926
  let maxContextChars;
2761
2927
  let mode = "heuristic";
2928
+ let routeSelectionStartedAtNs = null;
2929
+ let routeSelectionMs = null;
2930
+ let promptAssemblyStartedAtNs = null;
2931
+ let promptAssemblyMs = null;
2762
2932
  let result;
2763
2933
  try {
2764
2934
  activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
@@ -2773,7 +2943,11 @@ export function compileRuntimeContext(input) {
2773
2943
  mode = normalizeMode(input.mode);
2774
2944
  }
2775
2945
  catch (error) {
2776
- result = failOpenCompileResult(error, fallbackActivationRoot);
2946
+ result = failOpenCompileResult(error, fallbackActivationRoot, buildBrainServeHotPathTiming({
2947
+ totalMs: elapsedMsFrom(totalStartedAtNs),
2948
+ routeSelectionMs,
2949
+ promptAssemblyMs
2950
+ }));
2777
2951
  appendCompileServeRouteDecisionLog({
2778
2952
  compileInput: input,
2779
2953
  activationRoot: result.activationRoot,
@@ -2785,6 +2959,7 @@ export function compileRuntimeContext(input) {
2785
2959
  try {
2786
2960
  const target = resolveActivePackForCompile(activationRoot);
2787
2961
  const resolvedBudget = resolveCompileBudget(target, input);
2962
+ routeSelectionStartedAtNs = monotonicClockNs();
2788
2963
  const compile = compileRuntimeFromActivation(activationRoot, {
2789
2964
  contract: CONTRACT_IDS.runtimeCompile,
2790
2965
  agentId,
@@ -2798,6 +2973,7 @@ export function compileRuntimeContext(input) {
2798
2973
  }, {
2799
2974
  ...(selectionMode !== undefined ? { selectionMode } : {})
2800
2975
  });
2976
+ routeSelectionMs = elapsedMsFrom(routeSelectionStartedAtNs);
2801
2977
  const compileResponse = {
2802
2978
  ...compile.response,
2803
2979
  diagnostics: {
@@ -2805,6 +2981,9 @@ export function compileRuntimeContext(input) {
2805
2981
  notes: uniqueNotes([...compile.response.diagnostics.notes, ...resolvedBudget.notes, "OpenClaw remains the runtime owner"])
2806
2982
  }
2807
2983
  };
2984
+ promptAssemblyStartedAtNs = monotonicClockNs();
2985
+ const brainContext = formatPromptContext(compileResponse);
2986
+ promptAssemblyMs = elapsedMsFrom(promptAssemblyStartedAtNs);
2808
2987
  result = {
2809
2988
  ok: true,
2810
2989
  fallbackToStaticContext: false,
@@ -2813,11 +2992,26 @@ export function compileRuntimeContext(input) {
2813
2992
  activePackId: compile.target.packId,
2814
2993
  packRootDir: path.resolve(target.activePointer.packRootDir),
2815
2994
  compileResponse,
2816
- brainContext: formatPromptContext(compileResponse)
2995
+ brainContext,
2996
+ timing: buildBrainServeHotPathTiming({
2997
+ totalMs: elapsedMsFrom(totalStartedAtNs),
2998
+ routeSelectionMs,
2999
+ promptAssemblyMs
3000
+ })
2817
3001
  };
2818
3002
  }
2819
3003
  catch (error) {
2820
- result = classifyCompileFailure(error, activationRoot);
3004
+ if (routeSelectionStartedAtNs !== null && routeSelectionMs === null) {
3005
+ routeSelectionMs = elapsedMsFrom(routeSelectionStartedAtNs);
3006
+ }
3007
+ if (promptAssemblyStartedAtNs !== null && promptAssemblyMs === null) {
3008
+ promptAssemblyMs = elapsedMsFrom(promptAssemblyStartedAtNs);
3009
+ }
3010
+ result = classifyCompileFailure(error, activationRoot, buildBrainServeHotPathTiming({
3011
+ totalMs: elapsedMsFrom(totalStartedAtNs),
3012
+ routeSelectionMs,
3013
+ promptAssemblyMs
3014
+ }));
2821
3015
  }
2822
3016
  appendCompileServeRouteDecisionLog({
2823
3017
  compileInput: input,
@@ -3020,6 +3214,7 @@ function buildAttachCompileStatus(result, observability, activePackId) {
3020
3214
  activePackId,
3021
3215
  usedLearnedRouteFn: null,
3022
3216
  routerIdentity: observability?.learnedRouteFn.routerIdentity ?? null,
3217
+ selectionDigest: null,
3023
3218
  initMode: observability?.initHandoff.initMode ?? null,
3024
3219
  handoffState: observability?.initHandoff.handoffState ?? null,
3025
3220
  seedSources: observability?.initHandoff.seedSources ?? [],
@@ -3028,6 +3223,7 @@ function buildAttachCompileStatus(result, observability, activePackId) {
3028
3223
  hardRequirementViolated: result.hardRequirementViolated,
3029
3224
  usedLearnedRouteFn: null
3030
3225
  }),
3226
+ timing: result.timing,
3031
3227
  notes: [],
3032
3228
  error: result.error
3033
3229
  };
@@ -3047,12 +3243,14 @@ function buildAttachCompileStatus(result, observability, activePackId) {
3047
3243
  activePackId: result.activePackId,
3048
3244
  usedLearnedRouteFn: result.compileResponse.diagnostics.usedLearnedRouteFn,
3049
3245
  routerIdentity: result.compileResponse.diagnostics.routerIdentity,
3246
+ selectionDigest: result.compileResponse.diagnostics.selectionDigest,
3050
3247
  initMode: readDiagnosticNoteValue(notes, "init_mode=") ?? observability?.initHandoff.initMode ?? null,
3051
3248
  handoffState: readDiagnosticNoteValue(notes, "handoff_state=") ?? observability?.initHandoff.handoffState ?? null,
3052
3249
  seedSources: readDiagnosticNoteList(notes, "seed_sources=").length > 0
3053
3250
  ? readDiagnosticNoteList(notes, "seed_sources=")
3054
3251
  : observability?.initHandoff.seedSources ?? [],
3055
3252
  contextAttribution,
3253
+ timing: result.timing,
3056
3254
  notes,
3057
3255
  error: null
3058
3256
  };
@@ -3447,6 +3645,7 @@ function buildCompileInteractionEvent(input) {
3447
3645
  runtimeOwner: "openclaw",
3448
3646
  stream: input.sourceStream
3449
3647
  },
3648
+ semantic: buildInteractionSemanticMetadata("runtime_turn", "memory_compiled"),
3450
3649
  packId: input.compileResult.compileResponse.packId,
3451
3650
  principal: buildRuntimeSelfPrincipal(input.turn),
3452
3651
  attribution: input.attribution
@@ -3482,6 +3681,7 @@ function buildDeliveryInteractionEvent(input) {
3482
3681
  runtimeOwner: "openclaw",
3483
3682
  stream: input.sourceStream
3484
3683
  },
3684
+ semantic: buildInteractionSemanticMetadata("runtime_turn", "message_delivered"),
3485
3685
  attribution: input.attribution,
3486
3686
  ...(input.compileResult.ok ? { packId: input.compileResult.compileResponse.packId } : {}),
3487
3687
  ...(messageId !== undefined ? { messageId } : {})
@@ -3531,6 +3731,7 @@ function buildFeedbackEvents(input) {
3531
3731
  stream: input.sourceStream
3532
3732
  },
3533
3733
  content,
3734
+ semantic: buildFeedbackSemanticMetadata("runtime_turn", kind),
3534
3735
  attribution: input.attribution,
3535
3736
  ...(messageId !== undefined ? { messageId } : {}),
3536
3737
  ...(principal === undefined ? {} : { principal }),
@@ -3980,6 +4181,7 @@ function buildRecordedSessionSeedExport(trace) {
3980
4181
  runtimeOwner: "openclaw",
3981
4182
  stream: sourceStream
3982
4183
  },
4184
+ semantic: buildInteractionSemanticMetadata("recorded_session_seed", "operator_override"),
3983
4185
  messageId: `${cue.cueId}-seed-message`
3984
4186
  });
3985
4187
  sequence += 1;
@@ -3996,6 +4198,7 @@ function buildRecordedSessionSeedExport(trace) {
3996
4198
  stream: sourceStream
3997
4199
  },
3998
4200
  content: cue.content,
4201
+ semantic: buildFeedbackSemanticMetadata("recorded_session_seed", cue.kind ?? "teaching"),
3999
4202
  relatedInteractionId: interaction.eventId
4000
4203
  });
4001
4204
  sequence += 1;
@@ -5005,18 +5208,22 @@ function summarizeBrainStateWithoutObservability(active, activation) {
5005
5208
  detail: activation.detail
5006
5209
  };
5007
5210
  }
5008
- function summarizeGraphWithoutObservability(active, activation) {
5211
+ function summarizeGraphWithoutObservability(input, active, activation) {
5212
+ const latestMaterialization = summarizeLatestGraphMaterialization(input, active, null);
5009
5213
  return {
5010
5214
  available: false,
5011
5215
  runtimePlasticitySource: null,
5012
5216
  structuralOps: null,
5217
+ connectDiagnostics: null,
5013
5218
  changed: null,
5219
+ blockCount: null,
5014
5220
  operationsApplied: [],
5015
5221
  liveBlockCount: null,
5016
5222
  prunedBlockCount: null,
5017
5223
  prePruneBlockCount: null,
5018
5224
  strongestBlockId: null,
5019
5225
  operatorSummary: null,
5226
+ latestMaterialization,
5020
5227
  detail: active === null
5021
5228
  ? activation.detail
5022
5229
  : `active pack ${active.packId} is pinned, but graph observability is unavailable`
@@ -5077,19 +5284,59 @@ function summarizeBrainState(active, observability) {
5077
5284
  detail
5078
5285
  };
5079
5286
  }
5080
- function summarizeGraphObservability(active, observability) {
5287
+ function summarizeLatestGraphMaterialization(input, active, activeGraphEvolution) {
5288
+ const loadedTeacherSurface = loadTeacherSurfaceFromInput(input);
5289
+ const latestMaterialization = loadedTeacherSurface?.snapshot.learner.lastMaterialization ?? null;
5290
+ const latestGraph = latestMaterialization?.candidate.summary.graphEvolutionLog ?? null;
5291
+ if (latestGraph !== null) {
5292
+ const packId = latestMaterialization?.candidate.summary.packId ?? latestGraph.packId;
5293
+ return {
5294
+ known: true,
5295
+ packId,
5296
+ changed: latestGraph.structuralEvolutionSummary.changed,
5297
+ connectDiagnostics: latestGraph.connectDiagnostics === null ? null : { ...latestGraph.connectDiagnostics },
5298
+ operatorSummary: latestGraph.structuralEvolutionSummary.operatorSummary,
5299
+ detail: `latest known materialization is ${packId} from the teacher snapshot`
5300
+ };
5301
+ }
5302
+ if (active !== null && activeGraphEvolution !== null) {
5303
+ return {
5304
+ known: true,
5305
+ packId: active.packId,
5306
+ changed: activeGraphEvolution.structuralEvolutionSummary.changed,
5307
+ connectDiagnostics: activeGraphEvolution.connectDiagnostics === null ? null : { ...activeGraphEvolution.connectDiagnostics },
5308
+ operatorSummary: activeGraphEvolution.structuralEvolutionSummary.operatorSummary,
5309
+ detail: `latest known materialization is the active pack ${active.packId}`
5310
+ };
5311
+ }
5312
+ return {
5313
+ known: false,
5314
+ packId: null,
5315
+ changed: null,
5316
+ connectDiagnostics: null,
5317
+ operatorSummary: null,
5318
+ detail: active === null
5319
+ ? "no active pack or materialized learner snapshot is visible"
5320
+ : `active pack ${active.packId} is pinned, but no latest materialization snapshot is visible`
5321
+ };
5322
+ }
5323
+ function summarizeGraphObservability(input, active, observability) {
5324
+ const latestMaterialization = summarizeLatestGraphMaterialization(input, active, observability.graphEvolutionLog);
5081
5325
  if (active === null) {
5082
5326
  return {
5083
5327
  available: false,
5084
5328
  runtimePlasticitySource: null,
5085
5329
  structuralOps: null,
5330
+ connectDiagnostics: null,
5086
5331
  changed: null,
5332
+ blockCount: null,
5087
5333
  operationsApplied: [],
5088
5334
  liveBlockCount: null,
5089
5335
  prunedBlockCount: null,
5090
5336
  prePruneBlockCount: null,
5091
5337
  strongestBlockId: null,
5092
5338
  operatorSummary: null,
5339
+ latestMaterialization,
5093
5340
  detail: "no active pack is pinned, so there is no structural graph surface to inspect"
5094
5341
  };
5095
5342
  }
@@ -5099,13 +5346,16 @@ function summarizeGraphObservability(active, observability) {
5099
5346
  available: false,
5100
5347
  runtimePlasticitySource: observability.graphDynamics.runtimePlasticitySource,
5101
5348
  structuralOps: null,
5349
+ connectDiagnostics: null,
5102
5350
  changed: null,
5351
+ blockCount: null,
5103
5352
  operationsApplied: [],
5104
5353
  liveBlockCount: null,
5105
5354
  prunedBlockCount: null,
5106
5355
  prePruneBlockCount: null,
5107
5356
  strongestBlockId: null,
5108
5357
  operatorSummary: null,
5358
+ latestMaterialization,
5109
5359
  detail: "active pack is present, but the graph evolution log is missing from activation observability"
5110
5360
  };
5111
5361
  }
@@ -5113,13 +5363,16 @@ function summarizeGraphObservability(active, observability) {
5113
5363
  available: true,
5114
5364
  runtimePlasticitySource: observability.graphDynamics.runtimePlasticitySource,
5115
5365
  structuralOps: { ...graphEvolution.structuralOps },
5366
+ connectDiagnostics: graphEvolution.connectDiagnostics === null ? null : { ...graphEvolution.connectDiagnostics },
5116
5367
  changed: graphEvolution.structuralEvolutionSummary.changed,
5368
+ blockCount: graphEvolution.blockCount,
5117
5369
  operationsApplied: [...graphEvolution.structuralEvolutionSummary.operationsApplied],
5118
5370
  liveBlockCount: graphEvolution.structuralEvolutionSummary.liveBlockCount,
5119
5371
  prunedBlockCount: graphEvolution.structuralEvolutionSummary.prunedBlockCount,
5120
5372
  prePruneBlockCount: graphEvolution.structuralEvolutionSummary.prePruneBlockCount,
5121
5373
  strongestBlockId: graphEvolution.strongestBlockId,
5122
5374
  operatorSummary: graphEvolution.structuralEvolutionSummary.operatorSummary,
5375
+ latestMaterialization,
5123
5376
  detail: graphEvolution.structuralEvolutionSummary.changed
5124
5377
  ? graphEvolution.structuralEvolutionSummary.operatorSummary
5125
5378
  : "active pack graph is stable with no structural evolution beyond the current promoted artifact"
@@ -5136,6 +5389,7 @@ function summarizeServePath(compile) {
5136
5389
  usedLearnedRouteFn: null,
5137
5390
  routerIdentity: null,
5138
5391
  selectionMode: null,
5392
+ selectionDigest: null,
5139
5393
  refreshStatus: null,
5140
5394
  freshnessChecksum: null,
5141
5395
  requestedBudgetStrategy: null,
@@ -5151,6 +5405,7 @@ function summarizeServePath(compile) {
5151
5405
  usedLearnedRouteFn: null,
5152
5406
  unprobed: true
5153
5407
  }),
5408
+ timing: buildUnavailableBrainServeHotPathTiming("serve-path timing is unavailable because the hot path was not probed"),
5154
5409
  error: null
5155
5410
  };
5156
5411
  }
@@ -5163,6 +5418,7 @@ function summarizeServePath(compile) {
5163
5418
  usedLearnedRouteFn: compile.usedLearnedRouteFn,
5164
5419
  routerIdentity: compile.routerIdentity,
5165
5420
  selectionMode: null,
5421
+ selectionDigest: null,
5166
5422
  refreshStatus: null,
5167
5423
  freshnessChecksum: null,
5168
5424
  requestedBudgetStrategy: null,
@@ -5173,6 +5429,7 @@ function summarizeServePath(compile) {
5173
5429
  structuralBudgetPressures: null,
5174
5430
  structuralDecision,
5175
5431
  contextAttribution: compile.contextAttribution,
5432
+ timing: compile.timing,
5176
5433
  error: compile.error
5177
5434
  };
5178
5435
  }
@@ -5184,6 +5441,7 @@ function summarizeServePath(compile) {
5184
5441
  usedLearnedRouteFn: compile.usedLearnedRouteFn,
5185
5442
  routerIdentity: compile.routerIdentity,
5186
5443
  selectionMode: readDiagnosticNoteValue(compile.notes, "selection_mode="),
5444
+ selectionDigest: compile.selectionDigest,
5187
5445
  refreshStatus: readDiagnosticNoteValue(compile.notes, "router_refresh_status="),
5188
5446
  freshnessChecksum: readDiagnosticNoteValue(compile.notes, "router_freshness_checksum="),
5189
5447
  requestedBudgetStrategy: readDiagnosticNoteValue(compile.notes, "requested_budget_strategy="),
@@ -5195,6 +5453,7 @@ function summarizeServePath(compile) {
5195
5453
  structuralBudgetPressures: readDiagnosticNoteValue(compile.notes, "structural_budget_pressures="),
5196
5454
  structuralDecision,
5197
5455
  contextAttribution: compile.contextAttribution,
5456
+ timing: compile.timing,
5198
5457
  error: compile.error
5199
5458
  };
5200
5459
  }
@@ -5203,12 +5462,7 @@ function probeOperatorServePath(activationRoot, observability, activePackId) {
5203
5462
  const compile = compileInput === null ? null : buildAttachCompileStatus(compileRuntimeContext(compileInput), observability, activePackId);
5204
5463
  return summarizeServePath(compile);
5205
5464
  }
5206
- function loadOperatorEventExport(input) {
5207
- const eventExportPath = normalizeOptionalString(input.eventExportPath);
5208
- if (eventExportPath === undefined) {
5209
- return null;
5210
- }
5211
- const resolvedPath = path.resolve(eventExportPath);
5465
+ function loadOperatorEventExportFromPath(resolvedPath) {
5212
5466
  const stats = statSync(resolvedPath);
5213
5467
  if (stats.isDirectory()) {
5214
5468
  const bundle = loadRuntimeEventExportBundle(resolvedPath);
@@ -5231,6 +5485,44 @@ function loadOperatorEventExport(input) {
5231
5485
  exportedAt: null
5232
5486
  };
5233
5487
  }
5488
+ function resolveOperatorEventExportScanRoots(input) {
5489
+ const activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
5490
+ const teacherSurface = loadTeacherSurfaceFromInput(input);
5491
+ const teacherScanRoot = normalizeOptionalString(teacherSurface?.watchSnapshot?.scanRoot);
5492
+ return uniqueStringsInOrder([
5493
+ teacherScanRoot === undefined ? undefined : path.resolve(teacherScanRoot),
5494
+ path.join(activationRoot, "event-exports")
5495
+ ].filter((value) => value !== undefined));
5496
+ }
5497
+ function loadLatestOperatorEventExportFromScanRoots(scanRoots) {
5498
+ let latest = null;
5499
+ for (const scanRoot of scanRoots) {
5500
+ const discovered = discoverRuntimeEventExportBundles(scanRoot);
5501
+ const candidate = discovered.bundles[discovered.bundles.length - 1] ?? null;
5502
+ if (candidate === null) {
5503
+ continue;
5504
+ }
5505
+ if (latest === null || compareRuntimeEventExportScannerBundleCursor(latest.cursor, candidate.cursor) < 0) {
5506
+ latest = candidate;
5507
+ }
5508
+ }
5509
+ if (latest === null) {
5510
+ return null;
5511
+ }
5512
+ return {
5513
+ sourcePath: latest.descriptor.rootDir,
5514
+ sourceKind: "bundle_root",
5515
+ normalizedEventExport: latest.descriptor.normalizedEventExport,
5516
+ exportedAt: latest.descriptor.manifest.exportedAt
5517
+ };
5518
+ }
5519
+ function loadOperatorEventExport(input) {
5520
+ const eventExportPath = normalizeOptionalString(input.eventExportPath);
5521
+ if (eventExportPath !== undefined) {
5522
+ return loadOperatorEventExportFromPath(path.resolve(eventExportPath));
5523
+ }
5524
+ return loadLatestOperatorEventExportFromScanRoots(resolveOperatorEventExportScanRoots(input));
5525
+ }
5234
5526
  function summarizePrincipalItem(event) {
5235
5527
  if (event.principal === undefined) {
5236
5528
  return null;
@@ -5392,25 +5684,59 @@ function summarizeSupervision(input) {
5392
5684
  };
5393
5685
  }
5394
5686
  function loadTeacherSurfaceFromInput(input) {
5395
- const teacherSnapshotPath = normalizeOptionalString(input.teacherSnapshotPath);
5396
- if (teacherSnapshotPath === undefined) {
5687
+ const teacherSnapshotPath = resolveOperatorTeacherSnapshotPath(input.activationRoot, normalizeOptionalString(input.teacherSnapshotPath) ?? null);
5688
+ if (teacherSnapshotPath === null) {
5397
5689
  return null;
5398
5690
  }
5399
5691
  return loadTeacherSurface(teacherSnapshotPath);
5400
5692
  }
5693
+ function summarizeTeacherLoopWatchState(input) {
5694
+ if (input.sourceKind !== "watch_snapshot" || input.watchSnapshot === null) {
5695
+ return {
5696
+ snapshotUpdatedAt: null,
5697
+ lastWatchHeartbeatAt: null,
5698
+ pollIntervalSeconds: null,
5699
+ watchState: input.sourceKind === "async_snapshot" ? "snapshot_only" : "not_visible"
5700
+ };
5701
+ }
5702
+ const lastWatchHeartbeatAt = input.watchSnapshot.snapshot.runtime?.lastHeartbeatAt ?? input.watchSnapshot.lastRunAt;
5703
+ const pollIntervalSeconds = input.watchSnapshot.pollIntervalSeconds;
5704
+ if (lastWatchHeartbeatAt === null) {
5705
+ return {
5706
+ snapshotUpdatedAt: input.watchSnapshot.updatedAt,
5707
+ lastWatchHeartbeatAt: null,
5708
+ pollIntervalSeconds,
5709
+ watchState: "snapshot_only"
5710
+ };
5711
+ }
5712
+ const lagMs = Date.parse(input.observedAt) - Date.parse(lastWatchHeartbeatAt);
5713
+ const staleAfterMs = pollIntervalSeconds * 2000 + 15_000;
5714
+ return {
5715
+ snapshotUpdatedAt: input.watchSnapshot.updatedAt,
5716
+ lastWatchHeartbeatAt,
5717
+ pollIntervalSeconds,
5718
+ watchState: Number.isFinite(lagMs) && lagMs >= 0 && lagMs <= staleAfterMs ? "watching" : "stale_snapshot"
5719
+ };
5720
+ }
5401
5721
  function summarizeTeacherLoop(input) {
5402
5722
  const loaded = loadTeacherSurfaceFromInput(input);
5403
- if (loaded === null && normalizeOptionalString(input.teacherSnapshotPath) === undefined) {
5723
+ const teacherSnapshotPath = resolveOperatorTeacherSnapshotPath(input.activationRoot, normalizeOptionalString(input.teacherSnapshotPath) ?? null);
5724
+ const unavailableFromMissing = buildUnavailableLastObservedDelta("no watch teacher snapshot is visible for the latest observed cycle");
5725
+ const unavailableFromAsync = buildUnavailableLastObservedDelta("raw async teacher snapshots do not record the last observed export/label/promotion delta");
5726
+ if (loaded === null && teacherSnapshotPath === null) {
5404
5727
  return {
5405
5728
  available: false,
5406
5729
  sourcePath: null,
5407
5730
  sourceKind: "missing",
5731
+ snapshotUpdatedAt: null,
5408
5732
  lastRunAt: null,
5409
5733
  lastNoOpReason: "unavailable",
5410
5734
  latestFreshness: "unavailable",
5411
5735
  startedAt: null,
5412
5736
  lastHeartbeatAt: null,
5413
5737
  lastScanAt: null,
5738
+ pollIntervalSeconds: null,
5739
+ watchState: "not_visible",
5414
5740
  lastProcessedAt: null,
5415
5741
  artifactCount: null,
5416
5742
  queueDepth: null,
@@ -5431,22 +5757,25 @@ function summarizeTeacherLoop(input) {
5431
5757
  failureDetail: null,
5432
5758
  lastAppliedMaterializationJobId: null,
5433
5759
  lastMaterializedPackId: null,
5760
+ lastObservedDelta: unavailableFromMissing,
5434
5761
  notes: [],
5435
5762
  detail: "no teacher snapshot path supplied"
5436
5763
  };
5437
5764
  }
5438
5765
  if (loaded === null) {
5439
- const teacherSnapshotPath = normalizeOptionalString(input.teacherSnapshotPath);
5440
5766
  return {
5441
5767
  available: false,
5442
- sourcePath: teacherSnapshotPath === undefined ? null : path.resolve(teacherSnapshotPath),
5768
+ sourcePath: path.resolve(teacherSnapshotPath),
5443
5769
  sourceKind: "missing",
5770
+ snapshotUpdatedAt: null,
5444
5771
  lastRunAt: null,
5445
5772
  lastNoOpReason: "unavailable",
5446
5773
  latestFreshness: "unavailable",
5447
5774
  startedAt: null,
5448
5775
  lastHeartbeatAt: null,
5449
5776
  lastScanAt: null,
5777
+ pollIntervalSeconds: null,
5778
+ watchState: "not_visible",
5450
5779
  lastProcessedAt: null,
5451
5780
  artifactCount: null,
5452
5781
  queueDepth: null,
@@ -5467,22 +5796,31 @@ function summarizeTeacherLoop(input) {
5467
5796
  failureDetail: null,
5468
5797
  lastAppliedMaterializationJobId: null,
5469
5798
  lastMaterializedPackId: null,
5799
+ lastObservedDelta: unavailableFromMissing,
5470
5800
  notes: [],
5471
5801
  detail: "teacher snapshot could not be loaded"
5472
5802
  };
5473
5803
  }
5474
5804
  const snapshot = loaded.snapshot;
5475
5805
  const watchSnapshot = loaded.watchSnapshot;
5806
+ const watchState = summarizeTeacherLoopWatchState({
5807
+ observedAt: normalizeIsoTimestamp(input.updatedAt, "updatedAt", new Date().toISOString()),
5808
+ sourceKind: loaded.sourceKind,
5809
+ watchSnapshot
5810
+ });
5476
5811
  return {
5477
5812
  available: true,
5478
5813
  sourcePath: loaded.sourcePath,
5479
5814
  sourceKind: loaded.sourceKind,
5815
+ snapshotUpdatedAt: watchState.snapshotUpdatedAt,
5480
5816
  lastRunAt: watchSnapshot?.lastRunAt ?? snapshot.runtime?.lastHeartbeatAt ?? snapshot.diagnostics.lastProcessedAt ?? null,
5481
5817
  lastNoOpReason: snapshot.diagnostics.lastNoOpReason,
5482
5818
  latestFreshness: snapshot.diagnostics.latestFreshness,
5483
5819
  startedAt: snapshot.runtime?.startedAt ?? null,
5484
- lastHeartbeatAt: snapshot.runtime?.lastHeartbeatAt ?? null,
5820
+ lastHeartbeatAt: watchState.lastWatchHeartbeatAt ?? snapshot.runtime?.lastHeartbeatAt ?? null,
5485
5821
  lastScanAt: snapshot.runtime?.lastScanAt ?? null,
5822
+ pollIntervalSeconds: watchState.pollIntervalSeconds,
5823
+ watchState: watchState.watchState,
5486
5824
  lastProcessedAt: snapshot.diagnostics.lastProcessedAt,
5487
5825
  artifactCount: watchSnapshot?.teacher.artifactCount ?? snapshot.teacher.artifactCount,
5488
5826
  queueDepth: snapshot.queue.depth,
@@ -5506,12 +5844,95 @@ function summarizeTeacherLoop(input) {
5506
5844
  snapshot.learner.lastMaterialization?.jobId ??
5507
5845
  null,
5508
5846
  lastMaterializedPackId: snapshot.learner.lastMaterialization?.candidate.summary.packId ?? null,
5847
+ lastObservedDelta: loaded.sourceKind === "watch_snapshot" && watchSnapshot !== null
5848
+ ? cloneLastObservedDelta(watchSnapshot.lastObservedDelta)
5849
+ : unavailableFromAsync,
5509
5850
  notes: [...snapshot.diagnostics.notes],
5510
5851
  detail: loaded.sourceKind === "watch_snapshot"
5511
5852
  ? "canonical watch teacher snapshot loaded"
5512
5853
  : "raw async teacher snapshot loaded"
5513
5854
  };
5514
5855
  }
5856
+ function matchesActiveRouteFnLog(input) {
5857
+ if (input.activePackId !== null && input.entryPackId === input.activePackId) {
5858
+ return true;
5859
+ }
5860
+ if (input.routerChecksum !== null && input.entryRouterChecksum === input.routerChecksum) {
5861
+ return true;
5862
+ }
5863
+ return false;
5864
+ }
5865
+ function summarizeRouteFnFreshness(input) {
5866
+ if (input.activePackId === null) {
5867
+ return {
5868
+ available: false,
5869
+ activePackId: null,
5870
+ routerIdentity: input.learnedRouting.routerIdentity,
5871
+ routerChecksum: input.learnedRouting.routerChecksum,
5872
+ trainedAt: null,
5873
+ updatedAt: null,
5874
+ usedAt: null,
5875
+ lastDecisionAt: null,
5876
+ lastDecisionUsedLearnedRouteFn: null,
5877
+ detail: "no active pack is pinned, so there is no current route_fn to time"
5878
+ };
5879
+ }
5880
+ if (!input.learnedRouting.available) {
5881
+ return {
5882
+ available: false,
5883
+ activePackId: input.activePackId,
5884
+ routerIdentity: input.learnedRouting.routerIdentity,
5885
+ routerChecksum: input.learnedRouting.routerChecksum,
5886
+ trainedAt: input.learnedRouting.routerTrainedAt,
5887
+ updatedAt: null,
5888
+ usedAt: null,
5889
+ lastDecisionAt: null,
5890
+ lastDecisionUsedLearnedRouteFn: null,
5891
+ detail: input.learnedRouting.required
5892
+ ? `active pack ${input.activePackId} requires learned routing, but no route_fn artifact is available`
5893
+ : `active pack ${input.activePackId} does not require a learned route_fn`
5894
+ };
5895
+ }
5896
+ const updates = readLearningSpineLogEntries(input.activationRoot, "pgRouteUpdates");
5897
+ const decisions = readLearningSpineLogEntries(input.activationRoot, "serveTimeRouteDecisions");
5898
+ const updated = [...updates].reverse().find((entry) => matchesActiveRouteFnLog({
5899
+ activePackId: input.activePackId,
5900
+ routerChecksum: input.learnedRouting.routerChecksum,
5901
+ entryPackId: entry.nextPackId,
5902
+ entryRouterChecksum: entry.nextRouterChecksum
5903
+ }));
5904
+ const learnedUse = [...decisions].reverse().find((entry) => entry.usedLearnedRouteFn === true &&
5905
+ matchesActiveRouteFnLog({
5906
+ activePackId: input.activePackId,
5907
+ routerChecksum: input.learnedRouting.routerChecksum,
5908
+ entryPackId: entry.activePackId,
5909
+ entryRouterChecksum: entry.activePackRouterChecksum
5910
+ }));
5911
+ const lastDecision = [...decisions].reverse().find((entry) => matchesActiveRouteFnLog({
5912
+ activePackId: input.activePackId,
5913
+ routerChecksum: input.learnedRouting.routerChecksum,
5914
+ entryPackId: entry.activePackId,
5915
+ entryRouterChecksum: entry.activePackRouterChecksum
5916
+ }));
5917
+ return {
5918
+ available: true,
5919
+ activePackId: input.activePackId,
5920
+ routerIdentity: input.learnedRouting.routerIdentity,
5921
+ routerChecksum: input.learnedRouting.routerChecksum,
5922
+ trainedAt: input.learnedRouting.routerTrainedAt,
5923
+ updatedAt: updated?.recordedAt ?? null,
5924
+ usedAt: learnedUse?.recordedAt ?? null,
5925
+ lastDecisionAt: lastDecision?.recordedAt ?? null,
5926
+ lastDecisionUsedLearnedRouteFn: lastDecision?.usedLearnedRouteFn ?? null,
5927
+ detail: learnedUse !== undefined
5928
+ ? `active route_fn last served a learned turn at ${learnedUse.recordedAt}`
5929
+ : updated !== undefined
5930
+ ? `active route_fn was updated at ${updated.recordedAt}, but no learned serve decision for the current pack is visible yet`
5931
+ : input.learnedRouting.routerTrainedAt !== null
5932
+ ? `active route_fn was trained at ${input.learnedRouting.routerTrainedAt}, but no matching update or serve-use log is visible yet`
5933
+ : `active pack ${input.activePackId} exposes a route_fn, but the train/update timestamps are not visible`
5934
+ };
5935
+ }
5515
5936
  function summarizeLearningBacklogState(plan, principalLagStatus) {
5516
5937
  if (!plan.bootstrapped && plan.pending.total === 0) {
5517
5938
  return "awaiting_first_export";
@@ -5567,7 +5988,8 @@ function summarizeAlwaysOnLearning(input, active) {
5567
5988
  status: "unavailable"
5568
5989
  };
5569
5990
  const loadedTeacherSurface = loadTeacherSurfaceFromInput(input);
5570
- if (loadedTeacherSurface === null && normalizeOptionalString(input.teacherSnapshotPath) === undefined) {
5991
+ const teacherSnapshotPath = resolveOperatorTeacherSnapshotPath(input.activationRoot, normalizeOptionalString(input.teacherSnapshotPath) ?? null);
5992
+ if (loadedTeacherSurface === null && teacherSnapshotPath === null) {
5571
5993
  return {
5572
5994
  available: false,
5573
5995
  sourcePath: null,
@@ -5600,10 +6022,9 @@ function summarizeAlwaysOnLearning(input, active) {
5600
6022
  };
5601
6023
  }
5602
6024
  if (loadedTeacherSurface === null) {
5603
- const teacherSnapshotPath = normalizeOptionalString(input.teacherSnapshotPath);
5604
6025
  return {
5605
6026
  available: false,
5606
- sourcePath: teacherSnapshotPath === undefined ? null : path.resolve(teacherSnapshotPath),
6027
+ sourcePath: path.resolve(teacherSnapshotPath),
5607
6028
  bootstrapped: null,
5608
6029
  mode: "unavailable",
5609
6030
  nextPriorityLane: "unavailable",
@@ -5858,6 +6279,65 @@ function summarizeCurrentProfileLastLearningUpdateAt(activationRoot, learning, t
5858
6279
  const updates = readLearningSpineLogEntries(activationRoot, "pgRouteUpdates");
5859
6280
  return updates.at(-1)?.recordedAt ?? teacherLoop.lastRunAt ?? learning.lastMaterializedAt ?? null;
5860
6281
  }
6282
+ function didCurrentProfileFirstExportOccur(report) {
6283
+ if ((report.active?.eventRange.count ?? 0) > 0) {
6284
+ return true;
6285
+ }
6286
+ if (report.supervision.exportedAt !== null) {
6287
+ return true;
6288
+ }
6289
+ if (report.learning.available && (report.learning.learnedRange?.count ?? 0) > 0) {
6290
+ return true;
6291
+ }
6292
+ if (!report.teacherLoop.available) {
6293
+ return false;
6294
+ }
6295
+ return ((report.teacherLoop.replayedBundleCount ?? 0) > 0 ||
6296
+ (report.teacherLoop.exportedBundleCount ?? 0) > 0 ||
6297
+ report.teacherLoop.lastProcessedAt !== null ||
6298
+ report.teacherLoop.lastMaterializedPackId !== null);
6299
+ }
6300
+ function summarizeCurrentProfilePassiveLearning(report, activePackId) {
6301
+ const firstExportOccurred = didCurrentProfileFirstExportOccur(report);
6302
+ const exportState = !firstExportOccurred
6303
+ ? "awaiting_first_export"
6304
+ : report.supervision.exportedAt !== null
6305
+ ? "latest_export_visible"
6306
+ : "history_only";
6307
+ const backlogState = report.learning.available && report.learning.backlogState !== "unavailable"
6308
+ ? report.learning.backlogState
6309
+ : "unknown";
6310
+ const detail = !firstExportOccurred
6311
+ ? report.teacherLoop.watchState === "watching"
6312
+ ? "watch heartbeat is fresh, but this activation root has not observed its first export yet"
6313
+ : "this activation root is still waiting for the first export before passive learning can advance"
6314
+ : backlogState === "unknown"
6315
+ ? "first export is proven, but passive backlog state is not visible from the current local artifacts"
6316
+ : report.teacherLoop.watchState === "watching"
6317
+ ? `watch heartbeat is fresh; passive backlog is ${backlogState} with live=${report.learning.pendingLive ?? 0} and backfill=${report.learning.pendingBackfill ?? 0}`
6318
+ : report.teacherLoop.watchState === "stale_snapshot"
6319
+ ? `last saved watch snapshot is stale; latest known passive backlog is ${backlogState}`
6320
+ : report.teacherLoop.watchState === "snapshot_only"
6321
+ ? `passive backlog is visible from the last saved snapshot: ${backlogState}`
6322
+ : `passive backlog is visible from the last known learner state: ${backlogState}`;
6323
+ return {
6324
+ learnerRunning: report.teacherLoop.watchState === "watching",
6325
+ firstExportOccurred,
6326
+ watchState: report.teacherLoop.watchState,
6327
+ exportState,
6328
+ backlogState,
6329
+ pendingLive: report.learning.available ? report.learning.pendingLive : null,
6330
+ pendingBackfill: report.learning.available ? report.learning.pendingBackfill : null,
6331
+ lastWatchHeartbeatAt: report.teacherLoop.lastHeartbeatAt,
6332
+ watchIntervalSeconds: report.teacherLoop.pollIntervalSeconds,
6333
+ lastExportAt: report.supervision.exportedAt,
6334
+ lastPromotionAt: report.promotion.lastPromotion.at,
6335
+ currentServingPackId: activePackId,
6336
+ lastMaterializedPackId: report.learning.lastMaterializedPackId ?? report.teacherLoop.lastMaterializedPackId,
6337
+ lastObservedDelta: cloneLastObservedDelta(report.teacherLoop.lastObservedDelta),
6338
+ detail
6339
+ };
6340
+ }
5861
6341
  function summarizeCurrentProfileBrainSummary(input) {
5862
6342
  const packId = input.activePackId ?? "unknown";
5863
6343
  if (input.activationState === "broken_install") {
@@ -5898,6 +6378,85 @@ function summarizeCurrentProfileBrainStatusLevel(input) {
5898
6378
  }
5899
6379
  return input.routeFreshness === "updated" ? "ok" : "warn";
5900
6380
  }
6381
+ function buildCurrentProfileTurnAttributionFromReport(report, policyMode, profileId) {
6382
+ if (report.servePath.state === "unprobed") {
6383
+ return null;
6384
+ }
6385
+ const brainStatus = report.servePath.state;
6386
+ const sessionId = "current-profile-status-probe";
6387
+ const channel = "operator_status";
6388
+ const createdAt = report.generatedAt;
6389
+ const sourceStream = "openclaw/operator/status";
6390
+ const packId = brainStatus === "serving_active_pack"
6391
+ ? report.servePath.activePackId ?? report.brain.activePackId ?? report.active?.packId ?? null
6392
+ : null;
6393
+ const routerIdentity = brainStatus === "serving_active_pack"
6394
+ ? report.servePath.routerIdentity ?? report.learnedRouting.routerIdentity ?? report.active?.routerIdentity ?? null
6395
+ : null;
6396
+ const usedLearnedRouteFn = brainStatus === "serving_active_pack" ? report.servePath.usedLearnedRouteFn : null;
6397
+ const selectionMode = brainStatus === "serving_active_pack" ? report.servePath.selectionMode : null;
6398
+ const selectionDigest = brainStatus === "serving_active_pack" ? report.servePath.selectionDigest : null;
6399
+ const contextAttribution = report.servePath.contextAttribution;
6400
+ const probeTurn = {
6401
+ sessionId,
6402
+ channel,
6403
+ sourceStream,
6404
+ userMessage: DEFAULT_ATTACH_STATUS_MESSAGE,
6405
+ createdAt,
6406
+ runtimeHints: [...DEFAULT_ATTACH_STATUS_RUNTIME_HINTS],
6407
+ profileSelector: "current_profile",
6408
+ profileId,
6409
+ brainAttachmentPolicy: policyMode
6410
+ };
6411
+ return {
6412
+ contract: CONTRACT_IDS.profileTurnAttribution,
6413
+ hostRuntimeOwner: "openclaw",
6414
+ profileSelector: "current_profile",
6415
+ profileId,
6416
+ brainAttachmentPolicy: policyMode,
6417
+ brainStatus,
6418
+ sessionId,
6419
+ channel,
6420
+ interactionEventId: deterministicEventId({
6421
+ source: sourceStream,
6422
+ activationRoot: report.activationRoot,
6423
+ createdAt,
6424
+ brainStatus,
6425
+ packId,
6426
+ routerIdentity,
6427
+ selectionDigest
6428
+ }),
6429
+ createdAt,
6430
+ packId,
6431
+ routerIdentity,
6432
+ usedLearnedRouteFn,
6433
+ selectionMode,
6434
+ selectionTiers: contextAttribution.selectionTiers,
6435
+ selectionDigest,
6436
+ contextFingerprint: buildRuntimeContextFingerprint({
6437
+ turn: probeTurn,
6438
+ sourceStream,
6439
+ profileSelector: "current_profile",
6440
+ brainAttachmentPolicy: policyMode,
6441
+ brainStatus,
6442
+ activePackId: packId,
6443
+ usedLearnedRouteFn,
6444
+ routerIdentity,
6445
+ selectionDigest
6446
+ }),
6447
+ selectedContextCount: contextAttribution.selectedContextCount,
6448
+ stableKernelBlockCount: contextAttribution.stableKernelBlockCount,
6449
+ brainCompiledBlockCount: contextAttribution.brainCompiledBlockCount,
6450
+ stableKernelSources: [...contextAttribution.stableKernelSources],
6451
+ brainCompiledSources: [...contextAttribution.brainCompiledSources],
6452
+ contextEvidence: contextAttribution.evidence === "unprobed" ? "stable_kernel_only" : contextAttribution.evidence,
6453
+ detail: brainStatus === "serving_active_pack"
6454
+ ? "current profile status probe compiled from the active pack with explicit route-function and block-source attribution"
6455
+ : brainStatus === "hard_fail"
6456
+ ? "current profile status probe hit a learned-route hard fail before serving context could compile"
6457
+ : "current profile status probe fail-opened to static context because no serving pack was available"
6458
+ };
6459
+ }
5901
6460
  function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId) {
5902
6461
  const attached = report.active !== null;
5903
6462
  const awaitingFirstExport = isAwaitingFirstExportSlot(report.active);
@@ -5907,6 +6466,7 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
5907
6466
  ? report.servePath.refreshStatus
5908
6467
  : "unknown";
5909
6468
  const activePackId = report.brain.activePackId ?? report.servePath.activePackId ?? report.active?.packId ?? null;
6469
+ const passiveLearning = summarizeCurrentProfilePassiveLearning(report, activePackId);
5910
6470
  const status = summarizeCurrentProfileBrainStatusLevel({
5911
6471
  attached,
5912
6472
  serveState: report.servePath.state,
@@ -5987,6 +6547,7 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
5987
6547
  failOpen: report.servePath.fallbackToStaticContext,
5988
6548
  awaitingFirstExport,
5989
6549
  structuralDecision: report.servePath.structuralDecision,
6550
+ timing: report.servePath.timing,
5990
6551
  detail: activationState === "broken_install"
5991
6552
  ? `current profile activation is broken: ${report.activation.detail}`
5992
6553
  : activationState === "stale_incomplete"
@@ -6005,7 +6566,8 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
6005
6566
  ? "current profile cannot serve because the learned-route or activation requirement hard-failed"
6006
6567
  : "current profile serve state has not been compile-probed yet"
6007
6568
  },
6008
- currentTurnAttribution: null
6569
+ passiveLearning,
6570
+ currentTurnAttribution: buildCurrentProfileTurnAttributionFromReport(report, policyMode, profileId)
6009
6571
  };
6010
6572
  }
6011
6573
  export function buildOperatorSurfaceReport(input) {
@@ -6049,6 +6611,34 @@ export function buildOperatorSurfaceReport(input) {
6049
6611
  learningPath: buildMissingLearningPathSummary(`activation observability is unavailable: ${inspectionError}`)
6050
6612
  };
6051
6613
  const servePath = probeOperatorServePath(activationRoot, observability, active?.packId ?? null);
6614
+ const learnedRouting = observability === null
6615
+ ? summarizeLearnedRoutingWithoutObservability(active)
6616
+ : {
6617
+ required: observability.learnedRouteFn.required,
6618
+ available: observability.learnedRouteFn.available,
6619
+ routerIdentity: observability.learnedRouteFn.routerIdentity,
6620
+ routeFnVersion: observability.learnedRouteFn.routeFnVersion,
6621
+ trainingMethod: observability.learnedRouteFn.trainingMethod,
6622
+ routerTrainedAt: observability.learnedRouteFn.routerTrainedAt,
6623
+ objective: observability.learnedRouteFn.objective,
6624
+ pgProfile: observability.learnedRouteFn.pgProfile,
6625
+ routerChecksum: observability.learnedRouteFn.routerChecksum,
6626
+ objectiveChecksum: observability.learnedRouteFn.objectiveChecksum,
6627
+ updateMechanism: observability.learnedRouteFn.updateMechanism,
6628
+ updateVersion: observability.learnedRouteFn.updateVersion,
6629
+ updateCount: observability.learnedRouteFn.updateCount,
6630
+ supervisionCount: observability.learnedRouteFn.supervisionCount,
6631
+ collectedLabelsTotal: observability.learnedRouteFn.collectedLabels?.total ?? null,
6632
+ freshnessChecksum: observability.learnedRouteFn.freshnessChecksum,
6633
+ handoffState: observability.initHandoff.handoffState,
6634
+ initMode: observability.initHandoff.initMode,
6635
+ seedStateVisible: observability.initHandoff.seedStateVisible
6636
+ };
6637
+ const routeFn = summarizeRouteFnFreshness({
6638
+ activationRoot,
6639
+ activePackId: active?.packId ?? null,
6640
+ learnedRouting
6641
+ });
6052
6642
  const reportBase = {
6053
6643
  generatedAt: updatedAt,
6054
6644
  activationRoot,
@@ -6061,32 +6651,12 @@ export function buildOperatorSurfaceReport(input) {
6061
6651
  candidateAheadBy: summarizeCandidateAheadBy(observability?.promotionFreshness.candidateAheadBy ?? null)
6062
6652
  },
6063
6653
  brain: observability === null ? summarizeBrainStateWithoutObservability(active, activation) : summarizeBrainState(active, observability),
6064
- graph: observability === null ? summarizeGraphWithoutObservability(active, activation) : summarizeGraphObservability(active, observability),
6654
+ graph: observability === null
6655
+ ? summarizeGraphWithoutObservability(input, active, activation)
6656
+ : summarizeGraphObservability(input, active, observability),
6065
6657
  labelFlow: activeObservability.labelFlow,
6066
6658
  learningPath: activeObservability.learningPath,
6067
- learnedRouting: observability === null
6068
- ? summarizeLearnedRoutingWithoutObservability(active)
6069
- : {
6070
- required: observability.learnedRouteFn.required,
6071
- available: observability.learnedRouteFn.available,
6072
- routerIdentity: observability.learnedRouteFn.routerIdentity,
6073
- routeFnVersion: observability.learnedRouteFn.routeFnVersion,
6074
- trainingMethod: observability.learnedRouteFn.trainingMethod,
6075
- routerTrainedAt: observability.learnedRouteFn.routerTrainedAt,
6076
- objective: observability.learnedRouteFn.objective,
6077
- pgProfile: observability.learnedRouteFn.pgProfile,
6078
- routerChecksum: observability.learnedRouteFn.routerChecksum,
6079
- objectiveChecksum: observability.learnedRouteFn.objectiveChecksum,
6080
- updateMechanism: observability.learnedRouteFn.updateMechanism,
6081
- updateVersion: observability.learnedRouteFn.updateVersion,
6082
- updateCount: observability.learnedRouteFn.updateCount,
6083
- supervisionCount: observability.learnedRouteFn.supervisionCount,
6084
- collectedLabelsTotal: observability.learnedRouteFn.collectedLabels?.total ?? null,
6085
- freshnessChecksum: observability.learnedRouteFn.freshnessChecksum,
6086
- handoffState: observability.initHandoff.handoffState,
6087
- initMode: observability.initHandoff.initMode,
6088
- seedStateVisible: observability.initHandoff.seedStateVisible
6089
- },
6659
+ learnedRouting,
6090
6660
  servePath,
6091
6661
  promotion: {
6092
6662
  allowed: inspection?.promotion.allowed ?? false,
@@ -6110,6 +6680,7 @@ export function buildOperatorSurfaceReport(input) {
6110
6680
  supervision: summarizeSupervision(input),
6111
6681
  learning: summarizeAlwaysOnLearning(input, active),
6112
6682
  teacherLoop: summarizeTeacherLoop(input),
6683
+ routeFn,
6113
6684
  principal: summarizePrincipalObservability(input, active),
6114
6685
  manyProfile: summarizeManyProfileSupport(brainAttachmentPolicy)
6115
6686
  };