@replayci/replay 0.1.13 → 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 CHANGED
@@ -3778,7 +3778,7 @@ function createInitialState(sessionId, options) {
3778
3778
  checkpointCount: 0
3779
3779
  };
3780
3780
  }
3781
- function finalizeExecutedStep(state, step, contracts, compiledSession) {
3781
+ function finalizeExecutedStep(state, step, contracts, compiledSession, options) {
3782
3782
  const newSteps = [...state.steps, step];
3783
3783
  const newToolCallCounts = updateToolCallCounts(state.toolCallCounts, step);
3784
3784
  const resolvedContracts = compiledSession ? Array.from(compiledSession.perToolContracts.values()) : contracts;
@@ -3788,7 +3788,7 @@ function finalizeExecutedStep(state, step, contracts, compiledSession) {
3788
3788
  step
3789
3789
  );
3790
3790
  const costDelta = computeStepCost(step);
3791
- 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;
3792
3792
  return {
3793
3793
  ...state,
3794
3794
  steps: newSteps,
@@ -5659,6 +5659,7 @@ function replay(client, opts = {}) {
5659
5659
  let shadowEvaluationCount = 0;
5660
5660
  let manualFilter = null;
5661
5661
  const deferredReceipts = /* @__PURE__ */ new Map();
5662
+ let deferredPhase = null;
5662
5663
  const contractLimits = resolveSessionLimits(contracts);
5663
5664
  const compiledLimits = compiledSession?.sessionLimits;
5664
5665
  const mergedLimits = { ...contractLimits ?? {}, ...compiledLimits ?? {} };
@@ -5795,6 +5796,7 @@ function replay(client, opts = {}) {
5795
5796
  total_ms: 0,
5796
5797
  enforcement_ms: 0
5797
5798
  };
5799
+ deferredPhase = null;
5798
5800
  const trace = createTrace(sessionState.totalStepCount);
5799
5801
  const traceCtx = { trace };
5800
5802
  let currentTraceStage = "narrow";
@@ -6709,11 +6711,31 @@ function replay(client, opts = {}) {
6709
6711
  }
6710
6712
  }
6711
6713
  }
6714
+ const hasPhaseTransition = phaseResult?.legal && phaseResult.newPhase !== sessionState.currentPhase;
6715
+ const shouldDeferPhase = isActiveGovern && !attemptDegraded && hasPhaseTransition;
6712
6716
  const prevVersionAllow = sessionState.stateVersion;
6713
- sessionState = finalizeExecutedStep(sessionState, completedStep, contracts, compiledSession);
6717
+ sessionState = finalizeExecutedStep(
6718
+ sessionState,
6719
+ completedStep,
6720
+ contracts,
6721
+ compiledSession,
6722
+ shouldDeferPhase ? { deferPhase: true } : void 0
6723
+ );
6714
6724
  sessionState = recordDecisionOutcome(sessionState, "allowed");
6715
6725
  syncStateToStore(prevVersionAllow, sessionState);
6716
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
+ }
6717
6739
  if (isActiveGovern && !attemptDegraded && attemptPendingCalls && attemptPendingCalls.size > 0) {
6718
6740
  for (const [toolCallId, pending] of attemptPendingCalls) {
6719
6741
  deferredReceipts.set(toolCallId, {
@@ -6731,8 +6753,8 @@ function replay(client, opts = {}) {
6731
6753
  checked: { gate_mode: gateMode },
6732
6754
  found: { blocked_count: 0, action: "allow" }
6733
6755
  });
6734
- const allowNewPhase = phaseResult && phaseResult.legal && phaseResult.newPhase !== sessionState.currentPhase ? phaseResult.newPhase : sessionState.currentPhase;
6735
- 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 } });
6736
6758
  trace.complete = true;
6737
6759
  lastTrace = trace;
6738
6760
  emitDiagnostic2(diagnostics, { type: "replay_trace", session_id: sessionId, trace });
@@ -7079,6 +7101,10 @@ function replay(client, opts = {}) {
7079
7101
  throw new ReplayKillError(sessionId, killedAt);
7080
7102
  }
7081
7103
  const result = await executor(args);
7104
+ if (deferredPhase && deferredPhase.toolNames.has(toolName)) {
7105
+ sessionState = { ...sessionState, currentPhase: deferredPhase.newPhase };
7106
+ deferredPhase = null;
7107
+ }
7082
7108
  if (runtimeClient && leaseFence && !runtimeDegraded) {
7083
7109
  for (const [callId, deferred] of deferredReceipts) {
7084
7110
  if (deferred.toolName === toolName) {
package/dist/index.js CHANGED
@@ -3767,7 +3767,7 @@ function createInitialState(sessionId, options) {
3767
3767
  checkpointCount: 0
3768
3768
  };
3769
3769
  }
3770
- function finalizeExecutedStep(state, step, contracts, compiledSession) {
3770
+ function finalizeExecutedStep(state, step, contracts, compiledSession, options) {
3771
3771
  const newSteps = [...state.steps, step];
3772
3772
  const newToolCallCounts = updateToolCallCounts(state.toolCallCounts, step);
3773
3773
  const resolvedContracts = compiledSession ? Array.from(compiledSession.perToolContracts.values()) : contracts;
@@ -3777,7 +3777,7 @@ function finalizeExecutedStep(state, step, contracts, compiledSession) {
3777
3777
  step
3778
3778
  );
3779
3779
  const costDelta = computeStepCost(step);
3780
- 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;
3781
3781
  return {
3782
3782
  ...state,
3783
3783
  steps: newSteps,
@@ -5650,6 +5650,7 @@ function replay(client, opts = {}) {
5650
5650
  let shadowEvaluationCount = 0;
5651
5651
  let manualFilter = null;
5652
5652
  const deferredReceipts = /* @__PURE__ */ new Map();
5653
+ let deferredPhase = null;
5653
5654
  const contractLimits = resolveSessionLimits(contracts);
5654
5655
  const compiledLimits = compiledSession?.sessionLimits;
5655
5656
  const mergedLimits = { ...contractLimits ?? {}, ...compiledLimits ?? {} };
@@ -5786,6 +5787,7 @@ function replay(client, opts = {}) {
5786
5787
  total_ms: 0,
5787
5788
  enforcement_ms: 0
5788
5789
  };
5790
+ deferredPhase = null;
5789
5791
  const trace = createTrace(sessionState.totalStepCount);
5790
5792
  const traceCtx = { trace };
5791
5793
  let currentTraceStage = "narrow";
@@ -6700,11 +6702,31 @@ function replay(client, opts = {}) {
6700
6702
  }
6701
6703
  }
6702
6704
  }
6705
+ const hasPhaseTransition = phaseResult?.legal && phaseResult.newPhase !== sessionState.currentPhase;
6706
+ const shouldDeferPhase = isActiveGovern && !attemptDegraded && hasPhaseTransition;
6703
6707
  const prevVersionAllow = sessionState.stateVersion;
6704
- sessionState = finalizeExecutedStep(sessionState, completedStep, contracts, compiledSession);
6708
+ sessionState = finalizeExecutedStep(
6709
+ sessionState,
6710
+ completedStep,
6711
+ contracts,
6712
+ compiledSession,
6713
+ shouldDeferPhase ? { deferPhase: true } : void 0
6714
+ );
6705
6715
  sessionState = recordDecisionOutcome(sessionState, "allowed");
6706
6716
  syncStateToStore(prevVersionAllow, sessionState);
6707
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
+ }
6708
6730
  if (isActiveGovern && !attemptDegraded && attemptPendingCalls && attemptPendingCalls.size > 0) {
6709
6731
  for (const [toolCallId, pending] of attemptPendingCalls) {
6710
6732
  deferredReceipts.set(toolCallId, {
@@ -6722,8 +6744,8 @@ function replay(client, opts = {}) {
6722
6744
  checked: { gate_mode: gateMode },
6723
6745
  found: { blocked_count: 0, action: "allow" }
6724
6746
  });
6725
- const allowNewPhase = phaseResult && phaseResult.legal && phaseResult.newPhase !== sessionState.currentPhase ? phaseResult.newPhase : sessionState.currentPhase;
6726
- 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 } });
6727
6749
  trace.complete = true;
6728
6750
  lastTrace = trace;
6729
6751
  emitDiagnostic2(diagnostics, { type: "replay_trace", session_id: sessionId, trace });
@@ -7070,6 +7092,10 @@ function replay(client, opts = {}) {
7070
7092
  throw new ReplayKillError(sessionId, killedAt);
7071
7093
  }
7072
7094
  const result = await executor(args);
7095
+ if (deferredPhase && deferredPhase.toolNames.has(toolName)) {
7096
+ sessionState = { ...sessionState, currentPhase: deferredPhase.newPhase };
7097
+ deferredPhase = null;
7098
+ }
7073
7099
  if (runtimeClient && leaseFence && !runtimeDegraded) {
7074
7100
  for (const [callId, deferred] of deferredReceipts) {
7075
7101
  if (deferred.toolName === toolName) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replayci/replay",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "ReplayCI SDK for deterministic tool-call validation and observation.",
5
5
  "license": "ISC",
6
6
  "author": "ReplayCI",