@replayci/replay 0.1.12 → 0.1.14
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/index.cjs +87 -16
- package/dist/index.js +87 -16
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2578,6 +2578,22 @@ function evaluatePrecondition(precondition, sessionState, currentArguments) {
|
|
|
2578
2578
|
detail: `Prior tool output assertion failed: ${assertion.path} \u2014 expected ${JSON.stringify(assertion.equals)}, got ${JSON.stringify(value)}`
|
|
2579
2579
|
};
|
|
2580
2580
|
}
|
|
2581
|
+
if (assertion.gte !== void 0) {
|
|
2582
|
+
if (typeof value !== "number" || value < assertion.gte) {
|
|
2583
|
+
return {
|
|
2584
|
+
satisfied: false,
|
|
2585
|
+
detail: `Prior tool output assertion failed: ${assertion.path} \u2014 expected >= ${assertion.gte}, got ${JSON.stringify(value)}`
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
if (assertion.lte !== void 0) {
|
|
2590
|
+
if (typeof value !== "number" || value > assertion.lte) {
|
|
2591
|
+
return {
|
|
2592
|
+
satisfied: false,
|
|
2593
|
+
detail: `Prior tool output assertion failed: ${assertion.path} \u2014 expected <= ${assertion.lte}, got ${JSON.stringify(value)}`
|
|
2594
|
+
};
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2581
2597
|
}
|
|
2582
2598
|
}
|
|
2583
2599
|
}
|
|
@@ -3762,7 +3778,7 @@ function createInitialState(sessionId, options) {
|
|
|
3762
3778
|
checkpointCount: 0
|
|
3763
3779
|
};
|
|
3764
3780
|
}
|
|
3765
|
-
function finalizeExecutedStep(state, step, contracts, compiledSession) {
|
|
3781
|
+
function finalizeExecutedStep(state, step, contracts, compiledSession, options) {
|
|
3766
3782
|
const newSteps = [...state.steps, step];
|
|
3767
3783
|
const newToolCallCounts = updateToolCallCounts(state.toolCallCounts, step);
|
|
3768
3784
|
const resolvedContracts = compiledSession ? Array.from(compiledSession.perToolContracts.values()) : contracts;
|
|
@@ -3772,7 +3788,7 @@ function finalizeExecutedStep(state, step, contracts, compiledSession) {
|
|
|
3772
3788
|
step
|
|
3773
3789
|
);
|
|
3774
3790
|
const costDelta = computeStepCost(step);
|
|
3775
|
-
const newPhase = compiledSession ? recomputePhaseFromCommitted(step.toolCalls, state, compiledSession) : state.currentPhase;
|
|
3791
|
+
const newPhase = options?.deferPhase ? state.currentPhase : compiledSession ? recomputePhaseFromCommitted(step.toolCalls, state, compiledSession) : state.currentPhase;
|
|
3776
3792
|
return {
|
|
3777
3793
|
...state,
|
|
3778
3794
|
steps: newSteps,
|
|
@@ -4081,26 +4097,27 @@ function matchesTool(toolName, filter) {
|
|
|
4081
4097
|
if (typeof filter === "string") return filter === toolName;
|
|
4082
4098
|
return filter.includes(toolName);
|
|
4083
4099
|
}
|
|
4084
|
-
function speculativeCheck(toolName, parsedArgs, aggregates, definitions) {
|
|
4100
|
+
function speculativeCheck(toolName, parsedArgs, aggregates, definitions, bindings) {
|
|
4085
4101
|
const failures = [];
|
|
4086
4102
|
for (const def of definitions) {
|
|
4087
4103
|
if (!matchesTool(toolName, def.tool)) continue;
|
|
4088
4104
|
const current = aggregates.get(def.name);
|
|
4089
4105
|
if (!current) continue;
|
|
4106
|
+
const resolved = resolveBounds(def, bindings);
|
|
4090
4107
|
const currentValue = current.currentValue;
|
|
4091
4108
|
if (def.metric === "count") {
|
|
4092
4109
|
const speculative2 = currentValue + 1;
|
|
4093
|
-
if (
|
|
4110
|
+
if (resolved.lte !== void 0 && speculative2 > resolved.lte) {
|
|
4094
4111
|
failures.push({
|
|
4095
4112
|
aggregate: def.name,
|
|
4096
4113
|
reason: "aggregate_limit_exceeded",
|
|
4097
|
-
detail: `${def.reason} (count ${speculative2} > lte ${
|
|
4114
|
+
detail: `${def.reason} (count ${speculative2} > lte ${resolved.lte})`,
|
|
4098
4115
|
current: currentValue,
|
|
4099
4116
|
speculative: speculative2,
|
|
4100
|
-
bound: { lte:
|
|
4117
|
+
bound: { lte: resolved.lte }
|
|
4101
4118
|
});
|
|
4102
4119
|
}
|
|
4103
|
-
if (
|
|
4120
|
+
if (resolved.gte !== void 0 && speculative2 < resolved.gte) {
|
|
4104
4121
|
}
|
|
4105
4122
|
continue;
|
|
4106
4123
|
}
|
|
@@ -4182,21 +4199,21 @@ function speculativeCheck(toolName, parsedArgs, aggregates, definitions) {
|
|
|
4182
4199
|
default:
|
|
4183
4200
|
continue;
|
|
4184
4201
|
}
|
|
4185
|
-
if (
|
|
4202
|
+
if (resolved.lte !== void 0 && speculative > resolved.lte) {
|
|
4186
4203
|
failures.push({
|
|
4187
4204
|
aggregate: def.name,
|
|
4188
4205
|
reason: "aggregate_limit_exceeded",
|
|
4189
|
-
detail: `${def.reason} (${def.metric} ${speculative} > lte ${
|
|
4206
|
+
detail: `${def.reason} (${def.metric} ${speculative} > lte ${resolved.lte})`,
|
|
4190
4207
|
current: currentValue,
|
|
4191
4208
|
speculative,
|
|
4192
|
-
bound: { lte:
|
|
4209
|
+
bound: { lte: resolved.lte }
|
|
4193
4210
|
});
|
|
4194
4211
|
}
|
|
4195
|
-
if (
|
|
4212
|
+
if (resolved.gte !== void 0 && speculative < resolved.gte) {
|
|
4196
4213
|
failures.push({
|
|
4197
4214
|
aggregate: def.name,
|
|
4198
4215
|
reason: "aggregate_limit_exceeded",
|
|
4199
|
-
detail: `${def.reason} (${def.metric} ${speculative} < gte ${
|
|
4216
|
+
detail: `${def.reason} (${def.metric} ${speculative} < gte ${resolved.gte})`,
|
|
4200
4217
|
current: currentValue,
|
|
4201
4218
|
speculative,
|
|
4202
4219
|
bound: { gte: def.gte }
|
|
@@ -4248,6 +4265,34 @@ function commitAggregate(toolName, parsedArgs, aggregates, definitions) {
|
|
|
4248
4265
|
}
|
|
4249
4266
|
return updated;
|
|
4250
4267
|
}
|
|
4268
|
+
function resolveBounds(def, bindings) {
|
|
4269
|
+
if (!def.when || def.when.length === 0 || !bindings) {
|
|
4270
|
+
return { gte: def.gte, lte: def.lte };
|
|
4271
|
+
}
|
|
4272
|
+
for (const cond of def.when) {
|
|
4273
|
+
const bound = bindings.get(cond.binding);
|
|
4274
|
+
if (!bound) continue;
|
|
4275
|
+
const val = bound.value;
|
|
4276
|
+
if (!matchesCondition(val, cond)) continue;
|
|
4277
|
+
return {
|
|
4278
|
+
gte: cond.then_gte ?? def.gte,
|
|
4279
|
+
lte: cond.then_lte ?? def.lte
|
|
4280
|
+
};
|
|
4281
|
+
}
|
|
4282
|
+
return { gte: def.gte, lte: def.lte };
|
|
4283
|
+
}
|
|
4284
|
+
function matchesCondition(value, cond) {
|
|
4285
|
+
if (cond.equals !== void 0) {
|
|
4286
|
+
if (JSON.stringify(value) !== JSON.stringify(cond.equals)) return false;
|
|
4287
|
+
}
|
|
4288
|
+
if (cond.gte !== void 0) {
|
|
4289
|
+
if (typeof value !== "number" || value < cond.gte) return false;
|
|
4290
|
+
}
|
|
4291
|
+
if (cond.lte !== void 0) {
|
|
4292
|
+
if (typeof value !== "number" || value > cond.lte) return false;
|
|
4293
|
+
}
|
|
4294
|
+
return true;
|
|
4295
|
+
}
|
|
4251
4296
|
|
|
4252
4297
|
// src/envelopes.ts
|
|
4253
4298
|
function initializeEnvelopes(definitions) {
|
|
@@ -5614,6 +5659,7 @@ function replay(client, opts = {}) {
|
|
|
5614
5659
|
let shadowEvaluationCount = 0;
|
|
5615
5660
|
let manualFilter = null;
|
|
5616
5661
|
const deferredReceipts = /* @__PURE__ */ new Map();
|
|
5662
|
+
let deferredPhase = null;
|
|
5617
5663
|
const contractLimits = resolveSessionLimits(contracts);
|
|
5618
5664
|
const compiledLimits = compiledSession?.sessionLimits;
|
|
5619
5665
|
const mergedLimits = { ...contractLimits ?? {}, ...compiledLimits ?? {} };
|
|
@@ -5750,6 +5796,7 @@ function replay(client, opts = {}) {
|
|
|
5750
5796
|
total_ms: 0,
|
|
5751
5797
|
enforcement_ms: 0
|
|
5752
5798
|
};
|
|
5799
|
+
deferredPhase = null;
|
|
5753
5800
|
const trace = createTrace(sessionState.totalStepCount);
|
|
5754
5801
|
const traceCtx = { trace };
|
|
5755
5802
|
let currentTraceStage = "narrow";
|
|
@@ -6221,7 +6268,7 @@ function replay(client, opts = {}) {
|
|
|
6221
6268
|
} catch {
|
|
6222
6269
|
parsedArgs = {};
|
|
6223
6270
|
}
|
|
6224
|
-
const aggResult = speculativeCheck(tc.name, parsedArgs, workingAggregates, compiledSession.aggregates);
|
|
6271
|
+
const aggResult = speculativeCheck(tc.name, parsedArgs, workingAggregates, compiledSession.aggregates, sessionState.bindings);
|
|
6225
6272
|
if (!aggResult.passed) {
|
|
6226
6273
|
for (const f of aggResult.failures) {
|
|
6227
6274
|
trace.push({
|
|
@@ -6664,11 +6711,31 @@ function replay(client, opts = {}) {
|
|
|
6664
6711
|
}
|
|
6665
6712
|
}
|
|
6666
6713
|
}
|
|
6714
|
+
const hasPhaseTransition = phaseResult?.legal && phaseResult.newPhase !== sessionState.currentPhase;
|
|
6715
|
+
const shouldDeferPhase = isActiveGovern && !attemptDegraded && hasPhaseTransition;
|
|
6667
6716
|
const prevVersionAllow = sessionState.stateVersion;
|
|
6668
|
-
sessionState = finalizeExecutedStep(
|
|
6717
|
+
sessionState = finalizeExecutedStep(
|
|
6718
|
+
sessionState,
|
|
6719
|
+
completedStep,
|
|
6720
|
+
contracts,
|
|
6721
|
+
compiledSession,
|
|
6722
|
+
shouldDeferPhase ? { deferPhase: true } : void 0
|
|
6723
|
+
);
|
|
6669
6724
|
sessionState = recordDecisionOutcome(sessionState, "allowed");
|
|
6670
6725
|
syncStateToStore(prevVersionAllow, sessionState);
|
|
6671
6726
|
timing.finalize_ms += Date.now() - enforceFinalizeStart;
|
|
6727
|
+
if (shouldDeferPhase && compiledSession) {
|
|
6728
|
+
const advancingTools = /* @__PURE__ */ new Set();
|
|
6729
|
+
for (const tc of toolCalls) {
|
|
6730
|
+
const contract = compiledSession.perToolContracts.get(tc.name);
|
|
6731
|
+
if (contract?.transitions?.advances_to === phaseResult.newPhase) {
|
|
6732
|
+
advancingTools.add(tc.name);
|
|
6733
|
+
}
|
|
6734
|
+
}
|
|
6735
|
+
if (advancingTools.size > 0 && phaseResult.newPhase != null) {
|
|
6736
|
+
deferredPhase = { newPhase: phaseResult.newPhase, toolNames: advancingTools };
|
|
6737
|
+
}
|
|
6738
|
+
}
|
|
6672
6739
|
if (isActiveGovern && !attemptDegraded && attemptPendingCalls && attemptPendingCalls.size > 0) {
|
|
6673
6740
|
for (const [toolCallId, pending] of attemptPendingCalls) {
|
|
6674
6741
|
deferredReceipts.set(toolCallId, {
|
|
@@ -6686,8 +6753,8 @@ function replay(client, opts = {}) {
|
|
|
6686
6753
|
checked: { gate_mode: gateMode },
|
|
6687
6754
|
found: { blocked_count: 0, action: "allow" }
|
|
6688
6755
|
});
|
|
6689
|
-
const allowNewPhase = phaseResult && phaseResult.legal && phaseResult.newPhase !== sessionState.currentPhase ? phaseResult.newPhase : sessionState.currentPhase;
|
|
6690
|
-
trace.push({ stage: "finalize", tool: null, verdict: "info", reason: "cycle_complete", checked: {}, found: { state_version: sessionState.stateVersion, phase_before: completedStep.phase, phase_after: allowNewPhase, tools_committed: toolCalls.map((tc) => tc.name), tools_blocked: [], killed: false, step_index: sessionState.totalStepCount } });
|
|
6756
|
+
const allowNewPhase = phaseResult && phaseResult.legal && phaseResult.newPhase !== (completedStep.phase ?? sessionState.currentPhase) ? phaseResult.newPhase : sessionState.currentPhase;
|
|
6757
|
+
trace.push({ stage: "finalize", tool: null, verdict: "info", reason: "cycle_complete", checked: {}, found: { state_version: sessionState.stateVersion, phase_before: completedStep.phase, phase_after: allowNewPhase, ...shouldDeferPhase ? { phase_deferred: true } : {}, tools_committed: toolCalls.map((tc) => tc.name), tools_blocked: [], killed: false, step_index: sessionState.totalStepCount } });
|
|
6691
6758
|
trace.complete = true;
|
|
6692
6759
|
lastTrace = trace;
|
|
6693
6760
|
emitDiagnostic2(diagnostics, { type: "replay_trace", session_id: sessionId, trace });
|
|
@@ -7034,6 +7101,10 @@ function replay(client, opts = {}) {
|
|
|
7034
7101
|
throw new ReplayKillError(sessionId, killedAt);
|
|
7035
7102
|
}
|
|
7036
7103
|
const result = await executor(args);
|
|
7104
|
+
if (deferredPhase && deferredPhase.toolNames.has(toolName)) {
|
|
7105
|
+
sessionState = { ...sessionState, currentPhase: deferredPhase.newPhase };
|
|
7106
|
+
deferredPhase = null;
|
|
7107
|
+
}
|
|
7037
7108
|
if (runtimeClient && leaseFence && !runtimeDegraded) {
|
|
7038
7109
|
for (const [callId, deferred] of deferredReceipts) {
|
|
7039
7110
|
if (deferred.toolName === toolName) {
|
package/dist/index.js
CHANGED
|
@@ -2558,6 +2558,22 @@ function evaluatePrecondition(precondition, sessionState, currentArguments) {
|
|
|
2558
2558
|
detail: `Prior tool output assertion failed: ${assertion.path} \u2014 expected ${JSON.stringify(assertion.equals)}, got ${JSON.stringify(value)}`
|
|
2559
2559
|
};
|
|
2560
2560
|
}
|
|
2561
|
+
if (assertion.gte !== void 0) {
|
|
2562
|
+
if (typeof value !== "number" || value < assertion.gte) {
|
|
2563
|
+
return {
|
|
2564
|
+
satisfied: false,
|
|
2565
|
+
detail: `Prior tool output assertion failed: ${assertion.path} \u2014 expected >= ${assertion.gte}, got ${JSON.stringify(value)}`
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
if (assertion.lte !== void 0) {
|
|
2570
|
+
if (typeof value !== "number" || value > assertion.lte) {
|
|
2571
|
+
return {
|
|
2572
|
+
satisfied: false,
|
|
2573
|
+
detail: `Prior tool output assertion failed: ${assertion.path} \u2014 expected <= ${assertion.lte}, got ${JSON.stringify(value)}`
|
|
2574
|
+
};
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2561
2577
|
}
|
|
2562
2578
|
}
|
|
2563
2579
|
}
|
|
@@ -3751,7 +3767,7 @@ function createInitialState(sessionId, options) {
|
|
|
3751
3767
|
checkpointCount: 0
|
|
3752
3768
|
};
|
|
3753
3769
|
}
|
|
3754
|
-
function finalizeExecutedStep(state, step, contracts, compiledSession) {
|
|
3770
|
+
function finalizeExecutedStep(state, step, contracts, compiledSession, options) {
|
|
3755
3771
|
const newSteps = [...state.steps, step];
|
|
3756
3772
|
const newToolCallCounts = updateToolCallCounts(state.toolCallCounts, step);
|
|
3757
3773
|
const resolvedContracts = compiledSession ? Array.from(compiledSession.perToolContracts.values()) : contracts;
|
|
@@ -3761,7 +3777,7 @@ function finalizeExecutedStep(state, step, contracts, compiledSession) {
|
|
|
3761
3777
|
step
|
|
3762
3778
|
);
|
|
3763
3779
|
const costDelta = computeStepCost(step);
|
|
3764
|
-
const newPhase = compiledSession ? recomputePhaseFromCommitted(step.toolCalls, state, compiledSession) : state.currentPhase;
|
|
3780
|
+
const newPhase = options?.deferPhase ? state.currentPhase : compiledSession ? recomputePhaseFromCommitted(step.toolCalls, state, compiledSession) : state.currentPhase;
|
|
3765
3781
|
return {
|
|
3766
3782
|
...state,
|
|
3767
3783
|
steps: newSteps,
|
|
@@ -4070,26 +4086,27 @@ function matchesTool(toolName, filter) {
|
|
|
4070
4086
|
if (typeof filter === "string") return filter === toolName;
|
|
4071
4087
|
return filter.includes(toolName);
|
|
4072
4088
|
}
|
|
4073
|
-
function speculativeCheck(toolName, parsedArgs, aggregates, definitions) {
|
|
4089
|
+
function speculativeCheck(toolName, parsedArgs, aggregates, definitions, bindings) {
|
|
4074
4090
|
const failures = [];
|
|
4075
4091
|
for (const def of definitions) {
|
|
4076
4092
|
if (!matchesTool(toolName, def.tool)) continue;
|
|
4077
4093
|
const current = aggregates.get(def.name);
|
|
4078
4094
|
if (!current) continue;
|
|
4095
|
+
const resolved = resolveBounds(def, bindings);
|
|
4079
4096
|
const currentValue = current.currentValue;
|
|
4080
4097
|
if (def.metric === "count") {
|
|
4081
4098
|
const speculative2 = currentValue + 1;
|
|
4082
|
-
if (
|
|
4099
|
+
if (resolved.lte !== void 0 && speculative2 > resolved.lte) {
|
|
4083
4100
|
failures.push({
|
|
4084
4101
|
aggregate: def.name,
|
|
4085
4102
|
reason: "aggregate_limit_exceeded",
|
|
4086
|
-
detail: `${def.reason} (count ${speculative2} > lte ${
|
|
4103
|
+
detail: `${def.reason} (count ${speculative2} > lte ${resolved.lte})`,
|
|
4087
4104
|
current: currentValue,
|
|
4088
4105
|
speculative: speculative2,
|
|
4089
|
-
bound: { lte:
|
|
4106
|
+
bound: { lte: resolved.lte }
|
|
4090
4107
|
});
|
|
4091
4108
|
}
|
|
4092
|
-
if (
|
|
4109
|
+
if (resolved.gte !== void 0 && speculative2 < resolved.gte) {
|
|
4093
4110
|
}
|
|
4094
4111
|
continue;
|
|
4095
4112
|
}
|
|
@@ -4171,21 +4188,21 @@ function speculativeCheck(toolName, parsedArgs, aggregates, definitions) {
|
|
|
4171
4188
|
default:
|
|
4172
4189
|
continue;
|
|
4173
4190
|
}
|
|
4174
|
-
if (
|
|
4191
|
+
if (resolved.lte !== void 0 && speculative > resolved.lte) {
|
|
4175
4192
|
failures.push({
|
|
4176
4193
|
aggregate: def.name,
|
|
4177
4194
|
reason: "aggregate_limit_exceeded",
|
|
4178
|
-
detail: `${def.reason} (${def.metric} ${speculative} > lte ${
|
|
4195
|
+
detail: `${def.reason} (${def.metric} ${speculative} > lte ${resolved.lte})`,
|
|
4179
4196
|
current: currentValue,
|
|
4180
4197
|
speculative,
|
|
4181
|
-
bound: { lte:
|
|
4198
|
+
bound: { lte: resolved.lte }
|
|
4182
4199
|
});
|
|
4183
4200
|
}
|
|
4184
|
-
if (
|
|
4201
|
+
if (resolved.gte !== void 0 && speculative < resolved.gte) {
|
|
4185
4202
|
failures.push({
|
|
4186
4203
|
aggregate: def.name,
|
|
4187
4204
|
reason: "aggregate_limit_exceeded",
|
|
4188
|
-
detail: `${def.reason} (${def.metric} ${speculative} < gte ${
|
|
4205
|
+
detail: `${def.reason} (${def.metric} ${speculative} < gte ${resolved.gte})`,
|
|
4189
4206
|
current: currentValue,
|
|
4190
4207
|
speculative,
|
|
4191
4208
|
bound: { gte: def.gte }
|
|
@@ -4237,6 +4254,34 @@ function commitAggregate(toolName, parsedArgs, aggregates, definitions) {
|
|
|
4237
4254
|
}
|
|
4238
4255
|
return updated;
|
|
4239
4256
|
}
|
|
4257
|
+
function resolveBounds(def, bindings) {
|
|
4258
|
+
if (!def.when || def.when.length === 0 || !bindings) {
|
|
4259
|
+
return { gte: def.gte, lte: def.lte };
|
|
4260
|
+
}
|
|
4261
|
+
for (const cond of def.when) {
|
|
4262
|
+
const bound = bindings.get(cond.binding);
|
|
4263
|
+
if (!bound) continue;
|
|
4264
|
+
const val = bound.value;
|
|
4265
|
+
if (!matchesCondition(val, cond)) continue;
|
|
4266
|
+
return {
|
|
4267
|
+
gte: cond.then_gte ?? def.gte,
|
|
4268
|
+
lte: cond.then_lte ?? def.lte
|
|
4269
|
+
};
|
|
4270
|
+
}
|
|
4271
|
+
return { gte: def.gte, lte: def.lte };
|
|
4272
|
+
}
|
|
4273
|
+
function matchesCondition(value, cond) {
|
|
4274
|
+
if (cond.equals !== void 0) {
|
|
4275
|
+
if (JSON.stringify(value) !== JSON.stringify(cond.equals)) return false;
|
|
4276
|
+
}
|
|
4277
|
+
if (cond.gte !== void 0) {
|
|
4278
|
+
if (typeof value !== "number" || value < cond.gte) return false;
|
|
4279
|
+
}
|
|
4280
|
+
if (cond.lte !== void 0) {
|
|
4281
|
+
if (typeof value !== "number" || value > cond.lte) return false;
|
|
4282
|
+
}
|
|
4283
|
+
return true;
|
|
4284
|
+
}
|
|
4240
4285
|
|
|
4241
4286
|
// src/envelopes.ts
|
|
4242
4287
|
function initializeEnvelopes(definitions) {
|
|
@@ -5605,6 +5650,7 @@ function replay(client, opts = {}) {
|
|
|
5605
5650
|
let shadowEvaluationCount = 0;
|
|
5606
5651
|
let manualFilter = null;
|
|
5607
5652
|
const deferredReceipts = /* @__PURE__ */ new Map();
|
|
5653
|
+
let deferredPhase = null;
|
|
5608
5654
|
const contractLimits = resolveSessionLimits(contracts);
|
|
5609
5655
|
const compiledLimits = compiledSession?.sessionLimits;
|
|
5610
5656
|
const mergedLimits = { ...contractLimits ?? {}, ...compiledLimits ?? {} };
|
|
@@ -5741,6 +5787,7 @@ function replay(client, opts = {}) {
|
|
|
5741
5787
|
total_ms: 0,
|
|
5742
5788
|
enforcement_ms: 0
|
|
5743
5789
|
};
|
|
5790
|
+
deferredPhase = null;
|
|
5744
5791
|
const trace = createTrace(sessionState.totalStepCount);
|
|
5745
5792
|
const traceCtx = { trace };
|
|
5746
5793
|
let currentTraceStage = "narrow";
|
|
@@ -6212,7 +6259,7 @@ function replay(client, opts = {}) {
|
|
|
6212
6259
|
} catch {
|
|
6213
6260
|
parsedArgs = {};
|
|
6214
6261
|
}
|
|
6215
|
-
const aggResult = speculativeCheck(tc.name, parsedArgs, workingAggregates, compiledSession.aggregates);
|
|
6262
|
+
const aggResult = speculativeCheck(tc.name, parsedArgs, workingAggregates, compiledSession.aggregates, sessionState.bindings);
|
|
6216
6263
|
if (!aggResult.passed) {
|
|
6217
6264
|
for (const f of aggResult.failures) {
|
|
6218
6265
|
trace.push({
|
|
@@ -6655,11 +6702,31 @@ function replay(client, opts = {}) {
|
|
|
6655
6702
|
}
|
|
6656
6703
|
}
|
|
6657
6704
|
}
|
|
6705
|
+
const hasPhaseTransition = phaseResult?.legal && phaseResult.newPhase !== sessionState.currentPhase;
|
|
6706
|
+
const shouldDeferPhase = isActiveGovern && !attemptDegraded && hasPhaseTransition;
|
|
6658
6707
|
const prevVersionAllow = sessionState.stateVersion;
|
|
6659
|
-
sessionState = finalizeExecutedStep(
|
|
6708
|
+
sessionState = finalizeExecutedStep(
|
|
6709
|
+
sessionState,
|
|
6710
|
+
completedStep,
|
|
6711
|
+
contracts,
|
|
6712
|
+
compiledSession,
|
|
6713
|
+
shouldDeferPhase ? { deferPhase: true } : void 0
|
|
6714
|
+
);
|
|
6660
6715
|
sessionState = recordDecisionOutcome(sessionState, "allowed");
|
|
6661
6716
|
syncStateToStore(prevVersionAllow, sessionState);
|
|
6662
6717
|
timing.finalize_ms += Date.now() - enforceFinalizeStart;
|
|
6718
|
+
if (shouldDeferPhase && compiledSession) {
|
|
6719
|
+
const advancingTools = /* @__PURE__ */ new Set();
|
|
6720
|
+
for (const tc of toolCalls) {
|
|
6721
|
+
const contract = compiledSession.perToolContracts.get(tc.name);
|
|
6722
|
+
if (contract?.transitions?.advances_to === phaseResult.newPhase) {
|
|
6723
|
+
advancingTools.add(tc.name);
|
|
6724
|
+
}
|
|
6725
|
+
}
|
|
6726
|
+
if (advancingTools.size > 0 && phaseResult.newPhase != null) {
|
|
6727
|
+
deferredPhase = { newPhase: phaseResult.newPhase, toolNames: advancingTools };
|
|
6728
|
+
}
|
|
6729
|
+
}
|
|
6663
6730
|
if (isActiveGovern && !attemptDegraded && attemptPendingCalls && attemptPendingCalls.size > 0) {
|
|
6664
6731
|
for (const [toolCallId, pending] of attemptPendingCalls) {
|
|
6665
6732
|
deferredReceipts.set(toolCallId, {
|
|
@@ -6677,8 +6744,8 @@ function replay(client, opts = {}) {
|
|
|
6677
6744
|
checked: { gate_mode: gateMode },
|
|
6678
6745
|
found: { blocked_count: 0, action: "allow" }
|
|
6679
6746
|
});
|
|
6680
|
-
const allowNewPhase = phaseResult && phaseResult.legal && phaseResult.newPhase !== sessionState.currentPhase ? phaseResult.newPhase : sessionState.currentPhase;
|
|
6681
|
-
trace.push({ stage: "finalize", tool: null, verdict: "info", reason: "cycle_complete", checked: {}, found: { state_version: sessionState.stateVersion, phase_before: completedStep.phase, phase_after: allowNewPhase, tools_committed: toolCalls.map((tc) => tc.name), tools_blocked: [], killed: false, step_index: sessionState.totalStepCount } });
|
|
6747
|
+
const allowNewPhase = phaseResult && phaseResult.legal && phaseResult.newPhase !== (completedStep.phase ?? sessionState.currentPhase) ? phaseResult.newPhase : sessionState.currentPhase;
|
|
6748
|
+
trace.push({ stage: "finalize", tool: null, verdict: "info", reason: "cycle_complete", checked: {}, found: { state_version: sessionState.stateVersion, phase_before: completedStep.phase, phase_after: allowNewPhase, ...shouldDeferPhase ? { phase_deferred: true } : {}, tools_committed: toolCalls.map((tc) => tc.name), tools_blocked: [], killed: false, step_index: sessionState.totalStepCount } });
|
|
6682
6749
|
trace.complete = true;
|
|
6683
6750
|
lastTrace = trace;
|
|
6684
6751
|
emitDiagnostic2(diagnostics, { type: "replay_trace", session_id: sessionId, trace });
|
|
@@ -7025,6 +7092,10 @@ function replay(client, opts = {}) {
|
|
|
7025
7092
|
throw new ReplayKillError(sessionId, killedAt);
|
|
7026
7093
|
}
|
|
7027
7094
|
const result = await executor(args);
|
|
7095
|
+
if (deferredPhase && deferredPhase.toolNames.has(toolName)) {
|
|
7096
|
+
sessionState = { ...sessionState, currentPhase: deferredPhase.newPhase };
|
|
7097
|
+
deferredPhase = null;
|
|
7098
|
+
}
|
|
7028
7099
|
if (runtimeClient && leaseFence && !runtimeDegraded) {
|
|
7029
7100
|
for (const [callId, deferred] of deferredReceipts) {
|
|
7030
7101
|
if (deferred.toolName === toolName) {
|