@openclawbrain/cli 0.4.25 → 0.4.27

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.
@@ -455,6 +455,98 @@ function normalizeTeacherSupervisionArtifacts(artifacts) {
455
455
  .filter((artifact) => !artifact.sourceEventIds.some((eventId) => supersededEventIds.has(eventId)))
456
456
  .sort(compareTeacherSupervisionArtifacts);
457
457
  }
458
+ function normalizeServeTimeDecisionStringArray(values) {
459
+ if (!Array.isArray(values)) {
460
+ return [];
461
+ }
462
+ return values.filter((value) => typeof value === "string" && value.length > 0);
463
+ }
464
+ function normalizeServeTimeDecisionScore(score) {
465
+ if (score === null || typeof score !== "object" || Array.isArray(score)) {
466
+ return null;
467
+ }
468
+ if (typeof score.blockId !== "string" || score.blockId.length === 0) {
469
+ return null;
470
+ }
471
+ return {
472
+ blockId: score.blockId,
473
+ selected: score.selected === true,
474
+ actionScore: Number.isFinite(score.actionScore) ? score.actionScore : 0,
475
+ actionProbability: Number.isFinite(score.actionProbability) ? score.actionProbability : 0,
476
+ ...(Array.isArray(score.compactedFrom) ? { compactedFrom: normalizeServeTimeDecisionStringArray(score.compactedFrom) } : {}),
477
+ ...(Array.isArray(score.matchedTokens) ? { matchedTokens: normalizeServeTimeDecisionStringArray(score.matchedTokens) } : {}),
478
+ ...(Array.isArray(score.routingChannels) ? { routingChannels: normalizeServeTimeDecisionStringArray(score.routingChannels) } : {})
479
+ };
480
+ }
481
+ function normalizeServeTimeDecisionLogEntry(decision) {
482
+ if (decision === null || typeof decision !== "object" || Array.isArray(decision)) {
483
+ return null;
484
+ }
485
+ const selectedKernelContextIds = normalizeServeTimeDecisionStringArray(decision.selectedKernelContextIds);
486
+ const selectedBrainContextIds = normalizeServeTimeDecisionStringArray(decision.selectedBrainContextIds);
487
+ return {
488
+ ...decision,
489
+ candidateSetIds: normalizeServeTimeDecisionStringArray(decision.candidateSetIds),
490
+ chosenContextIds: normalizeServeTimeDecisionStringArray(decision.chosenContextIds),
491
+ candidateScores: Array.isArray(decision.candidateScores)
492
+ ? decision.candidateScores.map((score) => normalizeServeTimeDecisionScore(score)).filter((score) => score !== null)
493
+ : [],
494
+ kernelContextCount: Number.isInteger(decision.kernelContextCount) && decision.kernelContextCount >= 0
495
+ ? decision.kernelContextCount
496
+ : selectedKernelContextIds.length,
497
+ brainContextCount: Number.isInteger(decision.brainContextCount) && decision.brainContextCount >= 0
498
+ ? decision.brainContextCount
499
+ : selectedBrainContextIds.length,
500
+ selectedKernelContextIds,
501
+ selectedBrainContextIds
502
+ };
503
+ }
504
+ function normalizeServeTimeDecisionsForLearner(serveTimeDecisions) {
505
+ if (serveTimeDecisions === undefined) {
506
+ return undefined;
507
+ }
508
+ if (!Array.isArray(serveTimeDecisions)) {
509
+ return [];
510
+ }
511
+ return serveTimeDecisions
512
+ .map((decision) => normalizeServeTimeDecisionLogEntry(decision))
513
+ .filter((decision) => decision !== null);
514
+ }
515
+ function projectServeTimeDecisionForRoutingSeed(decision) {
516
+ return {
517
+ recordId: typeof decision.recordId === "string" ? decision.recordId : null,
518
+ recordedAt: typeof decision.recordedAt === "string" ? decision.recordedAt : null,
519
+ sessionId: typeof decision.sessionId === "string" ? decision.sessionId : null,
520
+ channel: typeof decision.channel === "string" ? decision.channel : null,
521
+ turnCompileEventId: typeof decision.turnCompileEventId === "string" ? decision.turnCompileEventId : null,
522
+ turnCreatedAt: typeof decision.turnCreatedAt === "string" ? decision.turnCreatedAt : null,
523
+ activePackId: typeof decision.activePackId === "string" ? decision.activePackId : null,
524
+ activePackGraphChecksum: typeof decision.activePackGraphChecksum === "string" ? decision.activePackGraphChecksum : null,
525
+ routerIdentity: typeof decision.routerIdentity === "string" ? decision.routerIdentity : null,
526
+ selectionDigest: typeof decision.selectionDigest === "string" ? decision.selectionDigest : null,
527
+ usedLearnedRouteFn: decision.usedLearnedRouteFn === true,
528
+ fallbackReason: typeof decision.fallbackReason === "string" ? decision.fallbackReason : null,
529
+ candidateSetIds: decision.candidateSetIds,
530
+ chosenContextIds: decision.chosenContextIds,
531
+ candidateScores: decision.candidateScores.map((score) => ({
532
+ blockId: score.blockId,
533
+ selected: score.selected,
534
+ actionScore: score.actionScore,
535
+ actionProbability: score.actionProbability,
536
+ compactedFrom: score.compactedFrom ?? []
537
+ })),
538
+ kernelContextCount: decision.kernelContextCount,
539
+ brainContextCount: decision.brainContextCount,
540
+ selectedKernelContextIds: decision.selectedKernelContextIds,
541
+ selectedBrainContextIds: decision.selectedBrainContextIds
542
+ };
543
+ }
544
+ function checksumServeTimeDecisionsForRoutingSeed(serveTimeDecisions) {
545
+ if (serveTimeDecisions === undefined) {
546
+ return null;
547
+ }
548
+ return checksumJsonPayload(serveTimeDecisions.map((decision) => projectServeTimeDecisionForRoutingSeed(decision)));
549
+ }
458
550
  function teacherSupervisionContentForInteraction(event) {
459
551
  const message = event.messageId === undefined ? "" : ` Message: ${event.messageId}.`;
460
552
  const pack = event.packId === undefined ? "" : ` Pack: ${event.packId}.`;
@@ -893,7 +985,7 @@ function buildAlwaysOnLearningMaterializationJob(input, current, selectedSlices,
893
985
  ...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
894
986
  principalBacklog,
895
987
  ...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
896
- ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: [...input.serveTimeDecisions] } : {}),
988
+ ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
897
989
  ...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {}),
898
990
  ...(input.activationRoot !== undefined ? { activationRoot: input.activationRoot } : {})
899
991
  };
@@ -1049,7 +1141,7 @@ export function buildCandidatePackFromNormalizedEventExportSlice(input) {
1049
1141
  ...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
1050
1142
  ...(input.principalBacklog !== undefined ? { principalBacklog: input.principalBacklog } : {}),
1051
1143
  ...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
1052
- ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: [...input.serveTimeDecisions] } : {}),
1144
+ ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
1053
1145
  ...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {})
1054
1146
  });
1055
1147
  }
@@ -1080,7 +1172,7 @@ export function buildCandidatePackBundleFromNormalizedEventExportBridge(input) {
1080
1172
  ...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
1081
1173
  ...(input.principalBacklog !== undefined ? { principalBacklog: input.principalBacklog } : {}),
1082
1174
  ...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
1083
- ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: [...input.serveTimeDecisions] } : {}),
1175
+ ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
1084
1176
  ...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {})
1085
1177
  })
1086
1178
  };
@@ -3565,7 +3657,8 @@ function remapServeTimeDecisionToGraph(decision, resolveBlockId) {
3565
3657
  const remappedSelectedBrainContextIds = remapIds(decision.selectedBrainContextIds);
3566
3658
  const chosenSet = new Set(remappedChosenContextIds);
3567
3659
  const remappedScoresByBlockId = new Map();
3568
- for (const score of decision.candidateScores) {
3660
+ const candidateScores = Array.isArray(decision.candidateScores) ? decision.candidateScores : [];
3661
+ for (const score of candidateScores) {
3569
3662
  const resolvedBlockId = resolveBlockId(score.blockId);
3570
3663
  if (resolvedBlockId === null) {
3571
3664
  continue;
@@ -4540,13 +4633,15 @@ function buildGraphLocalActionSetFromScores(nodeBlockId, neighborBlockIds, graph
4540
4633
  * Traces through the graph starting from the highest-scoring selected block.
4541
4634
  */
4542
4635
  export function reconstructTrajectoryFromServeDecision(decision, graph, vectors, adjacency, tau, outcome, baselineValue) {
4543
- const chosenSet = new Set(decision.chosenContextIds);
4636
+ const chosenContextIds = Array.isArray(decision.chosenContextIds) ? decision.chosenContextIds : [];
4637
+ const candidateScores = Array.isArray(decision.candidateScores) ? decision.candidateScores : [];
4638
+ const chosenSet = new Set(chosenContextIds);
4544
4639
  const candidateScoresMap = new Map();
4545
- for (const cs of decision.candidateScores) {
4640
+ for (const cs of candidateScores) {
4546
4641
  candidateScoresMap.set(cs.blockId, cs.actionScore);
4547
4642
  }
4548
4643
  // Sort chosen blocks by score descending to find entry point
4549
- const chosenWithScores = decision.chosenContextIds
4644
+ const chosenWithScores = chosenContextIds
4550
4645
  .map((blockId) => ({ blockId, score: candidateScoresMap.get(blockId) ?? 0 }))
4551
4646
  .sort((a, b) => b.score - a.score);
4552
4647
  const steps = [];
@@ -4679,7 +4774,7 @@ function createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport, se
4679
4774
  // 1. Build adjacency map from graph
4680
4775
  const adjacency = buildAdjacencyMap(graph);
4681
4776
  const resolveBlockId = buildGraphBlockIdResolver(graph);
4682
- const remappedServeTimeDecisions = serveTimeDecisions.map((decision) => remapServeTimeDecisionToGraph(decision, resolveBlockId));
4777
+ const remappedServeTimeDecisions = (serveTimeDecisions ?? []).map((decision) => remapServeTimeDecisionToGraph(decision, resolveBlockId));
4683
4778
  // 2. Join serve-time decisions with explicit feedback first, then let teacher-v2 observations override when available.
4684
4779
  const outcomeMap = joinDecisionsWithFeedback(remappedServeTimeDecisions, eventExport);
4685
4780
  const teacherObservationBindings = joinDecisionsWithTeacherObservationOutcomes(remappedServeTimeDecisions, teacherObservationOutcomes);
@@ -4710,7 +4805,7 @@ function createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport, se
4710
4805
  `traj-${stableHash(checksumJsonPayload({ decisionId: d.recordId, steps: trajectory.steps.map((s) => s.nodeBlockId) }))}` === trajectory.trajectoryId);
4711
4806
  const candidateScoresMap = new Map();
4712
4807
  if (decision !== undefined) {
4713
- for (const cs of decision.candidateScores) {
4808
+ for (const cs of decision.candidateScores ?? []) {
4714
4809
  candidateScoresMap.set(cs.blockId, cs.actionScore);
4715
4810
  }
4716
4811
  }
@@ -5000,7 +5095,8 @@ export function buildCandidatePack(input) {
5000
5095
  });
5001
5096
  const learningSurface = eventExport?.provenance.learningSurface ?? defaultLearningSurface(workspace, offlineArtifacts, workspaceInit);
5002
5097
  const sparseFeedback = normalizeSparseFeedbackPolicy(input.sparseFeedback);
5003
- const decisionLogCount = input.serveTimeDecisions?.length ?? 0;
5098
+ const serveTimeDecisions = normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions);
5099
+ const decisionLogCount = serveTimeDecisions?.length ?? 0;
5004
5100
  const useV2 = input.pgVersion === "v2" && decisionLogCount > 0;
5005
5101
  const fallbackReason = !input.learnedRouting
5006
5102
  ? null
@@ -5010,7 +5106,7 @@ export function buildCandidatePack(input) {
5010
5106
  const routingSeed = input.learnedRouting && (input.pgVersion === "v2" || decisionLogCount > 0 || input.baselineState !== undefined)
5011
5107
  ? {
5012
5108
  pgVersionRequested: input.pgVersion ?? "v1",
5013
- serveTimeDecisionDigest: input.serveTimeDecisions === undefined ? null : checksumJsonPayload(input.serveTimeDecisions),
5109
+ serveTimeDecisionDigest: checksumServeTimeDecisionsForRoutingSeed(serveTimeDecisions),
5014
5110
  baselineState: input.baselineState ?? null
5015
5111
  }
5016
5112
  : null;
@@ -5048,7 +5144,7 @@ export function buildCandidatePack(input) {
5048
5144
  : loadTeacherObservationOutcomesFromActivation(input.activationRoot);
5049
5145
  if (input.learnedRouting) {
5050
5146
  if (useV2) {
5051
- const v2Result = createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport, input.serveTimeDecisions, input.baselineState ?? initBaseline(), input.sparseFeedback, input.principalBacklog, teacherObservationOutcomes);
5147
+ const v2Result = createRouterArtifactV2(packId, builtAt, graph, vectors, eventExport, serveTimeDecisions ?? [], input.baselineState ?? initBaseline(), input.sparseFeedback, input.principalBacklog, teacherObservationOutcomes);
5052
5148
  router = v2Result.artifact;
5053
5149
  updatedBaseline = v2Result.updatedBaseline;
5054
5150
  observationBindingStats = v2Result.observationBindingStats;
@@ -5211,7 +5307,7 @@ export function buildCandidatePackFromNormalizedEventExport(input) {
5211
5307
  ...(input.sparseFeedback !== undefined ? { sparseFeedback: input.sparseFeedback } : {}),
5212
5308
  ...(input.principalBacklog !== undefined ? { principalBacklog: input.principalBacklog } : {}),
5213
5309
  ...(input.pgVersion !== undefined ? { pgVersion: input.pgVersion } : {}),
5214
- ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: [...input.serveTimeDecisions] } : {}),
5310
+ ...(input.serveTimeDecisions !== undefined ? { serveTimeDecisions: normalizeServeTimeDecisionsForLearner(input.serveTimeDecisions) } : {}),
5215
5311
  ...(input.baselineState !== undefined ? { baselineState: { ...input.baselineState } } : {}),
5216
5312
  ...(input.activationRoot !== undefined ? { activationRoot: input.activationRoot } : {})
5217
5313
  };
@@ -16,6 +16,7 @@ export interface OpenClawBrainHookInspection {
16
16
  manifestId: string | null;
17
17
  installId: string | null;
18
18
  packageName: string | null;
19
+ packageVersion: string | null;
19
20
  installLayout: OpenClawBrainInstallLayout | null;
20
21
  additionalInstallCount: number;
21
22
  installState: OpenClawBrainHookInstallState;
@@ -31,9 +32,30 @@ export interface OpenClawBrainHookLoadSummary extends OpenClawBrainHookInspectio
31
32
  guardSummary: string;
32
33
  guardAction: string;
33
34
  }
35
+ export interface OpenClawBrainDaemonRuntimeSurfaceInspection {
36
+ configuredRuntimePath: string | null;
37
+ configuredRuntimePackageSpec?: string | null;
38
+ configuredRuntimePackageName?: string | null;
39
+ configuredRuntimePackageVersion?: string | null;
40
+ }
41
+ export interface OpenClawBrainHotfixBoundarySummary {
42
+ boundary: string;
43
+ skew: string;
44
+ daemonPath: string | null;
45
+ hookPath: string | null;
46
+ runtimeGuardPath: string | null;
47
+ daemonPackage: string | null;
48
+ hookPackage: string | null;
49
+ guidance: string;
50
+ detail: string;
51
+ }
34
52
  export declare function inspectOpenClawBrainPluginAllowlist(openclawHome: string): {
35
53
  state: Exclude<OpenClawBrainPluginAllowlistState, "unverified">;
36
54
  detail: string;
37
55
  };
38
56
  export declare function inspectOpenClawBrainHookStatus(openclawHome: string | null | undefined): OpenClawBrainHookInspection;
39
57
  export declare function summarizeOpenClawBrainHookLoad(inspection: OpenClawBrainHookInspection, statusProbeReady: boolean): OpenClawBrainHookLoadSummary;
58
+ export declare function describeOpenClawBrainHotfixBoundary(input: {
59
+ hookInspection: OpenClawBrainHookInspection;
60
+ daemonInspection?: OpenClawBrainDaemonRuntimeSurfaceInspection | null;
61
+ }): OpenClawBrainHotfixBoundarySummary;
@@ -35,6 +35,37 @@ function shortenPath(fullPath) {
35
35
  }
36
36
  return fullPath;
37
37
  }
38
+ function readInstalledHookPackageVersion(packageJsonPath) {
39
+ if (typeof packageJsonPath !== "string" || packageJsonPath.trim().length === 0) {
40
+ return null;
41
+ }
42
+ try {
43
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
44
+ return typeof parsed?.version === "string" && parsed.version.trim().length > 0
45
+ ? parsed.version.trim()
46
+ : null;
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ function formatPackageIdentity(packageName, packageVersion, packageSpec = null) {
53
+ if (typeof packageSpec === "string" && packageSpec.trim().length > 0) {
54
+ return packageSpec.trim();
55
+ }
56
+ if (typeof packageName !== "string" || packageName.trim().length === 0) {
57
+ return null;
58
+ }
59
+ const normalizedName = packageName.trim();
60
+ return typeof packageVersion === "string" && packageVersion.trim().length > 0
61
+ ? `${normalizedName}@${packageVersion.trim()}`
62
+ : normalizedName;
63
+ }
64
+ function normalizeSurfacePath(filePath) {
65
+ return typeof filePath === "string" && filePath.trim().length > 0
66
+ ? path.resolve(filePath)
67
+ : null;
68
+ }
38
69
  function inspectInstalledHookActivationRoot(loaderEntryPath) {
39
70
  let content;
40
71
  try {
@@ -147,6 +178,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
147
178
  manifestId: null,
148
179
  installId: null,
149
180
  packageName: null,
181
+ packageVersion: null,
150
182
  installLayout: null,
151
183
  additionalInstallCount: 0,
152
184
  installState: "unverified",
@@ -173,6 +205,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
173
205
  manifestId: incompleteInstall?.manifestId ?? null,
174
206
  installId: incompleteInstall?.installId ?? null,
175
207
  packageName: incompleteInstall?.packageName ?? null,
208
+ packageVersion: readInstalledHookPackageVersion(incompleteInstall?.packageJsonPath ?? null),
176
209
  installLayout: incompleteInstall?.installLayout ?? null,
177
210
  additionalInstallCount: installedPlugin.additionalInstalls.length,
178
211
  installState: "not_installed",
@@ -189,6 +222,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
189
222
  const allowlist = inspectOpenClawBrainPluginAllowlist(resolvedHome);
190
223
  const layoutLabel = describeOpenClawBrainInstallLayout(selectedInstall.installLayout);
191
224
  const identityDetail = describeOpenClawBrainInstallIdentity(selectedInstall);
225
+ const packageVersion = readInstalledHookPackageVersion(selectedInstall.packageJsonPath);
192
226
  const activationRootState = inspectInstalledHookActivationRoot(selectedInstall.loaderEntryPath);
193
227
  if (allowlist.state === "blocked") {
194
228
  return {
@@ -202,6 +236,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
202
236
  manifestId: selectedInstall.manifestId,
203
237
  installId: selectedInstall.installId,
204
238
  packageName: selectedInstall.packageName,
239
+ packageVersion,
205
240
  installLayout: selectedInstall.installLayout,
206
241
  additionalInstallCount: installedPlugin.additionalInstalls.length,
207
242
  installState: "blocked_by_allowlist",
@@ -224,6 +259,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
224
259
  manifestId: selectedInstall.manifestId,
225
260
  installId: selectedInstall.installId,
226
261
  packageName: selectedInstall.packageName,
262
+ packageVersion,
227
263
  installLayout: selectedInstall.installLayout,
228
264
  additionalInstallCount: installedPlugin.additionalInstalls.length,
229
265
  installState: "blocked_by_allowlist",
@@ -246,6 +282,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
246
282
  manifestId: selectedInstall.manifestId,
247
283
  installId: selectedInstall.installId,
248
284
  packageName: selectedInstall.packageName,
285
+ packageVersion,
249
286
  installLayout: selectedInstall.installLayout,
250
287
  additionalInstallCount: installedPlugin.additionalInstalls.length,
251
288
  installState: "installed",
@@ -266,6 +303,7 @@ export function inspectOpenClawBrainHookStatus(openclawHome) {
266
303
  manifestId: selectedInstall.manifestId,
267
304
  installId: selectedInstall.installId,
268
305
  packageName: selectedInstall.packageName,
306
+ packageVersion,
269
307
  installLayout: selectedInstall.installLayout,
270
308
  additionalInstallCount: installedPlugin.additionalInstalls.length,
271
309
  installState: "installed",
@@ -284,4 +322,83 @@ export function summarizeOpenClawBrainHookLoad(inspection, statusProbeReady) {
284
322
  : "not_ready"
285
323
  };
286
324
  }
325
+ export function describeOpenClawBrainHotfixBoundary(input) {
326
+ const hookInspection = input.hookInspection;
327
+ const daemonInspection = input.daemonInspection ?? null;
328
+ const daemonPath = normalizeSurfacePath(daemonInspection?.configuredRuntimePath ?? null);
329
+ const hookPath = normalizeSurfacePath(hookInspection.hookPath);
330
+ const runtimeGuardPath = normalizeSurfacePath(hookInspection.runtimeGuardPath);
331
+ const daemonPackage = formatPackageIdentity(daemonInspection?.configuredRuntimePackageName ?? null, daemonInspection?.configuredRuntimePackageVersion ?? null, daemonInspection?.configuredRuntimePackageSpec ?? null);
332
+ const hookPackage = formatPackageIdentity(hookInspection.packageName, hookInspection.packageVersion);
333
+ if (hookInspection.scope === "activation_root_only") {
334
+ return {
335
+ boundary: "hook_surface_unverified",
336
+ skew: "unverified",
337
+ daemonPath,
338
+ hookPath: null,
339
+ runtimeGuardPath: null,
340
+ daemonPackage,
341
+ hookPackage: null,
342
+ guidance: "Pin --openclaw-home before patching the installed hook/runtime-guard surface; activation-root-only status does not prove which OpenClaw install you would be changing.",
343
+ detail: daemonPath === null
344
+ ? "activation-root-only status does not expose the installed hook/runtime-guard surface."
345
+ : `daemon runtime path ${shortenPath(daemonPath)} is visible, but activation-root-only status still does not expose the installed hook/runtime-guard surface.`
346
+ };
347
+ }
348
+ if (hookPath === null && runtimeGuardPath === null) {
349
+ return {
350
+ boundary: "hook_surface_unverified",
351
+ skew: "unverified",
352
+ daemonPath,
353
+ hookPath: null,
354
+ runtimeGuardPath: null,
355
+ daemonPackage,
356
+ hookPackage,
357
+ guidance: daemonPath === null
358
+ ? "Repair or reinstall the installed hook surface before patching OpenClaw load behavior."
359
+ : "Patch the daemon runtime path for background watch fixes, but repair or reinstall the installed hook/runtime-guard surface before patching OpenClaw load behavior.",
360
+ detail: daemonPath === null
361
+ ? "no verified daemon runtime path or installed hook/runtime-guard path is visible from this status snapshot."
362
+ : `daemon runtime path ${shortenPath(daemonPath)} is visible, but the installed hook/runtime-guard surface is not yet loadable.`
363
+ };
364
+ }
365
+ if (daemonPath === null) {
366
+ return {
367
+ boundary: "daemon_surface_only",
368
+ skew: "unverified",
369
+ daemonPath: null,
370
+ hookPath,
371
+ runtimeGuardPath,
372
+ daemonPackage: null,
373
+ hookPackage,
374
+ guidance: "Patch the installed hook/runtime-guard surface for OpenClaw load fixes. No configured daemon runtime path is visible from status.",
375
+ detail: `installed hook loads from ${hookPath === null ? "unverified" : shortenPath(hookPath)}${runtimeGuardPath === null ? "" : ` with runtime-guard ${shortenPath(runtimeGuardPath)}`}, but no configured daemon runtime path is visible.`
376
+ };
377
+ }
378
+ const samePath = daemonPath === hookPath || daemonPath === runtimeGuardPath;
379
+ const daemonVersion = daemonInspection?.configuredRuntimePackageVersion ?? null;
380
+ const hookVersion = hookInspection.packageVersion ?? null;
381
+ const skew = samePath
382
+ ? "same_path"
383
+ : daemonVersion !== null && hookVersion !== null
384
+ ? daemonVersion === hookVersion
385
+ ? "split_path_same_version"
386
+ : "split_path_version_skew"
387
+ : "split_path_version_unverified";
388
+ return {
389
+ boundary: samePath ? "same_surface" : "split_surfaces",
390
+ skew,
391
+ daemonPath,
392
+ hookPath,
393
+ runtimeGuardPath,
394
+ daemonPackage,
395
+ hookPackage,
396
+ guidance: samePath
397
+ ? "Daemon and installed hook paths currently collapse to the same file; verify both surfaces before patching anyway."
398
+ : "Patch the daemon runtime path for background watch/learner fixes. Patch the installed hook/runtime-guard paths for OpenClaw load fixes.",
399
+ detail: samePath
400
+ ? `daemon runtime path ${shortenPath(daemonPath)} currently resolves to the same file as the installed OpenClaw hook surface.`
401
+ : `daemon background watch runs from ${shortenPath(daemonPath)}${daemonPackage === null ? "" : ` (${daemonPackage})`}; OpenClaw loads the installed hook from ${hookPath === null ? "unverified" : shortenPath(hookPath)}${hookPackage === null ? "" : ` (${hookPackage})`}${runtimeGuardPath === null ? "" : ` and runtime-guard ${shortenPath(runtimeGuardPath)}`}.`
402
+ };
403
+ }
287
404
  //# sourceMappingURL=openclaw-hook-truth.js.map
@@ -546,7 +546,7 @@ function buildVerdict({ steps, gatewayStatus, pluginInspect, statusSignals, brea
546
546
  };
547
547
  }
548
548
 
549
- function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, guardLine, feedbackLine, attributionLine, attributionCoverageLine, learningPathLine, coverageSnapshot, hardeningSnapshot }) {
549
+ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, surfaceLine, surfacesLine, hotfixLine, guardLine, feedbackLine, attributionLine, attributionCoverageLine, learningPathLine, learningFlowLine, learningHealthLine, coverageSnapshot, hardeningSnapshot }) {
550
550
  const passed = [];
551
551
  const missing = [];
552
552
  const warnings = Array.isArray(verdict.warnings) ? verdict.warnings : [];
@@ -602,11 +602,33 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
602
602
  "## Warnings",
603
603
  ...(warnings.length === 0 ? ["- none"] : warnings.map((item) => `- ${item}`)),
604
604
  "",
605
+ "## Hotfix Boundary",
606
+ ...(surfaceLine === null
607
+ ? ["- hotfix boundary line not reported by detailed status"]
608
+ : [`- ${surfaceLine}`]),
609
+ ...(surfacesLine === null
610
+ ? ["- hotfix paths line not reported by detailed status"]
611
+ : [`- ${surfacesLine}`]),
612
+ ...(hotfixLine === null
613
+ ? ["- hotfix guidance line not reported by detailed status"]
614
+ : [`- ${hotfixLine}`]),
615
+ "",
605
616
  "## Runtime Guard",
606
617
  ...(guardLine === null
607
618
  ? ["- runtime guard line not reported by detailed status"]
608
619
  : [`- ${guardLine}`]),
609
620
  "",
621
+ "## Learning Flow",
622
+ ...(learningPathLine === null
623
+ ? ["- learning path line not reported by detailed status"]
624
+ : [`- ${learningPathLine}`]),
625
+ ...(learningFlowLine === null
626
+ ? ["- learning flow line not reported by detailed status"]
627
+ : [`- ${learningFlowLine}`]),
628
+ ...(learningHealthLine === null
629
+ ? ["- learning health line not reported by detailed status"]
630
+ : [`- ${learningHealthLine}`]),
631
+ "",
610
632
  "## Learning Attribution",
611
633
  ...(feedbackLine === null
612
634
  ? ["- feedback line not reported by detailed status"]
@@ -617,9 +639,6 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
617
639
  ...(attributionCoverageLine === null
618
640
  ? ["- attribution coverage line not reported by detailed status"]
619
641
  : [`- ${attributionCoverageLine}`]),
620
- ...(learningPathLine === null
621
- ? []
622
- : [`- ${learningPathLine}`]),
623
642
  "",
624
643
  "## Coverage snapshot",
625
644
  `- attached profiles: ${coverageSnapshot.attachedProfileCount}`,
@@ -916,11 +935,16 @@ export function captureOperatorProofBundle(options) {
916
935
  const gatewayLogPath = extractGatewayLogPath(gatewayStatusCapture.stdout);
917
936
  const activationRoot = extractActivationRoot(statusCapture.stdout, options.activationRoot ?? null);
918
937
  const statusSignals = extractStatusSignals(statusCapture.stdout);
938
+ const surfaceLine = extractDetailedStatusLine(statusCapture.stdout, "surface");
939
+ const surfacesLine = extractDetailedStatusLine(statusCapture.stdout, "surfaces");
940
+ const hotfixLine = extractDetailedStatusLine(statusCapture.stdout, "hotfix");
919
941
  const attachTruthLine = extractDetailedStatusLine(statusCapture.stdout, "attachTruth");
920
942
  const attachedSetLine = extractDetailedStatusLine(statusCapture.stdout, "attachedSet");
921
943
  const serveLine = extractDetailedStatusLine(statusCapture.stdout, "serve");
922
944
  const routeFnLine = extractDetailedStatusLine(statusCapture.stdout, "routeFn");
923
945
  const guardLine = extractDetailedStatusLine(statusCapture.stdout, "guard");
946
+ const learningFlowLine = extractDetailedStatusLine(statusCapture.stdout, "learnFlow");
947
+ const learningHealthLine = extractDetailedStatusLine(statusCapture.stdout, "health");
924
948
  const feedbackLine = extractDetailedStatusLine(statusCapture.stdout, "feedback");
925
949
  const attributionLine = extractDetailedStatusLine(statusCapture.stdout, "attribution");
926
950
  const attributionCoverageLine = extractDetailedStatusLine(statusCapture.stdout, "attrCover");
@@ -978,7 +1002,12 @@ export function captureOperatorProofBundle(options) {
978
1002
  },
979
1003
  runtimeLoadProofPath,
980
1004
  runtimeLoadProofError: runtimeLoadProofSnapshot.error,
1005
+ surfaceLine,
1006
+ surfacesLine,
1007
+ hotfixLine,
981
1008
  guardLine,
1009
+ learningFlowLine,
1010
+ learningHealthLine,
982
1011
  feedbackLine,
983
1012
  attributionLine,
984
1013
  attributionCoverageLine,
@@ -994,7 +1023,12 @@ export function captureOperatorProofBundle(options) {
994
1023
  statusSignals,
995
1024
  breadcrumbs,
996
1025
  runtimeLoadProofSnapshot,
1026
+ surfaceLine,
1027
+ surfacesLine,
1028
+ hotfixLine,
997
1029
  guardLine,
1030
+ learningFlowLine,
1031
+ learningHealthLine,
998
1032
  feedbackLine,
999
1033
  attributionLine,
1000
1034
  attributionCoverageLine,
@@ -1015,7 +1049,12 @@ export function captureOperatorProofBundle(options) {
1015
1049
  hardeningSnapshot,
1016
1050
  verdict,
1017
1051
  statusSignals,
1052
+ surfaceLine,
1053
+ surfacesLine,
1054
+ hotfixLine,
1018
1055
  guardLine,
1056
+ learningFlowLine,
1057
+ learningHealthLine,
1019
1058
  feedbackLine,
1020
1059
  attributionLine,
1021
1060
  attributionCoverageLine,