@lucern/confidence 0.3.0-alpha.0 → 0.3.0-alpha.10

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.
Files changed (54) hide show
  1. package/README.md +5 -1
  2. package/dist/index.d.ts +5 -3
  3. package/dist/index.js +227 -98
  4. package/dist/index.js.map +1 -1
  5. package/dist/v1/codec.d.ts +42 -0
  6. package/dist/v1/codec.js +62 -0
  7. package/dist/v1/codec.js.map +1 -0
  8. package/dist/v1/index.d.ts +5 -3
  9. package/dist/v1/index.js +227 -98
  10. package/dist/v1/index.js.map +1 -1
  11. package/dist/v1/operations/approximation.js +30 -21
  12. package/dist/v1/operations/approximation.js.map +1 -1
  13. package/dist/v1/operations/bridge/index.d.ts +3 -3
  14. package/dist/v1/operations/bridge/index.js +27 -13
  15. package/dist/v1/operations/bridge/index.js.map +1 -1
  16. package/dist/v1/operations/canonical.d.ts +2 -2
  17. package/dist/v1/operations/canonical.js +16 -19
  18. package/dist/v1/operations/canonical.js.map +1 -1
  19. package/dist/v1/operations/contracts/epistemicContract.d.ts +1 -1
  20. package/dist/v1/operations/contracts/epistemicContract.js +13 -11
  21. package/dist/v1/operations/contracts/epistemicContract.js.map +1 -1
  22. package/dist/v1/operations/contradiction/detectTupleContradiction.js.map +1 -1
  23. package/dist/v1/operations/contradiction/index.js.map +1 -1
  24. package/dist/v1/operations/dynamics/cascade.js +19 -6
  25. package/dist/v1/operations/dynamics/cascade.js.map +1 -1
  26. package/dist/v1/operations/dynamics/decay.d.ts +1 -1
  27. package/dist/v1/operations/dynamics/decay.js +5 -4
  28. package/dist/v1/operations/dynamics/decay.js.map +1 -1
  29. package/dist/v1/operations/dynamics/defeat.d.ts +1 -1
  30. package/dist/v1/operations/dynamics/defeat.js +22 -17
  31. package/dist/v1/operations/dynamics/defeat.js.map +1 -1
  32. package/dist/v1/operations/dynamics/propagation.js +66 -33
  33. package/dist/v1/operations/dynamics/propagation.js.map +1 -1
  34. package/dist/v1/operations/dynamics/revision.d.ts +6 -6
  35. package/dist/v1/operations/dynamics/revision.js +31 -19
  36. package/dist/v1/operations/dynamics/revision.js.map +1 -1
  37. package/dist/v1/operations/index.js +9 -5
  38. package/dist/v1/operations/index.js.map +1 -1
  39. package/dist/v1/operations/lucern.d.ts +4 -2
  40. package/dist/v1/operations/lucern.js +192 -87
  41. package/dist/v1/operations/lucern.js.map +1 -1
  42. package/dist/v1/operations/operatorTaxonomy.d.ts +23 -1
  43. package/dist/v1/operations/operatorTaxonomy.js +28 -0
  44. package/dist/v1/operations/operatorTaxonomy.js.map +1 -1
  45. package/dist/v1/operations/scoring.d.ts +30 -12
  46. package/dist/v1/operations/scoring.js +82 -40
  47. package/dist/v1/operations/scoring.js.map +1 -1
  48. package/dist/v1/operations/subjectiveLogic/index.d.ts +20 -19
  49. package/dist/v1/operations/subjectiveLogic/index.js +11 -10
  50. package/dist/v1/operations/subjectiveLogic/index.js.map +1 -1
  51. package/dist/v1/operations/temporalDecay.js +9 -5
  52. package/dist/v1/operations/temporalDecay.js.map +1 -1
  53. package/dist/v1/types.d.ts +5 -1
  54. package/package.json +5 -1
@@ -1,8 +1,10 @@
1
+ import { z } from 'zod';
2
+
1
3
  // src/v1/operations/subjectiveLogic/index.ts
2
- function opinion(belief, disbelief, uncertainty, baseRate = 0.5) {
3
- const b = Math.max(0, Math.min(1, belief));
4
- const d = Math.max(0, Math.min(1, disbelief));
5
- const u = Math.max(0, Math.min(1, uncertainty));
4
+ function mkOpinion(belief, disbelief, uncertainty, baseRate) {
5
+ const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;
6
+ const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;
7
+ const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;
6
8
  const a = Math.max(0, Math.min(1, baseRate));
7
9
  const sum = b + d + u;
8
10
  if (sum === 0) {
@@ -15,8 +17,9 @@ function opinion(belief, disbelief, uncertainty, baseRate = 0.5) {
15
17
  a
16
18
  };
17
19
  }
18
- function vacuous(baseRate = 0.5) {
19
- return { b: 0, d: 0, u: 1, a: baseRate };
20
+ var opinion = mkOpinion;
21
+ function vacuous(baseRate) {
22
+ return mkOpinion(0, 0, 1, baseRate);
20
23
  }
21
24
  function project(o) {
22
25
  return o.b + o.a * o.u;
@@ -172,7 +175,7 @@ function conditionalDeduction(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
172
175
  );
173
176
  }
174
177
  function negate(o) {
175
- return { b: o.d, d: o.b, u: o.u, a: 1 - o.a };
178
+ return mkOpinion(o.d, o.b, o.u, 1 - o.a);
176
179
  }
177
180
  function constraintFusion(left, right, mode = "pressure") {
178
181
  if (mode === "redistribute") {
@@ -239,6 +242,15 @@ function informationGain(o) {
239
242
  function finiteNumber(value) {
240
243
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
241
244
  }
245
+ function requiredOpinionNumber(label, ...values) {
246
+ for (const value of values) {
247
+ const numberValue = finiteNumber(value);
248
+ if (numberValue !== void 0) {
249
+ return numberValue;
250
+ }
251
+ }
252
+ throw new Error(`Opinion record is missing required ${label}.`);
253
+ }
242
254
  function clamp01(value) {
243
255
  return Math.max(0, Math.min(1, value));
244
256
  }
@@ -253,34 +265,56 @@ function toStoredOpinionFields(opinion2) {
253
265
  baseRate: opinion2.a
254
266
  };
255
267
  }
256
- function readOpinionFromRecord(source, fallback = {}) {
268
+ function readOpinionFromRecord(source) {
257
269
  const record = source && typeof source === "object" ? source : {};
258
- return {
259
- b: finiteNumber(record.b) ?? finiteNumber(record.belief) ?? finiteNumber(record.slBelief) ?? finiteNumber(record.opinion_b) ?? fallback.b ?? 0,
260
- d: finiteNumber(record.d) ?? finiteNumber(record.disbelief) ?? finiteNumber(record.slDisbelief) ?? finiteNumber(record.opinion_d) ?? fallback.d ?? 0,
261
- u: finiteNumber(record.u) ?? finiteNumber(record.uncertainty) ?? finiteNumber(record.slUncertainty) ?? finiteNumber(record.opinion_u) ?? fallback.u ?? 1,
262
- a: finiteNumber(record.a) ?? finiteNumber(record.baseRate) ?? finiteNumber(record.slBaseRate) ?? finiteNumber(record.opinion_a) ?? fallback.a ?? 0.5
263
- };
270
+ return mkOpinion(
271
+ requiredOpinionNumber(
272
+ "belief",
273
+ record.b,
274
+ record.belief,
275
+ record.slBelief,
276
+ record.opinion_b
277
+ ),
278
+ requiredOpinionNumber(
279
+ "disbelief",
280
+ record.d,
281
+ record.disbelief,
282
+ record.slDisbelief,
283
+ record.opinion_d
284
+ ),
285
+ requiredOpinionNumber(
286
+ "uncertainty",
287
+ record.u,
288
+ record.uncertainty,
289
+ record.slUncertainty,
290
+ record.opinion_u
291
+ ),
292
+ requiredOpinionNumber(
293
+ "baseRate",
294
+ record.a,
295
+ record.baseRate,
296
+ record.slBaseRate,
297
+ record.opinion_a
298
+ )
299
+ );
264
300
  }
265
301
  function opinionFromScalar(value, mode, options) {
266
302
  const clampedValue = clamp01(value);
267
- const baseRate = clamp01(options?.baseRate ?? 0.5);
303
+ const baseRate = options?.baseRate === void 0 ? void 0 : clamp01(options.baseRate);
268
304
  switch (mode) {
269
305
  case "base_rate":
270
- return {
271
- b: 0,
272
- d: 0,
273
- u: 1,
274
- a: clampedValue
275
- };
306
+ return mkOpinion(0, 0, 1, clampedValue);
276
307
  case "dogmatic":
277
- return {
278
- b: clampedValue,
279
- d: 1 - clampedValue,
280
- u: 0,
281
- a: baseRate
282
- };
308
+ if (baseRate === void 0) {
309
+ throw new Error('opinionFromScalar(value, "dogmatic") requires options.baseRate.');
310
+ }
311
+ return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);
283
312
  case "projected_with_u": {
313
+ if (baseRate === void 0) {
314
+ throw new Error(
315
+ 'opinionFromScalar(value, "projected_with_u") requires options.baseRate.'
316
+ );
317
+ }
284
318
  const uncertainty = options?.uncertainty;
285
319
  if (uncertainty === void 0) {
286
320
  throw new Error(
@@ -289,22 +323,57 @@ function opinionFromScalar(value, mode, options) {
289
323
  }
290
324
  const clampedUncertainty = clamp01(uncertainty);
291
325
  const evidenceWeight = 1 - clampedUncertainty;
292
- return {
293
- b: clampedValue * evidenceWeight,
294
- d: (1 - clampedValue) * evidenceWeight,
295
- u: clampedUncertainty,
296
- a: baseRate
297
- };
326
+ return mkOpinion(
327
+ clampedValue * evidenceWeight,
328
+ (1 - clampedValue) * evidenceWeight,
329
+ clampedUncertainty,
330
+ baseRate
331
+ );
298
332
  }
299
333
  }
300
334
  throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);
301
335
  }
302
- function toDogmaticOpinion(confidence, baseRate = 0.5) {
336
+ function toDogmaticOpinion(confidence, baseRate) {
303
337
  return opinionFromScalar(confidence, "dogmatic", { baseRate });
304
338
  }
305
339
  function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
306
340
  return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
307
341
  }
342
+ var SL_EPSILON = 1e-9;
343
+ z.object({
344
+ b: z.number(),
345
+ d: z.number(),
346
+ u: z.number(),
347
+ a: z.number()
348
+ }).refine((o) => Math.abs(o.b + o.d + o.u - 1) < SL_EPSILON, {
349
+ message: "SL invariant b+d+u=1 violated"
350
+ });
351
+ function fromStorage(fields) {
352
+ const sum = fields.belief + fields.disbelief + fields.uncertainty;
353
+ const opinion2 = mkOpinion(
354
+ fields.belief,
355
+ fields.disbelief,
356
+ fields.uncertainty,
357
+ fields.baseRate
358
+ );
359
+ if (Math.abs(sum - 1) < SL_EPSILON) {
360
+ return { ok: true, opinion: opinion2 };
361
+ }
362
+ return {
363
+ ok: false,
364
+ opinion: opinion2,
365
+ repairNeeded: true,
366
+ reason: `Stored fields sum to ${sum.toFixed(6)}, not 1; normalized on read`
367
+ };
368
+ }
369
+ function toStorage(opinion2) {
370
+ return {
371
+ belief: opinion2.b,
372
+ disbelief: opinion2.d,
373
+ uncertainty: opinion2.u,
374
+ baseRate: opinion2.a
375
+ };
376
+ }
308
377
  function toEpochMs(value) {
309
378
  if (typeof value === "number" && Number.isFinite(value)) {
310
379
  return value;
@@ -336,7 +405,10 @@ function temporalDecay(sourceOpinion, now, decayParams) {
336
405
  return { ...sourceOpinion };
337
406
  }
338
407
  const retainedEvidenceWeight = Math.pow(0.5, ageMs / halfLifeMs);
339
- return trustDiscount(sourceOpinion, retainedEvidenceWeight);
408
+ return trustDiscount(
409
+ mkOpinion(sourceOpinion.b, sourceOpinion.d, sourceOpinion.u, sourceOpinion.a),
410
+ retainedEvidenceWeight
411
+ );
340
412
  }
341
413
 
342
414
  // src/v1/operations/contradiction/detectTupleContradiction.ts
@@ -373,7 +445,14 @@ function evaluateTupleContradictionTransition(args) {
373
445
 
374
446
  // src/v1/operations/dynamics/cascade.ts
375
447
  function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
376
- const dependencyProjection = project(dependencyOpinion);
448
+ const dependencyProjection = project(
449
+ mkOpinion(
450
+ dependencyOpinion.b,
451
+ dependencyOpinion.d,
452
+ dependencyOpinion.u,
453
+ dependencyOpinion.a
454
+ )
455
+ );
377
456
  if (mode === "threshold") {
378
457
  if (dependencyProjection < threshold) {
379
458
  return opinion(
@@ -398,40 +477,49 @@ function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "conti
398
477
  opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
399
478
  operator: "dependency_cascade",
400
479
  rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
401
- dependencyOpinion
480
+ mkOpinion(
481
+ dependencyOpinion.b,
482
+ dependencyOpinion.d,
483
+ dependencyOpinion.u,
484
+ dependencyOpinion.a
485
+ )
402
486
  ).toFixed(2)}`
403
487
  };
404
488
  }
405
489
 
406
490
  // src/v1/operations/dynamics/defeat.ts
407
491
  function applyNegativeSupport(source, target, weight, metadata = {}) {
492
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
493
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
408
494
  if (metadata.constraint === "xor") {
409
495
  const result = constraintFusion(
410
- source,
411
- target,
496
+ sourceOpinion,
497
+ targetOpinion,
412
498
  metadata.normalization ?? "pressure"
413
499
  );
414
500
  return {
415
501
  opinion: result.o2,
416
502
  operator: "constraint_fusion",
417
- rationale: `XOR constraint: source belief at ${project(source).toFixed(
418
- 2
419
- )} pressures target`
503
+ rationale: `XOR constraint: source belief at ${project(
504
+ sourceOpinion
505
+ ).toFixed(2)} pressures target`
420
506
  };
421
507
  }
422
- const discounted = trustDiscount(negate(source), Math.abs(weight));
508
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
423
509
  return {
424
- opinion: cumulativeFusion(target, discounted),
510
+ opinion: cumulativeFusion(targetOpinion, discounted),
425
511
  operator: "cumulative_fusion",
426
512
  rationale: `Contradicting evidence (weight=${weight.toFixed(
427
513
  2
428
- )}) from source at ${project(source).toFixed(2)}`
514
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
429
515
  };
430
516
  }
431
517
  function applyNegativeEvidence(source, target, weight) {
432
- const discounted = trustDiscount(negate(source), Math.abs(weight));
518
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
519
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
520
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
433
521
  return {
434
- opinion: cumulativeFusion(target, discounted),
522
+ opinion: cumulativeFusion(targetOpinion, discounted),
435
523
  operator: "cumulative_fusion",
436
524
  rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
437
525
  };
@@ -442,28 +530,32 @@ var EDGE_PROPAGATION_RULES = {
442
530
  supports: {
443
531
  direction: "outgoing",
444
532
  handler: (source, target, weight, metadata) => {
533
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
534
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
445
535
  if (weight < 0) {
446
- return applyNegativeSupport(source, target, weight, metadata);
536
+ return applyNegativeSupport(sourceOpinion, targetOpinion, weight, metadata);
447
537
  }
448
- const discounted = trustDiscount(source, weight);
538
+ const discounted = trustDiscount(sourceOpinion, weight);
449
539
  return {
450
- opinion: cumulativeFusion(target, discounted),
540
+ opinion: cumulativeFusion(targetOpinion, discounted),
451
541
  operator: "cumulative_fusion",
452
542
  rationale: `Supporting evidence (weight=${weight.toFixed(
453
543
  2
454
- )}) from source at ${project(source).toFixed(2)}`
544
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
455
545
  };
456
546
  }
457
547
  },
458
548
  informs: {
459
549
  direction: "outgoing",
460
550
  handler: (source, target, weight) => {
551
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
552
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
461
553
  if (weight < 0) {
462
- return applyNegativeEvidence(source, target, weight);
554
+ return applyNegativeEvidence(sourceOpinion, targetOpinion, weight);
463
555
  }
464
- const discounted = trustDiscount(source, Math.abs(weight));
556
+ const discounted = trustDiscount(sourceOpinion, Math.abs(weight));
465
557
  return {
466
- opinion: cumulativeFusion(target, discounted),
558
+ opinion: cumulativeFusion(targetOpinion, discounted),
467
559
  operator: "cumulative_fusion",
468
560
  rationale: `Supporting evidence (weight=${weight.toFixed(2)})`
469
561
  };
@@ -472,23 +564,35 @@ var EDGE_PROPAGATION_RULES = {
472
564
  depends_on: {
473
565
  direction: "incoming",
474
566
  handler: (source, target, _weight, metadata) => {
567
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
568
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
475
569
  if (metadata.conditionalA && metadata.conditionalNotA) {
476
570
  return {
477
571
  opinion: conditionalDeduction(
478
- source,
479
- metadata.conditionalA,
480
- metadata.conditionalNotA,
481
- target.a
572
+ sourceOpinion,
573
+ mkOpinion(
574
+ metadata.conditionalA.b,
575
+ metadata.conditionalA.d,
576
+ metadata.conditionalA.u,
577
+ metadata.conditionalA.a
578
+ ),
579
+ mkOpinion(
580
+ metadata.conditionalNotA.b,
581
+ metadata.conditionalNotA.d,
582
+ metadata.conditionalNotA.u,
583
+ metadata.conditionalNotA.a
584
+ ),
585
+ targetOpinion.a
482
586
  ),
483
587
  operator: "conditional_deduction",
484
588
  rationale: `Conditional deduction: prerequisite at ${project(
485
- source
589
+ sourceOpinion
486
590
  ).toFixed(2)}`
487
591
  };
488
592
  }
489
593
  return dampedDependencyCascade(
490
- source,
491
- target,
594
+ sourceOpinion,
595
+ targetOpinion,
492
596
  metadata.propagation ?? "continuous"
493
597
  );
494
598
  }
@@ -580,10 +684,6 @@ function normalizeBaseRateVector(baseRate, size) {
580
684
  if (size === 0) {
581
685
  return [];
582
686
  }
583
- const fallback = Array.from({ length: size }, () => 1 / size);
584
- if (!baseRate) {
585
- return fallback;
586
- }
587
687
  if (baseRate.length !== size) {
588
688
  throw new Error(
589
689
  `Base-rate vector length ${baseRate.length} must match evidence vector length ${size}.`
@@ -592,11 +692,11 @@ function normalizeBaseRateVector(baseRate, size) {
592
692
  const normalized = baseRate.map((value) => clampNonNegative(value));
593
693
  const total = normalized.reduce((sum, value) => sum + value, 0);
594
694
  if (total === 0) {
595
- return fallback;
695
+ throw new Error("Base-rate vector must contain at least one positive value.");
596
696
  }
597
697
  return normalized.map((value) => value / total);
598
698
  }
599
- function opinionFromDirichlet(alpha, nonInformativeWeight = DEFAULT_NON_INFORMATIVE_WEIGHT, baseRate) {
699
+ function opinionFromDirichlet(alpha, nonInformativeWeight, baseRate) {
600
700
  const evidence = alpha.map((value) => clampNonNegative(value));
601
701
  const safeWeight = normalizeNonInformativeWeight(nonInformativeWeight);
602
702
  const normalizedBaseRate = normalizeBaseRateVector(baseRate, evidence.length);
@@ -615,18 +715,18 @@ function opinionFromDirichlet(alpha, nonInformativeWeight = DEFAULT_NON_INFORMAT
615
715
  a: normalizedBaseRate
616
716
  };
617
717
  }
618
- function opinionFromBeta(alpha, beta, nonInformativeWeight = DEFAULT_NON_INFORMATIVE_WEIGHT, baseRate = 0.5) {
718
+ function opinionFromBeta(alpha, beta, nonInformativeWeight, baseRate) {
619
719
  const dirichlet = opinionFromDirichlet(
620
720
  [alpha, beta],
621
721
  nonInformativeWeight,
622
722
  [clamp012(baseRate), 1 - clamp012(baseRate)]
623
723
  );
624
- return {
625
- b: dirichlet.b[0] ?? 0,
626
- d: dirichlet.b[1] ?? 0,
627
- u: dirichlet.u,
628
- a: dirichlet.a[0] ?? clamp012(baseRate)
629
- };
724
+ return mkOpinion(
725
+ dirichlet.b[0] ?? 0,
726
+ dirichlet.b[1] ?? 0,
727
+ dirichlet.u,
728
+ dirichlet.a[0] ?? clamp012(baseRate)
729
+ );
630
730
  }
631
731
 
632
732
  // src/v1/operations/dynamics/revision.ts
@@ -661,7 +761,7 @@ function reviseConfidenceOpinion(args) {
661
761
  priorEvidence.alpha + newEvidence.alpha,
662
762
  priorEvidence.beta + newEvidence.beta,
663
763
  args.nonInformativeWeight ?? DEFAULT_NON_INFORMATIVE_WEIGHT,
664
- args.baseRate ?? 0.5
764
+ args.baseRate
665
765
  );
666
766
  }
667
767
 
@@ -928,6 +1028,9 @@ function generateContractId() {
928
1028
  }
929
1029
  return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
930
1030
  }
1031
+ function isRecord(value) {
1032
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1033
+ }
931
1034
  function deriveContractStatus(result, currentStatus) {
932
1035
  if (currentStatus === "archived") {
933
1036
  return currentStatus;
@@ -1069,18 +1172,17 @@ function pickFiniteNumber(config, keys) {
1069
1172
  return void 0;
1070
1173
  }
1071
1174
  function getEvaluatorInputRecord(inputData, nestedKey) {
1072
- if (!inputData || typeof inputData !== "object") {
1175
+ if (!isRecord(inputData)) {
1073
1176
  return {};
1074
1177
  }
1075
- const root = inputData;
1076
- const nested = root[nestedKey];
1077
- if (nested && typeof nested === "object") {
1178
+ const nested = inputData[nestedKey];
1179
+ if (isRecord(nested)) {
1078
1180
  return nested;
1079
1181
  }
1080
- return root;
1182
+ return inputData;
1081
1183
  }
1082
1184
  function parseEvidentialEvaluatorConfig(value) {
1083
- if (!value || typeof value !== "object") {
1185
+ if (!isRecord(value)) {
1084
1186
  throw new Error(
1085
1187
  "Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
1086
1188
  );
@@ -1098,7 +1200,7 @@ function parseEvidentialEvaluatorConfig(value) {
1098
1200
  if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
1099
1201
  throw new Error("Evidential contracts require a numeric threshold.");
1100
1202
  }
1101
- const actionParams = config.actionParams && typeof config.actionParams === "object" && config.actionParams !== null ? config.actionParams : void 0;
1203
+ const actionParams = isRecord(config.actionParams) ? config.actionParams : void 0;
1102
1204
  return {
1103
1205
  metric,
1104
1206
  operator,
@@ -1147,7 +1249,7 @@ function buildEvidentialRationale(args) {
1147
1249
  return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
1148
1250
  }
1149
1251
  function parseMetricCheckerConfig(value) {
1150
- if (!value || typeof value !== "object") {
1252
+ if (!isRecord(value)) {
1151
1253
  throw new Error(
1152
1254
  "metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
1153
1255
  );
@@ -1164,7 +1266,7 @@ function parseMetricCheckerConfig(value) {
1164
1266
  };
1165
1267
  }
1166
1268
  function parseReferenceCheckCounterConfig(value) {
1167
- if (!value || typeof value !== "object") {
1269
+ if (!isRecord(value)) {
1168
1270
  throw new Error(
1169
1271
  "reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
1170
1272
  );
@@ -1187,7 +1289,7 @@ function parseReferenceCheckCounterConfig(value) {
1187
1289
  };
1188
1290
  }
1189
1291
  function parseTemporalDeadlineConfig(value) {
1190
- if (!value || typeof value !== "object") {
1292
+ if (!isRecord(value)) {
1191
1293
  return {};
1192
1294
  }
1193
1295
  const config = value;
@@ -1201,7 +1303,7 @@ function parseTemporalDeadlineConfig(value) {
1201
1303
  };
1202
1304
  }
1203
1305
  function parseMarketIndexComparatorConfig(value) {
1204
- if (!value || typeof value !== "object") {
1306
+ if (!isRecord(value)) {
1205
1307
  throw new Error(
1206
1308
  "market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
1207
1309
  );
@@ -1228,6 +1330,8 @@ function parseMarketIndexComparatorConfig(value) {
1228
1330
  // src/v1/operations/lucern.ts
1229
1331
  var LUCERN_SPECIFIC_OPERATOR_NAMES = [
1230
1332
  "clamp01",
1333
+ "fromStorage",
1334
+ "toStorage",
1231
1335
  "toStoredOpinionFields",
1232
1336
  "readOpinionFromRecord",
1233
1337
  "opinionFromScalar",
@@ -1248,6 +1352,7 @@ var LUCERN_SPECIFIC_OPERATOR_NAMES = [
1248
1352
  "propagateAllEdges",
1249
1353
  "bayesianUpdate",
1250
1354
  "reviseConfidence",
1355
+ "reviseConfidenceOpinion",
1251
1356
  "computeBaseDecay",
1252
1357
  "computeDeadlineUrgency",
1253
1358
  "computeEffectiveDecay",
@@ -1275,6 +1380,6 @@ var LUCERN_SPECIFIC_OPERATOR_NAMES = [
1275
1380
  "parseMarketIndexComparatorConfig"
1276
1381
  ];
1277
1382
 
1278
- export { LUCERN_SPECIFIC_OPERATOR_NAMES, applyNegativeEvidence, applyNegativeSupport, areTensioned, bayesianUpdate, buildComparisonRationale, buildEvidentialRationale, clamp01, compareMetricValue, computeBaseDecay, computeDeadlineUrgency, computeEffectiveDecay, confidenceLevel, constraintFusion, createInheritedContractRecord, decay, deriveContractModulationPlan, deriveContractStatus, deriveVerificationTrigger, detectTupleContradiction, evaluateTupleContradictionTransition, evidenceBalance, getEvaluatorInputRecord, getPropagationTraversalSpecs, getRescoringSchedule, hasProjectedOpinionChanged, informationGain, isPropagationEdgeType, normalizeEvidentialAction, normalizeTupleContradictionPolicy, opinionFromScalar, parseComparisonOperator, parseEvidentialEvaluatorConfig, parseMarketIndexComparatorConfig, parseMetricCheckerConfig, parseNumericThreshold, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, pickFiniteNumber, propagateAllEdges, propagateThroughEdge, readOpinionFromRecord, resolveComparisonResult, reviseConfidence, temporalDecay, toDogmaticOpinion, toStoredOpinionFields };
1383
+ export { LUCERN_SPECIFIC_OPERATOR_NAMES, applyNegativeEvidence, applyNegativeSupport, areTensioned, bayesianUpdate, buildComparisonRationale, buildEvidentialRationale, clamp01, compareMetricValue, computeBaseDecay, computeDeadlineUrgency, computeEffectiveDecay, confidenceLevel, constraintFusion, createInheritedContractRecord, decay, deriveContractModulationPlan, deriveContractStatus, deriveVerificationTrigger, detectTupleContradiction, evaluateTupleContradictionTransition, evidenceBalance, fromStorage, getEvaluatorInputRecord, getPropagationTraversalSpecs, getRescoringSchedule, hasProjectedOpinionChanged, informationGain, isPropagationEdgeType, normalizeEvidentialAction, normalizeTupleContradictionPolicy, opinionFromScalar, parseComparisonOperator, parseEvidentialEvaluatorConfig, parseMarketIndexComparatorConfig, parseMetricCheckerConfig, parseNumericThreshold, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, pickFiniteNumber, propagateAllEdges, propagateThroughEdge, readOpinionFromRecord, resolveComparisonResult, reviseConfidence, reviseConfidenceOpinion, temporalDecay, toDogmaticOpinion, toStorage, toStoredOpinionFields };
1279
1384
  //# sourceMappingURL=lucern.js.map
1280
1385
  //# sourceMappingURL=lucern.js.map