@openclawbrain/cli 0.4.13 → 0.4.15
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/README.md +17 -11
- package/dist/extension/index.js +29 -3
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/runtime-guard.d.ts +8 -0
- package/dist/extension/runtime-guard.js +100 -12
- package/dist/extension/runtime-guard.js.map +1 -1
- package/dist/src/attachment-truth.d.ts +32 -22
- package/dist/src/attachment-truth.js +338 -186
- package/dist/src/cli.d.ts +13 -1
- package/dist/src/cli.js +595 -113
- package/dist/src/index.d.ts +242 -3
- package/dist/src/index.js +1029 -38
- package/dist/src/install-converge.js +217 -0
- package/dist/src/learning-spine.d.ts +2 -1
- package/dist/src/learning-spine.js +49 -19
- package/dist/src/local-learner.d.ts +30 -0
- package/dist/src/local-learner.js +298 -179
- package/dist/src/local-session-passive-learning.js +28 -2
- package/dist/src/materialization-embedder.js +11 -0
- package/dist/src/openclaw-hook-truth.d.ts +6 -0
- package/dist/src/openclaw-hook-truth.js +27 -0
- package/dist/src/proof-command.js +301 -42
- package/dist/src/runtime-core.js +658 -0
- package/dist/src/status-learning-path.js +32 -2
- package/dist/src/teacher-decision-match.js +277 -0
- package/dist/src/teacher-labeler.js +4 -30
- package/dist/src/traced-learning-bridge.js +17 -1
- package/extension/index.ts +35 -4
- package/extension/runtime-guard.ts +92 -14
- package/package.json +4 -3
package/dist/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import process from "node:process";
|
|
5
6
|
import { compileRuntimeFromActivation } from "@openclawbrain/compiler";
|
|
@@ -27,6 +28,27 @@ export const RUNTIME_EVENT_EXPORT_BUNDLE_LAYOUT = {
|
|
|
27
28
|
manifest: "manifest.json",
|
|
28
29
|
payload: "normalized-event-export.json"
|
|
29
30
|
};
|
|
31
|
+
const RECORDED_SESSION_REPLAY_PROOF_MANIFEST_CONTRACT = "recorded_session_replay_proof_manifest.v1";
|
|
32
|
+
const RECORDED_SESSION_REPLAY_PROOF_ENVIRONMENT_CONTRACT = "recorded_session_replay_environment.v1";
|
|
33
|
+
const RECORDED_SESSION_REPLAY_PROOF_SUMMARY_TABLES_CONTRACT = "recorded_session_replay_summary_tables.v1";
|
|
34
|
+
const RECORDED_SESSION_REPLAY_PROOF_COVERAGE_SNAPSHOT_CONTRACT = "recorded_session_replay_coverage_snapshot.v1";
|
|
35
|
+
const RECORDED_SESSION_REPLAY_PROOF_HARDENING_SNAPSHOT_CONTRACT = "recorded_session_replay_hardening_snapshot.v1";
|
|
36
|
+
const RECORDED_SESSION_REPLAY_PROOF_HASHES_CONTRACT = "recorded_session_replay_hashes.v1";
|
|
37
|
+
const RECORDED_SESSION_REPLAY_PROOF_VALIDATION_CONTRACT = "recorded_session_replay_proof_validation.v1";
|
|
38
|
+
const RECORDED_SESSION_REPLAY_MODE_ORDER = ["no_brain", "vector_only", "graph_prior_only", "learned_route"];
|
|
39
|
+
export const RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT = {
|
|
40
|
+
manifest: "manifest.json",
|
|
41
|
+
trace: "trace.json",
|
|
42
|
+
fixture: "fixture.json",
|
|
43
|
+
bundle: "bundle.json",
|
|
44
|
+
environment: "environment.json",
|
|
45
|
+
summary: "summary.md",
|
|
46
|
+
summaryTables: "summary-tables.json",
|
|
47
|
+
coverageSnapshot: "coverage-snapshot.json",
|
|
48
|
+
hardeningSnapshot: "hardening-snapshot.json",
|
|
49
|
+
hashes: "hashes.json",
|
|
50
|
+
modeDir: "modes"
|
|
51
|
+
};
|
|
30
52
|
function normalizeRuntimeProfileSelector(value, fieldName, fallback = "current_profile") {
|
|
31
53
|
if (value === undefined || value === null) {
|
|
32
54
|
return fallback;
|
|
@@ -1058,6 +1080,24 @@ export function scanLiveEventExport(input) {
|
|
|
1058
1080
|
function readJsonFile(filePath) {
|
|
1059
1081
|
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
1060
1082
|
}
|
|
1083
|
+
function checksumTextPayload(value) {
|
|
1084
|
+
return `sha256-${createHash("sha256").update(value).digest("hex")}`;
|
|
1085
|
+
}
|
|
1086
|
+
function orderedRecordedSessionReplayModes(modes) {
|
|
1087
|
+
const byMode = new Map(modes.map((mode) => [mode.mode, mode]));
|
|
1088
|
+
return RECORDED_SESSION_REPLAY_MODE_ORDER
|
|
1089
|
+
.map((mode) => byMode.get(mode))
|
|
1090
|
+
.filter(isPresent);
|
|
1091
|
+
}
|
|
1092
|
+
function recordedSessionReplayModeOutputPath(mode) {
|
|
1093
|
+
return path.posix.join(RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.modeDir, `${mode}.json`);
|
|
1094
|
+
}
|
|
1095
|
+
function resolveRecordedSessionReplayProofPath(rootDir, relativePath, fieldName) {
|
|
1096
|
+
return resolveBundlePayloadPath(rootDir, normalizeNonEmptyString(relativePath, fieldName));
|
|
1097
|
+
}
|
|
1098
|
+
function readRecordedSessionReplayProofText(rootDir, relativePath, fieldName) {
|
|
1099
|
+
return readFileSync(resolveRecordedSessionReplayProofPath(rootDir, relativePath, fieldName), "utf8");
|
|
1100
|
+
}
|
|
1061
1101
|
export function resolveAsyncTeacherLiveLoopSnapshotPath(activationRoot) {
|
|
1062
1102
|
return path.join(path.resolve(normalizeNonEmptyString(activationRoot, "activationRoot")), "async-teacher-live-loop.snapshot.json");
|
|
1063
1103
|
}
|
|
@@ -2340,8 +2380,61 @@ function normalizeIsoTimestamp(value, fieldName, fallbackValue) {
|
|
|
2340
2380
|
}
|
|
2341
2381
|
return new Date(candidate).toISOString();
|
|
2342
2382
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2383
|
+
const RUNTIME_COMPARATIVE_REPLAY_MODE_CONFIG = {
|
|
2384
|
+
vector_only: {
|
|
2385
|
+
routeMode: "heuristic",
|
|
2386
|
+
selectionMode: "flat_rank_v1"
|
|
2387
|
+
},
|
|
2388
|
+
graph_prior_only: {
|
|
2389
|
+
routeMode: "heuristic",
|
|
2390
|
+
selectionMode: "graph_walk_v1"
|
|
2391
|
+
},
|
|
2392
|
+
learned_route: {
|
|
2393
|
+
routeMode: "learned",
|
|
2394
|
+
selectionMode: "graph_walk_v1"
|
|
2395
|
+
}
|
|
2396
|
+
};
|
|
2397
|
+
function resolveRuntimeComparativeReplayMode(value) {
|
|
2398
|
+
return Object.prototype.hasOwnProperty.call(RUNTIME_COMPARATIVE_REPLAY_MODE_CONFIG, value)
|
|
2399
|
+
? value
|
|
2400
|
+
: null;
|
|
2401
|
+
}
|
|
2402
|
+
function resolveCompileModePlan(modeValue, selectionModeValue) {
|
|
2403
|
+
const requestedSelectionMode = normalizeCompileSelectionMode(selectionModeValue);
|
|
2404
|
+
const comparativeMode = resolveRuntimeComparativeReplayMode(modeValue);
|
|
2405
|
+
if (comparativeMode === null) {
|
|
2406
|
+
if (modeValue === undefined) {
|
|
2407
|
+
return {
|
|
2408
|
+
comparativeMode: null,
|
|
2409
|
+
routeMode: "heuristic",
|
|
2410
|
+
selectionMode: requestedSelectionMode
|
|
2411
|
+
};
|
|
2412
|
+
}
|
|
2413
|
+
if (modeValue === "heuristic" || modeValue === "learned") {
|
|
2414
|
+
return {
|
|
2415
|
+
comparativeMode: null,
|
|
2416
|
+
routeMode: modeValue,
|
|
2417
|
+
selectionMode: requestedSelectionMode
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
2420
|
+
throw new Error("mode must be heuristic, learned, vector_only, graph_prior_only, or learned_route");
|
|
2421
|
+
}
|
|
2422
|
+
const plan = RUNTIME_COMPARATIVE_REPLAY_MODE_CONFIG[comparativeMode];
|
|
2423
|
+
if (requestedSelectionMode !== undefined && requestedSelectionMode !== plan.selectionMode) {
|
|
2424
|
+
throw new Error(`selectionMode ${requestedSelectionMode} conflicts with comparative mode ${comparativeMode}, expected ${plan.selectionMode}`);
|
|
2425
|
+
}
|
|
2426
|
+
return {
|
|
2427
|
+
comparativeMode,
|
|
2428
|
+
routeMode: plan.routeMode,
|
|
2429
|
+
selectionMode: plan.selectionMode
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
function resolveSyntheticTurnMode(value) {
|
|
2433
|
+
const comparativeMode = resolveRuntimeComparativeReplayMode(value);
|
|
2434
|
+
if (comparativeMode !== null) {
|
|
2435
|
+
return RUNTIME_COMPARATIVE_REPLAY_MODE_CONFIG[comparativeMode].routeMode;
|
|
2436
|
+
}
|
|
2437
|
+
return value === "heuristic" || value === "learned" ? value : undefined;
|
|
2345
2438
|
}
|
|
2346
2439
|
function normalizeCompileSelectionMode(value) {
|
|
2347
2440
|
if (value === undefined) {
|
|
@@ -2681,8 +2774,9 @@ function appendCompileServeRouteDecisionLog(input) {
|
|
|
2681
2774
|
if (input.compileInput.budgetStrategy === "fixed_v1" || input.compileInput.budgetStrategy === "empirical_v1") {
|
|
2682
2775
|
syntheticTurn.budgetStrategy = input.compileInput.budgetStrategy;
|
|
2683
2776
|
}
|
|
2684
|
-
|
|
2685
|
-
|
|
2777
|
+
const syntheticTurnMode = resolveSyntheticTurnMode(input.compileInput.mode);
|
|
2778
|
+
if (syntheticTurnMode !== undefined) {
|
|
2779
|
+
syntheticTurn.mode = syntheticTurnMode;
|
|
2686
2780
|
}
|
|
2687
2781
|
if (input.compileInput.runtimeHints !== undefined) {
|
|
2688
2782
|
syntheticTurn.runtimeHints = input.compileInput.runtimeHints;
|
|
@@ -2936,16 +3030,42 @@ export function resolveActivePackForCompile(activationRoot) {
|
|
|
2936
3030
|
inspection: inspection.active
|
|
2937
3031
|
};
|
|
2938
3032
|
}
|
|
3033
|
+
function normalizeFrozenReplayEvalIdentity(value) {
|
|
3034
|
+
if (value === undefined || value === null) {
|
|
3035
|
+
return null;
|
|
3036
|
+
}
|
|
3037
|
+
if (typeof value !== "object") {
|
|
3038
|
+
throw new Error("_frozenReplayEvalIdentity must be an object");
|
|
3039
|
+
}
|
|
3040
|
+
const frozenIdentity = value;
|
|
3041
|
+
return {
|
|
3042
|
+
packId: normalizeNonEmptyString(frozenIdentity.packId, "_frozenReplayEvalIdentity.packId"),
|
|
3043
|
+
routerIdentity: normalizeOptionalString(frozenIdentity.routerIdentity) ?? null
|
|
3044
|
+
};
|
|
3045
|
+
}
|
|
3046
|
+
function validateFrozenReplayEvalIdentity(target, frozenReplayEvalIdentity) {
|
|
3047
|
+
if (frozenReplayEvalIdentity === null) {
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
const actualRouterIdentity = target.inspection.routerIdentity ?? null;
|
|
3051
|
+
if (target.activePointer.packId === frozenReplayEvalIdentity.packId &&
|
|
3052
|
+
actualRouterIdentity === frozenReplayEvalIdentity.routerIdentity) {
|
|
3053
|
+
return;
|
|
3054
|
+
}
|
|
3055
|
+
throw new Error(`Frozen replay eval identity mismatch: expected pack ${frozenReplayEvalIdentity.packId} (routerIdentity=${frozenReplayEvalIdentity.routerIdentity ?? "null"}), received pack ${target.activePointer.packId} (routerIdentity=${actualRouterIdentity ?? "null"})`);
|
|
3056
|
+
}
|
|
2939
3057
|
export function compileRuntimeContext(input) {
|
|
2940
3058
|
const totalStartedAtNs = monotonicClockNs();
|
|
2941
3059
|
const fallbackActivationRoot = resolveActivationRootForFailure(input.activationRoot);
|
|
2942
3060
|
let activationRoot = fallbackActivationRoot;
|
|
2943
3061
|
let agentId = process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
|
|
2944
3062
|
let runtimeHints = [];
|
|
3063
|
+
let comparativeMode = null;
|
|
2945
3064
|
let selectionMode;
|
|
2946
3065
|
let userMessage = "";
|
|
2947
3066
|
let maxContextChars;
|
|
2948
3067
|
let mode = "heuristic";
|
|
3068
|
+
let frozenReplayEvalIdentity = null;
|
|
2949
3069
|
let routeSelectionStartedAtNs = null;
|
|
2950
3070
|
let routeSelectionMs = null;
|
|
2951
3071
|
let promptAssemblyStartedAtNs = null;
|
|
@@ -2955,13 +3075,16 @@ export function compileRuntimeContext(input) {
|
|
|
2955
3075
|
activationRoot = path.resolve(normalizeNonEmptyString(input.activationRoot, "activationRoot"));
|
|
2956
3076
|
agentId = normalizeOptionalString(input.agentId) ?? process.env.OPENCLAWBRAIN_AGENT_ID ?? DEFAULT_AGENT_ID;
|
|
2957
3077
|
runtimeHints = normalizeRuntimeHints(input.runtimeHints);
|
|
2958
|
-
selectionMode = normalizeCompileSelectionMode(input.selectionMode);
|
|
2959
3078
|
userMessage = normalizeNonEmptyString(input.message, "message");
|
|
2960
3079
|
maxContextChars =
|
|
2961
3080
|
input.maxContextChars !== undefined
|
|
2962
3081
|
? normalizeNonNegativeInteger(input.maxContextChars, "maxContextChars", input.maxContextChars)
|
|
2963
3082
|
: undefined;
|
|
2964
|
-
|
|
3083
|
+
const compileModePlan = resolveCompileModePlan(input.mode, input.selectionMode);
|
|
3084
|
+
comparativeMode = compileModePlan.comparativeMode;
|
|
3085
|
+
mode = compileModePlan.routeMode;
|
|
3086
|
+
selectionMode = compileModePlan.selectionMode;
|
|
3087
|
+
frozenReplayEvalIdentity = normalizeFrozenReplayEvalIdentity(input._frozenReplayEvalIdentity);
|
|
2965
3088
|
}
|
|
2966
3089
|
catch (error) {
|
|
2967
3090
|
result = failOpenCompileResult(error, fallbackActivationRoot, buildBrainServeHotPathTiming({
|
|
@@ -2979,6 +3102,7 @@ export function compileRuntimeContext(input) {
|
|
|
2979
3102
|
}
|
|
2980
3103
|
try {
|
|
2981
3104
|
const target = resolveActivePackForCompile(activationRoot);
|
|
3105
|
+
validateFrozenReplayEvalIdentity(target, frozenReplayEvalIdentity);
|
|
2982
3106
|
const resolvedBudget = resolveCompileBudget(target, input);
|
|
2983
3107
|
routeSelectionStartedAtNs = monotonicClockNs();
|
|
2984
3108
|
const compile = compileRuntimeFromActivation(activationRoot, {
|
|
@@ -2995,11 +3119,29 @@ export function compileRuntimeContext(input) {
|
|
|
2995
3119
|
...(selectionMode !== undefined ? { selectionMode } : {})
|
|
2996
3120
|
});
|
|
2997
3121
|
routeSelectionMs = elapsedMsFrom(routeSelectionStartedAtNs);
|
|
3122
|
+
const selectionEngine = selectionMode ?? "flat_rank_v1";
|
|
2998
3123
|
const compileResponse = {
|
|
2999
3124
|
...compile.response,
|
|
3000
3125
|
diagnostics: {
|
|
3001
3126
|
...compile.response.diagnostics,
|
|
3002
|
-
notes: uniqueNotes([
|
|
3127
|
+
notes: uniqueNotes([
|
|
3128
|
+
...compile.response.diagnostics.notes,
|
|
3129
|
+
...resolvedBudget.notes,
|
|
3130
|
+
`selection_engine=${selectionEngine}`,
|
|
3131
|
+
...(comparativeMode === null
|
|
3132
|
+
? []
|
|
3133
|
+
: [
|
|
3134
|
+
`comparative_mode=${comparativeMode}`,
|
|
3135
|
+
`comparative_mode_plan=${mode}+${selectionEngine}`
|
|
3136
|
+
]),
|
|
3137
|
+
...(frozenReplayEvalIdentity === null
|
|
3138
|
+
? []
|
|
3139
|
+
: [
|
|
3140
|
+
`replay_eval_pack_id=${frozenReplayEvalIdentity.packId}`,
|
|
3141
|
+
`replay_eval_router_identity=${frozenReplayEvalIdentity.routerIdentity ?? "null"}`
|
|
3142
|
+
]),
|
|
3143
|
+
"OpenClaw remains the runtime owner"
|
|
3144
|
+
])
|
|
3003
3145
|
}
|
|
3004
3146
|
};
|
|
3005
3147
|
promptAssemblyStartedAtNs = monotonicClockNs();
|
|
@@ -3882,6 +4024,7 @@ export function runRuntimeTurn(turn, options = {}) {
|
|
|
3882
4024
|
...(turn.mode !== undefined ? { mode: turn.mode } : {}),
|
|
3883
4025
|
...(turn.selectionMode !== undefined ? { selectionMode: turn.selectionMode } : {}),
|
|
3884
4026
|
...(turn.runtimeHints !== undefined ? { runtimeHints: turn.runtimeHints } : {}),
|
|
4027
|
+
...(options._frozenReplayEvalIdentity !== undefined ? { _frozenReplayEvalIdentity: options._frozenReplayEvalIdentity } : {}),
|
|
3885
4028
|
_suppressServeLog: true
|
|
3886
4029
|
};
|
|
3887
4030
|
const compileResult = compileRuntimeContext(compileInput);
|
|
@@ -4130,6 +4273,7 @@ function ensureRecordedSessionTrace(trace) {
|
|
|
4130
4273
|
if (trace.turns.length === 0) {
|
|
4131
4274
|
throw new Error("recorded session trace requires at least one turn");
|
|
4132
4275
|
}
|
|
4276
|
+
resolveRecordedSessionReplayEvalTurnCount(trace.turns.length, trace.evalTurnCount, "evalTurnCount");
|
|
4133
4277
|
for (const [index, cue] of trace.seedCues.entries()) {
|
|
4134
4278
|
normalizeNonEmptyString(cue.cueId, `seedCues[${index}].cueId`);
|
|
4135
4279
|
normalizeIsoTimestamp(cue.createdAt, `seedCues[${index}].createdAt`);
|
|
@@ -4181,6 +4325,52 @@ function uniqueStringsInOrder(values) {
|
|
|
4181
4325
|
}
|
|
4182
4326
|
return unique;
|
|
4183
4327
|
}
|
|
4328
|
+
function resolveRecordedSessionReplayEvalTurnCount(turnCount, value, fieldName) {
|
|
4329
|
+
if (turnCount === 0) {
|
|
4330
|
+
return 0;
|
|
4331
|
+
}
|
|
4332
|
+
if (value === undefined) {
|
|
4333
|
+
return 1;
|
|
4334
|
+
}
|
|
4335
|
+
const normalized = normalizeNonNegativeInteger(value, fieldName, value);
|
|
4336
|
+
if (normalized < 1) {
|
|
4337
|
+
throw new Error(`${fieldName} must be at least 1 when turns are present`);
|
|
4338
|
+
}
|
|
4339
|
+
if (normalized > turnCount) {
|
|
4340
|
+
throw new Error(`${fieldName} cannot exceed turns.length (${turnCount})`);
|
|
4341
|
+
}
|
|
4342
|
+
return normalized;
|
|
4343
|
+
}
|
|
4344
|
+
function buildRecordedSessionReplayTurnPlan(fixture) {
|
|
4345
|
+
const evalTurnCount = resolveRecordedSessionReplayEvalTurnCount(fixture.turns.length, fixture.evalTurnCount, "evalTurnCount");
|
|
4346
|
+
const trainTurnCount = Math.max(0, fixture.turns.length - evalTurnCount);
|
|
4347
|
+
return {
|
|
4348
|
+
trainTurns: fixture.turns.slice(0, trainTurnCount),
|
|
4349
|
+
evalTurns: fixture.turns.slice(trainTurnCount),
|
|
4350
|
+
trainTurnCount,
|
|
4351
|
+
evalTurnCount
|
|
4352
|
+
};
|
|
4353
|
+
}
|
|
4354
|
+
function cloneRecordedSessionReplayFrozenEvalIdentity(value) {
|
|
4355
|
+
if (value === null) {
|
|
4356
|
+
return null;
|
|
4357
|
+
}
|
|
4358
|
+
return {
|
|
4359
|
+
packId: value.packId,
|
|
4360
|
+
routerIdentity: value.routerIdentity
|
|
4361
|
+
};
|
|
4362
|
+
}
|
|
4363
|
+
function readRecordedSessionReplayFrozenEvalIdentity(activationRoot) {
|
|
4364
|
+
const inspection = inspectActivationState(activationRoot);
|
|
4365
|
+
const activePointer = inspection.pointers.active;
|
|
4366
|
+
if (inspection.active === null || activePointer === null) {
|
|
4367
|
+
return null;
|
|
4368
|
+
}
|
|
4369
|
+
return {
|
|
4370
|
+
packId: activePointer.packId,
|
|
4371
|
+
routerIdentity: inspection.active.routerIdentity ?? null
|
|
4372
|
+
};
|
|
4373
|
+
}
|
|
4184
4374
|
function buildRecordedSessionSeedExport(trace) {
|
|
4185
4375
|
const agentId = normalizeOptionalString(trace.agentId) ?? DEFAULT_AGENT_ID;
|
|
4186
4376
|
const seedSessionId = `${trace.sessionId}-seed`;
|
|
@@ -4292,6 +4482,9 @@ function recordedSessionFixtureBase(trace) {
|
|
|
4292
4482
|
revision: trace.workspace.revision,
|
|
4293
4483
|
...(trace.workspace.labels !== undefined ? { labels: [...trace.workspace.labels] } : {})
|
|
4294
4484
|
},
|
|
4485
|
+
...(trace.evalTurnCount !== undefined
|
|
4486
|
+
? { evalTurnCount: resolveRecordedSessionReplayEvalTurnCount(trace.turns.length, trace.evalTurnCount, "evalTurnCount") }
|
|
4487
|
+
: {}),
|
|
4295
4488
|
seedBuiltAt: trace.seedBuiltAt,
|
|
4296
4489
|
seedActivatedAt: trace.seedActivatedAt,
|
|
4297
4490
|
seedExport: buildRecordedSessionSeedExport(trace),
|
|
@@ -4327,6 +4520,9 @@ function recordedSessionReplayFixtureBase(fixture) {
|
|
|
4327
4520
|
revision: fixture.workspace.revision,
|
|
4328
4521
|
...(fixture.workspace.labels !== undefined ? { labels: [...fixture.workspace.labels] } : {})
|
|
4329
4522
|
},
|
|
4523
|
+
...(fixture.evalTurnCount !== undefined
|
|
4524
|
+
? { evalTurnCount: resolveRecordedSessionReplayEvalTurnCount(fixture.turns.length, fixture.evalTurnCount, "evalTurnCount") }
|
|
4525
|
+
: {}),
|
|
4330
4526
|
seedBuiltAt: fixture.seedBuiltAt,
|
|
4331
4527
|
seedActivatedAt: fixture.seedActivatedAt,
|
|
4332
4528
|
seedExport: fixture.seedExport,
|
|
@@ -4377,7 +4573,49 @@ function buildRecordedSessionTurnObservability(result) {
|
|
|
4377
4573
|
freshestCreatedAt: observability.teacherFreshness.freshestCreatedAt ?? freshestSource?.freshestCreatedAt ?? null
|
|
4378
4574
|
};
|
|
4379
4575
|
}
|
|
4380
|
-
|
|
4576
|
+
const RECORDED_SESSION_REPLAY_MODE_PLAN = {
|
|
4577
|
+
no_brain: {
|
|
4578
|
+
activationStrategy: "no_brain",
|
|
4579
|
+
runtimeMode: null,
|
|
4580
|
+
routeModeRequested: null,
|
|
4581
|
+
selectionEngine: null,
|
|
4582
|
+
learnedRouting: false
|
|
4583
|
+
},
|
|
4584
|
+
vector_only: {
|
|
4585
|
+
activationStrategy: "seed_pack",
|
|
4586
|
+
runtimeMode: "vector_only",
|
|
4587
|
+
routeModeRequested: "heuristic",
|
|
4588
|
+
selectionEngine: "flat_rank_v1",
|
|
4589
|
+
learnedRouting: false
|
|
4590
|
+
},
|
|
4591
|
+
graph_prior_only: {
|
|
4592
|
+
activationStrategy: "seed_pack",
|
|
4593
|
+
runtimeMode: "graph_prior_only",
|
|
4594
|
+
routeModeRequested: "heuristic",
|
|
4595
|
+
selectionEngine: "graph_walk_v1",
|
|
4596
|
+
learnedRouting: false
|
|
4597
|
+
},
|
|
4598
|
+
learned_route: {
|
|
4599
|
+
activationStrategy: "continuous_learned_loop",
|
|
4600
|
+
runtimeMode: "learned_route",
|
|
4601
|
+
routeModeRequested: "learned",
|
|
4602
|
+
selectionEngine: "graph_walk_v1",
|
|
4603
|
+
learnedRouting: true
|
|
4604
|
+
}
|
|
4605
|
+
};
|
|
4606
|
+
function recordedSessionReplayModePlan(mode) {
|
|
4607
|
+
return RECORDED_SESSION_REPLAY_MODE_PLAN[mode];
|
|
4608
|
+
}
|
|
4609
|
+
function buildRecordedSessionReplayTurnInput(turnFixture, modeRoot, replayMode) {
|
|
4610
|
+
const plan = recordedSessionReplayModePlan(replayMode);
|
|
4611
|
+
return {
|
|
4612
|
+
...turnFixture.turn,
|
|
4613
|
+
...(plan.runtimeMode === null ? {} : { mode: plan.runtimeMode }),
|
|
4614
|
+
export: buildRecordedSessionTurnExportRoot(modeRoot, turnFixture.turnId)
|
|
4615
|
+
};
|
|
4616
|
+
}
|
|
4617
|
+
function buildRecordedSessionTurnReport(replayMode, turnFixture, result, options) {
|
|
4618
|
+
const plan = recordedSessionReplayModePlan(replayMode);
|
|
4381
4619
|
const compileOk = result.ok;
|
|
4382
4620
|
const selectedContextTexts = compileOk ? result.compileResponse.selectedContext.map((block) => block.text) : [];
|
|
4383
4621
|
const selectedContextIds = compileOk ? result.compileResponse.selectedContext.map((block) => block.id) : [];
|
|
@@ -4390,10 +4628,15 @@ function buildRecordedSessionTurnReport(turnFixture, result, options) {
|
|
|
4390
4628
|
const eventExportDigest = result.eventExport.ok === true ? result.eventExport.normalizedEventExport.provenance.exportDigest : null;
|
|
4391
4629
|
return {
|
|
4392
4630
|
turnId: turnFixture.turnId,
|
|
4631
|
+
replayMode,
|
|
4632
|
+
phase: options.phase,
|
|
4393
4633
|
compileOk,
|
|
4394
4634
|
fallbackToStaticContext: result.fallbackToStaticContext,
|
|
4395
4635
|
hardRequirementViolated: result.hardRequirementViolated,
|
|
4396
4636
|
activePackId: result.ok ? result.activePackId : null,
|
|
4637
|
+
modeRequested: plan.routeModeRequested,
|
|
4638
|
+
modeEffective: result.ok ? result.compileResponse.diagnostics.modeEffective : null,
|
|
4639
|
+
selectionEngine: plan.selectionEngine,
|
|
4397
4640
|
usedLearnedRouteFn: result.ok ? result.compileResponse.diagnostics.usedLearnedRouteFn : false,
|
|
4398
4641
|
routerIdentity: result.ok ? result.compileResponse.diagnostics.routerIdentity : null,
|
|
4399
4642
|
selectionDigest: result.ok ? result.compileResponse.diagnostics.selectionDigest : null,
|
|
@@ -4447,7 +4690,7 @@ function buildRecordedSessionReplayScannerWarnings(mode, turns, activePackChange
|
|
|
4447
4690
|
if (turns.some((turn) => turn.compileOk) && selectionDigestTurnCount === 0) {
|
|
4448
4691
|
warnings.push("selection_digest_missing");
|
|
4449
4692
|
}
|
|
4450
|
-
if (mode === "
|
|
4693
|
+
if (mode === "learned_route" && activePackChangeCount === 0) {
|
|
4451
4694
|
warnings.push("active_pack_never_moved");
|
|
4452
4695
|
}
|
|
4453
4696
|
return warnings;
|
|
@@ -4479,17 +4722,33 @@ function buildRecordedSessionReplayScannerEvidence(mode, turns) {
|
|
|
4479
4722
|
warnings: buildRecordedSessionReplayScannerWarnings(mode, turns, activePackChangeCount)
|
|
4480
4723
|
};
|
|
4481
4724
|
}
|
|
4482
|
-
function
|
|
4725
|
+
function buildRecordedSessionReplayModeQualityScore(turns, compileOkCount, phraseHitCount, phraseCount) {
|
|
4726
|
+
if (turns.length === 0) {
|
|
4727
|
+
return 0;
|
|
4728
|
+
}
|
|
4729
|
+
// Score mode quality from aggregate replay coverage so multi-phrase turns
|
|
4730
|
+
// keep their full weight instead of being flattened into a per-turn average.
|
|
4731
|
+
const compileScore = (compileOkCount / turns.length) * 40;
|
|
4732
|
+
const phraseScore = phraseCount === 0 ? 60 : (phraseHitCount / phraseCount) * 60;
|
|
4733
|
+
return Math.min(100, Math.round(compileScore + phraseScore));
|
|
4734
|
+
}
|
|
4735
|
+
function buildRecordedSessionReplayModeSummary(mode, turns, options = {}) {
|
|
4736
|
+
const plan = recordedSessionReplayModePlan(mode);
|
|
4483
4737
|
const compileOkCount = turns.filter((turn) => turn.compileOk).length;
|
|
4484
4738
|
const phraseHitCount = turns.reduce((sum, turn) => sum + turn.phraseHits.length, 0);
|
|
4485
4739
|
const phraseCount = turns.reduce((sum, turn) => sum + turn.expectedContextPhrases.length, 0);
|
|
4486
4740
|
const usedLearnedRouteTurnCount = turns.filter((turn) => turn.usedLearnedRouteFn).length;
|
|
4487
4741
|
const promotionCount = turns.filter((turn) => turn.promoted).length;
|
|
4488
|
-
const qualityScore =
|
|
4742
|
+
const qualityScore = buildRecordedSessionReplayModeQualityScore(turns, compileOkCount, phraseHitCount, phraseCount);
|
|
4489
4743
|
const packIds = uniqueStringsInOrder(turns.map((turn) => turn.activePackId).filter(isPresent));
|
|
4744
|
+
const trainTurnCount = turns.filter((turn) => turn.phase === "train").length;
|
|
4745
|
+
const evalTurnCount = turns.filter((turn) => turn.phase === "eval").length;
|
|
4490
4746
|
const scannerEvidence = buildRecordedSessionReplayScannerEvidence(mode, turns);
|
|
4491
4747
|
const base = {
|
|
4492
4748
|
mode,
|
|
4749
|
+
activationStrategy: plan.activationStrategy,
|
|
4750
|
+
modeRequested: plan.routeModeRequested,
|
|
4751
|
+
selectionEngine: plan.selectionEngine,
|
|
4493
4752
|
qualityScore,
|
|
4494
4753
|
compileOkCount,
|
|
4495
4754
|
phraseHitCount,
|
|
@@ -4497,6 +4756,10 @@ function buildRecordedSessionReplayModeSummary(mode, turns) {
|
|
|
4497
4756
|
usedLearnedRouteTurnCount,
|
|
4498
4757
|
promotionCount,
|
|
4499
4758
|
packIds,
|
|
4759
|
+
trainTurnCount,
|
|
4760
|
+
evalTurnCount,
|
|
4761
|
+
frozenEvalPackId: options.frozenEvalIdentity?.packId ?? null,
|
|
4762
|
+
frozenEvalRouterIdentity: options.frozenEvalIdentity?.routerIdentity ?? null,
|
|
4500
4763
|
scannerEvidence
|
|
4501
4764
|
};
|
|
4502
4765
|
return {
|
|
@@ -4505,10 +4768,15 @@ function buildRecordedSessionReplayModeSummary(mode, turns) {
|
|
|
4505
4768
|
summary: base,
|
|
4506
4769
|
turns: turns.map((turn) => ({
|
|
4507
4770
|
turnId: turn.turnId,
|
|
4771
|
+
phase: turn.phase,
|
|
4508
4772
|
qualityScore: turn.qualityScore,
|
|
4509
4773
|
phraseHits: turn.phraseHits,
|
|
4510
4774
|
missedPhrases: turn.missedPhrases,
|
|
4511
4775
|
compileOk: turn.compileOk,
|
|
4776
|
+
replayMode: turn.replayMode,
|
|
4777
|
+
modeRequested: turn.modeRequested,
|
|
4778
|
+
modeEffective: turn.modeEffective,
|
|
4779
|
+
selectionEngine: turn.selectionEngine,
|
|
4512
4780
|
usedLearnedRouteFn: turn.usedLearnedRouteFn,
|
|
4513
4781
|
activePackId: turn.activePackId,
|
|
4514
4782
|
selectionDigest: turn.selectionDigest,
|
|
@@ -4518,16 +4786,19 @@ function buildRecordedSessionReplayModeSummary(mode, turns) {
|
|
|
4518
4786
|
})
|
|
4519
4787
|
};
|
|
4520
4788
|
}
|
|
4521
|
-
function buildRecordedSessionReplayModeReport(mode, turns) {
|
|
4789
|
+
function buildRecordedSessionReplayModeReport(mode, turns, options = {}) {
|
|
4522
4790
|
return {
|
|
4523
4791
|
mode,
|
|
4524
|
-
summary: buildRecordedSessionReplayModeSummary(mode, turns),
|
|
4792
|
+
summary: buildRecordedSessionReplayModeSummary(mode, turns, options),
|
|
4525
4793
|
turns: [...turns]
|
|
4526
4794
|
};
|
|
4527
4795
|
}
|
|
4528
4796
|
function buildRecordedSessionReplayScoreHash(modes) {
|
|
4529
4797
|
return checksumJsonPayload(modes.map((mode) => ({
|
|
4530
4798
|
mode: mode.mode,
|
|
4799
|
+
activationStrategy: mode.summary.activationStrategy,
|
|
4800
|
+
modeRequested: mode.summary.modeRequested,
|
|
4801
|
+
selectionEngine: mode.summary.selectionEngine,
|
|
4531
4802
|
qualityScore: mode.summary.qualityScore,
|
|
4532
4803
|
compileOkCount: mode.summary.compileOkCount,
|
|
4533
4804
|
phraseHitCount: mode.summary.phraseHitCount,
|
|
@@ -4535,6 +4806,10 @@ function buildRecordedSessionReplayScoreHash(modes) {
|
|
|
4535
4806
|
usedLearnedRouteTurnCount: mode.summary.usedLearnedRouteTurnCount,
|
|
4536
4807
|
promotionCount: mode.summary.promotionCount,
|
|
4537
4808
|
packIds: mode.summary.packIds,
|
|
4809
|
+
trainTurnCount: mode.summary.trainTurnCount,
|
|
4810
|
+
evalTurnCount: mode.summary.evalTurnCount,
|
|
4811
|
+
frozenEvalPackId: mode.summary.frozenEvalPackId,
|
|
4812
|
+
frozenEvalRouterIdentity: mode.summary.frozenEvalRouterIdentity,
|
|
4538
4813
|
scannerEvidence: mode.summary.scannerEvidence,
|
|
4539
4814
|
scoreHash: mode.summary.scoreHash
|
|
4540
4815
|
})));
|
|
@@ -4625,45 +4900,42 @@ function runRecordedSessionNoBrainMode(rootDir, fixture) {
|
|
|
4625
4900
|
const modeRoot = prepareReplayModeRoot(rootDir, "no_brain");
|
|
4626
4901
|
const activationRoot = path.join(modeRoot, "activation");
|
|
4627
4902
|
const turns = fixture.turns.map((turnFixture) => {
|
|
4628
|
-
const result = runRuntimeTurn({
|
|
4629
|
-
...turnFixture.turn,
|
|
4630
|
-
export: buildRecordedSessionTurnExportRoot(modeRoot, turnFixture.turnId)
|
|
4631
|
-
}, {
|
|
4903
|
+
const result = runRuntimeTurn(buildRecordedSessionReplayTurnInput(turnFixture, modeRoot, "no_brain"), {
|
|
4632
4904
|
activationRoot,
|
|
4633
4905
|
failOpen: true
|
|
4634
4906
|
});
|
|
4635
|
-
return buildRecordedSessionTurnReport(turnFixture, result, {
|
|
4907
|
+
return buildRecordedSessionTurnReport("no_brain", turnFixture, result, {
|
|
4908
|
+
phase: "eval",
|
|
4636
4909
|
compileActiveVersion: null,
|
|
4637
4910
|
promoted: false
|
|
4638
4911
|
});
|
|
4639
4912
|
});
|
|
4640
4913
|
return buildRecordedSessionReplayModeReport("no_brain", turns);
|
|
4641
4914
|
}
|
|
4642
|
-
function
|
|
4643
|
-
const modeRoot = prepareReplayModeRoot(rootDir,
|
|
4915
|
+
function runRecordedSessionSeededComparativeMode(rootDir, fixture, replayMode) {
|
|
4916
|
+
const modeRoot = prepareReplayModeRoot(rootDir, replayMode);
|
|
4644
4917
|
const { activationRoot } = prepareSeedActivation(modeRoot, fixture);
|
|
4645
4918
|
const turns = fixture.turns.map((turnFixture) => {
|
|
4646
|
-
const result = runRuntimeTurn({
|
|
4647
|
-
...turnFixture.turn,
|
|
4648
|
-
export: buildRecordedSessionTurnExportRoot(modeRoot, turnFixture.turnId)
|
|
4649
|
-
}, {
|
|
4919
|
+
const result = runRuntimeTurn(buildRecordedSessionReplayTurnInput(turnFixture, modeRoot, replayMode), {
|
|
4650
4920
|
activationRoot,
|
|
4651
4921
|
failOpen: false
|
|
4652
4922
|
});
|
|
4653
|
-
return buildRecordedSessionTurnReport(turnFixture, result, {
|
|
4923
|
+
return buildRecordedSessionTurnReport(replayMode, turnFixture, result, {
|
|
4924
|
+
phase: "eval",
|
|
4654
4925
|
compileActiveVersion: 1,
|
|
4655
4926
|
promoted: false
|
|
4656
4927
|
});
|
|
4657
4928
|
});
|
|
4658
|
-
return buildRecordedSessionReplayModeReport(
|
|
4929
|
+
return buildRecordedSessionReplayModeReport(replayMode, turns);
|
|
4659
4930
|
}
|
|
4660
|
-
function
|
|
4661
|
-
const modeRoot = prepareReplayModeRoot(rootDir, "
|
|
4931
|
+
function runRecordedSessionLearnedRouteMode(rootDir, fixture) {
|
|
4932
|
+
const modeRoot = prepareReplayModeRoot(rootDir, "learned_route");
|
|
4662
4933
|
const { activationRoot } = prepareSeedActivation(modeRoot, fixture);
|
|
4663
4934
|
const loopRoot = path.join(modeRoot, "loop");
|
|
4935
|
+
const turnPlan = buildRecordedSessionReplayTurnPlan(fixture);
|
|
4664
4936
|
let state;
|
|
4665
4937
|
const turns = [];
|
|
4666
|
-
for (const turnFixture of
|
|
4938
|
+
for (const turnFixture of turnPlan.trainTurns) {
|
|
4667
4939
|
const compileCreatedAt = normalizeIsoTimestamp(turnFixture.turn.compile?.createdAt, "turn.compile.createdAt", turnFixture.turn.createdAt);
|
|
4668
4940
|
const result = runContinuousProductLoopTurn({
|
|
4669
4941
|
activationRoot,
|
|
@@ -4682,12 +4954,40 @@ function runRecordedSessionLearnedReplayMode(rootDir, fixture) {
|
|
|
4682
4954
|
promoteUpdatedAt: addMinutes(compileCreatedAt, 4)
|
|
4683
4955
|
});
|
|
4684
4956
|
state = result.state;
|
|
4685
|
-
turns.push(buildRecordedSessionTurnReport(turnFixture, result.turn, {
|
|
4957
|
+
turns.push(buildRecordedSessionTurnReport("learned_route", turnFixture, result.turn, {
|
|
4958
|
+
phase: "train",
|
|
4686
4959
|
compileActiveVersion: result.compileActiveVersion,
|
|
4687
4960
|
promoted: result.learning.promoted
|
|
4688
4961
|
}));
|
|
4689
4962
|
}
|
|
4690
|
-
|
|
4963
|
+
const frozenEvalIdentity = readRecordedSessionReplayFrozenEvalIdentity(activationRoot);
|
|
4964
|
+
for (const turnFixture of turnPlan.evalTurns) {
|
|
4965
|
+
const currentState = cloneContinuousProductLoopState(state ??
|
|
4966
|
+
createContinuousProductLoopState({
|
|
4967
|
+
activationRoot,
|
|
4968
|
+
loopRoot
|
|
4969
|
+
}));
|
|
4970
|
+
currentState.activationRoot = activationRoot;
|
|
4971
|
+
currentState.loopRoot = loopRoot;
|
|
4972
|
+
const activeBeforeTurn = syncContinuousActivePack(currentState);
|
|
4973
|
+
state = cloneContinuousProductLoopState(currentState);
|
|
4974
|
+
const result = runRuntimeTurn({
|
|
4975
|
+
...turnFixture.turn,
|
|
4976
|
+
export: buildRecordedSessionTurnExportRoot(modeRoot, turnFixture.turnId)
|
|
4977
|
+
}, {
|
|
4978
|
+
activationRoot,
|
|
4979
|
+
failOpen: false,
|
|
4980
|
+
...(frozenEvalIdentity === null ? {} : { _frozenReplayEvalIdentity: frozenEvalIdentity })
|
|
4981
|
+
});
|
|
4982
|
+
turns.push(buildRecordedSessionTurnReport("learned_route", turnFixture, result, {
|
|
4983
|
+
phase: "eval",
|
|
4984
|
+
compileActiveVersion: activeBeforeTurn?.version ?? 0,
|
|
4985
|
+
promoted: false
|
|
4986
|
+
}));
|
|
4987
|
+
}
|
|
4988
|
+
return buildRecordedSessionReplayModeReport("learned_route", turns, {
|
|
4989
|
+
frozenEvalIdentity: cloneRecordedSessionReplayFrozenEvalIdentity(frozenEvalIdentity)
|
|
4990
|
+
});
|
|
4691
4991
|
}
|
|
4692
4992
|
export function runRecordedSessionReplay(rootDir, fixture) {
|
|
4693
4993
|
const resolvedRoot = path.resolve(normalizeNonEmptyString(rootDir, "rootDir"));
|
|
@@ -4701,8 +5001,9 @@ export function runRecordedSessionReplay(rootDir, fixture) {
|
|
|
4701
5001
|
}
|
|
4702
5002
|
const modes = [
|
|
4703
5003
|
runRecordedSessionNoBrainMode(resolvedRoot, fixture),
|
|
4704
|
-
|
|
4705
|
-
|
|
5004
|
+
runRecordedSessionSeededComparativeMode(resolvedRoot, fixture, "vector_only"),
|
|
5005
|
+
runRecordedSessionSeededComparativeMode(resolvedRoot, fixture, "graph_prior_only"),
|
|
5006
|
+
runRecordedSessionLearnedRouteMode(resolvedRoot, fixture)
|
|
4706
5007
|
];
|
|
4707
5008
|
const ranking = modes
|
|
4708
5009
|
.map((mode) => ({
|
|
@@ -4754,7 +5055,14 @@ function rescoreRecordedSessionReplayTurn(turn) {
|
|
|
4754
5055
|
}
|
|
4755
5056
|
function rescoreRecordedSessionReplayMode(mode) {
|
|
4756
5057
|
const turns = mode.turns.map((turn) => rescoreRecordedSessionReplayTurn(turn));
|
|
4757
|
-
return buildRecordedSessionReplayModeReport(mode.mode, turns
|
|
5058
|
+
return buildRecordedSessionReplayModeReport(mode.mode, turns, {
|
|
5059
|
+
frozenEvalIdentity: mode.summary.frozenEvalPackId === null
|
|
5060
|
+
? null
|
|
5061
|
+
: {
|
|
5062
|
+
packId: mode.summary.frozenEvalPackId,
|
|
5063
|
+
routerIdentity: mode.summary.frozenEvalRouterIdentity ?? null
|
|
5064
|
+
}
|
|
5065
|
+
});
|
|
4758
5066
|
}
|
|
4759
5067
|
export function rescoreRecordedSessionReplayBundle(bundle) {
|
|
4760
5068
|
const modes = bundle.modes.map((mode) => rescoreRecordedSessionReplayMode(mode));
|
|
@@ -4775,6 +5083,558 @@ export function verifyRecordedSessionReplayBundleHashes(bundle) {
|
|
|
4775
5083
|
scoreHashMatches: rescored.scoreHash === bundle.scoreHash
|
|
4776
5084
|
};
|
|
4777
5085
|
}
|
|
5086
|
+
function buildRecordedSessionReplayProofEnvironment() {
|
|
5087
|
+
return {
|
|
5088
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_ENVIRONMENT_CONTRACT,
|
|
5089
|
+
runtimeOwner: "openclaw",
|
|
5090
|
+
generator: {
|
|
5091
|
+
packageName: "@openclawbrain/cli",
|
|
5092
|
+
entrypoint: "writeRecordedSessionReplayProofBundle",
|
|
5093
|
+
nodeVersion: process.version,
|
|
5094
|
+
platform: process.platform,
|
|
5095
|
+
arch: process.arch
|
|
5096
|
+
},
|
|
5097
|
+
determinism: {
|
|
5098
|
+
hashAlgorithm: "sha256",
|
|
5099
|
+
canonicalJson: true,
|
|
5100
|
+
modeOrder: [...RECORDED_SESSION_REPLAY_MODE_ORDER],
|
|
5101
|
+
scratchReplayRoot: "temporary_directory"
|
|
5102
|
+
}
|
|
5103
|
+
};
|
|
5104
|
+
}
|
|
5105
|
+
function toRecordedSessionReplayProofRate(numerator, denominator) {
|
|
5106
|
+
return denominator > 0 ? Number((numerator / denominator).toFixed(6)) : null;
|
|
5107
|
+
}
|
|
5108
|
+
function buildRecordedSessionReplayProofSummaryTables(bundle) {
|
|
5109
|
+
const orderedModes = orderedRecordedSessionReplayModes(bundle.modes);
|
|
5110
|
+
return {
|
|
5111
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_SUMMARY_TABLES_CONTRACT,
|
|
5112
|
+
traceId: bundle.traceId,
|
|
5113
|
+
winnerMode: bundle.summary.winnerMode,
|
|
5114
|
+
ranking: bundle.summary.ranking.map((entry) => ({ ...entry })),
|
|
5115
|
+
modes: orderedModes.map((mode) => ({
|
|
5116
|
+
mode: mode.mode,
|
|
5117
|
+
turnCount: mode.turns.length,
|
|
5118
|
+
qualityScore: mode.summary.qualityScore,
|
|
5119
|
+
compileOkCount: mode.summary.compileOkCount,
|
|
5120
|
+
phraseHitCount: mode.summary.phraseHitCount,
|
|
5121
|
+
phraseCount: mode.summary.phraseCount,
|
|
5122
|
+
usedLearnedRouteTurnCount: mode.summary.usedLearnedRouteTurnCount,
|
|
5123
|
+
promotionCount: mode.summary.promotionCount,
|
|
5124
|
+
exportTurnCount: mode.summary.scannerEvidence.exportTurnCount,
|
|
5125
|
+
humanLabelCount: mode.summary.scannerEvidence.humanLabelCount,
|
|
5126
|
+
attributedTurnCount: mode.summary.scannerEvidence.attributedTurnCount,
|
|
5127
|
+
activePackChangeCount: mode.summary.scannerEvidence.activePackChangeCount,
|
|
5128
|
+
warningCount: mode.summary.scannerEvidence.warnings.length,
|
|
5129
|
+
scoreHash: mode.summary.scoreHash
|
|
5130
|
+
})),
|
|
5131
|
+
turns: orderedModes.flatMap((mode) => mode.turns.map((turn) => ({
|
|
5132
|
+
mode: mode.mode,
|
|
5133
|
+
turnId: turn.turnId,
|
|
5134
|
+
qualityScore: turn.qualityScore,
|
|
5135
|
+
compileOk: turn.compileOk,
|
|
5136
|
+
phraseHitCount: turn.phraseHits.length,
|
|
5137
|
+
phraseCount: turn.expectedContextPhrases.length,
|
|
5138
|
+
usedLearnedRouteFn: turn.usedLearnedRouteFn,
|
|
5139
|
+
promoted: turn.promoted,
|
|
5140
|
+
activePackId: turn.activePackId,
|
|
5141
|
+
selectionDigest: turn.selectionDigest,
|
|
5142
|
+
eventExportDigest: turn.eventExportDigest,
|
|
5143
|
+
warningCount: turn.warnings.length
|
|
5144
|
+
})))
|
|
5145
|
+
};
|
|
5146
|
+
}
|
|
5147
|
+
function buildRecordedSessionReplayProofCoverageSnapshot(bundle) {
|
|
5148
|
+
const orderedModes = orderedRecordedSessionReplayModes(bundle.modes);
|
|
5149
|
+
const totalTurns = orderedModes.reduce((sum, mode) => sum + mode.turns.length, 0);
|
|
5150
|
+
const compileOkTurnCount = orderedModes.reduce((sum, mode) => sum + mode.summary.compileOkCount, 0);
|
|
5151
|
+
const phraseHitCount = orderedModes.reduce((sum, mode) => sum + mode.summary.phraseHitCount, 0);
|
|
5152
|
+
const phraseCount = orderedModes.reduce((sum, mode) => sum + mode.summary.phraseCount, 0);
|
|
5153
|
+
return {
|
|
5154
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_COVERAGE_SNAPSHOT_CONTRACT,
|
|
5155
|
+
traceId: bundle.traceId,
|
|
5156
|
+
winnerMode: bundle.summary.winnerMode,
|
|
5157
|
+
totalTurns,
|
|
5158
|
+
compileOkTurnCount,
|
|
5159
|
+
compileOkRate: toRecordedSessionReplayProofRate(compileOkTurnCount, totalTurns),
|
|
5160
|
+
phraseHitCount,
|
|
5161
|
+
phraseCount,
|
|
5162
|
+
phraseHitRate: toRecordedSessionReplayProofRate(phraseHitCount, phraseCount),
|
|
5163
|
+
modes: orderedModes.map((mode) => ({
|
|
5164
|
+
mode: mode.mode,
|
|
5165
|
+
turnCount: mode.turns.length,
|
|
5166
|
+
compileOkRate: toRecordedSessionReplayProofRate(mode.summary.compileOkCount, mode.turns.length),
|
|
5167
|
+
phraseHitRate: toRecordedSessionReplayProofRate(mode.summary.phraseHitCount, mode.summary.phraseCount),
|
|
5168
|
+
learnedRouteTurnRate: toRecordedSessionReplayProofRate(mode.summary.usedLearnedRouteTurnCount, mode.turns.length),
|
|
5169
|
+
attributedTurnRate: toRecordedSessionReplayProofRate(mode.summary.scannerEvidence.attributedTurnCount, mode.turns.length)
|
|
5170
|
+
}))
|
|
5171
|
+
};
|
|
5172
|
+
}
|
|
5173
|
+
function buildRecordedSessionReplayProofHardeningSnapshot(bundle) {
|
|
5174
|
+
const orderedModes = orderedRecordedSessionReplayModes(bundle.modes);
|
|
5175
|
+
const totalTurns = orderedModes.reduce((sum, mode) => sum + mode.turns.length, 0);
|
|
5176
|
+
const compileFailureCount = orderedModes.reduce((sum, mode) => sum + (mode.turns.length - mode.summary.compileOkCount), 0);
|
|
5177
|
+
const warningCount = orderedModes.reduce((sum, mode) => sum + mode.summary.scannerEvidence.warnings.length, 0);
|
|
5178
|
+
const promotionCount = orderedModes.reduce((sum, mode) => sum + mode.summary.promotionCount, 0);
|
|
5179
|
+
const exportTurnCount = orderedModes.reduce((sum, mode) => sum + mode.summary.scannerEvidence.exportTurnCount, 0);
|
|
5180
|
+
const attributedTurnCount = orderedModes.reduce((sum, mode) => sum + mode.summary.scannerEvidence.attributedTurnCount, 0);
|
|
5181
|
+
return {
|
|
5182
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_HARDENING_SNAPSHOT_CONTRACT,
|
|
5183
|
+
traceId: bundle.traceId,
|
|
5184
|
+
totalTurns,
|
|
5185
|
+
compileFailureCount,
|
|
5186
|
+
compileFailureRate: toRecordedSessionReplayProofRate(compileFailureCount, totalTurns),
|
|
5187
|
+
warningCount,
|
|
5188
|
+
promotionCount,
|
|
5189
|
+
exportTurnCount,
|
|
5190
|
+
attributedTurnCount,
|
|
5191
|
+
modes: orderedModes.map((mode) => ({
|
|
5192
|
+
mode: mode.mode,
|
|
5193
|
+
warningCount: mode.summary.scannerEvidence.warnings.length,
|
|
5194
|
+
compileFailureCount: mode.turns.length - mode.summary.compileOkCount,
|
|
5195
|
+
promotionCount: mode.summary.promotionCount,
|
|
5196
|
+
exportTurnCount: mode.summary.scannerEvidence.exportTurnCount,
|
|
5197
|
+
attributedTurnCount: mode.summary.scannerEvidence.attributedTurnCount
|
|
5198
|
+
}))
|
|
5199
|
+
};
|
|
5200
|
+
}
|
|
5201
|
+
function buildRecordedSessionReplayProofSummary(input) {
|
|
5202
|
+
const rankingRows = input.summaryTables.ranking.map((entry, index) => `| ${index + 1} | ${entry.mode} | ${entry.qualityScore} |`);
|
|
5203
|
+
const modeRows = input.summaryTables.modes.map((mode) => `| ${mode.mode} | ${mode.turnCount} | ${mode.compileOkCount} | ${mode.phraseHitCount}/${mode.phraseCount} | ${mode.usedLearnedRouteTurnCount} | ${mode.promotionCount} | ${mode.exportTurnCount} | ${mode.humanLabelCount} | ${mode.warningCount} | ${mode.scoreHash} |`);
|
|
5204
|
+
const turnRows = input.summaryTables.turns.map((turn) => `| ${turn.mode} | ${turn.turnId} | ${turn.qualityScore} | ${turn.compileOk ? "yes" : "no"} | ${turn.phraseHitCount}/${turn.phraseCount} | ${turn.usedLearnedRouteFn ? "yes" : "no"} | ${turn.promoted ? "yes" : "no"} | ${turn.activePackId ?? "none"} | ${turn.selectionDigest ?? "none"} |`);
|
|
5205
|
+
const coverageRows = input.coverageSnapshot.modes.map((mode) => `| ${mode.mode} | ${mode.turnCount} | ${mode.compileOkRate ?? "none"} | ${mode.phraseHitRate ?? "none"} | ${mode.learnedRouteTurnRate ?? "none"} | ${mode.attributedTurnRate ?? "none"} |`);
|
|
5206
|
+
const hardeningRows = input.hardeningSnapshot.modes.map((mode) => `| ${mode.mode} | ${mode.warningCount} | ${mode.compileFailureCount} | ${mode.promotionCount} | ${mode.exportTurnCount} | ${mode.attributedTurnCount} |`);
|
|
5207
|
+
return [
|
|
5208
|
+
"# Recorded Session Replay Proof Bundle",
|
|
5209
|
+
"",
|
|
5210
|
+
`- trace id: \`${input.bundle.traceId}\``,
|
|
5211
|
+
`- winner mode: \`${input.bundle.summary.winnerMode ?? "none"}\``,
|
|
5212
|
+
`- trace hash: \`${input.semanticHashes.traceHash}\``,
|
|
5213
|
+
`- fixture hash: \`${input.semanticHashes.fixtureHash}\``,
|
|
5214
|
+
`- score hash: \`${input.semanticHashes.scoreHash}\``,
|
|
5215
|
+
`- bundle hash: \`${input.semanticHashes.bundleHash}\``,
|
|
5216
|
+
"",
|
|
5217
|
+
"## Ranking",
|
|
5218
|
+
"| rank | mode | quality score |",
|
|
5219
|
+
"| --- | --- | ---: |",
|
|
5220
|
+
...(rankingRows.length === 0 ? ["| - | none | 0 |"] : rankingRows),
|
|
5221
|
+
"",
|
|
5222
|
+
"## Coverage Snapshot",
|
|
5223
|
+
`- compile ok turns: ${input.coverageSnapshot.compileOkTurnCount}/${input.coverageSnapshot.totalTurns}`,
|
|
5224
|
+
`- compile ok rate: ${input.coverageSnapshot.compileOkRate ?? "none"}`,
|
|
5225
|
+
`- phrase hits: ${input.coverageSnapshot.phraseHitCount}/${input.coverageSnapshot.phraseCount}`,
|
|
5226
|
+
`- phrase hit rate: ${input.coverageSnapshot.phraseHitRate ?? "none"}`,
|
|
5227
|
+
"",
|
|
5228
|
+
"| mode | turns | compile ok rate | phrase hit rate | learned route turn rate | attributed turn rate |",
|
|
5229
|
+
"| --- | ---: | ---: | ---: | ---: | ---: |",
|
|
5230
|
+
...(coverageRows.length === 0 ? ["| - | 0 | none | none | none | none |"] : coverageRows),
|
|
5231
|
+
"",
|
|
5232
|
+
"## Hardening Snapshot",
|
|
5233
|
+
`- compile failures: ${input.hardeningSnapshot.compileFailureCount}/${input.hardeningSnapshot.totalTurns}`,
|
|
5234
|
+
`- compile failure rate: ${input.hardeningSnapshot.compileFailureRate ?? "none"}`,
|
|
5235
|
+
`- warnings: ${input.hardeningSnapshot.warningCount}`,
|
|
5236
|
+
`- promotions: ${input.hardeningSnapshot.promotionCount}`,
|
|
5237
|
+
"",
|
|
5238
|
+
"| mode | warnings | compile failures | promotions | export turns | attributed turns |",
|
|
5239
|
+
"| --- | ---: | ---: | ---: | ---: | ---: |",
|
|
5240
|
+
...(hardeningRows.length === 0 ? ["| - | 0 | 0 | 0 | 0 | 0 |"] : hardeningRows),
|
|
5241
|
+
"",
|
|
5242
|
+
"## Mode Table",
|
|
5243
|
+
"| mode | turns | compile ok | phrase hits | learned route turns | promotions | export turns | human labels | warnings | score hash |",
|
|
5244
|
+
"| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |",
|
|
5245
|
+
...(modeRows.length === 0 ? ["| - | 0 | 0 | 0/0 | 0 | 0 | 0 | 0 | 0 | none |"] : modeRows),
|
|
5246
|
+
"",
|
|
5247
|
+
"## Turn Table",
|
|
5248
|
+
"| mode | turn | quality | compile ok | phrase hits | learned route | promoted | active pack | selection digest |",
|
|
5249
|
+
"| --- | --- | ---: | --- | ---: | --- | --- | --- | --- |",
|
|
5250
|
+
...(turnRows.length === 0 ? ["| - | none | 0 | no | 0/0 | no | no | none | none |"] : turnRows),
|
|
5251
|
+
""
|
|
5252
|
+
].join("\n");
|
|
5253
|
+
}
|
|
5254
|
+
function buildRecordedSessionReplayProofManifest(bundle) {
|
|
5255
|
+
return {
|
|
5256
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_MANIFEST_CONTRACT,
|
|
5257
|
+
traceId: bundle.traceId,
|
|
5258
|
+
source: bundle.source,
|
|
5259
|
+
recordedAt: bundle.recordedAt,
|
|
5260
|
+
generatedAt: bundle.generatedAt,
|
|
5261
|
+
hashAlgorithm: "sha256",
|
|
5262
|
+
modeOrder: [...RECORDED_SESSION_REPLAY_MODE_ORDER],
|
|
5263
|
+
contracts: {
|
|
5264
|
+
trace: RECORDED_SESSION_TRACE_CONTRACT,
|
|
5265
|
+
fixture: RECORDED_SESSION_FIXTURE_CONTRACT,
|
|
5266
|
+
bundle: RECORDED_SESSION_BUNDLE_CONTRACT,
|
|
5267
|
+
environment: RECORDED_SESSION_REPLAY_PROOF_ENVIRONMENT_CONTRACT,
|
|
5268
|
+
summaryTables: RECORDED_SESSION_REPLAY_PROOF_SUMMARY_TABLES_CONTRACT,
|
|
5269
|
+
coverageSnapshot: RECORDED_SESSION_REPLAY_PROOF_COVERAGE_SNAPSHOT_CONTRACT,
|
|
5270
|
+
hardeningSnapshot: RECORDED_SESSION_REPLAY_PROOF_HARDENING_SNAPSHOT_CONTRACT,
|
|
5271
|
+
hashes: RECORDED_SESSION_REPLAY_PROOF_HASHES_CONTRACT
|
|
5272
|
+
},
|
|
5273
|
+
hashes: {
|
|
5274
|
+
traceHash: bundle.traceHash,
|
|
5275
|
+
fixtureHash: bundle.fixtureHash,
|
|
5276
|
+
scoreHash: bundle.scoreHash,
|
|
5277
|
+
bundleHash: bundle.bundleHash
|
|
5278
|
+
},
|
|
5279
|
+
files: {
|
|
5280
|
+
trace: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.trace,
|
|
5281
|
+
fixture: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.fixture,
|
|
5282
|
+
bundle: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.bundle,
|
|
5283
|
+
environment: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.environment,
|
|
5284
|
+
summary: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.summary,
|
|
5285
|
+
summaryTables: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.summaryTables,
|
|
5286
|
+
coverageSnapshot: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.coverageSnapshot,
|
|
5287
|
+
hardeningSnapshot: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.hardeningSnapshot,
|
|
5288
|
+
hashes: RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.hashes,
|
|
5289
|
+
modes: RECORDED_SESSION_REPLAY_MODE_ORDER.map((mode) => ({
|
|
5290
|
+
mode,
|
|
5291
|
+
path: recordedSessionReplayModeOutputPath(mode)
|
|
5292
|
+
}))
|
|
5293
|
+
}
|
|
5294
|
+
};
|
|
5295
|
+
}
|
|
5296
|
+
function validateRecordedSessionReplayProofManifest(manifest) {
|
|
5297
|
+
const errors = [];
|
|
5298
|
+
if (manifest.contract !== RECORDED_SESSION_REPLAY_PROOF_MANIFEST_CONTRACT) {
|
|
5299
|
+
errors.push("manifest contract is invalid");
|
|
5300
|
+
}
|
|
5301
|
+
if (canonicalJson(manifest.modeOrder ?? []) !== canonicalJson(RECORDED_SESSION_REPLAY_MODE_ORDER)) {
|
|
5302
|
+
errors.push("manifest modeOrder must stay fixed at no_brain, vector_only, graph_prior_only, learned_route");
|
|
5303
|
+
}
|
|
5304
|
+
if (manifest.hashAlgorithm !== "sha256") {
|
|
5305
|
+
errors.push("manifest hashAlgorithm must be sha256");
|
|
5306
|
+
}
|
|
5307
|
+
if (manifest.contracts?.trace !== RECORDED_SESSION_TRACE_CONTRACT ||
|
|
5308
|
+
manifest.contracts?.fixture !== RECORDED_SESSION_FIXTURE_CONTRACT ||
|
|
5309
|
+
manifest.contracts?.bundle !== RECORDED_SESSION_BUNDLE_CONTRACT ||
|
|
5310
|
+
manifest.contracts?.environment !== RECORDED_SESSION_REPLAY_PROOF_ENVIRONMENT_CONTRACT ||
|
|
5311
|
+
manifest.contracts?.summaryTables !== RECORDED_SESSION_REPLAY_PROOF_SUMMARY_TABLES_CONTRACT ||
|
|
5312
|
+
manifest.contracts?.coverageSnapshot !== RECORDED_SESSION_REPLAY_PROOF_COVERAGE_SNAPSHOT_CONTRACT ||
|
|
5313
|
+
manifest.contracts?.hardeningSnapshot !== RECORDED_SESSION_REPLAY_PROOF_HARDENING_SNAPSHOT_CONTRACT ||
|
|
5314
|
+
manifest.contracts?.hashes !== RECORDED_SESSION_REPLAY_PROOF_HASHES_CONTRACT) {
|
|
5315
|
+
errors.push("manifest contracts block is invalid");
|
|
5316
|
+
}
|
|
5317
|
+
if (manifest.files?.trace !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.trace ||
|
|
5318
|
+
manifest.files?.fixture !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.fixture ||
|
|
5319
|
+
manifest.files?.bundle !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.bundle ||
|
|
5320
|
+
manifest.files?.environment !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.environment ||
|
|
5321
|
+
manifest.files?.summary !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.summary ||
|
|
5322
|
+
manifest.files?.summaryTables !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.summaryTables ||
|
|
5323
|
+
manifest.files?.coverageSnapshot !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.coverageSnapshot ||
|
|
5324
|
+
manifest.files?.hardeningSnapshot !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.hardeningSnapshot ||
|
|
5325
|
+
manifest.files?.hashes !== RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.hashes) {
|
|
5326
|
+
errors.push("manifest top-level file layout is invalid");
|
|
5327
|
+
}
|
|
5328
|
+
const expectedModeFiles = RECORDED_SESSION_REPLAY_MODE_ORDER.map((mode) => ({
|
|
5329
|
+
mode,
|
|
5330
|
+
path: recordedSessionReplayModeOutputPath(mode)
|
|
5331
|
+
}));
|
|
5332
|
+
if (canonicalJson(manifest.files?.modes ?? []) !== canonicalJson(expectedModeFiles)) {
|
|
5333
|
+
errors.push("manifest mode outputs must stay under modes/<mode>.json in canonical order");
|
|
5334
|
+
}
|
|
5335
|
+
return errors;
|
|
5336
|
+
}
|
|
5337
|
+
function validateRecordedSessionReplayProofEnvironment(environment) {
|
|
5338
|
+
const errors = [];
|
|
5339
|
+
if (environment.contract !== RECORDED_SESSION_REPLAY_PROOF_ENVIRONMENT_CONTRACT) {
|
|
5340
|
+
errors.push("environment contract is invalid");
|
|
5341
|
+
}
|
|
5342
|
+
if (environment.runtimeOwner !== "openclaw") {
|
|
5343
|
+
errors.push("environment runtimeOwner must be openclaw");
|
|
5344
|
+
}
|
|
5345
|
+
if (environment.generator?.packageName !== "@openclawbrain/cli" ||
|
|
5346
|
+
environment.generator?.entrypoint !== "writeRecordedSessionReplayProofBundle") {
|
|
5347
|
+
errors.push("environment generator metadata is invalid");
|
|
5348
|
+
}
|
|
5349
|
+
if (normalizeOptionalString(environment.generator?.nodeVersion) === undefined ||
|
|
5350
|
+
normalizeOptionalString(environment.generator?.platform) === undefined ||
|
|
5351
|
+
normalizeOptionalString(environment.generator?.arch) === undefined) {
|
|
5352
|
+
errors.push("environment generator runtime fields are required");
|
|
5353
|
+
}
|
|
5354
|
+
if (environment.determinism?.hashAlgorithm !== "sha256" ||
|
|
5355
|
+
environment.determinism?.canonicalJson !== true ||
|
|
5356
|
+
canonicalJson(environment.determinism?.modeOrder ?? []) !== canonicalJson(RECORDED_SESSION_REPLAY_MODE_ORDER) ||
|
|
5357
|
+
environment.determinism?.scratchReplayRoot !== "temporary_directory") {
|
|
5358
|
+
errors.push("environment determinism block is invalid");
|
|
5359
|
+
}
|
|
5360
|
+
return errors;
|
|
5361
|
+
}
|
|
5362
|
+
function buildRecordedSessionReplayProofFileDigestEntries(rootDir, manifest) {
|
|
5363
|
+
const relativePaths = [
|
|
5364
|
+
manifest.files.trace,
|
|
5365
|
+
manifest.files.fixture,
|
|
5366
|
+
manifest.files.bundle,
|
|
5367
|
+
manifest.files.environment,
|
|
5368
|
+
manifest.files.summary,
|
|
5369
|
+
manifest.files.summaryTables,
|
|
5370
|
+
manifest.files.coverageSnapshot,
|
|
5371
|
+
manifest.files.hardeningSnapshot,
|
|
5372
|
+
manifest.files.modes.map((entry) => entry.path),
|
|
5373
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.manifest
|
|
5374
|
+
].flat();
|
|
5375
|
+
return relativePaths.map((relativePath, index) => ({
|
|
5376
|
+
path: relativePath,
|
|
5377
|
+
digest: checksumTextPayload(readRecordedSessionReplayProofText(rootDir, relativePath, `files[${index}]`))
|
|
5378
|
+
}));
|
|
5379
|
+
}
|
|
5380
|
+
function buildRecordedSessionReplayProofHashes(rootDir, manifest) {
|
|
5381
|
+
return {
|
|
5382
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_HASHES_CONTRACT,
|
|
5383
|
+
algorithm: "sha256",
|
|
5384
|
+
semantic: {
|
|
5385
|
+
traceHash: manifest.hashes.traceHash,
|
|
5386
|
+
fixtureHash: manifest.hashes.fixtureHash,
|
|
5387
|
+
scoreHash: manifest.hashes.scoreHash,
|
|
5388
|
+
bundleHash: manifest.hashes.bundleHash
|
|
5389
|
+
},
|
|
5390
|
+
files: buildRecordedSessionReplayProofFileDigestEntries(rootDir, manifest)
|
|
5391
|
+
};
|
|
5392
|
+
}
|
|
5393
|
+
export function loadRecordedSessionReplayProofBundle(rootDir) {
|
|
5394
|
+
const resolvedRoot = path.resolve(rootDir);
|
|
5395
|
+
const manifestPath = path.join(resolvedRoot, RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.manifest);
|
|
5396
|
+
const manifest = readJsonFile(manifestPath);
|
|
5397
|
+
const tracePath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.trace, "manifest.files.trace");
|
|
5398
|
+
const fixturePath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.fixture, "manifest.files.fixture");
|
|
5399
|
+
const bundlePath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.bundle, "manifest.files.bundle");
|
|
5400
|
+
const environmentPath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.environment, "manifest.files.environment");
|
|
5401
|
+
const summaryPath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.summary, "manifest.files.summary");
|
|
5402
|
+
const summaryTablesPath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.summaryTables, "manifest.files.summaryTables");
|
|
5403
|
+
const coverageSnapshotPath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.coverageSnapshot, "manifest.files.coverageSnapshot");
|
|
5404
|
+
const hardeningSnapshotPath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.hardeningSnapshot, "manifest.files.hardeningSnapshot");
|
|
5405
|
+
const hashesPath = resolveRecordedSessionReplayProofPath(resolvedRoot, manifest.files.hashes, "manifest.files.hashes");
|
|
5406
|
+
const modeOutputs = (manifest.files.modes ?? []).map((entry, index) => {
|
|
5407
|
+
const outputPath = resolveRecordedSessionReplayProofPath(resolvedRoot, entry.path, `manifest.files.modes[${index}].path`);
|
|
5408
|
+
return {
|
|
5409
|
+
mode: entry.mode,
|
|
5410
|
+
path: outputPath,
|
|
5411
|
+
report: readJsonFile(outputPath)
|
|
5412
|
+
};
|
|
5413
|
+
});
|
|
5414
|
+
return {
|
|
5415
|
+
rootDir: resolvedRoot,
|
|
5416
|
+
manifestPath,
|
|
5417
|
+
tracePath,
|
|
5418
|
+
fixturePath,
|
|
5419
|
+
bundlePath,
|
|
5420
|
+
environmentPath,
|
|
5421
|
+
summaryPath,
|
|
5422
|
+
summaryTablesPath,
|
|
5423
|
+
coverageSnapshotPath,
|
|
5424
|
+
hardeningSnapshotPath,
|
|
5425
|
+
hashesPath,
|
|
5426
|
+
manifest,
|
|
5427
|
+
trace: readJsonFile(tracePath),
|
|
5428
|
+
fixture: readJsonFile(fixturePath),
|
|
5429
|
+
bundle: readJsonFile(bundlePath),
|
|
5430
|
+
environment: readJsonFile(environmentPath),
|
|
5431
|
+
summaryText: readFileSync(summaryPath, "utf8"),
|
|
5432
|
+
summaryTables: readJsonFile(summaryTablesPath),
|
|
5433
|
+
coverageSnapshot: readJsonFile(coverageSnapshotPath),
|
|
5434
|
+
hardeningSnapshot: readJsonFile(hardeningSnapshotPath),
|
|
5435
|
+
hashes: readJsonFile(hashesPath),
|
|
5436
|
+
modeOutputs
|
|
5437
|
+
};
|
|
5438
|
+
}
|
|
5439
|
+
export function validateRecordedSessionReplayProofBundle(rootDir) {
|
|
5440
|
+
const resolvedRoot = path.resolve(rootDir);
|
|
5441
|
+
try {
|
|
5442
|
+
const descriptor = loadRecordedSessionReplayProofBundle(resolvedRoot);
|
|
5443
|
+
const errors = [];
|
|
5444
|
+
errors.push(...validateRecordedSessionReplayProofManifest(descriptor.manifest));
|
|
5445
|
+
errors.push(...validateRecordedSessionReplayProofEnvironment(descriptor.environment));
|
|
5446
|
+
if (descriptor.trace.contract !== RECORDED_SESSION_TRACE_CONTRACT) {
|
|
5447
|
+
errors.push("trace.json contract is invalid");
|
|
5448
|
+
}
|
|
5449
|
+
if (descriptor.fixture.contract !== RECORDED_SESSION_FIXTURE_CONTRACT) {
|
|
5450
|
+
errors.push("fixture.json contract is invalid");
|
|
5451
|
+
}
|
|
5452
|
+
if (descriptor.bundle.contract !== RECORDED_SESSION_BUNDLE_CONTRACT) {
|
|
5453
|
+
errors.push("bundle.json contract is invalid");
|
|
5454
|
+
}
|
|
5455
|
+
if (descriptor.summaryTables.contract !== RECORDED_SESSION_REPLAY_PROOF_SUMMARY_TABLES_CONTRACT) {
|
|
5456
|
+
errors.push("summary-tables.json contract is invalid");
|
|
5457
|
+
}
|
|
5458
|
+
if (descriptor.coverageSnapshot.contract !== RECORDED_SESSION_REPLAY_PROOF_COVERAGE_SNAPSHOT_CONTRACT) {
|
|
5459
|
+
errors.push("coverage-snapshot.json contract is invalid");
|
|
5460
|
+
}
|
|
5461
|
+
if (descriptor.hardeningSnapshot.contract !== RECORDED_SESSION_REPLAY_PROOF_HARDENING_SNAPSHOT_CONTRACT) {
|
|
5462
|
+
errors.push("hardening-snapshot.json contract is invalid");
|
|
5463
|
+
}
|
|
5464
|
+
if (descriptor.hashes.contract !== RECORDED_SESSION_REPLAY_PROOF_HASHES_CONTRACT) {
|
|
5465
|
+
errors.push("hashes.json contract is invalid");
|
|
5466
|
+
}
|
|
5467
|
+
if (descriptor.hashes.algorithm !== "sha256") {
|
|
5468
|
+
errors.push("hashes.json algorithm must be sha256");
|
|
5469
|
+
}
|
|
5470
|
+
const rebuiltFixture = buildRecordedSessionReplayFixture(structuredClone(descriptor.trace));
|
|
5471
|
+
if (canonicalJson(rebuiltFixture) !== canonicalJson(descriptor.fixture)) {
|
|
5472
|
+
errors.push("fixture.json does not match the canonical fixture rebuilt from trace.json");
|
|
5473
|
+
}
|
|
5474
|
+
if (descriptor.bundle.traceHash !== descriptor.fixture.traceHash) {
|
|
5475
|
+
errors.push("bundle traceHash does not match fixture traceHash");
|
|
5476
|
+
}
|
|
5477
|
+
if (descriptor.bundle.fixtureHash !== descriptor.fixture.fixtureHash) {
|
|
5478
|
+
errors.push("bundle fixtureHash does not match fixture fixtureHash");
|
|
5479
|
+
}
|
|
5480
|
+
if (descriptor.manifest.hashes.traceHash !== descriptor.fixture.traceHash ||
|
|
5481
|
+
descriptor.manifest.hashes.fixtureHash !== descriptor.fixture.fixtureHash ||
|
|
5482
|
+
descriptor.manifest.hashes.scoreHash !== descriptor.bundle.scoreHash ||
|
|
5483
|
+
descriptor.manifest.hashes.bundleHash !== descriptor.bundle.bundleHash) {
|
|
5484
|
+
errors.push("manifest hashes do not match the replay artifacts");
|
|
5485
|
+
}
|
|
5486
|
+
const summaryTables = buildRecordedSessionReplayProofSummaryTables(descriptor.bundle);
|
|
5487
|
+
if (canonicalJson(summaryTables) !== canonicalJson(descriptor.summaryTables)) {
|
|
5488
|
+
errors.push("summary-tables.json does not match bundle.json");
|
|
5489
|
+
}
|
|
5490
|
+
const coverageSnapshot = buildRecordedSessionReplayProofCoverageSnapshot(descriptor.bundle);
|
|
5491
|
+
if (canonicalJson(coverageSnapshot) !== canonicalJson(descriptor.coverageSnapshot)) {
|
|
5492
|
+
errors.push("coverage-snapshot.json does not match bundle.json");
|
|
5493
|
+
}
|
|
5494
|
+
const hardeningSnapshot = buildRecordedSessionReplayProofHardeningSnapshot(descriptor.bundle);
|
|
5495
|
+
if (canonicalJson(hardeningSnapshot) !== canonicalJson(descriptor.hardeningSnapshot)) {
|
|
5496
|
+
errors.push("hardening-snapshot.json does not match bundle.json");
|
|
5497
|
+
}
|
|
5498
|
+
const expectedSummaryText = buildRecordedSessionReplayProofSummary({
|
|
5499
|
+
bundle: descriptor.bundle,
|
|
5500
|
+
summaryTables: descriptor.summaryTables,
|
|
5501
|
+
coverageSnapshot: descriptor.coverageSnapshot,
|
|
5502
|
+
hardeningSnapshot: descriptor.hardeningSnapshot,
|
|
5503
|
+
semanticHashes: descriptor.hashes.semantic
|
|
5504
|
+
});
|
|
5505
|
+
if (descriptor.summaryText !== expectedSummaryText) {
|
|
5506
|
+
errors.push("summary.md does not match the canonical replay proof summary");
|
|
5507
|
+
}
|
|
5508
|
+
const expectedModeCount = descriptor.bundle.modes.length;
|
|
5509
|
+
if (descriptor.modeOutputs.length !== expectedModeCount) {
|
|
5510
|
+
errors.push("mode output count does not match bundle modes");
|
|
5511
|
+
}
|
|
5512
|
+
const bundleModes = new Map(descriptor.bundle.modes.map((mode) => [mode.mode, mode]));
|
|
5513
|
+
for (const modeOutput of descriptor.modeOutputs) {
|
|
5514
|
+
const expectedMode = bundleModes.get(modeOutput.mode);
|
|
5515
|
+
if (expectedMode === undefined) {
|
|
5516
|
+
errors.push(`unexpected mode output: ${modeOutput.mode}`);
|
|
5517
|
+
continue;
|
|
5518
|
+
}
|
|
5519
|
+
if (canonicalJson(expectedMode) !== canonicalJson(modeOutput.report)) {
|
|
5520
|
+
errors.push(`mode output drift detected for ${modeOutput.mode}`);
|
|
5521
|
+
}
|
|
5522
|
+
}
|
|
5523
|
+
const semanticHashVerification = verifyRecordedSessionReplayBundleHashes(descriptor.bundle);
|
|
5524
|
+
if (!semanticHashVerification.bundleHashMatches) {
|
|
5525
|
+
errors.push("bundleHash verification failed");
|
|
5526
|
+
}
|
|
5527
|
+
if (!semanticHashVerification.scoreHashMatches) {
|
|
5528
|
+
errors.push("scoreHash verification failed");
|
|
5529
|
+
}
|
|
5530
|
+
const expectedHashes = buildRecordedSessionReplayProofHashes(resolvedRoot, descriptor.manifest);
|
|
5531
|
+
const expectedFileDigests = new Map(expectedHashes.files.map((entry) => [entry.path, entry.digest]));
|
|
5532
|
+
let verifiedFileCount = 0;
|
|
5533
|
+
for (const fileEntry of descriptor.hashes.files ?? []) {
|
|
5534
|
+
if (expectedFileDigests.get(fileEntry.path) === fileEntry.digest) {
|
|
5535
|
+
verifiedFileCount += 1;
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
const fileHashesMatch = canonicalJson(expectedHashes.files) === canonicalJson(descriptor.hashes.files ?? []);
|
|
5539
|
+
if (!fileHashesMatch) {
|
|
5540
|
+
errors.push("hashes.json file digests do not match the written artifacts");
|
|
5541
|
+
}
|
|
5542
|
+
if (canonicalJson(expectedHashes.semantic) !== canonicalJson(descriptor.hashes.semantic ?? {})) {
|
|
5543
|
+
errors.push("hashes.json semantic hashes do not match the manifest");
|
|
5544
|
+
}
|
|
5545
|
+
return {
|
|
5546
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_VALIDATION_CONTRACT,
|
|
5547
|
+
ok: errors.length === 0,
|
|
5548
|
+
rootDir: resolvedRoot,
|
|
5549
|
+
expectedFileCount: expectedHashes.files.length,
|
|
5550
|
+
verifiedFileCount,
|
|
5551
|
+
fileHashesMatch,
|
|
5552
|
+
bundleHashMatches: semanticHashVerification.bundleHashMatches,
|
|
5553
|
+
scoreHashMatches: semanticHashVerification.scoreHashMatches,
|
|
5554
|
+
errors
|
|
5555
|
+
};
|
|
5556
|
+
}
|
|
5557
|
+
catch (error) {
|
|
5558
|
+
return {
|
|
5559
|
+
contract: RECORDED_SESSION_REPLAY_PROOF_VALIDATION_CONTRACT,
|
|
5560
|
+
ok: false,
|
|
5561
|
+
rootDir: resolvedRoot,
|
|
5562
|
+
expectedFileCount: 0,
|
|
5563
|
+
verifiedFileCount: 0,
|
|
5564
|
+
fileHashesMatch: false,
|
|
5565
|
+
bundleHashMatches: false,
|
|
5566
|
+
scoreHashMatches: false,
|
|
5567
|
+
errors: [toErrorMessage(error)]
|
|
5568
|
+
};
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
export function writeRecordedSessionReplayProofBundle(input) {
|
|
5572
|
+
const resolvedRoot = path.resolve(normalizeNonEmptyString(input.rootDir, "rootDir"));
|
|
5573
|
+
const scratchRootParent = path.resolve(normalizeOptionalString(input.scratchRootDir) ?? tmpdir());
|
|
5574
|
+
mkdirSync(resolvedRoot, { recursive: true });
|
|
5575
|
+
mkdirSync(scratchRootParent, { recursive: true });
|
|
5576
|
+
rmSync(path.join(resolvedRoot, RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.modeDir), {
|
|
5577
|
+
recursive: true,
|
|
5578
|
+
force: true
|
|
5579
|
+
});
|
|
5580
|
+
for (const relativePath of [
|
|
5581
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.trace,
|
|
5582
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.fixture,
|
|
5583
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.bundle,
|
|
5584
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.environment,
|
|
5585
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.summary,
|
|
5586
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.summaryTables,
|
|
5587
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.coverageSnapshot,
|
|
5588
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.hardeningSnapshot,
|
|
5589
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.manifest,
|
|
5590
|
+
RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.hashes
|
|
5591
|
+
]) {
|
|
5592
|
+
rmSync(path.join(resolvedRoot, relativePath), { force: true });
|
|
5593
|
+
}
|
|
5594
|
+
const trace = structuredClone(input.trace);
|
|
5595
|
+
const fixture = buildRecordedSessionReplayFixture(trace);
|
|
5596
|
+
const scratchRoot = mkdtempSync(path.join(scratchRootParent, "openclawbrain-recorded-session-replay-"));
|
|
5597
|
+
let bundle;
|
|
5598
|
+
try {
|
|
5599
|
+
bundle = runRecordedSessionReplay(scratchRoot, fixture);
|
|
5600
|
+
}
|
|
5601
|
+
finally {
|
|
5602
|
+
rmSync(scratchRoot, { recursive: true, force: true });
|
|
5603
|
+
}
|
|
5604
|
+
const environment = buildRecordedSessionReplayProofEnvironment();
|
|
5605
|
+
const summaryTables = buildRecordedSessionReplayProofSummaryTables(bundle);
|
|
5606
|
+
const coverageSnapshot = buildRecordedSessionReplayProofCoverageSnapshot(bundle);
|
|
5607
|
+
const hardeningSnapshot = buildRecordedSessionReplayProofHardeningSnapshot(bundle);
|
|
5608
|
+
const manifest = buildRecordedSessionReplayProofManifest(bundle);
|
|
5609
|
+
const summaryText = buildRecordedSessionReplayProofSummary({
|
|
5610
|
+
bundle,
|
|
5611
|
+
summaryTables,
|
|
5612
|
+
coverageSnapshot,
|
|
5613
|
+
hardeningSnapshot,
|
|
5614
|
+
semanticHashes: manifest.hashes
|
|
5615
|
+
});
|
|
5616
|
+
const modeRoot = path.join(resolvedRoot, RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.modeDir);
|
|
5617
|
+
mkdirSync(modeRoot, { recursive: true });
|
|
5618
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.trace), canonicalJson(trace), "utf8");
|
|
5619
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.fixture), canonicalJson(fixture), "utf8");
|
|
5620
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.bundle), canonicalJson(bundle), "utf8");
|
|
5621
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.environment), canonicalJson(environment), "utf8");
|
|
5622
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.summaryTables), canonicalJson(summaryTables), "utf8");
|
|
5623
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.coverageSnapshot), canonicalJson(coverageSnapshot), "utf8");
|
|
5624
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.hardeningSnapshot), canonicalJson(hardeningSnapshot), "utf8");
|
|
5625
|
+
for (const mode of orderedRecordedSessionReplayModes(bundle.modes)) {
|
|
5626
|
+
writeFileSync(path.join(resolvedRoot, recordedSessionReplayModeOutputPath(mode.mode)), canonicalJson(mode), "utf8");
|
|
5627
|
+
}
|
|
5628
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.summary), summaryText, "utf8");
|
|
5629
|
+
writeFileSync(path.join(resolvedRoot, RECORDED_SESSION_REPLAY_PROOF_BUNDLE_LAYOUT.manifest), canonicalJson(manifest), "utf8");
|
|
5630
|
+
const hashes = buildRecordedSessionReplayProofHashes(resolvedRoot, manifest);
|
|
5631
|
+
writeFileSync(path.join(resolvedRoot, manifest.files.hashes), canonicalJson(hashes), "utf8");
|
|
5632
|
+
const validation = validateRecordedSessionReplayProofBundle(resolvedRoot);
|
|
5633
|
+
if (!validation.ok) {
|
|
5634
|
+
throw new Error(`recorded session replay proof bundle is invalid: ${validation.errors.join("; ")}`);
|
|
5635
|
+
}
|
|
5636
|
+
return loadRecordedSessionReplayProofBundle(resolvedRoot);
|
|
5637
|
+
}
|
|
4778
5638
|
export const OPERATOR_API_CONTRACT_ID = "openclaw_operator_api.v1";
|
|
4779
5639
|
export const SUPPORTED_OPERATOR_API_FAMILIES = [
|
|
4780
5640
|
"bootstrap_attach",
|
|
@@ -5737,7 +6597,128 @@ function summarizeTeacherLoopWatchState(input) {
|
|
|
5737
6597
|
snapshotUpdatedAt: input.watchSnapshot.updatedAt,
|
|
5738
6598
|
lastWatchHeartbeatAt,
|
|
5739
6599
|
pollIntervalSeconds,
|
|
5740
|
-
|
|
6600
|
+
watchState: Number.isFinite(lagMs) && lagMs >= 0 && lagMs <= staleAfterMs ? "watching" : "stale_snapshot"
|
|
6601
|
+
};
|
|
6602
|
+
}
|
|
6603
|
+
function emptyOperatorLearningAttribution(source, snapshotKind, detail) {
|
|
6604
|
+
return {
|
|
6605
|
+
available: false,
|
|
6606
|
+
source,
|
|
6607
|
+
snapshotKind,
|
|
6608
|
+
quality: "unavailable",
|
|
6609
|
+
nonZeroObservationCount: 0,
|
|
6610
|
+
skippedZeroRewardCount: 0,
|
|
6611
|
+
exactMatchCount: 0,
|
|
6612
|
+
heuristicMatchCount: 0,
|
|
6613
|
+
unmatchedCount: 0,
|
|
6614
|
+
ambiguousCount: 0,
|
|
6615
|
+
matchedByMode: {
|
|
6616
|
+
exactDecisionId: 0,
|
|
6617
|
+
exactSelectionDigest: 0,
|
|
6618
|
+
turnCompileEventId: 0,
|
|
6619
|
+
legacyHeuristic: 0
|
|
6620
|
+
},
|
|
6621
|
+
unmatchedByMode: {
|
|
6622
|
+
exactDecisionId: 0,
|
|
6623
|
+
exactSelectionDigest: 0,
|
|
6624
|
+
turnCompileEventId: 0,
|
|
6625
|
+
legacyHeuristic: 0
|
|
6626
|
+
},
|
|
6627
|
+
ambiguousByMode: {
|
|
6628
|
+
exactDecisionId: 0,
|
|
6629
|
+
exactSelectionDigest: 0,
|
|
6630
|
+
turnCompileEventId: 0,
|
|
6631
|
+
legacyHeuristic: 0
|
|
6632
|
+
},
|
|
6633
|
+
detail
|
|
6634
|
+
};
|
|
6635
|
+
}
|
|
6636
|
+
function sumObservationBindingModes(counts) {
|
|
6637
|
+
return (counts.exactDecisionId ?? 0)
|
|
6638
|
+
+ (counts.exactSelectionDigest ?? 0)
|
|
6639
|
+
+ (counts.turnCompileEventId ?? 0)
|
|
6640
|
+
+ (counts.legacyHeuristic ?? 0);
|
|
6641
|
+
}
|
|
6642
|
+
function deriveObservationBindingQuality(summary) {
|
|
6643
|
+
if (summary.nonZeroObservationCount === 0) {
|
|
6644
|
+
return "no_nonzero_observations";
|
|
6645
|
+
}
|
|
6646
|
+
if (summary.ambiguousCount > 0) {
|
|
6647
|
+
if (summary.exactMatchCount > 0) {
|
|
6648
|
+
return "exact_with_ambiguous";
|
|
6649
|
+
}
|
|
6650
|
+
if (summary.heuristicMatchCount > 0) {
|
|
6651
|
+
return "heuristic_with_ambiguous";
|
|
6652
|
+
}
|
|
6653
|
+
return "ambiguous_present";
|
|
6654
|
+
}
|
|
6655
|
+
if (summary.unmatchedCount > 0) {
|
|
6656
|
+
if (summary.exactMatchCount > 0) {
|
|
6657
|
+
return "exact_with_unmatched";
|
|
6658
|
+
}
|
|
6659
|
+
if (summary.heuristicMatchCount > 0) {
|
|
6660
|
+
return "heuristic_with_unmatched";
|
|
6661
|
+
}
|
|
6662
|
+
return "unmatched_present";
|
|
6663
|
+
}
|
|
6664
|
+
if (summary.exactMatchCount > 0 && summary.heuristicMatchCount > 0) {
|
|
6665
|
+
return "exact_plus_heuristic";
|
|
6666
|
+
}
|
|
6667
|
+
if (summary.exactMatchCount > 0) {
|
|
6668
|
+
return "exact_only";
|
|
6669
|
+
}
|
|
6670
|
+
if (summary.heuristicMatchCount > 0) {
|
|
6671
|
+
return "heuristic_only";
|
|
6672
|
+
}
|
|
6673
|
+
return "no_matches";
|
|
6674
|
+
}
|
|
6675
|
+
function summarizeTeacherLoopObservationBinding(snapshot, sourceKind) {
|
|
6676
|
+
const stats = snapshot.learner.lastMaterialization?.candidate.routingBuild?.observationBindingStats ?? null;
|
|
6677
|
+
if (stats === null) {
|
|
6678
|
+
return emptyOperatorLearningAttribution("latest_materialization", sourceKind, snapshot.learner.lastMaterialization === null
|
|
6679
|
+
? "no materialized candidate pack is visible in the teacher snapshot"
|
|
6680
|
+
: "latest materialization did not expose observation binding stats");
|
|
6681
|
+
}
|
|
6682
|
+
const exactMatchCount = (stats.matched.exactDecisionId ?? 0)
|
|
6683
|
+
+ (stats.matched.exactSelectionDigest ?? 0)
|
|
6684
|
+
+ (stats.matched.turnCompileEventId ?? 0);
|
|
6685
|
+
const heuristicMatchCount = stats.matched.legacyHeuristic ?? 0;
|
|
6686
|
+
const unmatchedCount = sumObservationBindingModes(stats.unmatched);
|
|
6687
|
+
const ambiguousCount = sumObservationBindingModes(stats.ambiguous);
|
|
6688
|
+
const summary = {
|
|
6689
|
+
available: true,
|
|
6690
|
+
source: "latest_materialization",
|
|
6691
|
+
snapshotKind: sourceKind,
|
|
6692
|
+
quality: "unavailable",
|
|
6693
|
+
nonZeroObservationCount: stats.nonZeroObservationCount ?? 0,
|
|
6694
|
+
skippedZeroRewardCount: stats.skippedZeroRewardCount ?? 0,
|
|
6695
|
+
exactMatchCount,
|
|
6696
|
+
heuristicMatchCount,
|
|
6697
|
+
unmatchedCount,
|
|
6698
|
+
ambiguousCount,
|
|
6699
|
+
matchedByMode: {
|
|
6700
|
+
exactDecisionId: stats.matched.exactDecisionId ?? 0,
|
|
6701
|
+
exactSelectionDigest: stats.matched.exactSelectionDigest ?? 0,
|
|
6702
|
+
turnCompileEventId: stats.matched.turnCompileEventId ?? 0,
|
|
6703
|
+
legacyHeuristic: stats.matched.legacyHeuristic ?? 0
|
|
6704
|
+
},
|
|
6705
|
+
unmatchedByMode: {
|
|
6706
|
+
exactDecisionId: stats.unmatched.exactDecisionId ?? 0,
|
|
6707
|
+
exactSelectionDigest: stats.unmatched.exactSelectionDigest ?? 0,
|
|
6708
|
+
turnCompileEventId: stats.unmatched.turnCompileEventId ?? 0,
|
|
6709
|
+
legacyHeuristic: stats.unmatched.legacyHeuristic ?? 0
|
|
6710
|
+
},
|
|
6711
|
+
ambiguousByMode: {
|
|
6712
|
+
exactDecisionId: stats.ambiguous.exactDecisionId ?? 0,
|
|
6713
|
+
exactSelectionDigest: stats.ambiguous.exactSelectionDigest ?? 0,
|
|
6714
|
+
turnCompileEventId: stats.ambiguous.turnCompileEventId ?? 0,
|
|
6715
|
+
legacyHeuristic: stats.ambiguous.legacyHeuristic ?? 0
|
|
6716
|
+
},
|
|
6717
|
+
detail: "teacher observation binding stats came from the latest materialized candidate"
|
|
6718
|
+
};
|
|
6719
|
+
return {
|
|
6720
|
+
...summary,
|
|
6721
|
+
quality: deriveObservationBindingQuality(summary)
|
|
5741
6722
|
};
|
|
5742
6723
|
}
|
|
5743
6724
|
function summarizeTeacherLoop(input) {
|
|
@@ -5779,6 +6760,7 @@ function summarizeTeacherLoop(input) {
|
|
|
5779
6760
|
failureDetail: null,
|
|
5780
6761
|
lastAppliedMaterializationJobId: null,
|
|
5781
6762
|
lastMaterializedPackId: null,
|
|
6763
|
+
observationBinding: emptyOperatorLearningAttribution("unavailable", "missing", "no teacher snapshot path supplied"),
|
|
5782
6764
|
lastObservedDelta: unavailableFromMissing,
|
|
5783
6765
|
notes: [],
|
|
5784
6766
|
detail: "no teacher snapshot path supplied"
|
|
@@ -5818,6 +6800,7 @@ function summarizeTeacherLoop(input) {
|
|
|
5818
6800
|
failureDetail: null,
|
|
5819
6801
|
lastAppliedMaterializationJobId: null,
|
|
5820
6802
|
lastMaterializedPackId: null,
|
|
6803
|
+
observationBinding: emptyOperatorLearningAttribution("unavailable", "missing", "teacher snapshot could not be loaded"),
|
|
5821
6804
|
lastObservedDelta: unavailableFromMissing,
|
|
5822
6805
|
notes: [],
|
|
5823
6806
|
detail: "teacher snapshot could not be loaded"
|
|
@@ -5866,6 +6849,7 @@ function summarizeTeacherLoop(input) {
|
|
|
5866
6849
|
snapshot.learner.lastMaterialization?.jobId ??
|
|
5867
6850
|
null,
|
|
5868
6851
|
lastMaterializedPackId: snapshot.learner.lastMaterialization?.candidate.summary.packId ?? null,
|
|
6852
|
+
observationBinding: summarizeTeacherLoopObservationBinding(snapshot, loaded.sourceKind),
|
|
5869
6853
|
lastObservedDelta: loaded.sourceKind === "watch_snapshot" && watchSnapshot !== null
|
|
5870
6854
|
? cloneLastObservedDelta(watchSnapshot.lastObservedDelta)
|
|
5871
6855
|
: unavailableFromAsync,
|
|
@@ -5994,7 +6978,7 @@ function summarizeLearningWarningStates(input) {
|
|
|
5994
6978
|
input.teacherSnapshot.queue.depth >= input.teacherSnapshot.queue.capacity) {
|
|
5995
6979
|
warnings.add("teacher_queue_full");
|
|
5996
6980
|
}
|
|
5997
|
-
if (input.teacherSnapshot.diagnostics.latestFreshness === "stale") {
|
|
6981
|
+
if (input.teacherSnapshot.diagnostics.latestFreshness === "stale" && input.teacherSnapshot.diagnostics.lastNoOpReason !== "no_teacher_artifacts") {
|
|
5998
6982
|
warnings.add("teacher_labels_stale");
|
|
5999
6983
|
}
|
|
6000
6984
|
if (input.teacherSnapshot.diagnostics.lastNoOpReason === "no_teacher_artifacts") {
|
|
@@ -6619,6 +7603,10 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
|
|
|
6619
7603
|
installState: report.hook.installState,
|
|
6620
7604
|
loadability: report.hook.loadability,
|
|
6621
7605
|
loadProof: report.hook.loadProof,
|
|
7606
|
+
guardSeverity: report.hook.guardSeverity,
|
|
7607
|
+
guardActionability: report.hook.guardActionability,
|
|
7608
|
+
guardSummary: report.hook.guardSummary,
|
|
7609
|
+
guardAction: report.hook.guardAction,
|
|
6622
7610
|
desynced: report.hook.desynced,
|
|
6623
7611
|
detail: report.hook.detail
|
|
6624
7612
|
},
|
|
@@ -6665,7 +7653,10 @@ function buildCurrentProfileBrainStatusFromReport(report, policyMode, profileId)
|
|
|
6665
7653
|
? "current profile would fail open to static context because no serving pack is available"
|
|
6666
7654
|
: report.servePath.state === "hard_fail"
|
|
6667
7655
|
? "current profile cannot serve because the learned-route or activation requirement hard-failed"
|
|
6668
|
-
|
|
7656
|
+
: "current profile serve state has not been compile-probed yet"
|
|
7657
|
+
},
|
|
7658
|
+
learningAttribution: {
|
|
7659
|
+
...report.teacherLoop.observationBinding
|
|
6669
7660
|
},
|
|
6670
7661
|
passiveLearning,
|
|
6671
7662
|
currentTurnAttribution: buildCurrentProfileTurnAttributionFromReport(report, policyMode, profileId)
|