witnora 0.18.10 → 0.18.11

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/gateway.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createHash, createPrivateKey, createPublicKey, randomBytes } from "node:crypto";
1
+ import { createHash, createPrivateKey, createPublicKey, randomBytes, randomUUID } from "node:crypto";
2
2
  import { spawn } from "node:child_process";
3
3
  import { closeSync, openSync } from "node:fs";
4
4
  import { access, chmod, mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
@@ -8,6 +8,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
8
8
  import { loadConnection } from "./credentials.js";
9
9
  import { authorizeProjectConnection } from "./device-authorization.js";
10
10
  import { verifyHostedProbeCredential } from "./runtime-bootstrap.js";
11
+ import { activateRealPathIntegrations } from "./real-path-activation.js";
11
12
  import { inspectIsolatedOutcomeProbe, observeInIsolatedOutcomeProbe } from "./probe-process.js";
12
13
  import { findAvailableRuntimeSandboxOrigin, LOCAL_SANDBOX_FIXTURE_CONTRACT_SHA256, startRuntimeSandboxFixture, } from "./runtime-sandbox-fixture.js";
13
14
  import { generateRuntimeSandboxKit, LOCAL_SANDBOX_ADAPTER_ID, LOCAL_SANDBOX_ADAPTER_VERSION, LOCAL_SANDBOX_PROBE_ID, } from "./runtime-sandbox-kit.js";
@@ -509,10 +510,6 @@ export async function runCustomerGateway(options) {
509
510
  throw new Error("The saved Gateway credential does not match gateway.json. Run gateway init again.");
510
511
  }
511
512
  const dataDirectory = resolve(directory, config.storageDirectory);
512
- const workflowHarnessConfigPath = join(directory, "workflow-harness.json");
513
- const workflowHarnessConfig = await exists(workflowHarnessConfigPath)
514
- ? parseManagedWorkflowHarnessConfig(await readFile(workflowHarnessConfigPath, "utf8"))
515
- : undefined;
516
513
  const keyRingPath = join(dataDirectory, "source-keys.json");
517
514
  const keyRing = await (await exists(keyRingPath)
518
515
  ? CustomerSourceKeyRing.open(keyRingPath)
@@ -534,16 +531,10 @@ export async function runCustomerGateway(options) {
534
531
  FileActionCheckpointStore: (await durableWorker).FileActionCheckpointStore,
535
532
  })
536
533
  : undefined;
537
- const workflowHarness = workflowHarnessConfig
538
- ? await createConfiguredWorkflowHarness({
539
- directory,
540
- projectId: config.projectId,
541
- server: config.server,
542
- apiKey: connection.apiKey,
543
- config: workflowHarnessConfig,
544
- managed: await configManagedWorkflowHarnessImport(),
545
- })
546
- : undefined;
534
+ const assuranceController = await createContinuousAssuranceController({
535
+ repository: resolve(directory, "..", ".."), directory, projectId: config.projectId, server: config.server,
536
+ apiKey: connection.apiKey, config, sourceSigner: () => keyRing.activeSigner(),
537
+ });
547
538
  actionWorker?.start();
548
539
  const gateway = await startCustomerOwnedCollectorGateway({
549
540
  client: new RemoteCollectorClient({ baseUrl: connection.server, projectId: connection.projectId, apiKey: connection.apiKey }),
@@ -592,19 +583,17 @@ export async function runCustomerGateway(options) {
592
583
  fixtureReady: false,
593
584
  } } : {}),
594
585
  } } : {}),
595
- ...(workflowHarnessConfig?.schemaVersion === MANAGED_WORKFLOW_HARNESS_SCHEMA && workflowHarness
596
- ? { assuranceHarness: { status: () => workflowHarness.status() } }
597
- : {}),
586
+ assuranceHarness: { status: () => assuranceController.status() },
598
587
  });
599
- workflowHarness?.start();
588
+ assuranceController.start();
600
589
  process.stdout.write(`Witnora customer-owned Gateway listening on ${gateway.baseUrl}\n`);
601
590
  process.stdout.write(config.runtimeWorker
602
591
  ? "Runtime worker: READY. Approved exact configured actions execute automatically, then use the separate read-only probe and Hosted signed receipt.\n"
603
592
  : "Evidence ceiling: RECORDED. No exact target adapter and separate outcome probe are configured, so runtime writes remain fail-closed.\n");
604
- if (workflowHarness)
605
- process.stdout.write("Managed Workflow Harness: CONFIGURED. Only authority-ready Replay and no-write Shadow evaluations will be sent to the pinned customer evaluator.\n");
593
+ if (await assuranceController.status())
594
+ process.stdout.write("Managed Workflow Harness: ACTIVE. Approved task changes are detected and revalidated automatically.\n");
606
595
  for (const signal of ["SIGINT", "SIGTERM"]) {
607
- process.once(signal, () => void Promise.allSettled([gateway.close(), ...(workflowHarness ? [workflowHarness.close()] : []), ...(sandboxFixture ? [sandboxFixture.close()] : [])]).finally(() => process.exit(0)));
596
+ process.once(signal, () => void Promise.allSettled([gateway.close(), assuranceController.close(), ...(sandboxFixture ? [sandboxFixture.close()] : [])]).finally(() => process.exit(0)));
608
597
  }
609
598
  }
610
599
  catch (error) {
@@ -727,6 +716,210 @@ export async function createConfiguredWorkflowHarness(input) {
727
716
  tick,
728
717
  };
729
718
  }
719
+ function configSignedChangeManifestImport() {
720
+ return import(new URL("./vendor/onegent-runtime/signed-change-manifest.js", import.meta.url).href);
721
+ }
722
+ /**
723
+ * Reconciles the existing approved-task, Real Path, Manifest, and Autopilot
724
+ * contracts from inside the already-running Gateway. No new service or durable
725
+ * orchestration state is introduced; local config remains the recoverable cache.
726
+ */
727
+ export async function createContinuousAssuranceController(input) {
728
+ const request = input.fetch ?? fetch;
729
+ const managed = input.managed ?? await configManagedWorkflowHarnessImport();
730
+ let harness;
731
+ let harnessFingerprint;
732
+ let timer;
733
+ let reconciling = false;
734
+ let closing = false;
735
+ let lastReportedError;
736
+ const replaceHarness = async (config) => {
737
+ const fingerprint = createHash("sha256").update(JSON.stringify(config)).digest("hex");
738
+ if (harness && fingerprint === harnessFingerprint)
739
+ return;
740
+ const next = await createConfiguredWorkflowHarness({
741
+ directory: input.directory,
742
+ projectId: input.projectId,
743
+ server: input.server,
744
+ apiKey: input.apiKey,
745
+ config,
746
+ managed,
747
+ evaluatorKit: input.evaluatorKit,
748
+ fetch: request,
749
+ });
750
+ next.start();
751
+ const previous = harness;
752
+ harness = next;
753
+ harnessFingerprint = fingerprint;
754
+ await previous?.close();
755
+ };
756
+ const workflowHarnessPath = join(input.directory, "workflow-harness.json");
757
+ if (await exists(workflowHarnessPath)) {
758
+ try {
759
+ await replaceHarness(parseManagedWorkflowHarnessConfig(await readFile(workflowHarnessPath, "utf8")));
760
+ }
761
+ catch (error) {
762
+ lastReportedError = message(error);
763
+ process.stderr.write(`Existing Assurance Harness will be repaired in the background: ${lastReportedError}\n`);
764
+ }
765
+ }
766
+ const reconcile = async () => {
767
+ if (closing || reconciling)
768
+ return;
769
+ reconciling = true;
770
+ try {
771
+ const activation = await activateRealPathIntegrations({
772
+ repository: input.repository,
773
+ server: input.server,
774
+ projectId: input.projectId,
775
+ apiKey: input.apiKey,
776
+ fetch: request,
777
+ });
778
+ if (activation.state === "READY_TO_START") {
779
+ const configured = await activateManagedWorkflowHarness({
780
+ repository: input.repository,
781
+ modulePath: activation.modulePath,
782
+ realPathActivations: activation.activations,
783
+ previousGeneratedModuleSha256: activation.previousGeneratedModuleSha256,
784
+ });
785
+ await replaceHarness(configured.config);
786
+ }
787
+ await publishCurrentChangeManifests({ ...input, fetch: request }, harness ? await harness.status() : undefined);
788
+ lastReportedError = undefined;
789
+ }
790
+ catch (error) {
791
+ const current = message(error).slice(0, 500);
792
+ if (current !== lastReportedError)
793
+ process.stderr.write(`Continuous Assurance reconciliation is waiting safely: ${current}\n`);
794
+ lastReportedError = current;
795
+ }
796
+ finally {
797
+ reconciling = false;
798
+ }
799
+ };
800
+ return {
801
+ start() {
802
+ if (timer || closing)
803
+ return;
804
+ void reconcile();
805
+ timer = setInterval(() => void reconcile(), input.intervalMs ?? 15_000);
806
+ timer.unref?.();
807
+ },
808
+ reconcile,
809
+ status: () => harness?.status() ?? Promise.resolve(undefined),
810
+ async close() {
811
+ closing = true;
812
+ if (timer)
813
+ clearInterval(timer);
814
+ timer = undefined;
815
+ await harness?.close();
816
+ harness = undefined;
817
+ },
818
+ };
819
+ }
820
+ async function publishCurrentChangeManifests(input, heartbeat) {
821
+ const base = input.server.replace(/\/$/, "");
822
+ const [activationResponse, manifestResponse] = await Promise.all([
823
+ input.fetch(`${base}/v1/projects/${encodeURIComponent(input.projectId)}/nora/activation-plan`, { headers: { authorization: `Bearer ${input.apiKey}` }, redirect: "error", signal: AbortSignal.timeout(10_000) }),
824
+ input.fetch(`${base}/v1/projects/${encodeURIComponent(input.projectId)}/change-manifests`, { headers: { authorization: `Bearer ${input.apiKey}` }, redirect: "error", signal: AbortSignal.timeout(10_000) }),
825
+ ]);
826
+ if (!activationResponse.ok)
827
+ throw new Error(`Assurance activation plan returned HTTP ${activationResponse.status}.`);
828
+ if (!manifestResponse.ok)
829
+ throw new Error(`Signed Change Manifest collection returned HTTP ${manifestResponse.status}.`);
830
+ const activation = await boundedResponseJson(activationResponse, 512 * 1024);
831
+ const collection = await boundedResponseJson(manifestResponse, 512 * 1024);
832
+ const targets = Array.isArray(activation.targets) ? activation.targets.filter(validActivationTarget) : [];
833
+ const manifests = Array.isArray(collection.manifests) ? collection.manifests.filter(validChangeManifestRecord) : [];
834
+ if (!targets.length)
835
+ return;
836
+ const packageDigest = await optionalFileDigest(join(input.repository, "package.json"));
837
+ const discoveryDigest = await optionalFileDigest(join(input.repository, "witnora.discovery.json"));
838
+ const policyRevision = createHash("sha256").update(JSON.stringify({ privacyMode: input.config.privacyMode, coverage: input.config.coverage })).digest("hex");
839
+ const explicitModelDigest = process.env.WITNORA_MODEL_DIGEST?.trim();
840
+ const explicitPromptWorkflowDigest = process.env.WITNORA_PROMPT_WORKFLOW_DIGEST?.trim();
841
+ const runtime = input.config.runtimeWorker;
842
+ const components = {
843
+ ...(explicitModelDigest && /^[a-f0-9]{64}$/.test(explicitModelDigest) ? { modelDigest: explicitModelDigest } : {}),
844
+ ...(validSha256(explicitPromptWorkflowDigest) ? { promptWorkflowDigest: explicitPromptWorkflowDigest } : packageDigest ? { promptWorkflowDigest: packageDigest } : {}),
845
+ ...(discoveryDigest ? { toolManifestDigest: discoveryDigest } : {}),
846
+ policyRevision,
847
+ ...(heartbeat ? { evaluatorIdentity: { id: "witnora-managed-evaluator", version: "1", digestSha256: heartbeat.evaluatorContractSha256 } } : {}),
848
+ ...(runtime ? { adapterIdentity: { id: runtime.adapterId, version: runtime.adapterVersion, digestSha256: runtime.adapterModuleSha256 } } : {}),
849
+ };
850
+ const signed = input.signedChangeManifest ?? await configSignedChangeManifestImport();
851
+ const unique = new Map();
852
+ const exactBindings = heartbeat?.realPathActivations ?? [];
853
+ for (const target of targets) {
854
+ for (const environment of target.environments) {
855
+ if (!exactBindings.some((binding) => binding.agentId === target.agentId && binding.environment === environment))
856
+ continue;
857
+ unique.set(`${target.agentId}:${environment}`, { agentId: target.agentId, agentVersion: target.currentAgentVersion, environment });
858
+ }
859
+ }
860
+ for (const target of unique.values()) {
861
+ const previous = manifests.find((manifest) => manifest.agentId === target.agentId && manifest.environment === target.environment);
862
+ if (previous && previous.agentVersion === target.agentVersion && sameManifestComponents(previous, components))
863
+ continue;
864
+ const observedAt = new Date().toISOString();
865
+ const payload = {
866
+ schemaVersion: "witnora.signed_change_manifest.v0.1",
867
+ manifestId: `gateway-${randomUUID()}`,
868
+ projectId: input.projectId,
869
+ agentId: target.agentId,
870
+ agentVersion: target.agentVersion,
871
+ environment: target.environment,
872
+ observedAt,
873
+ ...components,
874
+ ...(previous?.manifestDigestSha256 ? { previousManifestDigest: previous.manifestDigestSha256 } : {}),
875
+ };
876
+ const envelope = signed.createSignedChangeManifestEnvelope(payload, input.sourceSigner());
877
+ await signed.uploadSignedChangeManifest({ baseUrl: base, projectId: input.projectId, apiKey: input.apiKey, envelope, fetch: input.fetch });
878
+ }
879
+ }
880
+ function validActivationTarget(value) {
881
+ if (!value || typeof value !== "object" || Array.isArray(value))
882
+ return false;
883
+ const target = value;
884
+ return typeof target.agentId === "string" && typeof target.currentAgentVersion === "string"
885
+ && Array.isArray(target.environments) && target.environments.every((environment) => environment === "sandbox" || environment === "staging" || environment === "production");
886
+ }
887
+ function validChangeManifestRecord(value) {
888
+ if (!value || typeof value !== "object" || Array.isArray(value))
889
+ return false;
890
+ const manifest = value;
891
+ return typeof manifest.agentId === "string" && typeof manifest.agentVersion === "string"
892
+ && (manifest.environment === "sandbox" || manifest.environment === "staging" || manifest.environment === "production")
893
+ && typeof manifest.manifestDigestSha256 === "string";
894
+ }
895
+ function sameManifestComponents(previous, next) {
896
+ return previous.modelDigest === next.modelDigest && previous.promptWorkflowDigest === next.promptWorkflowDigest
897
+ && previous.toolManifestDigest === next.toolManifestDigest && previous.policyRevision === next.policyRevision
898
+ && JSON.stringify(previous.evaluatorIdentity) === JSON.stringify(next.evaluatorIdentity)
899
+ && JSON.stringify(previous.adapterIdentity) === JSON.stringify(next.adapterIdentity);
900
+ }
901
+ async function optionalFileDigest(path) {
902
+ try {
903
+ return createHash("sha256").update(await readFile(path)).digest("hex");
904
+ }
905
+ catch (error) {
906
+ if (error.code === "ENOENT")
907
+ return undefined;
908
+ throw error;
909
+ }
910
+ }
911
+ function validSha256(value) {
912
+ return Boolean(value && /^[a-f0-9]{64}$/.test(value));
913
+ }
914
+ async function boundedResponseJson(response, maxBytes) {
915
+ const text = await response.text();
916
+ if (Buffer.byteLength(text) > maxBytes)
917
+ throw new Error("Hosted Assurance response exceeded its size limit.");
918
+ const value = JSON.parse(text);
919
+ if (!value || typeof value !== "object" || Array.isArray(value))
920
+ throw new Error("Hosted Assurance response is invalid.");
921
+ return value;
922
+ }
730
923
  async function startManagedLocalEvaluator(directory, config, evaluatorKit) {
731
924
  const repository = resolve(directory, "..", "..");
732
925
  const modulePath = resolve(repository, config.evaluatorModulePath);
@@ -48,7 +48,7 @@ export interface CustomerOwnedCollectorGatewayOptions {
48
48
  };
49
49
  };
50
50
  assuranceHarness?: {
51
- status(): Promise<AssuranceHarnessHeartbeat>;
51
+ status(): Promise<AssuranceHarnessHeartbeat | undefined>;
52
52
  };
53
53
  runtimeBinding?: RuntimeReadinessBinding;
54
54
  onRepairRequested?: (request: {
@@ -1 +1 @@
1
- {"version":3,"file":"collector-gateway.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/collector-gateway.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collector-gateway.d.ts","sourceRoot":"","sources":["../../../../agentcert-sdk/src/collector-gateway.ts"],"names":[],"mappings":"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"}
@@ -76,6 +76,7 @@ export async function startCustomerOwnedCollectorGateway(options) {
76
76
  return { delivered, reconciled, pending };
77
77
  };
78
78
  const status = async () => {
79
+ const assuranceHarness = options.assuranceHarness ? await options.assuranceHarness.status() : undefined;
79
80
  let pendingRecordCount = 0;
80
81
  let lastAckSequence;
81
82
  for (const journal of journals.values()) {
@@ -94,7 +95,7 @@ export async function startCustomerOwnedCollectorGateway(options) {
94
95
  lastRemoteSuccessAt,
95
96
  lastRemoteError,
96
97
  ...(options.actionWorker ? { actionWorker: await options.actionWorker.status() } : {}),
97
- ...(options.assuranceHarness ? { assuranceHarness: await options.assuranceHarness.status() } : {}),
98
+ ...(assuranceHarness ? { assuranceHarness } : {}),
98
99
  ...(monitoringControlFor() ? { monitoring: monitoringControlFor() } : {}),
99
100
  };
100
101
  };
@@ -11,11 +11,25 @@ export async function activateRealPathIntegrations(options) {
11
11
  if (!response.ok)
12
12
  throw new Error(`Could not load approved real-path integrations (${response.status}).`);
13
13
  const body = await boundedJson(response);
14
- const approved = Array.isArray(body.integrations) ? body.integrations.map(parsePlan).filter((plan) => plan.status === "READY_TO_ACTIVATE") : [];
14
+ const approved = Array.isArray(body.integrations) ? body.integrations.map(parsePlan).filter((plan) => plan.status === "READY_TO_ACTIVATE" || plan.status === "HARNESS_ACTIVE") : [];
15
15
  const plans = approved.filter((plan) => ["STRIPE_REFUND", "SHOPIFY_DISPUTE", "ZENDESK_TICKET", "SALESFORCE_RECORD", "HUBSPOT_CRM_RECORD", "POSTGRES_RECORD"].includes(plan.generated.providerPackId) && plan.environment === "sandbox" && plan.customerSummary.evaluationMode === "SHADOW");
16
16
  if (!plans.length)
17
17
  return { state: "NOT_CONFIGURED", created: false, activations: [], generatedFiles: [], rollback: async () => undefined };
18
18
  const environment = options.env ?? process.env;
19
+ const modulePath = join(repository, "witnora.assurance-harness.mjs");
20
+ const manifestPath = join(repository, ".witnora", "gateway", "real-path-activations.json");
21
+ const source = generatedProviderHarness(plans);
22
+ const moduleDigestSha256 = sha(source);
23
+ const current = await readFile(modulePath, "utf8").catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
24
+ const priorSource = await readFile(manifestPath, "utf8").catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
25
+ const prior = priorSource === undefined ? undefined : JSON.parse(priorSource);
26
+ const cachedActivations = prior?.projectId === options.projectId && prior.moduleDigestSha256 === moduleDigestSha256 && current === source
27
+ && Array.isArray(prior.activations) && sameActivationPlans(plans, prior.activations) ? structuredClone(prior.activations) : undefined;
28
+ if (cachedActivations) {
29
+ for (const plan of plans)
30
+ await persistProviderCredential(repository, plan, environment);
31
+ return { state: "READY_TO_START", created: false, modulePath: "witnora.assurance-harness.mjs", activations: cachedActivations, generatedFiles: [], previousGeneratedModuleSha256: moduleDigestSha256, rollback: async () => undefined };
32
+ }
19
33
  const activations = [];
20
34
  const scenarios = [];
21
35
  for (const plan of plans) {
@@ -25,15 +39,8 @@ export async function activateRealPathIntegrations(options) {
25
39
  activations.push({ integrationId: plan.id, integrationDigestSha256: plan.digestSha256, taskContractId: plan.taskContractId, taskContractDigestSha256: plan.taskContractDigestSha256, agentId: plan.subject.agentId, agentVersion: plan.subject.agentVersion, environment: plan.environment, providerPackId: plan.generated.providerPackId, providerContractDigestSha256: plan.generated.providerContractDigestSha256, actionPathIds: plan.generated.actionPathBindings.map((item) => item.actionPathId), acceptance });
26
40
  scenarios.push({ plan, value: [preflight.scenario] });
27
41
  }
28
- const modulePath = join(repository, "witnora.assurance-harness.mjs");
29
- const manifestPath = join(repository, ".witnora", "gateway", "real-path-activations.json");
30
- const source = generatedProviderHarness(plans);
31
- const moduleDigestSha256 = sha(source);
32
42
  let created = false;
33
43
  const generatedFiles = [];
34
- const current = await readFile(modulePath, "utf8").catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
35
- const priorSource = await readFile(manifestPath, "utf8").catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
36
- const prior = priorSource === undefined ? undefined : JSON.parse(priorSource);
37
44
  const previousGeneratedModuleSha256 = current !== undefined && sha(current) === prior?.moduleDigestSha256 ? prior.moduleDigestSha256 : undefined;
38
45
  if (current === undefined) {
39
46
  await writeFile(modulePath, source, { encoding: "utf8", mode: 0o600, flag: "wx" });
@@ -253,16 +260,30 @@ async function persistProviderCredential(repository, plan, environment) {
253
260
  return;
254
261
  const name = providerCredentialEnvironmentName(plan.generated.providerPackId);
255
262
  const value = environment[name];
256
- if (!value)
257
- throw new Error(`${plan.generated.providerPackId} activation requires its read-only credential in the customer environment.`);
258
263
  const directory = join(repository, ".witnora", "provider-credentials");
259
264
  const target = join(directory, `${plan.id}.secret`);
260
- const temporary = `${target}.${randomUUID()}.tmp`;
265
+ const current = await readFile(target, "utf8").catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
266
+ if (!value) {
267
+ if (current !== undefined)
268
+ return;
269
+ throw new Error(`${plan.generated.providerPackId} activation requires its read-only credential in the customer environment.`);
270
+ }
271
+ if (current === value)
272
+ return;
261
273
  await mkdir(directory, { recursive: true });
262
274
  await writeFile(join(directory, ".gitignore"), "*\n!.gitignore\n", { encoding: "utf8", mode: 0o600, flag: "wx" }).catch((error) => { if (error.code !== "EEXIST")
263
275
  throw error; });
264
- await writeFile(temporary, value, { encoding: "utf8", mode: 0o600, flag: "wx" });
265
- await rename(temporary, target);
276
+ await writeFile(target, value, { encoding: "utf8", mode: 0o600 });
277
+ }
278
+ function sameActivationPlans(plans, activations) {
279
+ if (plans.length !== activations.length)
280
+ return false;
281
+ return plans.every((plan) => activations.some((activation) => activation.integrationId === plan.id && activation.integrationDigestSha256 === plan.digestSha256
282
+ && activation.taskContractId === plan.taskContractId && activation.taskContractDigestSha256 === plan.taskContractDigestSha256
283
+ && activation.agentId === plan.subject.agentId && activation.agentVersion === plan.subject.agentVersion && activation.environment === plan.environment
284
+ && activation.providerPackId === plan.generated.providerPackId && activation.providerContractDigestSha256 === plan.generated.providerContractDigestSha256
285
+ && canonical([...activation.actionPathIds].sort()) === canonical(plan.generated.actionPathBindings.map((item) => item.actionPathId).sort())
286
+ && activation.acceptance?.kind === "READ_ONLY_PROVIDER_PREFLIGHT" && activation.acceptance.productionWrites === 0 && digest(activation.acceptance.observationDigestSha256)));
266
287
  }
267
288
  function providerCredentialEnvironmentName(packId) {
268
289
  if (packId === "STRIPE_REFUND")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "witnora",
3
- "version": "0.18.10",
3
+ "version": "0.18.11",
4
4
  "description": "Independent assurance for covered agent action paths across models and frameworks.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",