@replayci/replay 0.1.16 → 0.1.18

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
@@ -5213,7 +5213,9 @@ var RuntimeClient = class {
5213
5213
  accepted: r.accepted,
5214
5214
  commitState: r.commit_state,
5215
5215
  stateAdvanced: r.state_advanced,
5216
- stateVersion: r.state_version
5216
+ stateVersion: r.state_version,
5217
+ executionState: r.execution_state ?? "outcome_recorded",
5218
+ pendingStatus: r.pending_status ?? (r.state_advanced ? "resolved" : "pending")
5217
5219
  };
5218
5220
  }
5219
5221
  async setToolFilter(input) {
@@ -5474,6 +5476,7 @@ var DEFAULT_AGENT2 = "default";
5474
5476
  var DEFAULT_MAX_UNGUARDED_CALLS = 3;
5475
5477
  function replay(client, opts = {}) {
5476
5478
  assertSupportedNodeRuntime();
5479
+ const internalOpts = opts;
5477
5480
  const sessionId = opts.sessionId ?? generateSessionId2();
5478
5481
  const agent = typeof opts.agent === "string" && opts.agent.length > 0 ? opts.agent : DEFAULT_AGENT2;
5479
5482
  const mode = opts.mode ?? "enforce";
@@ -5495,17 +5498,20 @@ function replay(client, opts = {}) {
5495
5498
  return createInactiveSession(client, sessionId, "Client already has an active observe() or replay() attachment");
5496
5499
  }
5497
5500
  let contracts;
5498
- let zeroConfigMode = false;
5499
- try {
5500
- contracts = resolveContracts(opts);
5501
- } catch (err) {
5502
- const apiKeyForGov = resolveApiKey2(opts);
5503
- if (apiKeyForGov && !opts.contracts && !opts.contractsDir) {
5504
- return createGovernanceSession(client, sessionId, agent, provider, apiKeyForGov, opts, diagnostics);
5501
+ if (internalOpts.__preparedContracts && internalOpts.__preparedContracts.length > 0) {
5502
+ contracts = internalOpts.__preparedContracts;
5503
+ } else {
5504
+ try {
5505
+ contracts = resolveContracts(opts);
5506
+ } catch (err) {
5507
+ const apiKeyForGov = resolveApiKey2(opts);
5508
+ if (apiKeyForGov && !opts.contracts && !opts.contractsDir) {
5509
+ return createGovernanceSession(client, sessionId, agent, provider, apiKeyForGov, opts, diagnostics);
5510
+ }
5511
+ const detail = err instanceof Error ? err.message : "Failed to load contracts";
5512
+ emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
5513
+ return createBlockingInactiveSession(client, sessionId, detail);
5505
5514
  }
5506
- const detail = err instanceof Error ? err.message : "Failed to load contracts";
5507
- emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
5508
- return createBlockingInactiveSession(client, sessionId, detail);
5509
5515
  }
5510
5516
  const configError = validateConfig(contracts, opts);
5511
5517
  if (configError) {
@@ -5532,20 +5538,22 @@ function replay(client, opts = {}) {
5532
5538
  } else if (sessionYaml && opts.providerConstraints && !sessionYaml.provider_constraints) {
5533
5539
  sessionYaml = { ...sessionYaml, provider_constraints: opts.providerConstraints };
5534
5540
  }
5535
- let compiledSession = null;
5536
- try {
5537
- compiledSession = (0, import_contracts_core7.compileSession)(contracts, sessionYaml, {
5538
- principal: opts.principal,
5539
- tools: opts.tools ? new Map(Object.entries(opts.tools)) : void 0
5540
- });
5541
- } catch (err) {
5542
- const detail = `Session compilation failed: ${err instanceof Error ? err.message : String(err)}`;
5543
- emitDiagnostic2(diagnostics, {
5544
- type: "replay_compile_error",
5545
- details: detail
5546
- });
5547
- if (discoveredSessionYaml) {
5548
- return createBlockingInactiveSession(client, sessionId, detail);
5541
+ let compiledSession = internalOpts.__compiledSession ?? null;
5542
+ if (!compiledSession) {
5543
+ try {
5544
+ compiledSession = (0, import_contracts_core7.compileSession)(contracts, sessionYaml, {
5545
+ principal: opts.principal,
5546
+ tools: opts.tools ? new Map(Object.entries(opts.tools)) : void 0
5547
+ });
5548
+ } catch (err) {
5549
+ const detail = `Session compilation failed: ${err instanceof Error ? err.message : String(err)}`;
5550
+ emitDiagnostic2(diagnostics, {
5551
+ type: "replay_compile_error",
5552
+ details: detail
5553
+ });
5554
+ if (discoveredSessionYaml) {
5555
+ return createBlockingInactiveSession(client, sessionId, detail);
5556
+ }
5549
5557
  }
5550
5558
  }
5551
5559
  if (compiledSession?.warnings && compiledSession.warnings.length > 0) {
@@ -5612,7 +5620,7 @@ function replay(client, opts = {}) {
5612
5620
  return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
5613
5621
  }
5614
5622
  const apiKey = resolveApiKey2(opts);
5615
- const protectionLevel = determineProtectionLevel(mode, opts.tools, contracts, apiKey);
5623
+ const protectionLevel = internalOpts.__disableRuntimeControlPlane ? determineRuntimeFreeProtectionLevel(mode) : determineProtectionLevel(mode, opts.tools, contracts, apiKey);
5616
5624
  const maxUnguardedCalls = opts.maxUnguardedCalls ?? DEFAULT_MAX_UNGUARDED_CALLS;
5617
5625
  const narrowingFeedback = opts.narrowingFeedback ?? "silent";
5618
5626
  let runtimeClient = null;
@@ -7971,6 +7979,185 @@ function createBlockingInactiveSession(client, sessionId, detail, configError) {
7971
7979
  handoff: () => Promise.resolve(null)
7972
7980
  };
7973
7981
  }
7982
+ function createPreparedContractsFromCompiledSession(compiledSession) {
7983
+ return Array.from(compiledSession.perToolContracts.values()).map((contract) => ({
7984
+ ...contract,
7985
+ contract_file: contract.tool
7986
+ }));
7987
+ }
7988
+ function requireArtifactRecord(value, field) {
7989
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7990
+ throw new ReplayConfigError(
7991
+ "compilation_failed",
7992
+ `Approved governance artifact has invalid ${field}`
7993
+ );
7994
+ }
7995
+ return value;
7996
+ }
7997
+ function requireArtifactStringArray(value, field) {
7998
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
7999
+ throw new ReplayConfigError(
8000
+ "compilation_failed",
8001
+ `Approved governance artifact has invalid ${field}`
8002
+ );
8003
+ }
8004
+ return value;
8005
+ }
8006
+ function requireArtifactEntryArray(value, field) {
8007
+ if (!Array.isArray(value)) {
8008
+ throw new ReplayConfigError(
8009
+ "compilation_failed",
8010
+ `Approved governance artifact has invalid ${field}`
8011
+ );
8012
+ }
8013
+ return value.map((entry) => {
8014
+ if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") {
8015
+ throw new ReplayConfigError(
8016
+ "compilation_failed",
8017
+ `Approved governance artifact has invalid ${field}`
8018
+ );
8019
+ }
8020
+ return [entry[0], entry[1]];
8021
+ });
8022
+ }
8023
+ function hydrateStringArrayMap(value, field) {
8024
+ return new Map(
8025
+ requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
8026
+ key,
8027
+ requireArtifactStringArray(entryValue, `${field}.${key}`)
8028
+ ])
8029
+ );
8030
+ }
8031
+ function hydrateContractMap(value, field) {
8032
+ return new Map(
8033
+ requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
8034
+ key,
8035
+ requireArtifactRecord(entryValue, `${field}.${key}`)
8036
+ ])
8037
+ );
8038
+ }
8039
+ function hydrateExecutionConstraintMap(value, field) {
8040
+ return new Map(
8041
+ requireArtifactEntryArray(value, field).map(([key, entryValue]) => {
8042
+ if (!Array.isArray(entryValue)) {
8043
+ throw new ReplayConfigError(
8044
+ "compilation_failed",
8045
+ `Approved governance artifact has invalid ${field}.${key}`
8046
+ );
8047
+ }
8048
+ return [key, entryValue];
8049
+ })
8050
+ );
8051
+ }
8052
+ function hydrateNestedStringMap(value, field) {
8053
+ return new Map(
8054
+ requireArtifactEntryArray(value, field).map(([outerKey, innerValue]) => {
8055
+ const nested = new Map(
8056
+ requireArtifactEntryArray(innerValue, `${field}.${outerKey}`).map(([innerKey, nestedValue]) => {
8057
+ if (typeof nestedValue !== "string") {
8058
+ throw new ReplayConfigError(
8059
+ "compilation_failed",
8060
+ `Approved governance artifact has invalid ${field}.${outerKey}.${innerKey}`
8061
+ );
8062
+ }
8063
+ return [innerKey, nestedValue];
8064
+ })
8065
+ );
8066
+ return [outerKey, nested];
8067
+ })
8068
+ );
8069
+ }
8070
+ function hydratePolicyProgram(value) {
8071
+ if (value == null) return null;
8072
+ const policyProgram = requireArtifactRecord(value, "policyProgram");
8073
+ if (typeof policyProgram.defaultDeny !== "boolean" || !Array.isArray(policyProgram.sessionRules)) {
8074
+ throw new ReplayConfigError(
8075
+ "compilation_failed",
8076
+ "Approved governance artifact has invalid policyProgram"
8077
+ );
8078
+ }
8079
+ return {
8080
+ defaultDeny: policyProgram.defaultDeny,
8081
+ sessionRules: policyProgram.sessionRules,
8082
+ perToolRules: new Map(
8083
+ requireArtifactEntryArray(policyProgram.perToolRules ?? [], "policyProgram.perToolRules").map(
8084
+ ([toolName, ruleValue]) => [toolName, requireArtifactRecord(ruleValue, `policyProgram.perToolRules.${toolName}`)]
8085
+ )
8086
+ )
8087
+ };
8088
+ }
8089
+ function rehydrateCompiledSessionArtifact(artifact, expectedHash) {
8090
+ const record = requireArtifactRecord(artifact, "compiled_session");
8091
+ if (typeof record.agent !== "string" || typeof record.schemaVersion !== "string") {
8092
+ throw new ReplayConfigError(
8093
+ "compilation_failed",
8094
+ "Approved governance artifact is missing required session metadata"
8095
+ );
8096
+ }
8097
+ if (record.phases != null && !Array.isArray(record.phases)) {
8098
+ throw new ReplayConfigError(
8099
+ "compilation_failed",
8100
+ "Approved governance artifact has invalid phases"
8101
+ );
8102
+ }
8103
+ if (!Array.isArray(record.contractHashes) || record.contractHashes.some((hash) => typeof hash !== "string")) {
8104
+ throw new ReplayConfigError(
8105
+ "compilation_failed",
8106
+ "Approved governance artifact has invalid contractHashes"
8107
+ );
8108
+ }
8109
+ const compiledSession = {
8110
+ agent: record.agent,
8111
+ schemaVersion: record.schemaVersion,
8112
+ phases: record.phases ?? null,
8113
+ transitions: hydrateStringArrayMap(record.transitions ?? [], "transitions"),
8114
+ sessionLimits: record.sessionLimits ?? {},
8115
+ perToolContracts: hydrateContractMap(record.perToolContracts ?? [], "perToolContracts"),
8116
+ riskDefaults: requireArtifactRecord(record.riskDefaults ?? {}, "riskDefaults"),
8117
+ providerConstraints: record.providerConstraints ?? null,
8118
+ contractHashes: record.contractHashes,
8119
+ compiledHash: "",
8120
+ principal: null,
8121
+ policyProgram: hydratePolicyProgram(record.policyProgram),
8122
+ executionConstraints: hydrateExecutionConstraintMap(record.executionConstraints ?? [], "executionConstraints"),
8123
+ toolExecutors: null,
8124
+ resources: hydrateNestedStringMap(record.resources ?? [], "resources"),
8125
+ warnings: [],
8126
+ graphDiagnostics: [],
8127
+ schemaDerivedDiagnostics: [],
8128
+ aggregates: Array.isArray(record.aggregates) ? record.aggregates : [],
8129
+ envelopes: Array.isArray(record.envelopes) ? record.envelopes : [],
8130
+ labelGates: Array.isArray(record.labelGates) ? record.labelGates : [],
8131
+ checkpoints: Array.isArray(record.checkpoints) ? record.checkpoints : []
8132
+ };
8133
+ const serialized = (0, import_contracts_core7.serializeCompiledSession)(compiledSession);
8134
+ const computedHash = import_node_crypto6.default.createHash("sha256").update(serialized).digest("hex");
8135
+ compiledSession.compiledHash = computedHash;
8136
+ if (expectedHash && expectedHash !== computedHash) {
8137
+ throw new ReplayConfigError(
8138
+ "compilation_failed",
8139
+ `Approved governance artifact hash mismatch: expected ${expectedHash}, got ${computedHash}`
8140
+ );
8141
+ }
8142
+ return compiledSession;
8143
+ }
8144
+ function createDetachedProviderClient(provider, terminal, originalCreate) {
8145
+ const boundCreate = (...args) => originalCreate.apply(terminal, args);
8146
+ if (provider === "openai") {
8147
+ return {
8148
+ chat: {
8149
+ completions: {
8150
+ create: boundCreate
8151
+ }
8152
+ }
8153
+ };
8154
+ }
8155
+ return {
8156
+ messages: {
8157
+ create: boundCreate
8158
+ }
8159
+ };
8160
+ }
7974
8161
  function resolveGovernanceEnvironment(opts) {
7975
8162
  if (opts.environment) return opts.environment;
7976
8163
  const envVar = typeof process !== "undefined" ? process.env.REPLAYCI_ENVIRONMENT : void 0;
@@ -7993,7 +8180,7 @@ function governanceProtectionLevel(env) {
7993
8180
  }
7994
8181
  function createGovernanceSession(client, sessionId, agent, provider, apiKey, opts, diagnostics) {
7995
8182
  const environment = resolveGovernanceEnvironment(opts);
7996
- const protLevel = governanceProtectionLevel(environment);
8183
+ const observeProtectionLevel = governanceProtectionLevel(environment);
7997
8184
  const runtimeClient = new RuntimeClient({
7998
8185
  apiKey,
7999
8186
  apiUrl: opts.runtimeUrl
@@ -8002,13 +8189,22 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
8002
8189
  let planFetchPromise = null;
8003
8190
  let planFetchDone = false;
8004
8191
  let planFetchError = null;
8192
+ let planFetchErrorCode = null;
8193
+ let approvedRuntimeSession = null;
8194
+ let approvedRuntimeInitPromise = null;
8195
+ let approvedRuntimeInitError = null;
8005
8196
  planFetchPromise = runtimeClient.fetchGovernancePlan(agent, environment).then((result) => {
8006
8197
  governancePlan = result;
8007
8198
  planFetchDone = true;
8199
+ if (!hasApprovedGovernanceArtifact(result)) {
8200
+ emitDiagnostic2(diagnostics, { type: "replay_governance_no_plan", session_id: sessionId, environment });
8201
+ }
8008
8202
  }).catch((err) => {
8009
8203
  planFetchDone = true;
8010
8204
  planFetchError = err instanceof Error ? err.message : String(err);
8205
+ planFetchErrorCode = err instanceof RuntimeClientError ? err.code : null;
8011
8206
  governancePlan = null;
8207
+ emitDiagnostic2(diagnostics, { type: "replay_governance_fetch_failed", session_id: sessionId, details: planFetchError });
8012
8208
  });
8013
8209
  const captureBuffer = new CaptureBuffer({
8014
8210
  apiKey,
@@ -8021,12 +8217,139 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
8021
8217
  return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
8022
8218
  }
8023
8219
  const { terminal, originalCreate } = terminalInfo;
8220
+ const fallbackTools = buildWrappedToolsMap(opts.tools, null);
8221
+ function hasApprovedGovernanceArtifact(plan) {
8222
+ return Boolean(
8223
+ plan && (plan.status === "approved" || plan.status === "enforcing")
8224
+ );
8225
+ }
8226
+ async function ensureApprovedRuntimeSession() {
8227
+ if (approvedRuntimeSession) return approvedRuntimeSession;
8228
+ if (approvedRuntimeInitError) throw approvedRuntimeInitError;
8229
+ if (approvedRuntimeInitPromise) {
8230
+ await approvedRuntimeInitPromise;
8231
+ if (approvedRuntimeInitError) throw approvedRuntimeInitError;
8232
+ return approvedRuntimeSession;
8233
+ }
8234
+ approvedRuntimeInitPromise = (async () => {
8235
+ if (!hasApprovedGovernanceArtifact(governancePlan)) {
8236
+ throw new ReplayConfigError(
8237
+ "compilation_failed",
8238
+ "Approved governance artifact was not available for runtime enforcement"
8239
+ );
8240
+ }
8241
+ if (!governancePlan?.compiledSession) {
8242
+ throw new ReplayConfigError(
8243
+ "compilation_failed",
8244
+ "Approved governance plan is missing compiled_session"
8245
+ );
8246
+ }
8247
+ if (!governancePlan.compiledHash) {
8248
+ throw new ReplayConfigError(
8249
+ "compilation_failed",
8250
+ "Approved governance plan is missing compiled_hash"
8251
+ );
8252
+ }
8253
+ const compiledSession = rehydrateCompiledSessionArtifact(
8254
+ governancePlan.compiledSession,
8255
+ governancePlan.compiledHash
8256
+ );
8257
+ const preparedContracts = createPreparedContractsFromCompiledSession(compiledSession);
8258
+ const detachedClient = createDetachedProviderClient(
8259
+ provider,
8260
+ terminal,
8261
+ originalCreate
8262
+ );
8263
+ const approvedMode = environment === "development" ? "shadow" : "enforce";
8264
+ const approvedCompatEnforcement = environment === "staging" ? "advisory" : opts.compatEnforcement ?? "protective";
8265
+ approvedRuntimeSession = replay(detachedClient, {
8266
+ ...opts,
8267
+ agent,
8268
+ sessionId,
8269
+ apiKey,
8270
+ mode: approvedMode,
8271
+ compatEnforcement: approvedCompatEnforcement,
8272
+ contracts: void 0,
8273
+ contractsDir: void 0,
8274
+ sessionYamlPath: void 0,
8275
+ environment: void 0,
8276
+ __preparedContracts: preparedContracts,
8277
+ __compiledSession: compiledSession,
8278
+ __disableRuntimeControlPlane: true
8279
+ });
8280
+ emitDiagnostic2(diagnostics, { type: "replay_governance_attached", session_id: sessionId, environment });
8281
+ })().catch((err) => {
8282
+ approvedRuntimeInitError = err instanceof Error ? err : new ReplayConfigError("compilation_failed", String(err));
8283
+ const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
8284
+ emitDiagnostic2(diagnostics, {
8285
+ type: isArtifactInvalid ? "replay_governance_artifact_invalid" : "replay_governance_attachment_failed",
8286
+ session_id: sessionId,
8287
+ details: approvedRuntimeInitError.message
8288
+ });
8289
+ emitDiagnostic2(diagnostics, {
8290
+ type: "replay_compile_error",
8291
+ details: approvedRuntimeInitError.message
8292
+ });
8293
+ });
8294
+ await approvedRuntimeInitPromise;
8295
+ if (approvedRuntimeInitError) throw approvedRuntimeInitError;
8296
+ return approvedRuntimeSession;
8297
+ }
8298
+ async function invokeApprovedRuntimeCreate(args) {
8299
+ const runtimeSession = await ensureApprovedRuntimeSession();
8300
+ if (provider === "openai") {
8301
+ return runtimeSession.client.chat.completions.create(...args);
8302
+ }
8303
+ return runtimeSession.client.messages.create(...args);
8304
+ }
8305
+ const tools = opts.tools ? new Proxy(fallbackTools, {
8306
+ get(_target, prop) {
8307
+ if (typeof prop !== "string") return void 0;
8308
+ if (approvedRuntimeSession?.tools[prop]) {
8309
+ return approvedRuntimeSession.tools[prop];
8310
+ }
8311
+ return fallbackTools[prop];
8312
+ },
8313
+ has(_target, prop) {
8314
+ if (typeof prop !== "string") return false;
8315
+ return Boolean(approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]);
8316
+ },
8317
+ ownKeys() {
8318
+ const keys = /* @__PURE__ */ new Set([
8319
+ ...Reflect.ownKeys(fallbackTools),
8320
+ ...Reflect.ownKeys(approvedRuntimeSession?.tools ?? {})
8321
+ ]);
8322
+ return Array.from(keys);
8323
+ },
8324
+ getOwnPropertyDescriptor(_target, prop) {
8325
+ if (typeof prop !== "string") return void 0;
8326
+ if (approvedRuntimeSession?.tools[prop] || fallbackTools[prop]) {
8327
+ return {
8328
+ configurable: true,
8329
+ enumerable: true,
8330
+ writable: false,
8331
+ value: approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]
8332
+ };
8333
+ }
8334
+ return void 0;
8335
+ }
8336
+ }) : {};
8024
8337
  const patchedCreate = async function(...args) {
8025
8338
  if (!planFetchDone && planFetchPromise) {
8026
8339
  await planFetchPromise;
8027
8340
  }
8028
- const hasApprovedPlan = governancePlan && (governancePlan.status === "approved" || governancePlan.status === "enforcing") && governancePlan.compiledSession;
8029
- if (hasApprovedPlan) {
8341
+ if (planFetchError) {
8342
+ const artifactBroken = planFetchErrorCode === "APPROVED_ARTIFACT_INVALID";
8343
+ const requiresEnforcement = observeProtectionLevel !== "monitor";
8344
+ if (artifactBroken || requiresEnforcement) {
8345
+ throw new ReplayConfigError(
8346
+ "governance_unavailable",
8347
+ `Governance plan fetch failed (fail-closed): ${planFetchError}`
8348
+ );
8349
+ }
8350
+ }
8351
+ if (hasApprovedGovernanceArtifact(governancePlan)) {
8352
+ return invokeApprovedRuntimeCreate(args);
8030
8353
  }
8031
8354
  const result = await originalCreate.apply(this, args);
8032
8355
  try {
@@ -8055,40 +8378,81 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
8055
8378
  setReplayAttached(client);
8056
8379
  return {
8057
8380
  client,
8058
- flush: () => captureBuffer.flush(),
8381
+ flush: () => approvedRuntimeSession ? approvedRuntimeSession.flush() : captureBuffer.flush(),
8059
8382
  restore() {
8060
8383
  terminal[terminalInfo.methodName] = originalCreate;
8384
+ approvedRuntimeSession?.restore();
8385
+ clearReplayAttached(client);
8061
8386
  },
8062
8387
  kill() {
8388
+ approvedRuntimeSession?.kill();
8063
8389
  },
8064
- getHealth: () => ({
8065
- status: "healthy",
8066
- authorityState: "active",
8067
- protectionLevel: protLevel,
8068
- durability: "inactive",
8069
- tier: "compat",
8070
- compatEnforcement: "protective",
8071
- cluster_detected: false,
8072
- bypass_detected: false,
8073
- totalSteps: 0,
8074
- totalBlocks: 0,
8075
- totalErrors: 0,
8076
- killed: false,
8077
- shadowEvaluations: 0
8078
- }),
8079
- getState: () => EMPTY_STATE_SNAPSHOT,
8080
- getLastNarrowing: () => null,
8081
- getLastShadowDelta: () => null,
8082
- getLastTrace: () => null,
8083
- narrow() {
8390
+ getHealth: () => {
8391
+ if (approvedRuntimeSession) {
8392
+ const inner = approvedRuntimeSession.getHealth();
8393
+ return { ...inner, governanceAttachment: "attached" };
8394
+ }
8395
+ let governanceAttachment;
8396
+ let status;
8397
+ let authorityState;
8398
+ let totalErrors = 0;
8399
+ if (!planFetchDone) {
8400
+ governanceAttachment = "pending";
8401
+ status = "healthy";
8402
+ authorityState = "advisory";
8403
+ } else if (planFetchError) {
8404
+ governanceAttachment = "fetch_failed";
8405
+ status = "degraded";
8406
+ authorityState = "inactive";
8407
+ totalErrors = 1;
8408
+ } else if (approvedRuntimeInitError) {
8409
+ const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
8410
+ governanceAttachment = isArtifactInvalid ? "artifact_invalid" : "attachment_failed";
8411
+ status = "degraded";
8412
+ authorityState = "inactive";
8413
+ totalErrors = 1;
8414
+ } else if (!hasApprovedGovernanceArtifact(governancePlan)) {
8415
+ governanceAttachment = "no_plan";
8416
+ status = "healthy";
8417
+ authorityState = "advisory";
8418
+ } else {
8419
+ governanceAttachment = "pending";
8420
+ status = "healthy";
8421
+ authorityState = "advisory";
8422
+ }
8423
+ return {
8424
+ status,
8425
+ authorityState,
8426
+ protectionLevel: observeProtectionLevel,
8427
+ durability: "inactive",
8428
+ tier: "compat",
8429
+ compatEnforcement: "protective",
8430
+ cluster_detected: false,
8431
+ bypass_detected: false,
8432
+ totalSteps: 0,
8433
+ totalBlocks: 0,
8434
+ totalErrors,
8435
+ killed: false,
8436
+ shadowEvaluations: 0,
8437
+ governanceAttachment
8438
+ };
8439
+ },
8440
+ getState: () => approvedRuntimeSession ? approvedRuntimeSession.getState() : EMPTY_STATE_SNAPSHOT,
8441
+ getLastNarrowing: () => approvedRuntimeSession ? approvedRuntimeSession.getLastNarrowing() : null,
8442
+ getLastShadowDelta: () => approvedRuntimeSession ? approvedRuntimeSession.getLastShadowDelta() : null,
8443
+ getLastTrace: () => approvedRuntimeSession ? approvedRuntimeSession.getLastTrace() : null,
8444
+ narrow(...args) {
8445
+ approvedRuntimeSession?.narrow(...args);
8084
8446
  },
8085
8447
  widen() {
8448
+ approvedRuntimeSession?.widen();
8086
8449
  },
8087
- addLabel() {
8450
+ addLabel(label) {
8451
+ approvedRuntimeSession?.addLabel(label);
8088
8452
  },
8089
- tools: {},
8090
- getWorkflowState: () => Promise.resolve(null),
8091
- handoff: () => Promise.resolve(null)
8453
+ tools,
8454
+ getWorkflowState: () => approvedRuntimeSession ? approvedRuntimeSession.getWorkflowState() : Promise.resolve(null),
8455
+ handoff: (offer) => approvedRuntimeSession ? approvedRuntimeSession.handoff(offer) : Promise.resolve(null)
8092
8456
  };
8093
8457
  }
8094
8458
  function toNarrowingSnapshot(result) {
@@ -8265,6 +8629,9 @@ function determineProtectionLevel(mode, tools, contracts, apiKey) {
8265
8629
  const allWrapped = stateBearingTools.every((c) => wrappedTools.has(c.tool));
8266
8630
  return allWrapped ? "govern" : "protect";
8267
8631
  }
8632
+ function determineRuntimeFreeProtectionLevel(mode) {
8633
+ return mode === "enforce" ? "protect" : "monitor";
8634
+ }
8268
8635
  function isStateBearing(contract) {
8269
8636
  if (contract.commit_requirement != null && contract.commit_requirement !== "none") return true;
8270
8637
  if (contract.transitions != null) return true;
package/dist/index.d.cts CHANGED
@@ -699,6 +699,11 @@ type ReplaySession<T> = {
699
699
  */
700
700
  handoff: (offer: HandoffOfferInput$1) => Promise<HandoffOfferResult$1 | null>;
701
701
  };
702
+ /**
703
+ * Governance attachment state for zero-config governance sessions.
704
+ * @see replay.ts § createGovernanceSession
705
+ */
706
+ type GovernanceAttachmentState = "pending" | "no_plan" | "attached" | "artifact_invalid" | "attachment_failed" | "fetch_failed";
702
707
  /** @see specs/runtime-replay.md § ReplayHealthSnapshot */
703
708
  type ReplayHealthSnapshot = {
704
709
  status: "healthy" | "degraded" | "inactive";
@@ -716,6 +721,8 @@ type ReplayHealthSnapshot = {
716
721
  killed: boolean;
717
722
  /** Number of shadow-mode evaluations performed (always 0 in enforce/log-only). */
718
723
  shadowEvaluations: number;
724
+ /** Governance attachment state. Only present for zero-config governance sessions. */
725
+ governanceAttachment?: GovernanceAttachmentState;
719
726
  };
720
727
  /**
721
728
  * Public, redacted, JSON-serializable snapshot of session state.
@@ -1031,6 +1038,26 @@ type ReplayDiagnosticEvent = {
1031
1038
  tool?: string;
1032
1039
  phase?: string;
1033
1040
  suggestion?: string;
1041
+ } | {
1042
+ type: "replay_governance_attached";
1043
+ session_id: string;
1044
+ environment: string;
1045
+ } | {
1046
+ type: "replay_governance_no_plan";
1047
+ session_id: string;
1048
+ environment: string;
1049
+ } | {
1050
+ type: "replay_governance_artifact_invalid";
1051
+ session_id: string;
1052
+ details: string;
1053
+ } | {
1054
+ type: "replay_governance_attachment_failed";
1055
+ session_id: string;
1056
+ details: string;
1057
+ } | {
1058
+ type: "replay_governance_fetch_failed";
1059
+ session_id: string;
1060
+ details: string;
1034
1061
  };
1035
1062
  /**
1036
1063
  * Workflow state snapshot returned by `session.getWorkflowState()`.
@@ -1113,9 +1140,9 @@ declare class ReplayKillError extends Error {
1113
1140
  * @see specs/replay-v1.md § Config errors (fail-closed)
1114
1141
  */
1115
1142
  declare class ReplayConfigError extends ReplayConfigurationError {
1116
- readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible";
1143
+ readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable";
1117
1144
  readonly details: string;
1118
- constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible", details: string);
1145
+ constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable", details: string);
1119
1146
  }
1120
1147
 
1121
1148
  /**
@@ -1242,7 +1269,7 @@ type ReceiptInput = {
1242
1269
  executorId?: string | null;
1243
1270
  toolName: string;
1244
1271
  argumentsHash: string;
1245
- status: "SUCCEEDED" | "FAILED" | "DISCARDED";
1272
+ status: "SUCCEEDED" | "FAILED" | "DISCARDED" | "AMBIGUOUS";
1246
1273
  outputHash?: string | null;
1247
1274
  outputExtract?: Record<string, unknown> | null;
1248
1275
  resourceValues?: Record<string, unknown> | null;
@@ -1255,6 +1282,8 @@ type ReceiptResult = {
1255
1282
  commitState: "committed" | "uncommitted";
1256
1283
  stateAdvanced: boolean;
1257
1284
  stateVersion: number;
1285
+ executionState: "outcome_recorded" | "ambiguous";
1286
+ pendingStatus: "resolved" | "pending" | "ambiguous";
1258
1287
  };
1259
1288
  type ToolFilterInput = {
1260
1289
  sessionId: string;
@@ -1366,4 +1395,4 @@ declare class RuntimeClient {
1366
1395
  private recordFailure;
1367
1396
  }
1368
1397
 
1369
- export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
1398
+ export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type GovernanceAttachmentState, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
package/dist/index.d.ts CHANGED
@@ -699,6 +699,11 @@ type ReplaySession<T> = {
699
699
  */
700
700
  handoff: (offer: HandoffOfferInput$1) => Promise<HandoffOfferResult$1 | null>;
701
701
  };
702
+ /**
703
+ * Governance attachment state for zero-config governance sessions.
704
+ * @see replay.ts § createGovernanceSession
705
+ */
706
+ type GovernanceAttachmentState = "pending" | "no_plan" | "attached" | "artifact_invalid" | "attachment_failed" | "fetch_failed";
702
707
  /** @see specs/runtime-replay.md § ReplayHealthSnapshot */
703
708
  type ReplayHealthSnapshot = {
704
709
  status: "healthy" | "degraded" | "inactive";
@@ -716,6 +721,8 @@ type ReplayHealthSnapshot = {
716
721
  killed: boolean;
717
722
  /** Number of shadow-mode evaluations performed (always 0 in enforce/log-only). */
718
723
  shadowEvaluations: number;
724
+ /** Governance attachment state. Only present for zero-config governance sessions. */
725
+ governanceAttachment?: GovernanceAttachmentState;
719
726
  };
720
727
  /**
721
728
  * Public, redacted, JSON-serializable snapshot of session state.
@@ -1031,6 +1038,26 @@ type ReplayDiagnosticEvent = {
1031
1038
  tool?: string;
1032
1039
  phase?: string;
1033
1040
  suggestion?: string;
1041
+ } | {
1042
+ type: "replay_governance_attached";
1043
+ session_id: string;
1044
+ environment: string;
1045
+ } | {
1046
+ type: "replay_governance_no_plan";
1047
+ session_id: string;
1048
+ environment: string;
1049
+ } | {
1050
+ type: "replay_governance_artifact_invalid";
1051
+ session_id: string;
1052
+ details: string;
1053
+ } | {
1054
+ type: "replay_governance_attachment_failed";
1055
+ session_id: string;
1056
+ details: string;
1057
+ } | {
1058
+ type: "replay_governance_fetch_failed";
1059
+ session_id: string;
1060
+ details: string;
1034
1061
  };
1035
1062
  /**
1036
1063
  * Workflow state snapshot returned by `session.getWorkflowState()`.
@@ -1113,9 +1140,9 @@ declare class ReplayKillError extends Error {
1113
1140
  * @see specs/replay-v1.md § Config errors (fail-closed)
1114
1141
  */
1115
1142
  declare class ReplayConfigError extends ReplayConfigurationError {
1116
- readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible";
1143
+ readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable";
1117
1144
  readonly details: string;
1118
- constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible", details: string);
1145
+ constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable", details: string);
1119
1146
  }
1120
1147
 
1121
1148
  /**
@@ -1242,7 +1269,7 @@ type ReceiptInput = {
1242
1269
  executorId?: string | null;
1243
1270
  toolName: string;
1244
1271
  argumentsHash: string;
1245
- status: "SUCCEEDED" | "FAILED" | "DISCARDED";
1272
+ status: "SUCCEEDED" | "FAILED" | "DISCARDED" | "AMBIGUOUS";
1246
1273
  outputHash?: string | null;
1247
1274
  outputExtract?: Record<string, unknown> | null;
1248
1275
  resourceValues?: Record<string, unknown> | null;
@@ -1255,6 +1282,8 @@ type ReceiptResult = {
1255
1282
  commitState: "committed" | "uncommitted";
1256
1283
  stateAdvanced: boolean;
1257
1284
  stateVersion: number;
1285
+ executionState: "outcome_recorded" | "ambiguous";
1286
+ pendingStatus: "resolved" | "pending" | "ambiguous";
1258
1287
  };
1259
1288
  type ToolFilterInput = {
1260
1289
  sessionId: string;
@@ -1366,4 +1395,4 @@ declare class RuntimeClient {
1366
1395
  private recordFailure;
1367
1396
  }
1368
1397
 
1369
- export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
1398
+ export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type GovernanceAttachmentState, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
package/dist/index.js CHANGED
@@ -5205,7 +5205,9 @@ var RuntimeClient = class {
5205
5205
  accepted: r.accepted,
5206
5206
  commitState: r.commit_state,
5207
5207
  stateAdvanced: r.state_advanced,
5208
- stateVersion: r.state_version
5208
+ stateVersion: r.state_version,
5209
+ executionState: r.execution_state ?? "outcome_recorded",
5210
+ pendingStatus: r.pending_status ?? (r.state_advanced ? "resolved" : "pending")
5209
5211
  };
5210
5212
  }
5211
5213
  async setToolFilter(input) {
@@ -5466,6 +5468,7 @@ var DEFAULT_AGENT2 = "default";
5466
5468
  var DEFAULT_MAX_UNGUARDED_CALLS = 3;
5467
5469
  function replay(client, opts = {}) {
5468
5470
  assertSupportedNodeRuntime();
5471
+ const internalOpts = opts;
5469
5472
  const sessionId = opts.sessionId ?? generateSessionId2();
5470
5473
  const agent = typeof opts.agent === "string" && opts.agent.length > 0 ? opts.agent : DEFAULT_AGENT2;
5471
5474
  const mode = opts.mode ?? "enforce";
@@ -5487,17 +5490,20 @@ function replay(client, opts = {}) {
5487
5490
  return createInactiveSession(client, sessionId, "Client already has an active observe() or replay() attachment");
5488
5491
  }
5489
5492
  let contracts;
5490
- let zeroConfigMode = false;
5491
- try {
5492
- contracts = resolveContracts(opts);
5493
- } catch (err) {
5494
- const apiKeyForGov = resolveApiKey2(opts);
5495
- if (apiKeyForGov && !opts.contracts && !opts.contractsDir) {
5496
- return createGovernanceSession(client, sessionId, agent, provider, apiKeyForGov, opts, diagnostics);
5493
+ if (internalOpts.__preparedContracts && internalOpts.__preparedContracts.length > 0) {
5494
+ contracts = internalOpts.__preparedContracts;
5495
+ } else {
5496
+ try {
5497
+ contracts = resolveContracts(opts);
5498
+ } catch (err) {
5499
+ const apiKeyForGov = resolveApiKey2(opts);
5500
+ if (apiKeyForGov && !opts.contracts && !opts.contractsDir) {
5501
+ return createGovernanceSession(client, sessionId, agent, provider, apiKeyForGov, opts, diagnostics);
5502
+ }
5503
+ const detail = err instanceof Error ? err.message : "Failed to load contracts";
5504
+ emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
5505
+ return createBlockingInactiveSession(client, sessionId, detail);
5497
5506
  }
5498
- const detail = err instanceof Error ? err.message : "Failed to load contracts";
5499
- emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
5500
- return createBlockingInactiveSession(client, sessionId, detail);
5501
5507
  }
5502
5508
  const configError = validateConfig(contracts, opts);
5503
5509
  if (configError) {
@@ -5524,20 +5530,22 @@ function replay(client, opts = {}) {
5524
5530
  } else if (sessionYaml && opts.providerConstraints && !sessionYaml.provider_constraints) {
5525
5531
  sessionYaml = { ...sessionYaml, provider_constraints: opts.providerConstraints };
5526
5532
  }
5527
- let compiledSession = null;
5528
- try {
5529
- compiledSession = compileSession(contracts, sessionYaml, {
5530
- principal: opts.principal,
5531
- tools: opts.tools ? new Map(Object.entries(opts.tools)) : void 0
5532
- });
5533
- } catch (err) {
5534
- const detail = `Session compilation failed: ${err instanceof Error ? err.message : String(err)}`;
5535
- emitDiagnostic2(diagnostics, {
5536
- type: "replay_compile_error",
5537
- details: detail
5538
- });
5539
- if (discoveredSessionYaml) {
5540
- return createBlockingInactiveSession(client, sessionId, detail);
5533
+ let compiledSession = internalOpts.__compiledSession ?? null;
5534
+ if (!compiledSession) {
5535
+ try {
5536
+ compiledSession = compileSession(contracts, sessionYaml, {
5537
+ principal: opts.principal,
5538
+ tools: opts.tools ? new Map(Object.entries(opts.tools)) : void 0
5539
+ });
5540
+ } catch (err) {
5541
+ const detail = `Session compilation failed: ${err instanceof Error ? err.message : String(err)}`;
5542
+ emitDiagnostic2(diagnostics, {
5543
+ type: "replay_compile_error",
5544
+ details: detail
5545
+ });
5546
+ if (discoveredSessionYaml) {
5547
+ return createBlockingInactiveSession(client, sessionId, detail);
5548
+ }
5541
5549
  }
5542
5550
  }
5543
5551
  if (compiledSession?.warnings && compiledSession.warnings.length > 0) {
@@ -5604,7 +5612,7 @@ function replay(client, opts = {}) {
5604
5612
  return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
5605
5613
  }
5606
5614
  const apiKey = resolveApiKey2(opts);
5607
- const protectionLevel = determineProtectionLevel(mode, opts.tools, contracts, apiKey);
5615
+ const protectionLevel = internalOpts.__disableRuntimeControlPlane ? determineRuntimeFreeProtectionLevel(mode) : determineProtectionLevel(mode, opts.tools, contracts, apiKey);
5608
5616
  const maxUnguardedCalls = opts.maxUnguardedCalls ?? DEFAULT_MAX_UNGUARDED_CALLS;
5609
5617
  const narrowingFeedback = opts.narrowingFeedback ?? "silent";
5610
5618
  let runtimeClient = null;
@@ -7963,6 +7971,185 @@ function createBlockingInactiveSession(client, sessionId, detail, configError) {
7963
7971
  handoff: () => Promise.resolve(null)
7964
7972
  };
7965
7973
  }
7974
+ function createPreparedContractsFromCompiledSession(compiledSession) {
7975
+ return Array.from(compiledSession.perToolContracts.values()).map((contract) => ({
7976
+ ...contract,
7977
+ contract_file: contract.tool
7978
+ }));
7979
+ }
7980
+ function requireArtifactRecord(value, field) {
7981
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7982
+ throw new ReplayConfigError(
7983
+ "compilation_failed",
7984
+ `Approved governance artifact has invalid ${field}`
7985
+ );
7986
+ }
7987
+ return value;
7988
+ }
7989
+ function requireArtifactStringArray(value, field) {
7990
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
7991
+ throw new ReplayConfigError(
7992
+ "compilation_failed",
7993
+ `Approved governance artifact has invalid ${field}`
7994
+ );
7995
+ }
7996
+ return value;
7997
+ }
7998
+ function requireArtifactEntryArray(value, field) {
7999
+ if (!Array.isArray(value)) {
8000
+ throw new ReplayConfigError(
8001
+ "compilation_failed",
8002
+ `Approved governance artifact has invalid ${field}`
8003
+ );
8004
+ }
8005
+ return value.map((entry) => {
8006
+ if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") {
8007
+ throw new ReplayConfigError(
8008
+ "compilation_failed",
8009
+ `Approved governance artifact has invalid ${field}`
8010
+ );
8011
+ }
8012
+ return [entry[0], entry[1]];
8013
+ });
8014
+ }
8015
+ function hydrateStringArrayMap(value, field) {
8016
+ return new Map(
8017
+ requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
8018
+ key,
8019
+ requireArtifactStringArray(entryValue, `${field}.${key}`)
8020
+ ])
8021
+ );
8022
+ }
8023
+ function hydrateContractMap(value, field) {
8024
+ return new Map(
8025
+ requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
8026
+ key,
8027
+ requireArtifactRecord(entryValue, `${field}.${key}`)
8028
+ ])
8029
+ );
8030
+ }
8031
+ function hydrateExecutionConstraintMap(value, field) {
8032
+ return new Map(
8033
+ requireArtifactEntryArray(value, field).map(([key, entryValue]) => {
8034
+ if (!Array.isArray(entryValue)) {
8035
+ throw new ReplayConfigError(
8036
+ "compilation_failed",
8037
+ `Approved governance artifact has invalid ${field}.${key}`
8038
+ );
8039
+ }
8040
+ return [key, entryValue];
8041
+ })
8042
+ );
8043
+ }
8044
+ function hydrateNestedStringMap(value, field) {
8045
+ return new Map(
8046
+ requireArtifactEntryArray(value, field).map(([outerKey, innerValue]) => {
8047
+ const nested = new Map(
8048
+ requireArtifactEntryArray(innerValue, `${field}.${outerKey}`).map(([innerKey, nestedValue]) => {
8049
+ if (typeof nestedValue !== "string") {
8050
+ throw new ReplayConfigError(
8051
+ "compilation_failed",
8052
+ `Approved governance artifact has invalid ${field}.${outerKey}.${innerKey}`
8053
+ );
8054
+ }
8055
+ return [innerKey, nestedValue];
8056
+ })
8057
+ );
8058
+ return [outerKey, nested];
8059
+ })
8060
+ );
8061
+ }
8062
+ function hydratePolicyProgram(value) {
8063
+ if (value == null) return null;
8064
+ const policyProgram = requireArtifactRecord(value, "policyProgram");
8065
+ if (typeof policyProgram.defaultDeny !== "boolean" || !Array.isArray(policyProgram.sessionRules)) {
8066
+ throw new ReplayConfigError(
8067
+ "compilation_failed",
8068
+ "Approved governance artifact has invalid policyProgram"
8069
+ );
8070
+ }
8071
+ return {
8072
+ defaultDeny: policyProgram.defaultDeny,
8073
+ sessionRules: policyProgram.sessionRules,
8074
+ perToolRules: new Map(
8075
+ requireArtifactEntryArray(policyProgram.perToolRules ?? [], "policyProgram.perToolRules").map(
8076
+ ([toolName, ruleValue]) => [toolName, requireArtifactRecord(ruleValue, `policyProgram.perToolRules.${toolName}`)]
8077
+ )
8078
+ )
8079
+ };
8080
+ }
8081
+ function rehydrateCompiledSessionArtifact(artifact, expectedHash) {
8082
+ const record = requireArtifactRecord(artifact, "compiled_session");
8083
+ if (typeof record.agent !== "string" || typeof record.schemaVersion !== "string") {
8084
+ throw new ReplayConfigError(
8085
+ "compilation_failed",
8086
+ "Approved governance artifact is missing required session metadata"
8087
+ );
8088
+ }
8089
+ if (record.phases != null && !Array.isArray(record.phases)) {
8090
+ throw new ReplayConfigError(
8091
+ "compilation_failed",
8092
+ "Approved governance artifact has invalid phases"
8093
+ );
8094
+ }
8095
+ if (!Array.isArray(record.contractHashes) || record.contractHashes.some((hash) => typeof hash !== "string")) {
8096
+ throw new ReplayConfigError(
8097
+ "compilation_failed",
8098
+ "Approved governance artifact has invalid contractHashes"
8099
+ );
8100
+ }
8101
+ const compiledSession = {
8102
+ agent: record.agent,
8103
+ schemaVersion: record.schemaVersion,
8104
+ phases: record.phases ?? null,
8105
+ transitions: hydrateStringArrayMap(record.transitions ?? [], "transitions"),
8106
+ sessionLimits: record.sessionLimits ?? {},
8107
+ perToolContracts: hydrateContractMap(record.perToolContracts ?? [], "perToolContracts"),
8108
+ riskDefaults: requireArtifactRecord(record.riskDefaults ?? {}, "riskDefaults"),
8109
+ providerConstraints: record.providerConstraints ?? null,
8110
+ contractHashes: record.contractHashes,
8111
+ compiledHash: "",
8112
+ principal: null,
8113
+ policyProgram: hydratePolicyProgram(record.policyProgram),
8114
+ executionConstraints: hydrateExecutionConstraintMap(record.executionConstraints ?? [], "executionConstraints"),
8115
+ toolExecutors: null,
8116
+ resources: hydrateNestedStringMap(record.resources ?? [], "resources"),
8117
+ warnings: [],
8118
+ graphDiagnostics: [],
8119
+ schemaDerivedDiagnostics: [],
8120
+ aggregates: Array.isArray(record.aggregates) ? record.aggregates : [],
8121
+ envelopes: Array.isArray(record.envelopes) ? record.envelopes : [],
8122
+ labelGates: Array.isArray(record.labelGates) ? record.labelGates : [],
8123
+ checkpoints: Array.isArray(record.checkpoints) ? record.checkpoints : []
8124
+ };
8125
+ const serialized = serializeCompiledSession(compiledSession);
8126
+ const computedHash = crypto5.createHash("sha256").update(serialized).digest("hex");
8127
+ compiledSession.compiledHash = computedHash;
8128
+ if (expectedHash && expectedHash !== computedHash) {
8129
+ throw new ReplayConfigError(
8130
+ "compilation_failed",
8131
+ `Approved governance artifact hash mismatch: expected ${expectedHash}, got ${computedHash}`
8132
+ );
8133
+ }
8134
+ return compiledSession;
8135
+ }
8136
+ function createDetachedProviderClient(provider, terminal, originalCreate) {
8137
+ const boundCreate = (...args) => originalCreate.apply(terminal, args);
8138
+ if (provider === "openai") {
8139
+ return {
8140
+ chat: {
8141
+ completions: {
8142
+ create: boundCreate
8143
+ }
8144
+ }
8145
+ };
8146
+ }
8147
+ return {
8148
+ messages: {
8149
+ create: boundCreate
8150
+ }
8151
+ };
8152
+ }
7966
8153
  function resolveGovernanceEnvironment(opts) {
7967
8154
  if (opts.environment) return opts.environment;
7968
8155
  const envVar = typeof process !== "undefined" ? process.env.REPLAYCI_ENVIRONMENT : void 0;
@@ -7985,7 +8172,7 @@ function governanceProtectionLevel(env) {
7985
8172
  }
7986
8173
  function createGovernanceSession(client, sessionId, agent, provider, apiKey, opts, diagnostics) {
7987
8174
  const environment = resolveGovernanceEnvironment(opts);
7988
- const protLevel = governanceProtectionLevel(environment);
8175
+ const observeProtectionLevel = governanceProtectionLevel(environment);
7989
8176
  const runtimeClient = new RuntimeClient({
7990
8177
  apiKey,
7991
8178
  apiUrl: opts.runtimeUrl
@@ -7994,13 +8181,22 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
7994
8181
  let planFetchPromise = null;
7995
8182
  let planFetchDone = false;
7996
8183
  let planFetchError = null;
8184
+ let planFetchErrorCode = null;
8185
+ let approvedRuntimeSession = null;
8186
+ let approvedRuntimeInitPromise = null;
8187
+ let approvedRuntimeInitError = null;
7997
8188
  planFetchPromise = runtimeClient.fetchGovernancePlan(agent, environment).then((result) => {
7998
8189
  governancePlan = result;
7999
8190
  planFetchDone = true;
8191
+ if (!hasApprovedGovernanceArtifact(result)) {
8192
+ emitDiagnostic2(diagnostics, { type: "replay_governance_no_plan", session_id: sessionId, environment });
8193
+ }
8000
8194
  }).catch((err) => {
8001
8195
  planFetchDone = true;
8002
8196
  planFetchError = err instanceof Error ? err.message : String(err);
8197
+ planFetchErrorCode = err instanceof RuntimeClientError ? err.code : null;
8003
8198
  governancePlan = null;
8199
+ emitDiagnostic2(diagnostics, { type: "replay_governance_fetch_failed", session_id: sessionId, details: planFetchError });
8004
8200
  });
8005
8201
  const captureBuffer = new CaptureBuffer({
8006
8202
  apiKey,
@@ -8013,12 +8209,139 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
8013
8209
  return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
8014
8210
  }
8015
8211
  const { terminal, originalCreate } = terminalInfo;
8212
+ const fallbackTools = buildWrappedToolsMap(opts.tools, null);
8213
+ function hasApprovedGovernanceArtifact(plan) {
8214
+ return Boolean(
8215
+ plan && (plan.status === "approved" || plan.status === "enforcing")
8216
+ );
8217
+ }
8218
+ async function ensureApprovedRuntimeSession() {
8219
+ if (approvedRuntimeSession) return approvedRuntimeSession;
8220
+ if (approvedRuntimeInitError) throw approvedRuntimeInitError;
8221
+ if (approvedRuntimeInitPromise) {
8222
+ await approvedRuntimeInitPromise;
8223
+ if (approvedRuntimeInitError) throw approvedRuntimeInitError;
8224
+ return approvedRuntimeSession;
8225
+ }
8226
+ approvedRuntimeInitPromise = (async () => {
8227
+ if (!hasApprovedGovernanceArtifact(governancePlan)) {
8228
+ throw new ReplayConfigError(
8229
+ "compilation_failed",
8230
+ "Approved governance artifact was not available for runtime enforcement"
8231
+ );
8232
+ }
8233
+ if (!governancePlan?.compiledSession) {
8234
+ throw new ReplayConfigError(
8235
+ "compilation_failed",
8236
+ "Approved governance plan is missing compiled_session"
8237
+ );
8238
+ }
8239
+ if (!governancePlan.compiledHash) {
8240
+ throw new ReplayConfigError(
8241
+ "compilation_failed",
8242
+ "Approved governance plan is missing compiled_hash"
8243
+ );
8244
+ }
8245
+ const compiledSession = rehydrateCompiledSessionArtifact(
8246
+ governancePlan.compiledSession,
8247
+ governancePlan.compiledHash
8248
+ );
8249
+ const preparedContracts = createPreparedContractsFromCompiledSession(compiledSession);
8250
+ const detachedClient = createDetachedProviderClient(
8251
+ provider,
8252
+ terminal,
8253
+ originalCreate
8254
+ );
8255
+ const approvedMode = environment === "development" ? "shadow" : "enforce";
8256
+ const approvedCompatEnforcement = environment === "staging" ? "advisory" : opts.compatEnforcement ?? "protective";
8257
+ approvedRuntimeSession = replay(detachedClient, {
8258
+ ...opts,
8259
+ agent,
8260
+ sessionId,
8261
+ apiKey,
8262
+ mode: approvedMode,
8263
+ compatEnforcement: approvedCompatEnforcement,
8264
+ contracts: void 0,
8265
+ contractsDir: void 0,
8266
+ sessionYamlPath: void 0,
8267
+ environment: void 0,
8268
+ __preparedContracts: preparedContracts,
8269
+ __compiledSession: compiledSession,
8270
+ __disableRuntimeControlPlane: true
8271
+ });
8272
+ emitDiagnostic2(diagnostics, { type: "replay_governance_attached", session_id: sessionId, environment });
8273
+ })().catch((err) => {
8274
+ approvedRuntimeInitError = err instanceof Error ? err : new ReplayConfigError("compilation_failed", String(err));
8275
+ const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
8276
+ emitDiagnostic2(diagnostics, {
8277
+ type: isArtifactInvalid ? "replay_governance_artifact_invalid" : "replay_governance_attachment_failed",
8278
+ session_id: sessionId,
8279
+ details: approvedRuntimeInitError.message
8280
+ });
8281
+ emitDiagnostic2(diagnostics, {
8282
+ type: "replay_compile_error",
8283
+ details: approvedRuntimeInitError.message
8284
+ });
8285
+ });
8286
+ await approvedRuntimeInitPromise;
8287
+ if (approvedRuntimeInitError) throw approvedRuntimeInitError;
8288
+ return approvedRuntimeSession;
8289
+ }
8290
+ async function invokeApprovedRuntimeCreate(args) {
8291
+ const runtimeSession = await ensureApprovedRuntimeSession();
8292
+ if (provider === "openai") {
8293
+ return runtimeSession.client.chat.completions.create(...args);
8294
+ }
8295
+ return runtimeSession.client.messages.create(...args);
8296
+ }
8297
+ const tools = opts.tools ? new Proxy(fallbackTools, {
8298
+ get(_target, prop) {
8299
+ if (typeof prop !== "string") return void 0;
8300
+ if (approvedRuntimeSession?.tools[prop]) {
8301
+ return approvedRuntimeSession.tools[prop];
8302
+ }
8303
+ return fallbackTools[prop];
8304
+ },
8305
+ has(_target, prop) {
8306
+ if (typeof prop !== "string") return false;
8307
+ return Boolean(approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]);
8308
+ },
8309
+ ownKeys() {
8310
+ const keys = /* @__PURE__ */ new Set([
8311
+ ...Reflect.ownKeys(fallbackTools),
8312
+ ...Reflect.ownKeys(approvedRuntimeSession?.tools ?? {})
8313
+ ]);
8314
+ return Array.from(keys);
8315
+ },
8316
+ getOwnPropertyDescriptor(_target, prop) {
8317
+ if (typeof prop !== "string") return void 0;
8318
+ if (approvedRuntimeSession?.tools[prop] || fallbackTools[prop]) {
8319
+ return {
8320
+ configurable: true,
8321
+ enumerable: true,
8322
+ writable: false,
8323
+ value: approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]
8324
+ };
8325
+ }
8326
+ return void 0;
8327
+ }
8328
+ }) : {};
8016
8329
  const patchedCreate = async function(...args) {
8017
8330
  if (!planFetchDone && planFetchPromise) {
8018
8331
  await planFetchPromise;
8019
8332
  }
8020
- const hasApprovedPlan = governancePlan && (governancePlan.status === "approved" || governancePlan.status === "enforcing") && governancePlan.compiledSession;
8021
- if (hasApprovedPlan) {
8333
+ if (planFetchError) {
8334
+ const artifactBroken = planFetchErrorCode === "APPROVED_ARTIFACT_INVALID";
8335
+ const requiresEnforcement = observeProtectionLevel !== "monitor";
8336
+ if (artifactBroken || requiresEnforcement) {
8337
+ throw new ReplayConfigError(
8338
+ "governance_unavailable",
8339
+ `Governance plan fetch failed (fail-closed): ${planFetchError}`
8340
+ );
8341
+ }
8342
+ }
8343
+ if (hasApprovedGovernanceArtifact(governancePlan)) {
8344
+ return invokeApprovedRuntimeCreate(args);
8022
8345
  }
8023
8346
  const result = await originalCreate.apply(this, args);
8024
8347
  try {
@@ -8047,40 +8370,81 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
8047
8370
  setReplayAttached(client);
8048
8371
  return {
8049
8372
  client,
8050
- flush: () => captureBuffer.flush(),
8373
+ flush: () => approvedRuntimeSession ? approvedRuntimeSession.flush() : captureBuffer.flush(),
8051
8374
  restore() {
8052
8375
  terminal[terminalInfo.methodName] = originalCreate;
8376
+ approvedRuntimeSession?.restore();
8377
+ clearReplayAttached(client);
8053
8378
  },
8054
8379
  kill() {
8380
+ approvedRuntimeSession?.kill();
8055
8381
  },
8056
- getHealth: () => ({
8057
- status: "healthy",
8058
- authorityState: "active",
8059
- protectionLevel: protLevel,
8060
- durability: "inactive",
8061
- tier: "compat",
8062
- compatEnforcement: "protective",
8063
- cluster_detected: false,
8064
- bypass_detected: false,
8065
- totalSteps: 0,
8066
- totalBlocks: 0,
8067
- totalErrors: 0,
8068
- killed: false,
8069
- shadowEvaluations: 0
8070
- }),
8071
- getState: () => EMPTY_STATE_SNAPSHOT,
8072
- getLastNarrowing: () => null,
8073
- getLastShadowDelta: () => null,
8074
- getLastTrace: () => null,
8075
- narrow() {
8382
+ getHealth: () => {
8383
+ if (approvedRuntimeSession) {
8384
+ const inner = approvedRuntimeSession.getHealth();
8385
+ return { ...inner, governanceAttachment: "attached" };
8386
+ }
8387
+ let governanceAttachment;
8388
+ let status;
8389
+ let authorityState;
8390
+ let totalErrors = 0;
8391
+ if (!planFetchDone) {
8392
+ governanceAttachment = "pending";
8393
+ status = "healthy";
8394
+ authorityState = "advisory";
8395
+ } else if (planFetchError) {
8396
+ governanceAttachment = "fetch_failed";
8397
+ status = "degraded";
8398
+ authorityState = "inactive";
8399
+ totalErrors = 1;
8400
+ } else if (approvedRuntimeInitError) {
8401
+ const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
8402
+ governanceAttachment = isArtifactInvalid ? "artifact_invalid" : "attachment_failed";
8403
+ status = "degraded";
8404
+ authorityState = "inactive";
8405
+ totalErrors = 1;
8406
+ } else if (!hasApprovedGovernanceArtifact(governancePlan)) {
8407
+ governanceAttachment = "no_plan";
8408
+ status = "healthy";
8409
+ authorityState = "advisory";
8410
+ } else {
8411
+ governanceAttachment = "pending";
8412
+ status = "healthy";
8413
+ authorityState = "advisory";
8414
+ }
8415
+ return {
8416
+ status,
8417
+ authorityState,
8418
+ protectionLevel: observeProtectionLevel,
8419
+ durability: "inactive",
8420
+ tier: "compat",
8421
+ compatEnforcement: "protective",
8422
+ cluster_detected: false,
8423
+ bypass_detected: false,
8424
+ totalSteps: 0,
8425
+ totalBlocks: 0,
8426
+ totalErrors,
8427
+ killed: false,
8428
+ shadowEvaluations: 0,
8429
+ governanceAttachment
8430
+ };
8431
+ },
8432
+ getState: () => approvedRuntimeSession ? approvedRuntimeSession.getState() : EMPTY_STATE_SNAPSHOT,
8433
+ getLastNarrowing: () => approvedRuntimeSession ? approvedRuntimeSession.getLastNarrowing() : null,
8434
+ getLastShadowDelta: () => approvedRuntimeSession ? approvedRuntimeSession.getLastShadowDelta() : null,
8435
+ getLastTrace: () => approvedRuntimeSession ? approvedRuntimeSession.getLastTrace() : null,
8436
+ narrow(...args) {
8437
+ approvedRuntimeSession?.narrow(...args);
8076
8438
  },
8077
8439
  widen() {
8440
+ approvedRuntimeSession?.widen();
8078
8441
  },
8079
- addLabel() {
8442
+ addLabel(label) {
8443
+ approvedRuntimeSession?.addLabel(label);
8080
8444
  },
8081
- tools: {},
8082
- getWorkflowState: () => Promise.resolve(null),
8083
- handoff: () => Promise.resolve(null)
8445
+ tools,
8446
+ getWorkflowState: () => approvedRuntimeSession ? approvedRuntimeSession.getWorkflowState() : Promise.resolve(null),
8447
+ handoff: (offer) => approvedRuntimeSession ? approvedRuntimeSession.handoff(offer) : Promise.resolve(null)
8084
8448
  };
8085
8449
  }
8086
8450
  function toNarrowingSnapshot(result) {
@@ -8257,6 +8621,9 @@ function determineProtectionLevel(mode, tools, contracts, apiKey) {
8257
8621
  const allWrapped = stateBearingTools.every((c) => wrappedTools.has(c.tool));
8258
8622
  return allWrapped ? "govern" : "protect";
8259
8623
  }
8624
+ function determineRuntimeFreeProtectionLevel(mode) {
8625
+ return mode === "enforce" ? "protect" : "monitor";
8626
+ }
8260
8627
  function isStateBearing(contract) {
8261
8628
  if (contract.commit_requirement != null && contract.commit_requirement !== "none") return true;
8262
8629
  if (contract.transitions != null) return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replayci/replay",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "ReplayCI SDK for deterministic tool-call validation and observation.",
5
5
  "license": "ISC",
6
6
  "author": "ReplayCI",
@@ -45,12 +45,14 @@
45
45
  ],
46
46
  "scripts": {
47
47
  "build": "tsup src/index.ts --format cjs,esm --dts",
48
+ "postbuild": "node scripts/check-dist-parity.mjs",
48
49
  "prepublishOnly": "npm run build",
50
+ "check-dist": "node scripts/check-dist-parity.mjs",
49
51
  "typecheck": "tsc --noEmit",
50
52
  "test": "vitest run"
51
53
  },
52
54
  "dependencies": {
53
- "@replayci/contracts-core": "^0.1.0",
55
+ "@replayci/contracts-core": "^0.1.11",
54
56
  "re2": "^1.20.0",
55
57
  "yaml": "^2.0.0"
56
58
  },