@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
package/README.md CHANGED
@@ -13,12 +13,16 @@ This module contains the pure logic for confidence updates. Convex-facing adapte
13
13
  Constraints:
14
14
  - `modulateConfidence` remains append-only at the mutation boundary
15
15
  - Confidence history continues to be written through the existing belief-confidence ledger
16
- - Public mutation signatures do not change; only the pure scoring and evaluation math moves here
16
+ - Belief creation starts from the canonical vacuous prior `(b=0, d=0, u=1, a=0.5)` unless the caller supplies an explicit prior
17
+ - Belief/disbelief mass only moves when a confidence modulation cites a truth-bearing artifact: evidence, an answered question or answer node, a contradiction, or a worktree outcome
18
+ - Public mutation callers must provide opinion-space tuple fields; scalar confidence is a derived projection, not a write contract
17
19
 
18
20
  ## SL rigor
19
21
 
20
22
  - The canonical confidence shape is the 4-tuple `(b, d, u, a)`.
21
23
  - `b + d + u = 1`, and the projected scalar remains `P = b + a*u`.
24
+ - A newly created belief is vacuous by default: `b=0`, `d=0`, `u=1`, `a=0.5`.
25
+ - `modulateConfidence` is provenance-bound. `manual` and `decay` are not confidence triggers; direct human or agent assessments must still cite evidence, an answered question/answer, a contradiction, or a worktree outcome.
22
26
  - Use `opinionFromScalar(value, mode, options?)` for scalar conversion.
23
27
  - Supported modes are `base_rate`, `dogmatic`, and `projected_with_u`.
24
28
  - `toDogmaticOpinion()` remains as a deprecated shim to the explicit dogmatic mode.
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- export { BeliefLifecycleBucket, ConfidencePolicyConfig, ConfidenceScoringMode, ContractConfirmedRule, ContractDisconfirmedRule, ContractExpiredRule, ContractModulationPlan, ContractPartialRule, DeadlineUrgency, DeadlineUrgencyLabel, DeadlineUrgencyTier, DecayTier, DecayTierLabel, DirichletOpinion, EdgeConstraint, EdgeMetadata, EdgeNormalization, EffectiveDecay, EpistemicContractCompositeOperator, EpistemicContractCondition, EpistemicContractConditionType, EpistemicContractDirection, EpistemicContractEvaluationResult, EpistemicContractLineageSource, EpistemicContractModulation, EpistemicContractRecord, EpistemicContractSchedule, EpistemicContractStatus, EvidentialAction, EvidentialEvaluatorConfig, EvidentialMetric, EvidentialMetricSnapshot, EvidentialOperator, MarketIndexComparatorConfig, MetricCheckerEvaluatorConfig, Opinion, PropagationMode, PropagationResult, ReferenceCheckCounterConfig, RescoringSchedule, SLOperator, StoredOpinionFields, TemporalDeadlineEvaluatorConfig, TupleContradictionPolicy, TupleContradictionTransition, VerificationConfidenceTrigger } from './v1/types.js';
1
+ export { BeliefLifecycleBucket, ConfidencePolicyConfig, ConfidenceScoringMode, ContractConfirmedRule, ContractDisconfirmedRule, ContractExpiredRule, ContractModulationPlan, ContractPartialRule, DeadlineUrgency, DeadlineUrgencyLabel, DeadlineUrgencyTier, DecayTier, DecayTierLabel, DirichletOpinion, EdgeConstraint, EdgeMetadata, EdgeNormalization, EffectiveDecay, EpistemicContractCompositeOperator, EpistemicContractCondition, EpistemicContractConditionType, EpistemicContractDirection, EpistemicContractEvaluationResult, EpistemicContractLineageSource, EpistemicContractModulation, EpistemicContractRecord, EpistemicContractSchedule, EpistemicContractStatus, EvidentialAction, EvidentialEvaluatorConfig, EvidentialMetric, EvidentialMetricSnapshot, EvidentialOperator, MarketIndexComparatorConfig, MetricCheckerEvaluatorConfig, Opinion, PropagationMode, PropagationResult, ReferenceCheckCounterConfig, RescoringSchedule, SLOperator, SLOpinion, StoredOpinionFields, TemporalDeadlineEvaluatorConfig, TupleContradictionPolicy, TupleContradictionTransition, VerificationConfidenceTrigger } from './v1/types.js';
2
+ export { FromStorageResult, SLOpinionRefinement, fromStorage, toStorage } from './v1/codec.js';
2
3
  export { ConfidenceEngine, ContractEvaluatorPort, SubjectiveLogicOperatorPort } from './v1/interfaces.js';
3
4
  export { DEFAULT_TEMPORAL_DECAY_HALF_LIFE_MS, TemporalDecayParams, temporalDecay } from './v1/operations/temporalDecay.js';
4
5
  export { DEFAULT_NON_INFORMATIVE_WEIGHT, betaFromOpinion, opinionFromBeta, opinionFromDirichlet, projectDirichletOpinion } from './v1/operations/bridge/index.js';
5
- export { OpinionFromScalarMode, clamp01, confidenceFromOpinion, confidenceFromSL, hasProjectedOpinionChanged, opinionFromBaseRate, opinionFromDogmatic, opinionFromProjected, opinionFromScalar, readOpinionFromRecord, toDogmaticOpinion, toStoredOpinionFields } from './v1/operations/scoring.js';
6
+ export { OpinionFromScalarMode, OpinionFromScalarOptions, clamp01, confidenceFromOpinion, confidenceFromSL, hasProjectedOpinionChanged, opinionFromBaseRate, opinionFromDogmatic, opinionFromProjected, opinionFromScalar, readOpinionFromRecord, toDogmaticOpinion, toStoredOpinionFields } from './v1/operations/scoring.js';
6
7
  export { DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD, detectTupleContradiction, evaluateTupleContradictionTransition, normalizeTupleContradictionPolicy } from './v1/operations/contradiction/detectTupleContradiction.js';
7
- export { areTensioned, averagingFusion, conditionalAbduction, conditionalDeduction, confidenceLevel, constraintFusion, cumulativeFusion, dogmatic, evidenceBalance, informationGain, negate, opinion, project, trustDiscount, vacuous } from './v1/operations/subjectiveLogic/index.js';
8
+ export { areTensioned, averagingFusion, conditionalAbduction, conditionalDeduction, confidenceLevel, constraintFusion, cumulativeFusion, dogmatic, evidenceBalance, informationGain, mkOpinion, negate, opinion, project, trustDiscount, vacuous } from './v1/operations/subjectiveLogic/index.js';
8
9
  export { PROPAGATION_TRAVERSAL_SPECS, PropagationEdgeType, PropagationTraversalDirection, PropagationTraversalSpec, getPropagationTraversalSpecs, isPropagationEdgeType, propagateAllEdges, propagateThroughEdge } from './v1/operations/dynamics/propagation.js';
9
10
  export { bayesianUpdate, reviseConfidence, reviseConfidenceOpinion } from './v1/operations/dynamics/revision.js';
10
11
  export { DEADLINE_URGENCY, DECAY_TIERS, computeBaseDecay, computeDeadlineUrgency, computeEffectiveDecay, decay, getRescoringSchedule } from './v1/operations/dynamics/decay.js';
@@ -12,6 +13,7 @@ export { applyNegativeEvidence, applyNegativeSupport } from './v1/operations/dyn
12
13
  export { dampedDependencyCascade, dampedDependencyOpinion } from './v1/operations/dynamics/cascade.js';
13
14
  export { BUILT_IN_EVIDENTIAL_ALIASES, BUILT_IN_EVIDENTIAL_EVALUATOR, BUILT_IN_MARKET_INDEX_COMPARATOR, BUILT_IN_METRIC_CHECKER, BUILT_IN_REFERENCE_CHECK_COUNTER, BUILT_IN_TEMPORAL_DEADLINE, buildComparisonRationale, buildEvidentialRationale, compareMetricValue, createInheritedContractRecord, deriveContractModulationPlan, deriveContractStatus, deriveVerificationTrigger, getEvaluatorInputRecord, normalizeEvidentialAction, parseComparisonOperator, parseEvidentialEvaluatorConfig, parseMarketIndexComparatorConfig, parseMetricCheckerConfig, parseNumericThreshold, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, pickFiniteNumber, resolveComparisonResult } from './v1/operations/contracts/epistemicContract.js';
14
15
  export { ConfidenceOperatorName, OPERATOR_TAXONOMY, OPERATOR_TAXONOMY_BY_TAG, OPERATOR_TAXONOMY_ENTRIES, OPERATOR_TAXONOMY_TAGS, OperatorTaxonomyEntry, OperatorTaxonomyTag, PUBLIC_OPERATOR_EXPORT_NAMES } from './v1/operations/operatorTaxonomy.js';
16
+ import 'zod';
15
17
  import './v1/operations/approximation.js';
16
18
  import './v1/operations/canonical.js';
17
19
  import './v1/operations/lucern.js';
package/dist/index.js CHANGED
@@ -1,8 +1,12 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/v1/codec.ts
4
+
1
5
  // 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));
6
+ function mkOpinion(belief, disbelief, uncertainty, baseRate) {
7
+ const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;
8
+ const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;
9
+ const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;
6
10
  const a = Math.max(0, Math.min(1, baseRate));
7
11
  const sum = b + d + u;
8
12
  if (sum === 0) {
@@ -15,12 +19,13 @@ function opinion(belief, disbelief, uncertainty, baseRate = 0.5) {
15
19
  a
16
20
  };
17
21
  }
18
- function vacuous(baseRate = 0.5) {
19
- return { b: 0, d: 0, u: 1, a: baseRate };
22
+ var opinion = mkOpinion;
23
+ function vacuous(baseRate) {
24
+ return mkOpinion(0, 0, 1, baseRate);
20
25
  }
21
- function dogmatic(probability, baseRate = 0.5) {
26
+ function dogmatic(probability, baseRate) {
22
27
  const p = Math.max(0, Math.min(1, probability));
23
- return { b: p, d: 1 - p, u: 0, a: baseRate };
28
+ return mkOpinion(p, 1 - p, 0, baseRate);
24
29
  }
25
30
  function project(o) {
26
31
  return o.b + o.a * o.u;
@@ -217,7 +222,7 @@ function conditionalAbduction(opinionY, ifTrue, ifFalse, baseRateX) {
217
222
  );
218
223
  }
219
224
  function negate(o) {
220
- return { b: o.d, d: o.b, u: o.u, a: 1 - o.a };
225
+ return mkOpinion(o.d, o.b, o.u, 1 - o.a);
221
226
  }
222
227
  function constraintFusion(left, right, mode = "pressure") {
223
228
  if (mode === "redistribute") {
@@ -280,6 +285,43 @@ function informationGain(o) {
280
285
  return o.u * (1 - Math.abs(o.b - o.d));
281
286
  }
282
287
 
288
+ // src/v1/codec.ts
289
+ var SL_EPSILON = 1e-9;
290
+ var SLOpinionRefinement = z.object({
291
+ b: z.number(),
292
+ d: z.number(),
293
+ u: z.number(),
294
+ a: z.number()
295
+ }).refine((o) => Math.abs(o.b + o.d + o.u - 1) < SL_EPSILON, {
296
+ message: "SL invariant b+d+u=1 violated"
297
+ });
298
+ function fromStorage(fields) {
299
+ const sum = fields.belief + fields.disbelief + fields.uncertainty;
300
+ const opinion2 = mkOpinion(
301
+ fields.belief,
302
+ fields.disbelief,
303
+ fields.uncertainty,
304
+ fields.baseRate
305
+ );
306
+ if (Math.abs(sum - 1) < SL_EPSILON) {
307
+ return { ok: true, opinion: opinion2 };
308
+ }
309
+ return {
310
+ ok: false,
311
+ opinion: opinion2,
312
+ repairNeeded: true,
313
+ reason: `Stored fields sum to ${sum.toFixed(6)}, not 1; normalized on read`
314
+ };
315
+ }
316
+ function toStorage(opinion2) {
317
+ return {
318
+ belief: opinion2.b,
319
+ disbelief: opinion2.d,
320
+ uncertainty: opinion2.u,
321
+ baseRate: opinion2.a
322
+ };
323
+ }
324
+
283
325
  // src/v1/operations/temporalDecay.ts
284
326
  var DEFAULT_TEMPORAL_DECAY_HALF_LIFE_MS = 90 * 24 * 60 * 60 * 1e3;
285
327
  function toEpochMs(value) {
@@ -313,7 +355,10 @@ function temporalDecay(sourceOpinion, now, decayParams) {
313
355
  return { ...sourceOpinion };
314
356
  }
315
357
  const retainedEvidenceWeight = Math.pow(0.5, ageMs / halfLifeMs);
316
- return trustDiscount(sourceOpinion, retainedEvidenceWeight);
358
+ return trustDiscount(
359
+ mkOpinion(sourceOpinion.b, sourceOpinion.d, sourceOpinion.u, sourceOpinion.a),
360
+ retainedEvidenceWeight
361
+ );
317
362
  }
318
363
 
319
364
  // src/v1/operations/bridge/index.ts
@@ -334,10 +379,6 @@ function normalizeBaseRateVector(baseRate, size) {
334
379
  if (size === 0) {
335
380
  return [];
336
381
  }
337
- const fallback = Array.from({ length: size }, () => 1 / size);
338
- if (!baseRate) {
339
- return fallback;
340
- }
341
382
  if (baseRate.length !== size) {
342
383
  throw new Error(
343
384
  `Base-rate vector length ${baseRate.length} must match evidence vector length ${size}.`
@@ -346,11 +387,11 @@ function normalizeBaseRateVector(baseRate, size) {
346
387
  const normalized = baseRate.map((value) => clampNonNegative(value));
347
388
  const total = normalized.reduce((sum, value) => sum + value, 0);
348
389
  if (total === 0) {
349
- return fallback;
390
+ throw new Error("Base-rate vector must contain at least one positive value.");
350
391
  }
351
392
  return normalized.map((value) => value / total);
352
393
  }
353
- function opinionFromDirichlet(alpha, nonInformativeWeight = DEFAULT_NON_INFORMATIVE_WEIGHT, baseRate) {
394
+ function opinionFromDirichlet(alpha, nonInformativeWeight, baseRate) {
354
395
  const evidence = alpha.map((value) => clampNonNegative(value));
355
396
  const safeWeight = normalizeNonInformativeWeight(nonInformativeWeight);
356
397
  const normalizedBaseRate = normalizeBaseRateVector(baseRate, evidence.length);
@@ -374,18 +415,18 @@ function projectDirichletOpinion(opinion2) {
374
415
  (belief, index) => belief + (opinion2.a[index] ?? 0) * opinion2.u
375
416
  );
376
417
  }
377
- function opinionFromBeta(alpha, beta, nonInformativeWeight = DEFAULT_NON_INFORMATIVE_WEIGHT, baseRate = 0.5) {
418
+ function opinionFromBeta(alpha, beta, nonInformativeWeight, baseRate) {
378
419
  const dirichlet = opinionFromDirichlet(
379
420
  [alpha, beta],
380
421
  nonInformativeWeight,
381
422
  [clamp01(baseRate), 1 - clamp01(baseRate)]
382
423
  );
383
- return {
384
- b: dirichlet.b[0] ?? 0,
385
- d: dirichlet.b[1] ?? 0,
386
- u: dirichlet.u,
387
- a: dirichlet.a[0] ?? clamp01(baseRate)
388
- };
424
+ return mkOpinion(
425
+ dirichlet.b[0] ?? 0,
426
+ dirichlet.b[1] ?? 0,
427
+ dirichlet.u,
428
+ dirichlet.a[0] ?? clamp01(baseRate)
429
+ );
389
430
  }
390
431
  function betaFromOpinion(opinion2, nonInformativeWeight = DEFAULT_NON_INFORMATIVE_WEIGHT) {
391
432
  if (opinion2.u === 0) {
@@ -406,13 +447,22 @@ function betaFromOpinion(opinion2, nonInformativeWeight = DEFAULT_NON_INFORMATIV
406
447
  function finiteNumber(value) {
407
448
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
408
449
  }
450
+ function requiredOpinionNumber(label, ...values) {
451
+ for (const value of values) {
452
+ const numberValue = finiteNumber(value);
453
+ if (numberValue !== void 0) {
454
+ return numberValue;
455
+ }
456
+ }
457
+ throw new Error(`Opinion record is missing required ${label}.`);
458
+ }
409
459
  function clamp012(value) {
410
460
  return Math.max(0, Math.min(1, value));
411
461
  }
412
462
  function confidenceFromOpinion(opinion2) {
413
463
  return clamp012(opinion2.b + opinion2.a * opinion2.u);
414
464
  }
415
- function confidenceFromSL(belief, _disbelief, uncertainty, baseRate = 0.5) {
465
+ function confidenceFromSL(belief, _disbelief, uncertainty, baseRate) {
416
466
  return confidenceFromOpinion({
417
467
  b: belief,
418
468
  u: uncertainty,
@@ -427,34 +477,56 @@ function toStoredOpinionFields(opinion2) {
427
477
  baseRate: opinion2.a
428
478
  };
429
479
  }
430
- function readOpinionFromRecord(source, fallback = {}) {
480
+ function readOpinionFromRecord(source) {
431
481
  const record = source && typeof source === "object" ? source : {};
432
- return {
433
- b: finiteNumber(record.b) ?? finiteNumber(record.belief) ?? finiteNumber(record.slBelief) ?? finiteNumber(record.opinion_b) ?? fallback.b ?? 0,
434
- d: finiteNumber(record.d) ?? finiteNumber(record.disbelief) ?? finiteNumber(record.slDisbelief) ?? finiteNumber(record.opinion_d) ?? fallback.d ?? 0,
435
- u: finiteNumber(record.u) ?? finiteNumber(record.uncertainty) ?? finiteNumber(record.slUncertainty) ?? finiteNumber(record.opinion_u) ?? fallback.u ?? 1,
436
- a: finiteNumber(record.a) ?? finiteNumber(record.baseRate) ?? finiteNumber(record.slBaseRate) ?? finiteNumber(record.opinion_a) ?? fallback.a ?? 0.5
437
- };
482
+ return mkOpinion(
483
+ requiredOpinionNumber(
484
+ "belief",
485
+ record.b,
486
+ record.belief,
487
+ record.slBelief,
488
+ record.opinion_b
489
+ ),
490
+ requiredOpinionNumber(
491
+ "disbelief",
492
+ record.d,
493
+ record.disbelief,
494
+ record.slDisbelief,
495
+ record.opinion_d
496
+ ),
497
+ requiredOpinionNumber(
498
+ "uncertainty",
499
+ record.u,
500
+ record.uncertainty,
501
+ record.slUncertainty,
502
+ record.opinion_u
503
+ ),
504
+ requiredOpinionNumber(
505
+ "baseRate",
506
+ record.a,
507
+ record.baseRate,
508
+ record.slBaseRate,
509
+ record.opinion_a
510
+ )
511
+ );
438
512
  }
439
513
  function opinionFromScalar(value, mode, options) {
440
514
  const clampedValue = clamp012(value);
441
- const baseRate = clamp012(options?.baseRate ?? 0.5);
515
+ const baseRate = options?.baseRate === void 0 ? void 0 : clamp012(options.baseRate);
442
516
  switch (mode) {
443
517
  case "base_rate":
444
- return {
445
- b: 0,
446
- d: 0,
447
- u: 1,
448
- a: clampedValue
449
- };
518
+ return mkOpinion(0, 0, 1, clampedValue);
450
519
  case "dogmatic":
451
- return {
452
- b: clampedValue,
453
- d: 1 - clampedValue,
454
- u: 0,
455
- a: baseRate
456
- };
520
+ if (baseRate === void 0) {
521
+ throw new Error('opinionFromScalar(value, "dogmatic") requires options.baseRate.');
522
+ }
523
+ return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);
457
524
  case "projected_with_u": {
525
+ if (baseRate === void 0) {
526
+ throw new Error(
527
+ 'opinionFromScalar(value, "projected_with_u") requires options.baseRate.'
528
+ );
529
+ }
458
530
  const uncertainty = options?.uncertainty;
459
531
  if (uncertainty === void 0) {
460
532
  throw new Error(
@@ -463,35 +535,30 @@ function opinionFromScalar(value, mode, options) {
463
535
  }
464
536
  const clampedUncertainty = clamp012(uncertainty);
465
537
  const evidenceWeight = 1 - clampedUncertainty;
466
- return {
467
- b: clampedValue * evidenceWeight,
468
- d: (1 - clampedValue) * evidenceWeight,
469
- u: clampedUncertainty,
470
- a: baseRate
471
- };
538
+ return mkOpinion(
539
+ clampedValue * evidenceWeight,
540
+ (1 - clampedValue) * evidenceWeight,
541
+ clampedUncertainty,
542
+ baseRate
543
+ );
472
544
  }
473
545
  }
474
546
  throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);
475
547
  }
476
- function toDogmaticOpinion(confidence, baseRate = 0.5) {
548
+ function toDogmaticOpinion(confidence, baseRate) {
477
549
  return opinionFromScalar(confidence, "dogmatic", { baseRate });
478
550
  }
479
551
  function opinionFromBaseRate(probability) {
480
552
  return vacuous(clamp012(probability));
481
553
  }
482
- function opinionFromDogmatic(probability, baseRate = 0.5) {
554
+ function opinionFromDogmatic(probability, baseRate) {
483
555
  return dogmatic(clamp012(probability), clamp012(baseRate));
484
556
  }
485
- function opinionFromProjected(probability, uncertainty, baseRate = 0.5) {
557
+ function opinionFromProjected(probability, uncertainty, baseRate) {
486
558
  const p = clamp012(probability);
487
559
  const u = clamp012(uncertainty);
488
560
  const remainingMass = 1 - u;
489
- return {
490
- b: p * remainingMass,
491
- d: (1 - p) * remainingMass,
492
- u,
493
- a: clamp012(baseRate)
494
- };
561
+ return mkOpinion(p * remainingMass, (1 - p) * remainingMass, u, clamp012(baseRate));
495
562
  }
496
563
  function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
497
564
  return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
@@ -531,7 +598,14 @@ function evaluateTupleContradictionTransition(args) {
531
598
 
532
599
  // src/v1/operations/dynamics/cascade.ts
533
600
  function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
534
- const dependencyProjection = project(dependencyOpinion);
601
+ const dependencyProjection = project(
602
+ mkOpinion(
603
+ dependencyOpinion.b,
604
+ dependencyOpinion.d,
605
+ dependencyOpinion.u,
606
+ dependencyOpinion.a
607
+ )
608
+ );
535
609
  if (mode === "threshold") {
536
610
  if (dependencyProjection < threshold) {
537
611
  return opinion(
@@ -556,40 +630,49 @@ function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "conti
556
630
  opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
557
631
  operator: "dependency_cascade",
558
632
  rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
559
- dependencyOpinion
633
+ mkOpinion(
634
+ dependencyOpinion.b,
635
+ dependencyOpinion.d,
636
+ dependencyOpinion.u,
637
+ dependencyOpinion.a
638
+ )
560
639
  ).toFixed(2)}`
561
640
  };
562
641
  }
563
642
 
564
643
  // src/v1/operations/dynamics/defeat.ts
565
644
  function applyNegativeSupport(source, target, weight, metadata = {}) {
645
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
646
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
566
647
  if (metadata.constraint === "xor") {
567
648
  const result = constraintFusion(
568
- source,
569
- target,
649
+ sourceOpinion,
650
+ targetOpinion,
570
651
  metadata.normalization ?? "pressure"
571
652
  );
572
653
  return {
573
654
  opinion: result.o2,
574
655
  operator: "constraint_fusion",
575
- rationale: `XOR constraint: source belief at ${project(source).toFixed(
576
- 2
577
- )} pressures target`
656
+ rationale: `XOR constraint: source belief at ${project(
657
+ sourceOpinion
658
+ ).toFixed(2)} pressures target`
578
659
  };
579
660
  }
580
- const discounted = trustDiscount(negate(source), Math.abs(weight));
661
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
581
662
  return {
582
- opinion: cumulativeFusion(target, discounted),
663
+ opinion: cumulativeFusion(targetOpinion, discounted),
583
664
  operator: "cumulative_fusion",
584
665
  rationale: `Contradicting evidence (weight=${weight.toFixed(
585
666
  2
586
- )}) from source at ${project(source).toFixed(2)}`
667
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
587
668
  };
588
669
  }
589
670
  function applyNegativeEvidence(source, target, weight) {
590
- const discounted = trustDiscount(negate(source), Math.abs(weight));
671
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
672
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
673
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
591
674
  return {
592
- opinion: cumulativeFusion(target, discounted),
675
+ opinion: cumulativeFusion(targetOpinion, discounted),
593
676
  operator: "cumulative_fusion",
594
677
  rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
595
678
  };
@@ -600,28 +683,32 @@ var EDGE_PROPAGATION_RULES = {
600
683
  supports: {
601
684
  direction: "outgoing",
602
685
  handler: (source, target, weight, metadata) => {
686
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
687
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
603
688
  if (weight < 0) {
604
- return applyNegativeSupport(source, target, weight, metadata);
689
+ return applyNegativeSupport(sourceOpinion, targetOpinion, weight, metadata);
605
690
  }
606
- const discounted = trustDiscount(source, weight);
691
+ const discounted = trustDiscount(sourceOpinion, weight);
607
692
  return {
608
- opinion: cumulativeFusion(target, discounted),
693
+ opinion: cumulativeFusion(targetOpinion, discounted),
609
694
  operator: "cumulative_fusion",
610
695
  rationale: `Supporting evidence (weight=${weight.toFixed(
611
696
  2
612
- )}) from source at ${project(source).toFixed(2)}`
697
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
613
698
  };
614
699
  }
615
700
  },
616
701
  informs: {
617
702
  direction: "outgoing",
618
703
  handler: (source, target, weight) => {
704
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
705
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
619
706
  if (weight < 0) {
620
- return applyNegativeEvidence(source, target, weight);
707
+ return applyNegativeEvidence(sourceOpinion, targetOpinion, weight);
621
708
  }
622
- const discounted = trustDiscount(source, Math.abs(weight));
709
+ const discounted = trustDiscount(sourceOpinion, Math.abs(weight));
623
710
  return {
624
- opinion: cumulativeFusion(target, discounted),
711
+ opinion: cumulativeFusion(targetOpinion, discounted),
625
712
  operator: "cumulative_fusion",
626
713
  rationale: `Supporting evidence (weight=${weight.toFixed(2)})`
627
714
  };
@@ -630,23 +717,35 @@ var EDGE_PROPAGATION_RULES = {
630
717
  depends_on: {
631
718
  direction: "incoming",
632
719
  handler: (source, target, _weight, metadata) => {
720
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
721
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
633
722
  if (metadata.conditionalA && metadata.conditionalNotA) {
634
723
  return {
635
724
  opinion: conditionalDeduction(
636
- source,
637
- metadata.conditionalA,
638
- metadata.conditionalNotA,
639
- target.a
725
+ sourceOpinion,
726
+ mkOpinion(
727
+ metadata.conditionalA.b,
728
+ metadata.conditionalA.d,
729
+ metadata.conditionalA.u,
730
+ metadata.conditionalA.a
731
+ ),
732
+ mkOpinion(
733
+ metadata.conditionalNotA.b,
734
+ metadata.conditionalNotA.d,
735
+ metadata.conditionalNotA.u,
736
+ metadata.conditionalNotA.a
737
+ ),
738
+ targetOpinion.a
640
739
  ),
641
740
  operator: "conditional_deduction",
642
741
  rationale: `Conditional deduction: prerequisite at ${project(
643
- source
742
+ sourceOpinion
644
743
  ).toFixed(2)}`
645
744
  };
646
745
  }
647
746
  return dampedDependencyCascade(
648
- source,
649
- target,
747
+ sourceOpinion,
748
+ targetOpinion,
650
749
  metadata.propagation ?? "continuous"
651
750
  );
652
751
  }
@@ -752,7 +851,7 @@ function reviseConfidenceOpinion(args) {
752
851
  priorEvidence.alpha + newEvidence.alpha,
753
852
  priorEvidence.beta + newEvidence.beta,
754
853
  args.nonInformativeWeight ?? DEFAULT_NON_INFORMATIVE_WEIGHT,
755
- args.baseRate ?? 0.5
854
+ args.baseRate
756
855
  );
757
856
  }
758
857
 
@@ -1026,6 +1125,9 @@ function generateContractId() {
1026
1125
  }
1027
1126
  return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
1028
1127
  }
1128
+ function isRecord(value) {
1129
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1130
+ }
1029
1131
  function deriveContractStatus(result, currentStatus) {
1030
1132
  if (currentStatus === "archived") {
1031
1133
  return currentStatus;
@@ -1167,18 +1269,17 @@ function pickFiniteNumber(config, keys) {
1167
1269
  return void 0;
1168
1270
  }
1169
1271
  function getEvaluatorInputRecord(inputData, nestedKey) {
1170
- if (!inputData || typeof inputData !== "object") {
1272
+ if (!isRecord(inputData)) {
1171
1273
  return {};
1172
1274
  }
1173
- const root = inputData;
1174
- const nested = root[nestedKey];
1175
- if (nested && typeof nested === "object") {
1275
+ const nested = inputData[nestedKey];
1276
+ if (isRecord(nested)) {
1176
1277
  return nested;
1177
1278
  }
1178
- return root;
1279
+ return inputData;
1179
1280
  }
1180
1281
  function parseEvidentialEvaluatorConfig(value) {
1181
- if (!value || typeof value !== "object") {
1282
+ if (!isRecord(value)) {
1182
1283
  throw new Error(
1183
1284
  "Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
1184
1285
  );
@@ -1196,7 +1297,7 @@ function parseEvidentialEvaluatorConfig(value) {
1196
1297
  if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
1197
1298
  throw new Error("Evidential contracts require a numeric threshold.");
1198
1299
  }
1199
- const actionParams = config.actionParams && typeof config.actionParams === "object" && config.actionParams !== null ? config.actionParams : void 0;
1300
+ const actionParams = isRecord(config.actionParams) ? config.actionParams : void 0;
1200
1301
  return {
1201
1302
  metric,
1202
1303
  operator,
@@ -1245,7 +1346,7 @@ function buildEvidentialRationale(args) {
1245
1346
  return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
1246
1347
  }
1247
1348
  function parseMetricCheckerConfig(value) {
1248
- if (!value || typeof value !== "object") {
1349
+ if (!isRecord(value)) {
1249
1350
  throw new Error(
1250
1351
  "metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
1251
1352
  );
@@ -1262,7 +1363,7 @@ function parseMetricCheckerConfig(value) {
1262
1363
  };
1263
1364
  }
1264
1365
  function parseReferenceCheckCounterConfig(value) {
1265
- if (!value || typeof value !== "object") {
1366
+ if (!isRecord(value)) {
1266
1367
  throw new Error(
1267
1368
  "reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
1268
1369
  );
@@ -1285,7 +1386,7 @@ function parseReferenceCheckCounterConfig(value) {
1285
1386
  };
1286
1387
  }
1287
1388
  function parseTemporalDeadlineConfig(value) {
1288
- if (!value || typeof value !== "object") {
1389
+ if (!isRecord(value)) {
1289
1390
  return {};
1290
1391
  }
1291
1392
  const config = value;
@@ -1299,7 +1400,7 @@ function parseTemporalDeadlineConfig(value) {
1299
1400
  };
1300
1401
  }
1301
1402
  function parseMarketIndexComparatorConfig(value) {
1302
- if (!value || typeof value !== "object") {
1403
+ if (!isRecord(value)) {
1303
1404
  throw new Error(
1304
1405
  "market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
1305
1406
  );
@@ -1338,6 +1439,7 @@ var SL_APPROXIMATION_OPERATOR_NAMES = [
1338
1439
 
1339
1440
  // src/v1/operations/canonical.ts
1340
1441
  var SL_CANONICAL_OPERATOR_NAMES = [
1442
+ "mkOpinion",
1341
1443
  "opinion",
1342
1444
  "vacuous",
1343
1445
  "dogmatic",
@@ -1355,6 +1457,8 @@ var SL_CANONICAL_OPERATOR_NAMES = [
1355
1457
  // src/v1/operations/lucern.ts
1356
1458
  var LUCERN_SPECIFIC_OPERATOR_NAMES = [
1357
1459
  "clamp01",
1460
+ "fromStorage",
1461
+ "toStorage",
1358
1462
  "toStoredOpinionFields",
1359
1463
  "readOpinionFromRecord",
1360
1464
  "opinionFromScalar",
@@ -1375,6 +1479,7 @@ var LUCERN_SPECIFIC_OPERATOR_NAMES = [
1375
1479
  "propagateAllEdges",
1376
1480
  "bayesianUpdate",
1377
1481
  "reviseConfidence",
1482
+ "reviseConfidenceOpinion",
1378
1483
  "computeBaseDecay",
1379
1484
  "computeDeadlineUrgency",
1380
1485
  "computeEffectiveDecay",
@@ -1414,6 +1519,12 @@ var PUBLIC_OPERATOR_EXPORT_NAMES = [
1414
1519
  ...LUCERN_SPECIFIC_OPERATOR_NAMES
1415
1520
  ];
1416
1521
  var OPERATOR_TAXONOMY_ENTRIES = [
1522
+ {
1523
+ operator: "mkOpinion",
1524
+ tag: "SL_CANONICAL",
1525
+ sourceModule: "operations/subjectiveLogic/index.ts",
1526
+ rationale: "Constructs the canonical binomial SL opinion tuple and normalizes it into valid mass components."
1527
+ },
1417
1528
  {
1418
1529
  operator: "opinion",
1419
1530
  tag: "SL_CANONICAL",
@@ -1546,6 +1657,18 @@ var OPERATOR_TAXONOMY_ENTRIES = [
1546
1657
  sourceModule: "operations/scoring.ts",
1547
1658
  rationale: "Implementation helper for Lucern APIs; it has no direct J\xF8sang operator analogue."
1548
1659
  },
1660
+ {
1661
+ operator: "fromStorage",
1662
+ tag: "LUCERN_SPECIFIC",
1663
+ sourceModule: "codec.ts",
1664
+ rationale: "Reads Lucern storage fields into a normalized opinion and reports repair metadata; it is storage glue, not SL algebra."
1665
+ },
1666
+ {
1667
+ operator: "toStorage",
1668
+ tag: "LUCERN_SPECIFIC",
1669
+ sourceModule: "codec.ts",
1670
+ rationale: "Serializes a normalized opinion into Lucern storage fields rather than implementing an SL algebra operator."
1671
+ },
1549
1672
  {
1550
1673
  operator: "toStoredOpinionFields",
1551
1674
  tag: "LUCERN_SPECIFIC",
@@ -1666,6 +1789,12 @@ var OPERATOR_TAXONOMY_ENTRIES = [
1666
1789
  sourceModule: "operations/dynamics/revision.ts",
1667
1790
  rationale: "Lucern wrapper around the scalar Bayesian revision helper rather than a direct SL operator."
1668
1791
  },
1792
+ {
1793
+ operator: "reviseConfidenceOpinion",
1794
+ tag: "LUCERN_SPECIFIC",
1795
+ sourceModule: "operations/dynamics/revision.ts",
1796
+ rationale: "Lucern revision helper that exposes the Beta-bridge opinion behind scalar confidence revision."
1797
+ },
1669
1798
  {
1670
1799
  operator: "computeBaseDecay",
1671
1800
  tag: "LUCERN_SPECIFIC",
@@ -1828,6 +1957,6 @@ var OPERATOR_TAXONOMY_BY_TAG = Object.freeze({
1828
1957
  LUCERN_SPECIFIC: LUCERN_SPECIFIC_OPERATOR_NAMES
1829
1958
  });
1830
1959
 
1831
- export { BUILT_IN_EVIDENTIAL_ALIASES, BUILT_IN_EVIDENTIAL_EVALUATOR, BUILT_IN_MARKET_INDEX_COMPARATOR, BUILT_IN_METRIC_CHECKER, BUILT_IN_REFERENCE_CHECK_COUNTER, BUILT_IN_TEMPORAL_DEADLINE, DEADLINE_URGENCY, DECAY_TIERS, DEFAULT_NON_INFORMATIVE_WEIGHT, DEFAULT_TEMPORAL_DECAY_HALF_LIFE_MS, DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD, OPERATOR_TAXONOMY, OPERATOR_TAXONOMY_BY_TAG, OPERATOR_TAXONOMY_ENTRIES, OPERATOR_TAXONOMY_TAGS, PROPAGATION_TRAVERSAL_SPECS, PUBLIC_OPERATOR_EXPORT_NAMES, applyNegativeEvidence, applyNegativeSupport, areTensioned, averagingFusion, bayesianUpdate, betaFromOpinion, buildComparisonRationale, buildEvidentialRationale, clamp012 as clamp01, compareMetricValue, computeBaseDecay, computeDeadlineUrgency, computeEffectiveDecay, conditionalAbduction, conditionalDeduction, confidenceFromOpinion, confidenceFromSL, confidenceLevel, constraintFusion, createInheritedContractRecord, cumulativeFusion, dampedDependencyCascade, dampedDependencyOpinion, decay, deriveContractModulationPlan, deriveContractStatus, deriveVerificationTrigger, detectTupleContradiction, dogmatic, evaluateTupleContradictionTransition, evidenceBalance, getEvaluatorInputRecord, getPropagationTraversalSpecs, getRescoringSchedule, hasProjectedOpinionChanged, informationGain, isPropagationEdgeType, negate, normalizeEvidentialAction, normalizeTupleContradictionPolicy, opinion, opinionFromBaseRate, opinionFromBeta, opinionFromDirichlet, opinionFromDogmatic, opinionFromProjected, opinionFromScalar, parseComparisonOperator, parseEvidentialEvaluatorConfig, parseMarketIndexComparatorConfig, parseMetricCheckerConfig, parseNumericThreshold, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, pickFiniteNumber, project, projectDirichletOpinion, propagateAllEdges, propagateThroughEdge, readOpinionFromRecord, resolveComparisonResult, reviseConfidence, reviseConfidenceOpinion, temporalDecay, toDogmaticOpinion, toStoredOpinionFields, trustDiscount, vacuous };
1960
+ export { BUILT_IN_EVIDENTIAL_ALIASES, BUILT_IN_EVIDENTIAL_EVALUATOR, BUILT_IN_MARKET_INDEX_COMPARATOR, BUILT_IN_METRIC_CHECKER, BUILT_IN_REFERENCE_CHECK_COUNTER, BUILT_IN_TEMPORAL_DEADLINE, DEADLINE_URGENCY, DECAY_TIERS, DEFAULT_NON_INFORMATIVE_WEIGHT, DEFAULT_TEMPORAL_DECAY_HALF_LIFE_MS, DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD, OPERATOR_TAXONOMY, OPERATOR_TAXONOMY_BY_TAG, OPERATOR_TAXONOMY_ENTRIES, OPERATOR_TAXONOMY_TAGS, PROPAGATION_TRAVERSAL_SPECS, PUBLIC_OPERATOR_EXPORT_NAMES, SLOpinionRefinement, applyNegativeEvidence, applyNegativeSupport, areTensioned, averagingFusion, bayesianUpdate, betaFromOpinion, buildComparisonRationale, buildEvidentialRationale, clamp012 as clamp01, compareMetricValue, computeBaseDecay, computeDeadlineUrgency, computeEffectiveDecay, conditionalAbduction, conditionalDeduction, confidenceFromOpinion, confidenceFromSL, confidenceLevel, constraintFusion, createInheritedContractRecord, cumulativeFusion, dampedDependencyCascade, dampedDependencyOpinion, decay, deriveContractModulationPlan, deriveContractStatus, deriveVerificationTrigger, detectTupleContradiction, dogmatic, evaluateTupleContradictionTransition, evidenceBalance, fromStorage, getEvaluatorInputRecord, getPropagationTraversalSpecs, getRescoringSchedule, hasProjectedOpinionChanged, informationGain, isPropagationEdgeType, mkOpinion, negate, normalizeEvidentialAction, normalizeTupleContradictionPolicy, opinion, opinionFromBaseRate, opinionFromBeta, opinionFromDirichlet, opinionFromDogmatic, opinionFromProjected, opinionFromScalar, parseComparisonOperator, parseEvidentialEvaluatorConfig, parseMarketIndexComparatorConfig, parseMetricCheckerConfig, parseNumericThreshold, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, pickFiniteNumber, project, projectDirichletOpinion, propagateAllEdges, propagateThroughEdge, readOpinionFromRecord, resolveComparisonResult, reviseConfidence, reviseConfidenceOpinion, temporalDecay, toDogmaticOpinion, toStorage, toStoredOpinionFields, trustDiscount, vacuous };
1832
1961
  //# sourceMappingURL=index.js.map
1833
1962
  //# sourceMappingURL=index.js.map