@openclawbrain/cli 0.4.24 → 0.4.26
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 +8 -6
- package/dist/src/index.js +8 -2
- package/dist/src/proof-command.js +73 -5
- package/dist/src/status-learning-path.js +24 -1
- package/dist/src/traced-learning-bridge.js +485 -17
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ import { inspectOpenClawBrainHookStatus, inspectOpenClawBrainPluginAllowlist } f
|
|
|
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,
|
|
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 { formatOperatorLearningAttributionSummary, formatOperatorLearningPathSummary } from "./status-learning-path.js";
|
|
28
|
+
import { formatOperatorAttributionCoverageSummary, formatOperatorFeedbackSummary, formatOperatorLearningAttributionSummary, 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";
|
|
@@ -1500,7 +1500,9 @@ function formatCurrentProfileStatusSummary(status, report, targetInspection, opt
|
|
|
1500
1500
|
learningPath: report.learningPath,
|
|
1501
1501
|
tracedLearning
|
|
1502
1502
|
})}`,
|
|
1503
|
+
`feedback ${formatOperatorFeedbackSummary({ tracedLearning })}`,
|
|
1503
1504
|
`attribution ${formatOperatorLearningAttributionSummary({ status })}`,
|
|
1505
|
+
`attrCover ${formatOperatorAttributionCoverageSummary({ tracedLearning })}`,
|
|
1504
1506
|
`learning state=${report.learning.backlogState} bootstrapped=${yesNo(report.learning.bootstrapped)} mode=${report.learning.mode} next=${report.learning.nextPriorityLane} priority=${report.learning.nextPriorityBucket} pending=${report.learning.pendingLive ?? "none"}/${report.learning.pendingBackfill ?? "none"} buckets=${formatLearningBuckets(report)} warn=${formatLearningWarnings(report)} lastPack=${report.learning.lastMaterializedPackId ?? "none"} detail=${report.learning.detail}`,
|
|
1505
1507
|
`traced ${formatTracedLearningSurface(tracedLearning)}`,
|
|
1506
1508
|
`teacherProof ${formatTeacherLoopSummary(report)}`,
|
|
@@ -1690,8 +1692,7 @@ function inspectInstallConvergeVerification(parsed) {
|
|
|
1690
1692
|
openclawHome: parsed.openclawHome,
|
|
1691
1693
|
...(targetInspection.profileId === null ? {} : { profileId: targetInspection.profileId })
|
|
1692
1694
|
};
|
|
1693
|
-
const status =
|
|
1694
|
-
const report = buildOperatorSurfaceReport(operatorInput);
|
|
1695
|
+
const { status, report } = describeCurrentProfileBrainStatusWithReport(operatorInput);
|
|
1695
1696
|
const normalizedStatusAndReport = applyAttachmentPolicyTruth(status, report);
|
|
1696
1697
|
const installHook = summarizeStatusInstallHook(parsed.openclawHome);
|
|
1697
1698
|
const attachmentTruth = summarizeStatusAttachmentTruth({
|
|
@@ -6362,9 +6363,10 @@ export function runOperatorCli(argv = process.argv.slice(2)) {
|
|
|
6362
6363
|
: { profileId: targetInspection.profileId }),
|
|
6363
6364
|
teacherSnapshotPath: resolveOperatorTeacherSnapshotPath(activationRoot, statusOrRollback.input.teacherSnapshotPath)
|
|
6364
6365
|
};
|
|
6365
|
-
const
|
|
6366
|
+
const statusWithReport = describeCurrentProfileBrainStatusWithReport(operatorInput);
|
|
6367
|
+
const status = statusWithReport.status;
|
|
6366
6368
|
const tracedLearning = buildTracedLearningStatusSurface(activationRoot);
|
|
6367
|
-
const normalizedStatusAndReport = applyAttachmentPolicyTruth(status, statusOrRollback.json ? null :
|
|
6369
|
+
const normalizedStatusAndReport = applyAttachmentPolicyTruth(status, statusOrRollback.json ? null : statusWithReport.report);
|
|
6368
6370
|
if (statusOrRollback.json) {
|
|
6369
6371
|
console.log(JSON.stringify({
|
|
6370
6372
|
...normalizedStatusAndReport.status,
|
package/dist/src/index.js
CHANGED
|
@@ -8031,9 +8031,15 @@ export function buildOperatorSurfaceReport(input) {
|
|
|
8031
8031
|
findings
|
|
8032
8032
|
};
|
|
8033
8033
|
}
|
|
8034
|
-
export function
|
|
8034
|
+
export function describeCurrentProfileBrainStatusWithReport(input) {
|
|
8035
8035
|
const report = buildOperatorSurfaceReport(input);
|
|
8036
|
-
return
|
|
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";
|
|
@@ -76,6 +76,41 @@ function writeJson(filePath, value) {
|
|
|
76
76
|
writeText(filePath, `${JSON.stringify(value, null, 2)}\n`);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function readJsonObject(value) {
|
|
80
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function parseJsonObjectText(text) {
|
|
87
|
+
if (typeof text !== "string" || text.trim().length === 0) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return readJsonObject(JSON.parse(text));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalizeOptionalBoolean(value) {
|
|
99
|
+
return value === true ? true : value === false ? false : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function extractInstallRestartState(text) {
|
|
103
|
+
const parsed = parseJsonObjectText(text);
|
|
104
|
+
const restart = readJsonObject(parsed?.restart ?? null);
|
|
105
|
+
if (restart === null) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
required: normalizeOptionalBoolean(restart.required),
|
|
110
|
+
performed: normalizeOptionalBoolean(restart.performed),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
79
114
|
function buildCurrentCliInvocation(cliEntryPath = process.argv[1]) {
|
|
80
115
|
const normalizedEntryPath = normalizeOptionalCliString(cliEntryPath);
|
|
81
116
|
if (normalizedEntryPath === null) {
|
|
@@ -511,7 +546,7 @@ function buildVerdict({ steps, gatewayStatus, pluginInspect, statusSignals, brea
|
|
|
511
546
|
};
|
|
512
547
|
}
|
|
513
548
|
|
|
514
|
-
function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, guardLine, attributionLine, learningPathLine, coverageSnapshot, hardeningSnapshot }) {
|
|
549
|
+
function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspectText, statusSignals, breadcrumbs, runtimeLoadProofSnapshot, guardLine, feedbackLine, attributionLine, attributionCoverageLine, learningPathLine, coverageSnapshot, hardeningSnapshot }) {
|
|
515
550
|
const passed = [];
|
|
516
551
|
const missing = [];
|
|
517
552
|
const warnings = Array.isArray(verdict.warnings) ? verdict.warnings : [];
|
|
@@ -573,9 +608,15 @@ function buildSummary({ options, steps, verdict, gatewayStatusText, pluginInspec
|
|
|
573
608
|
: [`- ${guardLine}`]),
|
|
574
609
|
"",
|
|
575
610
|
"## Learning Attribution",
|
|
611
|
+
...(feedbackLine === null
|
|
612
|
+
? ["- feedback line not reported by detailed status"]
|
|
613
|
+
: [`- ${feedbackLine}`]),
|
|
576
614
|
...(attributionLine === null
|
|
577
615
|
? ["- attribution line not reported by detailed status"]
|
|
578
616
|
: [`- ${attributionLine}`]),
|
|
617
|
+
...(attributionCoverageLine === null
|
|
618
|
+
? ["- attribution coverage line not reported by detailed status"]
|
|
619
|
+
: [`- ${attributionCoverageLine}`]),
|
|
579
620
|
...(learningPathLine === null
|
|
580
621
|
? []
|
|
581
622
|
: [`- ${learningPathLine}`]),
|
|
@@ -802,7 +843,7 @@ export function captureOperatorProofBundle(options) {
|
|
|
802
843
|
mkdirSync(bundleDir, { recursive: true });
|
|
803
844
|
const steps = [];
|
|
804
845
|
const gatewayProfile = readOpenClawProfileName(options.openclawHome);
|
|
805
|
-
function addStep(stepId, label, command, args, { skipped = false } = {}) {
|
|
846
|
+
function addStep(stepId, label, command, args, { skipped = false, skipSummary = "step intentionally skipped" } = {}) {
|
|
806
847
|
if (skipped) {
|
|
807
848
|
steps.push({
|
|
808
849
|
stepId,
|
|
@@ -811,7 +852,7 @@ export function captureOperatorProofBundle(options) {
|
|
|
811
852
|
skipped: true,
|
|
812
853
|
captureState: "complete",
|
|
813
854
|
resultClass: "success",
|
|
814
|
-
summary:
|
|
855
|
+
summary: skipSummary,
|
|
815
856
|
stdoutPath: null,
|
|
816
857
|
stderrPath: null,
|
|
817
858
|
});
|
|
@@ -844,8 +885,27 @@ export function captureOperatorProofBundle(options) {
|
|
|
844
885
|
});
|
|
845
886
|
return capture;
|
|
846
887
|
}
|
|
847
|
-
addStep("01-install", "install", cliInvocation.command, [...cliInvocation.args, "install", "--openclaw-home", options.openclawHome], { skipped: options.skipInstall === true });
|
|
848
|
-
|
|
888
|
+
const installCapture = addStep("01-install", "install", cliInvocation.command, [...cliInvocation.args, "install", "--openclaw-home", options.openclawHome, "--json"], { skipped: options.skipInstall === true });
|
|
889
|
+
const installRestartState = options.skipInstall === true || installCapture.exitCode !== 0 || installCapture.error
|
|
890
|
+
? null
|
|
891
|
+
: extractInstallRestartState(installCapture.stdout);
|
|
892
|
+
let restartSkipSummary = null;
|
|
893
|
+
if (options.skipRestart === true) {
|
|
894
|
+
restartSkipSummary = "step intentionally skipped";
|
|
895
|
+
}
|
|
896
|
+
else if (installRestartState?.performed === true) {
|
|
897
|
+
restartSkipSummary = "step intentionally skipped because install already performed the gateway restart";
|
|
898
|
+
}
|
|
899
|
+
else if (installRestartState?.required === false) {
|
|
900
|
+
restartSkipSummary = "step intentionally skipped because install reported no gateway restart was required";
|
|
901
|
+
}
|
|
902
|
+
else if (gatewayProfile === null) {
|
|
903
|
+
restartSkipSummary = "skipped because exact OpenClaw profile token could not be inferred; avoiding shared-gateway self-interrupt during proof capture";
|
|
904
|
+
}
|
|
905
|
+
addStep("02-restart", "gateway restart", "openclaw", buildGatewayArgs("restart", gatewayProfile), {
|
|
906
|
+
skipped: restartSkipSummary !== null,
|
|
907
|
+
skipSummary: restartSkipSummary ?? undefined
|
|
908
|
+
});
|
|
849
909
|
const gatewayStatusCapture = addStep("03-gateway-status", "gateway status", "openclaw", buildGatewayStatusArgs(
|
|
850
910
|
gatewayProfile,
|
|
851
911
|
normalizeOptionalCliString(options.gatewayUrl ?? null),
|
|
@@ -861,7 +921,9 @@ export function captureOperatorProofBundle(options) {
|
|
|
861
921
|
const serveLine = extractDetailedStatusLine(statusCapture.stdout, "serve");
|
|
862
922
|
const routeFnLine = extractDetailedStatusLine(statusCapture.stdout, "routeFn");
|
|
863
923
|
const guardLine = extractDetailedStatusLine(statusCapture.stdout, "guard");
|
|
924
|
+
const feedbackLine = extractDetailedStatusLine(statusCapture.stdout, "feedback");
|
|
864
925
|
const attributionLine = extractDetailedStatusLine(statusCapture.stdout, "attribution");
|
|
926
|
+
const attributionCoverageLine = extractDetailedStatusLine(statusCapture.stdout, "attrCover");
|
|
865
927
|
const learningPathLine = extractDetailedStatusLine(statusCapture.stdout, "path");
|
|
866
928
|
const runtimeLoadProofPath = normalizeReportedProofPath(statusSignals.proofPath)
|
|
867
929
|
?? path.join(activationRoot, "attachment-truth", "runtime-load-proofs.json");
|
|
@@ -917,7 +979,9 @@ export function captureOperatorProofBundle(options) {
|
|
|
917
979
|
runtimeLoadProofPath,
|
|
918
980
|
runtimeLoadProofError: runtimeLoadProofSnapshot.error,
|
|
919
981
|
guardLine,
|
|
982
|
+
feedbackLine,
|
|
920
983
|
attributionLine,
|
|
984
|
+
attributionCoverageLine,
|
|
921
985
|
learningPathLine,
|
|
922
986
|
});
|
|
923
987
|
writeJson(path.join(bundleDir, "hardening-snapshot.json"), hardeningSnapshot);
|
|
@@ -931,7 +995,9 @@ export function captureOperatorProofBundle(options) {
|
|
|
931
995
|
breadcrumbs,
|
|
932
996
|
runtimeLoadProofSnapshot,
|
|
933
997
|
guardLine,
|
|
998
|
+
feedbackLine,
|
|
934
999
|
attributionLine,
|
|
1000
|
+
attributionCoverageLine,
|
|
935
1001
|
learningPathLine,
|
|
936
1002
|
coverageSnapshot,
|
|
937
1003
|
hardeningSnapshot,
|
|
@@ -950,7 +1016,9 @@ export function captureOperatorProofBundle(options) {
|
|
|
950
1016
|
verdict,
|
|
951
1017
|
statusSignals,
|
|
952
1018
|
guardLine,
|
|
1019
|
+
feedbackLine,
|
|
953
1020
|
attributionLine,
|
|
1021
|
+
attributionCoverageLine,
|
|
954
1022
|
learningPathLine,
|
|
955
1023
|
steps,
|
|
956
1024
|
summaryPath: path.join(bundleDir, "summary.md"),
|
|
@@ -7,6 +7,29 @@ function isSeedAwaitingFirstPromotion(status) {
|
|
|
7
7
|
function normalizeOptionalString(value) {
|
|
8
8
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
9
9
|
}
|
|
10
|
+
function formatOptionalFeedbackLatest(tracedLearning) {
|
|
11
|
+
const latestLabel = normalizeOptionalString(tracedLearning?.feedbackSummary?.latestLabel);
|
|
12
|
+
return latestLabel === null ? "" : ` latest=${latestLabel}`;
|
|
13
|
+
}
|
|
14
|
+
function formatOperatorFeedbackSummary({ tracedLearning }) {
|
|
15
|
+
const routeTraceCount = tracedLearning?.feedbackSummary?.routeTraceCount ?? tracedLearning?.routeTraceCount ?? 0;
|
|
16
|
+
const supervisedTraceCount = tracedLearning?.feedbackSummary?.supervisedTraceCount ?? tracedLearning?.supervisionCount ?? 0;
|
|
17
|
+
return [
|
|
18
|
+
`helpful=${tracedLearning?.feedbackSummary?.helpfulCount ?? 0}`,
|
|
19
|
+
`irrelevant=${tracedLearning?.feedbackSummary?.irrelevantCount ?? 0}`,
|
|
20
|
+
`harmful=${tracedLearning?.feedbackSummary?.harmfulCount ?? 0}`,
|
|
21
|
+
`supervisedTraceCount=${supervisedTraceCount}`,
|
|
22
|
+
`routeTraceCount=${routeTraceCount}`
|
|
23
|
+
].join(" ") + formatOptionalFeedbackLatest(tracedLearning);
|
|
24
|
+
}
|
|
25
|
+
function formatOperatorAttributionCoverageSummary({ tracedLearning }) {
|
|
26
|
+
return [
|
|
27
|
+
`completedWithoutEvaluation=${tracedLearning?.attributionCoverage?.completedWithoutEvaluationCount ?? 0}`,
|
|
28
|
+
`ready=${tracedLearning?.attributionCoverage?.readyCount ?? 0}`,
|
|
29
|
+
`delayed=${tracedLearning?.attributionCoverage?.delayedCount ?? 0}`,
|
|
30
|
+
`budgetDeferred=${tracedLearning?.attributionCoverage?.budgetDeferredCount ?? 0}`
|
|
31
|
+
].join(" ");
|
|
32
|
+
}
|
|
10
33
|
function formatOperatorLearningAttributionSummary({ status }) {
|
|
11
34
|
const attribution = status?.learningAttribution ?? null;
|
|
12
35
|
if (!attribution) {
|
|
@@ -55,4 +78,4 @@ export function formatOperatorLearningPathSummary({ status, learningPath, traced
|
|
|
55
78
|
...detailParts
|
|
56
79
|
].join(" ");
|
|
57
80
|
}
|
|
58
|
-
export { formatOperatorLearningAttributionSummary };
|
|
81
|
+
export { formatOperatorAttributionCoverageSummary, formatOperatorFeedbackSummary, formatOperatorLearningAttributionSummary };
|
|
@@ -15,12 +15,412 @@ function normalizeCount(value) {
|
|
|
15
15
|
function normalizeOptionalString(value) {
|
|
16
16
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
17
17
|
}
|
|
18
|
+
function parseJsonValue(value, fallback) {
|
|
19
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
20
|
+
return fallback;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(value);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return fallback;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
18
29
|
function normalizeUnitInterval(value) {
|
|
19
30
|
return Number.isFinite(value) ? Math.max(0, Math.min(1, Number(value))) : 0;
|
|
20
31
|
}
|
|
21
32
|
function normalizeSource(value) {
|
|
22
33
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
23
34
|
}
|
|
35
|
+
function toRecord(value) {
|
|
36
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
37
|
+
}
|
|
38
|
+
function normalizeAgentIdentity(value) {
|
|
39
|
+
const record = toRecord(value);
|
|
40
|
+
const agentId = normalizeOptionalString(record?.agentId);
|
|
41
|
+
const lane = normalizeOptionalString(record?.lane);
|
|
42
|
+
return agentId === null || lane === null ? null : { agentId, lane };
|
|
43
|
+
}
|
|
44
|
+
function formatAgentIdentity(identity) {
|
|
45
|
+
if (identity === null) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return identity.lane === "main" ? identity.agentId : `${identity.agentId}:${identity.lane}`;
|
|
49
|
+
}
|
|
50
|
+
function defaultFeedbackSummary(routeTraceCount = 0, supervisedTraceCount = 0, detail = "feedback truth is not visible in the current status surface") {
|
|
51
|
+
return {
|
|
52
|
+
visible: false,
|
|
53
|
+
helpfulCount: 0,
|
|
54
|
+
irrelevantCount: 0,
|
|
55
|
+
harmfulCount: 0,
|
|
56
|
+
supervisedTraceCount,
|
|
57
|
+
routeTraceCount,
|
|
58
|
+
latestAgentIdentity: null,
|
|
59
|
+
latestLabel: null,
|
|
60
|
+
detail
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function normalizeFeedbackSummary(value, counts = {}) {
|
|
64
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
65
|
+
return defaultFeedbackSummary(normalizeCount(counts.routeTraceCount), normalizeCount(counts.supervisedTraceCount));
|
|
66
|
+
}
|
|
67
|
+
const routeTraceCount = normalizeCount(value.routeTraceCount ?? counts.routeTraceCount);
|
|
68
|
+
const supervisedTraceCount = normalizeCount(value.supervisedTraceCount ?? counts.supervisedTraceCount);
|
|
69
|
+
const latestAgentIdentity = normalizeAgentIdentity(value.latestAgentIdentity);
|
|
70
|
+
return {
|
|
71
|
+
visible: value.visible === true,
|
|
72
|
+
helpfulCount: normalizeCount(value.helpfulCount),
|
|
73
|
+
irrelevantCount: normalizeCount(value.irrelevantCount),
|
|
74
|
+
harmfulCount: normalizeCount(value.harmfulCount),
|
|
75
|
+
supervisedTraceCount,
|
|
76
|
+
routeTraceCount,
|
|
77
|
+
latestAgentIdentity,
|
|
78
|
+
latestLabel: normalizeOptionalString(value.latestLabel) ?? formatAgentIdentity(latestAgentIdentity),
|
|
79
|
+
detail: normalizeOptionalString(value.detail)
|
|
80
|
+
?? (routeTraceCount === 0
|
|
81
|
+
? "no traced routes recorded yet"
|
|
82
|
+
: `${supervisedTraceCount}/${routeTraceCount} traced routes are covered by live verdicts`)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function defaultAttributionCoverage(detail = "teacher gating truth is not visible in the current status surface") {
|
|
86
|
+
return {
|
|
87
|
+
visible: false,
|
|
88
|
+
gatingVisible: false,
|
|
89
|
+
completedWithoutEvaluationCount: 0,
|
|
90
|
+
readyCount: 0,
|
|
91
|
+
delayedCount: 0,
|
|
92
|
+
budgetDeferredCount: 0,
|
|
93
|
+
detail
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function normalizeAttributionCoverage(value) {
|
|
97
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
98
|
+
return defaultAttributionCoverage();
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
visible: value.visible === true,
|
|
102
|
+
gatingVisible: value.gatingVisible === true,
|
|
103
|
+
completedWithoutEvaluationCount: normalizeCount(value.completedWithoutEvaluationCount),
|
|
104
|
+
readyCount: normalizeCount(value.readyCount),
|
|
105
|
+
delayedCount: normalizeCount(value.delayedCount),
|
|
106
|
+
budgetDeferredCount: normalizeCount(value.budgetDeferredCount),
|
|
107
|
+
detail: normalizeOptionalString(value.detail)
|
|
108
|
+
?? "teacher gating truth is not visible in the current status surface"
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function hasNonEmptyToolResults(value) {
|
|
112
|
+
if (Array.isArray(value)) {
|
|
113
|
+
return value.length > 0;
|
|
114
|
+
}
|
|
115
|
+
return typeof value === "string" && value.trim().length > 0 && value.trim() !== "[]";
|
|
116
|
+
}
|
|
117
|
+
function hasTeacherBindingMode(rawEvaluation) {
|
|
118
|
+
const evaluation = parseJsonValue(rawEvaluation, null);
|
|
119
|
+
switch (evaluation?.bindingMode) {
|
|
120
|
+
case "exact_decision_id":
|
|
121
|
+
case "exact_selection_digest":
|
|
122
|
+
case "turn_compile_event_id":
|
|
123
|
+
case "trace_id":
|
|
124
|
+
case "legacy_heuristic":
|
|
125
|
+
case "unbound":
|
|
126
|
+
return true;
|
|
127
|
+
default:
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function classifyContextFeedbackVerdict(score) {
|
|
132
|
+
if (Number(score) >= 0.25) {
|
|
133
|
+
return "helpful";
|
|
134
|
+
}
|
|
135
|
+
if (Number(score) <= -0.25) {
|
|
136
|
+
return "harmful";
|
|
137
|
+
}
|
|
138
|
+
return "irrelevant";
|
|
139
|
+
}
|
|
140
|
+
function isObservationReadyForTeacher(row, readyBefore) {
|
|
141
|
+
return row.status === "pending_teacher"
|
|
142
|
+
|| normalizeOptionalString(row.follow_up_text) !== null
|
|
143
|
+
|| hasNonEmptyToolResults(row.tool_results_json)
|
|
144
|
+
|| Number(row.created_at ?? 0) <= readyBefore;
|
|
145
|
+
}
|
|
146
|
+
function buildDerivedFeedbackSummary(db, routeTraceCount, defaultSupervisionCount) {
|
|
147
|
+
const traceRows = db.prepare(`
|
|
148
|
+
SELECT id, route_trace_json
|
|
149
|
+
FROM brain_traces
|
|
150
|
+
`).all();
|
|
151
|
+
const traceAgentIdentityById = new Map();
|
|
152
|
+
for (const row of traceRows) {
|
|
153
|
+
const routeTrace = parseJsonValue(row?.route_trace_json, null);
|
|
154
|
+
const agentIdentity = normalizeAgentIdentity(routeTrace?.agentIdentity);
|
|
155
|
+
if (agentIdentity !== null && typeof row?.id === "string") {
|
|
156
|
+
traceAgentIdentityById.set(row.id, agentIdentity);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const verdictCounts = {
|
|
160
|
+
helpfulCount: 0,
|
|
161
|
+
irrelevantCount: 0,
|
|
162
|
+
harmfulCount: 0
|
|
163
|
+
};
|
|
164
|
+
const latestTraceIds = new Set();
|
|
165
|
+
let latestAgentIdentity = null;
|
|
166
|
+
const supervisionRows = db.prepare(`
|
|
167
|
+
SELECT trace_id, metadata, value
|
|
168
|
+
FROM brain_trace_supervision
|
|
169
|
+
WHERE resolution = 'promoted_to_label'
|
|
170
|
+
ORDER BY created_at DESC
|
|
171
|
+
`).all();
|
|
172
|
+
for (const row of supervisionRows) {
|
|
173
|
+
const traceId = normalizeOptionalString(row?.trace_id);
|
|
174
|
+
if (traceId === null || latestTraceIds.has(traceId)) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
latestTraceIds.add(traceId);
|
|
178
|
+
const metadata = parseJsonValue(row?.metadata, {});
|
|
179
|
+
const agentIdentity = normalizeAgentIdentity(metadata?.agentIdentity)
|
|
180
|
+
?? traceAgentIdentityById.get(traceId)
|
|
181
|
+
?? null;
|
|
182
|
+
if (latestAgentIdentity === null) {
|
|
183
|
+
latestAgentIdentity = agentIdentity;
|
|
184
|
+
}
|
|
185
|
+
const verdict = classifyContextFeedbackVerdict(Number(row?.value ?? 0));
|
|
186
|
+
if (verdict === "helpful") {
|
|
187
|
+
verdictCounts.helpfulCount += 1;
|
|
188
|
+
}
|
|
189
|
+
else if (verdict === "harmful") {
|
|
190
|
+
verdictCounts.harmfulCount += 1;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
verdictCounts.irrelevantCount += 1;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const supervisedTraceCount = latestTraceIds.size || normalizeCount(defaultSupervisionCount);
|
|
197
|
+
return {
|
|
198
|
+
visible: true,
|
|
199
|
+
...verdictCounts,
|
|
200
|
+
supervisedTraceCount,
|
|
201
|
+
routeTraceCount,
|
|
202
|
+
latestAgentIdentity,
|
|
203
|
+
latestLabel: formatAgentIdentity(latestAgentIdentity),
|
|
204
|
+
detail: routeTraceCount === 0
|
|
205
|
+
? "no traced routes recorded yet"
|
|
206
|
+
: `${verdictCounts.helpfulCount} helpful, ${verdictCounts.irrelevantCount} irrelevant, ${verdictCounts.harmfulCount} harmful; ${supervisedTraceCount}/${routeTraceCount} traced routes are supervised`
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function buildDerivedAttributionCoverage(db) {
|
|
210
|
+
const completedRows = db.prepare(`
|
|
211
|
+
SELECT teacher_evaluation_json
|
|
212
|
+
FROM brain_observations
|
|
213
|
+
WHERE status = 'completed'
|
|
214
|
+
`).all();
|
|
215
|
+
const completedWithoutEvaluationCount = completedRows.reduce((sum, row) => sum + (hasTeacherBindingMode(row?.teacher_evaluation_json) ? 0 : 1), 0);
|
|
216
|
+
const evaluationCycle = loadTrainingStateJson(db, "last_teacher_evaluation_cycle_json");
|
|
217
|
+
const budgetPerTick = Number.isFinite(evaluationCycle.value?.budgetPerTick)
|
|
218
|
+
? Math.max(0, Math.trunc(evaluationCycle.value.budgetPerTick))
|
|
219
|
+
: null;
|
|
220
|
+
const delayMs = Number.isFinite(evaluationCycle.value?.delayMs)
|
|
221
|
+
? Math.max(0, Math.trunc(evaluationCycle.value.delayMs))
|
|
222
|
+
: null;
|
|
223
|
+
if (budgetPerTick === null || delayMs === null) {
|
|
224
|
+
return {
|
|
225
|
+
visible: true,
|
|
226
|
+
gatingVisible: false,
|
|
227
|
+
completedWithoutEvaluationCount,
|
|
228
|
+
readyCount: 0,
|
|
229
|
+
delayedCount: 0,
|
|
230
|
+
budgetDeferredCount: 0,
|
|
231
|
+
detail: "teacher gating truth is not visible in the current status surface"
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const pendingRows = db.prepare(`
|
|
235
|
+
SELECT status, follow_up_text, tool_results_json, created_at
|
|
236
|
+
FROM brain_observations
|
|
237
|
+
WHERE status IN ('pending_followup', 'pending_teacher')
|
|
238
|
+
ORDER BY created_at ASC
|
|
239
|
+
`).all();
|
|
240
|
+
const readyBefore = Date.now() - delayMs;
|
|
241
|
+
let readyCount = 0;
|
|
242
|
+
for (const row of pendingRows) {
|
|
243
|
+
if (isObservationReadyForTeacher(row, readyBefore)) {
|
|
244
|
+
readyCount += 1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const delayedCount = Math.max(0, pendingRows.length - readyCount);
|
|
248
|
+
const budgetDeferredCount = Math.max(0, readyCount - budgetPerTick);
|
|
249
|
+
return {
|
|
250
|
+
visible: true,
|
|
251
|
+
gatingVisible: true,
|
|
252
|
+
completedWithoutEvaluationCount,
|
|
253
|
+
readyCount,
|
|
254
|
+
delayedCount,
|
|
255
|
+
budgetDeferredCount,
|
|
256
|
+
detail: pendingRows.length === 0
|
|
257
|
+
? "no teacher observations are pending"
|
|
258
|
+
: `completed_without_evaluation=${completedWithoutEvaluationCount}; ready=${readyCount}, delayed=${delayedCount}, budget_deferred=${budgetDeferredCount}`
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function loadJsonFile(pathname) {
|
|
262
|
+
if (!existsSync(pathname)) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
return JSON.parse(readFileSync(pathname, "utf8"));
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function resolveActivePackPaths(activationRoot) {
|
|
273
|
+
const pointers = toRecord(loadJsonFile(path.join(path.resolve(activationRoot), "activation-pointers.json")));
|
|
274
|
+
const active = toRecord(pointers?.active);
|
|
275
|
+
const packRootDir = normalizeOptionalString(active?.packRootDir)
|
|
276
|
+
?? (normalizeOptionalString(active?.packId) === null
|
|
277
|
+
? null
|
|
278
|
+
: path.join(path.resolve(activationRoot), "packs", String(active.packId)));
|
|
279
|
+
const manifestPath = normalizeOptionalString(active?.manifestPath)
|
|
280
|
+
?? (packRootDir === null ? null : path.join(packRootDir, "manifest.json"));
|
|
281
|
+
return {
|
|
282
|
+
packRootDir,
|
|
283
|
+
manifestPath
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function buildActivePackFeedbackSummary(activationRoot) {
|
|
287
|
+
const active = resolveActivePackPaths(activationRoot);
|
|
288
|
+
if (active.packRootDir === null || active.manifestPath === null) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const manifest = toRecord(loadJsonFile(active.manifestPath));
|
|
292
|
+
const runtimeAssets = toRecord(manifest?.runtimeAssets);
|
|
293
|
+
const router = toRecord(runtimeAssets?.router);
|
|
294
|
+
const routerArtifactPath = normalizeOptionalString(router?.artifactPath);
|
|
295
|
+
if (routerArtifactPath === null) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
const routerPath = path.isAbsolute(routerArtifactPath)
|
|
299
|
+
? routerArtifactPath
|
|
300
|
+
: path.join(active.packRootDir, routerArtifactPath);
|
|
301
|
+
const routerArtifact = toRecord(loadJsonFile(routerPath));
|
|
302
|
+
const traces = Array.isArray(routerArtifact?.traces) ? routerArtifact.traces : [];
|
|
303
|
+
const verdictCounts = {
|
|
304
|
+
helpfulCount: 0,
|
|
305
|
+
irrelevantCount: 0,
|
|
306
|
+
harmfulCount: 0
|
|
307
|
+
};
|
|
308
|
+
for (const trace of traces) {
|
|
309
|
+
const traceRecord = toRecord(trace);
|
|
310
|
+
if (normalizeOptionalString(traceRecord?.supervisionKind) === "route_trace") {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
const verdict = classifyContextFeedbackVerdict(Number(traceRecord?.reward ?? 0));
|
|
314
|
+
if (verdict === "helpful") {
|
|
315
|
+
verdictCounts.helpfulCount += 1;
|
|
316
|
+
}
|
|
317
|
+
else if (verdict === "harmful") {
|
|
318
|
+
verdictCounts.harmfulCount += 1;
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
verdictCounts.irrelevantCount += 1;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const routeTraceCount = normalizeCount(routerArtifact?.training?.routeTraceCount) || traces.length;
|
|
325
|
+
const supervisedTraceCount = verdictCounts.helpfulCount + verdictCounts.irrelevantCount + verdictCounts.harmfulCount;
|
|
326
|
+
if (routeTraceCount === 0 && supervisedTraceCount === 0) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
visible: true,
|
|
331
|
+
...verdictCounts,
|
|
332
|
+
supervisedTraceCount,
|
|
333
|
+
routeTraceCount,
|
|
334
|
+
latestAgentIdentity: null,
|
|
335
|
+
latestLabel: null,
|
|
336
|
+
detail: routeTraceCount === 0
|
|
337
|
+
? "no active-pack traced routes are visible"
|
|
338
|
+
: `${verdictCounts.helpfulCount} helpful, ${verdictCounts.irrelevantCount} irrelevant, ${verdictCounts.harmfulCount} harmful; ${supervisedTraceCount}/${routeTraceCount} active-pack traced routes are supervised`
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function readIntegerNote(notes, prefix) {
|
|
342
|
+
if (!Array.isArray(notes)) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
const entry = notes.find((candidate) => typeof candidate === "string" && candidate.startsWith(prefix));
|
|
346
|
+
if (typeof entry !== "string") {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
const parsed = Number.parseInt(entry.slice(prefix.length), 10);
|
|
350
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
351
|
+
}
|
|
352
|
+
function buildWatchSnapshotAttributionCoverage(activationRoot) {
|
|
353
|
+
const snapshot = toRecord(loadJsonFile(path.join(path.resolve(activationRoot), "watch", "teacher-snapshot.json")));
|
|
354
|
+
const notes = Array.isArray(snapshot?.notes)
|
|
355
|
+
? snapshot.notes
|
|
356
|
+
: Array.isArray(snapshot?.snapshot?.diagnostics?.notes)
|
|
357
|
+
? snapshot.snapshot.diagnostics.notes
|
|
358
|
+
: Array.isArray(snapshot?.diagnostics?.notes)
|
|
359
|
+
? snapshot.diagnostics.notes
|
|
360
|
+
: [];
|
|
361
|
+
const readyCount = readIntegerNote(notes, "teacher_feedback_eligible=");
|
|
362
|
+
const delayedCount = readIntegerNote(notes, "teacher_feedback_delayed=");
|
|
363
|
+
const budgetDeferredCount = readIntegerNote(notes, "teacher_feedback_budgeted_out=");
|
|
364
|
+
const budgetPerTick = readIntegerNote(notes, "teacher_budget=");
|
|
365
|
+
const delayMs = readIntegerNote(notes, "teacher_delay_ms=");
|
|
366
|
+
if (readyCount === null && delayedCount === null && budgetDeferredCount === null && budgetPerTick === null && delayMs === null) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
visible: true,
|
|
371
|
+
gatingVisible: budgetPerTick !== null || delayMs !== null,
|
|
372
|
+
completedWithoutEvaluationCount: 0,
|
|
373
|
+
readyCount: normalizeCount(readyCount),
|
|
374
|
+
delayedCount: normalizeCount(delayedCount),
|
|
375
|
+
budgetDeferredCount: normalizeCount(budgetDeferredCount),
|
|
376
|
+
detail: `watch sparse-feedback queue: completed_without_evaluation=0, ready=${normalizeCount(readyCount)}, delayed=${normalizeCount(delayedCount)}, budget_deferred=${normalizeCount(budgetDeferredCount)}`
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function shouldPreferActivationFeedbackSummary(current, fallback) {
|
|
380
|
+
if (fallback === null) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
if (current.visible !== true) {
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
return normalizeCount(current.supervisedTraceCount) === 0 && normalizeCount(fallback.supervisedTraceCount) > 0;
|
|
387
|
+
}
|
|
388
|
+
function shouldPreferWatchAttributionCoverage(current, fallback) {
|
|
389
|
+
if (fallback === null) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
if (current.visible !== true || current.gatingVisible !== true) {
|
|
393
|
+
return normalizeCount(fallback.readyCount) > 0
|
|
394
|
+
|| normalizeCount(fallback.delayedCount) > 0
|
|
395
|
+
|| normalizeCount(fallback.budgetDeferredCount) > 0;
|
|
396
|
+
}
|
|
397
|
+
const currentKnown = normalizeCount(current.completedWithoutEvaluationCount)
|
|
398
|
+
+ normalizeCount(current.readyCount)
|
|
399
|
+
+ normalizeCount(current.delayedCount)
|
|
400
|
+
+ normalizeCount(current.budgetDeferredCount);
|
|
401
|
+
const fallbackKnown = normalizeCount(fallback.completedWithoutEvaluationCount)
|
|
402
|
+
+ normalizeCount(fallback.readyCount)
|
|
403
|
+
+ normalizeCount(fallback.delayedCount)
|
|
404
|
+
+ normalizeCount(fallback.budgetDeferredCount);
|
|
405
|
+
return currentKnown === 0 && fallbackKnown > 0;
|
|
406
|
+
}
|
|
407
|
+
function enrichBridgeWithActivationTruth(activationRoot, bridge) {
|
|
408
|
+
const feedbackSummary = buildActivePackFeedbackSummary(activationRoot);
|
|
409
|
+
const attributionCoverage = buildWatchSnapshotAttributionCoverage(activationRoot);
|
|
410
|
+
if (!shouldPreferActivationFeedbackSummary(bridge.feedbackSummary, feedbackSummary)
|
|
411
|
+
&& !shouldPreferWatchAttributionCoverage(bridge.attributionCoverage, attributionCoverage)) {
|
|
412
|
+
return bridge;
|
|
413
|
+
}
|
|
414
|
+
return normalizeBridgePayload({
|
|
415
|
+
...bridge,
|
|
416
|
+
feedbackSummary: shouldPreferActivationFeedbackSummary(bridge.feedbackSummary, feedbackSummary)
|
|
417
|
+
? feedbackSummary
|
|
418
|
+
: bridge.feedbackSummary,
|
|
419
|
+
attributionCoverage: shouldPreferWatchAttributionCoverage(bridge.attributionCoverage, attributionCoverage)
|
|
420
|
+
? attributionCoverage
|
|
421
|
+
: bridge.attributionCoverage
|
|
422
|
+
});
|
|
423
|
+
}
|
|
24
424
|
function normalizeLastInterruptionSummary(value) {
|
|
25
425
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
26
426
|
return null;
|
|
@@ -95,11 +495,13 @@ function normalizeBridgePayload(payload) {
|
|
|
95
495
|
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
96
496
|
throw new Error("expected traced-learning bridge payload object");
|
|
97
497
|
}
|
|
498
|
+
const routeTraceCount = normalizeCount(payload.routeTraceCount);
|
|
499
|
+
const supervisionCount = normalizeCount(payload.supervisionCount);
|
|
98
500
|
return {
|
|
99
501
|
contract: TRACED_LEARNING_BRIDGE_CONTRACT,
|
|
100
502
|
updatedAt: normalizeOptionalString(payload.updatedAt) ?? new Date().toISOString(),
|
|
101
|
-
routeTraceCount
|
|
102
|
-
supervisionCount
|
|
503
|
+
routeTraceCount,
|
|
504
|
+
supervisionCount,
|
|
103
505
|
routerUpdateCount: normalizeCount(payload.routerUpdateCount),
|
|
104
506
|
teacherArtifactCount: normalizeCount(payload.teacherArtifactCount),
|
|
105
507
|
pgVersionRequested: normalizeOptionalString(payload.pgVersionRequested),
|
|
@@ -111,6 +513,11 @@ function normalizeBridgePayload(payload) {
|
|
|
111
513
|
promoted: payload.promoted === true,
|
|
112
514
|
baselinePersisted: payload.baselinePersisted === true,
|
|
113
515
|
lastInterruptionSummary: normalizeLastInterruptionSummary(payload.lastInterruptionSummary),
|
|
516
|
+
feedbackSummary: normalizeFeedbackSummary(payload.feedbackSummary, {
|
|
517
|
+
routeTraceCount,
|
|
518
|
+
supervisedTraceCount: supervisionCount
|
|
519
|
+
}),
|
|
520
|
+
attributionCoverage: normalizeAttributionCoverage(payload.attributionCoverage),
|
|
114
521
|
source: normalizeSource(payload.source)
|
|
115
522
|
};
|
|
116
523
|
}
|
|
@@ -122,11 +529,13 @@ function normalizePersistedStatusSurface(payload) {
|
|
|
122
529
|
if (source === null) {
|
|
123
530
|
throw new Error("expected traced-learning status surface source");
|
|
124
531
|
}
|
|
532
|
+
const routeTraceCount = normalizeCount(payload.routeTraceCount);
|
|
533
|
+
const supervisionCount = normalizeCount(payload.supervisionCount);
|
|
125
534
|
return {
|
|
126
535
|
contract: TRACED_LEARNING_STATUS_SURFACE_CONTRACT,
|
|
127
536
|
updatedAt: normalizeOptionalString(payload.updatedAt) ?? new Date().toISOString(),
|
|
128
|
-
routeTraceCount
|
|
129
|
-
supervisionCount
|
|
537
|
+
routeTraceCount,
|
|
538
|
+
supervisionCount,
|
|
130
539
|
routerUpdateCount: normalizeCount(payload.routerUpdateCount),
|
|
131
540
|
teacherArtifactCount: normalizeCount(payload.teacherArtifactCount),
|
|
132
541
|
pgVersionRequested: normalizeOptionalString(payload.pgVersionRequested),
|
|
@@ -138,6 +547,11 @@ function normalizePersistedStatusSurface(payload) {
|
|
|
138
547
|
promoted: payload.promoted === true,
|
|
139
548
|
baselinePersisted: payload.baselinePersisted === true,
|
|
140
549
|
lastInterruptionSummary: normalizeLastInterruptionSummary(payload.lastInterruptionSummary),
|
|
550
|
+
feedbackSummary: normalizeFeedbackSummary(payload.feedbackSummary, {
|
|
551
|
+
routeTraceCount,
|
|
552
|
+
supervisedTraceCount: supervisionCount
|
|
553
|
+
}),
|
|
554
|
+
attributionCoverage: normalizeAttributionCoverage(payload.attributionCoverage),
|
|
141
555
|
source
|
|
142
556
|
};
|
|
143
557
|
}
|
|
@@ -157,6 +571,8 @@ function defaultSurface(pathname, detail, error = null) {
|
|
|
157
571
|
promoted: false,
|
|
158
572
|
baselinePersisted: false,
|
|
159
573
|
lastInterruptionSummary: null,
|
|
574
|
+
feedbackSummary: defaultFeedbackSummary(),
|
|
575
|
+
attributionCoverage: defaultAttributionCoverage(),
|
|
160
576
|
source: null,
|
|
161
577
|
detail,
|
|
162
578
|
error
|
|
@@ -278,6 +694,8 @@ function buildPersistedStatusSurfaceBridge(summary, context) {
|
|
|
278
694
|
promoted: summary.promoted,
|
|
279
695
|
baselinePersisted: summary.baselinePersisted,
|
|
280
696
|
lastInterruptionSummary: summary.lastInterruptionSummary,
|
|
697
|
+
feedbackSummary: summary.feedbackSummary,
|
|
698
|
+
attributionCoverage: summary.attributionCoverage,
|
|
281
699
|
source: {
|
|
282
700
|
command: "brain-store",
|
|
283
701
|
bridge: TRACED_LEARNING_STATUS_SURFACE_BRIDGE,
|
|
@@ -321,6 +739,20 @@ function buildDerivedBrainStoreBridge(db, context, lastInterruptionSummary = nul
|
|
|
321
739
|
? null
|
|
322
740
|
: JSON.parse(candidateUpdateRaw);
|
|
323
741
|
const candidatePackVersion = Number.parseInt(candidatePackVersionRaw ?? "", 10);
|
|
742
|
+
let feedbackSummary = defaultFeedbackSummary(routeTraceCount, supervisionCount);
|
|
743
|
+
try {
|
|
744
|
+
feedbackSummary = buildDerivedFeedbackSummary(db, routeTraceCount, supervisionCount);
|
|
745
|
+
}
|
|
746
|
+
catch {
|
|
747
|
+
feedbackSummary = defaultFeedbackSummary(routeTraceCount, supervisionCount);
|
|
748
|
+
}
|
|
749
|
+
let attributionCoverage = defaultAttributionCoverage();
|
|
750
|
+
try {
|
|
751
|
+
attributionCoverage = buildDerivedAttributionCoverage(db);
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
attributionCoverage = defaultAttributionCoverage();
|
|
755
|
+
}
|
|
324
756
|
return normalizeBridgePayload({
|
|
325
757
|
updatedAt: toIsoTimestamp(candidateUpdate?.generatedAt),
|
|
326
758
|
routeTraceCount,
|
|
@@ -336,6 +768,8 @@ function buildDerivedBrainStoreBridge(db, context, lastInterruptionSummary = nul
|
|
|
336
768
|
promoted: false,
|
|
337
769
|
baselinePersisted: false,
|
|
338
770
|
lastInterruptionSummary,
|
|
771
|
+
feedbackSummary,
|
|
772
|
+
attributionCoverage,
|
|
339
773
|
source: {
|
|
340
774
|
command: "brain-store",
|
|
341
775
|
bridge: "brain_store_state",
|
|
@@ -360,6 +794,13 @@ function hasMeaningfulTracedLearningSignal(bridge) {
|
|
|
360
794
|
bridge.pgVersionUsed !== null ||
|
|
361
795
|
bridge.fallbackReason !== null ||
|
|
362
796
|
bridge.routerNoOpReason !== null ||
|
|
797
|
+
bridge.feedbackSummary.helpfulCount > 0 ||
|
|
798
|
+
bridge.feedbackSummary.irrelevantCount > 0 ||
|
|
799
|
+
bridge.feedbackSummary.harmfulCount > 0 ||
|
|
800
|
+
bridge.attributionCoverage.completedWithoutEvaluationCount > 0 ||
|
|
801
|
+
bridge.attributionCoverage.readyCount > 0 ||
|
|
802
|
+
bridge.attributionCoverage.delayedCount > 0 ||
|
|
803
|
+
bridge.attributionCoverage.budgetDeferredCount > 0 ||
|
|
363
804
|
Number.isFinite(bridge.source?.candidatePackVersion) ||
|
|
364
805
|
normalizeCount(bridge.source?.candidateUpdateCount) > 0;
|
|
365
806
|
}
|
|
@@ -479,27 +920,41 @@ export function loadBrainStoreTracedLearningBridge(options = {}) {
|
|
|
479
920
|
try {
|
|
480
921
|
db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
|
|
481
922
|
const lastInterruptionSummary = loadLastAssemblyInterruptionSummary(db);
|
|
923
|
+
let derived = null;
|
|
924
|
+
try {
|
|
925
|
+
derived = buildDerivedBrainStoreBridge(db, {
|
|
926
|
+
brainRoot,
|
|
927
|
+
dbPath
|
|
928
|
+
}, lastInterruptionSummary);
|
|
929
|
+
}
|
|
930
|
+
catch {
|
|
931
|
+
derived = null;
|
|
932
|
+
}
|
|
482
933
|
const persisted = loadPersistedStatusSurface(db, {
|
|
483
934
|
brainRoot,
|
|
484
935
|
dbPath
|
|
485
936
|
});
|
|
486
937
|
if (persisted.bridge !== null) {
|
|
487
|
-
const bridge =
|
|
488
|
-
|
|
489
|
-
:
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
938
|
+
const bridge = normalizeBridgePayload({
|
|
939
|
+
...persisted.bridge,
|
|
940
|
+
lastInterruptionSummary: lastInterruptionSummary ?? persisted.bridge.lastInterruptionSummary,
|
|
941
|
+
feedbackSummary: derived?.feedbackSummary ?? persisted.bridge.feedbackSummary,
|
|
942
|
+
attributionCoverage: derived?.attributionCoverage ?? persisted.bridge.attributionCoverage
|
|
943
|
+
});
|
|
493
944
|
return {
|
|
494
945
|
path: dbPath,
|
|
495
946
|
bridge,
|
|
496
947
|
error: null
|
|
497
948
|
};
|
|
498
949
|
}
|
|
499
|
-
const bridge =
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
950
|
+
const bridge = derived;
|
|
951
|
+
if (bridge === null) {
|
|
952
|
+
return {
|
|
953
|
+
path: dbPath,
|
|
954
|
+
bridge: null,
|
|
955
|
+
error: persisted.error
|
|
956
|
+
};
|
|
957
|
+
}
|
|
503
958
|
if (!hasMeaningfulTracedLearningSignal(bridge)) {
|
|
504
959
|
return {
|
|
505
960
|
path: dbPath,
|
|
@@ -565,6 +1020,8 @@ function buildStatusSurface(pathname, bridge, options = {}) {
|
|
|
565
1020
|
promoted: bridge.promoted,
|
|
566
1021
|
baselinePersisted: bridge.baselinePersisted,
|
|
567
1022
|
lastInterruptionSummary: bridge.lastInterruptionSummary,
|
|
1023
|
+
feedbackSummary: bridge.feedbackSummary,
|
|
1024
|
+
attributionCoverage: bridge.attributionCoverage,
|
|
568
1025
|
source: bridge.source,
|
|
569
1026
|
detail: detailParts.join(" "),
|
|
570
1027
|
error: options.error ?? null
|
|
@@ -611,6 +1068,8 @@ function mergeCanonicalStatusBridge(canonicalBridge, runtimeLoaded) {
|
|
|
611
1068
|
promoted: canonicalBridge.promoted,
|
|
612
1069
|
baselinePersisted: canonicalBridge.baselinePersisted,
|
|
613
1070
|
lastInterruptionSummary: canonicalBridge.lastInterruptionSummary ?? runtimeBridge?.lastInterruptionSummary ?? null,
|
|
1071
|
+
feedbackSummary: canonicalBridge.feedbackSummary,
|
|
1072
|
+
attributionCoverage: canonicalBridge.attributionCoverage,
|
|
614
1073
|
fallbackReason: canonicalBridge.fallbackReason,
|
|
615
1074
|
routerNoOpReason: canonicalBridge.routerNoOpReason,
|
|
616
1075
|
source: runtimeMaterialized === null
|
|
@@ -634,6 +1093,8 @@ function mergeCanonicalStatusBridge(canonicalBridge, runtimeLoaded) {
|
|
|
634
1093
|
promoted: runtimeBridge?.promoted ?? canonicalBridge.promoted,
|
|
635
1094
|
baselinePersisted: runtimeBridge?.baselinePersisted ?? canonicalBridge.baselinePersisted,
|
|
636
1095
|
lastInterruptionSummary: canonicalBridge.lastInterruptionSummary ?? runtimeBridge?.lastInterruptionSummary ?? null,
|
|
1096
|
+
feedbackSummary: canonicalBridge.feedbackSummary,
|
|
1097
|
+
attributionCoverage: canonicalBridge.attributionCoverage,
|
|
637
1098
|
fallbackReason: runtimeBridge?.fallbackReason ?? canonicalBridge.fallbackReason ?? null,
|
|
638
1099
|
routerNoOpReason: runtimeBridge?.routerNoOpReason ?? canonicalBridge.routerNoOpReason ?? null,
|
|
639
1100
|
source: runtimeMaterialized === null
|
|
@@ -655,11 +1116,16 @@ export function mergeTracedLearningBridgePayload(payload, persisted) {
|
|
|
655
1116
|
const routerUpdateCount = Math.max(current.routerUpdateCount, persistedBridge.routerUpdateCount);
|
|
656
1117
|
const teacherArtifactCount = Math.max(current.teacherArtifactCount, persistedBridge.teacherArtifactCount);
|
|
657
1118
|
const lastInterruptionSummary = current.lastInterruptionSummary ?? persistedBridge.lastInterruptionSummary ?? null;
|
|
1119
|
+
const feedbackSummary = current.feedbackSummary.visible ? current.feedbackSummary : persistedBridge.feedbackSummary;
|
|
1120
|
+
const attributionCoverage = current.attributionCoverage.visible ? current.attributionCoverage : persistedBridge.attributionCoverage;
|
|
658
1121
|
const usedBridge = routeTraceCount !== current.routeTraceCount ||
|
|
659
1122
|
supervisionCount !== current.supervisionCount ||
|
|
660
1123
|
routerUpdateCount !== current.routerUpdateCount ||
|
|
661
1124
|
teacherArtifactCount !== current.teacherArtifactCount ||
|
|
662
|
-
lastInterruptionSummary !== current.lastInterruptionSummary
|
|
1125
|
+
lastInterruptionSummary !== current.lastInterruptionSummary ||
|
|
1126
|
+
feedbackSummary.visible !== current.feedbackSummary.visible ||
|
|
1127
|
+
attributionCoverage.visible !== current.attributionCoverage.visible ||
|
|
1128
|
+
attributionCoverage.gatingVisible !== current.attributionCoverage.gatingVisible;
|
|
663
1129
|
if (!usedBridge) {
|
|
664
1130
|
return current;
|
|
665
1131
|
}
|
|
@@ -670,6 +1136,8 @@ export function mergeTracedLearningBridgePayload(payload, persisted) {
|
|
|
670
1136
|
routerUpdateCount,
|
|
671
1137
|
teacherArtifactCount,
|
|
672
1138
|
lastInterruptionSummary,
|
|
1139
|
+
feedbackSummary,
|
|
1140
|
+
attributionCoverage,
|
|
673
1141
|
routerNoOpReason: supervisionCount > 0 || routerUpdateCount > 0 ? null : current.routerNoOpReason,
|
|
674
1142
|
source: {
|
|
675
1143
|
...(current.source ?? {}),
|
|
@@ -690,12 +1158,12 @@ export function buildTracedLearningStatusSurface(activationRoot, options = {}) {
|
|
|
690
1158
|
const persisted = loadBrainStoreTracedLearningBridge(options);
|
|
691
1159
|
const runtime = loadTracedLearningBridge(activationRoot);
|
|
692
1160
|
if (persisted.bridge !== null) {
|
|
693
|
-
return buildStatusSurface(persisted.path, mergeCanonicalStatusBridge(persisted.bridge, runtime), {
|
|
1161
|
+
return buildStatusSurface(persisted.path, enrichBridgeWithActivationTruth(activationRoot, mergeCanonicalStatusBridge(persisted.bridge, runtime)), {
|
|
694
1162
|
runtimeState: describeBridgeRuntimeState(runtime)
|
|
695
1163
|
});
|
|
696
1164
|
}
|
|
697
1165
|
if (runtime.bridge !== null) {
|
|
698
|
-
return buildStatusSurface(runtime.path, runtime.bridge);
|
|
1166
|
+
return buildStatusSurface(runtime.path, enrichBridgeWithActivationTruth(activationRoot, runtime.bridge));
|
|
699
1167
|
}
|
|
700
1168
|
if (persisted.error !== null) {
|
|
701
1169
|
return defaultSurface(persisted.path, "brain_store_unreadable", persisted.error);
|
package/package.json
CHANGED