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