coderifts 5.0.0 → 5.0.1

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/cli.js CHANGED
@@ -3028,7 +3028,7 @@ var require_package = __commonJS({
3028
3028
  "package.json"(exports2, module2) {
3029
3029
  module2.exports = {
3030
3030
  name: "coderifts",
3031
- version: "5.0.0",
3031
+ version: "5.0.1",
3032
3032
  description: "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
3033
3033
  author: "CodeRifts <hello@coderifts.com>",
3034
3034
  license: "MIT",
@@ -3073,7 +3073,7 @@ var require_package = __commonJS({
3073
3073
  test: "node --test test/*.test.js"
3074
3074
  },
3075
3075
  dependencies: {
3076
- "@coderifts/agent-guard": "^11.0.0",
3076
+ "@coderifts/agent-guard": "^12.0.0",
3077
3077
  chalk: "^4.1.2",
3078
3078
  "cli-table3": "^0.6.4",
3079
3079
  commander: "^12.0.0",
@@ -66357,7 +66357,7 @@ var require_execution_time_fingerprint = __commonJS({
66357
66357
  exports2.authorizedFingerprintFromEnvelope = authorizedFingerprintFromEnvelope;
66358
66358
  exports2.checkExecutionTimeFingerprint = checkExecutionTimeFingerprint;
66359
66359
  var node_crypto_1 = require("node:crypto");
66360
- var NUL = "";
66360
+ var US = "";
66361
66361
  var BUNDLE_FP_DOMAIN = "crbundle.v1";
66362
66362
  function sha256hex(s) {
66363
66363
  return (0, node_crypto_1.createHash)("sha256").update(s, "utf8").digest("hex");
@@ -66372,13 +66372,13 @@ var require_execution_time_fingerprint = __commonJS({
66372
66372
  }
66373
66373
  function computeCanonicalBundleFingerprint(artifacts, context) {
66374
66374
  const sorted = artifacts.slice().sort((x, y) => {
66375
- const kx = `${x.type}${NUL}${x.id}`;
66376
- const ky = `${y.type}${NUL}${y.id}`;
66375
+ const kx = `${x.type}${US}${x.id}`;
66376
+ const ky = `${y.type}${US}${y.id}`;
66377
66377
  return kx < ky ? -1 : kx > ky ? 1 : 0;
66378
66378
  });
66379
66379
  const parts = [BUNDLE_FP_DOMAIN, String(artifacts.length)];
66380
66380
  for (const a of sorted) {
66381
- parts.push([a.type, a.id, sha256hex(specStr(a.before)), sha256hex(specStr(a.after))].join(NUL));
66381
+ parts.push([a.type, a.id, sha256hex(specStr(a.before)), sha256hex(specStr(a.after))].join(US));
66382
66382
  }
66383
66383
  const ctx = context || {};
66384
66384
  parts.push([
@@ -66388,8 +66388,8 @@ var require_execution_time_fingerprint = __commonJS({
66388
66388
  scalar(ctx.branch),
66389
66389
  scalar(ctx.pull_request),
66390
66390
  scalar(ctx.policy_profile)
66391
- ].join(NUL));
66392
- return `sha256:${sha256hex(parts.join(NUL))}`;
66391
+ ].join(US));
66392
+ return `sha256:${sha256hex(parts.join(US))}`;
66393
66393
  }
66394
66394
  exports2.EXECUTION_TIME_FP_REASONS = Object.freeze({
66395
66395
  MATCH: "match",
@@ -66485,7 +66485,7 @@ var require_enforcement_gate = __commonJS({
66485
66485
  function isAction(v) {
66486
66486
  return v === "CONTINUE" || v === "CONTINUE_WITH_MONITORING" || v === "REQUEST_APPROVAL" || v === "STOP";
66487
66487
  }
66488
- var NUL = "";
66488
+ var US = "";
66489
66489
  function sha256hex(s) {
66490
66490
  return (0, node_crypto_1.createHash)("sha256").update(s).digest("hex");
66491
66491
  }
@@ -66493,7 +66493,7 @@ var require_enforcement_gate = __commonJS({
66493
66493
  return v == null ? "" : typeof v === "string" ? v : JSON.stringify(v);
66494
66494
  }
66495
66495
  function computeArtifactDigest(artifacts) {
66496
- const preimage = artifacts.slice().sort((a, b) => `${a.type}${NUL}${a.id}` < `${b.type}${NUL}${b.id}` ? -1 : 1).map((a) => `${sha256hex(specStr(a.before))}${sha256hex(specStr(a.after))}`).join(NUL);
66496
+ const preimage = artifacts.slice().sort((a, b) => `${a.type}${US}${a.id}` < `${b.type}${US}${b.id}` ? -1 : 1).map((a) => `${sha256hex(specStr(a.before))}${sha256hex(specStr(a.after))}`).join(US);
66497
66497
  return `sha256:${sha256hex(preimage)}`;
66498
66498
  }
66499
66499
  function computeBundleFingerprint(artifacts, context) {
@@ -66699,7 +66699,8 @@ var require_execution_proof = __commonJS({
66699
66699
  if (input.preflighted !== true || input.receiptVerified !== true) {
66700
66700
  throw new Error("@coderifts/agent-guard: enforced:true without receiptVerified+preflighted (runtime invariant)");
66701
66701
  }
66702
- if (input.requireConditionalWrite === true && input.writeStyle === true) {
66702
+ const mutating = input.mutating === void 0 ? input.writeStyle === true : input.mutating === true;
66703
+ if (input.requireConditionalWrite === true && mutating) {
66703
66704
  if (input.conditionalWrite !== true) {
66704
66705
  throw new Error("@coderifts/agent-guard: enforced:true without conditional_write:true under requireConditionalWrite (runtime invariant)");
66705
66706
  }
@@ -66763,6 +66764,7 @@ var require_execution_proof = __commonJS({
66763
66764
  receiptVerified,
66764
66765
  requireConditionalWrite: cwb?.require_conditional_write,
66765
66766
  writeStyle: cwb?.write_style,
66767
+ mutating: cwb?.mutating,
66766
66768
  conditionalWrite: cwb?.conditional_write
66767
66769
  });
66768
66770
  const env = envelopeOf(input.verdict);
@@ -66854,6 +66856,7 @@ var require_freshness = __commonJS({
66854
66856
  exports2.assessWriteStylePrior = assessWriteStylePrior;
66855
66857
  exports2.freshnessAllowsEnforce = freshnessAllowsEnforce;
66856
66858
  exports2.isWriteStyleCall = isWriteStyleCall;
66859
+ exports2.isMutatingCall = isMutatingCall;
66857
66860
  exports2.artifactIdsForResolve = artifactIdsForResolve;
66858
66861
  exports2.collectFreshnessCallContext = collectFreshnessCallContext;
66859
66862
  exports2.buildFreshnessBasis = buildFreshnessBasis;
@@ -66987,6 +66990,24 @@ var require_freshness = __commonJS({
66987
66990
  }
66988
66991
  return false;
66989
66992
  }
66993
+ function isMutatingCall(call) {
66994
+ const arts = call.artifacts;
66995
+ if (Array.isArray(arts)) {
66996
+ for (const a of arts) {
66997
+ if (a && typeof a.after === "string" && a.after.length > 0)
66998
+ return true;
66999
+ }
67000
+ }
67001
+ const args = call.arguments && typeof call.arguments === "object" ? call.arguments : {};
67002
+ for (const k of ["contents", "content", "new_string", "old_string", "patch"]) {
67003
+ const v = args[k];
67004
+ if (typeof v === "string" && v.length > 0)
67005
+ return true;
67006
+ }
67007
+ if (Array.isArray(args.edits) && args.edits.length > 0)
67008
+ return true;
67009
+ return false;
67010
+ }
66990
67011
  function artifactIdsForResolve(call) {
66991
67012
  const ids = [];
66992
67013
  if (Array.isArray(call.artifacts)) {
@@ -67159,12 +67180,14 @@ var require_conditional_write = __commonJS({
67159
67180
  function buildConditionalWriteBasis(input) {
67160
67181
  const require_conditional_write2 = input.requireConditionalWrite === true;
67161
67182
  const write_style = input.writeStyle === true;
67183
+ const mutating = input.mutating === void 0 ? write_style : input.mutating === true;
67162
67184
  const ctx = input.ctx && typeof input.ctx === "object" ? input.ctx : {};
67163
67185
  const conditional_write = normalizeReport(ctx.conditional_write);
67164
67186
  const basis = {
67165
67187
  conditional_write,
67166
67188
  require_conditional_write: require_conditional_write2,
67167
- write_style
67189
+ write_style,
67190
+ mutating
67168
67191
  };
67169
67192
  if (conditional_write === true) {
67170
67193
  if (typeof ctx.conditioned_on_token === "string") {
@@ -67175,7 +67198,7 @@ var require_conditional_write = __commonJS({
67175
67198
  basis.conditioned_on_token = null;
67176
67199
  }
67177
67200
  }
67178
- if (write_style && require_conditional_write2 && conditional_write !== true) {
67201
+ if (mutating && require_conditional_write2 && conditional_write !== true) {
67179
67202
  return { basis, blockCause: "CONDITIONAL_WRITE_REQUIRED" };
67180
67203
  }
67181
67204
  return { basis };
@@ -67184,7 +67207,8 @@ var require_conditional_write = __commonJS({
67184
67207
  function conditionalWriteResidual(input) {
67185
67208
  if (input.requireConditionalWrite !== true)
67186
67209
  return null;
67187
- if (input.writeStyle !== true)
67210
+ const mutating = input.mutating === void 0 ? input.writeStyle === true : input.mutating === true;
67211
+ if (!mutating)
67188
67212
  return null;
67189
67213
  if (input.conditionalWrite === true)
67190
67214
  return null;
@@ -70303,9 +70327,11 @@ var require_guard = __commonJS({
70303
70327
  allowStaleContext: config.allowStaleContext
70304
70328
  });
70305
70329
  }
70306
- function conditionalWriteFor(config, redacted, ctx) {
70330
+ function conditionalWriteFor(config, redacted, ctx, detectedArts) {
70331
+ const mutating = (0, freshness_js_1.isMutatingCall)(redacted) || Array.isArray(detectedArts) && (0, freshness_js_1.isMutatingCall)({ artifacts: detectedArts });
70307
70332
  return (0, conditional_write_js_1.buildConditionalWriteBasis)({
70308
70333
  writeStyle: (0, freshness_js_1.isWriteStyleCall)(redacted),
70334
+ mutating,
70309
70335
  requireConditionalWrite: config.requireConditionalWrite === true,
70310
70336
  ctx
70311
70337
  });
@@ -70377,7 +70403,7 @@ var require_guard = __commonJS({
70377
70403
  }
70378
70404
  }
70379
70405
  {
70380
- const { blockCause } = conditionalWriteFor(config, redacted, cwctx);
70406
+ const { blockCause } = conditionalWriteFor(config, redacted, cwctx, detection.artifacts);
70381
70407
  if (blockCause === "CONDITIONAL_WRITE_REQUIRED") {
70382
70408
  breakerRecord(config);
70383
70409
  return closedIntegrity(config, blockCause, failPolicy, fctx, cwctx, redacted, detection.artifacts);
@@ -70388,7 +70414,7 @@ var require_guard = __commonJS({
70388
70414
  const count = breakers.get(config)?.fails.length ?? 0;
70389
70415
  const v = unavailableVerdict({ cause: "MISSING_ARTIFACT_CONTENT", failPolicy, resolution: "CLOSED", action: "STOP" }, count);
70390
70416
  const { basis } = freshnessFor(config, redacted, fctx, detection.artifacts);
70391
- const { basis: cw } = conditionalWriteFor(config, redacted, cwctx);
70417
+ const { basis: cw } = conditionalWriteFor(config, redacted, cwctx, detection.artifacts);
70392
70418
  return blocked(config, v, false, basis, cw);
70393
70419
  }
70394
70420
  if (failPolicy === "lkg" && !config.lkg) {
@@ -70425,7 +70451,7 @@ var require_guard = __commonJS({
70425
70451
  breakerRecord(config);
70426
70452
  const count = breakers.get(config)?.fails.length ?? 1;
70427
70453
  const { basis } = freshnessFor(config, redacted, fctx, detection.artifacts);
70428
- const { basis: cw } = conditionalWriteFor(config, redacted, cwctx);
70454
+ const { basis: cw } = conditionalWriteFor(config, redacted, cwctx, detection.artifacts);
70429
70455
  if (pf.integrity) {
70430
70456
  emit(config, { type: "breaker_tripped", at: iso(), cause: pf.cause });
70431
70457
  const v2 = unavailableVerdict({ cause: pf.cause, failPolicy, resolution: "CLOSED", action: "STOP" }, count);
@@ -70493,7 +70519,7 @@ var require_guard = __commonJS({
70493
70519
  }
70494
70520
  if (gate.verdict === "block-strict") {
70495
70521
  const { basis } = freshnessFor(config, redacted, fctx, detection.artifacts);
70496
- const { basis: cw } = conditionalWriteFor(config, redacted, cwctx);
70522
+ const { basis: cw } = conditionalWriteFor(config, redacted, cwctx, detection.artifacts);
70497
70523
  return gate.decision === "BLOCK" ? blocked(config, { kind: "BLOCK", action: "STOP", envelope, receiptVerified }, true, basis, cw, void 0, void 0, grantObs) : blocked(config, { kind: "APPROVAL", action: "REQUEST_APPROVAL", envelope, receiptVerified }, true, basis, cw, void 0, void 0, grantObs);
70498
70524
  }
70499
70525
  const kind = gate.kind;
@@ -70564,7 +70590,7 @@ var require_guard = __commonJS({
70564
70590
  breakerRecord(config);
70565
70591
  return closedIntegrity(config, freshBlock, failPolicy, fctx, cwctx, redacted, detection.artifacts, void 0, void 0, grantObs);
70566
70592
  }
70567
- const { basis: cwBasis, blockCause: cwBlock } = conditionalWriteFor(config, redacted, cwctx);
70593
+ const { basis: cwBasis, blockCause: cwBlock } = conditionalWriteFor(config, redacted, cwctx, detection.artifacts);
70568
70594
  if (cwBlock === "CONDITIONAL_WRITE_REQUIRED") {
70569
70595
  breakerRecord(config);
70570
70596
  return closedIntegrity(config, cwBlock, failPolicy, fctx, cwctx, redacted, detection.artifacts, void 0, void 0, grantObs);
@@ -70639,7 +70665,7 @@ var require_guard = __commonJS({
70639
70665
  emit(config, { type: "breaker_tripped", at: iso(), cause });
70640
70666
  const v = unavailableVerdict({ cause, failPolicy, resolution: "CLOSED", action: "STOP" }, count);
70641
70667
  const { basis } = freshnessFor(config, redacted, fctx, arts);
70642
- const { basis: cw } = conditionalWriteFor(config, redacted, cwctx);
70668
+ const { basis: cw } = conditionalWriteFor(config, redacted, cwctx, arts);
70643
70669
  return blocked(config, v, false, basis, cw, monitoring_delivery, monitoring_attestation, grantObs);
70644
70670
  }
70645
70671
  function isExpired(envelope) {
@@ -74818,7 +74844,8 @@ var require_execute_tool_call = __commonJS({
74818
74844
  var CW_NOT_REPORTED = Object.freeze({
74819
74845
  conditional_write: "not_reported",
74820
74846
  require_conditional_write: false,
74821
- write_style: false
74847
+ write_style: false,
74848
+ mutating: false
74822
74849
  });
74823
74850
  function notObserved() {
74824
74851
  return {
@@ -75271,9 +75298,9 @@ var require_cjs4 = __commonJS({
75271
75298
  "use strict";
75272
75299
  Object.defineProperty(exports2, "__esModule", { value: true });
75273
75300
  exports2.monitorAttestSigningInput = exports2.kidFromMonitoringAttestation = exports2.tryIssueMonitoringAttestation = exports2.DEFAULT_MONITORING_SINK_TIMEOUT_MS = exports2.ackBytes = exports2.verifyAckHmac = exports2.monitoringDeliveryFailClosed = exports2.formatMonitoringDeliveryLine = exports2.deliverMonitoring = exports2.hashObservedContent = exports2.observeCommit = exports2.deriveKeySignal = exports2.pathClass = exports2.classifyCommand = exports2.projectState = exports2.emptySessionState = exports2.computeTainted = exports2.evaluate = exports2.updateSession = exports2.SESSION_TAINT_VERSION = exports2.SessionTaintTracker = exports2.readDecision = exports2.EXECUTION_TIME_FP_REASONS = exports2.EXECUTION_STATE_UNMEASURABLE_NOTE = exports2.isUnmeasurableExecutionStateReason = exports2.computeCanonicalBundleFingerprint = exports2.authorizedFingerprintFromEnvelope = exports2.checkExecutionTimeFingerprint = exports2.computeBundleFingerprint = exports2.computeArtifactDigest = exports2.evaluateEnvelope = exports2.RECEIPT_PREV_NULL = exports2.decodeReceiptBodyPrev = exports2.previousReceiptCommitment = exports2.verifyReceiptChainLinkage = exports2.canonicalJson = exports2.computeBodyHash = exports2.bindReceiptToEnvelope = exports2.DETECTOR_VERSION = exports2.builtinDetector = exports2.resetPolicyWarnForTests = exports2.warnPolicyAbsentOnce = exports2.observePolicyPresence = exports2.detectPolicyPresence = exports2.policyPresenceOf = exports2.withPolicy = exports2.POLICY_ABSENT_WARN = exports2.POLICY_MARKER = exports2.CODERIFTS_POLICY = exports2.guardToolCall = void 0;
75274
- exports2.createRegistryVersionToken = exports2.DB_ABSENT_TOKEN = exports2.DB_VERSION_TOKEN_PREFIX = exports2.dbTokenRaw = exports2.writeDbIfUnchanged = exports2.createDbVersionToken = exports2.API_ABSENT_TOKEN = exports2.API_VERSION_TOKEN_PREFIX = exports2.apiTokenRaw = exports2.writeApiIfUnchanged = exports2.createApiVersionToken = exports2.FS_ABSENT_TOKEN = exports2.FS_VERSION_TOKEN_PREFIX = exports2.fsTokenContentHash = exports2.createFsPriorContentResolver = exports2.writeFileIfUnchanged = exports2.readVersionedFile = exports2.createFsVersionToken = exports2.StaleVersionTokenAbort = exports2.executeIfUnchanged = exports2.RESIDUAL_UNCONDITIONAL_WRITE = exports2.conditionalWriteResidual = exports2.tokensEqual = exports2.buildConditionalWriteBasis = exports2.buildFreshnessBasis = exports2.collectFreshnessCallContext = exports2.artifactIdsForResolve = exports2.isWriteStyleCall = exports2.freshnessAllowsEnforce = exports2.computePathSetTreeHash = exports2.contentByteIdentical = exports2.assessWriteStylePrior = exports2.assessFreshness = exports2.deriveProofBanner = exports2.attachProofToAgentResponse = exports2.renderFinalAnswerProof = exports2.EXECUTION_PROOF_SPEC = exports2.assertEnforcedReceiptInvariant = exports2.hashExecutionResult = exports2.buildExecutionProof = exports2.COVERAGE_ATTEST_ENVELOPE_TAG = exports2.COVERAGE_ATTEST_SIGNING_PREFIX = exports2.COVERAGE_ATTEST_VERSION = exports2.coverageAttestSigningInput = exports2.kidFromCoverageAttestation = exports2.tryIssueCoverageAttestation = exports2.MONITOR_ATTEST_ENVELOPE_TAG = exports2.MONITOR_ATTEST_SIGNING_PREFIX = exports2.MONITOR_ATTEST_VERSION = exports2.receiptDigestOfToken = void 0;
75275
- exports2.formatCoverageObservedLine = exports2.freezeCoverageObserved = exports2.createCoverageObserver = exports2.readExecutionGrantToken = exports2.isExecutionGrantEnabled = exports2.guardedFractionAmongRoutes = exports2.foldTableSettledCalls = exports2.withCodeRifts = exports2.AUTO_DERIVE_READ_TIMEOUT_MS = exports2.AUTO_DERIVE_SOURCE = exports2.defaultFsReader = exports2.normalizeAutoDerive = exports2.runAutoDerive = exports2.AUTO_RECHECK_MAX_CAP = exports2.clampMaxAttempts = exports2.normalizeAutoRecheck = exports2.runAutoRecheckLoop = exports2.coverageReport = exports2.DEPLOY_REPAIRABLE_REASONS = exports2.bindDeploy = exports2.verifyDeployReceiptToken = exports2.DEPLOY_RECEIPT_VIEW_SPEC = exports2.isVerifiedDeployReceiptView = exports2.asVerifiedDeployReceiptView = exports2.deployGate = exports2.gateDecision = exports2.RegistryConstructionError = exports2.guardToolRegistry = exports2.globToRegExp = exports2.matchGlob = exports2.blobMapKey = exports2.classifyByName = exports2.resolveArtifacts = exports2.REMEDIATION_LOOP_ATTESTATION_SPEC = exports2.isCasAttestation = exports2.readPriorBlockRemediation = exports2.readRemediationTransaction = exports2.buildRemediationLoopAttestation = exports2.COMMIT_EVIDENCE_MISSING = exports2.CAS_ATTESTATION_SPEC = exports2.strictCommitObservation = exports2.extractExecutorAttestationToken = exports2.evaluateCasEvidence = exports2.isExecuteIfUnchangedOutcome = exports2.isGuardExecutionProof = exports2.buildCasAttestation = exports2.REGISTRY_ABSENT_TOKEN = exports2.REGISTRY_VERSION_TOKEN_PREFIX = exports2.registryTokenRaw = exports2.writeRegistryIfUnchanged = void 0;
75276
- exports2.kidFromToolsetAttestation = exports2.tryIssueToolsetAttestation = exports2.toolsetAttestSigningInput = exports2.declarationEntriesFromTools = exports2.computeToolsetDigest = exports2.TOOLSET_ATTEST_STATEMENT = exports2.TOOLSET_ATTEST_ENVELOPE_TAG = exports2.TOOLSET_ATTEST_SIGNING_PREFIX = exports2.TOOLSET_ATTEST_VERSION = exports2.surfaceEnvelopeFields = exports2.isGuardOutcome = exports2.executeLangGraphToolCall = exports2.executeGeminiToolCall = exports2.executeAnthropicToolCall = exports2.executeOpenAIToolCall = exports2.executeProtectedTool = exports2.defaultSerializeGeminiToolResult = exports2.bindGeminiGuardOutcome = exports2.protectedToolToFunctionDeclaration = exports2.toGeminiTools = exports2.geminiToolAdapter = exports2.withCodeRiftsGemini = exports2.wrapWriteWithFsCas = exports2.inferFullFileWriteContent = exports2.inferFsPathFromArgs = exports2.FRESHNESS_RESOLVER_FIX = exports2.freshnessRefusalTeaching = exports2.formatGateRefusalBody = exports2.defaultSerializeLangGraphToolResult = exports2.bindLangGraphGuardOutcome = exports2.LangGraphToolsNotStructuredError = exports2.isLangGraphReactAgentTool = exports2.bindLangGraphTools = exports2.protectedToolToLangGraph = exports2.toLangGraphTools = exports2.langGraphToolAdapter = exports2.withCodeRiftsLangGraph = exports2.defaultSerializeAnthropicToolResult = exports2.bindAnthropicGuardOutcome = exports2.protectedToolToAnthropic = exports2.toAnthropicTools = exports2.anthropicToolAdapter = exports2.withCodeRiftsAnthropic = exports2.defaultSerializeOpenAIToolResult = exports2.bindOpenAIGuardOutcome = exports2.protectedToolToOpenAI = exports2.toOpenAITools = exports2.openAIToolAdapter = exports2.withCodeRiftsOpenAI = void 0;
75301
+ exports2.DB_ABSENT_TOKEN = exports2.DB_VERSION_TOKEN_PREFIX = exports2.dbTokenRaw = exports2.writeDbIfUnchanged = exports2.createDbVersionToken = exports2.API_ABSENT_TOKEN = exports2.API_VERSION_TOKEN_PREFIX = exports2.apiTokenRaw = exports2.writeApiIfUnchanged = exports2.createApiVersionToken = exports2.FS_ABSENT_TOKEN = exports2.FS_VERSION_TOKEN_PREFIX = exports2.fsTokenContentHash = exports2.createFsPriorContentResolver = exports2.writeFileIfUnchanged = exports2.readVersionedFile = exports2.createFsVersionToken = exports2.StaleVersionTokenAbort = exports2.executeIfUnchanged = exports2.RESIDUAL_UNCONDITIONAL_WRITE = exports2.conditionalWriteResidual = exports2.tokensEqual = exports2.buildConditionalWriteBasis = exports2.buildFreshnessBasis = exports2.collectFreshnessCallContext = exports2.artifactIdsForResolve = exports2.isMutatingCall = exports2.isWriteStyleCall = exports2.freshnessAllowsEnforce = exports2.computePathSetTreeHash = exports2.contentByteIdentical = exports2.assessWriteStylePrior = exports2.assessFreshness = exports2.deriveProofBanner = exports2.attachProofToAgentResponse = exports2.renderFinalAnswerProof = exports2.EXECUTION_PROOF_SPEC = exports2.assertEnforcedReceiptInvariant = exports2.hashExecutionResult = exports2.buildExecutionProof = exports2.COVERAGE_ATTEST_ENVELOPE_TAG = exports2.COVERAGE_ATTEST_SIGNING_PREFIX = exports2.COVERAGE_ATTEST_VERSION = exports2.coverageAttestSigningInput = exports2.kidFromCoverageAttestation = exports2.tryIssueCoverageAttestation = exports2.MONITOR_ATTEST_ENVELOPE_TAG = exports2.MONITOR_ATTEST_SIGNING_PREFIX = exports2.MONITOR_ATTEST_VERSION = exports2.receiptDigestOfToken = void 0;
75302
+ exports2.freezeCoverageObserved = exports2.createCoverageObserver = exports2.readExecutionGrantToken = exports2.isExecutionGrantEnabled = exports2.guardedFractionAmongRoutes = exports2.foldTableSettledCalls = exports2.withCodeRifts = exports2.AUTO_DERIVE_READ_TIMEOUT_MS = exports2.AUTO_DERIVE_SOURCE = exports2.defaultFsReader = exports2.normalizeAutoDerive = exports2.runAutoDerive = exports2.AUTO_RECHECK_MAX_CAP = exports2.clampMaxAttempts = exports2.normalizeAutoRecheck = exports2.runAutoRecheckLoop = exports2.coverageReport = exports2.DEPLOY_REPAIRABLE_REASONS = exports2.bindDeploy = exports2.verifyDeployReceiptToken = exports2.DEPLOY_RECEIPT_VIEW_SPEC = exports2.isVerifiedDeployReceiptView = exports2.asVerifiedDeployReceiptView = exports2.deployGate = exports2.gateDecision = exports2.RegistryConstructionError = exports2.guardToolRegistry = exports2.globToRegExp = exports2.matchGlob = exports2.blobMapKey = exports2.classifyByName = exports2.resolveArtifacts = exports2.REMEDIATION_LOOP_ATTESTATION_SPEC = exports2.isCasAttestation = exports2.readPriorBlockRemediation = exports2.readRemediationTransaction = exports2.buildRemediationLoopAttestation = exports2.COMMIT_EVIDENCE_MISSING = exports2.CAS_ATTESTATION_SPEC = exports2.strictCommitObservation = exports2.extractExecutorAttestationToken = exports2.evaluateCasEvidence = exports2.isExecuteIfUnchangedOutcome = exports2.isGuardExecutionProof = exports2.buildCasAttestation = exports2.REGISTRY_ABSENT_TOKEN = exports2.REGISTRY_VERSION_TOKEN_PREFIX = exports2.registryTokenRaw = exports2.writeRegistryIfUnchanged = exports2.createRegistryVersionToken = void 0;
75303
+ exports2.kidFromToolsetAttestation = exports2.tryIssueToolsetAttestation = exports2.toolsetAttestSigningInput = exports2.declarationEntriesFromTools = exports2.computeToolsetDigest = exports2.TOOLSET_ATTEST_STATEMENT = exports2.TOOLSET_ATTEST_ENVELOPE_TAG = exports2.TOOLSET_ATTEST_SIGNING_PREFIX = exports2.TOOLSET_ATTEST_VERSION = exports2.surfaceEnvelopeFields = exports2.isGuardOutcome = exports2.executeLangGraphToolCall = exports2.executeGeminiToolCall = exports2.executeAnthropicToolCall = exports2.executeOpenAIToolCall = exports2.executeProtectedTool = exports2.defaultSerializeGeminiToolResult = exports2.bindGeminiGuardOutcome = exports2.protectedToolToFunctionDeclaration = exports2.toGeminiTools = exports2.geminiToolAdapter = exports2.withCodeRiftsGemini = exports2.wrapWriteWithFsCas = exports2.inferFullFileWriteContent = exports2.inferFsPathFromArgs = exports2.FRESHNESS_RESOLVER_FIX = exports2.freshnessRefusalTeaching = exports2.formatGateRefusalBody = exports2.defaultSerializeLangGraphToolResult = exports2.bindLangGraphGuardOutcome = exports2.LangGraphToolsNotStructuredError = exports2.isLangGraphReactAgentTool = exports2.bindLangGraphTools = exports2.protectedToolToLangGraph = exports2.toLangGraphTools = exports2.langGraphToolAdapter = exports2.withCodeRiftsLangGraph = exports2.defaultSerializeAnthropicToolResult = exports2.bindAnthropicGuardOutcome = exports2.protectedToolToAnthropic = exports2.toAnthropicTools = exports2.anthropicToolAdapter = exports2.withCodeRiftsAnthropic = exports2.defaultSerializeOpenAIToolResult = exports2.bindOpenAIGuardOutcome = exports2.protectedToolToOpenAI = exports2.toOpenAITools = exports2.openAIToolAdapter = exports2.withCodeRiftsOpenAI = exports2.formatCoverageObservedLine = void 0;
75277
75304
  var guard_js_1 = require_guard();
75278
75305
  Object.defineProperty(exports2, "guardToolCall", { enumerable: true, get: function() {
75279
75306
  return guard_js_1.guardToolCall;
@@ -75509,6 +75536,9 @@ var require_cjs4 = __commonJS({
75509
75536
  Object.defineProperty(exports2, "isWriteStyleCall", { enumerable: true, get: function() {
75510
75537
  return freshness_js_1.isWriteStyleCall;
75511
75538
  } });
75539
+ Object.defineProperty(exports2, "isMutatingCall", { enumerable: true, get: function() {
75540
+ return freshness_js_1.isMutatingCall;
75541
+ } });
75512
75542
  Object.defineProperty(exports2, "artifactIdsForResolve", { enumerable: true, get: function() {
75513
75543
  return freshness_js_1.artifactIdsForResolve;
75514
75544
  } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coderifts",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
5
5
  "author": "CodeRifts <hello@coderifts.com>",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "test": "node --test test/*.test.js"
46
46
  },
47
47
  "dependencies": {
48
- "@coderifts/agent-guard": "^11.0.0",
48
+ "@coderifts/agent-guard": "^12.0.0",
49
49
  "chalk": "^4.1.2",
50
50
  "cli-table3": "^0.6.4",
51
51
  "commander": "^12.0.0",
@@ -25,13 +25,33 @@
25
25
  * rises anyway, because a semantics floor is about what the CLI may RUN against, not about what
26
26
  * it happens to import today — a fingerprint that disagrees with the server is exactly the class
27
27
  * of difference this gate exists to refuse.)
28
+ * 5.0.0: floor raised to 12 (requireConditionalWrite now FIRES on an ordinary mutation. Through
29
+ * 11.0.1 the policy gated on isWriteStyleCall, which answers "did the caller supply a both-sides
30
+ * snapshot" — the right question for FRESHNESS, which it was written for, and the wrong one for
31
+ * atomicity. So a mutation carrying artifacts[] with non-empty before AND after classified as
32
+ * not-write-style and the demand never fired: reproduced against the published 11.0.1 tarball,
33
+ * where the side effect RAN with enforced:true and conditional_write:"not_reported". It bites on
34
+ * the NORMAL path, not an exotic config, because the tool-registry defaultBinder lifts
35
+ * old_string/new_string and edits[] into exactly that shape — so an agent editing a contract
36
+ * artifact under ENFORCING_STRICT wrote unconditionally. 12.0.0 adds isMutatingCall and gates on
37
+ * it; ConditionalWriteBasis gains a required `mutating` field. COST MEASURED AS ZERO, the same
38
+ * way the 11-raise was: the CLI imports only deployGate, asVerifiedDeployReceiptView,
39
+ * DEPLOY_RECEIPT_VIEW_SPEC and matchGlob, whose implementing modules (deploy-gate.js,
40
+ * resolver-glob.js, deploy-receipt-token.js) are BYTE-IDENTICAL 11.0.1 -> 12.0.0; the CLI
41
+ * constructs no ConditionalWriteBasis and never sets requireConditionalWrite, so the one
42
+ * type-level break cannot reach it — it is JS besides. Suite on 12.0.0: 556/554/2, identical to
43
+ * 11.0.0 with a byte-identical failure set; the only edits the raise needed were this gate's own
44
+ * two value-pins in assert-guard-major-coverage.test.js, which exist to move with each recorded
45
+ * raise, and no product code. The floor rises anyway, because a semantics floor is about
46
+ * what the CLI may RUN against: a guard that silently skips the atomicity demand on an ordinary
47
+ * edit is exactly the class of difference this gate exists to refuse.)
28
48
  */
29
49
 
30
50
  const fs = require('fs');
31
51
  const path = require('path');
32
52
 
33
53
  /** Minimum acceptable major for @coderifts/agent-guard in THIS package (the CLI). */
34
- const MIN_GUARD_MAJOR = 11;
54
+ const MIN_GUARD_MAJOR = 12;
35
55
  const DEP = '@coderifts/agent-guard';
36
56
 
37
57
  /**
@@ -91,6 +111,18 @@ const CHECKOUTS = [
91
111
  * 11 makes the bump neither easier nor harder — the blocker is unchanged and the deferral still
92
112
  * holds for exactly the reason above, not for a residual shape that moved.
93
113
  *
114
+ *
115
+ * WHAT THE RESOLVED-RANGE CHECK SAYS ABOUT THIS ENTRY: NOTHING, and that is the correct
116
+ * answer rather than a lucky one. The check added for the 5.0.0 finding grades whether the
117
+ * DECLARED range and the RESOLVED install AGREE. The root declares ^3.0.0 and resolves 3.0.0,
118
+ * so they agree exactly and it reports "in range". The root's gap is not drift between its
119
+ * manifest and its tree — it is a deliberately LOW FLOOR, and a floor is a human decision this
120
+ * gate records rather than derives. That decision lives in `floor: 3` and the reason above.
121
+ *
122
+ * A check that DID flag it — "resolved major must equal the newest published major" — was
123
+ * considered and rejected: it would force exactly the bump the paragraphs above say must not
124
+ * be forced before the residual-precedence reconciliation. The gate must not legislate a
125
+ * decision it is only supposed to remember.
94
126
  * WHAT THE BUMP ROUND MUST DECIDE: whether the guard should emit all holding residuals (then
95
127
  * the app consumes gateOut.residuals and collectBindingResiduals is deleted), or whether the
96
128
  * single-slot shape is deliberate (then the app keeps its collector and the duplication is
@@ -148,6 +180,94 @@ function resolvedVersionFor(startDir) {
148
180
  return null;
149
181
  }
150
182
 
183
+ /**
184
+ * RESOLVED-VERSION GRADING — the half the floor check cannot do.
185
+ *
186
+ * WHY THIS EXISTS. coderifts@5.0.0 published declaring `@coderifts/agent-guard: ^11.0.0` while
187
+ * guard 12.0.0 was already out carrying a semantics break (requireConditionalWrite began firing on
188
+ * ordinary mutations). This gate PASSED, and it was not wrong to: it graded the declared floor
189
+ * (11 >= 11) and the resolved version (11.0.0 >= 11) against a constant a human maintains by hand.
190
+ * Both facts were true. Both were stale. A gate that can only compare against the last floor
191
+ * someone remembered to raise cannot notice a major it has never been told about.
192
+ *
193
+ * So the constant is not the whole gate. What CAN be checked without a registry call is whether
194
+ * the tree and the manifest AGREE — and they must agree in both directions:
195
+ *
196
+ * · resolved BELOW the declared range → a stale install. The suite measured an older guard than
197
+ * the one we ship against, so every "cost measured as zero" conclusion is about the wrong
198
+ * package.
199
+ * · resolved ABOVE the declared range → the more dangerous direction, and the one that produced
200
+ * this finding's shape. Staging a NEWER guard into node_modules to measure a raise, then
201
+ * publishing with the old range, means the suite proved something adopters never receive: they
202
+ * resolve the range, not our node_modules. A green suite over a version we do not declare is a
203
+ * false confidence, not a measurement.
204
+ *
205
+ * NOT RESOLVED IS A FAILURE, not a pass. The previous code returned a success line reading
206
+ * "not resolved in tree" — "we could not look" recorded as "we looked and it is fine", which is
207
+ * the exact fail-open class this repository refuses elsewhere (a 404 on the source_ref anchor is
208
+ * deliberately on the FAIL side for the same reason). A publish gate that verifies nothing must
209
+ * say so by failing.
210
+ *
211
+ * WHAT THIS STILL CANNOT DO, named rather than implied: it makes no network call, so it cannot
212
+ * know that a newer major exists. Raising the floor stays a human act with a recorded reason. This
213
+ * check only guarantees that what we measured is what we declare.
214
+ */
215
+
216
+ /** Parse "1.2.3" (ignoring any prerelease/build suffix) to [1,2,3], or null. */
217
+ function parseVersion(v) {
218
+ const m = /^(\d+)\.(\d+)\.(\d+)/.exec(String(v || '').trim());
219
+ return m ? [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)] : null;
220
+ }
221
+
222
+ /** -1 / 0 / 1 over [maj,min,pat] triples. */
223
+ function compareVersions(a, b) {
224
+ for (let i = 0; i < 3; i += 1) {
225
+ if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
226
+ }
227
+ return 0;
228
+ }
229
+
230
+ /**
231
+ * Inclusive lower bound and EXCLUSIVE upper bound for the range forms this gate already accepts.
232
+ * Deliberately dependency-free — the rest of this file is, and a publish gate that needs an
233
+ * install to run is a gate that stops running.
234
+ *
235
+ * ^1.2.3 -> [1.2.3, 2.0.0) ~1.2.3 -> [1.2.3, 1.3.0) >=1.2.3 -> [1.2.3, inf)
236
+ * 1.2.3 -> [1.2.3, 1.2.4) 1.x -> [1.0.0, 2.0.0)
237
+ * Anything else -> null (caller treats an unparseable range as unverifiable, never as satisfied).
238
+ */
239
+ function rangeBounds(range) {
240
+ const s = String(range || '').trim();
241
+ const m = /^(\^|~|>=|=)?\s*(\d+)(?:\.(\d+|x|\*))?(?:\.(\d+|x|\*))?/.exec(s);
242
+ if (!m) return null;
243
+ const op = m[1] || '';
244
+ const maj = parseInt(m[2], 10);
245
+ const minRaw = m[3];
246
+ const patRaw = m[4];
247
+ const wild = (t) => t === undefined || t === 'x' || t === '*';
248
+ const min = wild(minRaw) ? 0 : parseInt(minRaw, 10);
249
+ const pat = wild(patRaw) ? 0 : parseInt(patRaw, 10);
250
+ const lower = [maj, min, pat];
251
+ if (wild(minRaw)) return { lower, upper: [maj + 1, 0, 0] }; // 1.x
252
+ if (op === '^') return { lower, upper: [maj + 1, 0, 0] };
253
+ if (op === '~') return { lower, upper: [maj, min + 1, 0] };
254
+ if (op === '>=') return { lower, upper: null };
255
+ if (wild(patRaw)) return { lower, upper: [maj, min + 1, 0] }; // 1.2.x
256
+ return { lower, upper: [maj, min, pat + 1] }; // exact
257
+ }
258
+
259
+ /**
260
+ * @returns {'in'|'below'|'above'|'unknown'} where `version` sits relative to `range`.
261
+ */
262
+ function versionVsRange(version, range) {
263
+ const v = parseVersion(version);
264
+ const b = rangeBounds(range);
265
+ if (!v || !b) return 'unknown';
266
+ if (compareVersions(v, b.lower) < 0) return 'below';
267
+ if (b.upper && compareVersions(v, b.upper) >= 0) return 'above';
268
+ return 'in';
269
+ }
270
+
151
271
  /** Check ONE checkout. Returns a line for the summary; calls fail() and exits on a violation. */
152
272
  function checkCheckout(c) {
153
273
  if (!fs.existsSync(c.pkgPath)) {
@@ -173,7 +293,15 @@ function checkCheckout(c) {
173
293
 
174
294
  const resolved = resolvedVersionFor(path.dirname(c.pkgPath));
175
295
  if (!resolved) {
176
- return `${c.label}: declared ${range} (floor ${floor} >= ${c.floor}); not resolved in tree`;
296
+ // FAIL-CLOSED, with NO opt-out. An `allowUnresolved` flag was written and then removed on
297
+ // purpose: the first time this fires in CI the cheapest response is to set the flag, and the
298
+ // hole is back with a config line to justify it. If a checkout ever legitimately ships
299
+ // uninstalled, add the exemption THEN, with the measurement that earned it.
300
+ fail(
301
+ `${c.label}: ${DEP} is declared ${JSON.stringify(range)} but is NOT RESOLVABLE from `
302
+ + `${path.dirname(c.pkgPath)}. This gate cannot verify what will ship, and an unverified `
303
+ + 'publish is not a verified one. Install dependencies for this checkout and re-run.',
304
+ );
177
305
  }
178
306
  const rm = /^(\d+)/.exec(resolved);
179
307
  const rMajor = rm ? parseInt(rm[1], 10) : null;
@@ -183,7 +311,32 @@ function checkCheckout(c) {
183
311
  if (rMajor < floor) {
184
312
  fail(`${c.label}: resolved ${DEP}@${resolved} major ${rMajor} is below declared range floor ${floor}`);
185
313
  }
186
- return `${c.label}: declared ${range} (floor ${floor} >= ${c.floor}); resolved ${resolved}`;
314
+
315
+ // THE DECLARED RANGE AND THE INSTALLED TREE MUST AGREE — both directions, full precision.
316
+ const where = versionVsRange(resolved, range);
317
+ if (where === 'below') {
318
+ fail(
319
+ `${c.label}: resolved ${DEP}@${resolved} is BELOW the declared range ${JSON.stringify(range)} `
320
+ + '— a stale install. Every cost measured against this tree describes an older guard than the '
321
+ + 'one this package declares. Run npm install for this checkout and re-measure.',
322
+ );
323
+ }
324
+ if (where === 'above') {
325
+ fail(
326
+ `${c.label}: resolved ${DEP}@${resolved} is ABOVE the declared range ${JSON.stringify(range)}. `
327
+ + 'The tree runs a guard this package does not declare, so the suite measured a version '
328
+ + 'adopters will never receive — they resolve the range, not our node_modules. Either raise '
329
+ + `the declared range to admit ${resolved} (and record WHY in the history block), or remove `
330
+ + 'the staged install.',
331
+ );
332
+ }
333
+ if (where === 'unknown') {
334
+ fail(
335
+ `${c.label}: cannot decide whether resolved ${DEP}@${resolved} satisfies declared range `
336
+ + `${JSON.stringify(range)} — unparseable. A range this gate cannot grade must not ship.`,
337
+ );
338
+ }
339
+ return `${c.label}: declared ${range} (floor ${floor} >= ${c.floor}); resolved ${resolved} (in range)`;
187
340
  }
188
341
 
189
342
  function main() {
@@ -206,4 +359,7 @@ function main() {
206
359
  // floorMajorFromRange without triggering a process.exit.
207
360
  if (require.main === module) main();
208
361
 
209
- module.exports = { CHECKOUTS, floorMajorFromRange, MIN_GUARD_MAJOR, DEP };
362
+ module.exports = {
363
+ CHECKOUTS, floorMajorFromRange, MIN_GUARD_MAJOR, DEP,
364
+ parseVersion, compareVersions, rangeBounds, versionVsRange, resolvedVersionFor,
365
+ };