@lucern/confidence 1.0.29 → 1.0.30

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 (49) hide show
  1. package/dist/index.d.ts +7 -7
  2. package/dist/index.js +905 -770
  3. package/dist/index.js.map +1 -1
  4. package/dist/proof-attestation.json +1 -1
  5. package/dist/v1/codec.js.map +1 -1
  6. package/dist/v1/index.d.ts +7 -7
  7. package/dist/v1/index.js +905 -770
  8. package/dist/v1/index.js.map +1 -1
  9. package/dist/v1/interfaces.d.ts +5 -5
  10. package/dist/v1/operations/approximation.d.ts +1 -1
  11. package/dist/v1/operations/approximation.js +8 -7
  12. package/dist/v1/operations/approximation.js.map +1 -1
  13. package/dist/v1/operations/bridge/index.js +7 -6
  14. package/dist/v1/operations/bridge/index.js.map +1 -1
  15. package/dist/v1/operations/canonical.d.ts +1 -1
  16. package/dist/v1/operations/canonical.js +106 -57
  17. package/dist/v1/operations/canonical.js.map +1 -1
  18. package/dist/v1/operations/contracts/epistemicContract.d.ts +1 -1
  19. package/dist/v1/operations/contracts/epistemicContract.js +9 -3
  20. package/dist/v1/operations/contracts/epistemicContract.js.map +1 -1
  21. package/dist/v1/operations/contradiction/detectTupleContradiction.js.map +1 -1
  22. package/dist/v1/operations/contradiction/index.js.map +1 -1
  23. package/dist/v1/operations/dynamics/cascade.js +1 -1
  24. package/dist/v1/operations/dynamics/cascade.js.map +1 -1
  25. package/dist/v1/operations/dynamics/decay.js +105 -41
  26. package/dist/v1/operations/dynamics/decay.js.map +1 -1
  27. package/dist/v1/operations/dynamics/defeat.js.map +1 -1
  28. package/dist/v1/operations/dynamics/propagation.d.ts +3 -3
  29. package/dist/v1/operations/dynamics/propagation.js +101 -57
  30. package/dist/v1/operations/dynamics/propagation.js.map +1 -1
  31. package/dist/v1/operations/dynamics/revision.js +7 -6
  32. package/dist/v1/operations/dynamics/revision.js.map +1 -1
  33. package/dist/v1/operations/index.js +8 -3
  34. package/dist/v1/operations/index.js.map +1 -1
  35. package/dist/v1/operations/lucern.d.ts +7 -7
  36. package/dist/v1/operations/lucern.js +934 -807
  37. package/dist/v1/operations/lucern.js.map +1 -1
  38. package/dist/v1/operations/operatorTaxonomy.d.ts +10 -10
  39. package/dist/v1/operations/operatorTaxonomy.js.map +1 -1
  40. package/dist/v1/operations/scoring.d.ts +2 -1
  41. package/dist/v1/operations/scoring.js +20 -5
  42. package/dist/v1/operations/scoring.js.map +1 -1
  43. package/dist/v1/operations/subjectiveLogic/index.js +91 -54
  44. package/dist/v1/operations/subjectiveLogic/index.js.map +1 -1
  45. package/dist/v1/operations/temporalDecay.d.ts +3 -3
  46. package/dist/v1/operations/temporalDecay.js +8 -3
  47. package/dist/v1/operations/temporalDecay.js.map +1 -1
  48. package/dist/v1/types.d.ts +101 -101
  49. package/package.json +1 -1
package/dist/v1/index.js CHANGED
@@ -135,14 +135,91 @@ function computeConditionalDeductionBaseRate(opinionA, ifTrue, ifFalse, fallback
135
135
  }
136
136
  function safeCorrectionTerm(numerator, denominator) {
137
137
  if (Math.abs(denominator) <= EPSILON) {
138
- return void 0;
138
+ return;
139
139
  }
140
140
  const value = numerator / denominator;
141
141
  if (!Number.isFinite(value)) {
142
- return void 0;
142
+ return;
143
143
  }
144
144
  return Math.max(0, value);
145
145
  }
146
+ function correctionOrZero(numerator, denominator) {
147
+ return safeCorrectionTerm(numerator, denominator) ?? 0;
148
+ }
149
+ function hasNoConditionalDeductionCorrection(ifTrue, ifFalse) {
150
+ return ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d || ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d;
151
+ }
152
+ function usesLowerVacuousBranch(context) {
153
+ return context.projectedVacuousDeduction <= context.projectedConditionalA;
154
+ }
155
+ function usesLowerAntecedentBranch(context) {
156
+ return context.projectedAntecedent <= context.opinionA.a;
157
+ }
158
+ function computeTrueDominantDeductionCorrection(context) {
159
+ const beliefGap = context.ifTrue.b - context.ifFalse.b;
160
+ const disbeliefGap = context.ifFalse.d - context.ifTrue.d;
161
+ const lowerVacuous = usesLowerVacuousBranch(context);
162
+ const lowerAntecedent = usesLowerAntecedentBranch(context);
163
+ if (lowerVacuous && lowerAntecedent) {
164
+ return correctionOrZero(
165
+ context.opinionA.a * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b),
166
+ context.projectedAntecedent * context.childBaseRate
167
+ );
168
+ }
169
+ if (lowerVacuous) {
170
+ return correctionOrZero(
171
+ context.opinionA.a * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d) * beliefGap,
172
+ context.projectedAntecedentComplement * context.childBaseRate * disbeliefGap
173
+ );
174
+ }
175
+ if (lowerAntecedent) {
176
+ return correctionOrZero(
177
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b) * disbeliefGap,
178
+ context.projectedAntecedent * (1 - context.childBaseRate) * beliefGap
179
+ );
180
+ }
181
+ return correctionOrZero(
182
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d),
183
+ context.projectedAntecedentComplement * (1 - context.childBaseRate)
184
+ );
185
+ }
186
+ function computeFalseDominantDeductionCorrection(context) {
187
+ const beliefGap = context.ifFalse.b - context.ifTrue.b;
188
+ const disbeliefGap = context.ifTrue.d - context.ifFalse.d;
189
+ const lowerVacuous = usesLowerVacuousBranch(context);
190
+ const lowerAntecedent = usesLowerAntecedentBranch(context);
191
+ if (lowerVacuous && lowerAntecedent) {
192
+ return correctionOrZero(
193
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d) * beliefGap,
194
+ context.projectedAntecedent * context.childBaseRate * disbeliefGap
195
+ );
196
+ }
197
+ if (lowerVacuous) {
198
+ return correctionOrZero(
199
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b),
200
+ context.projectedAntecedentComplement * context.childBaseRate
201
+ );
202
+ }
203
+ if (lowerAntecedent) {
204
+ return correctionOrZero(
205
+ context.opinionA.a * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d),
206
+ context.projectedAntecedent * (1 - context.childBaseRate)
207
+ );
208
+ }
209
+ return correctionOrZero(
210
+ context.opinionA.a * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b) * disbeliefGap,
211
+ context.projectedAntecedentComplement * (1 - context.childBaseRate) * beliefGap
212
+ );
213
+ }
214
+ function computeConditionalDeductionCorrection(context) {
215
+ if (hasNoConditionalDeductionCorrection(context.ifTrue, context.ifFalse)) {
216
+ return 0;
217
+ }
218
+ if (context.ifTrue.b > context.ifFalse.b && context.ifTrue.d <= context.ifFalse.d) {
219
+ return computeTrueDominantDeductionCorrection(context);
220
+ }
221
+ return computeFalseDominantDeductionCorrection(context);
222
+ }
146
223
  function conditionalDeduction(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
147
224
  const fallbackChildBaseRate = childBaseRateFallback(
148
225
  ifTrue,
@@ -162,58 +239,18 @@ function conditionalDeduction(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
162
239
  const intermediateUncertainty = opinionA.b * ifTrue.u + opinionA.d * ifFalse.u + opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
163
240
  const projectedVacuousDeduction = ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a) + childBaseRate * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
164
241
  const projectedConditionalA = ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);
165
- let correction = 0;
166
- if (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d || ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d) {
167
- correction = 0;
168
- } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {
169
- const beliefGap = ifTrue.b - ifFalse.b;
170
- const disbeliefGap = ifFalse.d - ifTrue.d;
171
- if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
172
- correction = safeCorrectionTerm(
173
- opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),
174
- projectedAntecedent * childBaseRate
175
- ) ?? 0;
176
- } else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
177
- correction = safeCorrectionTerm(
178
- opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
179
- projectedAntecedentComplement * childBaseRate * disbeliefGap
180
- ) ?? 0;
181
- } else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
182
- correction = safeCorrectionTerm(
183
- (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
184
- projectedAntecedent * (1 - childBaseRate) * beliefGap
185
- ) ?? 0;
186
- } else {
187
- correction = safeCorrectionTerm(
188
- (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),
189
- projectedAntecedentComplement * (1 - childBaseRate)
190
- ) ?? 0;
191
- }
192
- } else {
193
- const beliefGap = ifFalse.b - ifTrue.b;
194
- const disbeliefGap = ifTrue.d - ifFalse.d;
195
- if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
196
- correction = safeCorrectionTerm(
197
- (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
198
- projectedAntecedent * childBaseRate * disbeliefGap
199
- ) ?? 0;
200
- } else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
201
- correction = safeCorrectionTerm(
202
- (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),
203
- projectedAntecedentComplement * childBaseRate
204
- ) ?? 0;
205
- } else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
206
- correction = safeCorrectionTerm(
207
- opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),
208
- projectedAntecedent * (1 - childBaseRate)
209
- ) ?? 0;
210
- } else {
211
- correction = safeCorrectionTerm(
212
- opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
213
- projectedAntecedentComplement * (1 - childBaseRate) * beliefGap
214
- ) ?? 0;
215
- }
216
- }
242
+ const correction = computeConditionalDeductionCorrection({
243
+ childBaseRate,
244
+ ifFalse,
245
+ ifTrue,
246
+ intermediateBelief,
247
+ intermediateDisbelief,
248
+ opinionA,
249
+ projectedAntecedent,
250
+ projectedAntecedentComplement,
251
+ projectedConditionalA,
252
+ projectedVacuousDeduction
253
+ });
217
254
  return opinion(
218
255
  intermediateBelief - childBaseRate * correction,
219
256
  intermediateDisbelief - (1 - childBaseRate) * correction,
@@ -353,7 +390,7 @@ function toEpochMs(value) {
353
390
  const epochMs = value.getTime();
354
391
  return Number.isFinite(epochMs) ? epochMs : void 0;
355
392
  }
356
- return void 0;
393
+ return;
357
394
  }
358
395
  function normalizeHalfLifeMs(halfLifeMs) {
359
396
  if (halfLifeMs === void 0 || !Number.isFinite(halfLifeMs)) {
@@ -375,9 +412,14 @@ function temporalDecay(sourceOpinion, now, decayParams) {
375
412
  if (ageMs === 0) {
376
413
  return { ...sourceOpinion };
377
414
  }
378
- const retainedEvidenceWeight = Math.pow(0.5, ageMs / halfLifeMs);
415
+ const retainedEvidenceWeight = 0.5 ** (ageMs / halfLifeMs);
379
416
  return trustDiscount(
380
- mkOpinion(sourceOpinion.b, sourceOpinion.d, sourceOpinion.u, sourceOpinion.a),
417
+ mkOpinion(
418
+ sourceOpinion.b,
419
+ sourceOpinion.d,
420
+ sourceOpinion.u,
421
+ sourceOpinion.a
422
+ ),
381
423
  retainedEvidenceWeight
382
424
  );
383
425
  }
@@ -408,7 +450,9 @@ function normalizeBaseRateVector(baseRate, size) {
408
450
  const normalized = baseRate.map((value) => clampNonNegative(value));
409
451
  const total = normalized.reduce((sum, value) => sum + value, 0);
410
452
  if (total === 0) {
411
- throw new Error("Base-rate vector must contain at least one positive value.");
453
+ throw new Error(
454
+ "Base-rate vector must contain at least one positive value."
455
+ );
412
456
  }
413
457
  return normalized.map((value) => value / total);
414
458
  }
@@ -437,11 +481,10 @@ function projectDirichletOpinion(opinion2) {
437
481
  );
438
482
  }
439
483
  function opinionFromBeta(alpha, beta, nonInformativeWeight, baseRate) {
440
- const dirichlet = opinionFromDirichlet(
441
- [alpha, beta],
442
- nonInformativeWeight,
443
- [clamp01(baseRate), 1 - clamp01(baseRate)]
444
- );
484
+ const dirichlet = opinionFromDirichlet([alpha, beta], nonInformativeWeight, [
485
+ clamp01(baseRate),
486
+ 1 - clamp01(baseRate)
487
+ ]);
445
488
  return mkOpinion(
446
489
  dirichlet.b[0] ?? 0,
447
490
  dirichlet.b[1] ?? 0,
@@ -464,417 +507,542 @@ function betaFromOpinion(opinion2, nonInformativeWeight = DEFAULT_NON_INFORMATIV
464
507
  };
465
508
  }
466
509
 
467
- // src/v1/operations/scoring.ts
468
- function finiteNumber(value) {
469
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
510
+ // src/v1/operations/contracts/epistemicContract.ts
511
+ var BUILT_IN_EVIDENTIAL_EVALUATOR = "evidential";
512
+ var BUILT_IN_EVIDENTIAL_ALIASES = /* @__PURE__ */ new Set([
513
+ BUILT_IN_EVIDENTIAL_EVALUATOR,
514
+ "built_in_evidential",
515
+ "builtin_evidential"
516
+ ]);
517
+ var BUILT_IN_METRIC_CHECKER = "metric_checker";
518
+ var BUILT_IN_REFERENCE_CHECK_COUNTER = "reference_check_counter";
519
+ var BUILT_IN_TEMPORAL_DEADLINE = "temporal_deadline";
520
+ var BUILT_IN_MARKET_INDEX_COMPARATOR = "market_index_comparator";
521
+ function clampConfidence(value) {
522
+ return Math.max(0, Math.min(1, value));
470
523
  }
471
- function requiredOpinionNumber(label, ...values) {
472
- for (const value of values) {
473
- const numberValue = finiteNumber(value);
474
- if (numberValue !== void 0) {
475
- return numberValue;
476
- }
524
+ function generateContractId() {
525
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
526
+ return crypto.randomUUID();
477
527
  }
478
- throw new Error(`Opinion record is missing required ${label}.`);
528
+ return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
479
529
  }
480
- function clamp012(value) {
481
- return Math.max(0, Math.min(1, value));
530
+ function isRecord(value) {
531
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
482
532
  }
483
- function confidenceFromOpinion(opinion2) {
484
- return clamp012(opinion2.b + opinion2.a * opinion2.u);
533
+ function deriveContractStatus(result, currentStatus) {
534
+ if (currentStatus === "archived") {
535
+ return currentStatus;
536
+ }
537
+ switch (result) {
538
+ case "confirmed":
539
+ return "satisfied";
540
+ case "disconfirmed":
541
+ return "violated";
542
+ case "expired":
543
+ return "expired";
544
+ default:
545
+ if (currentStatus === "satisfied" || currentStatus === "violated" || currentStatus === "expired") {
546
+ return "active";
547
+ }
548
+ return currentStatus;
549
+ }
485
550
  }
486
- function confidenceFromSL(belief, _disbelief, uncertainty, baseRate) {
487
- return confidenceFromOpinion({
488
- b: belief,
489
- u: uncertainty,
490
- a: baseRate
491
- });
551
+ function deriveVerificationTrigger(result) {
552
+ switch (result) {
553
+ case "confirmed":
554
+ return "verification_confirmed";
555
+ case "disconfirmed":
556
+ return "verification_disconfirmed";
557
+ case "expired":
558
+ return "verification_expired";
559
+ case "partial":
560
+ return "verification_partial";
561
+ default:
562
+ return null;
563
+ }
492
564
  }
493
- function toStoredOpinionFields(opinion2) {
565
+ function deriveContractModulationPlan(args) {
566
+ const trigger = deriveVerificationTrigger(args.result);
567
+ if (!trigger) {
568
+ return null;
569
+ }
570
+ if (args.result === "confirmed") {
571
+ const rawNext = args.currentConfidence + args.modulation.onConfirmed.delta;
572
+ const confidenceAfter = clampConfidence(
573
+ Math.min(
574
+ args.modulation.onConfirmed.ceiling ?? Number.POSITIVE_INFINITY,
575
+ rawNext
576
+ )
577
+ );
578
+ return {
579
+ trigger,
580
+ confidenceBefore: args.currentConfidence,
581
+ confidenceAfter,
582
+ confidenceDelta: confidenceAfter - args.currentConfidence
583
+ };
584
+ }
585
+ if (args.result === "disconfirmed") {
586
+ const rawNext = args.currentConfidence + args.modulation.onDisconfirmed.delta;
587
+ const confidenceAfter = clampConfidence(
588
+ Math.max(args.modulation.onDisconfirmed.floor ?? 0, rawNext)
589
+ );
590
+ return {
591
+ trigger,
592
+ confidenceBefore: args.currentConfidence,
593
+ confidenceAfter,
594
+ confidenceDelta: confidenceAfter - args.currentConfidence
595
+ };
596
+ }
597
+ if (args.result === "expired" && args.modulation.onExpired) {
598
+ const confidenceAfter = clampConfidence(
599
+ args.currentConfidence + args.modulation.onExpired.delta
600
+ );
601
+ return {
602
+ trigger,
603
+ confidenceBefore: args.currentConfidence,
604
+ confidenceAfter,
605
+ confidenceDelta: confidenceAfter - args.currentConfidence
606
+ };
607
+ }
608
+ if (args.result === "partial" && args.modulation.onPartial) {
609
+ if ((args.resultConfidence ?? 0) < args.modulation.onPartial.threshold) {
610
+ return null;
611
+ }
612
+ const confidenceAfter = clampConfidence(
613
+ args.currentConfidence + args.modulation.onPartial.delta
614
+ );
615
+ return {
616
+ trigger,
617
+ confidenceBefore: args.currentConfidence,
618
+ confidenceAfter,
619
+ confidenceDelta: confidenceAfter - args.currentConfidence
620
+ };
621
+ }
622
+ return null;
623
+ }
624
+ function createInheritedContractRecord(contract, args) {
494
625
  return {
495
- belief: opinion2.b,
496
- disbelief: opinion2.d,
497
- uncertainty: opinion2.u,
498
- baseRate: opinion2.a
626
+ beliefNodeId: args.beliefNodeId,
627
+ contractId: generateContractId(),
628
+ title: contract.title,
629
+ description: contract.description,
630
+ conditionType: contract.conditionType,
631
+ direction: contract.direction,
632
+ condition: contract.condition,
633
+ deadline: contract.deadline,
634
+ compositeOf: contract.compositeOf,
635
+ compositeOperator: contract.compositeOperator,
636
+ modulation: contract.modulation,
637
+ evaluationSchedule: contract.evaluationSchedule,
638
+ periodicIntervalMs: contract.periodicIntervalMs,
639
+ status: "active",
640
+ lineageSource: "inherited",
641
+ inheritedFromContractId: contract.contractId,
642
+ inheritedFromBeliefNodeId: contract.beliefNodeId,
643
+ inheritedAt: args.now,
644
+ topicId: args.topicId,
645
+ createdAt: args.now,
646
+ createdBy: args.createdBy,
647
+ updatedAt: args.now
499
648
  };
500
649
  }
501
- function readOpinionFromRecord(source) {
502
- const record = source && typeof source === "object" ? source : {};
503
- return mkOpinion(
504
- requiredOpinionNumber(
505
- "belief",
506
- record.b,
507
- record.belief,
508
- record.slBelief,
509
- record.opinion_b
510
- ),
511
- requiredOpinionNumber(
512
- "disbelief",
513
- record.d,
514
- record.disbelief,
515
- record.slDisbelief,
516
- record.opinion_d
517
- ),
518
- requiredOpinionNumber(
519
- "uncertainty",
520
- record.u,
521
- record.uncertainty,
522
- record.slUncertainty,
523
- record.opinion_u
524
- ),
525
- requiredOpinionNumber(
526
- "baseRate",
527
- record.a,
528
- record.baseRate,
529
- record.slBaseRate,
530
- record.opinion_a
531
- )
650
+ function normalizeEvidentialAction(value) {
651
+ return value === "append_sl_scoring" || value === "flag_review" || value === "archive" ? value : void 0;
652
+ }
653
+ function parseComparisonOperator(value, evaluatorName) {
654
+ if (value === "gte" || value === "lte" || value === "eq" || value === "gt" || value === "lt") {
655
+ return value;
656
+ }
657
+ throw new Error(
658
+ `${evaluatorName} requires operator to be one of gte, lte, eq, gt, or lt.`
532
659
  );
533
660
  }
534
- function opinionFromScalar(value, mode, options) {
535
- const clampedValue = clamp012(value);
536
- const baseRate = options?.baseRate === void 0 ? void 0 : clamp012(options.baseRate);
537
- switch (mode) {
538
- case "base_rate":
539
- return mkOpinion(0, 0, 1, clampedValue);
540
- case "dogmatic":
541
- if (baseRate === void 0) {
542
- throw new Error('opinionFromScalar(value, "dogmatic") requires options.baseRate.');
543
- }
544
- return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);
545
- case "projected_with_u": {
546
- if (baseRate === void 0) {
547
- throw new Error(
548
- 'opinionFromScalar(value, "projected_with_u") requires options.baseRate.'
549
- );
550
- }
551
- const uncertainty = options?.uncertainty;
552
- if (uncertainty === void 0) {
553
- throw new Error(
554
- 'opinionFromScalar(value, "projected_with_u") requires options.uncertainty.'
555
- );
556
- }
557
- const clampedUncertainty = clamp012(uncertainty);
558
- const evidenceWeight = 1 - clampedUncertainty;
559
- return mkOpinion(
560
- clampedValue * evidenceWeight,
561
- (1 - clampedValue) * evidenceWeight,
562
- clampedUncertainty,
563
- baseRate
564
- );
661
+ function parseNumericThreshold(value, evaluatorName) {
662
+ if (typeof value === "number" && Number.isFinite(value)) {
663
+ return value;
664
+ }
665
+ throw new Error(`${evaluatorName} requires a finite numeric threshold.`);
666
+ }
667
+ function pickFiniteNumber(config, keys) {
668
+ for (const key of keys) {
669
+ const value = config[key];
670
+ if (typeof value === "number" && Number.isFinite(value)) {
671
+ return value;
565
672
  }
566
673
  }
567
- throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);
674
+ return;
568
675
  }
569
- function toDogmaticOpinion(confidence, baseRate) {
570
- return opinionFromScalar(confidence, "dogmatic", { baseRate });
676
+ function getEvaluatorInputRecord(inputData, nestedKey) {
677
+ if (!isRecord(inputData)) {
678
+ return {};
679
+ }
680
+ const nested = inputData[nestedKey];
681
+ if (isRecord(nested)) {
682
+ return nested;
683
+ }
684
+ return inputData;
571
685
  }
572
- function opinionFromBaseRate(probability) {
573
- return vacuous(clamp012(probability));
686
+ function parseEvidentialEvaluatorConfig(value) {
687
+ if (!isRecord(value)) {
688
+ throw new Error(
689
+ "Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
690
+ );
691
+ }
692
+ const config = value;
693
+ const metric = config.metric;
694
+ const operator = config.operator;
695
+ const threshold = config.threshold;
696
+ if (metric !== "evidence_count" && metric !== "contradiction_status" && metric !== "edge_freshness" && metric !== "dependent_count") {
697
+ throw new Error(`Unsupported evidential metric: ${String(metric)}`);
698
+ }
699
+ if (operator !== "gte" && operator !== "lte" && operator !== "eq" && operator !== "gt" && operator !== "lt") {
700
+ throw new Error(`Unsupported evidential operator: ${String(operator)}`);
701
+ }
702
+ if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
703
+ throw new Error("Evidential contracts require a numeric threshold.");
704
+ }
705
+ const actionParams = isRecord(config.actionParams) ? config.actionParams : void 0;
706
+ return {
707
+ metric,
708
+ operator,
709
+ threshold,
710
+ action: normalizeEvidentialAction(config.action),
711
+ actionParams: actionParams && (typeof actionParams.targetConfidence === "number" || typeof actionParams.rationale === "string") ? {
712
+ targetConfidence: typeof actionParams.targetConfidence === "number" ? actionParams.targetConfidence : void 0,
713
+ rationale: typeof actionParams.rationale === "string" ? actionParams.rationale : void 0
714
+ } : void 0
715
+ };
574
716
  }
575
- function opinionFromDogmatic(probability, baseRate) {
576
- return dogmatic(clamp012(probability), clamp012(baseRate));
717
+ function compareMetricValue(operator, left, right) {
718
+ switch (operator) {
719
+ case "gte":
720
+ return left >= right;
721
+ case "lte":
722
+ return left <= right;
723
+ case "eq":
724
+ return left === right;
725
+ case "gt":
726
+ return left > right;
727
+ case "lt":
728
+ return left < right;
729
+ default:
730
+ return false;
731
+ }
577
732
  }
578
- function opinionFromProjected(probability, uncertainty, baseRate) {
579
- const p = clamp012(probability);
580
- const u = clamp012(uncertainty);
581
- const remainingMass = 1 - u;
582
- return mkOpinion(p * remainingMass, (1 - p) * remainingMass, u, clamp012(baseRate));
733
+ function resolveComparisonResult(direction, comparisonSatisfied) {
734
+ if (direction === "falsifies") {
735
+ return comparisonSatisfied ? "disconfirmed" : "confirmed";
736
+ }
737
+ return comparisonSatisfied ? "confirmed" : "disconfirmed";
583
738
  }
584
- function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
585
- return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
739
+ function buildComparisonRationale(args) {
740
+ const renderedObserved = args.observedValue === null ? "no data" : `${args.observedValue}${args.unit ? ` ${args.unit}` : ""}`;
741
+ const renderedThreshold = `${args.threshold}${args.unit ? ` ${args.unit}` : ""}`;
742
+ const clause = `${args.label} observed ${renderedObserved} against ${args.operator} ${renderedThreshold}`;
743
+ if (args.observedValue === null) {
744
+ return `${clause}; evaluator returned ${args.result} because no current data was available.`;
745
+ }
746
+ return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
586
747
  }
587
-
588
- // src/v1/operations/contradiction/detectTupleContradiction.ts
589
- var DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD = 0.7;
590
- var DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD = 0.7;
591
- function normalizeTupleContradictionPolicy(policy = {}) {
748
+ function buildEvidentialRationale(args) {
749
+ const observed = args.snapshot.value === null ? "no data" : String(args.snapshot.value);
750
+ const clause = `${args.snapshot.metric} observed ${observed} against ${args.config.operator} ${args.config.threshold}`;
751
+ if (args.snapshot.value === null) {
752
+ return `${clause}; evidential evaluator treated the comparison as unmet, resulting in ${args.result}.`;
753
+ }
754
+ return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
755
+ }
756
+ function parseMetricCheckerConfig(value) {
757
+ if (!isRecord(value)) {
758
+ throw new Error(
759
+ "metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
760
+ );
761
+ }
762
+ const config = value;
592
763
  return {
593
- beliefThreshold: clamp012(
594
- policy.beliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD
595
- ),
596
- disbeliefThreshold: clamp012(
597
- policy.disbeliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD
598
- )
764
+ metric: typeof config.metric === "string" && config.metric.length > 0 ? config.metric : void 0,
765
+ operator: parseComparisonOperator(config.operator, BUILT_IN_METRIC_CHECKER),
766
+ threshold: parseNumericThreshold(config.threshold, BUILT_IN_METRIC_CHECKER),
767
+ observedValue: pickFiniteNumber(config, ["observedValue", "value"]),
768
+ currentValue: pickFiniteNumber(config, ["currentValue"]),
769
+ metricValue: pickFiniteNumber(config, ["metricValue"]),
770
+ unit: typeof config.unit === "string" && config.unit.length > 0 ? config.unit : void 0
599
771
  };
600
772
  }
601
- function detectTupleContradiction(opinion2, tauB = DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, tauD = DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD) {
602
- return opinion2.b > tauB && opinion2.d > tauD;
603
- }
604
- function evaluateTupleContradictionTransition(args) {
605
- const policy = normalizeTupleContradictionPolicy(args.policy);
606
- const tupleContradicted = detectTupleContradiction(
607
- args.opinion,
608
- policy.beliefThreshold,
609
- policy.disbeliefThreshold
610
- );
611
- const previousTupleContradicted = Boolean(args.previousTupleContradicted);
773
+ function parseReferenceCheckCounterConfig(value) {
774
+ if (!isRecord(value)) {
775
+ throw new Error(
776
+ "reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
777
+ );
778
+ }
779
+ const config = value;
780
+ if (typeof config.tag !== "string" || config.tag.trim().length === 0) {
781
+ throw new Error("reference_check_counter requires a non-empty tag.");
782
+ }
612
783
  return {
613
- tupleContradicted,
614
- crossedIntoTupleContradiction: !previousTupleContradicted && tupleContradicted,
615
- crossedOutOfTupleContradiction: previousTupleContradicted && !tupleContradicted,
616
- policy
784
+ tag: config.tag.trim(),
785
+ operator: parseComparisonOperator(
786
+ config.operator,
787
+ BUILT_IN_REFERENCE_CHECK_COUNTER
788
+ ),
789
+ threshold: parseNumericThreshold(
790
+ config.threshold,
791
+ BUILT_IN_REFERENCE_CHECK_COUNTER
792
+ ),
793
+ caseSensitive: config.caseSensitive === true
617
794
  };
618
795
  }
619
-
620
- // src/v1/operations/dynamics/cascade.ts
621
- function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
622
- const dependencyProjection = project(
623
- mkOpinion(
624
- dependencyOpinion.b,
625
- dependencyOpinion.d,
626
- dependencyOpinion.u,
627
- dependencyOpinion.a
628
- )
629
- );
630
- if (mode === "threshold") {
631
- if (dependencyProjection < threshold) {
632
- return opinion(
633
- 0,
634
- beliefOpinion.d + beliefOpinion.b * 0.5,
635
- 0.5,
636
- beliefOpinion.a
637
- );
638
- }
639
- return beliefOpinion;
796
+ function parseTemporalDeadlineConfig(value) {
797
+ if (!isRecord(value)) {
798
+ return {};
640
799
  }
641
- const dampingFactor = Math.pow(dependencyProjection, 0.5);
642
- return opinion(
643
- beliefOpinion.b * dampingFactor,
644
- beliefOpinion.d + beliefOpinion.b * (1 - dampingFactor) * 0.3,
645
- beliefOpinion.u + beliefOpinion.b * (1 - dampingFactor) * 0.7,
646
- beliefOpinion.a
647
- );
648
- }
649
- function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "continuous") {
800
+ const config = value;
650
801
  return {
651
- opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
652
- operator: "dependency_cascade",
653
- rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
654
- mkOpinion(
655
- dependencyOpinion.b,
656
- dependencyOpinion.d,
657
- dependencyOpinion.u,
658
- dependencyOpinion.a
659
- )
660
- ).toFixed(2)}`
802
+ label: typeof config.label === "string" && config.label.length > 0 ? config.label : void 0,
803
+ completed: config.completed === true,
804
+ completedAt: pickFiniteNumber(config, ["completedAt"]),
805
+ observedAt: pickFiniteNumber(config, ["observedAt"]),
806
+ satisfiedAt: pickFiniteNumber(config, ["satisfiedAt"]),
807
+ achievedAt: pickFiniteNumber(config, ["achievedAt"])
661
808
  };
662
809
  }
663
-
664
- // src/v1/operations/dynamics/defeat.ts
665
- function applyNegativeSupport(source, target, weight, metadata = {}) {
666
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
667
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
668
- if (metadata.constraint === "xor") {
669
- const result = constraintFusion(
670
- sourceOpinion,
671
- targetOpinion,
672
- metadata.normalization ?? "pressure"
810
+ function parseMarketIndexComparatorConfig(value) {
811
+ if (!isRecord(value)) {
812
+ throw new Error(
813
+ "market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
673
814
  );
674
- return {
675
- opinion: result.o2,
676
- operator: "constraint_fusion",
677
- rationale: `XOR constraint: source belief at ${project(
678
- sourceOpinion
679
- ).toFixed(2)} pressures target`
680
- };
681
815
  }
682
- const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
816
+ const config = value;
683
817
  return {
684
- opinion: cumulativeFusion(targetOpinion, discounted),
685
- operator: "cumulative_fusion",
686
- rationale: `Contradicting evidence (weight=${weight.toFixed(
687
- 2
688
- )}) from source at ${project(sourceOpinion).toFixed(2)}`
689
- };
690
- }
691
- function applyNegativeEvidence(source, target, weight) {
692
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
693
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
694
- const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
695
- return {
696
- opinion: cumulativeFusion(targetOpinion, discounted),
697
- operator: "cumulative_fusion",
698
- rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
818
+ subject: typeof config.subject === "string" && config.subject.length > 0 ? config.subject : void 0,
819
+ subjectValue: pickFiniteNumber(config, ["subjectValue", "leftValue"]),
820
+ primaryValue: pickFiniteNumber(config, ["primaryValue"]),
821
+ benchmark: typeof config.benchmark === "string" && config.benchmark.length > 0 ? config.benchmark : void 0,
822
+ benchmarkValue: pickFiniteNumber(config, ["benchmarkValue", "rightValue"]),
823
+ comparisonValue: pickFiniteNumber(config, ["comparisonValue"]),
824
+ operator: parseComparisonOperator(
825
+ config.operator,
826
+ BUILT_IN_MARKET_INDEX_COMPARATOR
827
+ ),
828
+ threshold: parseNumericThreshold(
829
+ config.threshold,
830
+ BUILT_IN_MARKET_INDEX_COMPARATOR
831
+ )
699
832
  };
700
833
  }
701
834
 
702
- // src/v1/operations/dynamics/propagation.ts
703
- var EDGE_PROPAGATION_RULES = {
704
- supports: {
705
- direction: "outgoing",
706
- handler: (source, target, weight, metadata) => {
707
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
708
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
709
- if (weight < 0) {
710
- return applyNegativeSupport(sourceOpinion, targetOpinion, weight, metadata);
711
- }
712
- const discounted = trustDiscount(sourceOpinion, weight);
713
- return {
714
- opinion: cumulativeFusion(targetOpinion, discounted),
715
- operator: "cumulative_fusion",
716
- rationale: `Supporting evidence (weight=${weight.toFixed(
717
- 2
718
- )}) from source at ${project(sourceOpinion).toFixed(2)}`
719
- };
835
+ // src/v1/operations/scoring.ts
836
+ function finiteNumber(value) {
837
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
838
+ }
839
+ function requiredOpinionNumber(label, ...values) {
840
+ for (const value of values) {
841
+ const numberValue = finiteNumber(value);
842
+ if (numberValue !== void 0) {
843
+ return numberValue;
720
844
  }
721
- },
722
- informs: {
723
- direction: "outgoing",
724
- handler: (source, target, weight) => {
725
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
726
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
727
- if (weight < 0) {
728
- return applyNegativeEvidence(sourceOpinion, targetOpinion, weight);
845
+ }
846
+ throw new Error(`Opinion record is missing required ${label}.`);
847
+ }
848
+ function clamp012(value) {
849
+ return Math.max(0, Math.min(1, value));
850
+ }
851
+ function confidenceFromOpinion(opinion2) {
852
+ return clamp012(opinion2.b + opinion2.a * opinion2.u);
853
+ }
854
+ function confidenceFromSL(belief, _disbelief, uncertainty, baseRate) {
855
+ return confidenceFromOpinion({
856
+ b: belief,
857
+ u: uncertainty,
858
+ a: baseRate
859
+ });
860
+ }
861
+ function toStoredOpinionFields(opinion2) {
862
+ return {
863
+ belief: opinion2.b,
864
+ disbelief: opinion2.d,
865
+ uncertainty: opinion2.u,
866
+ baseRate: opinion2.a
867
+ };
868
+ }
869
+ function readOpinionFromRecord(source) {
870
+ const record = source && typeof source === "object" ? source : {};
871
+ return mkOpinion(
872
+ requiredOpinionNumber(
873
+ "belief",
874
+ record.b,
875
+ record.belief,
876
+ record.slBelief,
877
+ record.opinion_b
878
+ ),
879
+ requiredOpinionNumber(
880
+ "disbelief",
881
+ record.d,
882
+ record.disbelief,
883
+ record.slDisbelief,
884
+ record.opinion_d
885
+ ),
886
+ requiredOpinionNumber(
887
+ "uncertainty",
888
+ record.u,
889
+ record.uncertainty,
890
+ record.slUncertainty,
891
+ record.opinion_u
892
+ ),
893
+ requiredOpinionNumber(
894
+ "baseRate",
895
+ record.a,
896
+ record.baseRate,
897
+ record.slBaseRate,
898
+ record.opinion_a
899
+ )
900
+ );
901
+ }
902
+ function opinionFromScalar(value, mode, options) {
903
+ const clampedValue = clamp012(value);
904
+ const baseRate = options?.baseRate === void 0 ? void 0 : clamp012(options.baseRate);
905
+ switch (mode) {
906
+ case "base_rate":
907
+ return mkOpinion(0, 0, 1, clampedValue);
908
+ case "dogmatic":
909
+ if (baseRate === void 0) {
910
+ throw new Error(
911
+ 'opinionFromScalar(value, "dogmatic") requires options.baseRate.'
912
+ );
729
913
  }
730
- const discounted = trustDiscount(sourceOpinion, Math.abs(weight));
731
- return {
732
- opinion: cumulativeFusion(targetOpinion, discounted),
733
- operator: "cumulative_fusion",
734
- rationale: `Supporting evidence (weight=${weight.toFixed(2)})`
735
- };
736
- }
737
- },
738
- depends_on: {
739
- direction: "incoming",
740
- handler: (source, target, _weight, metadata) => {
741
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
742
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
743
- if (metadata.conditionalA && metadata.conditionalNotA) {
744
- return {
745
- opinion: conditionalDeduction(
746
- sourceOpinion,
747
- mkOpinion(
748
- metadata.conditionalA.b,
749
- metadata.conditionalA.d,
750
- metadata.conditionalA.u,
751
- metadata.conditionalA.a
752
- ),
753
- mkOpinion(
754
- metadata.conditionalNotA.b,
755
- metadata.conditionalNotA.d,
756
- metadata.conditionalNotA.u,
757
- metadata.conditionalNotA.a
758
- ),
759
- targetOpinion.a
760
- ),
761
- operator: "conditional_deduction",
762
- rationale: `Conditional deduction: prerequisite at ${project(
763
- sourceOpinion
764
- ).toFixed(2)}`
765
- };
914
+ return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);
915
+ case "projected_with_u": {
916
+ if (baseRate === void 0) {
917
+ throw new Error(
918
+ 'opinionFromScalar(value, "projected_with_u") requires options.baseRate.'
919
+ );
766
920
  }
767
- return dampedDependencyCascade(
768
- sourceOpinion,
769
- targetOpinion,
770
- metadata.propagation ?? "continuous"
921
+ const uncertainty = options?.uncertainty;
922
+ if (uncertainty === void 0) {
923
+ throw new Error(
924
+ 'opinionFromScalar(value, "projected_with_u") requires options.uncertainty.'
925
+ );
926
+ }
927
+ const clampedUncertainty = clamp012(uncertainty);
928
+ const evidenceWeight = 1 - clampedUncertainty;
929
+ return mkOpinion(
930
+ clampedValue * evidenceWeight,
931
+ (1 - clampedValue) * evidenceWeight,
932
+ clampedUncertainty,
933
+ baseRate
771
934
  );
772
935
  }
773
- },
774
- derived_from: {
775
- direction: "incoming",
776
- handler: (_source, target) => ({
777
- opinion: target,
778
- operator: "trust_discount",
779
- rationale: "Provenance edge \u2014 no confidence propagation"
780
- })
781
- },
782
- contains: {
783
- direction: "outgoing",
784
- handler: (_source, target) => ({
785
- opinion: target,
786
- operator: "trust_discount",
787
- rationale: "Containment edge \u2014 no confidence propagation"
788
- })
789
- },
790
- tests: {
791
- direction: "outgoing",
792
- handler: (_source, target) => ({
793
- opinion: target,
794
- operator: "trust_discount",
795
- rationale: "Testing edge \u2014 no confidence propagation"
796
- })
936
+ default:
937
+ throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);
797
938
  }
798
- };
799
- var PROPAGATION_TRAVERSAL_SPECS = Object.entries(EDGE_PROPAGATION_RULES).map(([edgeType, rule]) => ({
800
- edgeType,
801
- direction: rule.direction
802
- }));
803
- function isPropagationEdgeType(edgeType) {
804
- return edgeType in EDGE_PROPAGATION_RULES;
805
939
  }
806
- function getPropagationTraversalSpecs() {
807
- return PROPAGATION_TRAVERSAL_SPECS;
940
+ function toDogmaticOpinion(confidence, baseRate) {
941
+ return opinionFromScalar(confidence, "dogmatic", { baseRate });
808
942
  }
809
- function propagateThroughEdge(sourceOpinion, targetOpinion, edgeType, weight = 1, metadata = {}) {
810
- const handler = isPropagationEdgeType(edgeType) ? EDGE_PROPAGATION_RULES[edgeType].handler : void 0;
811
- if (!handler) {
812
- return {
813
- opinion: targetOpinion,
814
- operator: "no_op",
815
- rationale: `Unknown edge type: ${edgeType} \u2014 no propagation`
816
- };
817
- }
818
- return handler(sourceOpinion, targetOpinion, weight, metadata);
943
+ function opinionFromBaseRate(probability) {
944
+ return vacuous(clamp012(probability));
819
945
  }
820
- function propagateAllEdges(currentOpinion, incomingEdges) {
821
- let result = currentOpinion;
822
- const rationales = [];
823
- for (const edgeType of ["depends_on", "informs", "supports"]) {
824
- for (const incoming of incomingEdges.filter((edge) => edge.edgeType === edgeType)) {
825
- const propagated = propagateThroughEdge(
826
- incoming.sourceOpinion,
827
- result,
828
- incoming.edgeType,
829
- incoming.weight,
830
- incoming.metadata
831
- );
832
- result = propagated.opinion;
833
- rationales.push(propagated.rationale);
834
- }
835
- }
836
- return {
837
- opinion: result,
838
- operator: "cumulative_fusion",
839
- rationale: rationales.join("; ")
840
- };
946
+ function opinionFromDogmatic(probability, baseRate) {
947
+ return dogmatic(clamp012(probability), clamp012(baseRate));
841
948
  }
842
-
843
- // src/v1/operations/dynamics/revision.ts
844
- function clamp013(value) {
845
- return Math.max(0, Math.min(1, value));
949
+ function representableProjectedUncertainty(probability, uncertainty, baseRate) {
950
+ const maxBeliefUncertainty = baseRate > 0 ? probability / baseRate : Number.POSITIVE_INFINITY;
951
+ const maxDisbeliefUncertainty = baseRate < 1 ? (1 - probability) / (1 - baseRate) : Number.POSITIVE_INFINITY;
952
+ return clamp012(
953
+ Math.min(uncertainty, maxBeliefUncertainty, maxDisbeliefUncertainty)
954
+ );
846
955
  }
847
- function toEvidence(probability, weight) {
848
- const safeProbability = clamp013(probability);
849
- const safeWeight = Number.isFinite(weight) ? Math.max(0, weight) : 0;
956
+ function opinionFromProjected(probability, uncertainty, baseRate) {
957
+ const p = clamp012(probability);
958
+ const a = clamp012(baseRate);
959
+ const u = representableProjectedUncertainty(p, clamp012(uncertainty), a);
960
+ return mkOpinion(
961
+ Math.max(0, p - a * u),
962
+ Math.max(0, 1 - p - (1 - a) * u),
963
+ u,
964
+ a
965
+ );
966
+ }
967
+ function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
968
+ return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
969
+ }
970
+
971
+ // src/v1/operations/contradiction/detectTupleContradiction.ts
972
+ var DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD = 0.7;
973
+ var DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD = 0.7;
974
+ function normalizeTupleContradictionPolicy(policy = {}) {
850
975
  return {
851
- alpha: safeProbability * safeWeight,
852
- beta: (1 - safeProbability) * safeWeight
976
+ beliefThreshold: clamp012(
977
+ policy.beliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD
978
+ ),
979
+ disbeliefThreshold: clamp012(
980
+ policy.disbeliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD
981
+ )
853
982
  };
854
983
  }
855
- function bayesianUpdate(priorConfidence, priorWeight, newAssessment, newWeight, options) {
856
- return reviseConfidence({
857
- priorConfidence,
858
- priorWeight,
859
- newAssessment,
860
- newWeight,
861
- baseRate: options?.baseRate,
862
- nonInformativeWeight: options?.nonInformativeWeight
863
- });
984
+ function detectTupleContradiction(opinion2, tauB = DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, tauD = DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD) {
985
+ return opinion2.b > tauB && opinion2.d > tauD;
864
986
  }
865
- function reviseConfidence(args) {
866
- return project(reviseConfidenceOpinion(args));
987
+ function evaluateTupleContradictionTransition(args) {
988
+ const policy = normalizeTupleContradictionPolicy(args.policy);
989
+ const tupleContradicted = detectTupleContradiction(
990
+ args.opinion,
991
+ policy.beliefThreshold,
992
+ policy.disbeliefThreshold
993
+ );
994
+ const previousTupleContradicted = Boolean(args.previousTupleContradicted);
995
+ return {
996
+ tupleContradicted,
997
+ crossedIntoTupleContradiction: !previousTupleContradicted && tupleContradicted,
998
+ crossedOutOfTupleContradiction: previousTupleContradicted && !tupleContradicted,
999
+ policy
1000
+ };
867
1001
  }
868
- function reviseConfidenceOpinion(args) {
869
- const priorEvidence = toEvidence(args.priorConfidence, args.priorWeight);
870
- const newEvidence = toEvidence(args.newAssessment, args.newWeight ?? 1);
871
- return opinionFromBeta(
872
- priorEvidence.alpha + newEvidence.alpha,
873
- priorEvidence.beta + newEvidence.beta,
874
- args.nonInformativeWeight ?? DEFAULT_NON_INFORMATIVE_WEIGHT,
875
- args.baseRate
1002
+
1003
+ // src/v1/operations/dynamics/cascade.ts
1004
+ function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
1005
+ const dependencyProjection = project(
1006
+ mkOpinion(
1007
+ dependencyOpinion.b,
1008
+ dependencyOpinion.d,
1009
+ dependencyOpinion.u,
1010
+ dependencyOpinion.a
1011
+ )
1012
+ );
1013
+ if (mode === "threshold") {
1014
+ if (dependencyProjection < threshold) {
1015
+ return opinion(
1016
+ 0,
1017
+ beliefOpinion.d + beliefOpinion.b * 0.5,
1018
+ 0.5,
1019
+ beliefOpinion.a
1020
+ );
1021
+ }
1022
+ return beliefOpinion;
1023
+ }
1024
+ const dampingFactor = dependencyProjection ** 0.5;
1025
+ return opinion(
1026
+ beliefOpinion.b * dampingFactor,
1027
+ beliefOpinion.d + beliefOpinion.b * (1 - dampingFactor) * 0.3,
1028
+ beliefOpinion.u + beliefOpinion.b * (1 - dampingFactor) * 0.7,
1029
+ beliefOpinion.a
876
1030
  );
877
1031
  }
1032
+ function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "continuous") {
1033
+ return {
1034
+ opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
1035
+ operator: "dependency_cascade",
1036
+ rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
1037
+ mkOpinion(
1038
+ dependencyOpinion.b,
1039
+ dependencyOpinion.d,
1040
+ dependencyOpinion.u,
1041
+ dependencyOpinion.a
1042
+ )
1043
+ ).toFixed(2)}`
1044
+ };
1045
+ }
878
1046
 
879
1047
  // src/v1/operations/dynamics/decay.ts
880
1048
  var DECAY_TIERS = {
@@ -974,22 +1142,118 @@ function resolveLifecycleBucket(args) {
974
1142
  if (normalizeBeliefConfidence(args.confidence) === 0 || normalizeBeliefConfidence(args.confidence) === 1 || hasResolvedPredictionOutcome(args.predictionMeta)) {
975
1143
  return "fact";
976
1144
  }
977
- if (args.beliefStatus === "assumption" || args.beliefStatus === "hypothesis" || args.beliefStatus === "belief" || args.beliefStatus === "fact") {
978
- if (normalizeBeliefConfidence(args.confidence) !== null && (args.beliefStatus === "assumption" || args.beliefStatus === "hypothesis")) {
979
- return "belief";
980
- }
981
- return args.beliefStatus;
1145
+ if (args.beliefStatus === "assumption" || args.beliefStatus === "hypothesis" || args.beliefStatus === "belief" || args.beliefStatus === "fact") {
1146
+ if (normalizeBeliefConfidence(args.confidence) !== null && (args.beliefStatus === "assumption" || args.beliefStatus === "hypothesis")) {
1147
+ return "belief";
1148
+ }
1149
+ return args.beliefStatus;
1150
+ }
1151
+ return "assumption";
1152
+ }
1153
+ function lifecycleMultiplier(status) {
1154
+ if (status === "assumption") {
1155
+ return 0.65;
1156
+ }
1157
+ if (status === "hypothesis") {
1158
+ return 0.8;
1159
+ }
1160
+ return 1;
1161
+ }
1162
+ function resolveLifecycleRescore(context) {
1163
+ if (context.isOverdue && context.lifecycleStatus === "assumption") {
1164
+ return {
1165
+ priority: "critical",
1166
+ reason: `Untested assumption is stale (${Math.round(context.decayState.ageDays)}d) \u2014 validate or supersede`
1167
+ };
1168
+ }
1169
+ if (context.isOverdue && context.lifecycleStatus === "hypothesis" || context.lifecycleStatus === "hypothesis" && context.daysUntilRescore < 7) {
1170
+ return {
1171
+ priority: "high",
1172
+ reason: `Hypothesis aging without validation (${Math.round(context.decayState.ageDays)}d) \u2014 run/finish sprint testing`
1173
+ };
1174
+ }
1175
+ }
1176
+ function resolveDeadlineRescore(context) {
1177
+ const urgency = context.decayState.urgency;
1178
+ if (urgency?.isOverdue) {
1179
+ return {
1180
+ priority: "critical",
1181
+ reason: `Prediction deadline passed ${Math.abs(urgency.daysToDeadline)}d ago \u2014 validate or archive`
1182
+ };
1183
+ }
1184
+ if (urgency?.urgencyTier.label === "critical") {
1185
+ return {
1186
+ priority: "critical",
1187
+ reason: `Deadline in ${urgency.daysToDeadline}d \u2014 needs immediate rescoring`
1188
+ };
1189
+ }
1190
+ if (urgency?.urgencyTier.label === "imminent") {
1191
+ return {
1192
+ priority: "high",
1193
+ reason: `Deadline in ${urgency.daysToDeadline}d \u2014 weekly rescoring required`
1194
+ };
1195
+ }
1196
+ }
1197
+ function resolveStalenessRescore(context) {
1198
+ if (context.isOverdue && context.decayState.baseTier.label === "expired") {
1199
+ return {
1200
+ priority: "critical",
1201
+ reason: `Not scored in ${Math.round(context.decayState.ageDays)}d \u2014 confidence severely degraded`
1202
+ };
1203
+ }
1204
+ if (context.isOverdue && context.decayState.baseTier.label === "stale") {
1205
+ return {
1206
+ priority: "high",
1207
+ reason: `Stale (${Math.round(context.decayState.ageDays)}d since scoring) \u2014 evidence update required`
1208
+ };
1209
+ }
1210
+ if (context.isOverdue) {
1211
+ return {
1212
+ priority: "high",
1213
+ reason: `Rescore overdue by ${Math.abs(Math.round(context.daysUntilRescore))}d`
1214
+ };
1215
+ }
1216
+ }
1217
+ function resolveRoutineRescore(context) {
1218
+ if (context.temporalNature === "forecast" && context.daysUntilRescore < 7) {
1219
+ return {
1220
+ priority: "medium",
1221
+ reason: `Forecast belief \u2014 next rescore due in ${Math.round(context.daysUntilRescore)}d`
1222
+ };
1223
+ }
1224
+ if (context.daysUntilRescore < 14) {
1225
+ return {
1226
+ priority: "medium",
1227
+ reason: `Rescore due in ${Math.round(context.daysUntilRescore)}d`
1228
+ };
982
1229
  }
983
- return "assumption";
1230
+ return {
1231
+ priority: "low",
1232
+ reason: `On schedule \u2014 next rescore in ${Math.round(context.daysUntilRescore)}d`
1233
+ };
984
1234
  }
985
- function lifecycleMultiplier(status) {
986
- if (status === "assumption") {
987
- return 0.65;
1235
+ function escalateHighConfidenceRescore(result, context) {
1236
+ if ((context.confidence ?? 0) >= 0.8 && context.decayState.baseTier.label !== "fresh" && result.priority === "medium") {
1237
+ return {
1238
+ priority: "high",
1239
+ reason: `High-confidence belief (${((context.confidence ?? 0) * 100).toFixed(0)}%) aging without rescore \u2014 ${result.reason}`
1240
+ };
988
1241
  }
989
- if (status === "hypothesis") {
990
- return 0.8;
1242
+ return result;
1243
+ }
1244
+ var RESCORING_RULES = [
1245
+ resolveLifecycleRescore,
1246
+ resolveDeadlineRescore,
1247
+ resolveStalenessRescore
1248
+ ];
1249
+ function resolveRescoringPriority(context) {
1250
+ for (const rule of RESCORING_RULES) {
1251
+ const result = rule(context);
1252
+ if (result) {
1253
+ return escalateHighConfidenceRescore(result, context);
1254
+ }
991
1255
  }
992
- return 1;
1256
+ return escalateHighConfidenceRescore(resolveRoutineRescore(context), context);
993
1257
  }
994
1258
  function computeBaseDecay(lastScoredAt) {
995
1259
  const ageDays = (Date.now() - lastScoredAt) / (1e3 * 60 * 60 * 24);
@@ -1062,46 +1326,14 @@ function getRescoringSchedule(opts) {
1062
1326
  );
1063
1327
  const daysUntilRescore = (decayState.rescoreByDate - Date.now()) / (1e3 * 60 * 60 * 24);
1064
1328
  const isOverdue = daysUntilRescore < 0;
1065
- let priority;
1066
- let reason;
1067
- if (isOverdue && lifecycleStatus === "assumption") {
1068
- priority = "critical";
1069
- reason = `Untested assumption is stale (${Math.round(decayState.ageDays)}d) \u2014 validate or supersede`;
1070
- } else if (isOverdue && lifecycleStatus === "hypothesis" || lifecycleStatus === "hypothesis" && daysUntilRescore < 7) {
1071
- priority = "high";
1072
- reason = `Hypothesis aging without validation (${Math.round(decayState.ageDays)}d) \u2014 run/finish sprint testing`;
1073
- } else if (decayState.urgency?.isOverdue) {
1074
- priority = "critical";
1075
- reason = `Prediction deadline passed ${Math.abs(decayState.urgency.daysToDeadline)}d ago \u2014 validate or archive`;
1076
- } else if (isOverdue && decayState.baseTier.label === "expired") {
1077
- priority = "critical";
1078
- reason = `Not scored in ${Math.round(decayState.ageDays)}d \u2014 confidence severely degraded`;
1079
- } else if (isOverdue && decayState.baseTier.label === "stale") {
1080
- priority = "high";
1081
- reason = `Stale (${Math.round(decayState.ageDays)}d since scoring) \u2014 evidence update required`;
1082
- } else if (decayState.urgency && decayState.urgency.urgencyTier.label === "critical") {
1083
- priority = "critical";
1084
- reason = `Deadline in ${decayState.urgency.daysToDeadline}d \u2014 needs immediate rescoring`;
1085
- } else if (decayState.urgency && decayState.urgency.urgencyTier.label === "imminent") {
1086
- priority = "high";
1087
- reason = `Deadline in ${decayState.urgency.daysToDeadline}d \u2014 weekly rescoring required`;
1088
- } else if (isOverdue) {
1089
- priority = "high";
1090
- reason = `Rescore overdue by ${Math.abs(Math.round(daysUntilRescore))}d`;
1091
- } else if (opts.temporalNature === "forecast" && daysUntilRescore < 7) {
1092
- priority = "medium";
1093
- reason = `Forecast belief \u2014 next rescore due in ${Math.round(daysUntilRescore)}d`;
1094
- } else if (daysUntilRescore < 14) {
1095
- priority = "medium";
1096
- reason = `Rescore due in ${Math.round(daysUntilRescore)}d`;
1097
- } else {
1098
- priority = "low";
1099
- reason = `On schedule \u2014 next rescore in ${Math.round(daysUntilRescore)}d`;
1100
- }
1101
- if ((opts.confidence ?? 0) >= 0.8 && decayState.baseTier.label !== "fresh" && priority === "medium") {
1102
- priority = "high";
1103
- reason = `High-confidence belief (${((opts.confidence ?? 0) * 100).toFixed(0)}%) aging without rescore \u2014 ${reason}`;
1104
- }
1329
+ const { priority, reason } = resolveRescoringPriority({
1330
+ confidence: opts.confidence,
1331
+ daysUntilRescore,
1332
+ decayState,
1333
+ isOverdue,
1334
+ lifecycleStatus,
1335
+ temporalNature: opts.temporalNature
1336
+ });
1105
1337
  return {
1106
1338
  nextRescoreBy: decayState.rescoreByDate,
1107
1339
  daysUntilRescore: Math.round(daysUntilRescore),
@@ -1115,7 +1347,7 @@ function decay(current, daysSinceLastUpdate, halfLifeDays = 90) {
1115
1347
  if (daysSinceLastUpdate <= 0) {
1116
1348
  return current;
1117
1349
  }
1118
- const decayFactor = Math.pow(0.5, daysSinceLastUpdate / halfLifeDays);
1350
+ const decayFactor = 0.5 ** (daysSinceLastUpdate / halfLifeDays);
1119
1351
  const certainty = current.b + current.d;
1120
1352
  const lostCertainty = certainty - certainty * decayFactor;
1121
1353
  return opinion(
@@ -1126,323 +1358,226 @@ function decay(current, daysSinceLastUpdate, halfLifeDays = 90) {
1126
1358
  );
1127
1359
  }
1128
1360
 
1129
- // src/v1/operations/contracts/epistemicContract.ts
1130
- var BUILT_IN_EVIDENTIAL_EVALUATOR = "evidential";
1131
- var BUILT_IN_EVIDENTIAL_ALIASES = /* @__PURE__ */ new Set([
1132
- BUILT_IN_EVIDENTIAL_EVALUATOR,
1133
- "built_in_evidential",
1134
- "builtin_evidential"
1135
- ]);
1136
- var BUILT_IN_METRIC_CHECKER = "metric_checker";
1137
- var BUILT_IN_REFERENCE_CHECK_COUNTER = "reference_check_counter";
1138
- var BUILT_IN_TEMPORAL_DEADLINE = "temporal_deadline";
1139
- var BUILT_IN_MARKET_INDEX_COMPARATOR = "market_index_comparator";
1140
- function clampConfidence(value) {
1141
- return Math.max(0, Math.min(1, value));
1142
- }
1143
- function generateContractId() {
1144
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1145
- return crypto.randomUUID();
1146
- }
1147
- return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
1148
- }
1149
- function isRecord(value) {
1150
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1151
- }
1152
- function deriveContractStatus(result, currentStatus) {
1153
- if (currentStatus === "archived") {
1154
- return currentStatus;
1155
- }
1156
- switch (result) {
1157
- case "confirmed":
1158
- return "satisfied";
1159
- case "disconfirmed":
1160
- return "violated";
1161
- case "expired":
1162
- return "expired";
1163
- default:
1164
- return currentStatus === "satisfied" || currentStatus === "violated" || currentStatus === "expired" ? "active" : currentStatus;
1165
- }
1166
- }
1167
- function deriveVerificationTrigger(result) {
1168
- switch (result) {
1169
- case "confirmed":
1170
- return "verification_confirmed";
1171
- case "disconfirmed":
1172
- return "verification_disconfirmed";
1173
- case "expired":
1174
- return "verification_expired";
1175
- case "partial":
1176
- return "verification_partial";
1177
- default:
1178
- return null;
1179
- }
1180
- }
1181
- function deriveContractModulationPlan(args) {
1182
- const trigger = deriveVerificationTrigger(args.result);
1183
- if (!trigger) {
1184
- return null;
1185
- }
1186
- if (args.result === "confirmed") {
1187
- const rawNext = args.currentConfidence + args.modulation.onConfirmed.delta;
1188
- const confidenceAfter = clampConfidence(
1189
- Math.min(
1190
- args.modulation.onConfirmed.ceiling ?? Number.POSITIVE_INFINITY,
1191
- rawNext
1192
- )
1193
- );
1194
- return {
1195
- trigger,
1196
- confidenceBefore: args.currentConfidence,
1197
- confidenceAfter,
1198
- confidenceDelta: confidenceAfter - args.currentConfidence
1199
- };
1200
- }
1201
- if (args.result === "disconfirmed") {
1202
- const rawNext = args.currentConfidence + args.modulation.onDisconfirmed.delta;
1203
- const confidenceAfter = clampConfidence(
1204
- Math.max(args.modulation.onDisconfirmed.floor ?? 0, rawNext)
1205
- );
1206
- return {
1207
- trigger,
1208
- confidenceBefore: args.currentConfidence,
1209
- confidenceAfter,
1210
- confidenceDelta: confidenceAfter - args.currentConfidence
1211
- };
1212
- }
1213
- if (args.result === "expired" && args.modulation.onExpired) {
1214
- const confidenceAfter = clampConfidence(
1215
- args.currentConfidence + args.modulation.onExpired.delta
1361
+ // src/v1/operations/dynamics/defeat.ts
1362
+ function applyNegativeSupport(source, target, weight, metadata = {}) {
1363
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1364
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1365
+ if (metadata.constraint === "xor") {
1366
+ const result = constraintFusion(
1367
+ sourceOpinion,
1368
+ targetOpinion,
1369
+ metadata.normalization ?? "pressure"
1216
1370
  );
1217
1371
  return {
1218
- trigger,
1219
- confidenceBefore: args.currentConfidence,
1220
- confidenceAfter,
1221
- confidenceDelta: confidenceAfter - args.currentConfidence
1372
+ opinion: result.o2,
1373
+ operator: "constraint_fusion",
1374
+ rationale: `XOR constraint: source belief at ${project(
1375
+ sourceOpinion
1376
+ ).toFixed(2)} pressures target`
1222
1377
  };
1223
1378
  }
1224
- if (args.result === "partial" && args.modulation.onPartial) {
1225
- if ((args.resultConfidence ?? 0) < args.modulation.onPartial.threshold) {
1226
- return null;
1379
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
1380
+ return {
1381
+ opinion: cumulativeFusion(targetOpinion, discounted),
1382
+ operator: "cumulative_fusion",
1383
+ rationale: `Contradicting evidence (weight=${weight.toFixed(
1384
+ 2
1385
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
1386
+ };
1387
+ }
1388
+ function applyNegativeEvidence(source, target, weight) {
1389
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1390
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1391
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
1392
+ return {
1393
+ opinion: cumulativeFusion(targetOpinion, discounted),
1394
+ operator: "cumulative_fusion",
1395
+ rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
1396
+ };
1397
+ }
1398
+
1399
+ // src/v1/operations/dynamics/propagation.ts
1400
+ var EDGE_PROPAGATION_RULES = {
1401
+ supports: {
1402
+ direction: "outgoing",
1403
+ handler: (source, target, weight, metadata) => {
1404
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1405
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1406
+ if (weight < 0) {
1407
+ return applyNegativeSupport(
1408
+ sourceOpinion,
1409
+ targetOpinion,
1410
+ weight,
1411
+ metadata
1412
+ );
1413
+ }
1414
+ const discounted = trustDiscount(sourceOpinion, weight);
1415
+ return {
1416
+ opinion: cumulativeFusion(targetOpinion, discounted),
1417
+ operator: "cumulative_fusion",
1418
+ rationale: `Supporting evidence (weight=${weight.toFixed(
1419
+ 2
1420
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
1421
+ };
1227
1422
  }
1228
- const confidenceAfter = clampConfidence(
1229
- args.currentConfidence + args.modulation.onPartial.delta
1230
- );
1231
- return {
1232
- trigger,
1233
- confidenceBefore: args.currentConfidence,
1234
- confidenceAfter,
1235
- confidenceDelta: confidenceAfter - args.currentConfidence
1236
- };
1423
+ },
1424
+ informs: {
1425
+ direction: "outgoing",
1426
+ handler: (source, target, weight) => {
1427
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1428
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1429
+ if (weight < 0) {
1430
+ return applyNegativeEvidence(sourceOpinion, targetOpinion, weight);
1431
+ }
1432
+ const discounted = trustDiscount(sourceOpinion, Math.abs(weight));
1433
+ return {
1434
+ opinion: cumulativeFusion(targetOpinion, discounted),
1435
+ operator: "cumulative_fusion",
1436
+ rationale: `Supporting evidence (weight=${weight.toFixed(2)})`
1437
+ };
1438
+ }
1439
+ },
1440
+ depends_on: {
1441
+ direction: "incoming",
1442
+ handler: (source, target, _weight, metadata) => {
1443
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1444
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1445
+ if (metadata.conditionalA && metadata.conditionalNotA) {
1446
+ return {
1447
+ opinion: conditionalDeduction(
1448
+ sourceOpinion,
1449
+ mkOpinion(
1450
+ metadata.conditionalA.b,
1451
+ metadata.conditionalA.d,
1452
+ metadata.conditionalA.u,
1453
+ metadata.conditionalA.a
1454
+ ),
1455
+ mkOpinion(
1456
+ metadata.conditionalNotA.b,
1457
+ metadata.conditionalNotA.d,
1458
+ metadata.conditionalNotA.u,
1459
+ metadata.conditionalNotA.a
1460
+ ),
1461
+ targetOpinion.a
1462
+ ),
1463
+ operator: "conditional_deduction",
1464
+ rationale: `Conditional deduction: prerequisite at ${project(
1465
+ sourceOpinion
1466
+ ).toFixed(2)}`
1467
+ };
1468
+ }
1469
+ return dampedDependencyCascade(
1470
+ sourceOpinion,
1471
+ targetOpinion,
1472
+ metadata.propagation ?? "continuous"
1473
+ );
1474
+ }
1475
+ },
1476
+ derived_from: {
1477
+ direction: "incoming",
1478
+ handler: (_source, target) => ({
1479
+ opinion: target,
1480
+ operator: "trust_discount",
1481
+ rationale: "Provenance edge \u2014 no confidence propagation"
1482
+ })
1483
+ },
1484
+ contains: {
1485
+ direction: "outgoing",
1486
+ handler: (_source, target) => ({
1487
+ opinion: target,
1488
+ operator: "trust_discount",
1489
+ rationale: "Containment edge \u2014 no confidence propagation"
1490
+ })
1491
+ },
1492
+ tests: {
1493
+ direction: "outgoing",
1494
+ handler: (_source, target) => ({
1495
+ opinion: target,
1496
+ operator: "trust_discount",
1497
+ rationale: "Testing edge \u2014 no confidence propagation"
1498
+ })
1237
1499
  }
1238
- return null;
1239
- }
1240
- function createInheritedContractRecord(contract, args) {
1241
- return {
1242
- beliefNodeId: args.beliefNodeId,
1243
- contractId: generateContractId(),
1244
- title: contract.title,
1245
- description: contract.description,
1246
- conditionType: contract.conditionType,
1247
- direction: contract.direction,
1248
- condition: contract.condition,
1249
- deadline: contract.deadline,
1250
- compositeOf: contract.compositeOf,
1251
- compositeOperator: contract.compositeOperator,
1252
- modulation: contract.modulation,
1253
- evaluationSchedule: contract.evaluationSchedule,
1254
- periodicIntervalMs: contract.periodicIntervalMs,
1255
- status: "active",
1256
- lineageSource: "inherited",
1257
- inheritedFromContractId: contract.contractId,
1258
- inheritedFromBeliefNodeId: contract.beliefNodeId,
1259
- inheritedAt: args.now,
1260
- topicId: args.topicId,
1261
- createdAt: args.now,
1262
- createdBy: args.createdBy,
1263
- updatedAt: args.now
1264
- };
1265
- }
1266
- function normalizeEvidentialAction(value) {
1267
- return value === "append_sl_scoring" || value === "flag_review" || value === "archive" ? value : void 0;
1500
+ };
1501
+ var PROPAGATION_TRAVERSAL_SPECS = Object.entries(EDGE_PROPAGATION_RULES).map(([edgeType, rule]) => ({
1502
+ edgeType,
1503
+ direction: rule.direction
1504
+ }));
1505
+ function isPropagationEdgeType(edgeType) {
1506
+ return edgeType in EDGE_PROPAGATION_RULES;
1268
1507
  }
1269
- function parseComparisonOperator(value, evaluatorName) {
1270
- if (value === "gte" || value === "lte" || value === "eq" || value === "gt" || value === "lt") {
1271
- return value;
1272
- }
1273
- throw new Error(
1274
- `${evaluatorName} requires operator to be one of gte, lte, eq, gt, or lt.`
1275
- );
1508
+ function getPropagationTraversalSpecs() {
1509
+ return PROPAGATION_TRAVERSAL_SPECS;
1276
1510
  }
1277
- function parseNumericThreshold(value, evaluatorName) {
1278
- if (typeof value === "number" && Number.isFinite(value)) {
1279
- return value;
1511
+ function propagateThroughEdge(sourceOpinion, targetOpinion, edgeType, weight = 1, metadata = {}) {
1512
+ const handler = isPropagationEdgeType(edgeType) ? EDGE_PROPAGATION_RULES[edgeType].handler : void 0;
1513
+ if (!handler) {
1514
+ return {
1515
+ opinion: targetOpinion,
1516
+ operator: "no_op",
1517
+ rationale: `Unknown edge type: ${edgeType} \u2014 no propagation`
1518
+ };
1280
1519
  }
1281
- throw new Error(`${evaluatorName} requires a finite numeric threshold.`);
1520
+ return handler(sourceOpinion, targetOpinion, weight, metadata);
1282
1521
  }
1283
- function pickFiniteNumber(config, keys) {
1284
- for (const key of keys) {
1285
- const value = config[key];
1286
- if (typeof value === "number" && Number.isFinite(value)) {
1287
- return value;
1522
+ function propagateAllEdges(currentOpinion, incomingEdges) {
1523
+ let result = currentOpinion;
1524
+ const rationales = [];
1525
+ for (const edgeType of ["depends_on", "informs", "supports"]) {
1526
+ for (const incoming of incomingEdges.filter(
1527
+ (edge) => edge.edgeType === edgeType
1528
+ )) {
1529
+ const propagated = propagateThroughEdge(
1530
+ incoming.sourceOpinion,
1531
+ result,
1532
+ incoming.edgeType,
1533
+ incoming.weight,
1534
+ incoming.metadata
1535
+ );
1536
+ result = propagated.opinion;
1537
+ rationales.push(propagated.rationale);
1288
1538
  }
1289
1539
  }
1290
- return void 0;
1291
- }
1292
- function getEvaluatorInputRecord(inputData, nestedKey) {
1293
- if (!isRecord(inputData)) {
1294
- return {};
1295
- }
1296
- const nested = inputData[nestedKey];
1297
- if (isRecord(nested)) {
1298
- return nested;
1299
- }
1300
- return inputData;
1301
- }
1302
- function parseEvidentialEvaluatorConfig(value) {
1303
- if (!isRecord(value)) {
1304
- throw new Error(
1305
- "Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
1306
- );
1307
- }
1308
- const config = value;
1309
- const metric = config.metric;
1310
- const operator = config.operator;
1311
- const threshold = config.threshold;
1312
- if (metric !== "evidence_count" && metric !== "contradiction_status" && metric !== "edge_freshness" && metric !== "dependent_count") {
1313
- throw new Error(`Unsupported evidential metric: ${String(metric)}`);
1314
- }
1315
- if (operator !== "gte" && operator !== "lte" && operator !== "eq" && operator !== "gt" && operator !== "lt") {
1316
- throw new Error(`Unsupported evidential operator: ${String(operator)}`);
1317
- }
1318
- if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
1319
- throw new Error("Evidential contracts require a numeric threshold.");
1320
- }
1321
- const actionParams = isRecord(config.actionParams) ? config.actionParams : void 0;
1322
1540
  return {
1323
- metric,
1324
- operator,
1325
- threshold,
1326
- action: normalizeEvidentialAction(config.action),
1327
- actionParams: actionParams && (typeof actionParams.targetConfidence === "number" || typeof actionParams.rationale === "string") ? {
1328
- targetConfidence: typeof actionParams.targetConfidence === "number" ? actionParams.targetConfidence : void 0,
1329
- rationale: typeof actionParams.rationale === "string" ? actionParams.rationale : void 0
1330
- } : void 0
1541
+ opinion: result,
1542
+ operator: "cumulative_fusion",
1543
+ rationale: rationales.join("; ")
1331
1544
  };
1332
1545
  }
1333
- function compareMetricValue(operator, left, right) {
1334
- switch (operator) {
1335
- case "gte":
1336
- return left >= right;
1337
- case "lte":
1338
- return left <= right;
1339
- case "eq":
1340
- return left === right;
1341
- case "gt":
1342
- return left > right;
1343
- case "lt":
1344
- return left < right;
1345
- default:
1346
- return false;
1347
- }
1348
- }
1349
- function resolveComparisonResult(direction, comparisonSatisfied) {
1350
- return direction === "falsifies" ? comparisonSatisfied ? "disconfirmed" : "confirmed" : comparisonSatisfied ? "confirmed" : "disconfirmed";
1351
- }
1352
- function buildComparisonRationale(args) {
1353
- const renderedObserved = args.observedValue === null ? "no data" : `${args.observedValue}${args.unit ? ` ${args.unit}` : ""}`;
1354
- const renderedThreshold = `${args.threshold}${args.unit ? ` ${args.unit}` : ""}`;
1355
- const clause = `${args.label} observed ${renderedObserved} against ${args.operator} ${renderedThreshold}`;
1356
- if (args.observedValue === null) {
1357
- return `${clause}; evaluator returned ${args.result} because no current data was available.`;
1358
- }
1359
- return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
1360
- }
1361
- function buildEvidentialRationale(args) {
1362
- const observed = args.snapshot.value === null ? "no data" : String(args.snapshot.value);
1363
- const clause = `${args.snapshot.metric} observed ${observed} against ${args.config.operator} ${args.config.threshold}`;
1364
- if (args.snapshot.value === null) {
1365
- return `${clause}; evidential evaluator treated the comparison as unmet, resulting in ${args.result}.`;
1366
- }
1367
- return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
1546
+
1547
+ // src/v1/operations/dynamics/revision.ts
1548
+ function clamp013(value) {
1549
+ return Math.max(0, Math.min(1, value));
1368
1550
  }
1369
- function parseMetricCheckerConfig(value) {
1370
- if (!isRecord(value)) {
1371
- throw new Error(
1372
- "metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
1373
- );
1374
- }
1375
- const config = value;
1551
+ function toEvidence(probability, weight) {
1552
+ const safeProbability = clamp013(probability);
1553
+ const safeWeight = Number.isFinite(weight) ? Math.max(0, weight) : 0;
1376
1554
  return {
1377
- metric: typeof config.metric === "string" && config.metric.length > 0 ? config.metric : void 0,
1378
- operator: parseComparisonOperator(config.operator, BUILT_IN_METRIC_CHECKER),
1379
- threshold: parseNumericThreshold(config.threshold, BUILT_IN_METRIC_CHECKER),
1380
- observedValue: pickFiniteNumber(config, ["observedValue", "value"]),
1381
- currentValue: pickFiniteNumber(config, ["currentValue"]),
1382
- metricValue: pickFiniteNumber(config, ["metricValue"]),
1383
- unit: typeof config.unit === "string" && config.unit.length > 0 ? config.unit : void 0
1555
+ alpha: safeProbability * safeWeight,
1556
+ beta: (1 - safeProbability) * safeWeight
1384
1557
  };
1385
1558
  }
1386
- function parseReferenceCheckCounterConfig(value) {
1387
- if (!isRecord(value)) {
1388
- throw new Error(
1389
- "reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
1390
- );
1391
- }
1392
- const config = value;
1393
- if (typeof config.tag !== "string" || config.tag.trim().length === 0) {
1394
- throw new Error("reference_check_counter requires a non-empty tag.");
1395
- }
1396
- return {
1397
- tag: config.tag.trim(),
1398
- operator: parseComparisonOperator(
1399
- config.operator,
1400
- BUILT_IN_REFERENCE_CHECK_COUNTER
1401
- ),
1402
- threshold: parseNumericThreshold(
1403
- config.threshold,
1404
- BUILT_IN_REFERENCE_CHECK_COUNTER
1405
- ),
1406
- caseSensitive: config.caseSensitive === true
1407
- };
1559
+ function bayesianUpdate(priorConfidence, priorWeight, newAssessment, newWeight, options) {
1560
+ return reviseConfidence({
1561
+ priorConfidence,
1562
+ priorWeight,
1563
+ newAssessment,
1564
+ newWeight,
1565
+ baseRate: options?.baseRate,
1566
+ nonInformativeWeight: options?.nonInformativeWeight
1567
+ });
1408
1568
  }
1409
- function parseTemporalDeadlineConfig(value) {
1410
- if (!isRecord(value)) {
1411
- return {};
1412
- }
1413
- const config = value;
1414
- return {
1415
- label: typeof config.label === "string" && config.label.length > 0 ? config.label : void 0,
1416
- completed: config.completed === true,
1417
- completedAt: pickFiniteNumber(config, ["completedAt"]),
1418
- observedAt: pickFiniteNumber(config, ["observedAt"]),
1419
- satisfiedAt: pickFiniteNumber(config, ["satisfiedAt"]),
1420
- achievedAt: pickFiniteNumber(config, ["achievedAt"])
1421
- };
1569
+ function reviseConfidence(args) {
1570
+ return project(reviseConfidenceOpinion(args));
1422
1571
  }
1423
- function parseMarketIndexComparatorConfig(value) {
1424
- if (!isRecord(value)) {
1425
- throw new Error(
1426
- "market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
1427
- );
1428
- }
1429
- const config = value;
1430
- return {
1431
- subject: typeof config.subject === "string" && config.subject.length > 0 ? config.subject : void 0,
1432
- subjectValue: pickFiniteNumber(config, ["subjectValue", "leftValue"]),
1433
- primaryValue: pickFiniteNumber(config, ["primaryValue"]),
1434
- benchmark: typeof config.benchmark === "string" && config.benchmark.length > 0 ? config.benchmark : void 0,
1435
- benchmarkValue: pickFiniteNumber(config, ["benchmarkValue", "rightValue"]),
1436
- comparisonValue: pickFiniteNumber(config, ["comparisonValue"]),
1437
- operator: parseComparisonOperator(
1438
- config.operator,
1439
- BUILT_IN_MARKET_INDEX_COMPARATOR
1440
- ),
1441
- threshold: parseNumericThreshold(
1442
- config.threshold,
1443
- BUILT_IN_MARKET_INDEX_COMPARATOR
1444
- )
1445
- };
1572
+ function reviseConfidenceOpinion(args) {
1573
+ const priorEvidence = toEvidence(args.priorConfidence, args.priorWeight);
1574
+ const newEvidence = toEvidence(args.newAssessment, args.newWeight ?? 1);
1575
+ return opinionFromBeta(
1576
+ priorEvidence.alpha + newEvidence.alpha,
1577
+ priorEvidence.beta + newEvidence.beta,
1578
+ args.nonInformativeWeight ?? DEFAULT_NON_INFORMATIVE_WEIGHT,
1579
+ args.baseRate
1580
+ );
1446
1581
  }
1447
1582
 
1448
1583
  // src/v1/operations/approximation.ts