@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.
package/dist/src/cli.js CHANGED
@@ -13,11 +13,11 @@ import { buildTeacherSupervisionArtifactsFromNormalizedEventExport, createAlways
13
13
  import { inspectActivationState, loadPackFromActivation, promoteCandidatePack, resolveLearningSpineLogPath, stageCandidatePack } from "@openclawbrain/pack-format";
14
14
  import { resolveActivationRoot } from "./resolve-activation-root.js";
15
15
  import { describeOpenClawHomeInspection, discoverOpenClawHomes, formatOpenClawHomeLayout, formatOpenClawHomeProfileSource, inspectOpenClawHome } from "./openclaw-home-layout.js";
16
- import { inspectOpenClawBrainHookStatus, inspectOpenClawBrainPluginAllowlist } from "./openclaw-hook-truth.js";
16
+ import { describeOpenClawBrainHotfixBoundary, inspectOpenClawBrainHookStatus, inspectOpenClawBrainPluginAllowlist } from "./openclaw-hook-truth.js";
17
17
  import { describeOpenClawBrainInstallIdentity, describeOpenClawBrainInstallLayout, findInstalledOpenClawBrainPlugin, getOpenClawBrainKnownPluginIds, normalizeOpenClawBrainPluginsConfig, pinInstalledOpenClawBrainPluginActivationRoot, resolveOpenClawBrainInstallTarget } from "./openclaw-plugin-install.js";
18
18
  import { buildOpenClawBrainConvergeRestartPlan, classifyOpenClawBrainConvergeVerification, describeOpenClawBrainConvergeChangeReasons, diffOpenClawBrainConvergeRuntimeFingerprint, finalizeOpenClawBrainConvergeResult, planOpenClawBrainConvergePluginAction, shouldReplaceOpenClawBrainInstallBeforeConverge } from "./install-converge.js";
19
19
  import { loadAttachmentPolicyDeclaration, resolveEffectiveAttachmentPolicyTruth, writeAttachmentPolicyDeclaration } from "./attachment-policy-truth.js";
20
- import { DEFAULT_WATCH_POLL_INTERVAL_SECONDS, buildNormalizedEventExportFromScannedEvents, bootstrapRuntimeAttach, buildOperatorSurfaceReport, clearOpenClawProfileRuntimeLoadProof, compileRuntimeContext, createAsyncTeacherLiveLoop, createOpenClawLocalSessionTail, createRuntimeEventExportScanner, describeCurrentProfileBrainStatus, formatOperatorRollbackReport, listOpenClawProfileRuntimeLoadProofs, loadRuntimeEventExportBundle, loadWatchTeacherSnapshotState, persistWatchTeacherSnapshot, rollbackRuntimeAttach, resolveAttachmentRuntimeLoadProofsPath, resolveOperatorTeacherSnapshotPath, resolveAsyncTeacherLiveLoopSnapshotPath, resolveWatchSessionTailCursorPath, resolveWatchStateRoot, resolveWatchTeacherSnapshotPath, scanLiveEventExport, scanRecordedSession, summarizeLearningPathFromMaterialization, summarizeNormalizedEventExportLabelFlow, summarizeTeacherNoArtifactCycle, writeScannedEventExportBundle } from "./index.js";
20
+ import { DEFAULT_WATCH_POLL_INTERVAL_SECONDS, buildNormalizedEventExportFromScannedEvents, bootstrapRuntimeAttach, clearOpenClawProfileRuntimeLoadProof, compileRuntimeContext, createAsyncTeacherLiveLoop, createOpenClawLocalSessionTail, createRuntimeEventExportScanner, describeCurrentProfileBrainStatusWithReport, formatOperatorRollbackReport, listOpenClawProfileRuntimeLoadProofs, loadRuntimeEventExportBundle, loadWatchTeacherSnapshotState, persistWatchTeacherSnapshot, rollbackRuntimeAttach, resolveAttachmentRuntimeLoadProofsPath, resolveOperatorTeacherSnapshotPath, resolveAsyncTeacherLiveLoopSnapshotPath, resolveWatchSessionTailCursorPath, resolveWatchStateRoot, resolveWatchTeacherSnapshotPath, scanLiveEventExport, scanRecordedSession, summarizeLearningPathFromMaterialization, summarizeNormalizedEventExportLabelFlow, summarizeTeacherNoArtifactCycle, writeScannedEventExportBundle } from "./index.js";
21
21
  import { appendLearningUpdateLogs } from "./learning-spine.js";
22
22
  import { buildPassiveLearningSessionExportFromOpenClawSessionStore } from "./local-session-passive-learning.js";
23
23
  import { reindexMaterializationCandidateWithEmbedder } from "./materialization-embedder.js";
@@ -25,7 +25,7 @@ import { summarizePackVectorEmbeddingState } from "./embedding-status.js";
25
25
  import { buildTracedLearningBridgePayloadFromRuntime, buildTracedLearningStatusSurface, persistTracedLearningBridgeState } from "./traced-learning-bridge.js";
26
26
  import { discoverOpenClawSessionStores, loadOpenClawSessionIndex, readOpenClawSessionFile } from "./session-store.js";
27
27
  import { readOpenClawBrainProviderDefaults, readOpenClawBrainProviderConfig, readOpenClawBrainProviderConfigFromSources, resolveOpenClawBrainProviderDefaultsPath } from "./provider-config.js";
28
- import { formatOperatorAttributionCoverageSummary, formatOperatorFeedbackSummary, formatOperatorLearningAttributionSummary, formatOperatorLearningPathSummary } from "./status-learning-path.js";
28
+ import { formatOperatorAttributionCoverageSummary, formatOperatorFeedbackSummary, formatOperatorLearningAttributionSummary, formatOperatorLearningFlowSummary, formatOperatorLearningHealthSummary, formatOperatorLearningPathSummary } from "./status-learning-path.js";
29
29
  import { buildProofCommandForOpenClawHome, buildProofCommandHelpSection, captureOperatorProofBundle, formatOperatorProofResult, parseProofCliArgs } from "./proof-command.js";
30
30
  const OPENCLAWBRAIN_EMBEDDER_BASE_URL_ENV = "OPENCLAWBRAIN_EMBEDDER_BASE_URL";
31
31
  const OPENCLAWBRAIN_EMBEDDER_PROVIDER_ENV = "OPENCLAWBRAIN_EMBEDDER_PROVIDER";
@@ -950,6 +950,27 @@ function summarizeStatusAttachmentTruth(input) {
950
950
  })
951
951
  };
952
952
  }
953
+ function summarizeStatusHotfixBoundary(status) {
954
+ return describeOpenClawBrainHotfixBoundary({
955
+ hookInspection: status.hook,
956
+ daemonInspection: inspectManagedLearnerService(status.host.activationRoot)
957
+ });
958
+ }
959
+ function formatStatusHotfixBoundarySummary(boundary) {
960
+ return [
961
+ `boundary=${boundary.boundary}`,
962
+ `skew=${boundary.skew}`,
963
+ `daemon=${boundary.daemonPackage ?? "unverified"}`,
964
+ `hook=${boundary.hookPackage ?? "unverified"}`
965
+ ].join(" ");
966
+ }
967
+ function formatStatusHotfixBoundaryPaths(boundary) {
968
+ return [
969
+ `daemonPath=${boundary.daemonPath === null ? "none" : shortenPath(boundary.daemonPath)}`,
970
+ `hookPath=${boundary.hookPath === null ? "unverified" : shortenPath(boundary.hookPath)}`,
971
+ `runtimeGuard=${boundary.runtimeGuardPath === null ? "unverified" : shortenPath(boundary.runtimeGuardPath)}`
972
+ ].join(" ");
973
+ }
953
974
  function normalizeAttachmentPolicyMode(value) {
954
975
  return value === "undeclared" || value === "dedicated" || value === "shared"
955
976
  ? value
@@ -1417,6 +1438,7 @@ function formatTracedLearningSurface(surface) {
1417
1438
  function buildCompactStatusHeader(status, report, options) {
1418
1439
  const installHook = summarizeStatusInstallHook(options.openclawHome);
1419
1440
  const hookLoad = summarizeStatusHookLoad(installHook, status);
1441
+ const hotfixBoundary = summarizeStatusHotfixBoundary(status);
1420
1442
  const embeddings = summarizeStatusEmbeddings(report, options.providerConfig);
1421
1443
  const localLlm = summarizeStatusLocalLlm(options.providerConfig);
1422
1444
  const teacher = summarizeStatusTeacher(report, options.providerConfig, localLlm);
@@ -1433,6 +1455,9 @@ function buildCompactStatusHeader(status, report, options) {
1433
1455
  return [
1434
1456
  `lifecycle attach=${status.attachment.state} learner=${yesNo(status.passiveLearning.learnerRunning)} watch=${summarizeStatusWatchState(status)} export=${status.passiveLearning.exportState} promote=${summarizeStatusPromotionState(status)} serve=${summarizeStatusServeReality(status)}`,
1435
1457
  `hook install=${hookLoad.installState} loadability=${hookLoad.loadability} loadProof=${hookLoad.loadProof} layout=${status.hook.installLayout ?? "unverified"} additional=${status.hook.additionalInstallCount ?? 0} severity=${hookLoad.guardSeverity} actionability=${hookLoad.guardActionability} summary=${hookLoad.guardSummary}`,
1458
+ `surface ${formatStatusHotfixBoundarySummary(hotfixBoundary)}`,
1459
+ `surfaces ${formatStatusHotfixBoundaryPaths(hotfixBoundary)}`,
1460
+ `hotfix ${hotfixBoundary.guidance}`,
1436
1461
  `attachTruth current=${attachmentTruth.currentProfileLabel} hook=${attachmentTruth.hookFiles} config=${attachmentTruth.configLoad} runtime=${attachmentTruth.runtimeLoad} watcher=${attachmentTruth.watcher} attachedSet=${formatAttachedProfileTruthCompactList(attachmentTruth.attachedProfiles)} why=${attachmentTruth.detail}`,
1437
1462
  `passive firstExport=${yesNo(status.passiveLearning.firstExportOccurred)} backlog=${status.passiveLearning.backlogState} pending=${formatStatusNullableNumber(status.passiveLearning.pendingLive)}/${formatStatusNullableNumber(status.passiveLearning.pendingBackfill)}`,
1438
1463
  `serving pack=${status.passiveLearning.currentServingPackId ?? "none"} lastExport=${status.passiveLearning.lastExportAt ?? "none"} lastPromotion=${status.passiveLearning.lastPromotionAt ?? "none"}`,
@@ -1442,6 +1467,8 @@ function buildCompactStatusHeader(status, report, options) {
1442
1467
  `explain ${status.brain.summary}`,
1443
1468
  `graph blocks=${report.graph.blockCount ?? "none"} strongest=${report.graph.strongestBlockId ?? "none"} latest=${report.graph.latestMaterialization.packId ?? "none"} latestChanged=${yesNo(report.graph.latestMaterialization.changed)} connect=${formatCompactGraphConnectDiagnostics(report.graph.latestMaterialization.connectDiagnostics ?? report.graph.connectDiagnostics)}`,
1444
1469
  `attribution ${formatOperatorLearningAttributionSummary({ status })}`,
1470
+ `learnFlow ${formatOperatorLearningFlowSummary({ tracedLearning })}`,
1471
+ `health ${formatOperatorLearningHealthSummary({ tracedLearning, teacher })}`,
1445
1472
  `teacher model=${teacher.model} enabled=${yesNo(teacher.enabled)} healthy=${yesNo(teacher.healthy)} stale=${yesNo(teacher.stale)} idle=${yesNo(teacher.idle)} cycle=${teacher.latestCycle} why=${teacher.detail}`,
1446
1473
  `embedder model=${embedder.model} provisioned=${yesNo(embedder.provisioned)} live=${yesNo(embedder.live)} why=${embedder.detail}`,
1447
1474
  `routeFn available=${yesNo(routeFn.available)} freshness=${routeFn.freshness} trained=${routeFn.trainedAt ?? "none"} updated=${routeFn.updatedAt ?? "none"} used=${routeFn.usedAt ?? "none"} why=${routeFn.detail}`,
@@ -1454,8 +1481,10 @@ function buildCompactStatusHeader(status, report, options) {
1454
1481
  function formatCurrentProfileStatusSummary(status, report, targetInspection, options) {
1455
1482
  const installHook = summarizeStatusInstallHook(options.openclawHome);
1456
1483
  const displayedStatus = summarizeDisplayedStatus(status, installHook);
1484
+ const hotfixBoundary = summarizeStatusHotfixBoundary(status);
1457
1485
  const embeddings = summarizeStatusEmbeddings(report, options.providerConfig);
1458
1486
  const localLlm = summarizeStatusLocalLlm(options.providerConfig);
1487
+ const teacher = summarizeStatusTeacher(report, options.providerConfig, localLlm);
1459
1488
  const liveModels = embeddings.models.length === 0 ? "none" : embeddings.models.join("|");
1460
1489
  const attachmentTruth = summarizeStatusAttachmentTruth({
1461
1490
  activationRoot: status.host.activationRoot,
@@ -1480,6 +1509,7 @@ function formatCurrentProfileStatusSummary(status, report, targetInspection, opt
1480
1509
  `host runtime=${status.host.runtimeOwner} activation=${status.host.activationRoot}`,
1481
1510
  `profile selector=${status.profile.selector}${profileIdSuffix} attachment=${status.attachment.state} policy=${status.attachment.policyMode}`,
1482
1511
  `guard severity=${status.hook.guardSeverity} actionability=${status.hook.guardActionability} action=${status.hook.guardAction} summary=${status.hook.guardSummary}`,
1512
+ `surfaceNote ${hotfixBoundary.detail}`,
1483
1513
  `attachTruth current=${attachmentTruth.currentProfileLabel} hook=${attachmentTruth.hookFiles} config=${attachmentTruth.configLoad} runtime=${attachmentTruth.runtimeLoad} watcher=${attachmentTruth.watcher} detail=${attachmentTruth.detail}`,
1484
1514
  `attachedSet ${formatAttachedProfileTruthDetailedList(attachmentTruth.attachedProfiles)} proofPath=${shortenPath(attachmentTruth.runtimeProofPath)} proofError=${attachmentTruth.runtimeProofError ?? "none"}`,
1485
1515
  `manyProfile surface=${report.manyProfile.operatorSurface} policy=${report.manyProfile.declaredAttachmentPolicy} intent=${report.manyProfile.sameGatewayIntent} checkedProof=${report.manyProfile.checkedInProofTopology} sameGatewayProof=${yesNo(report.manyProfile.sameGatewayProof)} sharedWriteProof=${yesNo(report.manyProfile.sharedWriteSafetyProof)}`,
@@ -1500,6 +1530,8 @@ function formatCurrentProfileStatusSummary(status, report, targetInspection, opt
1500
1530
  learningPath: report.learningPath,
1501
1531
  tracedLearning
1502
1532
  })}`,
1533
+ `learnFlow ${formatOperatorLearningFlowSummary({ tracedLearning })}`,
1534
+ `health ${formatOperatorLearningHealthSummary({ tracedLearning, teacher })}`,
1503
1535
  `feedback ${formatOperatorFeedbackSummary({ tracedLearning })}`,
1504
1536
  `attribution ${formatOperatorLearningAttributionSummary({ status })}`,
1505
1537
  `attrCover ${formatOperatorAttributionCoverageSummary({ tracedLearning })}`,
@@ -1692,8 +1724,7 @@ function inspectInstallConvergeVerification(parsed) {
1692
1724
  openclawHome: parsed.openclawHome,
1693
1725
  ...(targetInspection.profileId === null ? {} : { profileId: targetInspection.profileId })
1694
1726
  };
1695
- const status = describeCurrentProfileBrainStatus(operatorInput);
1696
- const report = buildOperatorSurfaceReport(operatorInput);
1727
+ const { status, report } = describeCurrentProfileBrainStatusWithReport(operatorInput);
1697
1728
  const normalizedStatusAndReport = applyAttachmentPolicyTruth(status, report);
1698
1729
  const installHook = summarizeStatusInstallHook(parsed.openclawHome);
1699
1730
  const attachmentTruth = summarizeStatusAttachmentTruth({
@@ -4597,19 +4628,170 @@ function runUninstallCommand(parsed) {
4597
4628
  }
4598
4629
  return 0;
4599
4630
  }
4600
- function resolveServeTimeLearningRuntimeInput(activationRoot) {
4631
+ function resolveServeTimeLearningRuntimeInput(activationRoot, normalizedEventExport = null) {
4601
4632
  const logPath = resolveLearningSpineLogPath(activationRoot, "serveTimeRouteDecisions");
4602
- const { entries: serveTimeDecisions, fallbackReason } = readBoundedJsonlTail(logPath);
4633
+ const { entries: boundedServeTimeDecisions, fallbackReason } = readBoundedJsonlTail(logPath);
4634
+ const historicalRecovery = fallbackReason === null
4635
+ ? { decisions: [], scanFailed: false }
4636
+ : readHistoricalServeTimeDecisions(logPath, collectServeTimeDecisionRecoveryTargets(normalizedEventExport));
4637
+ const serveTimeDecisions = mergeHistoricalServeTimeDecisions(historicalRecovery.decisions, boundedServeTimeDecisions);
4603
4638
  const decisionLogCount = serveTimeDecisions.length;
4604
4639
  const pgVersion = decisionLogCount > 0 ? "v2" : "v1";
4640
+ const resolvedFallbackReason = combineServeTimeLearningFallbackReasons(fallbackReason, historicalRecovery.scanFailed ? "historical_recovery_scan_failed" : null);
4605
4641
  return {
4606
4642
  pgVersion,
4607
4643
  serveTimeDecisions,
4608
4644
  decisionLogCount,
4609
4645
  baselineState: pgVersion === "v2" ? loadOrInitBaseline(activationRoot) : undefined,
4610
- fallbackReason: fallbackReason === null ? null : `serve_time_decision_log_${fallbackReason}`
4646
+ fallbackReason: resolvedFallbackReason === null ? null : `serve_time_decision_log_${resolvedFallbackReason}`
4611
4647
  };
4612
4648
  }
4649
+ function combineServeTimeLearningFallbackReasons(...reasons) {
4650
+ const resolved = reasons
4651
+ .filter((reason) => typeof reason === "string" && reason.length > 0);
4652
+ if (resolved.length === 0) {
4653
+ return null;
4654
+ }
4655
+ return [...new Set(resolved.flatMap((reason) => reason.split("+").filter((part) => part.length > 0)))].join("+");
4656
+ }
4657
+ function mergeHistoricalServeTimeDecisions(historicalDecisions, boundedServeTimeDecisions) {
4658
+ const merged = [];
4659
+ const seenRecordIds = new Set();
4660
+ for (const decision of [...historicalDecisions, ...boundedServeTimeDecisions]) {
4661
+ const recordId = normalizeServeTimeDecisionRecoveryString(decision?.recordId);
4662
+ if (recordId !== null) {
4663
+ if (seenRecordIds.has(recordId)) {
4664
+ continue;
4665
+ }
4666
+ seenRecordIds.add(recordId);
4667
+ }
4668
+ merged.push(decision);
4669
+ }
4670
+ return merged;
4671
+ }
4672
+ function readHistoricalServeTimeDecisions(logPath, targets) {
4673
+ if (!hasServeTimeDecisionRecoveryTargets(targets)) {
4674
+ return { decisions: [], scanFailed: false };
4675
+ }
4676
+ let raw;
4677
+ try {
4678
+ raw = readFileSync(logPath, "utf8");
4679
+ }
4680
+ catch {
4681
+ return { decisions: [], scanFailed: true };
4682
+ }
4683
+ const decisions = [];
4684
+ for (const line of raw.split(/\r?\n/u)) {
4685
+ const trimmed = line.trim();
4686
+ if (trimmed.length === 0) {
4687
+ continue;
4688
+ }
4689
+ try {
4690
+ const decision = JSON.parse(trimmed);
4691
+ const recordId = normalizeServeTimeDecisionRecoveryString(decision?.recordId);
4692
+ const selectionDigestKey = buildServeTimeDecisionRecoverySelectionKey(decision?.selectionDigest, decision?.activePackGraphChecksum);
4693
+ const turnCompileEventId = normalizeServeTimeDecisionRecoveryString(decision?.turnCompileEventId);
4694
+ if ((recordId !== null && targets.recordIds.has(recordId)) ||
4695
+ (selectionDigestKey !== null && targets.selectionDigestKeys.has(selectionDigestKey)) ||
4696
+ (turnCompileEventId !== null && targets.turnCompileEventIds.has(turnCompileEventId))) {
4697
+ decisions.push(decision);
4698
+ }
4699
+ }
4700
+ catch {
4701
+ // skip malformed lines
4702
+ }
4703
+ }
4704
+ return { decisions, scanFailed: false };
4705
+ }
4706
+ function hasServeTimeDecisionRecoveryTargets(targets) {
4707
+ return targets.recordIds.size > 0 ||
4708
+ targets.selectionDigestKeys.size > 0 ||
4709
+ targets.turnCompileEventIds.size > 0;
4710
+ }
4711
+ function collectServeTimeDecisionRecoveryTargets(normalizedEventExport) {
4712
+ const targets = {
4713
+ recordIds: new Set(),
4714
+ selectionDigestKeys: new Set(),
4715
+ turnCompileEventIds: new Set()
4716
+ };
4717
+ const interactions = Array.isArray(normalizedEventExport?.interactionEvents)
4718
+ ? normalizedEventExport.interactionEvents
4719
+ : [];
4720
+ const feedbackEvents = Array.isArray(normalizedEventExport?.feedbackEvents)
4721
+ ? normalizedEventExport.feedbackEvents
4722
+ : [];
4723
+ const interactionsById = new Map();
4724
+ for (const interaction of interactions) {
4725
+ const interactionId = normalizeServeTimeDecisionRecoveryString(interaction?.eventId);
4726
+ if (interactionId !== null && !interactionsById.has(interactionId)) {
4727
+ interactionsById.set(interactionId, interaction);
4728
+ }
4729
+ }
4730
+ const candidateInteractions = [];
4731
+ for (const feedback of feedbackEvents) {
4732
+ const relatedInteractionId = normalizeServeTimeDecisionRecoveryString(feedback?.relatedInteractionId);
4733
+ if (relatedInteractionId === null) {
4734
+ continue;
4735
+ }
4736
+ targets.turnCompileEventIds.add(relatedInteractionId);
4737
+ const relatedInteraction = interactionsById.get(relatedInteractionId);
4738
+ if (relatedInteraction !== undefined) {
4739
+ candidateInteractions.push(relatedInteraction);
4740
+ }
4741
+ }
4742
+ for (const interaction of candidateInteractions) {
4743
+ const routeMetadata = readServeTimeDecisionRecoveryRecord(interaction?.routeMetadata);
4744
+ const decisionProvenance = readServeTimeDecisionRecoveryRecord(interaction?.decisionProvenance);
4745
+ const metadata = readServeTimeDecisionRecoveryRecord(interaction?.metadata);
4746
+ const serveDecisionRecordId = normalizeServeTimeDecisionRecoveryString(interaction?.serveDecisionRecordId)
4747
+ ?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.serveDecisionRecordId)
4748
+ ?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.serveDecisionRecordId)
4749
+ ?? normalizeServeTimeDecisionRecoveryString(metadata?.serveDecisionRecordId);
4750
+ if (serveDecisionRecordId !== null) {
4751
+ targets.recordIds.add(serveDecisionRecordId);
4752
+ }
4753
+ const selectionDigestKey = buildServeTimeDecisionRecoverySelectionKey(normalizeServeTimeDecisionRecoveryString(interaction?.selectionDigest)
4754
+ ?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.selectionDigest)
4755
+ ?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.selectionDigest)
4756
+ ?? normalizeServeTimeDecisionRecoveryString(metadata?.selectionDigest), normalizeServeTimeDecisionRecoveryString(interaction?.activePackGraphChecksum)
4757
+ ?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.activePackGraphChecksum)
4758
+ ?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.activePackGraphChecksum)
4759
+ ?? normalizeServeTimeDecisionRecoveryString(metadata?.activePackGraphChecksum));
4760
+ if (selectionDigestKey !== null) {
4761
+ targets.selectionDigestKeys.add(selectionDigestKey);
4762
+ }
4763
+ const explicitTurnCompileEventId = normalizeServeTimeDecisionRecoveryString(interaction?.turnCompileEventId)
4764
+ ?? normalizeServeTimeDecisionRecoveryString(routeMetadata?.turnCompileEventId)
4765
+ ?? normalizeServeTimeDecisionRecoveryString(decisionProvenance?.turnCompileEventId)
4766
+ ?? normalizeServeTimeDecisionRecoveryString(metadata?.turnCompileEventId);
4767
+ if (explicitTurnCompileEventId !== null) {
4768
+ targets.turnCompileEventIds.add(explicitTurnCompileEventId);
4769
+ }
4770
+ const softTurnCompileEventId = normalizeServeTimeDecisionRecoveryString(interaction?.eventId);
4771
+ if (softTurnCompileEventId !== null) {
4772
+ targets.turnCompileEventIds.add(softTurnCompileEventId);
4773
+ }
4774
+ }
4775
+ return targets;
4776
+ }
4777
+ function readServeTimeDecisionRecoveryRecord(value) {
4778
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
4779
+ }
4780
+ function normalizeServeTimeDecisionRecoveryString(value) {
4781
+ if (typeof value !== "string") {
4782
+ return null;
4783
+ }
4784
+ const trimmed = value.trim();
4785
+ return trimmed.length > 0 ? trimmed : null;
4786
+ }
4787
+ function buildServeTimeDecisionRecoverySelectionKey(selectionDigest, activePackGraphChecksum) {
4788
+ const normalizedSelectionDigest = normalizeServeTimeDecisionRecoveryString(selectionDigest);
4789
+ const normalizedGraphChecksum = normalizeServeTimeDecisionRecoveryString(activePackGraphChecksum);
4790
+ if (normalizedSelectionDigest === null || normalizedGraphChecksum === null) {
4791
+ return null;
4792
+ }
4793
+ return `${normalizedGraphChecksum}|${normalizedSelectionDigest}`;
4794
+ }
4613
4795
  function resolveActivationInspectionPackId(inspection, slot) {
4614
4796
  return inspection?.[slot]?.packId ?? inspection?.pointers?.[slot]?.packId ?? null;
4615
4797
  }
@@ -4855,7 +5037,7 @@ async function runLearnCommand(parsed) {
4855
5037
  }
4856
5038
  const learningExport = normalizedEventExport;
4857
5039
  const resolvedEmbedder = resolveCliEmbedderConfig(undefined, activationRoot);
4858
- const serveTimeLearning = resolveServeTimeLearningRuntimeInput(activationRoot);
5040
+ const serveTimeLearning = resolveServeTimeLearningRuntimeInput(activationRoot, normalizedEventExport);
4859
5041
  const learnerResult = drainAlwaysOnLearningRuntime({
4860
5042
  packLabel: "learn-cli",
4861
5043
  workspace: {
@@ -5679,8 +5861,8 @@ export async function createWatchCommandRuntime(input) {
5679
5861
  },
5680
5862
  learnedRouting: true,
5681
5863
  ...(teacherLabeler !== null ? { teacherLabeler } : {}),
5682
- resolveLearnedRoutingState: () => {
5683
- const resolved = resolveServeTimeLearningRuntimeInput(activationRoot);
5864
+ resolveLearnedRoutingState: (normalizedEventExport) => {
5865
+ const resolved = resolveServeTimeLearningRuntimeInput(activationRoot, normalizedEventExport);
5684
5866
  if (resolved.fallbackReason !== null && resolved.fallbackReason !== lastServeTimeFallbackReason) {
5685
5867
  log(`Serve-time routing fallback: ${resolved.fallbackReason}`);
5686
5868
  }
@@ -6364,13 +6546,16 @@ export function runOperatorCli(argv = process.argv.slice(2)) {
6364
6546
  : { profileId: targetInspection.profileId }),
6365
6547
  teacherSnapshotPath: resolveOperatorTeacherSnapshotPath(activationRoot, statusOrRollback.input.teacherSnapshotPath)
6366
6548
  };
6367
- const status = describeCurrentProfileBrainStatus(operatorInput);
6549
+ const statusWithReport = describeCurrentProfileBrainStatusWithReport(operatorInput);
6550
+ const status = statusWithReport.status;
6368
6551
  const tracedLearning = buildTracedLearningStatusSurface(activationRoot);
6369
- const normalizedStatusAndReport = applyAttachmentPolicyTruth(status, statusOrRollback.json ? null : buildOperatorSurfaceReport(operatorInput));
6552
+ const normalizedStatusAndReport = applyAttachmentPolicyTruth(status, statusOrRollback.json ? null : statusWithReport.report);
6553
+ const hotfixBoundaryTruth = summarizeStatusHotfixBoundary(normalizedStatusAndReport.status);
6370
6554
  if (statusOrRollback.json) {
6371
6555
  console.log(JSON.stringify({
6372
6556
  ...normalizedStatusAndReport.status,
6373
- tracedLearning
6557
+ tracedLearning,
6558
+ hotfixBoundaryTruth
6374
6559
  }, null, 2));
6375
6560
  }
6376
6561
  else {
@@ -46,6 +46,8 @@ export interface ManagedLearnerServiceInspection {
46
46
  configuredCommand: string | null;
47
47
  configuredRuntimePath: string | null;
48
48
  configuredRuntimePackageSpec: string | null;
49
+ configuredRuntimePackageName: string | null;
50
+ configuredRuntimePackageVersion: string | null;
49
51
  configuredRuntimeLooksEphemeral: boolean | null;
50
52
  matchesRequestedActivationRoot: boolean | null;
51
53
  launchctlAvailable: boolean;
@@ -306,6 +306,17 @@ export function describeManagedLearnerServiceRuntimeGuard(inspection) {
306
306
  detail: `Learner service points at the durable ${CLI_PACKAGE_NAME} runtime.`
307
307
  };
308
308
  }
309
+ function buildDaemonHotfixBoundary(inspection) {
310
+ return {
311
+ surface: "daemon_runtime",
312
+ separateFromInstalledHookSurface: true,
313
+ runtimePath: inspection.configuredRuntimePath ?? null,
314
+ guidance: "Patch this daemon runtime path for background watch/learner fixes. Use `openclawbrain status --openclaw-home <path> --detailed` to inspect the separate installed hook/runtime-guard surface before patching OpenClaw load behavior.",
315
+ detail: inspection.configuredRuntimePath === null
316
+ ? "daemon status is only reporting the background watch surface; no configured runtime path is visible yet."
317
+ : `daemon status is reporting the background watch runtime at ${inspection.configuredRuntimePath}; installed hook/runtime-guard paths live on the OpenClaw profile side.`
318
+ };
319
+ }
309
320
  function resolveDaemonProgramArguments() {
310
321
  for (const candidate of getOpenclawbrainCliScriptPathCandidates()) {
311
322
  const cliScriptPath = resolveCliScriptCandidate(candidate);
@@ -970,6 +981,11 @@ export function daemonStatus(activationRoot, json) {
970
981
  ? null
971
982
  : canonicalizeActivationRoot(configuredActivationRoot) === serviceIdentity.canonicalActivationRoot;
972
983
  const daemonLaunchDescription = describeDaemonProgramArguments(configuredProgramArguments);
984
+ const hotfixBoundary = buildDaemonHotfixBoundary({
985
+ installed: plistInstalled,
986
+ configuredProgramArguments,
987
+ ...daemonLaunchDescription,
988
+ });
973
989
  if (json) {
974
990
  console.log(JSON.stringify({
975
991
  command: "daemon status",
@@ -986,6 +1002,7 @@ export function daemonStatus(activationRoot, json) {
986
1002
  ...watchStatePaths,
987
1003
  watchState,
988
1004
  lastLogLines,
1005
+ hotfixBoundary,
989
1006
  }, null, 2));
990
1007
  }
991
1008
  else {
@@ -1015,6 +1032,8 @@ export function daemonStatus(activationRoot, json) {
1015
1032
  const runtimeWarning = daemonLaunchDescription.configuredRuntimeLooksEphemeral ? " [ephemeral]" : "";
1016
1033
  console.log(` Runtime: ${daemonLaunchDescription.configuredRuntimePath}${runtimePackageSuffix}${runtimeWarning}`);
1017
1034
  }
1035
+ console.log(" Runtime surface: daemon watch/learner runtime");
1036
+ console.log(` Hotfix boundary: ${hotfixBoundary.guidance}`);
1018
1037
  const runtimeGuard = describeManagedLearnerServiceRuntimeGuard({
1019
1038
  installed: plistInstalled,
1020
1039
  configuredProgramArguments,
@@ -1,8 +1,8 @@
1
1
  import { type CompileSelectionMode } from "@openclawbrain/compiler";
2
2
  import { CONTRACT_IDS, type ArtifactManifestV1, type ActivationPointerRecordV1, type ActivationPointerSlot, type RuntimeTurnBrainAttachmentPolicyV1, type ContextCompactionMode, type ContextContributionEvidenceStateV1, type CurrentProfileBrainStatusAnswerV1, type CurrentProfileActivationStateV1, type CurrentProfilePassiveLearningDeltaSummaryV1, type CurrentProfilePassiveLearningWatchStateV1, type CurrentProfileAttachmentStateV1, type CurrentProfileAttachmentProofStateV1, type CurrentProfileHookInstallStateV1, type CurrentProfileHookLoadabilityV1, type CurrentProfileHookLoadProofV1, type BrainServeHotPathTimingV1, type CurrentProfileStructuralDecisionV1, type FeedbackEventKind, type PackGraphConnectDiagnosticsV1, type PackGraphEvolutionV1, type EventSemanticSurfaceV1, type FeedbackEventV1, type KernelSurfaceValidationResultV1, type LearningBootProfile, type LearningCadence, type LearningScanPolicy, type InteractionEventV1, type NormalizedEventExportV1, type NormalizedEventV1, type PrincipalPriorityClassV1, type PrincipalRoleV1, type RouteMode, type RuntimeCompileResponseV1, type RuntimeCompileStructuralSignalsV1, type RuntimeCompileTargetV1, type RuntimeGraphPlasticityStateV1, type RuntimePlasticitySourceV1, type SparseFeedbackPolicyV1, type TeacherAuthorityV1, type TeacherSupervisionArtifactV1, type WorkspaceInjectionSurfaceV1 } from "@openclawbrain/contracts";
3
3
  import { type EventExportLaneV1 } from "@openclawbrain/event-export";
4
- import { type AdvanceAlwaysOnLearningRuntimeInput, type AlwaysOnLearningCadenceV1, type AlwaysOnLearningMaterializationJobV1, type AlwaysOnLearningRuntimePlanV1, type AlwaysOnLearningRuntimeStateV1, type BaselineStateV1, type PendingPrincipalEventV1, type PrincipalLearningCheckpointV1 } from "./local-learner.js";
5
- import { type ActivationInspection, type ActivationObservabilityReport, type GraphEvolutionLogV1, type LearningSpineServeRouteBreadcrumbsV1, type ActivationSlotInspection, type InitHandoffState, type LearningSpineServeRouteDecisionLogEntryV1 } from "@openclawbrain/pack-format";
4
+ import { type AdvanceAlwaysOnLearningRuntimeInput, type AlwaysOnLearningCadenceV1, type AlwaysOnLearningMaterializationJobV1, type AlwaysOnLearningRuntimePlanV1, type AlwaysOnLearningRuntimeStateV1, type BaselineStateV1, type PendingPrincipalEventV1, type PrincipalLearningCheckpointV1, type LearningSpineServeRouteDecisionLogEntryV1 } from "./local-learner.js";
5
+ import { type ActivationInspection, type ActivationObservabilityReport, type GraphEvolutionLogV1, type LearningSpineServeRouteBreadcrumbsV1, type ActivationSlotInspection, type InitHandoffState } from "@openclawbrain/pack-format";
6
6
  export { clearOpenClawProfileRuntimeLoadProof, listOpenClawProfileRuntimeLoadProofs, recordOpenClawProfileRuntimeLoadProof, resolveAttachmentRuntimeLoadProofsPath, type OpenClawProfileRuntimeLoadProofRecordV1, type OpenClawProfileRuntimeLoadProofSetV1, type OpenClawProfileRuntimeLoadProofsV1 } from "./attachment-truth.js";
7
7
  import { type AsyncTeacherLabelerConfigV1 } from "./teacher-labeler.js";
8
8
  export { createHttpOllamaTeacherLabelerClient, createOllamaTeacherLabeler, createTeacherLabeler, summarizeTeacherLabelerOpportunity, type AsyncTeacherLabelerConfigV1, type AsyncTeacherNoopLabelerConfigV1, type AsyncTeacherOllamaLabelerConfigV1, type OllamaTeacherLabelerClient, type TeacherLabeler, type TeacherLabelerOpportunityInputV1, type TeacherLabelerOpportunityV1, type TeacherLabelerResultV1, type TeacherLabelerRunInputV1 } from "./teacher-labeler.js";
package/dist/src/index.js CHANGED
@@ -904,7 +904,7 @@ export class AsyncTeacherLiveLoop {
904
904
  interactionEvents: this.interactionEvents,
905
905
  feedbackEvents: this.feedbackEvents
906
906
  });
907
- const learnedRoutingState = this.input.resolveLearnedRoutingState?.() ?? {};
907
+ const learnedRoutingState = this.input.resolveLearnedRoutingState?.(mergedNormalizedEventExport) ?? {};
908
908
  const currentDedupIds = new Set(this.teacherArtifacts.map((artifact) => artifact.dedupId));
909
909
  const currentCycleBuiltArtifacts = buildTeacherSupervisionArtifactsFromNormalizedEventExport({
910
910
  normalizedEventExport: job.normalizedEventExport,
@@ -8031,9 +8031,15 @@ export function buildOperatorSurfaceReport(input) {
8031
8031
  findings
8032
8032
  };
8033
8033
  }
8034
- export function describeCurrentProfileBrainStatus(input) {
8034
+ export function describeCurrentProfileBrainStatusWithReport(input) {
8035
8035
  const report = buildOperatorSurfaceReport(input);
8036
- return buildCurrentProfileBrainStatusFromReport(report, report.manyProfile.declaredAttachmentPolicy, normalizeOptionalString(input.profileId) ?? null);
8036
+ return {
8037
+ report,
8038
+ status: buildCurrentProfileBrainStatusFromReport(report, report.manyProfile.declaredAttachmentPolicy, normalizeOptionalString(input.profileId) ?? null)
8039
+ };
8040
+ }
8041
+ export function describeCurrentProfileBrainStatus(input) {
8042
+ return describeCurrentProfileBrainStatusWithReport(input).status;
8037
8043
  }
8038
8044
  export function formatOperatorRollbackReport(result) {
8039
8045
  const header = result.allowed ? (result.dryRun ? "ROLLBACK ready" : "ROLLBACK ok") : "ROLLBACK blocked";
@@ -1,6 +1,7 @@
1
1
  import { type AlwaysOnLearningMaterializationJobV1 } from "@openclawbrain/learner";
2
2
  import { type BrainServeHotPathTimingV1, type NormalizedEventExportV1, type RouteMode, type RuntimeCompileResponseV1 } from "@openclawbrain/contracts";
3
- import { type LearningSpinePgRouteUpdateLogEntryV1, type LearningSpineServeRouteBreadcrumbsV1, type LearningSpineServeRouteDecisionLogEntryV1, type PackDescriptor } from "@openclawbrain/pack-format";
3
+ import { type LearningSpinePgRouteUpdateLogEntryV1, type LearningSpineServeRouteBreadcrumbsV1, type PackDescriptor } from "@openclawbrain/pack-format";
4
+ import { type LearningSpineServeRouteDecisionLogEntryV1 } from "./local-learner.js";
4
5
  type CompileFailureLike = {
5
6
  ok: false;
6
7
  fallbackToStaticContext: boolean;
@@ -1,8 +1,24 @@
1
1
  import { type ArtifactManifestV1, type FeedbackEventV1, type InteractionEventV1, type NormalizedEventExportV1, type NormalizedEventV1, type PrincipalPriorityClassV1, type PrincipalRoleV1, type PackGraphPayloadV1, type PackVectorsPayloadV1, type RouterArtifactV1, type RouterPolicyUpdateV1, type RuntimeCompileStructuralSignalsV1, type RuntimeGraphPlasticityStateV1, type SparseFeedbackPolicyV1, type TeacherSupervisionArtifactV1 } from "@openclawbrain/contracts";
2
2
  import { type EventExportCursorV1, type EventExportLaneV1, type NormalizedEventExportBridgeV1, type NormalizedEventExportSliceV1 } from "@openclawbrain/event-export";
3
3
  import type { TextEmbedder } from "@openclawbrain/compiler";
4
- import { type PackDescriptor, type GraphEvolutionLogV1, type LearningSpineServeRouteDecisionLogEntryV1 } from "@openclawbrain/pack-format";
4
+ import { type PackDescriptor, type GraphEvolutionLogV1, type LearningSpineServeRouteDecisionLogEntryV1 as PackFormatLearningSpineServeRouteDecisionLogEntryV1 } from "@openclawbrain/pack-format";
5
5
  import { type WorkspaceMetadataInput } from "@openclawbrain/workspace-metadata";
6
+ export interface LearningSpineServeRouteCandidateScoreV1 {
7
+ blockId: string;
8
+ selected: boolean;
9
+ actionScore: number;
10
+ actionProbability: number;
11
+ compactedFrom?: string[];
12
+ matchedTokens?: string[];
13
+ routingChannels?: string[];
14
+ }
15
+ export type LearningSpineServeRouteDecisionLogEntryV1 = Omit<PackFormatLearningSpineServeRouteDecisionLogEntryV1, "candidateSetIds" | "chosenContextIds" | "candidateScores" | "selectedKernelContextIds" | "selectedBrainContextIds"> & {
16
+ candidateSetIds: string[];
17
+ chosenContextIds: string[];
18
+ candidateScores: LearningSpineServeRouteCandidateScoreV1[];
19
+ selectedKernelContextIds: string[];
20
+ selectedBrainContextIds: string[];
21
+ };
6
22
  export interface CandidatePackEventExports {
7
23
  interactionEvents: InteractionEventV1[];
8
24
  feedbackEvents: FeedbackEventV1[];