@lucern/confidence 1.0.29 → 1.0.31

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
@@ -1,5 +1,7 @@
1
1
  import { z } from 'zod';
2
2
 
3
+ // src/v1/codec.ts
4
+
3
5
  // src/v1/operations/subjectiveLogic/index.ts
4
6
  function opinion(belief, disbelief, uncertainty, baseRate) {
5
7
  const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;
@@ -107,14 +109,91 @@ function computeConditionalDeductionBaseRate(opinionA, ifTrue, ifFalse, fallback
107
109
  }
108
110
  function safeCorrectionTerm(numerator, denominator) {
109
111
  if (Math.abs(denominator) <= EPSILON) {
110
- return void 0;
112
+ return;
111
113
  }
112
114
  const value = numerator / denominator;
113
115
  if (!Number.isFinite(value)) {
114
- return void 0;
116
+ return;
115
117
  }
116
118
  return Math.max(0, value);
117
119
  }
120
+ function correctionOrZero(numerator, denominator) {
121
+ return safeCorrectionTerm(numerator, denominator) ?? 0;
122
+ }
123
+ function hasNoConditionalDeductionCorrection(ifTrue, ifFalse) {
124
+ return ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d || ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d;
125
+ }
126
+ function usesLowerVacuousBranch(context) {
127
+ return context.projectedVacuousDeduction <= context.projectedConditionalA;
128
+ }
129
+ function usesLowerAntecedentBranch(context) {
130
+ return context.projectedAntecedent <= context.opinionA.a;
131
+ }
132
+ function computeTrueDominantDeductionCorrection(context) {
133
+ const beliefGap = context.ifTrue.b - context.ifFalse.b;
134
+ const disbeliefGap = context.ifFalse.d - context.ifTrue.d;
135
+ const lowerVacuous = usesLowerVacuousBranch(context);
136
+ const lowerAntecedent = usesLowerAntecedentBranch(context);
137
+ if (lowerVacuous && lowerAntecedent) {
138
+ return correctionOrZero(
139
+ context.opinionA.a * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b),
140
+ context.projectedAntecedent * context.childBaseRate
141
+ );
142
+ }
143
+ if (lowerVacuous) {
144
+ return correctionOrZero(
145
+ context.opinionA.a * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d) * beliefGap,
146
+ context.projectedAntecedentComplement * context.childBaseRate * disbeliefGap
147
+ );
148
+ }
149
+ if (lowerAntecedent) {
150
+ return correctionOrZero(
151
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b) * disbeliefGap,
152
+ context.projectedAntecedent * (1 - context.childBaseRate) * beliefGap
153
+ );
154
+ }
155
+ return correctionOrZero(
156
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d),
157
+ context.projectedAntecedentComplement * (1 - context.childBaseRate)
158
+ );
159
+ }
160
+ function computeFalseDominantDeductionCorrection(context) {
161
+ const beliefGap = context.ifFalse.b - context.ifTrue.b;
162
+ const disbeliefGap = context.ifTrue.d - context.ifFalse.d;
163
+ const lowerVacuous = usesLowerVacuousBranch(context);
164
+ const lowerAntecedent = usesLowerAntecedentBranch(context);
165
+ if (lowerVacuous && lowerAntecedent) {
166
+ return correctionOrZero(
167
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d) * beliefGap,
168
+ context.projectedAntecedent * context.childBaseRate * disbeliefGap
169
+ );
170
+ }
171
+ if (lowerVacuous) {
172
+ return correctionOrZero(
173
+ (1 - context.opinionA.a) * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b),
174
+ context.projectedAntecedentComplement * context.childBaseRate
175
+ );
176
+ }
177
+ if (lowerAntecedent) {
178
+ return correctionOrZero(
179
+ context.opinionA.a * context.opinionA.u * (context.intermediateDisbelief - context.ifTrue.d),
180
+ context.projectedAntecedent * (1 - context.childBaseRate)
181
+ );
182
+ }
183
+ return correctionOrZero(
184
+ context.opinionA.a * context.opinionA.u * (context.intermediateBelief - context.ifTrue.b) * disbeliefGap,
185
+ context.projectedAntecedentComplement * (1 - context.childBaseRate) * beliefGap
186
+ );
187
+ }
188
+ function computeConditionalDeductionCorrection(context) {
189
+ if (hasNoConditionalDeductionCorrection(context.ifTrue, context.ifFalse)) {
190
+ return 0;
191
+ }
192
+ if (context.ifTrue.b > context.ifFalse.b && context.ifTrue.d <= context.ifFalse.d) {
193
+ return computeTrueDominantDeductionCorrection(context);
194
+ }
195
+ return computeFalseDominantDeductionCorrection(context);
196
+ }
118
197
  function conditionalDeduction(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
119
198
  const fallbackChildBaseRate = childBaseRateFallback(
120
199
  ifTrue,
@@ -134,58 +213,18 @@ function conditionalDeduction(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
134
213
  const intermediateUncertainty = opinionA.b * ifTrue.u + opinionA.d * ifFalse.u + opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
135
214
  const projectedVacuousDeduction = ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a) + childBaseRate * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
136
215
  const projectedConditionalA = ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);
137
- let correction = 0;
138
- if (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d || ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d) {
139
- correction = 0;
140
- } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {
141
- const beliefGap = ifTrue.b - ifFalse.b;
142
- const disbeliefGap = ifFalse.d - ifTrue.d;
143
- if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
144
- correction = safeCorrectionTerm(
145
- opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),
146
- projectedAntecedent * childBaseRate
147
- ) ?? 0;
148
- } else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
149
- correction = safeCorrectionTerm(
150
- opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
151
- projectedAntecedentComplement * childBaseRate * disbeliefGap
152
- ) ?? 0;
153
- } else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
154
- correction = safeCorrectionTerm(
155
- (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
156
- projectedAntecedent * (1 - childBaseRate) * beliefGap
157
- ) ?? 0;
158
- } else {
159
- correction = safeCorrectionTerm(
160
- (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),
161
- projectedAntecedentComplement * (1 - childBaseRate)
162
- ) ?? 0;
163
- }
164
- } else {
165
- const beliefGap = ifFalse.b - ifTrue.b;
166
- const disbeliefGap = ifTrue.d - ifFalse.d;
167
- if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
168
- correction = safeCorrectionTerm(
169
- (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
170
- projectedAntecedent * childBaseRate * disbeliefGap
171
- ) ?? 0;
172
- } else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
173
- correction = safeCorrectionTerm(
174
- (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),
175
- projectedAntecedentComplement * childBaseRate
176
- ) ?? 0;
177
- } else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
178
- correction = safeCorrectionTerm(
179
- opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),
180
- projectedAntecedent * (1 - childBaseRate)
181
- ) ?? 0;
182
- } else {
183
- correction = safeCorrectionTerm(
184
- opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
185
- projectedAntecedentComplement * (1 - childBaseRate) * beliefGap
186
- ) ?? 0;
187
- }
188
- }
216
+ const correction = computeConditionalDeductionCorrection({
217
+ childBaseRate,
218
+ ifFalse,
219
+ ifTrue,
220
+ intermediateBelief,
221
+ intermediateDisbelief,
222
+ opinionA,
223
+ projectedAntecedent,
224
+ projectedAntecedentComplement,
225
+ projectedConditionalA,
226
+ projectedVacuousDeduction
227
+ });
189
228
  return opinion(
190
229
  intermediateBelief - childBaseRate * correction,
191
230
  intermediateDisbelief - (1 - childBaseRate) * correction,
@@ -257,107 +296,7 @@ function informationGain(o) {
257
296
  return o.u * (1 - Math.abs(o.b - o.d));
258
297
  }
259
298
 
260
- // src/v1/operations/scoring.ts
261
- function finiteNumber(value) {
262
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
263
- }
264
- function requiredOpinionNumber(label, ...values) {
265
- for (const value of values) {
266
- const numberValue = finiteNumber(value);
267
- if (numberValue !== void 0) {
268
- return numberValue;
269
- }
270
- }
271
- throw new Error(`Opinion record is missing required ${label}.`);
272
- }
273
- function clamp01(value) {
274
- return Math.max(0, Math.min(1, value));
275
- }
276
- function confidenceFromOpinion(opinion2) {
277
- return clamp01(opinion2.b + opinion2.a * opinion2.u);
278
- }
279
- function toStoredOpinionFields(opinion2) {
280
- return {
281
- belief: opinion2.b,
282
- disbelief: opinion2.d,
283
- uncertainty: opinion2.u,
284
- baseRate: opinion2.a
285
- };
286
- }
287
- function readOpinionFromRecord(source) {
288
- const record = source && typeof source === "object" ? source : {};
289
- return mkOpinion(
290
- requiredOpinionNumber(
291
- "belief",
292
- record.b,
293
- record.belief,
294
- record.slBelief,
295
- record.opinion_b
296
- ),
297
- requiredOpinionNumber(
298
- "disbelief",
299
- record.d,
300
- record.disbelief,
301
- record.slDisbelief,
302
- record.opinion_d
303
- ),
304
- requiredOpinionNumber(
305
- "uncertainty",
306
- record.u,
307
- record.uncertainty,
308
- record.slUncertainty,
309
- record.opinion_u
310
- ),
311
- requiredOpinionNumber(
312
- "baseRate",
313
- record.a,
314
- record.baseRate,
315
- record.slBaseRate,
316
- record.opinion_a
317
- )
318
- );
319
- }
320
- function opinionFromScalar(value, mode, options) {
321
- const clampedValue = clamp01(value);
322
- const baseRate = options?.baseRate === void 0 ? void 0 : clamp01(options.baseRate);
323
- switch (mode) {
324
- case "base_rate":
325
- return mkOpinion(0, 0, 1, clampedValue);
326
- case "dogmatic":
327
- if (baseRate === void 0) {
328
- throw new Error('opinionFromScalar(value, "dogmatic") requires options.baseRate.');
329
- }
330
- return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);
331
- case "projected_with_u": {
332
- if (baseRate === void 0) {
333
- throw new Error(
334
- 'opinionFromScalar(value, "projected_with_u") requires options.baseRate.'
335
- );
336
- }
337
- const uncertainty = options?.uncertainty;
338
- if (uncertainty === void 0) {
339
- throw new Error(
340
- 'opinionFromScalar(value, "projected_with_u") requires options.uncertainty.'
341
- );
342
- }
343
- const clampedUncertainty = clamp01(uncertainty);
344
- const evidenceWeight = 1 - clampedUncertainty;
345
- return mkOpinion(
346
- clampedValue * evidenceWeight,
347
- (1 - clampedValue) * evidenceWeight,
348
- clampedUncertainty,
349
- baseRate
350
- );
351
- }
352
- }
353
- throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);
354
- }
355
- function toDogmaticOpinion(confidence, baseRate) {
356
- return opinionFromScalar(confidence, "dogmatic", { baseRate });
357
- }
358
- function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
359
- return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
360
- }
299
+ // src/v1/codec.ts
361
300
  var SL_EPSILON = 1e-9;
362
301
  z.object({
363
302
  b: z.number(),
@@ -393,395 +332,460 @@ function toStorage(opinion2) {
393
332
  baseRate: opinion2.a
394
333
  };
395
334
  }
396
- function toEpochMs(value) {
397
- if (typeof value === "number" && Number.isFinite(value)) {
398
- return value;
335
+
336
+ // src/v1/operations/contracts/epistemicContract.ts
337
+ var BUILT_IN_METRIC_CHECKER = "metric_checker";
338
+ var BUILT_IN_REFERENCE_CHECK_COUNTER = "reference_check_counter";
339
+ var BUILT_IN_MARKET_INDEX_COMPARATOR = "market_index_comparator";
340
+ function clampConfidence(value) {
341
+ return Math.max(0, Math.min(1, value));
342
+ }
343
+ function generateContractId() {
344
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
345
+ return crypto.randomUUID();
399
346
  }
400
- if (value instanceof Date) {
401
- const epochMs = value.getTime();
402
- return Number.isFinite(epochMs) ? epochMs : void 0;
347
+ return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
348
+ }
349
+ function isRecord(value) {
350
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
351
+ }
352
+ function deriveContractStatus(result, currentStatus) {
353
+ if (currentStatus === "archived") {
354
+ return currentStatus;
355
+ }
356
+ switch (result) {
357
+ case "confirmed":
358
+ return "satisfied";
359
+ case "disconfirmed":
360
+ return "violated";
361
+ case "expired":
362
+ return "expired";
363
+ default:
364
+ if (currentStatus === "satisfied" || currentStatus === "violated" || currentStatus === "expired") {
365
+ return "active";
366
+ }
367
+ return currentStatus;
403
368
  }
404
- return void 0;
405
369
  }
406
- function normalizeHalfLifeMs(halfLifeMs) {
407
- if (halfLifeMs === void 0 || !Number.isFinite(halfLifeMs)) {
408
- return 0;
370
+ function deriveVerificationTrigger(result) {
371
+ switch (result) {
372
+ case "confirmed":
373
+ return "verification_confirmed";
374
+ case "disconfirmed":
375
+ return "verification_disconfirmed";
376
+ case "expired":
377
+ return "verification_expired";
378
+ case "partial":
379
+ return "verification_partial";
380
+ default:
381
+ return null;
409
382
  }
410
- return Math.max(0, halfLifeMs);
411
383
  }
412
- function temporalDecay(sourceOpinion, now, decayParams) {
413
- const halfLifeMs = normalizeHalfLifeMs(decayParams.halfLifeMs);
414
- if (halfLifeMs === 0) {
415
- return { ...sourceOpinion };
384
+ function deriveContractModulationPlan(args) {
385
+ const trigger = deriveVerificationTrigger(args.result);
386
+ if (!trigger) {
387
+ return null;
416
388
  }
417
- const nowMs = toEpochMs(now);
418
- const referenceTimeMs = toEpochMs(decayParams.referenceTime);
419
- if (nowMs === void 0 || referenceTimeMs === void 0) {
420
- return { ...sourceOpinion };
389
+ if (args.result === "confirmed") {
390
+ const rawNext = args.currentConfidence + args.modulation.onConfirmed.delta;
391
+ const confidenceAfter = clampConfidence(
392
+ Math.min(
393
+ args.modulation.onConfirmed.ceiling ?? Number.POSITIVE_INFINITY,
394
+ rawNext
395
+ )
396
+ );
397
+ return {
398
+ trigger,
399
+ confidenceBefore: args.currentConfidence,
400
+ confidenceAfter,
401
+ confidenceDelta: confidenceAfter - args.currentConfidence
402
+ };
421
403
  }
422
- const ageMs = Math.max(0, nowMs - referenceTimeMs);
423
- if (ageMs === 0) {
424
- return { ...sourceOpinion };
404
+ if (args.result === "disconfirmed") {
405
+ const rawNext = args.currentConfidence + args.modulation.onDisconfirmed.delta;
406
+ const confidenceAfter = clampConfidence(
407
+ Math.max(args.modulation.onDisconfirmed.floor ?? 0, rawNext)
408
+ );
409
+ return {
410
+ trigger,
411
+ confidenceBefore: args.currentConfidence,
412
+ confidenceAfter,
413
+ confidenceDelta: confidenceAfter - args.currentConfidence
414
+ };
425
415
  }
426
- const retainedEvidenceWeight = Math.pow(0.5, ageMs / halfLifeMs);
427
- return trustDiscount(
428
- mkOpinion(sourceOpinion.b, sourceOpinion.d, sourceOpinion.u, sourceOpinion.a),
429
- retainedEvidenceWeight
430
- );
416
+ if (args.result === "expired" && args.modulation.onExpired) {
417
+ const confidenceAfter = clampConfidence(
418
+ args.currentConfidence + args.modulation.onExpired.delta
419
+ );
420
+ return {
421
+ trigger,
422
+ confidenceBefore: args.currentConfidence,
423
+ confidenceAfter,
424
+ confidenceDelta: confidenceAfter - args.currentConfidence
425
+ };
426
+ }
427
+ if (args.result === "partial" && args.modulation.onPartial) {
428
+ if ((args.resultConfidence ?? 0) < args.modulation.onPartial.threshold) {
429
+ return null;
430
+ }
431
+ const confidenceAfter = clampConfidence(
432
+ args.currentConfidence + args.modulation.onPartial.delta
433
+ );
434
+ return {
435
+ trigger,
436
+ confidenceBefore: args.currentConfidence,
437
+ confidenceAfter,
438
+ confidenceDelta: confidenceAfter - args.currentConfidence
439
+ };
440
+ }
441
+ return null;
431
442
  }
432
-
433
- // src/v1/operations/contradiction/detectTupleContradiction.ts
434
- var DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD = 0.7;
435
- var DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD = 0.7;
436
- function normalizeTupleContradictionPolicy(policy = {}) {
443
+ function createInheritedContractRecord(contract, args) {
437
444
  return {
438
- beliefThreshold: clamp01(
439
- policy.beliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD
440
- ),
441
- disbeliefThreshold: clamp01(
442
- policy.disbeliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD
443
- )
445
+ beliefNodeId: args.beliefNodeId,
446
+ contractId: generateContractId(),
447
+ title: contract.title,
448
+ description: contract.description,
449
+ conditionType: contract.conditionType,
450
+ direction: contract.direction,
451
+ condition: contract.condition,
452
+ deadline: contract.deadline,
453
+ compositeOf: contract.compositeOf,
454
+ compositeOperator: contract.compositeOperator,
455
+ modulation: contract.modulation,
456
+ evaluationSchedule: contract.evaluationSchedule,
457
+ periodicIntervalMs: contract.periodicIntervalMs,
458
+ status: "active",
459
+ lineageSource: "inherited",
460
+ inheritedFromContractId: contract.contractId,
461
+ inheritedFromBeliefNodeId: contract.beliefNodeId,
462
+ inheritedAt: args.now,
463
+ topicId: args.topicId,
464
+ createdAt: args.now,
465
+ createdBy: args.createdBy,
466
+ updatedAt: args.now
444
467
  };
445
468
  }
446
- function detectTupleContradiction(opinion2, tauB = DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, tauD = DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD) {
447
- return opinion2.b > tauB && opinion2.d > tauD;
469
+ function normalizeEvidentialAction(value) {
470
+ return value === "append_sl_scoring" || value === "flag_review" || value === "archive" ? value : void 0;
448
471
  }
449
- function evaluateTupleContradictionTransition(args) {
450
- const policy = normalizeTupleContradictionPolicy(args.policy);
451
- const tupleContradicted = detectTupleContradiction(
452
- args.opinion,
453
- policy.beliefThreshold,
454
- policy.disbeliefThreshold
472
+ function parseComparisonOperator(value, evaluatorName) {
473
+ if (value === "gte" || value === "lte" || value === "eq" || value === "gt" || value === "lt") {
474
+ return value;
475
+ }
476
+ throw new Error(
477
+ `${evaluatorName} requires operator to be one of gte, lte, eq, gt, or lt.`
455
478
  );
456
- const previousTupleContradicted = Boolean(args.previousTupleContradicted);
479
+ }
480
+ function parseNumericThreshold(value, evaluatorName) {
481
+ if (typeof value === "number" && Number.isFinite(value)) {
482
+ return value;
483
+ }
484
+ throw new Error(`${evaluatorName} requires a finite numeric threshold.`);
485
+ }
486
+ function pickFiniteNumber(config, keys) {
487
+ for (const key of keys) {
488
+ const value = config[key];
489
+ if (typeof value === "number" && Number.isFinite(value)) {
490
+ return value;
491
+ }
492
+ }
493
+ return;
494
+ }
495
+ function getEvaluatorInputRecord(inputData, nestedKey) {
496
+ if (!isRecord(inputData)) {
497
+ return {};
498
+ }
499
+ const nested = inputData[nestedKey];
500
+ if (isRecord(nested)) {
501
+ return nested;
502
+ }
503
+ return inputData;
504
+ }
505
+ function parseEvidentialEvaluatorConfig(value) {
506
+ if (!isRecord(value)) {
507
+ throw new Error(
508
+ "Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
509
+ );
510
+ }
511
+ const config = value;
512
+ const metric = config.metric;
513
+ const operator = config.operator;
514
+ const threshold = config.threshold;
515
+ if (metric !== "evidence_count" && metric !== "contradiction_status" && metric !== "edge_freshness" && metric !== "dependent_count") {
516
+ throw new Error(`Unsupported evidential metric: ${String(metric)}`);
517
+ }
518
+ if (operator !== "gte" && operator !== "lte" && operator !== "eq" && operator !== "gt" && operator !== "lt") {
519
+ throw new Error(`Unsupported evidential operator: ${String(operator)}`);
520
+ }
521
+ if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
522
+ throw new Error("Evidential contracts require a numeric threshold.");
523
+ }
524
+ const actionParams = isRecord(config.actionParams) ? config.actionParams : void 0;
457
525
  return {
458
- tupleContradicted,
459
- crossedIntoTupleContradiction: !previousTupleContradicted && tupleContradicted,
460
- crossedOutOfTupleContradiction: previousTupleContradicted && !tupleContradicted,
461
- policy
526
+ metric,
527
+ operator,
528
+ threshold,
529
+ action: normalizeEvidentialAction(config.action),
530
+ actionParams: actionParams && (typeof actionParams.targetConfidence === "number" || typeof actionParams.rationale === "string") ? {
531
+ targetConfidence: typeof actionParams.targetConfidence === "number" ? actionParams.targetConfidence : void 0,
532
+ rationale: typeof actionParams.rationale === "string" ? actionParams.rationale : void 0
533
+ } : void 0
462
534
  };
463
535
  }
464
-
465
- // src/v1/operations/dynamics/cascade.ts
466
- function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
467
- const dependencyProjection = project(
468
- mkOpinion(
469
- dependencyOpinion.b,
470
- dependencyOpinion.d,
471
- dependencyOpinion.u,
472
- dependencyOpinion.a
473
- )
474
- );
475
- if (mode === "threshold") {
476
- if (dependencyProjection < threshold) {
477
- return opinion(
478
- 0,
479
- beliefOpinion.d + beliefOpinion.b * 0.5,
480
- 0.5,
481
- beliefOpinion.a
482
- );
483
- }
484
- return beliefOpinion;
536
+ function compareMetricValue(operator, left, right) {
537
+ switch (operator) {
538
+ case "gte":
539
+ return left >= right;
540
+ case "lte":
541
+ return left <= right;
542
+ case "eq":
543
+ return left === right;
544
+ case "gt":
545
+ return left > right;
546
+ case "lt":
547
+ return left < right;
548
+ default:
549
+ return false;
485
550
  }
486
- const dampingFactor = Math.pow(dependencyProjection, 0.5);
487
- return opinion(
488
- beliefOpinion.b * dampingFactor,
489
- beliefOpinion.d + beliefOpinion.b * (1 - dampingFactor) * 0.3,
490
- beliefOpinion.u + beliefOpinion.b * (1 - dampingFactor) * 0.7,
491
- beliefOpinion.a
492
- );
493
551
  }
494
- function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "continuous") {
552
+ function resolveComparisonResult(direction, comparisonSatisfied) {
553
+ if (direction === "falsifies") {
554
+ return comparisonSatisfied ? "disconfirmed" : "confirmed";
555
+ }
556
+ return comparisonSatisfied ? "confirmed" : "disconfirmed";
557
+ }
558
+ function buildComparisonRationale(args) {
559
+ const renderedObserved = args.observedValue === null ? "no data" : `${args.observedValue}${args.unit ? ` ${args.unit}` : ""}`;
560
+ const renderedThreshold = `${args.threshold}${args.unit ? ` ${args.unit}` : ""}`;
561
+ const clause = `${args.label} observed ${renderedObserved} against ${args.operator} ${renderedThreshold}`;
562
+ if (args.observedValue === null) {
563
+ return `${clause}; evaluator returned ${args.result} because no current data was available.`;
564
+ }
565
+ return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
566
+ }
567
+ function buildEvidentialRationale(args) {
568
+ const observed = args.snapshot.value === null ? "no data" : String(args.snapshot.value);
569
+ const clause = `${args.snapshot.metric} observed ${observed} against ${args.config.operator} ${args.config.threshold}`;
570
+ if (args.snapshot.value === null) {
571
+ return `${clause}; evidential evaluator treated the comparison as unmet, resulting in ${args.result}.`;
572
+ }
573
+ return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
574
+ }
575
+ function parseMetricCheckerConfig(value) {
576
+ if (!isRecord(value)) {
577
+ throw new Error(
578
+ "metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
579
+ );
580
+ }
581
+ const config = value;
495
582
  return {
496
- opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
497
- operator: "dependency_cascade",
498
- rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
499
- mkOpinion(
500
- dependencyOpinion.b,
501
- dependencyOpinion.d,
502
- dependencyOpinion.u,
503
- dependencyOpinion.a
504
- )
505
- ).toFixed(2)}`
583
+ metric: typeof config.metric === "string" && config.metric.length > 0 ? config.metric : void 0,
584
+ operator: parseComparisonOperator(config.operator, BUILT_IN_METRIC_CHECKER),
585
+ threshold: parseNumericThreshold(config.threshold, BUILT_IN_METRIC_CHECKER),
586
+ observedValue: pickFiniteNumber(config, ["observedValue", "value"]),
587
+ currentValue: pickFiniteNumber(config, ["currentValue"]),
588
+ metricValue: pickFiniteNumber(config, ["metricValue"]),
589
+ unit: typeof config.unit === "string" && config.unit.length > 0 ? config.unit : void 0
506
590
  };
507
591
  }
508
-
509
- // src/v1/operations/dynamics/defeat.ts
510
- function applyNegativeSupport(source, target, weight, metadata = {}) {
511
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
512
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
513
- if (metadata.constraint === "xor") {
514
- const result = constraintFusion(
515
- sourceOpinion,
516
- targetOpinion,
517
- metadata.normalization ?? "pressure"
592
+ function parseReferenceCheckCounterConfig(value) {
593
+ if (!isRecord(value)) {
594
+ throw new Error(
595
+ "reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
518
596
  );
519
- return {
520
- opinion: result.o2,
521
- operator: "constraint_fusion",
522
- rationale: `XOR constraint: source belief at ${project(
523
- sourceOpinion
524
- ).toFixed(2)} pressures target`
525
- };
526
597
  }
527
- const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
598
+ const config = value;
599
+ if (typeof config.tag !== "string" || config.tag.trim().length === 0) {
600
+ throw new Error("reference_check_counter requires a non-empty tag.");
601
+ }
528
602
  return {
529
- opinion: cumulativeFusion(targetOpinion, discounted),
530
- operator: "cumulative_fusion",
531
- rationale: `Contradicting evidence (weight=${weight.toFixed(
532
- 2
533
- )}) from source at ${project(sourceOpinion).toFixed(2)}`
603
+ tag: config.tag.trim(),
604
+ operator: parseComparisonOperator(
605
+ config.operator,
606
+ BUILT_IN_REFERENCE_CHECK_COUNTER
607
+ ),
608
+ threshold: parseNumericThreshold(
609
+ config.threshold,
610
+ BUILT_IN_REFERENCE_CHECK_COUNTER
611
+ ),
612
+ caseSensitive: config.caseSensitive === true
534
613
  };
535
614
  }
536
- function applyNegativeEvidence(source, target, weight) {
537
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
538
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
539
- const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
615
+ function parseTemporalDeadlineConfig(value) {
616
+ if (!isRecord(value)) {
617
+ return {};
618
+ }
619
+ const config = value;
540
620
  return {
541
- opinion: cumulativeFusion(targetOpinion, discounted),
542
- operator: "cumulative_fusion",
543
- rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
621
+ label: typeof config.label === "string" && config.label.length > 0 ? config.label : void 0,
622
+ completed: config.completed === true,
623
+ completedAt: pickFiniteNumber(config, ["completedAt"]),
624
+ observedAt: pickFiniteNumber(config, ["observedAt"]),
625
+ satisfiedAt: pickFiniteNumber(config, ["satisfiedAt"]),
626
+ achievedAt: pickFiniteNumber(config, ["achievedAt"])
544
627
  };
545
628
  }
546
-
547
- // src/v1/operations/dynamics/propagation.ts
548
- var EDGE_PROPAGATION_RULES = {
549
- supports: {
550
- direction: "outgoing",
551
- handler: (source, target, weight, metadata) => {
552
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
553
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
554
- if (weight < 0) {
555
- return applyNegativeSupport(sourceOpinion, targetOpinion, weight, metadata);
556
- }
557
- const discounted = trustDiscount(sourceOpinion, weight);
558
- return {
559
- opinion: cumulativeFusion(targetOpinion, discounted),
560
- operator: "cumulative_fusion",
561
- rationale: `Supporting evidence (weight=${weight.toFixed(
562
- 2
563
- )}) from source at ${project(sourceOpinion).toFixed(2)}`
564
- };
565
- }
566
- },
567
- informs: {
568
- direction: "outgoing",
569
- handler: (source, target, weight) => {
570
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
571
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
572
- if (weight < 0) {
573
- return applyNegativeEvidence(sourceOpinion, targetOpinion, weight);
574
- }
575
- const discounted = trustDiscount(sourceOpinion, Math.abs(weight));
576
- return {
577
- opinion: cumulativeFusion(targetOpinion, discounted),
578
- operator: "cumulative_fusion",
579
- rationale: `Supporting evidence (weight=${weight.toFixed(2)})`
580
- };
581
- }
582
- },
583
- depends_on: {
584
- direction: "incoming",
585
- handler: (source, target, _weight, metadata) => {
586
- const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
587
- const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
588
- if (metadata.conditionalA && metadata.conditionalNotA) {
589
- return {
590
- opinion: conditionalDeduction(
591
- sourceOpinion,
592
- mkOpinion(
593
- metadata.conditionalA.b,
594
- metadata.conditionalA.d,
595
- metadata.conditionalA.u,
596
- metadata.conditionalA.a
597
- ),
598
- mkOpinion(
599
- metadata.conditionalNotA.b,
600
- metadata.conditionalNotA.d,
601
- metadata.conditionalNotA.u,
602
- metadata.conditionalNotA.a
603
- ),
604
- targetOpinion.a
605
- ),
606
- operator: "conditional_deduction",
607
- rationale: `Conditional deduction: prerequisite at ${project(
608
- sourceOpinion
609
- ).toFixed(2)}`
610
- };
611
- }
612
- return dampedDependencyCascade(
613
- sourceOpinion,
614
- targetOpinion,
615
- metadata.propagation ?? "continuous"
616
- );
617
- }
618
- },
619
- derived_from: {
620
- direction: "incoming",
621
- handler: (_source, target) => ({
622
- opinion: target,
623
- operator: "trust_discount",
624
- rationale: "Provenance edge \u2014 no confidence propagation"
625
- })
626
- },
627
- contains: {
628
- direction: "outgoing",
629
- handler: (_source, target) => ({
630
- opinion: target,
631
- operator: "trust_discount",
632
- rationale: "Containment edge \u2014 no confidence propagation"
633
- })
634
- },
635
- tests: {
636
- direction: "outgoing",
637
- handler: (_source, target) => ({
638
- opinion: target,
639
- operator: "trust_discount",
640
- rationale: "Testing edge \u2014 no confidence propagation"
641
- })
642
- }
643
- };
644
- var PROPAGATION_TRAVERSAL_SPECS = Object.entries(EDGE_PROPAGATION_RULES).map(([edgeType, rule]) => ({
645
- edgeType,
646
- direction: rule.direction
647
- }));
648
- function isPropagationEdgeType(edgeType) {
649
- return edgeType in EDGE_PROPAGATION_RULES;
650
- }
651
- function getPropagationTraversalSpecs() {
652
- return PROPAGATION_TRAVERSAL_SPECS;
653
- }
654
- function propagateThroughEdge(sourceOpinion, targetOpinion, edgeType, weight = 1, metadata = {}) {
655
- const handler = isPropagationEdgeType(edgeType) ? EDGE_PROPAGATION_RULES[edgeType].handler : void 0;
656
- if (!handler) {
657
- return {
658
- opinion: targetOpinion,
659
- operator: "no_op",
660
- rationale: `Unknown edge type: ${edgeType} \u2014 no propagation`
661
- };
662
- }
663
- return handler(sourceOpinion, targetOpinion, weight, metadata);
664
- }
665
- function propagateAllEdges(currentOpinion, incomingEdges) {
666
- let result = currentOpinion;
667
- const rationales = [];
668
- for (const edgeType of ["depends_on", "informs", "supports"]) {
669
- for (const incoming of incomingEdges.filter((edge) => edge.edgeType === edgeType)) {
670
- const propagated = propagateThroughEdge(
671
- incoming.sourceOpinion,
672
- result,
673
- incoming.edgeType,
674
- incoming.weight,
675
- incoming.metadata
676
- );
677
- result = propagated.opinion;
678
- rationales.push(propagated.rationale);
679
- }
629
+ function parseMarketIndexComparatorConfig(value) {
630
+ if (!isRecord(value)) {
631
+ throw new Error(
632
+ "market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
633
+ );
680
634
  }
635
+ const config = value;
681
636
  return {
682
- opinion: result,
683
- operator: "cumulative_fusion",
684
- rationale: rationales.join("; ")
637
+ subject: typeof config.subject === "string" && config.subject.length > 0 ? config.subject : void 0,
638
+ subjectValue: pickFiniteNumber(config, ["subjectValue", "leftValue"]),
639
+ primaryValue: pickFiniteNumber(config, ["primaryValue"]),
640
+ benchmark: typeof config.benchmark === "string" && config.benchmark.length > 0 ? config.benchmark : void 0,
641
+ benchmarkValue: pickFiniteNumber(config, ["benchmarkValue", "rightValue"]),
642
+ comparisonValue: pickFiniteNumber(config, ["comparisonValue"]),
643
+ operator: parseComparisonOperator(
644
+ config.operator,
645
+ BUILT_IN_MARKET_INDEX_COMPARATOR
646
+ ),
647
+ threshold: parseNumericThreshold(
648
+ config.threshold,
649
+ BUILT_IN_MARKET_INDEX_COMPARATOR
650
+ )
685
651
  };
686
652
  }
687
653
 
688
- // src/v1/operations/bridge/index.ts
689
- var DEFAULT_NON_INFORMATIVE_WEIGHT = 2;
690
- function clamp012(value) {
691
- return Math.max(0, Math.min(1, value));
692
- }
693
- function clampNonNegative(value) {
694
- return Number.isFinite(value) ? Math.max(0, value) : 0;
654
+ // src/v1/operations/scoring.ts
655
+ function finiteNumber(value) {
656
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
695
657
  }
696
- function normalizeNonInformativeWeight(weight) {
697
- if (weight === void 0) {
698
- return DEFAULT_NON_INFORMATIVE_WEIGHT;
658
+ function requiredOpinionNumber(label, ...values) {
659
+ for (const value of values) {
660
+ const numberValue = finiteNumber(value);
661
+ if (numberValue !== void 0) {
662
+ return numberValue;
663
+ }
699
664
  }
700
- return Number.isFinite(weight) ? Math.max(0, weight) : DEFAULT_NON_INFORMATIVE_WEIGHT;
665
+ throw new Error(`Opinion record is missing required ${label}.`);
701
666
  }
702
- function normalizeBaseRateVector(baseRate, size) {
703
- if (size === 0) {
704
- return [];
705
- }
706
- if (baseRate.length !== size) {
707
- throw new Error(
708
- `Base-rate vector length ${baseRate.length} must match evidence vector length ${size}.`
709
- );
710
- }
711
- const normalized = baseRate.map((value) => clampNonNegative(value));
712
- const total = normalized.reduce((sum, value) => sum + value, 0);
713
- if (total === 0) {
714
- throw new Error("Base-rate vector must contain at least one positive value.");
715
- }
716
- return normalized.map((value) => value / total);
667
+ function clamp01(value) {
668
+ return Math.max(0, Math.min(1, value));
717
669
  }
718
- function opinionFromDirichlet(alpha, nonInformativeWeight, baseRate) {
719
- const evidence = alpha.map((value) => clampNonNegative(value));
720
- const safeWeight = normalizeNonInformativeWeight(nonInformativeWeight);
721
- const normalizedBaseRate = normalizeBaseRateVector(baseRate, evidence.length);
722
- const totalEvidence = evidence.reduce((sum, value) => sum + value, 0);
723
- const denominator = totalEvidence + safeWeight;
724
- if (denominator === 0) {
725
- return {
726
- b: evidence.map(() => 0),
727
- u: 1,
728
- a: normalizedBaseRate
729
- };
730
- }
670
+ function confidenceFromOpinion(opinion2) {
671
+ return clamp01(opinion2.b + opinion2.a * opinion2.u);
672
+ }
673
+ function toStoredOpinionFields(opinion2) {
731
674
  return {
732
- b: evidence.map((value) => value / denominator),
733
- u: safeWeight / denominator,
734
- a: normalizedBaseRate
675
+ belief: opinion2.b,
676
+ disbelief: opinion2.d,
677
+ uncertainty: opinion2.u,
678
+ baseRate: opinion2.a
735
679
  };
736
680
  }
737
- function opinionFromBeta(alpha, beta, nonInformativeWeight, baseRate) {
738
- const dirichlet = opinionFromDirichlet(
739
- [alpha, beta],
740
- nonInformativeWeight,
741
- [clamp012(baseRate), 1 - clamp012(baseRate)]
742
- );
681
+ function readOpinionFromRecord(source) {
682
+ const record = source && typeof source === "object" ? source : {};
743
683
  return mkOpinion(
744
- dirichlet.b[0] ?? 0,
745
- dirichlet.b[1] ?? 0,
746
- dirichlet.u,
747
- dirichlet.a[0] ?? clamp012(baseRate)
684
+ requiredOpinionNumber(
685
+ "belief",
686
+ record.b,
687
+ record.belief,
688
+ record.slBelief,
689
+ record.opinion_b
690
+ ),
691
+ requiredOpinionNumber(
692
+ "disbelief",
693
+ record.d,
694
+ record.disbelief,
695
+ record.slDisbelief,
696
+ record.opinion_d
697
+ ),
698
+ requiredOpinionNumber(
699
+ "uncertainty",
700
+ record.u,
701
+ record.uncertainty,
702
+ record.slUncertainty,
703
+ record.opinion_u
704
+ ),
705
+ requiredOpinionNumber(
706
+ "baseRate",
707
+ record.a,
708
+ record.baseRate,
709
+ record.slBaseRate,
710
+ record.opinion_a
711
+ )
748
712
  );
749
713
  }
750
-
751
- // src/v1/operations/dynamics/revision.ts
752
- function clamp013(value) {
753
- return Math.max(0, Math.min(1, value));
754
- }
755
- function toEvidence(probability, weight) {
756
- const safeProbability = clamp013(probability);
757
- const safeWeight = Number.isFinite(weight) ? Math.max(0, weight) : 0;
758
- return {
759
- alpha: safeProbability * safeWeight,
760
- beta: (1 - safeProbability) * safeWeight
761
- };
714
+ function opinionFromScalar(value, mode, options) {
715
+ const clampedValue = clamp01(value);
716
+ const baseRate = options?.baseRate === void 0 ? void 0 : clamp01(options.baseRate);
717
+ switch (mode) {
718
+ case "base_rate":
719
+ return mkOpinion(0, 0, 1, clampedValue);
720
+ case "dogmatic":
721
+ if (baseRate === void 0) {
722
+ throw new Error(
723
+ 'opinionFromScalar(value, "dogmatic") requires options.baseRate.'
724
+ );
725
+ }
726
+ return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);
727
+ case "projected_with_u": {
728
+ if (baseRate === void 0) {
729
+ throw new Error(
730
+ 'opinionFromScalar(value, "projected_with_u") requires options.baseRate.'
731
+ );
732
+ }
733
+ const uncertainty = options?.uncertainty;
734
+ if (uncertainty === void 0) {
735
+ throw new Error(
736
+ 'opinionFromScalar(value, "projected_with_u") requires options.uncertainty.'
737
+ );
738
+ }
739
+ const clampedUncertainty = clamp01(uncertainty);
740
+ const evidenceWeight = 1 - clampedUncertainty;
741
+ return mkOpinion(
742
+ clampedValue * evidenceWeight,
743
+ (1 - clampedValue) * evidenceWeight,
744
+ clampedUncertainty,
745
+ baseRate
746
+ );
747
+ }
748
+ default:
749
+ throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);
750
+ }
762
751
  }
763
- function bayesianUpdate(priorConfidence, priorWeight, newAssessment, newWeight, options) {
764
- return reviseConfidence({
765
- priorConfidence,
766
- priorWeight,
767
- newAssessment,
768
- newWeight,
769
- baseRate: options?.baseRate,
770
- nonInformativeWeight: options?.nonInformativeWeight
771
- });
752
+ function toDogmaticOpinion(confidence, baseRate) {
753
+ return opinionFromScalar(confidence, "dogmatic", { baseRate });
772
754
  }
773
- function reviseConfidence(args) {
774
- return project(reviseConfidenceOpinion(args));
755
+ function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
756
+ return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
775
757
  }
776
- function reviseConfidenceOpinion(args) {
777
- const priorEvidence = toEvidence(args.priorConfidence, args.priorWeight);
778
- const newEvidence = toEvidence(args.newAssessment, args.newWeight ?? 1);
779
- return opinionFromBeta(
780
- priorEvidence.alpha + newEvidence.alpha,
781
- priorEvidence.beta + newEvidence.beta,
782
- args.nonInformativeWeight ?? DEFAULT_NON_INFORMATIVE_WEIGHT,
783
- args.baseRate
758
+
759
+ // src/v1/operations/contradiction/detectTupleContradiction.ts
760
+ var DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD = 0.7;
761
+ var DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD = 0.7;
762
+ function normalizeTupleContradictionPolicy(policy = {}) {
763
+ return {
764
+ beliefThreshold: clamp01(
765
+ policy.beliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD
766
+ ),
767
+ disbeliefThreshold: clamp01(
768
+ policy.disbeliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD
769
+ )
770
+ };
771
+ }
772
+ function detectTupleContradiction(opinion2, tauB = DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, tauD = DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD) {
773
+ return opinion2.b > tauB && opinion2.d > tauD;
774
+ }
775
+ function evaluateTupleContradictionTransition(args) {
776
+ const policy = normalizeTupleContradictionPolicy(args.policy);
777
+ const tupleContradicted = detectTupleContradiction(
778
+ args.opinion,
779
+ policy.beliefThreshold,
780
+ policy.disbeliefThreshold
784
781
  );
782
+ const previousTupleContradicted = Boolean(args.previousTupleContradicted);
783
+ return {
784
+ tupleContradicted,
785
+ crossedIntoTupleContradiction: !previousTupleContradicted && tupleContradicted,
786
+ crossedOutOfTupleContradiction: previousTupleContradicted && !tupleContradicted,
787
+ policy
788
+ };
785
789
  }
786
790
 
787
791
  // src/v1/operations/dynamics/decay.ts
@@ -899,6 +903,102 @@ function lifecycleMultiplier(status) {
899
903
  }
900
904
  return 1;
901
905
  }
906
+ function resolveLifecycleRescore(context) {
907
+ if (context.isOverdue && context.lifecycleStatus === "assumption") {
908
+ return {
909
+ priority: "critical",
910
+ reason: `Untested assumption is stale (${Math.round(context.decayState.ageDays)}d) \u2014 validate or supersede`
911
+ };
912
+ }
913
+ if (context.isOverdue && context.lifecycleStatus === "hypothesis" || context.lifecycleStatus === "hypothesis" && context.daysUntilRescore < 7) {
914
+ return {
915
+ priority: "high",
916
+ reason: `Hypothesis aging without validation (${Math.round(context.decayState.ageDays)}d) \u2014 run/finish sprint testing`
917
+ };
918
+ }
919
+ }
920
+ function resolveDeadlineRescore(context) {
921
+ const urgency = context.decayState.urgency;
922
+ if (urgency?.isOverdue) {
923
+ return {
924
+ priority: "critical",
925
+ reason: `Prediction deadline passed ${Math.abs(urgency.daysToDeadline)}d ago \u2014 validate or archive`
926
+ };
927
+ }
928
+ if (urgency?.urgencyTier.label === "critical") {
929
+ return {
930
+ priority: "critical",
931
+ reason: `Deadline in ${urgency.daysToDeadline}d \u2014 needs immediate rescoring`
932
+ };
933
+ }
934
+ if (urgency?.urgencyTier.label === "imminent") {
935
+ return {
936
+ priority: "high",
937
+ reason: `Deadline in ${urgency.daysToDeadline}d \u2014 weekly rescoring required`
938
+ };
939
+ }
940
+ }
941
+ function resolveStalenessRescore(context) {
942
+ if (context.isOverdue && context.decayState.baseTier.label === "expired") {
943
+ return {
944
+ priority: "critical",
945
+ reason: `Not scored in ${Math.round(context.decayState.ageDays)}d \u2014 confidence severely degraded`
946
+ };
947
+ }
948
+ if (context.isOverdue && context.decayState.baseTier.label === "stale") {
949
+ return {
950
+ priority: "high",
951
+ reason: `Stale (${Math.round(context.decayState.ageDays)}d since scoring) \u2014 evidence update required`
952
+ };
953
+ }
954
+ if (context.isOverdue) {
955
+ return {
956
+ priority: "high",
957
+ reason: `Rescore overdue by ${Math.abs(Math.round(context.daysUntilRescore))}d`
958
+ };
959
+ }
960
+ }
961
+ function resolveRoutineRescore(context) {
962
+ if (context.temporalNature === "forecast" && context.daysUntilRescore < 7) {
963
+ return {
964
+ priority: "medium",
965
+ reason: `Forecast belief \u2014 next rescore due in ${Math.round(context.daysUntilRescore)}d`
966
+ };
967
+ }
968
+ if (context.daysUntilRescore < 14) {
969
+ return {
970
+ priority: "medium",
971
+ reason: `Rescore due in ${Math.round(context.daysUntilRescore)}d`
972
+ };
973
+ }
974
+ return {
975
+ priority: "low",
976
+ reason: `On schedule \u2014 next rescore in ${Math.round(context.daysUntilRescore)}d`
977
+ };
978
+ }
979
+ function escalateHighConfidenceRescore(result, context) {
980
+ if ((context.confidence ?? 0) >= 0.8 && context.decayState.baseTier.label !== "fresh" && result.priority === "medium") {
981
+ return {
982
+ priority: "high",
983
+ reason: `High-confidence belief (${((context.confidence ?? 0) * 100).toFixed(0)}%) aging without rescore \u2014 ${result.reason}`
984
+ };
985
+ }
986
+ return result;
987
+ }
988
+ var RESCORING_RULES = [
989
+ resolveLifecycleRescore,
990
+ resolveDeadlineRescore,
991
+ resolveStalenessRescore
992
+ ];
993
+ function resolveRescoringPriority(context) {
994
+ for (const rule of RESCORING_RULES) {
995
+ const result = rule(context);
996
+ if (result) {
997
+ return escalateHighConfidenceRescore(result, context);
998
+ }
999
+ }
1000
+ return escalateHighConfidenceRescore(resolveRoutineRescore(context), context);
1001
+ }
902
1002
  function computeBaseDecay(lastScoredAt) {
903
1003
  const ageDays = (Date.now() - lastScoredAt) / (1e3 * 60 * 60 * 24);
904
1004
  let tier = DECAY_TIERS.EXPIRED;
@@ -970,46 +1070,14 @@ function getRescoringSchedule(opts) {
970
1070
  );
971
1071
  const daysUntilRescore = (decayState.rescoreByDate - Date.now()) / (1e3 * 60 * 60 * 24);
972
1072
  const isOverdue = daysUntilRescore < 0;
973
- let priority;
974
- let reason;
975
- if (isOverdue && lifecycleStatus === "assumption") {
976
- priority = "critical";
977
- reason = `Untested assumption is stale (${Math.round(decayState.ageDays)}d) \u2014 validate or supersede`;
978
- } else if (isOverdue && lifecycleStatus === "hypothesis" || lifecycleStatus === "hypothesis" && daysUntilRescore < 7) {
979
- priority = "high";
980
- reason = `Hypothesis aging without validation (${Math.round(decayState.ageDays)}d) \u2014 run/finish sprint testing`;
981
- } else if (decayState.urgency?.isOverdue) {
982
- priority = "critical";
983
- reason = `Prediction deadline passed ${Math.abs(decayState.urgency.daysToDeadline)}d ago \u2014 validate or archive`;
984
- } else if (isOverdue && decayState.baseTier.label === "expired") {
985
- priority = "critical";
986
- reason = `Not scored in ${Math.round(decayState.ageDays)}d \u2014 confidence severely degraded`;
987
- } else if (isOverdue && decayState.baseTier.label === "stale") {
988
- priority = "high";
989
- reason = `Stale (${Math.round(decayState.ageDays)}d since scoring) \u2014 evidence update required`;
990
- } else if (decayState.urgency && decayState.urgency.urgencyTier.label === "critical") {
991
- priority = "critical";
992
- reason = `Deadline in ${decayState.urgency.daysToDeadline}d \u2014 needs immediate rescoring`;
993
- } else if (decayState.urgency && decayState.urgency.urgencyTier.label === "imminent") {
994
- priority = "high";
995
- reason = `Deadline in ${decayState.urgency.daysToDeadline}d \u2014 weekly rescoring required`;
996
- } else if (isOverdue) {
997
- priority = "high";
998
- reason = `Rescore overdue by ${Math.abs(Math.round(daysUntilRescore))}d`;
999
- } else if (opts.temporalNature === "forecast" && daysUntilRescore < 7) {
1000
- priority = "medium";
1001
- reason = `Forecast belief \u2014 next rescore due in ${Math.round(daysUntilRescore)}d`;
1002
- } else if (daysUntilRescore < 14) {
1003
- priority = "medium";
1004
- reason = `Rescore due in ${Math.round(daysUntilRescore)}d`;
1005
- } else {
1006
- priority = "low";
1007
- reason = `On schedule \u2014 next rescore in ${Math.round(daysUntilRescore)}d`;
1008
- }
1009
- if ((opts.confidence ?? 0) >= 0.8 && decayState.baseTier.label !== "fresh" && priority === "medium") {
1010
- priority = "high";
1011
- reason = `High-confidence belief (${((opts.confidence ?? 0) * 100).toFixed(0)}%) aging without rescore \u2014 ${reason}`;
1012
- }
1073
+ const { priority, reason } = resolveRescoringPriority({
1074
+ confidence: opts.confidence,
1075
+ daysUntilRescore,
1076
+ decayState,
1077
+ isOverdue,
1078
+ lifecycleStatus,
1079
+ temporalNature: opts.temporalNature
1080
+ });
1013
1081
  return {
1014
1082
  nextRescoreBy: decayState.rescoreByDate,
1015
1083
  daysUntilRescore: Math.round(daysUntilRescore),
@@ -1023,7 +1091,7 @@ function decay(current, daysSinceLastUpdate, halfLifeDays = 90) {
1023
1091
  if (daysSinceLastUpdate <= 0) {
1024
1092
  return current;
1025
1093
  }
1026
- const decayFactor = Math.pow(0.5, daysSinceLastUpdate / halfLifeDays);
1094
+ const decayFactor = 0.5 ** (daysSinceLastUpdate / halfLifeDays);
1027
1095
  const certainty = current.b + current.d;
1028
1096
  const lostCertainty = certainty - certainty * decayFactor;
1029
1097
  return opinion(
@@ -1034,316 +1102,375 @@ function decay(current, daysSinceLastUpdate, halfLifeDays = 90) {
1034
1102
  );
1035
1103
  }
1036
1104
 
1037
- // src/v1/operations/contracts/epistemicContract.ts
1038
- var BUILT_IN_METRIC_CHECKER = "metric_checker";
1039
- var BUILT_IN_REFERENCE_CHECK_COUNTER = "reference_check_counter";
1040
- var BUILT_IN_MARKET_INDEX_COMPARATOR = "market_index_comparator";
1041
- function clampConfidence(value) {
1042
- return Math.max(0, Math.min(1, value));
1043
- }
1044
- function generateContractId() {
1045
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1046
- return crypto.randomUUID();
1047
- }
1048
- return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
1049
- }
1050
- function isRecord(value) {
1051
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1052
- }
1053
- function deriveContractStatus(result, currentStatus) {
1054
- if (currentStatus === "archived") {
1055
- return currentStatus;
1056
- }
1057
- switch (result) {
1058
- case "confirmed":
1059
- return "satisfied";
1060
- case "disconfirmed":
1061
- return "violated";
1062
- case "expired":
1063
- return "expired";
1064
- default:
1065
- return currentStatus === "satisfied" || currentStatus === "violated" || currentStatus === "expired" ? "active" : currentStatus;
1066
- }
1067
- }
1068
- function deriveVerificationTrigger(result) {
1069
- switch (result) {
1070
- case "confirmed":
1071
- return "verification_confirmed";
1072
- case "disconfirmed":
1073
- return "verification_disconfirmed";
1074
- case "expired":
1075
- return "verification_expired";
1076
- case "partial":
1077
- return "verification_partial";
1078
- default:
1079
- return null;
1080
- }
1081
- }
1082
- function deriveContractModulationPlan(args) {
1083
- const trigger = deriveVerificationTrigger(args.result);
1084
- if (!trigger) {
1085
- return null;
1086
- }
1087
- if (args.result === "confirmed") {
1088
- const rawNext = args.currentConfidence + args.modulation.onConfirmed.delta;
1089
- const confidenceAfter = clampConfidence(
1090
- Math.min(
1091
- args.modulation.onConfirmed.ceiling ?? Number.POSITIVE_INFINITY,
1092
- rawNext
1093
- )
1094
- );
1095
- return {
1096
- trigger,
1097
- confidenceBefore: args.currentConfidence,
1098
- confidenceAfter,
1099
- confidenceDelta: confidenceAfter - args.currentConfidence
1100
- };
1101
- }
1102
- if (args.result === "disconfirmed") {
1103
- const rawNext = args.currentConfidence + args.modulation.onDisconfirmed.delta;
1104
- const confidenceAfter = clampConfidence(
1105
- Math.max(args.modulation.onDisconfirmed.floor ?? 0, rawNext)
1106
- );
1107
- return {
1108
- trigger,
1109
- confidenceBefore: args.currentConfidence,
1110
- confidenceAfter,
1111
- confidenceDelta: confidenceAfter - args.currentConfidence
1112
- };
1113
- }
1114
- if (args.result === "expired" && args.modulation.onExpired) {
1115
- const confidenceAfter = clampConfidence(
1116
- args.currentConfidence + args.modulation.onExpired.delta
1117
- );
1118
- return {
1119
- trigger,
1120
- confidenceBefore: args.currentConfidence,
1121
- confidenceAfter,
1122
- confidenceDelta: confidenceAfter - args.currentConfidence
1123
- };
1124
- }
1125
- if (args.result === "partial" && args.modulation.onPartial) {
1126
- if ((args.resultConfidence ?? 0) < args.modulation.onPartial.threshold) {
1127
- return null;
1128
- }
1129
- const confidenceAfter = clampConfidence(
1130
- args.currentConfidence + args.modulation.onPartial.delta
1105
+ // src/v1/operations/dynamics/defeat.ts
1106
+ function applyNegativeSupport(source, target, weight, metadata = {}) {
1107
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1108
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1109
+ if (metadata.constraint === "xor") {
1110
+ const result = constraintFusion(
1111
+ sourceOpinion,
1112
+ targetOpinion,
1113
+ metadata.normalization ?? "pressure"
1131
1114
  );
1132
1115
  return {
1133
- trigger,
1134
- confidenceBefore: args.currentConfidence,
1135
- confidenceAfter,
1136
- confidenceDelta: confidenceAfter - args.currentConfidence
1116
+ opinion: result.o2,
1117
+ operator: "constraint_fusion",
1118
+ rationale: `XOR constraint: source belief at ${project(
1119
+ sourceOpinion
1120
+ ).toFixed(2)} pressures target`
1137
1121
  };
1138
1122
  }
1139
- return null;
1140
- }
1141
- function createInheritedContractRecord(contract, args) {
1123
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
1142
1124
  return {
1143
- beliefNodeId: args.beliefNodeId,
1144
- contractId: generateContractId(),
1145
- title: contract.title,
1146
- description: contract.description,
1147
- conditionType: contract.conditionType,
1148
- direction: contract.direction,
1149
- condition: contract.condition,
1150
- deadline: contract.deadline,
1151
- compositeOf: contract.compositeOf,
1152
- compositeOperator: contract.compositeOperator,
1153
- modulation: contract.modulation,
1154
- evaluationSchedule: contract.evaluationSchedule,
1155
- periodicIntervalMs: contract.periodicIntervalMs,
1156
- status: "active",
1157
- lineageSource: "inherited",
1158
- inheritedFromContractId: contract.contractId,
1159
- inheritedFromBeliefNodeId: contract.beliefNodeId,
1160
- inheritedAt: args.now,
1161
- topicId: args.topicId,
1162
- createdAt: args.now,
1163
- createdBy: args.createdBy,
1164
- updatedAt: args.now
1125
+ opinion: cumulativeFusion(targetOpinion, discounted),
1126
+ operator: "cumulative_fusion",
1127
+ rationale: `Contradicting evidence (weight=${weight.toFixed(
1128
+ 2
1129
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
1165
1130
  };
1166
1131
  }
1167
- function normalizeEvidentialAction(value) {
1168
- return value === "append_sl_scoring" || value === "flag_review" || value === "archive" ? value : void 0;
1132
+ function applyNegativeEvidence(source, target, weight) {
1133
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1134
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1135
+ const discounted = trustDiscount(negate(sourceOpinion), Math.abs(weight));
1136
+ return {
1137
+ opinion: cumulativeFusion(targetOpinion, discounted),
1138
+ operator: "cumulative_fusion",
1139
+ rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
1140
+ };
1169
1141
  }
1170
- function parseComparisonOperator(value, evaluatorName) {
1171
- if (value === "gte" || value === "lte" || value === "eq" || value === "gt" || value === "lt") {
1172
- return value;
1173
- }
1174
- throw new Error(
1175
- `${evaluatorName} requires operator to be one of gte, lte, eq, gt, or lt.`
1142
+
1143
+ // src/v1/operations/dynamics/cascade.ts
1144
+ function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
1145
+ const dependencyProjection = project(
1146
+ mkOpinion(
1147
+ dependencyOpinion.b,
1148
+ dependencyOpinion.d,
1149
+ dependencyOpinion.u,
1150
+ dependencyOpinion.a
1151
+ )
1176
1152
  );
1177
- }
1178
- function parseNumericThreshold(value, evaluatorName) {
1179
- if (typeof value === "number" && Number.isFinite(value)) {
1180
- return value;
1181
- }
1182
- throw new Error(`${evaluatorName} requires a finite numeric threshold.`);
1183
- }
1184
- function pickFiniteNumber(config, keys) {
1185
- for (const key of keys) {
1186
- const value = config[key];
1187
- if (typeof value === "number" && Number.isFinite(value)) {
1188
- return value;
1153
+ if (mode === "threshold") {
1154
+ if (dependencyProjection < threshold) {
1155
+ return opinion(
1156
+ 0,
1157
+ beliefOpinion.d + beliefOpinion.b * 0.5,
1158
+ 0.5,
1159
+ beliefOpinion.a
1160
+ );
1189
1161
  }
1162
+ return beliefOpinion;
1190
1163
  }
1191
- return void 0;
1164
+ const dampingFactor = dependencyProjection ** 0.5;
1165
+ return opinion(
1166
+ beliefOpinion.b * dampingFactor,
1167
+ beliefOpinion.d + beliefOpinion.b * (1 - dampingFactor) * 0.3,
1168
+ beliefOpinion.u + beliefOpinion.b * (1 - dampingFactor) * 0.7,
1169
+ beliefOpinion.a
1170
+ );
1192
1171
  }
1193
- function getEvaluatorInputRecord(inputData, nestedKey) {
1194
- if (!isRecord(inputData)) {
1195
- return {};
1196
- }
1197
- const nested = inputData[nestedKey];
1198
- if (isRecord(nested)) {
1199
- return nested;
1200
- }
1201
- return inputData;
1172
+ function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "continuous") {
1173
+ return {
1174
+ opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
1175
+ operator: "dependency_cascade",
1176
+ rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
1177
+ mkOpinion(
1178
+ dependencyOpinion.b,
1179
+ dependencyOpinion.d,
1180
+ dependencyOpinion.u,
1181
+ dependencyOpinion.a
1182
+ )
1183
+ ).toFixed(2)}`
1184
+ };
1202
1185
  }
1203
- function parseEvidentialEvaluatorConfig(value) {
1204
- if (!isRecord(value)) {
1205
- throw new Error(
1206
- "Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
1207
- );
1208
- }
1209
- const config = value;
1210
- const metric = config.metric;
1211
- const operator = config.operator;
1212
- const threshold = config.threshold;
1213
- if (metric !== "evidence_count" && metric !== "contradiction_status" && metric !== "edge_freshness" && metric !== "dependent_count") {
1214
- throw new Error(`Unsupported evidential metric: ${String(metric)}`);
1186
+
1187
+ // src/v1/operations/dynamics/propagation.ts
1188
+ var EDGE_PROPAGATION_RULES = {
1189
+ supports: {
1190
+ direction: "outgoing",
1191
+ handler: (source, target, weight, metadata) => {
1192
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1193
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1194
+ if (weight < 0) {
1195
+ return applyNegativeSupport(
1196
+ sourceOpinion,
1197
+ targetOpinion,
1198
+ weight,
1199
+ metadata
1200
+ );
1201
+ }
1202
+ const discounted = trustDiscount(sourceOpinion, weight);
1203
+ return {
1204
+ opinion: cumulativeFusion(targetOpinion, discounted),
1205
+ operator: "cumulative_fusion",
1206
+ rationale: `Supporting evidence (weight=${weight.toFixed(
1207
+ 2
1208
+ )}) from source at ${project(sourceOpinion).toFixed(2)}`
1209
+ };
1210
+ }
1211
+ },
1212
+ informs: {
1213
+ direction: "outgoing",
1214
+ handler: (source, target, weight) => {
1215
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1216
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1217
+ if (weight < 0) {
1218
+ return applyNegativeEvidence(sourceOpinion, targetOpinion, weight);
1219
+ }
1220
+ const discounted = trustDiscount(sourceOpinion, Math.abs(weight));
1221
+ return {
1222
+ opinion: cumulativeFusion(targetOpinion, discounted),
1223
+ operator: "cumulative_fusion",
1224
+ rationale: `Supporting evidence (weight=${weight.toFixed(2)})`
1225
+ };
1226
+ }
1227
+ },
1228
+ depends_on: {
1229
+ direction: "incoming",
1230
+ handler: (source, target, _weight, metadata) => {
1231
+ const sourceOpinion = mkOpinion(source.b, source.d, source.u, source.a);
1232
+ const targetOpinion = mkOpinion(target.b, target.d, target.u, target.a);
1233
+ if (metadata.conditionalA && metadata.conditionalNotA) {
1234
+ return {
1235
+ opinion: conditionalDeduction(
1236
+ sourceOpinion,
1237
+ mkOpinion(
1238
+ metadata.conditionalA.b,
1239
+ metadata.conditionalA.d,
1240
+ metadata.conditionalA.u,
1241
+ metadata.conditionalA.a
1242
+ ),
1243
+ mkOpinion(
1244
+ metadata.conditionalNotA.b,
1245
+ metadata.conditionalNotA.d,
1246
+ metadata.conditionalNotA.u,
1247
+ metadata.conditionalNotA.a
1248
+ ),
1249
+ targetOpinion.a
1250
+ ),
1251
+ operator: "conditional_deduction",
1252
+ rationale: `Conditional deduction: prerequisite at ${project(
1253
+ sourceOpinion
1254
+ ).toFixed(2)}`
1255
+ };
1256
+ }
1257
+ return dampedDependencyCascade(
1258
+ sourceOpinion,
1259
+ targetOpinion,
1260
+ metadata.propagation ?? "continuous"
1261
+ );
1262
+ }
1263
+ },
1264
+ derived_from: {
1265
+ direction: "incoming",
1266
+ handler: (_source, target) => ({
1267
+ opinion: target,
1268
+ operator: "trust_discount",
1269
+ rationale: "Provenance edge \u2014 no confidence propagation"
1270
+ })
1271
+ },
1272
+ contains: {
1273
+ direction: "outgoing",
1274
+ handler: (_source, target) => ({
1275
+ opinion: target,
1276
+ operator: "trust_discount",
1277
+ rationale: "Containment edge \u2014 no confidence propagation"
1278
+ })
1279
+ },
1280
+ tests: {
1281
+ direction: "outgoing",
1282
+ handler: (_source, target) => ({
1283
+ opinion: target,
1284
+ operator: "trust_discount",
1285
+ rationale: "Testing edge \u2014 no confidence propagation"
1286
+ })
1215
1287
  }
1216
- if (operator !== "gte" && operator !== "lte" && operator !== "eq" && operator !== "gt" && operator !== "lt") {
1217
- throw new Error(`Unsupported evidential operator: ${String(operator)}`);
1288
+ };
1289
+ var PROPAGATION_TRAVERSAL_SPECS = Object.entries(EDGE_PROPAGATION_RULES).map(([edgeType, rule]) => ({
1290
+ edgeType,
1291
+ direction: rule.direction
1292
+ }));
1293
+ function isPropagationEdgeType(edgeType) {
1294
+ return edgeType in EDGE_PROPAGATION_RULES;
1295
+ }
1296
+ function getPropagationTraversalSpecs() {
1297
+ return PROPAGATION_TRAVERSAL_SPECS;
1298
+ }
1299
+ function propagateThroughEdge(sourceOpinion, targetOpinion, edgeType, weight = 1, metadata = {}) {
1300
+ const handler = isPropagationEdgeType(edgeType) ? EDGE_PROPAGATION_RULES[edgeType].handler : void 0;
1301
+ if (!handler) {
1302
+ return {
1303
+ opinion: targetOpinion,
1304
+ operator: "no_op",
1305
+ rationale: `Unknown edge type: ${edgeType} \u2014 no propagation`
1306
+ };
1218
1307
  }
1219
- if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
1220
- throw new Error("Evidential contracts require a numeric threshold.");
1308
+ return handler(sourceOpinion, targetOpinion, weight, metadata);
1309
+ }
1310
+ function propagateAllEdges(currentOpinion, incomingEdges) {
1311
+ let result = currentOpinion;
1312
+ const rationales = [];
1313
+ for (const edgeType of ["depends_on", "informs", "supports"]) {
1314
+ for (const incoming of incomingEdges.filter(
1315
+ (edge) => edge.edgeType === edgeType
1316
+ )) {
1317
+ const propagated = propagateThroughEdge(
1318
+ incoming.sourceOpinion,
1319
+ result,
1320
+ incoming.edgeType,
1321
+ incoming.weight,
1322
+ incoming.metadata
1323
+ );
1324
+ result = propagated.opinion;
1325
+ rationales.push(propagated.rationale);
1326
+ }
1221
1327
  }
1222
- const actionParams = isRecord(config.actionParams) ? config.actionParams : void 0;
1223
1328
  return {
1224
- metric,
1225
- operator,
1226
- threshold,
1227
- action: normalizeEvidentialAction(config.action),
1228
- actionParams: actionParams && (typeof actionParams.targetConfidence === "number" || typeof actionParams.rationale === "string") ? {
1229
- targetConfidence: typeof actionParams.targetConfidence === "number" ? actionParams.targetConfidence : void 0,
1230
- rationale: typeof actionParams.rationale === "string" ? actionParams.rationale : void 0
1231
- } : void 0
1329
+ opinion: result,
1330
+ operator: "cumulative_fusion",
1331
+ rationale: rationales.join("; ")
1232
1332
  };
1233
1333
  }
1234
- function compareMetricValue(operator, left, right) {
1235
- switch (operator) {
1236
- case "gte":
1237
- return left >= right;
1238
- case "lte":
1239
- return left <= right;
1240
- case "eq":
1241
- return left === right;
1242
- case "gt":
1243
- return left > right;
1244
- case "lt":
1245
- return left < right;
1246
- default:
1247
- return false;
1248
- }
1334
+
1335
+ // src/v1/operations/bridge/index.ts
1336
+ var DEFAULT_NON_INFORMATIVE_WEIGHT = 2;
1337
+ function clamp012(value) {
1338
+ return Math.max(0, Math.min(1, value));
1249
1339
  }
1250
- function resolveComparisonResult(direction, comparisonSatisfied) {
1251
- return direction === "falsifies" ? comparisonSatisfied ? "disconfirmed" : "confirmed" : comparisonSatisfied ? "confirmed" : "disconfirmed";
1340
+ function clampNonNegative(value) {
1341
+ return Number.isFinite(value) ? Math.max(0, value) : 0;
1252
1342
  }
1253
- function buildComparisonRationale(args) {
1254
- const renderedObserved = args.observedValue === null ? "no data" : `${args.observedValue}${args.unit ? ` ${args.unit}` : ""}`;
1255
- const renderedThreshold = `${args.threshold}${args.unit ? ` ${args.unit}` : ""}`;
1256
- const clause = `${args.label} observed ${renderedObserved} against ${args.operator} ${renderedThreshold}`;
1257
- if (args.observedValue === null) {
1258
- return `${clause}; evaluator returned ${args.result} because no current data was available.`;
1343
+ function normalizeNonInformativeWeight(weight) {
1344
+ if (weight === void 0) {
1345
+ return DEFAULT_NON_INFORMATIVE_WEIGHT;
1259
1346
  }
1260
- return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
1347
+ return Number.isFinite(weight) ? Math.max(0, weight) : DEFAULT_NON_INFORMATIVE_WEIGHT;
1261
1348
  }
1262
- function buildEvidentialRationale(args) {
1263
- const observed = args.snapshot.value === null ? "no data" : String(args.snapshot.value);
1264
- const clause = `${args.snapshot.metric} observed ${observed} against ${args.config.operator} ${args.config.threshold}`;
1265
- if (args.snapshot.value === null) {
1266
- return `${clause}; evidential evaluator treated the comparison as unmet, resulting in ${args.result}.`;
1349
+ function normalizeBaseRateVector(baseRate, size) {
1350
+ if (size === 0) {
1351
+ return [];
1267
1352
  }
1268
- return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
1269
- }
1270
- function parseMetricCheckerConfig(value) {
1271
- if (!isRecord(value)) {
1353
+ if (baseRate.length !== size) {
1272
1354
  throw new Error(
1273
- "metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
1355
+ `Base-rate vector length ${baseRate.length} must match evidence vector length ${size}.`
1274
1356
  );
1275
1357
  }
1276
- const config = value;
1277
- return {
1278
- metric: typeof config.metric === "string" && config.metric.length > 0 ? config.metric : void 0,
1279
- operator: parseComparisonOperator(config.operator, BUILT_IN_METRIC_CHECKER),
1280
- threshold: parseNumericThreshold(config.threshold, BUILT_IN_METRIC_CHECKER),
1281
- observedValue: pickFiniteNumber(config, ["observedValue", "value"]),
1282
- currentValue: pickFiniteNumber(config, ["currentValue"]),
1283
- metricValue: pickFiniteNumber(config, ["metricValue"]),
1284
- unit: typeof config.unit === "string" && config.unit.length > 0 ? config.unit : void 0
1285
- };
1286
- }
1287
- function parseReferenceCheckCounterConfig(value) {
1288
- if (!isRecord(value)) {
1358
+ const normalized = baseRate.map((value) => clampNonNegative(value));
1359
+ const total = normalized.reduce((sum, value) => sum + value, 0);
1360
+ if (total === 0) {
1289
1361
  throw new Error(
1290
- "reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
1362
+ "Base-rate vector must contain at least one positive value."
1291
1363
  );
1292
1364
  }
1293
- const config = value;
1294
- if (typeof config.tag !== "string" || config.tag.trim().length === 0) {
1295
- throw new Error("reference_check_counter requires a non-empty tag.");
1365
+ return normalized.map((value) => value / total);
1366
+ }
1367
+ function opinionFromDirichlet(alpha, nonInformativeWeight, baseRate) {
1368
+ const evidence = alpha.map((value) => clampNonNegative(value));
1369
+ const safeWeight = normalizeNonInformativeWeight(nonInformativeWeight);
1370
+ const normalizedBaseRate = normalizeBaseRateVector(baseRate, evidence.length);
1371
+ const totalEvidence = evidence.reduce((sum, value) => sum + value, 0);
1372
+ const denominator = totalEvidence + safeWeight;
1373
+ if (denominator === 0) {
1374
+ return {
1375
+ b: evidence.map(() => 0),
1376
+ u: 1,
1377
+ a: normalizedBaseRate
1378
+ };
1296
1379
  }
1297
1380
  return {
1298
- tag: config.tag.trim(),
1299
- operator: parseComparisonOperator(
1300
- config.operator,
1301
- BUILT_IN_REFERENCE_CHECK_COUNTER
1302
- ),
1303
- threshold: parseNumericThreshold(
1304
- config.threshold,
1305
- BUILT_IN_REFERENCE_CHECK_COUNTER
1306
- ),
1307
- caseSensitive: config.caseSensitive === true
1381
+ b: evidence.map((value) => value / denominator),
1382
+ u: safeWeight / denominator,
1383
+ a: normalizedBaseRate
1308
1384
  };
1309
1385
  }
1310
- function parseTemporalDeadlineConfig(value) {
1311
- if (!isRecord(value)) {
1312
- return {};
1313
- }
1314
- const config = value;
1386
+ function opinionFromBeta(alpha, beta, nonInformativeWeight, baseRate) {
1387
+ const dirichlet = opinionFromDirichlet([alpha, beta], nonInformativeWeight, [
1388
+ clamp012(baseRate),
1389
+ 1 - clamp012(baseRate)
1390
+ ]);
1391
+ return mkOpinion(
1392
+ dirichlet.b[0] ?? 0,
1393
+ dirichlet.b[1] ?? 0,
1394
+ dirichlet.u,
1395
+ dirichlet.a[0] ?? clamp012(baseRate)
1396
+ );
1397
+ }
1398
+
1399
+ // src/v1/operations/dynamics/revision.ts
1400
+ function clamp013(value) {
1401
+ return Math.max(0, Math.min(1, value));
1402
+ }
1403
+ function toEvidence(probability, weight) {
1404
+ const safeProbability = clamp013(probability);
1405
+ const safeWeight = Number.isFinite(weight) ? Math.max(0, weight) : 0;
1315
1406
  return {
1316
- label: typeof config.label === "string" && config.label.length > 0 ? config.label : void 0,
1317
- completed: config.completed === true,
1318
- completedAt: pickFiniteNumber(config, ["completedAt"]),
1319
- observedAt: pickFiniteNumber(config, ["observedAt"]),
1320
- satisfiedAt: pickFiniteNumber(config, ["satisfiedAt"]),
1321
- achievedAt: pickFiniteNumber(config, ["achievedAt"])
1407
+ alpha: safeProbability * safeWeight,
1408
+ beta: (1 - safeProbability) * safeWeight
1322
1409
  };
1323
1410
  }
1324
- function parseMarketIndexComparatorConfig(value) {
1325
- if (!isRecord(value)) {
1326
- throw new Error(
1327
- "market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
1328
- );
1411
+ function bayesianUpdate(priorConfidence, priorWeight, newAssessment, newWeight, options) {
1412
+ return reviseConfidence({
1413
+ priorConfidence,
1414
+ priorWeight,
1415
+ newAssessment,
1416
+ newWeight,
1417
+ baseRate: options?.baseRate,
1418
+ nonInformativeWeight: options?.nonInformativeWeight
1419
+ });
1420
+ }
1421
+ function reviseConfidence(args) {
1422
+ return project(reviseConfidenceOpinion(args));
1423
+ }
1424
+ function reviseConfidenceOpinion(args) {
1425
+ const priorEvidence = toEvidence(args.priorConfidence, args.priorWeight);
1426
+ const newEvidence = toEvidence(args.newAssessment, args.newWeight ?? 1);
1427
+ return opinionFromBeta(
1428
+ priorEvidence.alpha + newEvidence.alpha,
1429
+ priorEvidence.beta + newEvidence.beta,
1430
+ args.nonInformativeWeight ?? DEFAULT_NON_INFORMATIVE_WEIGHT,
1431
+ args.baseRate
1432
+ );
1433
+ }
1434
+ function toEpochMs(value) {
1435
+ if (typeof value === "number" && Number.isFinite(value)) {
1436
+ return value;
1329
1437
  }
1330
- const config = value;
1331
- return {
1332
- subject: typeof config.subject === "string" && config.subject.length > 0 ? config.subject : void 0,
1333
- subjectValue: pickFiniteNumber(config, ["subjectValue", "leftValue"]),
1334
- primaryValue: pickFiniteNumber(config, ["primaryValue"]),
1335
- benchmark: typeof config.benchmark === "string" && config.benchmark.length > 0 ? config.benchmark : void 0,
1336
- benchmarkValue: pickFiniteNumber(config, ["benchmarkValue", "rightValue"]),
1337
- comparisonValue: pickFiniteNumber(config, ["comparisonValue"]),
1338
- operator: parseComparisonOperator(
1339
- config.operator,
1340
- BUILT_IN_MARKET_INDEX_COMPARATOR
1438
+ if (value instanceof Date) {
1439
+ const epochMs = value.getTime();
1440
+ return Number.isFinite(epochMs) ? epochMs : void 0;
1441
+ }
1442
+ return;
1443
+ }
1444
+ function normalizeHalfLifeMs(halfLifeMs) {
1445
+ if (halfLifeMs === void 0 || !Number.isFinite(halfLifeMs)) {
1446
+ return 0;
1447
+ }
1448
+ return Math.max(0, halfLifeMs);
1449
+ }
1450
+ function temporalDecay(sourceOpinion, now, decayParams) {
1451
+ const halfLifeMs = normalizeHalfLifeMs(decayParams.halfLifeMs);
1452
+ if (halfLifeMs === 0) {
1453
+ return { ...sourceOpinion };
1454
+ }
1455
+ const nowMs = toEpochMs(now);
1456
+ const referenceTimeMs = toEpochMs(decayParams.referenceTime);
1457
+ if (nowMs === void 0 || referenceTimeMs === void 0) {
1458
+ return { ...sourceOpinion };
1459
+ }
1460
+ const ageMs = Math.max(0, nowMs - referenceTimeMs);
1461
+ if (ageMs === 0) {
1462
+ return { ...sourceOpinion };
1463
+ }
1464
+ const retainedEvidenceWeight = 0.5 ** (ageMs / halfLifeMs);
1465
+ return trustDiscount(
1466
+ mkOpinion(
1467
+ sourceOpinion.b,
1468
+ sourceOpinion.d,
1469
+ sourceOpinion.u,
1470
+ sourceOpinion.a
1341
1471
  ),
1342
- threshold: parseNumericThreshold(
1343
- config.threshold,
1344
- BUILT_IN_MARKET_INDEX_COMPARATOR
1345
- )
1346
- };
1472
+ retainedEvidenceWeight
1473
+ );
1347
1474
  }
1348
1475
 
1349
1476
  // src/v1/operations/lucern.ts