@lucern/graph-primitives 0.3.0-alpha.0 → 0.3.0-alpha.1

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 (76) hide show
  1. package/dist/beliefDecay.js +37 -1104
  2. package/dist/beliefDecay.js.map +1 -1
  3. package/dist/beliefEvidenceLinks.js +53 -834
  4. package/dist/beliefEvidenceLinks.js.map +1 -1
  5. package/dist/confidencePropagationDispatch.d.ts +3 -3
  6. package/dist/confidencePropagationDispatch.js +30 -308
  7. package/dist/confidencePropagationDispatch.js.map +1 -1
  8. package/dist/contradictions.js +5 -797
  9. package/dist/contradictions.js.map +1 -1
  10. package/dist/edges/contradicts.js +1 -122
  11. package/dist/edges/contradicts.js.map +1 -1
  12. package/dist/edges/dependsOn.js +14 -172
  13. package/dist/edges/dependsOn.js.map +1 -1
  14. package/dist/edges/elaborates.js +1 -49
  15. package/dist/edges/elaborates.js.map +1 -1
  16. package/dist/edges/index.js +14 -277
  17. package/dist/edges/index.js.map +1 -1
  18. package/dist/edges/informs.js +1 -62
  19. package/dist/edges/informs.js.map +1 -1
  20. package/dist/edges/propagationTypes.d.ts +2 -2
  21. package/dist/edges/propagationTypes.js.map +1 -1
  22. package/dist/edges/refutes.js +1 -62
  23. package/dist/edges/refutes.js.map +1 -1
  24. package/dist/edges/supports.js +1 -122
  25. package/dist/edges/supports.js.map +1 -1
  26. package/dist/edges/utils.d.ts +6 -6
  27. package/dist/edges/utils.js +1 -130
  28. package/dist/edges/utils.js.map +1 -1
  29. package/dist/entityBridge.js +2 -17
  30. package/dist/entityBridge.js.map +1 -1
  31. package/dist/entityLifecycle.js +62 -848
  32. package/dist/entityLifecycle.js.map +1 -1
  33. package/dist/epistemicAnswers.js +6 -802
  34. package/dist/epistemicAnswers.js.map +1 -1
  35. package/dist/epistemicBeliefs.js +125 -1594
  36. package/dist/epistemicBeliefs.js.map +1 -1
  37. package/dist/epistemicContractHelpers.js +1 -318
  38. package/dist/epistemicContractHelpers.js.map +1 -1
  39. package/dist/epistemicContracts.js +129 -1874
  40. package/dist/epistemicContracts.js.map +1 -1
  41. package/dist/epistemicEdges.js +60 -863
  42. package/dist/epistemicEdges.js.map +1 -1
  43. package/dist/epistemicEvidence.js +69 -1041
  44. package/dist/epistemicEvidence.js.map +1 -1
  45. package/dist/epistemicLinking.js +2 -785
  46. package/dist/epistemicLinking.js.map +1 -1
  47. package/dist/epistemicNodes.js +9 -866
  48. package/dist/epistemicNodes.js.map +1 -1
  49. package/dist/epistemicQuestions.js +66 -1071
  50. package/dist/epistemicQuestions.js.map +1 -1
  51. package/dist/epistemicSources.js +23 -880
  52. package/dist/epistemicSources.js.map +1 -1
  53. package/dist/evaluators/index.js +129 -1874
  54. package/dist/evaluators/index.js.map +1 -1
  55. package/dist/index.js +182 -2744
  56. package/dist/index.js.map +1 -1
  57. package/dist/ontology-matching.js +1 -344
  58. package/dist/ontology-matching.js.map +1 -1
  59. package/dist/ontologyApproval.js +1 -13
  60. package/dist/ontologyApproval.js.map +1 -1
  61. package/dist/ontologyDefinitions.js +2 -17
  62. package/dist/ontologyDefinitions.js.map +1 -1
  63. package/dist/ontologyRegistry.js +2 -17
  64. package/dist/ontologyRegistry.js.map +1 -1
  65. package/dist/projectionReconciliation.js +2 -17
  66. package/dist/projectionReconciliation.js.map +1 -1
  67. package/dist/questionEvidenceLinks.js +60 -841
  68. package/dist/questionEvidenceLinks.js.map +1 -1
  69. package/dist/text-matching.js +1 -244
  70. package/dist/text-matching.js.map +1 -1
  71. package/dist/workflowBridge.d.ts +27 -0
  72. package/dist/workflowBridge.js +303 -0
  73. package/dist/workflowBridge.js.map +1 -0
  74. package/dist/workspaceIsolation.js +2 -52
  75. package/dist/workspaceIsolation.js.map +1 -1
  76. package/package.json +6 -5
package/dist/index.js CHANGED
@@ -1,5 +1,15 @@
1
1
  import { v } from 'convex/values';
2
+ import { getRescoringSchedule, normalizeTupleContradictionPolicy, mkOpinion, createInheritedContractRecord, confidenceFromSL, conditionalDeduction, project, dampedDependencyCascade, hasProjectedOpinionChanged, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, deriveContractModulationPlan, deriveContractStatus, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, parseEvidentialEvaluatorConfig, compareMetricValue, buildEvidentialRationale, parseMetricCheckerConfig, getEvaluatorInputRecord, pickFiniteNumber, resolveComparisonResult, buildComparisonRationale, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, parseMarketIndexComparatorConfig, computeEffectiveDecay, computeDeadlineUrgency, computeBaseDecay, bayesianUpdate, DECAY_TIERS, DEADLINE_URGENCY } from '@lucern/confidence';
3
+ import { getAccessibleProjectIds, checkProjectAccess, requireProjectAccess, checkScopeAccess } from '@lucern/access-control/access';
4
+ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
2
5
  import { componentsGeneric, queryGeneric, mutationGeneric, anyApi, internalMutationGeneric, internalQueryGeneric, internalActionGeneric } from 'convex/server';
6
+ import { getCurrentUserId } from '@lucern/access-control/auth';
7
+ import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
8
+ import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
9
+ import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
10
+ import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
11
+ import { scoreEntityTypeMatch, scoreEntityConnection, rankEntityTypeMatches, rankEntityConnections } from '@lucern/contracts/v1/ontologies/v1';
12
+ import { wordTokenize, wordOverlapScore, tokenizeSearchText, tokenOverlapScore, stemToken, scoreLexicalSignals, scoreLexicalSignal, rerankLexicalWindow, rankWindowScore, prepareLexicalQuery, jaccardSimilarity, bigramTokenize } from '@lucern/contracts/text-matching.contract';
3
13
 
4
14
  var __defProp = Object.defineProperty;
5
15
  var __export = (target, all) => {
@@ -21,1867 +31,7 @@ __export(beliefDecay_exports, {
21
31
  getRescoringSchedule: () => getRescoringSchedule,
22
32
  identifyBeliefsNeedingRescore: () => identifyBeliefsNeedingRescore
23
33
  });
24
-
25
- // ../confidence/src/v1/operations/subjectiveLogic/index.ts
26
- function opinion(belief, disbelief, uncertainty, baseRate = 0.5) {
27
- const b = Math.max(0, Math.min(1, belief));
28
- const d = Math.max(0, Math.min(1, disbelief));
29
- const u = Math.max(0, Math.min(1, uncertainty));
30
- const a = Math.max(0, Math.min(1, baseRate));
31
- const sum = b + d + u;
32
- if (sum === 0) {
33
- return { b: 0, d: 0, u: 1, a };
34
- }
35
- return {
36
- b: b / sum,
37
- d: d / sum,
38
- u: u / sum,
39
- a
40
- };
41
- }
42
- function vacuous(baseRate = 0.5) {
43
- return { b: 0, d: 0, u: 1, a: baseRate };
44
- }
45
- function project(o) {
46
- return o.b + o.a * o.u;
47
- }
48
- function cumulativeFusion(left, right) {
49
- if (left.u === 0 && right.u === 0) {
50
- return opinion(
51
- (left.b + right.b) / 2,
52
- (left.d + right.d) / 2,
53
- 0,
54
- (left.a + right.a) / 2
55
- );
56
- }
57
- const k = left.u + right.u - left.u * right.u;
58
- if (k === 0) {
59
- return vacuous((left.a + right.a) / 2);
60
- }
61
- return opinion(
62
- (left.b * right.u + right.b * left.u) / k,
63
- (left.d * right.u + right.d * left.u) / k,
64
- left.u * right.u / k,
65
- (left.a + right.a) / 2
66
- );
67
- }
68
- function trustDiscount(sourceOpinion, trust) {
69
- const weight = Math.max(0, Math.min(1, Math.abs(trust)));
70
- return opinion(
71
- weight * sourceOpinion.b,
72
- weight * sourceOpinion.d,
73
- 1 - weight * (sourceOpinion.b + sourceOpinion.d),
74
- sourceOpinion.a
75
- );
76
- }
77
- var EPSILON = 1e-9;
78
- function childBaseRateFallback(ifTrue, ifFalse, fallbackBaseRate) {
79
- if (fallbackBaseRate !== void 0) {
80
- return Math.max(0, Math.min(1, fallbackBaseRate));
81
- }
82
- if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {
83
- return ifTrue.a;
84
- }
85
- return (ifTrue.a + ifFalse.a) / 2;
86
- }
87
- function computeConditionalDeductionBaseRate(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
88
- const denominator = 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;
89
- if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {
90
- const baseRate = (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;
91
- if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {
92
- return Math.max(0, Math.min(1, baseRate));
93
- }
94
- }
95
- return fallbackBaseRate;
96
- }
97
- function safeCorrectionTerm(numerator, denominator) {
98
- if (Math.abs(denominator) <= EPSILON) {
99
- return void 0;
100
- }
101
- const value = numerator / denominator;
102
- if (!Number.isFinite(value)) {
103
- return void 0;
104
- }
105
- return Math.max(0, value);
106
- }
107
- function conditionalDeduction(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
108
- const fallbackChildBaseRate = childBaseRateFallback(
109
- ifTrue,
110
- ifFalse,
111
- fallbackBaseRate
112
- );
113
- const childBaseRate = computeConditionalDeductionBaseRate(
114
- opinionA,
115
- ifTrue,
116
- ifFalse,
117
- fallbackChildBaseRate
118
- );
119
- const projectedAntecedent = project(opinionA);
120
- const projectedAntecedentComplement = 1 - projectedAntecedent;
121
- const intermediateBelief = opinionA.b * ifTrue.b + opinionA.d * ifFalse.b + opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));
122
- const intermediateDisbelief = opinionA.b * ifTrue.d + opinionA.d * ifFalse.d + opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));
123
- const intermediateUncertainty = opinionA.b * ifTrue.u + opinionA.d * ifFalse.u + opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
124
- const projectedVacuousDeduction = ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a) + childBaseRate * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
125
- const projectedConditionalA = ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);
126
- let correction = 0;
127
- if (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d || ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d) {
128
- correction = 0;
129
- } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {
130
- const beliefGap = ifTrue.b - ifFalse.b;
131
- const disbeliefGap = ifFalse.d - ifTrue.d;
132
- if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
133
- correction = safeCorrectionTerm(
134
- opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),
135
- projectedAntecedent * childBaseRate
136
- ) ?? 0;
137
- } else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
138
- correction = safeCorrectionTerm(
139
- opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
140
- projectedAntecedentComplement * childBaseRate * disbeliefGap
141
- ) ?? 0;
142
- } else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
143
- correction = safeCorrectionTerm(
144
- (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
145
- projectedAntecedent * (1 - childBaseRate) * beliefGap
146
- ) ?? 0;
147
- } else {
148
- correction = safeCorrectionTerm(
149
- (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),
150
- projectedAntecedentComplement * (1 - childBaseRate)
151
- ) ?? 0;
152
- }
153
- } else {
154
- const beliefGap = ifFalse.b - ifTrue.b;
155
- const disbeliefGap = ifTrue.d - ifFalse.d;
156
- if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
157
- correction = safeCorrectionTerm(
158
- (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
159
- projectedAntecedent * childBaseRate * disbeliefGap
160
- ) ?? 0;
161
- } else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
162
- correction = safeCorrectionTerm(
163
- (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),
164
- projectedAntecedentComplement * childBaseRate
165
- ) ?? 0;
166
- } else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
167
- correction = safeCorrectionTerm(
168
- opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),
169
- projectedAntecedent * (1 - childBaseRate)
170
- ) ?? 0;
171
- } else {
172
- correction = safeCorrectionTerm(
173
- opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
174
- projectedAntecedentComplement * (1 - childBaseRate) * beliefGap
175
- ) ?? 0;
176
- }
177
- }
178
- return opinion(
179
- intermediateBelief - childBaseRate * correction,
180
- intermediateDisbelief - (1 - childBaseRate) * correction,
181
- intermediateUncertainty + correction,
182
- childBaseRate
183
- );
184
- }
185
- function negate(o) {
186
- return { b: o.d, d: o.b, u: o.u, a: 1 - o.a };
187
- }
188
- function constraintFusion(left, right, mode = "pressure") {
189
- if (mode === "redistribute") {
190
- const leftProjected = project(left);
191
- const rightProjected = project(right);
192
- const total = leftProjected + rightProjected;
193
- if (total <= 1) {
194
- return { o1: left, o2: right };
195
- }
196
- const scale = 1 / total;
197
- return {
198
- o1: opinion(
199
- left.b * scale,
200
- left.d + left.b * (1 - scale),
201
- left.u,
202
- left.a
203
- ),
204
- o2: opinion(
205
- right.b * scale,
206
- right.d + right.b * (1 - scale),
207
- right.u,
208
- right.a
209
- )
210
- };
211
- }
212
- const pressureLeft = right.b * 0.5;
213
- const pressureRight = left.b * 0.5;
214
- return {
215
- o1: opinion(
216
- left.b - pressureLeft * 0.3,
217
- left.d + pressureLeft * 0.3,
218
- left.u,
219
- left.a
220
- ),
221
- o2: opinion(
222
- right.b - pressureRight * 0.3,
223
- right.d + pressureRight * 0.3,
224
- right.u,
225
- right.a
226
- )
227
- };
228
- }
229
-
230
- // ../confidence/src/v1/operations/bridge/index.ts
231
- var DEFAULT_NON_INFORMATIVE_WEIGHT = 2;
232
- function clamp01(value) {
233
- return Math.max(0, Math.min(1, value));
234
- }
235
- function clampNonNegative(value) {
236
- return Number.isFinite(value) ? Math.max(0, value) : 0;
237
- }
238
- function normalizeNonInformativeWeight(weight) {
239
- if (weight === void 0) {
240
- return DEFAULT_NON_INFORMATIVE_WEIGHT;
241
- }
242
- return Number.isFinite(weight) ? Math.max(0, weight) : DEFAULT_NON_INFORMATIVE_WEIGHT;
243
- }
244
- function normalizeBaseRateVector(baseRate, size) {
245
- if (size === 0) {
246
- return [];
247
- }
248
- const fallback = Array.from({ length: size }, () => 1 / size);
249
- if (!baseRate) {
250
- return fallback;
251
- }
252
- if (baseRate.length !== size) {
253
- throw new Error(
254
- `Base-rate vector length ${baseRate.length} must match evidence vector length ${size}.`
255
- );
256
- }
257
- const normalized = baseRate.map((value) => clampNonNegative(value));
258
- const total = normalized.reduce((sum, value) => sum + value, 0);
259
- if (total === 0) {
260
- return fallback;
261
- }
262
- return normalized.map((value) => value / total);
263
- }
264
- function opinionFromDirichlet(alpha, nonInformativeWeight = DEFAULT_NON_INFORMATIVE_WEIGHT, baseRate) {
265
- const evidence = alpha.map((value) => clampNonNegative(value));
266
- const safeWeight = normalizeNonInformativeWeight(nonInformativeWeight);
267
- const normalizedBaseRate = normalizeBaseRateVector(baseRate, evidence.length);
268
- const totalEvidence = evidence.reduce((sum, value) => sum + value, 0);
269
- const denominator = totalEvidence + safeWeight;
270
- if (denominator === 0) {
271
- return {
272
- b: evidence.map(() => 0),
273
- u: 1,
274
- a: normalizedBaseRate
275
- };
276
- }
277
- return {
278
- b: evidence.map((value) => value / denominator),
279
- u: safeWeight / denominator,
280
- a: normalizedBaseRate
281
- };
282
- }
283
- function opinionFromBeta(alpha, beta, nonInformativeWeight = DEFAULT_NON_INFORMATIVE_WEIGHT, baseRate = 0.5) {
284
- const dirichlet = opinionFromDirichlet(
285
- [alpha, beta],
286
- nonInformativeWeight,
287
- [clamp01(baseRate), 1 - clamp01(baseRate)]
288
- );
289
- return {
290
- b: dirichlet.b[0] ?? 0,
291
- d: dirichlet.b[1] ?? 0,
292
- u: dirichlet.u,
293
- a: dirichlet.a[0] ?? clamp01(baseRate)
294
- };
295
- }
296
-
297
- // ../confidence/src/v1/operations/scoring.ts
298
- function finiteNumber(value) {
299
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
300
- }
301
- function clamp012(value) {
302
- return Math.max(0, Math.min(1, value));
303
- }
304
- function confidenceFromOpinion(opinion2) {
305
- return clamp012(opinion2.b + opinion2.a * opinion2.u);
306
- }
307
- function confidenceFromSL(belief, _disbelief, uncertainty, baseRate = 0.5) {
308
- return confidenceFromOpinion({
309
- b: belief,
310
- u: uncertainty,
311
- a: baseRate
312
- });
313
- }
314
- function readOpinionFromRecord(source, fallback = {}) {
315
- const record = source && typeof source === "object" ? source : {};
316
- return {
317
- b: finiteNumber(record.b) ?? finiteNumber(record.belief) ?? finiteNumber(record.slBelief) ?? finiteNumber(record.opinion_b) ?? fallback.b ?? 0,
318
- d: finiteNumber(record.d) ?? finiteNumber(record.disbelief) ?? finiteNumber(record.slDisbelief) ?? finiteNumber(record.opinion_d) ?? fallback.d ?? 0,
319
- u: finiteNumber(record.u) ?? finiteNumber(record.uncertainty) ?? finiteNumber(record.slUncertainty) ?? finiteNumber(record.opinion_u) ?? fallback.u ?? 1,
320
- a: finiteNumber(record.a) ?? finiteNumber(record.baseRate) ?? finiteNumber(record.slBaseRate) ?? finiteNumber(record.opinion_a) ?? fallback.a ?? 0.5
321
- };
322
- }
323
- function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
324
- return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
325
- }
326
-
327
- // ../confidence/src/v1/operations/contradiction/detectTupleContradiction.ts
328
- var DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD = 0.7;
329
- var DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD = 0.7;
330
- function normalizeTupleContradictionPolicy(policy = {}) {
331
- return {
332
- beliefThreshold: clamp012(
333
- policy.beliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD
334
- ),
335
- disbeliefThreshold: clamp012(
336
- policy.disbeliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD
337
- )
338
- };
339
- }
340
- function detectTupleContradiction(opinion2, tauB = DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, tauD = DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD) {
341
- return opinion2.b > tauB && opinion2.d > tauD;
342
- }
343
- function evaluateTupleContradictionTransition(args) {
344
- const policy = normalizeTupleContradictionPolicy(args.policy);
345
- const tupleContradicted = detectTupleContradiction(
346
- args.opinion,
347
- policy.beliefThreshold,
348
- policy.disbeliefThreshold
349
- );
350
- const previousTupleContradicted = Boolean(args.previousTupleContradicted);
351
- return {
352
- tupleContradicted,
353
- crossedIntoTupleContradiction: !previousTupleContradicted && tupleContradicted,
354
- crossedOutOfTupleContradiction: previousTupleContradicted && !tupleContradicted,
355
- policy
356
- };
357
- }
358
-
359
- // ../confidence/src/v1/operations/dynamics/cascade.ts
360
- function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
361
- const dependencyProjection = project(dependencyOpinion);
362
- if (mode === "threshold") {
363
- if (dependencyProjection < threshold) {
364
- return opinion(
365
- 0,
366
- beliefOpinion.d + beliefOpinion.b * 0.5,
367
- 0.5,
368
- beliefOpinion.a
369
- );
370
- }
371
- return beliefOpinion;
372
- }
373
- const dampingFactor = Math.pow(dependencyProjection, 0.5);
374
- return opinion(
375
- beliefOpinion.b * dampingFactor,
376
- beliefOpinion.d + beliefOpinion.b * (1 - dampingFactor) * 0.3,
377
- beliefOpinion.u + beliefOpinion.b * (1 - dampingFactor) * 0.7,
378
- beliefOpinion.a
379
- );
380
- }
381
- function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "continuous") {
382
- return {
383
- opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
384
- operator: "dependency_cascade",
385
- rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
386
- dependencyOpinion
387
- ).toFixed(2)}`
388
- };
389
- }
390
-
391
- // ../confidence/src/v1/operations/dynamics/defeat.ts
392
- function applyNegativeSupport(source, target, weight, metadata = {}) {
393
- if (metadata.constraint === "xor") {
394
- const result = constraintFusion(
395
- source,
396
- target,
397
- metadata.normalization ?? "pressure"
398
- );
399
- return {
400
- opinion: result.o2,
401
- operator: "constraint_fusion",
402
- rationale: `XOR constraint: source belief at ${project(source).toFixed(
403
- 2
404
- )} pressures target`
405
- };
406
- }
407
- const discounted = trustDiscount(negate(source), Math.abs(weight));
408
- return {
409
- opinion: cumulativeFusion(target, discounted),
410
- operator: "cumulative_fusion",
411
- rationale: `Contradicting evidence (weight=${weight.toFixed(
412
- 2
413
- )}) from source at ${project(source).toFixed(2)}`
414
- };
415
- }
416
- function applyNegativeEvidence(source, target, weight) {
417
- const discounted = trustDiscount(negate(source), Math.abs(weight));
418
- return {
419
- opinion: cumulativeFusion(target, discounted),
420
- operator: "cumulative_fusion",
421
- rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
422
- };
423
- }
424
-
425
- // ../confidence/src/v1/operations/dynamics/revision.ts
426
- function clamp013(value) {
427
- return Math.max(0, Math.min(1, value));
428
- }
429
- function toEvidence(probability, weight) {
430
- const safeProbability = clamp013(probability);
431
- const safeWeight = Number.isFinite(weight) ? Math.max(0, weight) : 0;
432
- return {
433
- alpha: safeProbability * safeWeight,
434
- beta: (1 - safeProbability) * safeWeight
435
- };
436
- }
437
- function bayesianUpdate(priorConfidence, priorWeight, newAssessment, newWeight, options) {
438
- return reviseConfidence({
439
- priorConfidence,
440
- priorWeight,
441
- newAssessment,
442
- newWeight,
443
- baseRate: options?.baseRate,
444
- nonInformativeWeight: options?.nonInformativeWeight
445
- });
446
- }
447
- function reviseConfidence(args) {
448
- return project(reviseConfidenceOpinion(args));
449
- }
450
- function reviseConfidenceOpinion(args) {
451
- const priorEvidence = toEvidence(args.priorConfidence, args.priorWeight);
452
- const newEvidence = toEvidence(args.newAssessment, args.newWeight ?? 1);
453
- return opinionFromBeta(
454
- priorEvidence.alpha + newEvidence.alpha,
455
- priorEvidence.beta + newEvidence.beta,
456
- args.nonInformativeWeight ?? DEFAULT_NON_INFORMATIVE_WEIGHT,
457
- args.baseRate ?? 0.5
458
- );
459
- }
460
-
461
- // ../confidence/src/v1/operations/dynamics/decay.ts
462
- var DECAY_TIERS = {
463
- FRESH: {
464
- maxAgeDays: 30,
465
- weight: 1,
466
- label: "fresh",
467
- action: "Full confidence \u2014 recently validated",
468
- rescoreInDays: 30
469
- },
470
- AGING: {
471
- maxAgeDays: 90,
472
- weight: 0.8,
473
- label: "aging",
474
- action: "Evidence refresh recommended",
475
- rescoreInDays: 14
476
- },
477
- STALE: {
478
- maxAgeDays: 180,
479
- weight: 0.5,
480
- label: "stale",
481
- action: "Evidence update required before trusting",
482
- rescoreInDays: 7
483
- },
484
- EXPIRED: {
485
- maxAgeDays: Number.POSITIVE_INFINITY,
486
- weight: 0.2,
487
- label: "expired",
488
- action: "Full re-evaluation needed",
489
- rescoreInDays: 0
490
- }
491
- };
492
- var DEADLINE_URGENCY = {
493
- DISTANT: {
494
- minDaysToDeadline: 365,
495
- urgencyMultiplier: 1,
496
- label: "distant",
497
- rescoreIntervalDays: 90,
498
- action: "Quarterly confidence check"
499
- },
500
- APPROACHING: {
501
- minDaysToDeadline: 180,
502
- urgencyMultiplier: 0.9,
503
- label: "approaching",
504
- rescoreIntervalDays: 30,
505
- action: "Monthly confidence check \u2014 conditions may be shifting"
506
- },
507
- NEAR: {
508
- minDaysToDeadline: 90,
509
- urgencyMultiplier: 0.75,
510
- label: "near",
511
- rescoreIntervalDays: 14,
512
- action: "Biweekly rescore \u2014 deadline within 3 months"
513
- },
514
- IMMINENT: {
515
- minDaysToDeadline: 30,
516
- urgencyMultiplier: 0.6,
517
- label: "imminent",
518
- rescoreIntervalDays: 7,
519
- action: "Weekly rescore \u2014 deadline within 1 month"
520
- },
521
- CRITICAL: {
522
- minDaysToDeadline: 7,
523
- urgencyMultiplier: 0.4,
524
- label: "critical",
525
- rescoreIntervalDays: 1,
526
- action: "Daily rescore \u2014 deadline THIS WEEK"
527
- },
528
- OVERDUE: {
529
- minDaysToDeadline: Number.NEGATIVE_INFINITY,
530
- urgencyMultiplier: 0.2,
531
- label: "overdue",
532
- rescoreIntervalDays: 0,
533
- action: "OVERDUE \u2014 must validate or archive immediately"
534
- }
535
- };
536
- function normalizeBeliefConfidence(confidence) {
537
- if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
538
- return null;
539
- }
540
- if (confidence >= 0 && confidence <= 1) {
541
- return confidence;
542
- }
543
- if (confidence > 1 && confidence <= 100) {
544
- return confidence / 100;
545
- }
546
- return null;
547
- }
548
- function hasResolvedPredictionOutcome(predictionMeta) {
549
- if (!predictionMeta || typeof predictionMeta !== "object") {
550
- return false;
551
- }
552
- const outcome = predictionMeta.outcome;
553
- return outcome === "confirmed" || outcome === "disconfirmed" || outcome === "partial" || outcome === "expired";
554
- }
555
- function resolveLifecycleBucket(args) {
556
- if (normalizeBeliefConfidence(args.confidence) === 0 || normalizeBeliefConfidence(args.confidence) === 1 || hasResolvedPredictionOutcome(args.predictionMeta)) {
557
- return "fact";
558
- }
559
- if (args.beliefStatus === "assumption" || args.beliefStatus === "hypothesis" || args.beliefStatus === "belief" || args.beliefStatus === "fact") {
560
- if (normalizeBeliefConfidence(args.confidence) !== null && (args.beliefStatus === "assumption" || args.beliefStatus === "hypothesis")) {
561
- return "belief";
562
- }
563
- return args.beliefStatus;
564
- }
565
- return "assumption";
566
- }
567
- function lifecycleMultiplier(status) {
568
- if (status === "assumption") {
569
- return 0.65;
570
- }
571
- if (status === "hypothesis") {
572
- return 0.8;
573
- }
574
- return 1;
575
- }
576
- function computeBaseDecay(lastScoredAt) {
577
- const ageDays = (Date.now() - lastScoredAt) / (1e3 * 60 * 60 * 24);
578
- let tier = DECAY_TIERS.EXPIRED;
579
- if (ageDays <= DECAY_TIERS.FRESH.maxAgeDays) {
580
- tier = DECAY_TIERS.FRESH;
581
- } else if (ageDays <= DECAY_TIERS.AGING.maxAgeDays) {
582
- tier = DECAY_TIERS.AGING;
583
- } else if (ageDays <= DECAY_TIERS.STALE.maxAgeDays) {
584
- tier = DECAY_TIERS.STALE;
585
- }
586
- return { ageDays, tier, weight: tier.weight };
587
- }
588
- function computeDeadlineUrgency(expectedBy) {
589
- if (!expectedBy) {
590
- return null;
591
- }
592
- const daysToDeadline = (expectedBy - Date.now()) / (1e3 * 60 * 60 * 24);
593
- let urgencyTier = DEADLINE_URGENCY.DISTANT;
594
- if (daysToDeadline < 0) {
595
- urgencyTier = DEADLINE_URGENCY.OVERDUE;
596
- } else if (daysToDeadline <= 7) {
597
- urgencyTier = DEADLINE_URGENCY.CRITICAL;
598
- } else if (daysToDeadline <= 30) {
599
- urgencyTier = DEADLINE_URGENCY.IMMINENT;
600
- } else if (daysToDeadline <= 90) {
601
- urgencyTier = DEADLINE_URGENCY.NEAR;
602
- } else if (daysToDeadline <= 180) {
603
- urgencyTier = DEADLINE_URGENCY.APPROACHING;
604
- }
605
- return {
606
- daysToDeadline: Math.round(daysToDeadline),
607
- urgencyTier,
608
- urgencyMultiplier: urgencyTier.urgencyMultiplier,
609
- isOverdue: daysToDeadline < 0
610
- };
611
- }
612
- function computeEffectiveDecay(lastScoredAt, expectedBy, beliefStatus) {
613
- const base = computeBaseDecay(lastScoredAt);
614
- const urgency = computeDeadlineUrgency(expectedBy);
615
- const effectiveWeight = (urgency ? base.weight * urgency.urgencyMultiplier : base.weight) * lifecycleMultiplier(beliefStatus);
616
- const urgencyRescoreDays = urgency?.urgencyTier.rescoreIntervalDays ?? Number.POSITIVE_INFINITY;
617
- const rescoreInDays = Math.min(base.tier.rescoreInDays, urgencyRescoreDays);
618
- const rescoreByDate = lastScoredAt + rescoreInDays * 24 * 60 * 60 * 1e3;
619
- let action = base.tier.action;
620
- if (urgency && urgency.urgencyTier.label !== "distant") {
621
- action = `${urgency.urgencyTier.action}. ${base.tier.action}`;
622
- }
623
- return {
624
- ageDays: base.ageDays,
625
- baseTier: base.tier,
626
- baseWeight: base.weight,
627
- urgency,
628
- effectiveWeight: Math.max(0, Math.min(1, effectiveWeight)),
629
- rescoreByDate,
630
- rescoreInDays,
631
- action
632
- };
633
- }
634
- function getRescoringSchedule(opts) {
635
- const lifecycleStatus = resolveLifecycleBucket({
636
- beliefStatus: opts.beliefStatus,
637
- confidence: opts.confidence,
638
- predictionMeta: opts.predictionMeta
639
- });
640
- const decayState = computeEffectiveDecay(
641
- opts.lastScoredAt,
642
- opts.expectedBy,
643
- lifecycleStatus
644
- );
645
- const daysUntilRescore = (decayState.rescoreByDate - Date.now()) / (1e3 * 60 * 60 * 24);
646
- const isOverdue = daysUntilRescore < 0;
647
- let priority;
648
- let reason;
649
- if (isOverdue && lifecycleStatus === "assumption") {
650
- priority = "critical";
651
- reason = `Untested assumption is stale (${Math.round(decayState.ageDays)}d) \u2014 validate or supersede`;
652
- } else if (isOverdue && lifecycleStatus === "hypothesis" || lifecycleStatus === "hypothesis" && daysUntilRescore < 7) {
653
- priority = "high";
654
- reason = `Hypothesis aging without validation (${Math.round(decayState.ageDays)}d) \u2014 run/finish sprint testing`;
655
- } else if (decayState.urgency?.isOverdue) {
656
- priority = "critical";
657
- reason = `Prediction deadline passed ${Math.abs(decayState.urgency.daysToDeadline)}d ago \u2014 validate or archive`;
658
- } else if (isOverdue && decayState.baseTier.label === "expired") {
659
- priority = "critical";
660
- reason = `Not scored in ${Math.round(decayState.ageDays)}d \u2014 confidence severely degraded`;
661
- } else if (isOverdue && decayState.baseTier.label === "stale") {
662
- priority = "high";
663
- reason = `Stale (${Math.round(decayState.ageDays)}d since scoring) \u2014 evidence update required`;
664
- } else if (decayState.urgency && decayState.urgency.urgencyTier.label === "critical") {
665
- priority = "critical";
666
- reason = `Deadline in ${decayState.urgency.daysToDeadline}d \u2014 needs immediate rescoring`;
667
- } else if (decayState.urgency && decayState.urgency.urgencyTier.label === "imminent") {
668
- priority = "high";
669
- reason = `Deadline in ${decayState.urgency.daysToDeadline}d \u2014 weekly rescoring required`;
670
- } else if (isOverdue) {
671
- priority = "high";
672
- reason = `Rescore overdue by ${Math.abs(Math.round(daysUntilRescore))}d`;
673
- } else if (opts.temporalNature === "forecast" && daysUntilRescore < 7) {
674
- priority = "medium";
675
- reason = `Forecast belief \u2014 next rescore due in ${Math.round(daysUntilRescore)}d`;
676
- } else if (daysUntilRescore < 14) {
677
- priority = "medium";
678
- reason = `Rescore due in ${Math.round(daysUntilRescore)}d`;
679
- } else {
680
- priority = "low";
681
- reason = `On schedule \u2014 next rescore in ${Math.round(daysUntilRescore)}d`;
682
- }
683
- if ((opts.confidence ?? 0) >= 0.8 && decayState.baseTier.label !== "fresh" && priority === "medium") {
684
- priority = "high";
685
- reason = `High-confidence belief (${((opts.confidence ?? 0) * 100).toFixed(0)}%) aging without rescore \u2014 ${reason}`;
686
- }
687
- return {
688
- nextRescoreBy: decayState.rescoreByDate,
689
- daysUntilRescore: Math.round(daysUntilRescore),
690
- isOverdue,
691
- priority,
692
- reason,
693
- decay: decayState
694
- };
695
- }
696
-
697
- // ../confidence/src/v1/operations/contracts/epistemicContract.ts
698
- var BUILT_IN_METRIC_CHECKER = "metric_checker";
699
- var BUILT_IN_REFERENCE_CHECK_COUNTER = "reference_check_counter";
700
- var BUILT_IN_MARKET_INDEX_COMPARATOR = "market_index_comparator";
701
- function clampConfidence(value) {
702
- return Math.max(0, Math.min(1, value));
703
- }
704
- function generateContractId() {
705
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
706
- return crypto.randomUUID();
707
- }
708
- return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
709
- }
710
- function deriveContractStatus(result, currentStatus) {
711
- if (currentStatus === "archived") {
712
- return currentStatus;
713
- }
714
- switch (result) {
715
- case "confirmed":
716
- return "satisfied";
717
- case "disconfirmed":
718
- return "violated";
719
- case "expired":
720
- return "expired";
721
- default:
722
- return currentStatus === "satisfied" || currentStatus === "violated" || currentStatus === "expired" ? "active" : currentStatus;
723
- }
724
- }
725
- function deriveVerificationTrigger(result) {
726
- switch (result) {
727
- case "confirmed":
728
- return "verification_confirmed";
729
- case "disconfirmed":
730
- return "verification_disconfirmed";
731
- case "expired":
732
- return "verification_expired";
733
- case "partial":
734
- return "verification_partial";
735
- default:
736
- return null;
737
- }
738
- }
739
- function deriveContractModulationPlan(args) {
740
- const trigger = deriveVerificationTrigger(args.result);
741
- if (!trigger) {
742
- return null;
743
- }
744
- if (args.result === "confirmed") {
745
- const rawNext = args.currentConfidence + args.modulation.onConfirmed.delta;
746
- const confidenceAfter = clampConfidence(
747
- Math.min(
748
- args.modulation.onConfirmed.ceiling ?? Number.POSITIVE_INFINITY,
749
- rawNext
750
- )
751
- );
752
- return {
753
- trigger,
754
- confidenceBefore: args.currentConfidence,
755
- confidenceAfter,
756
- confidenceDelta: confidenceAfter - args.currentConfidence
757
- };
758
- }
759
- if (args.result === "disconfirmed") {
760
- const rawNext = args.currentConfidence + args.modulation.onDisconfirmed.delta;
761
- const confidenceAfter = clampConfidence(
762
- Math.max(args.modulation.onDisconfirmed.floor ?? 0, rawNext)
763
- );
764
- return {
765
- trigger,
766
- confidenceBefore: args.currentConfidence,
767
- confidenceAfter,
768
- confidenceDelta: confidenceAfter - args.currentConfidence
769
- };
770
- }
771
- if (args.result === "expired" && args.modulation.onExpired) {
772
- const confidenceAfter = clampConfidence(
773
- args.currentConfidence + args.modulation.onExpired.delta
774
- );
775
- return {
776
- trigger,
777
- confidenceBefore: args.currentConfidence,
778
- confidenceAfter,
779
- confidenceDelta: confidenceAfter - args.currentConfidence
780
- };
781
- }
782
- if (args.result === "partial" && args.modulation.onPartial) {
783
- if ((args.resultConfidence ?? 0) < args.modulation.onPartial.threshold) {
784
- return null;
785
- }
786
- const confidenceAfter = clampConfidence(
787
- args.currentConfidence + args.modulation.onPartial.delta
788
- );
789
- return {
790
- trigger,
791
- confidenceBefore: args.currentConfidence,
792
- confidenceAfter,
793
- confidenceDelta: confidenceAfter - args.currentConfidence
794
- };
795
- }
796
- return null;
797
- }
798
- function createInheritedContractRecord(contract, args) {
799
- return {
800
- beliefNodeId: args.beliefNodeId,
801
- contractId: generateContractId(),
802
- title: contract.title,
803
- description: contract.description,
804
- conditionType: contract.conditionType,
805
- direction: contract.direction,
806
- condition: contract.condition,
807
- deadline: contract.deadline,
808
- compositeOf: contract.compositeOf,
809
- compositeOperator: contract.compositeOperator,
810
- modulation: contract.modulation,
811
- evaluationSchedule: contract.evaluationSchedule,
812
- periodicIntervalMs: contract.periodicIntervalMs,
813
- status: "active",
814
- lineageSource: "inherited",
815
- inheritedFromContractId: contract.contractId,
816
- inheritedFromBeliefNodeId: contract.beliefNodeId,
817
- inheritedAt: args.now,
818
- topicId: args.topicId,
819
- createdAt: args.now,
820
- createdBy: args.createdBy,
821
- updatedAt: args.now
822
- };
823
- }
824
- function normalizeEvidentialAction(value) {
825
- return value === "modulate_confidence" || value === "flag_review" || value === "archive" ? value : void 0;
826
- }
827
- function parseComparisonOperator(value, evaluatorName) {
828
- if (value === "gte" || value === "lte" || value === "eq" || value === "gt" || value === "lt") {
829
- return value;
830
- }
831
- throw new Error(
832
- `${evaluatorName} requires operator to be one of gte, lte, eq, gt, or lt.`
833
- );
834
- }
835
- function parseNumericThreshold(value, evaluatorName) {
836
- if (typeof value === "number" && Number.isFinite(value)) {
837
- return value;
838
- }
839
- throw new Error(`${evaluatorName} requires a finite numeric threshold.`);
840
- }
841
- function pickFiniteNumber(config, keys) {
842
- for (const key of keys) {
843
- const value = config[key];
844
- if (typeof value === "number" && Number.isFinite(value)) {
845
- return value;
846
- }
847
- }
848
- return void 0;
849
- }
850
- function getEvaluatorInputRecord(inputData, nestedKey) {
851
- if (!inputData || typeof inputData !== "object") {
852
- return {};
853
- }
854
- const root = inputData;
855
- const nested = root[nestedKey];
856
- if (nested && typeof nested === "object") {
857
- return nested;
858
- }
859
- return root;
860
- }
861
- function parseEvidentialEvaluatorConfig(value) {
862
- if (!value || typeof value !== "object") {
863
- throw new Error(
864
- "Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
865
- );
866
- }
867
- const config = value;
868
- const metric = config.metric;
869
- const operator = config.operator;
870
- const threshold = config.threshold;
871
- if (metric !== "evidence_count" && metric !== "contradiction_status" && metric !== "edge_freshness" && metric !== "dependent_count") {
872
- throw new Error(`Unsupported evidential metric: ${String(metric)}`);
873
- }
874
- if (operator !== "gte" && operator !== "lte" && operator !== "eq" && operator !== "gt" && operator !== "lt") {
875
- throw new Error(`Unsupported evidential operator: ${String(operator)}`);
876
- }
877
- if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
878
- throw new Error("Evidential contracts require a numeric threshold.");
879
- }
880
- const actionParams = config.actionParams && typeof config.actionParams === "object" && config.actionParams !== null ? config.actionParams : void 0;
881
- return {
882
- metric,
883
- operator,
884
- threshold,
885
- action: normalizeEvidentialAction(config.action),
886
- actionParams: actionParams && (typeof actionParams.targetConfidence === "number" || typeof actionParams.rationale === "string") ? {
887
- targetConfidence: typeof actionParams.targetConfidence === "number" ? actionParams.targetConfidence : void 0,
888
- rationale: typeof actionParams.rationale === "string" ? actionParams.rationale : void 0
889
- } : void 0
890
- };
891
- }
892
- function compareMetricValue(operator, left, right) {
893
- switch (operator) {
894
- case "gte":
895
- return left >= right;
896
- case "lte":
897
- return left <= right;
898
- case "eq":
899
- return left === right;
900
- case "gt":
901
- return left > right;
902
- case "lt":
903
- return left < right;
904
- default:
905
- return false;
906
- }
907
- }
908
- function resolveComparisonResult(direction, comparisonSatisfied) {
909
- return direction === "falsifies" ? comparisonSatisfied ? "disconfirmed" : "confirmed" : comparisonSatisfied ? "confirmed" : "disconfirmed";
910
- }
911
- function buildComparisonRationale(args) {
912
- const renderedObserved = args.observedValue === null ? "no data" : `${args.observedValue}${args.unit ? ` ${args.unit}` : ""}`;
913
- const renderedThreshold = `${args.threshold}${args.unit ? ` ${args.unit}` : ""}`;
914
- const clause = `${args.label} observed ${renderedObserved} against ${args.operator} ${renderedThreshold}`;
915
- if (args.observedValue === null) {
916
- return `${clause}; evaluator returned ${args.result} because no current data was available.`;
917
- }
918
- return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
919
- }
920
- function buildEvidentialRationale(args) {
921
- const observed = args.snapshot.value === null ? "no data" : String(args.snapshot.value);
922
- const clause = `${args.snapshot.metric} observed ${observed} against ${args.config.operator} ${args.config.threshold}`;
923
- if (args.snapshot.value === null) {
924
- return `${clause}; evidential evaluator treated the comparison as unmet, resulting in ${args.result}.`;
925
- }
926
- return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
927
- }
928
- function parseMetricCheckerConfig(value) {
929
- if (!value || typeof value !== "object") {
930
- throw new Error(
931
- "metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
932
- );
933
- }
934
- const config = value;
935
- return {
936
- metric: typeof config.metric === "string" && config.metric.length > 0 ? config.metric : void 0,
937
- operator: parseComparisonOperator(config.operator, BUILT_IN_METRIC_CHECKER),
938
- threshold: parseNumericThreshold(config.threshold, BUILT_IN_METRIC_CHECKER),
939
- observedValue: pickFiniteNumber(config, ["observedValue", "value"]),
940
- currentValue: pickFiniteNumber(config, ["currentValue"]),
941
- metricValue: pickFiniteNumber(config, ["metricValue"]),
942
- unit: typeof config.unit === "string" && config.unit.length > 0 ? config.unit : void 0
943
- };
944
- }
945
- function parseReferenceCheckCounterConfig(value) {
946
- if (!value || typeof value !== "object") {
947
- throw new Error(
948
- "reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
949
- );
950
- }
951
- const config = value;
952
- if (typeof config.tag !== "string" || config.tag.trim().length === 0) {
953
- throw new Error("reference_check_counter requires a non-empty tag.");
954
- }
955
- return {
956
- tag: config.tag.trim(),
957
- operator: parseComparisonOperator(
958
- config.operator,
959
- BUILT_IN_REFERENCE_CHECK_COUNTER
960
- ),
961
- threshold: parseNumericThreshold(
962
- config.threshold,
963
- BUILT_IN_REFERENCE_CHECK_COUNTER
964
- ),
965
- caseSensitive: config.caseSensitive === true
966
- };
967
- }
968
- function parseTemporalDeadlineConfig(value) {
969
- if (!value || typeof value !== "object") {
970
- return {};
971
- }
972
- const config = value;
973
- return {
974
- label: typeof config.label === "string" && config.label.length > 0 ? config.label : void 0,
975
- completed: config.completed === true,
976
- completedAt: pickFiniteNumber(config, ["completedAt"]),
977
- observedAt: pickFiniteNumber(config, ["observedAt"]),
978
- satisfiedAt: pickFiniteNumber(config, ["satisfiedAt"]),
979
- achievedAt: pickFiniteNumber(config, ["achievedAt"])
980
- };
981
- }
982
- function parseMarketIndexComparatorConfig(value) {
983
- if (!value || typeof value !== "object") {
984
- throw new Error(
985
- "market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
986
- );
987
- }
988
- const config = value;
989
- return {
990
- subject: typeof config.subject === "string" && config.subject.length > 0 ? config.subject : void 0,
991
- subjectValue: pickFiniteNumber(config, ["subjectValue", "leftValue"]),
992
- primaryValue: pickFiniteNumber(config, ["primaryValue"]),
993
- benchmark: typeof config.benchmark === "string" && config.benchmark.length > 0 ? config.benchmark : void 0,
994
- benchmarkValue: pickFiniteNumber(config, ["benchmarkValue", "rightValue"]),
995
- comparisonValue: pickFiniteNumber(config, ["comparisonValue"]),
996
- operator: parseComparisonOperator(
997
- config.operator,
998
- BUILT_IN_MARKET_INDEX_COMPARATOR
999
- ),
1000
- threshold: parseNumericThreshold(
1001
- config.threshold,
1002
- BUILT_IN_MARKET_INDEX_COMPARATOR
1003
- )
1004
- };
1005
- }
1006
- var api = anyApi;
1007
- componentsGeneric();
1008
-
1009
- // ../access-control/src/topicProjectOverlay.ts
1010
- var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
1011
- function readNonEmptyString(value) {
1012
- if (typeof value !== "string") {
1013
- return;
1014
- }
1015
- const normalized = value.trim();
1016
- return normalized.length > 0 ? normalized : void 0;
1017
- }
1018
- function readStringArray(value) {
1019
- if (!Array.isArray(value)) {
1020
- return [];
1021
- }
1022
- return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
1023
- }
1024
- function readMetadata(topic) {
1025
- return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
1026
- }
1027
- function readLegacyProjectId(value) {
1028
- if (!value) {
1029
- return;
1030
- }
1031
- return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
1032
- }
1033
- function coerceVisibility(value) {
1034
- return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
1035
- }
1036
- function coerceStatus(value) {
1037
- return value === "active" || value === "archived" || value === "watching" ? value : void 0;
1038
- }
1039
- function mapProjectType(topic, metadata) {
1040
- const explicit = readNonEmptyString(metadata.projectType);
1041
- if (explicit) {
1042
- return explicit;
1043
- }
1044
- if (topic.type === "theme") {
1045
- return "thematic";
1046
- }
1047
- return readNonEmptyString(topic.type) || "general";
1048
- }
1049
- function isProjectLikeTopic(topic) {
1050
- const metadata = readMetadata(topic);
1051
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
1052
- }
1053
- async function resolveTopicDoc(ctx, scopeId) {
1054
- if (ctx?.db && typeof ctx.db.get === "function") {
1055
- try {
1056
- const directTopic = await ctx.db.get(scopeId);
1057
- if (directTopic) {
1058
- return directTopic;
1059
- }
1060
- } catch {
1061
- }
1062
- }
1063
- if (typeof ctx.runQuery !== "function") {
1064
- return null;
1065
- }
1066
- try {
1067
- const topic = await ctx.runQuery(api.topics.get, {
1068
- id: String(scopeId)
1069
- });
1070
- if (topic?.name !== void 0 && topic?.type !== void 0) {
1071
- return topic;
1072
- }
1073
- } catch {
1074
- }
1075
- try {
1076
- const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
1077
- projectId: String(scopeId)
1078
- });
1079
- if (topic?.name !== void 0 && topic?.type !== void 0) {
1080
- return topic;
1081
- }
1082
- } catch {
1083
- }
1084
- return null;
1085
- }
1086
- function materializeTopicProjectOverlay(topic, idMode = "legacy") {
1087
- const metadata = readMetadata(topic);
1088
- const topicId = String(topic._id);
1089
- const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
1090
- const storageProjectId = legacyProjectId || topicId;
1091
- const outwardId = idMode === "topic" ? topicId : storageProjectId;
1092
- const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
1093
- const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
1094
- const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
1095
- const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
1096
- return {
1097
- ...metadata,
1098
- _id: outwardId,
1099
- projectId: outwardId,
1100
- topicId,
1101
- storageProjectId,
1102
- legacyProjectId,
1103
- name: readNonEmptyString(topic.name) || "Untitled Theme",
1104
- type: mapProjectType(topic, metadata),
1105
- description: readNonEmptyString(topic.description),
1106
- ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
1107
- sharedWith: readStringArray(metadata.sharedWith),
1108
- visibility,
1109
- tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
1110
- workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
1111
- status,
1112
- tags: readStringArray(metadata.tags),
1113
- chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
1114
- artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
1115
- lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
1116
- _creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
1117
- createdAt,
1118
- updatedAt
1119
- };
1120
- }
1121
- async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
1122
- const topic = await resolveTopicDoc(ctx, scopeId);
1123
- if (!topic) {
1124
- return null;
1125
- }
1126
- if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
1127
- return null;
1128
- }
1129
- return materializeTopicProjectOverlay(topic, options.idMode);
1130
- }
1131
- async function listTopicProjectOverlays(ctx, options = {}) {
1132
- let allTopics = [];
1133
- if (ctx?.db?.query && typeof ctx.db.query === "function") {
1134
- try {
1135
- allTopics = await ctx.db.query("topics").collect();
1136
- } catch {
1137
- allTopics = [];
1138
- }
1139
- }
1140
- if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
1141
- allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
1142
- }
1143
- return allTopics.filter(
1144
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
1145
- ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
1146
- }
1147
-
1148
- // ../access-control/src/projectGrantsBridge.ts
1149
- var PROJECT_GRANT_STATUSES = ["active", "revoked", "expired"];
1150
- function normalizeString(value) {
1151
- if (typeof value !== "string") {
1152
- return;
1153
- }
1154
- const trimmed = value.trim();
1155
- return trimmed.length > 0 ? trimmed : void 0;
1156
- }
1157
- async function resolveGrantScopeIds(ctx, args) {
1158
- const topicId = normalizeString(args.topicId);
1159
- const projectId = normalizeString(args.projectId);
1160
- for (const scopeId of [topicId, projectId]) {
1161
- if (!scopeId) {
1162
- continue;
1163
- }
1164
- try {
1165
- const overlay = await resolveTopicProjectOverlay(ctx, scopeId, {
1166
- idMode: "legacy",
1167
- projectLikeOnly: false
1168
- });
1169
- if (overlay) {
1170
- return {
1171
- topicId: normalizeString(overlay.topicId) ?? topicId,
1172
- projectId: normalizeString(overlay.projectId) ?? projectId ?? scopeId
1173
- };
1174
- }
1175
- } catch {
1176
- }
1177
- }
1178
- return { topicId, projectId };
1179
- }
1180
- async function normalizeProjectGrantRow(ctx, row) {
1181
- const scope = await resolveGrantScopeIds(ctx, {
1182
- topicId: row.topicId,
1183
- projectId: row.projectId
1184
- });
1185
- return {
1186
- ...row,
1187
- ...scope.topicId ? { topicId: scope.topicId } : {},
1188
- ...scope.projectId ?? scope.topicId ? { projectId: scope.projectId ?? scope.topicId } : {}
1189
- };
1190
- }
1191
- async function normalizeProjectGrantRows(ctx, rows) {
1192
- return await Promise.all(rows.map((row) => normalizeProjectGrantRow(ctx, row)));
1193
- }
1194
- async function listProjectGrantsByPrincipal(ctx, principalId) {
1195
- const rows = await Promise.all(
1196
- PROJECT_GRANT_STATUSES.map(
1197
- (status) => ctx.db.query("projectGrants").withIndex(
1198
- "by_principal_status",
1199
- (q) => q.eq("principalId", principalId).eq("status", status)
1200
- ).collect()
1201
- )
1202
- );
1203
- return await normalizeProjectGrantRows(ctx, rows.flat());
1204
- }
1205
- async function listProjectGrantsByGroup(ctx, groupId) {
1206
- const rows = await Promise.all(
1207
- PROJECT_GRANT_STATUSES.map(
1208
- (status) => ctx.db.query("projectGrants").withIndex(
1209
- "by_group_status",
1210
- (q) => q.eq("groupId", groupId).eq("status", status)
1211
- ).collect()
1212
- )
1213
- );
1214
- return await normalizeProjectGrantRows(ctx, rows.flat());
1215
- }
1216
- function buildScopeMatchers(inputScopeId, resolved) {
1217
- return new Set(
1218
- [inputScopeId, resolved.topicId, resolved.projectId].map((value) => normalizeString(value)).filter((value) => Boolean(value))
1219
- );
1220
- }
1221
- function matchesResolvedScope(row, scopeIds) {
1222
- const rowTopicId = normalizeString(row.topicId);
1223
- const rowProjectId = normalizeString(row.projectId);
1224
- return rowTopicId !== void 0 && scopeIds.has(rowTopicId) || rowProjectId !== void 0 && scopeIds.has(rowProjectId);
1225
- }
1226
- async function bridgeListProjectGrantsByTopicAndPrincipal(ctx, topicId, principalId) {
1227
- const resolved = await resolveGrantScopeIds(ctx, { topicId });
1228
- const scopeIds = buildScopeMatchers(topicId, resolved);
1229
- const rows = await listProjectGrantsByPrincipal(ctx, principalId);
1230
- return rows.filter((row) => matchesResolvedScope(row, scopeIds));
1231
- }
1232
- async function bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId) {
1233
- const resolved = await resolveGrantScopeIds(ctx, { topicId });
1234
- const scopeIds = buildScopeMatchers(topicId, resolved);
1235
- const rows = await listProjectGrantsByGroup(ctx, groupId);
1236
- return rows.filter((row) => matchesResolvedScope(row, scopeIds));
1237
- }
1238
- async function bridgeListProjectGrantsByPrincipalStatus(ctx, principalId, status) {
1239
- const rows = await listProjectGrantsByPrincipal(ctx, principalId);
1240
- return rows.filter((row) => row.status === status);
1241
- }
1242
- async function bridgeListProjectGrantsByGroupStatus(ctx, groupId, status) {
1243
- const rows = await listProjectGrantsByGroup(ctx, groupId);
1244
- return rows.filter((row) => row.status === status);
1245
- }
1246
- async function bridgeInsertProjectGrant(ctx, value) {
1247
- const resolved = await resolveGrantScopeIds(ctx, value);
1248
- return await ctx.db.insert("projectGrants", {
1249
- ...value,
1250
- ...resolved.topicId ? { topicId: resolved.topicId } : {},
1251
- ...resolved.projectId ?? resolved.topicId ? { projectId: resolved.projectId ?? resolved.topicId } : {}
1252
- });
1253
- }
1254
-
1255
- // ../access-control/src/resolvers.ts
1256
- async function findUserByClerkId(ctx, clerkId) {
1257
- const normalizedClerkId = clerkId.trim();
1258
- if (!normalizedClerkId) {
1259
- return null;
1260
- }
1261
- if (typeof ctx.runQuery === "function") {
1262
- try {
1263
- const bridgedUser = await ctx.runQuery(api.users.getUserByClerkId, {
1264
- clerkId: normalizedClerkId
1265
- });
1266
- if (bridgedUser) {
1267
- return bridgedUser;
1268
- }
1269
- } catch {
1270
- }
1271
- }
1272
- try {
1273
- const users = await ctx.db.query("users").collect();
1274
- return users.find((user) => String(user.clerkId ?? "") === normalizedClerkId) ?? null;
1275
- } catch {
1276
- return null;
1277
- }
1278
- }
1279
- async function findUserByPrincipalId(ctx, principalId) {
1280
- const normalizedPrincipalId = principalId.trim();
1281
- if (!normalizedPrincipalId) {
1282
- return null;
1283
- }
1284
- try {
1285
- const users = await ctx.db.query("users").collect();
1286
- return users.find(
1287
- (user) => String(user.defaultPrincipalId ?? "") === normalizedPrincipalId
1288
- ) ?? null;
1289
- } catch {
1290
- return null;
1291
- }
1292
- }
1293
- async function findAgentByPrincipalId(ctx, principalId) {
1294
- const normalizedPrincipalId = principalId.trim();
1295
- if (!normalizedPrincipalId) {
1296
- return null;
1297
- }
1298
- if (typeof ctx.runQuery === "function") {
1299
- try {
1300
- const bridgedAgent = await ctx.runQuery(
1301
- api.agents.getAgentByPrincipalId,
1302
- {
1303
- principalId: normalizedPrincipalId
1304
- }
1305
- );
1306
- if (bridgedAgent) {
1307
- return bridgedAgent;
1308
- }
1309
- } catch {
1310
- }
1311
- }
1312
- try {
1313
- const agents = await ctx.db.query("agents").collect();
1314
- return agents.find(
1315
- (agent) => String(agent.principalId ?? "") === normalizedPrincipalId
1316
- ) ?? null;
1317
- } catch {
1318
- return null;
1319
- }
1320
- }
1321
- function defaultResolvers() {
1322
- return {
1323
- async getProject(ctx, topicId) {
1324
- return await resolveTopicProjectOverlay(ctx, topicId, {
1325
- idMode: "legacy",
1326
- projectLikeOnly: false
1327
- });
1328
- },
1329
- async listTopics(ctx) {
1330
- return await listTopicProjectOverlays(ctx, { idMode: "legacy" });
1331
- },
1332
- async listTopicsByOwner(ctx, ownerId) {
1333
- const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
1334
- return topics.filter((topic) => topic.ownerId === ownerId);
1335
- },
1336
- async listTopicsByVisibility(ctx, visibility) {
1337
- const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
1338
- return topics.filter((topic) => topic.visibility === visibility);
1339
- },
1340
- async listProjectGrantsByProjectAndPrincipal(ctx, topicId, principalId) {
1341
- return await bridgeListProjectGrantsByTopicAndPrincipal(
1342
- ctx,
1343
- topicId,
1344
- principalId
1345
- );
1346
- },
1347
- async listProjectGrantsByProjectAndGroup(ctx, topicId, groupId) {
1348
- return await bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId);
1349
- },
1350
- async listProjectGrantsByPrincipalStatus(ctx, principalId, status) {
1351
- return await bridgeListProjectGrantsByPrincipalStatus(
1352
- ctx,
1353
- principalId,
1354
- status
1355
- );
1356
- },
1357
- async listProjectGrantsByGroupStatus(ctx, groupId, status) {
1358
- return await bridgeListProjectGrantsByGroupStatus(ctx, groupId, status);
1359
- },
1360
- async insertProjectGrant(ctx, value) {
1361
- return await bridgeInsertProjectGrant(ctx, value);
1362
- },
1363
- async getAgentByPrincipalId(ctx, principalId) {
1364
- return await findAgentByPrincipalId(ctx, principalId);
1365
- },
1366
- async getUserByClerkId(ctx, clerkId) {
1367
- return await findUserByClerkId(ctx, clerkId);
1368
- },
1369
- async getUserByPrincipalId(ctx, principalId) {
1370
- return await findUserByPrincipalId(ctx, principalId);
1371
- }
1372
- };
1373
- }
1374
- var resolverOverrides = {};
1375
- function resolveAccessControlAppResolvers(_ctx) {
1376
- return {
1377
- ...defaultResolvers(),
1378
- ...resolverOverrides
1379
- };
1380
- }
1381
-
1382
- // ../access-control/src/principalContext.ts
1383
- function requireCanonicalResolvedUser(user, clerkId) {
1384
- const resolved = user;
1385
- if (!resolved) {
1386
- throw new Error(
1387
- `[AccessControl] Canonical user identity required for ${clerkId}. Sync users.upsertUser before user-bound access checks.`
1388
- );
1389
- }
1390
- const { mcRole, defaultTenantId, defaultWorkspaceId, defaultPrincipalId } = resolved;
1391
- if (mcRole !== "platform_admin" && mcRole !== "tenant_admin" && mcRole !== "workspace_admin" && mcRole !== "editor" && mcRole !== "viewer" && mcRole !== "auditor" && mcRole !== "service_agent") {
1392
- throw new Error(
1393
- `[AccessControl] Canonical MC role required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
1394
- );
1395
- }
1396
- if (typeof defaultTenantId !== "string" || defaultTenantId.trim().length === 0) {
1397
- throw new Error(
1398
- `[AccessControl] Canonical home tenant required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
1399
- );
1400
- }
1401
- if (typeof defaultWorkspaceId !== "string" || defaultWorkspaceId.trim().length === 0) {
1402
- throw new Error(
1403
- `[AccessControl] Canonical home workspace required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
1404
- );
1405
- }
1406
- if (typeof defaultPrincipalId !== "string" || defaultPrincipalId.trim().length === 0) {
1407
- throw new Error(
1408
- `[AccessControl] Canonical federated principal required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
1409
- );
1410
- }
1411
- return {
1412
- mcRole,
1413
- defaultTenantId: defaultTenantId.trim(),
1414
- defaultWorkspaceId: defaultWorkspaceId.trim(),
1415
- defaultPrincipalId: defaultPrincipalId.trim()
1416
- };
1417
- }
1418
- function isPrincipalIdInput(value) {
1419
- return value.startsWith("user:") || value.startsWith("group:") || value.startsWith("service:") || value.startsWith("agent:") || value.startsWith("external_viewer:");
1420
- }
1421
- async function resolveCanonicalUserRecord(ctx, actorId) {
1422
- const normalizedActorId = actorId.trim();
1423
- const clerkId = isPrincipalIdInput(normalizedActorId) && normalizedActorId.startsWith("user:") ? normalizedActorId.slice("user:".length) : normalizedActorId;
1424
- const resolvers = resolveAccessControlAppResolvers();
1425
- const resolvedByClerkId = await resolvers.getUserByClerkId(ctx, clerkId);
1426
- if (resolvedByClerkId) {
1427
- return {
1428
- resolvedUser: resolvedByClerkId,
1429
- clerkId,
1430
- contextClerkId: clerkId
1431
- };
1432
- }
1433
- const resolvedByPrincipalId = await resolvers.getUserByPrincipalId(
1434
- ctx,
1435
- normalizedActorId
1436
- );
1437
- return {
1438
- resolvedUser: resolvedByPrincipalId ?? null,
1439
- clerkId,
1440
- contextClerkId: normalizedActorId.startsWith("user:") && clerkId.length > 0 ? clerkId : normalizedActorId
1441
- };
1442
- }
1443
- function uniqRoles(roles) {
1444
- const roleSet = /* @__PURE__ */ new Set();
1445
- for (const role of roles) {
1446
- if (role === "platform_admin" || role === "tenant_admin" || role === "workspace_admin" || role === "editor" || role === "viewer" || role === "auditor" || role === "service_agent") {
1447
- roleSet.add(role);
1448
- }
1449
- }
1450
- return [...roleSet];
1451
- }
1452
- function normalizeGroupIds(value) {
1453
- if (!Array.isArray(value)) {
1454
- return [];
1455
- }
1456
- return [...new Set(
1457
- value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean)
1458
- )];
1459
- }
1460
- function requireServiceAgentUser(user, actorId) {
1461
- const canonicalUser = requireCanonicalResolvedUser(user, actorId);
1462
- if (canonicalUser.mcRole !== "service_agent") {
1463
- throw new Error(
1464
- `[AccessControl] Canonical service_agent identity required for ${actorId}. Sync users.upsertUser before agent-bound access checks.`
1465
- );
1466
- }
1467
- return canonicalUser;
1468
- }
1469
- function requireCanonicalResolvedAgent(agent, actorId) {
1470
- const resolved = agent;
1471
- if (!resolved) {
1472
- throw new Error(
1473
- `[AccessControl] Agent "${actorId}" not found in agents or users table.`
1474
- );
1475
- }
1476
- if (typeof resolved.principalId !== "string" || resolved.principalId.trim().length === 0) {
1477
- throw new Error(
1478
- `[AccessControl] Canonical agent principalId required for ${actorId}.`
1479
- );
1480
- }
1481
- if (typeof resolved.tenantId !== "string" || resolved.tenantId.trim().length === 0) {
1482
- throw new Error(
1483
- `[AccessControl] Canonical home tenant required for ${actorId}.`
1484
- );
1485
- }
1486
- if (typeof resolved.workspaceId !== "string" || resolved.workspaceId.trim().length === 0) {
1487
- throw new Error(
1488
- `[AccessControl] Canonical home workspace required for ${actorId}.`
1489
- );
1490
- }
1491
- return {
1492
- principalId: resolved.principalId.trim(),
1493
- tenantId: resolved.tenantId.trim(),
1494
- workspaceId: resolved.workspaceId.trim(),
1495
- roles: uniqRoles(Array.isArray(resolved.roles) ? resolved.roles : []) ?? ["service_agent"],
1496
- groupIds: normalizeGroupIds(resolved.groupIds)
1497
- };
1498
- }
1499
- async function resolvePrincipalContext(ctx, actorId) {
1500
- if (actorId.startsWith("agent:")) {
1501
- const resolvers = resolveAccessControlAppResolvers();
1502
- const resolvedAgent = await resolvers.getAgentByPrincipalId(ctx, actorId);
1503
- if (resolvedAgent) {
1504
- const agent = requireCanonicalResolvedAgent(
1505
- resolvedAgent,
1506
- actorId
1507
- );
1508
- return {
1509
- principalId: agent.principalId,
1510
- principalType: "service",
1511
- clerkId: actorId,
1512
- tenantId: agent.tenantId,
1513
- workspaceId: agent.workspaceId,
1514
- roles: agent.roles.length > 0 ? agent.roles : ["service_agent"],
1515
- groupIds: agent.groupIds,
1516
- isPlatformAdmin: false,
1517
- isTenantAdmin: false,
1518
- isWorkspaceAdmin: false,
1519
- isSystemFallback: false
1520
- };
1521
- }
1522
- const resolvedUser2 = await resolvers.getUserByClerkId(
1523
- ctx,
1524
- actorId
1525
- );
1526
- if (!resolvedUser2) {
1527
- throw new Error(
1528
- `[AccessControl] Agent "${actorId}" not found in agents or users table.`
1529
- );
1530
- }
1531
- const user2 = requireServiceAgentUser(
1532
- resolvedUser2,
1533
- actorId
1534
- );
1535
- console.warn(
1536
- `[AccessControl] Deprecated legacy service-agent fallback for ${actorId}; migrate this principal into identity.agents.`
1537
- );
1538
- return {
1539
- principalId: user2.defaultPrincipalId,
1540
- principalType: "service",
1541
- clerkId: actorId,
1542
- tenantId: user2.defaultTenantId,
1543
- workspaceId: user2.defaultWorkspaceId,
1544
- roles: ["service_agent"],
1545
- groupIds: normalizeGroupIds(resolvedUser2?.principalGroupIds),
1546
- isPlatformAdmin: false,
1547
- isTenantAdmin: false,
1548
- isWorkspaceAdmin: false,
1549
- isSystemFallback: false
1550
- };
1551
- }
1552
- const {
1553
- resolvedUser,
1554
- contextClerkId
1555
- } = await resolveCanonicalUserRecord(ctx, actorId);
1556
- const user = requireCanonicalResolvedUser(
1557
- resolvedUser,
1558
- contextClerkId
1559
- );
1560
- if (!user.defaultPrincipalId) {
1561
- throw new Error(
1562
- `[AccessControl] Canonical federated principal required for ${contextClerkId}. Re-sync Master Control identity before user-bound access checks.`
1563
- );
1564
- }
1565
- if (user.mcRole === "service_agent") {
1566
- return {
1567
- principalId: user.defaultPrincipalId,
1568
- principalType: "service",
1569
- clerkId: contextClerkId,
1570
- tenantId: user.defaultTenantId,
1571
- workspaceId: user.defaultWorkspaceId,
1572
- roles: ["service_agent"],
1573
- groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
1574
- isPlatformAdmin: false,
1575
- isTenantAdmin: false,
1576
- isWorkspaceAdmin: false,
1577
- isSystemFallback: false
1578
- };
1579
- }
1580
- const principalId = user.defaultPrincipalId;
1581
- const effectiveRole = user.mcRole;
1582
- const roles = effectiveRole === "platform_admin" ? ["platform_admin", "tenant_admin"] : effectiveRole === "tenant_admin" ? ["tenant_admin"] : [effectiveRole];
1583
- const tenantId = user.defaultTenantId;
1584
- const workspaceId = user.defaultWorkspaceId;
1585
- const isPlatformAdmin = effectiveRole === "platform_admin";
1586
- return {
1587
- principalId,
1588
- principalType: "user",
1589
- clerkId: contextClerkId,
1590
- tenantId,
1591
- workspaceId,
1592
- roles: uniqRoles(roles),
1593
- groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
1594
- isPlatformAdmin,
1595
- isTenantAdmin: isPlatformAdmin || effectiveRole === "tenant_admin",
1596
- isWorkspaceAdmin: isPlatformAdmin || effectiveRole === "tenant_admin" || effectiveRole === "workspace_admin",
1597
- isSystemFallback: false
1598
- };
1599
- }
1600
-
1601
- // ../access-control/src/access.ts
1602
- function isTopicInPrincipalTenant(topic, principalTenantId) {
1603
- if (!topic.tenantId) {
1604
- return false;
1605
- }
1606
- if (!principalTenantId) {
1607
- return false;
1608
- }
1609
- return String(topic.tenantId) === String(principalTenantId);
1610
- }
1611
- function isTopicInPrincipalWorkspace(topic, principalWorkspaceId) {
1612
- if (!topic.workspaceId) {
1613
- return false;
1614
- }
1615
- if (!principalWorkspaceId) {
1616
- return false;
1617
- }
1618
- return String(topic.workspaceId) === String(principalWorkspaceId);
1619
- }
1620
- function isLegacyUnscopedTopic(topic) {
1621
- return !topic.tenantId || !topic.workspaceId;
1622
- }
1623
- function isGrantScopeAlignedToTopic(topic, grant) {
1624
- if (topic.tenantId && grant.tenantId && String(topic.tenantId) !== String(grant.tenantId)) {
1625
- return false;
1626
- }
1627
- if (topic.workspaceId && grant.workspaceId && String(topic.workspaceId) !== String(grant.workspaceId)) {
1628
- return false;
1629
- }
1630
- return true;
1631
- }
1632
- function isGrantSourceAllowedForVisibility(visibility, source) {
1633
- if (source !== "external_share") {
1634
- return true;
1635
- }
1636
- return visibility === "external" || visibility === "public";
1637
- }
1638
- function isGrantActive(grant) {
1639
- if (grant.status !== "active") {
1640
- return false;
1641
- }
1642
- if (grant.expiresAt !== void 0 && grant.expiresAt <= Date.now()) {
1643
- return false;
1644
- }
1645
- return true;
1646
- }
1647
- async function hasPrincipalGrant(ctx, args) {
1648
- const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndPrincipal(
1649
- ctx,
1650
- args.topic._id,
1651
- args.principalId
1652
- );
1653
- if (grants.some(
1654
- (grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
1655
- args.topic.visibility,
1656
- grant.source
1657
- ) && (!args.principalIsExternal || args.topic.visibility === "public" || grant.source === "external_share")
1658
- )) {
1659
- return true;
1660
- }
1661
- return false;
1662
- }
1663
- async function hasGroupGrant(ctx, args) {
1664
- if (args.groupIds.length === 0) {
1665
- return false;
1666
- }
1667
- for (const groupId of args.groupIds) {
1668
- const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndGroup(ctx, args.topic._id, groupId);
1669
- if (grants.some(
1670
- (grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
1671
- args.topic.visibility,
1672
- grant.source
1673
- )
1674
- )) {
1675
- return true;
1676
- }
1677
- }
1678
- return false;
1679
- }
1680
- function isExternalPrincipal(_ctx, _args) {
1681
- return false;
1682
- }
1683
- async function evaluateTopicAccessDetailed(ctx, args) {
1684
- if (args.legacyUserId) {
1685
- return {
1686
- hasAccess: true,
1687
- isAdmin: false,
1688
- isOwner: false,
1689
- isShared: false,
1690
- hasGrant: true,
1691
- isFirmVisible: true,
1692
- isExternalVisible: false,
1693
- isPublicVisible: false,
1694
- isTenantScopeMatch: true,
1695
- isWorkspaceScopeMatch: true,
1696
- isPrincipalExternal: false
1697
- };
1698
- }
1699
- const topic = await resolveAccessControlAppResolvers().getProject(
1700
- ctx,
1701
- args.topicId
1702
- );
1703
- if (!topic) {
1704
- return {
1705
- hasAccess: false,
1706
- isAdmin: false,
1707
- isOwner: false,
1708
- isShared: false,
1709
- hasGrant: false,
1710
- isFirmVisible: false,
1711
- isExternalVisible: false,
1712
- isPublicVisible: false,
1713
- isTenantScopeMatch: false,
1714
- isWorkspaceScopeMatch: false,
1715
- isPrincipalExternal: false
1716
- };
1717
- }
1718
- const { principalContext, legacyUserId } = args;
1719
- const userIsAdmin = principalContext.isPlatformAdmin;
1720
- const isOwner = topic.ownerId === legacyUserId;
1721
- const isShared = (topic.sharedWith ?? []).includes(legacyUserId);
1722
- const principalIsExternal = await isExternalPrincipal(ctx, {
1723
- groupIds: principalContext.groupIds,
1724
- topicTenantId: topic.tenantId,
1725
- topicWorkspaceId: topic.workspaceId
1726
- });
1727
- const hasPrincipalGrantResult = await hasPrincipalGrant(ctx, {
1728
- topic,
1729
- principalId: principalContext.principalId,
1730
- principalIsExternal
1731
- });
1732
- const hasGroupGrantResult = await hasGroupGrant(ctx, {
1733
- topic,
1734
- groupIds: principalContext.groupIds
1735
- });
1736
- const hasGrant = isShared || hasPrincipalGrantResult || hasGroupGrantResult;
1737
- const legacyUnscoped = isLegacyUnscopedTopic(topic);
1738
- const tenantScopeMatch = isTopicInPrincipalTenant(
1739
- topic,
1740
- principalContext.tenantId
1741
- );
1742
- const workspaceScopeMatch = isTopicInPrincipalWorkspace(
1743
- topic,
1744
- principalContext.workspaceId
1745
- );
1746
- const isPublicVisible = topic.visibility === "public";
1747
- const isFirmVisible = topic.visibility === "firm" && !legacyUnscoped && tenantScopeMatch && workspaceScopeMatch && !principalIsExternal;
1748
- const hasScopedGrant = hasGrant && (legacyUnscoped || tenantScopeMatch && workspaceScopeMatch);
1749
- const isExternalVisible = topic.visibility === "external" && hasScopedGrant;
1750
- const hasAccess = userIsAdmin || isOwner || hasScopedGrant || isPublicVisible || isFirmVisible;
1751
- return {
1752
- hasAccess,
1753
- isAdmin: userIsAdmin,
1754
- isOwner,
1755
- isShared,
1756
- hasGrant,
1757
- isFirmVisible,
1758
- isExternalVisible,
1759
- isPublicVisible,
1760
- isTenantScopeMatch: tenantScopeMatch,
1761
- isWorkspaceScopeMatch: workspaceScopeMatch,
1762
- isPrincipalExternal: principalIsExternal
1763
- };
1764
- }
1765
- async function checkTopicAccessDetailed(ctx, topicId, userId) {
1766
- const principalContext = await resolvePrincipalContext(ctx, userId);
1767
- return evaluateTopicAccessDetailed(ctx, {
1768
- topicId,
1769
- legacyUserId: userId,
1770
- principalContext
1771
- });
1772
- }
1773
- async function checkTopicAccess(ctx, topicId, userId) {
1774
- const result = await checkTopicAccessDetailed(ctx, topicId, userId);
1775
- return result.hasAccess;
1776
- }
1777
- async function checkScopeAccess(ctx, scopeId, userId) {
1778
- try {
1779
- const topic = await ctx.db.get(scopeId);
1780
- if (topic && topic.name !== void 0 && topic.type !== void 0) {
1781
- return true;
1782
- }
1783
- } catch {
1784
- }
1785
- try {
1786
- return await checkTopicAccess(ctx, scopeId, userId);
1787
- } catch {
1788
- return false;
1789
- }
1790
- }
1791
- async function requireTopicAccess(ctx, topicId, userId) {
1792
- const hasAccess = await checkTopicAccess(ctx, topicId, userId);
1793
- if (!hasAccess) {
1794
- throw new Error(
1795
- "Access denied: You don't have permission to access this topic"
1796
- );
1797
- }
1798
- }
1799
- var checkProjectAccess = checkTopicAccess;
1800
- var requireProjectAccess = requireTopicAccess;
1801
- async function getAccessibleTopicIds(ctx, userId) {
1802
- const principalContext = await resolvePrincipalContext(ctx, userId);
1803
- if (principalContext.isPlatformAdmin) {
1804
- const allTopics2 = await resolveAccessControlAppResolvers().listTopics(ctx);
1805
- return new Set(allTopics2.map((topic) => topic._id));
1806
- }
1807
- const topicIds = /* @__PURE__ */ new Set();
1808
- const ownedTopics = await resolveAccessControlAppResolvers().listTopicsByOwner(ctx, userId);
1809
- for (const topic of ownedTopics) {
1810
- topicIds.add(topic._id);
1811
- }
1812
- const publicTopics = await resolveAccessControlAppResolvers().listTopicsByVisibility(ctx, "public");
1813
- for (const topic of publicTopics) {
1814
- topicIds.add(topic._id);
1815
- }
1816
- const principalIsExternal = await isExternalPrincipal(ctx, {
1817
- groupIds: principalContext.groupIds,
1818
- topicTenantId: principalContext.tenantId ?? void 0,
1819
- topicWorkspaceId: principalContext.workspaceId ?? void 0
1820
- });
1821
- if (!principalIsExternal) {
1822
- const firmTopics = await resolveAccessControlAppResolvers().listTopicsByVisibility(ctx, "firm");
1823
- for (const topic of firmTopics) {
1824
- if (isTopicInPrincipalTenant(topic, principalContext.tenantId) && isTopicInPrincipalWorkspace(topic, principalContext.workspaceId)) {
1825
- topicIds.add(topic._id);
1826
- }
1827
- }
1828
- }
1829
- const directGrants = await resolveAccessControlAppResolvers().listProjectGrantsByPrincipalStatus(
1830
- ctx,
1831
- principalContext.principalId,
1832
- "active"
1833
- );
1834
- for (const grant of directGrants) {
1835
- if (!isGrantActive(grant)) {
1836
- continue;
1837
- }
1838
- const topic = await resolveAccessControlAppResolvers().getProject(
1839
- ctx,
1840
- grant.projectId
1841
- );
1842
- if (!topic) {
1843
- continue;
1844
- }
1845
- if (!isLegacyUnscopedTopic(topic)) {
1846
- if (!isTopicInPrincipalTenant(topic, principalContext.tenantId)) {
1847
- continue;
1848
- }
1849
- if (!isTopicInPrincipalWorkspace(topic, principalContext.workspaceId)) {
1850
- continue;
1851
- }
1852
- }
1853
- if (!isGrantScopeAlignedToTopic(topic, grant)) {
1854
- continue;
1855
- }
1856
- if (!isGrantSourceAllowedForVisibility(topic.visibility, grant.source)) {
1857
- continue;
1858
- }
1859
- if (principalIsExternal && topic.visibility !== "public" && grant.source !== "external_share") {
1860
- continue;
1861
- }
1862
- topicIds.add(grant.projectId);
1863
- }
1864
- const allTopics = await resolveAccessControlAppResolvers().listTopics(ctx);
1865
- for (const topic of allTopics) {
1866
- if ((topic.sharedWith ?? []).includes(userId) && (isLegacyUnscopedTopic(topic) || isTopicInPrincipalTenant(topic, principalContext.tenantId) && isTopicInPrincipalWorkspace(topic, principalContext.workspaceId))) {
1867
- topicIds.add(topic._id);
1868
- }
1869
- }
1870
- return topicIds;
1871
- }
1872
- var getAccessibleProjectIds = getAccessibleTopicIds;
1873
- var permissiveReturn = v.optional(v.any());
1874
- var looseJsonObject = v.record(v.string(), v.any());
1875
- var looseJsonArray = v.array(v.any());
1876
- v.union(
1877
- v.string(),
1878
- v.number(),
1879
- v.boolean(),
1880
- v.null(),
1881
- looseJsonObject,
1882
- looseJsonArray
1883
- );
1884
- var api2 = anyApi;
34
+ var api = anyApi;
1885
35
  componentsGeneric();
1886
36
  var internal = anyApi;
1887
37
  var internalAction = internalActionGeneric;
@@ -1899,48 +49,48 @@ __export(resolvers_exports, {
1899
49
  });
1900
50
 
1901
51
  // src/topicProjectOverlay.ts
1902
- var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
1903
- function readNonEmptyString2(value) {
52
+ var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
53
+ function readNonEmptyString(value) {
1904
54
  if (typeof value !== "string") {
1905
55
  return;
1906
56
  }
1907
57
  const normalized = value.trim();
1908
58
  return normalized.length > 0 ? normalized : void 0;
1909
59
  }
1910
- function readStringArray2(value) {
60
+ function readStringArray(value) {
1911
61
  if (!Array.isArray(value)) {
1912
62
  return [];
1913
63
  }
1914
- return value.map((entry) => readNonEmptyString2(entry)).filter((entry) => Boolean(entry));
64
+ return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
1915
65
  }
1916
- function readMetadata2(topic) {
66
+ function readMetadata(topic) {
1917
67
  return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
1918
68
  }
1919
- function readLegacyProjectId2(value) {
69
+ function readLegacyProjectId(value) {
1920
70
  if (!value) {
1921
71
  return;
1922
72
  }
1923
- return readNonEmptyString2(value[LEGACY_SCOPE_FIELD2]);
73
+ return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
1924
74
  }
1925
- function coerceVisibility2(value) {
75
+ function coerceVisibility(value) {
1926
76
  return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
1927
77
  }
1928
- function coerceStatus2(value) {
78
+ function coerceStatus(value) {
1929
79
  return value === "active" || value === "archived" || value === "watching" ? value : void 0;
1930
80
  }
1931
- function mapProjectType2(topic, metadata) {
1932
- const explicit = readNonEmptyString2(metadata.projectType);
81
+ function mapProjectType(topic, metadata) {
82
+ const explicit = readNonEmptyString(metadata.projectType);
1933
83
  if (explicit) {
1934
84
  return explicit;
1935
85
  }
1936
86
  if (topic.type === "theme") {
1937
87
  return "thematic";
1938
88
  }
1939
- return readNonEmptyString2(topic.type) || "general";
89
+ return readNonEmptyString(topic.type) || "general";
1940
90
  }
1941
- function isProjectLikeTopic2(topic) {
1942
- const metadata = readMetadata2(topic);
1943
- return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId2(topic) !== void 0 || readNonEmptyString2(metadata.projectType) !== void 0;
91
+ function isProjectLikeTopic(topic) {
92
+ const metadata = readMetadata(topic);
93
+ return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
1944
94
  }
1945
95
  function isMissingLucernChildComponentError(error) {
1946
96
  const message = error instanceof Error ? error.message : String(error);
@@ -1948,7 +98,7 @@ function isMissingLucernChildComponentError(error) {
1948
98
  'Child component ComponentName(Identifier("lucern")) not found'
1949
99
  ) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
1950
100
  }
1951
- async function resolveTopicDoc2(ctx, scopeId) {
101
+ async function resolveTopicDoc(ctx, scopeId) {
1952
102
  if (ctx?.db && typeof ctx.db.get === "function") {
1953
103
  try {
1954
104
  const directTopic = await ctx.db.get(scopeId);
@@ -1962,7 +112,7 @@ async function resolveTopicDoc2(ctx, scopeId) {
1962
112
  return null;
1963
113
  }
1964
114
  try {
1965
- const topic = await ctx.runQuery(api2.topics.get, {
115
+ const topic = await ctx.runQuery(api.topics.get, {
1966
116
  id: String(scopeId)
1967
117
  });
1968
118
  if (topic?.name !== void 0 && topic?.type !== void 0) {
@@ -1971,7 +121,7 @@ async function resolveTopicDoc2(ctx, scopeId) {
1971
121
  } catch {
1972
122
  }
1973
123
  try {
1974
- const topic = await ctx.runQuery(api2.topics.getByLegacyScopeId, {
124
+ const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
1975
125
  projectId: String(scopeId)
1976
126
  });
1977
127
  if (topic?.name !== void 0 && topic?.type !== void 0) {
@@ -1981,14 +131,14 @@ async function resolveTopicDoc2(ctx, scopeId) {
1981
131
  }
1982
132
  return null;
1983
133
  }
1984
- function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1985
- const metadata = readMetadata2(topic);
134
+ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
135
+ const metadata = readMetadata(topic);
1986
136
  const topicId = String(topic._id);
1987
- const legacyProjectId = readLegacyProjectId2(topic) || readLegacyProjectId2(metadata) || readNonEmptyString2(metadata.legacyProjectId);
137
+ const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
1988
138
  const storageProjectId = legacyProjectId || topicId;
1989
139
  const outwardId = idMode === "topic" ? topicId : storageProjectId;
1990
- const visibility = coerceVisibility2(topic.visibility) || coerceVisibility2(metadata.visibility) || "private";
1991
- const status = coerceStatus2(topic.status) || coerceStatus2(metadata.status) || "active";
140
+ const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
141
+ const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
1992
142
  const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
1993
143
  const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
1994
144
  return {
@@ -1998,16 +148,16 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
1998
148
  topicId,
1999
149
  storageProjectId,
2000
150
  legacyProjectId,
2001
- name: readNonEmptyString2(topic.name) || "Untitled Theme",
2002
- type: mapProjectType2(topic, metadata),
2003
- description: readNonEmptyString2(topic.description),
2004
- ownerId: readNonEmptyString2(metadata.ownerId) || readNonEmptyString2(topic.createdBy) || "system",
2005
- sharedWith: readStringArray2(metadata.sharedWith),
151
+ name: readNonEmptyString(topic.name) || "Untitled Theme",
152
+ type: mapProjectType(topic, metadata),
153
+ description: readNonEmptyString(topic.description),
154
+ ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
155
+ sharedWith: readStringArray(metadata.sharedWith),
2006
156
  visibility,
2007
- tenantId: readNonEmptyString2(topic.tenantId) || readNonEmptyString2(metadata.tenantId),
2008
- workspaceId: readNonEmptyString2(topic.workspaceId) || readNonEmptyString2(metadata.workspaceId),
157
+ tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
158
+ workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
2009
159
  status,
2010
- tags: readStringArray2(metadata.tags),
160
+ tags: readStringArray(metadata.tags),
2011
161
  chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
2012
162
  artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
2013
163
  lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
@@ -2016,17 +166,17 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
2016
166
  updatedAt
2017
167
  };
2018
168
  }
2019
- async function resolveTopicProjectOverlay2(ctx, scopeId, options = {}) {
2020
- const topic = await resolveTopicDoc2(ctx, scopeId);
169
+ async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
170
+ const topic = await resolveTopicDoc(ctx, scopeId);
2021
171
  if (!topic) {
2022
172
  return null;
2023
173
  }
2024
- if (options.projectLikeOnly !== false && !isProjectLikeTopic2(topic)) {
174
+ if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
2025
175
  return null;
2026
176
  }
2027
- return materializeTopicProjectOverlay2(topic, options.idMode);
177
+ return materializeTopicProjectOverlay(topic, options.idMode);
2028
178
  }
2029
- async function listTopicProjectOverlays2(ctx, options = {}) {
179
+ async function listTopicProjectOverlays(ctx, options = {}) {
2030
180
  let allTopics = [];
2031
181
  if (ctx?.db?.query && typeof ctx.db.query === "function") {
2032
182
  try {
@@ -2036,18 +186,18 @@ async function listTopicProjectOverlays2(ctx, options = {}) {
2036
186
  }
2037
187
  }
2038
188
  if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
2039
- allTopics = (await ctx.runQuery(api2.topics.list, {}) ?? []) || [];
189
+ allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
2040
190
  }
2041
191
  return allTopics.filter(
2042
- (topic) => options.projectLikeOnly === false || isProjectLikeTopic2(topic)
2043
- ).map((topic) => materializeTopicProjectOverlay2(topic, options.idMode));
192
+ (topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
193
+ ).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
2044
194
  }
2045
195
  async function patchTopicProjectOverlay(ctx, scopeId, value) {
2046
- const topic = await resolveTopicDoc2(ctx, scopeId);
196
+ const topic = await resolveTopicDoc(ctx, scopeId);
2047
197
  if (!topic) {
2048
198
  return null;
2049
199
  }
2050
- const nextMetadata = { ...readMetadata2(topic) };
200
+ const nextMetadata = { ...readMetadata(topic) };
2051
201
  const patch = {};
2052
202
  const topicUpdateArgs = {
2053
203
  id: String(topic._id)
@@ -2072,7 +222,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
2072
222
  `patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
2073
223
  );
2074
224
  case "status": {
2075
- const status = coerceStatus2(rawValue);
225
+ const status = coerceStatus(rawValue);
2076
226
  if (status) {
2077
227
  patch.status = status;
2078
228
  topicUpdateArgs.status = status;
@@ -2080,7 +230,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
2080
230
  break;
2081
231
  }
2082
232
  case "visibility": {
2083
- const visibility = coerceVisibility2(rawValue);
233
+ const visibility = coerceVisibility(rawValue);
2084
234
  if (visibility) {
2085
235
  patch.visibility = visibility;
2086
236
  topicUpdateArgs.visibility = visibility;
@@ -2088,7 +238,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
2088
238
  break;
2089
239
  }
2090
240
  case "type": {
2091
- const projectType = readNonEmptyString2(rawValue);
241
+ const projectType = readNonEmptyString(rawValue);
2092
242
  if (projectType) {
2093
243
  nextMetadata.projectType = projectType;
2094
244
  } else {
@@ -2112,7 +262,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
2112
262
  topicUpdateArgs.metadata = nextMetadata;
2113
263
  if (typeof ctx.runMutation === "function") {
2114
264
  try {
2115
- await ctx.runMutation(api2.topics.update, topicUpdateArgs);
265
+ await ctx.runMutation(api.topics.update, topicUpdateArgs);
2116
266
  } catch (error) {
2117
267
  if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
2118
268
  throw error;
@@ -2126,7 +276,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
2126
276
  "Cannot patch topic without component adapter (ctx.runMutation unavailable)"
2127
277
  );
2128
278
  }
2129
- return materializeTopicProjectOverlay2(
279
+ return materializeTopicProjectOverlay(
2130
280
  {
2131
281
  ...topic,
2132
282
  ...patch,
@@ -2159,10 +309,10 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
2159
309
  });
2160
310
  }
2161
311
  }
2162
- function defaultResolvers2() {
312
+ function defaultResolvers() {
2163
313
  return {
2164
314
  async getProject(ctx, projectId) {
2165
- return await resolveTopicProjectOverlay2(ctx, projectId, {
315
+ return await resolveTopicProjectOverlay(ctx, projectId, {
2166
316
  idMode: "legacy",
2167
317
  projectLikeOnly: false
2168
318
  });
@@ -2171,7 +321,7 @@ function defaultResolvers2() {
2171
321
  await patchProjectWithTolerance(ctx, projectId, value);
2172
322
  },
2173
323
  async listTopics(ctx) {
2174
- return await listTopicProjectOverlays2(ctx, {
324
+ return await listTopicProjectOverlays(ctx, {
2175
325
  idMode: "legacy"
2176
326
  });
2177
327
  },
@@ -2180,20 +330,20 @@ function defaultResolvers2() {
2180
330
  }
2181
331
  };
2182
332
  }
2183
- var resolverOverrides2 = {};
333
+ var resolverOverrides = {};
2184
334
  function configureGraphPrimitivesAppResolvers(overrides) {
2185
- resolverOverrides2 = {
2186
- ...resolverOverrides2,
335
+ resolverOverrides = {
336
+ ...resolverOverrides,
2187
337
  ...overrides
2188
338
  };
2189
339
  }
2190
340
  function resetGraphPrimitivesAppResolvers() {
2191
- resolverOverrides2 = {};
341
+ resolverOverrides = {};
2192
342
  }
2193
343
  function resolveGraphPrimitivesAppResolvers(_ctx) {
2194
344
  return {
2195
- ...defaultResolvers2(),
2196
- ...resolverOverrides2
345
+ ...defaultResolvers(),
346
+ ...resolverOverrides
2197
347
  };
2198
348
  }
2199
349
 
@@ -2204,17 +354,17 @@ __export(topicScope_exports, {
2204
354
  readMaterializedTopicTableId: () => readMaterializedTopicTableId,
2205
355
  resolveTopicProjectScope: () => resolveTopicProjectScope
2206
356
  });
2207
- var LEGACY_SCOPE_FIELD3 = "graphScopeProjectId";
357
+ var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
2208
358
  function asMappedProjectId(topic) {
2209
359
  if (!topic) {
2210
360
  return;
2211
361
  }
2212
- const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD3]);
362
+ const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD2]);
2213
363
  if (directLegacyProjectId) {
2214
364
  return directLegacyProjectId;
2215
365
  }
2216
366
  const metadata = topic.metadata || {};
2217
- const candidate = metadata[LEGACY_SCOPE_FIELD3] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
367
+ const candidate = metadata[LEGACY_SCOPE_FIELD2] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
2218
368
  return candidate ? candidate : void 0;
2219
369
  }
2220
370
  function normalizeScopeValue(value) {
@@ -2243,7 +393,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
2243
393
  try {
2244
394
  return await ctx.db.query("topics").withIndex(
2245
395
  "by_graph_scope_project",
2246
- (q) => q.eq(LEGACY_SCOPE_FIELD3, scopeId)
396
+ (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
2247
397
  ).collect();
2248
398
  } catch {
2249
399
  const topics = await ctx.db.query("topics").collect();
@@ -2259,7 +409,7 @@ async function tryResolveHostTopicById(ctx, topicId) {
2259
409
  return null;
2260
410
  }
2261
411
  try {
2262
- return await ctx.runQuery(api2.topics.get, {
412
+ return await ctx.runQuery(api.topics.get, {
2263
413
  id: topicId
2264
414
  }) ?? null;
2265
415
  } catch {
@@ -2271,7 +421,7 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
2271
421
  return null;
2272
422
  }
2273
423
  try {
2274
- return await ctx.runQuery(api2.topics.getByLegacyScopeId, {
424
+ return await ctx.runQuery(api.topics.getByLegacyScopeId, {
2275
425
  projectId: legacyScopeId
2276
426
  }) ?? null;
2277
427
  } catch {
@@ -2516,12 +666,12 @@ var getGlobalBeliefHealth = query({
2516
666
  const allProjects = await resolveGraphPrimitivesAppResolvers().listTopics(ctx);
2517
667
  const accessibleProjectIds = await getAccessibleProjectIds(ctx, clerkId);
2518
668
  const accessibleProjects = allProjects.filter(
2519
- (project2) => accessibleProjectIds.has(project2._id)
669
+ (project3) => accessibleProjectIds.has(project3._id)
2520
670
  );
2521
671
  const allResults = [];
2522
- for (const project2 of accessibleProjects.slice(0, 20)) {
672
+ for (const project3 of accessibleProjects.slice(0, 20)) {
2523
673
  const scope = await resolveTopicProjectScope(ctx, {
2524
- projectId: String(project2._id)
674
+ projectId: String(project3._id)
2525
675
  }).catch(() => null);
2526
676
  if (!scope) {
2527
677
  continue;
@@ -2547,8 +697,8 @@ var getGlobalBeliefHealth = query({
2547
697
  });
2548
698
  if (priorityRank[schedule.priority] >= minRank) {
2549
699
  allResults.push({
2550
- projectId: project2._id,
2551
- projectName: project2.name,
700
+ projectId: project3._id,
701
+ projectName: project3.name,
2552
702
  beliefId: belief._id,
2553
703
  beliefText: belief.canonicalText,
2554
704
  confidence,
@@ -2743,8 +893,6 @@ async function resolveScopeSoft(ctx, args) {
2743
893
  ...projectId ? { projectId } : {}
2744
894
  };
2745
895
  }
2746
-
2747
- // src/beliefEvidenceLinks.ts
2748
896
  var beliefIdUnion = v.id("epistemicNodes");
2749
897
  var insightIdUnion = v.id("epistemicNodes");
2750
898
  var suggestionStatusValidator = v.union(
@@ -3377,7 +1525,7 @@ var getLinkedBeliefsForInsight = query({
3377
1525
  // src/beliefLifecycle.ts
3378
1526
  var beliefLifecycle_exports = {};
3379
1527
  __export(beliefLifecycle_exports, {
3380
- hasResolvedPredictionOutcome: () => hasResolvedPredictionOutcome2,
1528
+ hasResolvedPredictionOutcome: () => hasResolvedPredictionOutcome,
3381
1529
  isBeliefLifecycleStatus: () => isBeliefLifecycleStatus,
3382
1530
  isPreValidationBeliefStatus: () => isPreValidationBeliefStatus,
3383
1531
  isPropagationEligibleBeliefStatus: () => isPropagationEligibleBeliefStatus,
@@ -3401,7 +1549,7 @@ var RESOLVED_PREDICTION_OUTCOMES = [
3401
1549
  function isBeliefLifecycleStatus(value) {
3402
1550
  return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
3403
1551
  }
3404
- function normalizeBeliefConfidence2(confidence) {
1552
+ function normalizeBeliefConfidence(confidence) {
3405
1553
  if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
3406
1554
  return null;
3407
1555
  }
@@ -3414,13 +1562,13 @@ function normalizeBeliefConfidence2(confidence) {
3414
1562
  return null;
3415
1563
  }
3416
1564
  function isResolvedByConfidence(confidence) {
3417
- const normalized = normalizeBeliefConfidence2(confidence);
1565
+ const normalized = normalizeBeliefConfidence(confidence);
3418
1566
  if (normalized === null) {
3419
1567
  return false;
3420
1568
  }
3421
1569
  return normalized <= 0 || normalized >= 1;
3422
1570
  }
3423
- function hasResolvedPredictionOutcome2(predictionMeta) {
1571
+ function hasResolvedPredictionOutcome(predictionMeta) {
3424
1572
  if (!predictionMeta || typeof predictionMeta !== "object") {
3425
1573
  return false;
3426
1574
  }
@@ -3434,10 +1582,10 @@ function shouldTreatBeliefAsFact(opts) {
3434
1582
  if (isResolvedByConfidence(opts.confidence)) {
3435
1583
  return true;
3436
1584
  }
3437
- if (hasResolvedPredictionOutcome2(opts.predictionMeta)) {
1585
+ if (hasResolvedPredictionOutcome(opts.predictionMeta)) {
3438
1586
  return true;
3439
1587
  }
3440
- if (hasResolvedPredictionOutcome2(getPredictionMetaFromMetadata(opts.metadata))) {
1588
+ if (hasResolvedPredictionOutcome(getPredictionMetaFromMetadata(opts.metadata))) {
3441
1589
  return true;
3442
1590
  }
3443
1591
  return false;
@@ -3448,7 +1596,7 @@ function resolveBeliefLifecycleStatus(opts) {
3448
1596
  }
3449
1597
  const direct = opts.beliefStatus;
3450
1598
  if (isBeliefLifecycleStatus(direct)) {
3451
- const normalized = normalizeBeliefConfidence2(opts.confidence);
1599
+ const normalized = normalizeBeliefConfidence(opts.confidence);
3452
1600
  if (normalized !== null && isPreValidationBeliefStatus(direct)) {
3453
1601
  return "belief";
3454
1602
  }
@@ -3456,7 +1604,7 @@ function resolveBeliefLifecycleStatus(opts) {
3456
1604
  }
3457
1605
  const metaStatus = opts.metadata?.beliefStatus;
3458
1606
  if (isBeliefLifecycleStatus(metaStatus)) {
3459
- const normalized = normalizeBeliefConfidence2(opts.confidence);
1607
+ const normalized = normalizeBeliefConfidence(opts.confidence);
3460
1608
  if (normalized !== null && isPreValidationBeliefStatus(metaStatus)) {
3461
1609
  return "belief";
3462
1610
  }
@@ -4037,8 +2185,6 @@ var containsPropagationSpec = {
4037
2185
  operator: () => null,
4038
2186
  description: "Structural containment only. Traversed for explicit semantics, but it never propagates opinions."
4039
2187
  };
4040
-
4041
- // src/edges/utils.ts
4042
2188
  function readEdgeMetadata(edge) {
4043
2189
  return {
4044
2190
  constraint: edge.constraint ?? void 0,
@@ -4115,8 +2261,6 @@ var contradictsPropagationSpec = {
4115
2261
  },
4116
2262
  description: "Legacy contradiction edges move negative pressure in either direction, but never beyond one hop."
4117
2263
  };
4118
-
4119
- // src/edges/dependsOn.ts
4120
2264
  var dependsOnPropagationSpec = {
4121
2265
  edgeType: "depends_on",
4122
2266
  direction: "incoming",
@@ -4132,8 +2276,18 @@ var dependsOnPropagationSpec = {
4132
2276
  if (metadata.conditionalA && metadata.conditionalNotA) {
4133
2277
  const deducedOpinion = conditionalDeduction(
4134
2278
  dampedSource,
4135
- metadata.conditionalA,
4136
- metadata.conditionalNotA,
2279
+ mkOpinion(
2280
+ metadata.conditionalA.b,
2281
+ metadata.conditionalA.d,
2282
+ metadata.conditionalA.u,
2283
+ metadata.conditionalA.a
2284
+ ),
2285
+ mkOpinion(
2286
+ metadata.conditionalNotA.b,
2287
+ metadata.conditionalNotA.d,
2288
+ metadata.conditionalNotA.u,
2289
+ metadata.conditionalNotA.a
2290
+ ),
4137
2291
  targetOpinion.a
4138
2292
  );
4139
2293
  return annotateRationale(
@@ -4706,14 +2860,6 @@ __export(entityBridge_exports, {
4706
2860
  getEvidenceForEntity: () => getEvidenceForEntity,
4707
2861
  linkEntityToBelief: () => linkEntityToBelief
4708
2862
  });
4709
-
4710
- // ../access-control/src/auth.ts
4711
- async function getCurrentUserId(ctx) {
4712
- const identity = await ctx.auth.getUserIdentity();
4713
- return identity?.subject ?? null;
4714
- }
4715
-
4716
- // src/entityBridge.ts
4717
2863
  var ENTITY_BRIDGE_EDGE_TYPES = [
4718
2864
  "contains",
4719
2865
  "evaluates",
@@ -5211,7 +3357,7 @@ async function resolveTopicOntologyInternal(ctx, topicId) {
5211
3357
  "by_ontologyId",
5212
3358
  (q) => q.eq("ontologyId", current?.ontologyId)
5213
3359
  ).collect();
5214
- const published = versions.filter((v21) => v21.status === "published").sort((a, b) => (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
3360
+ const published = versions.filter((v20) => v20.status === "published").sort((a, b) => (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
5215
3361
  const latestPublished = published[0] ?? null;
5216
3362
  return {
5217
3363
  ontologyId: ontologyDef._id,
@@ -5313,16 +3459,16 @@ function buildEntityTitle(canonicalText) {
5313
3459
  async function resolveCanonicalEntityScope(ctx, args) {
5314
3460
  const scope = await resolveTopicProjectScope(ctx, args);
5315
3461
  const topic = scope.topicId ? await ctx.db.get(scope.topicId) ?? null : null;
5316
- const project2 = scope.projectId !== void 0 ? await resolveGraphPrimitivesAppResolvers().getProject(
3462
+ const project3 = scope.projectId !== void 0 ? await resolveGraphPrimitivesAppResolvers().getProject(
5317
3463
  ctx,
5318
3464
  scope.projectId
5319
3465
  ) ?? null : null;
5320
- const tenantId = typeof topic?.tenantId === "string" && topic.tenantId.trim().length > 0 ? topic.tenantId.trim() : typeof project2?.tenantId === "string" && project2.tenantId.trim().length > 0 ? project2.tenantId.trim() : void 0;
3466
+ const tenantId = typeof topic?.tenantId === "string" && topic.tenantId.trim().length > 0 ? topic.tenantId.trim() : typeof project3?.tenantId === "string" && project3.tenantId.trim().length > 0 ? project3.tenantId.trim() : void 0;
5321
3467
  return {
5322
3468
  ...scope,
5323
3469
  tenantId,
5324
3470
  topic,
5325
- project: project2
3471
+ project: project3
5326
3472
  };
5327
3473
  }
5328
3474
  function matchesCanonicalEntityRecord(node, args) {
@@ -5980,323 +4126,6 @@ __export(epistemicBeliefs_exports, {
5980
4126
  updateStatus: () => updateStatus2,
5981
4127
  updateStatusInternal: () => updateStatusInternal
5982
4128
  });
5983
-
5984
- // ../access-control/src/audience.ts
5985
- var AUDIENCE_CLASS_RANK = {
5986
- public: 0,
5987
- restricted_external: 1,
5988
- internal: 2
5989
- };
5990
- function normalizeKey(key) {
5991
- return (key ?? "").trim().toLowerCase().replace(/[^a-z0-9:_-]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
5992
- }
5993
- function normalizeAudienceKey(key) {
5994
- return normalizeKey(key);
5995
- }
5996
- function classFromAudienceKey(audienceKey, fallback = "internal") {
5997
- const key = normalizeKey(audienceKey);
5998
- if (!key) {
5999
- return fallback;
6000
- }
6001
- if (key === "internal") {
6002
- return "internal";
6003
- }
6004
- if (key === "public") {
6005
- return "public";
6006
- }
6007
- if (key === "lp" || key === "external" || key === "client" || key === "partner" || key === "portfolio" || key === "network" || key === "restricted_external") {
6008
- return "restricted_external";
6009
- }
6010
- return fallback;
6011
- }
6012
- function canAudienceClassAccess(viewerClass, resourceClass) {
6013
- return AUDIENCE_CLASS_RANK[viewerClass] >= AUDIENCE_CLASS_RANK[resourceClass];
6014
- }
6015
-
6016
- // ../access-control/src/audienceRegistry.ts
6017
- var DEFAULT_AUDIENCES = [
6018
- {
6019
- audienceKey: "internal",
6020
- audienceLabel: "Internal",
6021
- audienceClass: "internal"
6022
- },
6023
- {
6024
- audienceKey: "lp",
6025
- audienceLabel: "Limited Partners",
6026
- audienceClass: "restricted_external"
6027
- },
6028
- {
6029
- audienceKey: "public",
6030
- audienceLabel: "Public",
6031
- audienceClass: "public"
6032
- }
6033
- ];
6034
- var AUDIENCE_CLASS_PRIORITY = {
6035
- internal: 0,
6036
- restricted_external: 1,
6037
- public: 2
6038
- };
6039
- function normalizeRegistryRow(row) {
6040
- return {
6041
- audienceKey: normalizeAudienceKey(row.audienceKey),
6042
- audienceLabel: row.audienceLabel,
6043
- audienceClass: row.audienceClass,
6044
- workspaceId: row.workspaceId
6045
- };
6046
- }
6047
- function dedupeRegistryRows(rows) {
6048
- const byKey = /* @__PURE__ */ new Map();
6049
- for (const row of rows) {
6050
- const key = normalizeAudienceKey(row.audienceKey);
6051
- if (!key) {
6052
- continue;
6053
- }
6054
- const existing = byKey.get(key);
6055
- const isWorkspaceScoped = row.workspaceId !== void 0;
6056
- const existingWorkspaceScoped = existing?.workspaceId !== void 0;
6057
- if (!existing || isWorkspaceScoped && !existingWorkspaceScoped) {
6058
- byKey.set(key, {
6059
- ...row,
6060
- audienceKey: key
6061
- });
6062
- }
6063
- }
6064
- const normalized = [...byKey.values()];
6065
- normalized.sort((a, b) => {
6066
- const classDelta = AUDIENCE_CLASS_PRIORITY[a.audienceClass] - AUDIENCE_CLASS_PRIORITY[b.audienceClass];
6067
- if (classDelta !== 0) {
6068
- return classDelta;
6069
- }
6070
- return a.audienceKey.localeCompare(b.audienceKey);
6071
- });
6072
- return normalized;
6073
- }
6074
- async function queryRegistryRows(ctx, args) {
6075
- if (!args.tenantId) {
6076
- return [...DEFAULT_AUDIENCES];
6077
- }
6078
- const rows = await ctx.db.query("platformAudiences").withIndex("by_tenantId", (q) => q.eq("tenantId", args.tenantId)).collect();
6079
- const workspaceIdString = args.workspaceId ? String(args.workspaceId) : null;
6080
- const tenantScoped = rows.filter((row) => row.status === "active");
6081
- const applicable = tenantScoped.filter((row) => {
6082
- if (!row.workspaceId) {
6083
- return true;
6084
- }
6085
- if (!workspaceIdString) {
6086
- return false;
6087
- }
6088
- return String(row.workspaceId) === workspaceIdString;
6089
- });
6090
- return dedupeRegistryRows([
6091
- ...DEFAULT_AUDIENCES,
6092
- ...applicable.map(
6093
- (row) => normalizeRegistryRow({
6094
- audienceKey: row.audienceKey,
6095
- audienceLabel: row.audienceLabel,
6096
- audienceClass: row.audienceClass,
6097
- workspaceId: row.workspaceId
6098
- })
6099
- )
6100
- ]);
6101
- }
6102
- async function listAudienceRegistryRows(ctx, args) {
6103
- return queryRegistryRows(ctx, args);
6104
- }
6105
-
6106
- // ../../packages/contracts/src/schema-helpers/enumValidation.ts
6107
- var BUILTIN_ENUM_FALLBACK = {
6108
- topic_type: /* @__PURE__ */ new Set([
6109
- "domain",
6110
- "theme",
6111
- "deal",
6112
- "strategy",
6113
- "constitution",
6114
- "project",
6115
- "portfolio",
6116
- "architecture",
6117
- "capability",
6118
- "runtime",
6119
- "interface",
6120
- "governance",
6121
- "operations",
6122
- "security",
6123
- "data"
6124
- ]),
6125
- branch_schema: /* @__PURE__ */ new Set(["pillar", "track", "dimension", "axis", "phase"]),
6126
- lens_perspective_type: /* @__PURE__ */ new Set([
6127
- "investigation",
6128
- "monitoring",
6129
- "analysis",
6130
- "comparison",
6131
- "taxonomy"
6132
- ]),
6133
- belief_type: /* @__PURE__ */ new Set([
6134
- "belief",
6135
- "hypothesis",
6136
- "principle",
6137
- "invariant",
6138
- "assumption",
6139
- "tenet",
6140
- "prior",
6141
- "preference",
6142
- "goal",
6143
- "forecast",
6144
- "decision",
6145
- "constraint",
6146
- "tradeoff",
6147
- "policy",
6148
- "implementation_choice",
6149
- "implementation_decision",
6150
- "interface_contract",
6151
- "migration_state",
6152
- "code_pattern",
6153
- "deprecation_notice"
6154
- ]),
6155
- edge_type: /* @__PURE__ */ new Set([
6156
- "supports",
6157
- "informs",
6158
- "depends_on",
6159
- "derived_from",
6160
- "contains",
6161
- "tests",
6162
- "supersedes",
6163
- "responds_to",
6164
- "belongs_to",
6165
- "relates_to_thesis",
6166
- "works_at",
6167
- "invested_in",
6168
- "competes_with",
6169
- "participates_in",
6170
- "founded_by",
6171
- "evaluates",
6172
- "performs",
6173
- "function_in",
6174
- "impacts",
6175
- "raised_from",
6176
- "mentioned_in",
6177
- "perspective_on",
6178
- "plays_theme"
6179
- ]),
6180
- worktree_type: /* @__PURE__ */ new Set([
6181
- "belief_test",
6182
- "existential",
6183
- "contradiction",
6184
- "refinement",
6185
- "coverage",
6186
- "discovery",
6187
- "clarification",
6188
- "confirmation"
6189
- ]),
6190
- worktree_phase: /* @__PURE__ */ new Set([
6191
- "cluster_mapping",
6192
- "hypothesis_formation",
6193
- "question_generation",
6194
- "evidence_collection",
6195
- "synthesis",
6196
- "decision",
6197
- "retrospective"
6198
- ]),
6199
- activity_type: /* @__PURE__ */ new Set([
6200
- "create",
6201
- "update",
6202
- "review",
6203
- "merge",
6204
- "archive",
6205
- "comment",
6206
- "status_change",
6207
- "evidence_added",
6208
- "question_added"
6209
- ])
6210
- };
6211
- function normalizeEnumValue(value) {
6212
- return value.trim().toLowerCase();
6213
- }
6214
- async function validateSchemaEnumValue(_ctx, args) {
6215
- const normalized = normalizeEnumValue(args.value);
6216
- if (!normalized) {
6217
- return { valid: false, source: "none" };
6218
- }
6219
- if (BUILTIN_ENUM_FALLBACK[args.category].has(normalized)) {
6220
- return { valid: true, source: "builtin" };
6221
- }
6222
- return { valid: false, source: "none" };
6223
- }
6224
- async function assertSchemaEnumValue(ctx, args) {
6225
- if (typeof args.value !== "string") {
6226
- return;
6227
- }
6228
- const normalized = normalizeEnumValue(args.value);
6229
- if (!normalized) {
6230
- return;
6231
- }
6232
- const validation = await validateSchemaEnumValue(ctx, {
6233
- category: args.category,
6234
- value: normalized,
6235
- tenantId: args.tenantId
6236
- });
6237
- if (!validation.valid) {
6238
- const tenantHint = args.tenantId ? ` for tenant ${args.tenantId}` : "";
6239
- throw new Error(
6240
- `[${args.context}] Invalid value "${normalized}" for category "${args.category}"${tenantHint}. Add it to the contracts schema enum manifest before use.`
6241
- );
6242
- }
6243
- return normalized;
6244
- }
6245
-
6246
- // ../../packages/contracts/src/schema-helpers/spine/tables/epistemicNodes.ts
6247
- var NODE_TYPES = [
6248
- "decision",
6249
- "belief",
6250
- "question",
6251
- "theme",
6252
- "deal",
6253
- "topic",
6254
- "claim",
6255
- "evidence",
6256
- "synthesis",
6257
- "answer",
6258
- "atomic_fact",
6259
- "excerpt",
6260
- "source",
6261
- "company",
6262
- "person",
6263
- "investor",
6264
- "function",
6265
- "value_chain"
6266
- ];
6267
- function isNodeType(value) {
6268
- return NODE_TYPES.includes(value);
6269
- }
6270
- function getLayerForNodeType(type) {
6271
- switch (type) {
6272
- case "decision":
6273
- return "L4";
6274
- case "belief":
6275
- case "question":
6276
- case "theme":
6277
- case "deal":
6278
- return "L3";
6279
- case "claim":
6280
- case "evidence":
6281
- case "synthesis":
6282
- case "answer":
6283
- return "L2";
6284
- case "atomic_fact":
6285
- case "excerpt":
6286
- case "source":
6287
- return "L1";
6288
- case "topic":
6289
- return "organizational";
6290
- case "company":
6291
- case "person":
6292
- case "investor":
6293
- case "function":
6294
- case "value_chain":
6295
- return "ontological";
6296
- }
6297
- }
6298
-
6299
- // src/workspaceIsolation.ts
6300
4129
  function normalizeScopeValue3(value) {
6301
4130
  if (typeof value !== "string") {
6302
4131
  return;
@@ -6453,16 +4282,17 @@ function resolveTraversalTargetNodeId(edge, direction) {
6453
4282
  }
6454
4283
  function readNodeOpinion(node) {
6455
4284
  const metadata = node.metadata ?? {};
6456
- return readOpinionFromRecord(
6457
- {
4285
+ try {
4286
+ return readOpinionFromRecord({
6458
4287
  ...metadata,
6459
4288
  opinion_b: node.opinion_b,
6460
4289
  opinion_d: node.opinion_d,
6461
4290
  opinion_u: node.opinion_u,
6462
4291
  opinion_a: node.opinion_a
6463
- },
6464
- { b: 0, d: 0, u: 1, a: 0.5 }
6465
- );
4292
+ });
4293
+ } catch {
4294
+ return mkOpinion(0, 0, 1, 0.5);
4295
+ }
6466
4296
  }
6467
4297
  async function collectConfidencePropagationDispatches(args) {
6468
4298
  const dispatchesByTargetId = /* @__PURE__ */ new Map();
@@ -6531,14 +4361,20 @@ async function collectConfidencePropagationDispatches(args) {
6531
4361
  if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
6532
4362
  continue;
6533
4363
  }
6534
- opinionCache.set(cacheKey, result.opinion);
4364
+ const projectedOpinion = mkOpinion(
4365
+ result.opinion.b,
4366
+ result.opinion.d,
4367
+ result.opinion.u,
4368
+ result.opinion.a
4369
+ );
4370
+ opinionCache.set(cacheKey, projectedOpinion);
6535
4371
  const existingDispatch = dispatchesByTargetId.get(cacheKey);
6536
4372
  dispatchesByTargetId.set(cacheKey, {
6537
4373
  targetNodeId,
6538
4374
  edgeType: spec.edgeType,
6539
4375
  traversedDirection: direction,
6540
4376
  weight: edge.weight ?? 1,
6541
- opinion: result.opinion,
4377
+ opinion: projectedOpinion,
6542
4378
  operator: result.operator,
6543
4379
  rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
6544
4380
  hop: nextHop
@@ -6546,7 +4382,7 @@ async function collectConfidencePropagationDispatches(args) {
6546
4382
  if (canContinueTransitively(spec, nextHop)) {
6547
4383
  queue.push({
6548
4384
  nodeId: targetNodeId,
6549
- opinion: result.opinion,
4385
+ opinion: projectedOpinion,
6550
4386
  hop: nextHop,
6551
4387
  visitedNodeIds: /* @__PURE__ */ new Set([
6552
4388
  ...state.visitedNodeIds,
@@ -6673,7 +4509,7 @@ function throwStructuredMutationError2(args) {
6673
4509
  function readFiniteNumber(value) {
6674
4510
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
6675
4511
  }
6676
- function clamp014(value) {
4512
+ function clamp01(value) {
6677
4513
  return Math.max(0, Math.min(1, value));
6678
4514
  }
6679
4515
  function assertBaseRateInRange(baseRate, field = "baseRate") {
@@ -6723,20 +4559,14 @@ function deriveSyntheticBackfillOpinion(source) {
6723
4559
  const uncertainty = readFiniteNumber(source.opinion_u) ?? readFiniteNumber(source.uncertainty);
6724
4560
  const baseRate = readFiniteNumber(source.opinion_a) ?? readFiniteNumber(source.baseRate);
6725
4561
  if (belief !== void 0 || disbelief !== void 0 || uncertainty !== void 0 || baseRate !== void 0) {
6726
- return readOpinionFromRecord(source, {
6727
- b: 0,
6728
- d: 0,
6729
- u: 1,
6730
- a: 0.5
6731
- });
4562
+ try {
4563
+ return readOpinionFromRecord(source);
4564
+ } catch {
4565
+ return mkOpinion(0, 0, 1, 0.5);
4566
+ }
6732
4567
  }
6733
- const confidence = clamp014(readFiniteNumber(source.confidence) ?? 0);
6734
- return {
6735
- b: confidence,
6736
- d: 1 - confidence,
6737
- u: 0,
6738
- a: 0.5
6739
- };
4568
+ const confidence = clamp01(readFiniteNumber(source.confidence) ?? 0);
4569
+ return mkOpinion(confidence, 1 - confidence, 0, 0.5);
6740
4570
  }
6741
4571
  function clampBeliefLimit(limit, fallback = DEFAULT_PROJECT_BELIEF_LIMIT) {
6742
4572
  if (!Number.isFinite(limit)) {
@@ -6751,16 +4581,17 @@ function readTupleContradictedFlag(value) {
6751
4581
  return typeof value === "boolean" ? value : void 0;
6752
4582
  }
6753
4583
  function readBeliefOpinionSnapshot(node, metadata) {
6754
- return readOpinionFromRecord(
6755
- {
4584
+ try {
4585
+ return readOpinionFromRecord({
6756
4586
  ...metadata,
6757
4587
  opinion_b: node.opinion_b,
6758
4588
  opinion_d: node.opinion_d,
6759
4589
  opinion_u: node.opinion_u,
6760
4590
  opinion_a: node.opinion_a
6761
- },
6762
- { b: 0, d: 0, u: 1, a: 0.5 }
6763
- );
4591
+ });
4592
+ } catch {
4593
+ return mkOpinion(0, 0, 1, 0.5);
4594
+ }
6764
4595
  }
6765
4596
  function deriveTupleContradictionSeverity(node) {
6766
4597
  const metadata = node.metadata || {};
@@ -7208,12 +5039,12 @@ var propagateConfidenceChange = internalMutation({
7208
5039
  },
7209
5040
  returns: permissiveReturn,
7210
5041
  handler: async (ctx, args) => {
7211
- const sourceOpinion = {
7212
- b: args.opinion_b,
7213
- d: args.opinion_d,
7214
- u: args.opinion_u,
7215
- a: args.opinion_a
7216
- };
5042
+ const sourceOpinion = mkOpinion(
5043
+ args.opinion_b,
5044
+ args.opinion_d,
5045
+ args.opinion_u,
5046
+ args.opinion_a
5047
+ );
7217
5048
  const sourceNode = await ctx.db.get(args.nodeId);
7218
5049
  const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
7219
5050
  ctx,
@@ -7320,7 +5151,7 @@ var create3 = mutation({
7320
5151
  expectedBy: v.optional(v.number())
7321
5152
  })
7322
5153
  ),
7323
- baseRate: v.number(),
5154
+ baseRate: v.optional(v.number()),
7324
5155
  metadata: v.optional(v.any())
7325
5156
  // Additional metadata including isConditional
7326
5157
  },
@@ -7351,7 +5182,7 @@ var create3 = mutation({
7351
5182
  );
7352
5183
  }
7353
5184
  const now = Date.now();
7354
- const baseRate = assertBaseRateInRange(args.baseRate);
5185
+ const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
7355
5186
  const initialBeliefStatus = args.worktreeId ? "hypothesis" : "assumption";
7356
5187
  const initialEpistemicStatus = args.worktreeId ? "hypothesis" : "assumption";
7357
5188
  const seedOpinion = {
@@ -7925,8 +5756,8 @@ var modulateConfidence = mutation({
7925
5756
  // d: evidence AGAINST [0,1]
7926
5757
  uncertainty: v.number(),
7927
5758
  // u: lack of evidence [0,1]
7928
- baseRate: v.optional(v.number()),
7929
- // a: prior probability [0,1], defaults to 0.5
5759
+ baseRate: v.number(),
5760
+ // a: prior probability [0,1]
7930
5761
  trigger: v.union(
7931
5762
  v.literal("evidence_added"),
7932
5763
  v.literal("evidence_removed"),
@@ -9077,7 +6908,7 @@ var internalCreate = internalMutation({
9077
6908
  args: {
9078
6909
  ...optionalBeliefScopeArgs,
9079
6910
  formulation: v.string(),
9080
- baseRate: v.number(),
6911
+ baseRate: v.optional(v.number()),
9081
6912
  confidence: v.optional(
9082
6913
  v.union(v.literal("high"), v.literal("medium"), v.literal("low"))
9083
6914
  ),
@@ -9113,7 +6944,7 @@ var internalCreate = internalMutation({
9113
6944
  returns: permissiveReturn,
9114
6945
  handler: async (ctx, args) => {
9115
6946
  const now = Date.now();
9116
- const baseRate = assertBaseRateInRange(args.baseRate);
6947
+ const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
9117
6948
  const scope = await resolveTopicProjectScope(ctx, {
9118
6949
  topicId: args.topicId,
9119
6950
  projectId: args.projectId
@@ -9362,15 +7193,15 @@ var backfillSyntheticOpinionHistory = internalMutation({
9362
7193
  skippedHasHistory++;
9363
7194
  continue;
9364
7195
  }
9365
- const opinion2 = deriveSyntheticBackfillOpinion(node);
7196
+ const opinion = deriveSyntheticBackfillOpinion(node);
9366
7197
  await ctx.db.insert(
9367
7198
  "beliefConfidence",
9368
7199
  buildBeliefConfidenceRow({
9369
7200
  beliefId: node._id,
9370
- belief: opinion2.b,
9371
- disbelief: opinion2.d,
9372
- uncertainty: opinion2.u,
9373
- baseRate: opinion2.a,
7201
+ belief: opinion.b,
7202
+ disbelief: opinion.d,
7203
+ uncertainty: opinion.u,
7204
+ baseRate: opinion.a,
9374
7205
  trigger: "backfill_synthetic",
9375
7206
  rationale: "LK-6 backfill: synthesized t0 from node-level opinion fields (no prior beliefConfidence row found).",
9376
7207
  assessedAt: readFiniteNumber(node.createdAt) ?? readFiniteNumber(node.updatedAt) ?? Date.now(),
@@ -11667,7 +9498,7 @@ var create4 = mutation({
11667
9498
  });
11668
9499
  await ctx.scheduler.runAfter(
11669
9500
  0,
11670
- api2.embeddingActions.generateEpistemicNodeEmbedding,
9501
+ api.embeddingActions.generateEpistemicNodeEmbedding,
11671
9502
  {
11672
9503
  nodeId,
11673
9504
  projectId: topicId,
@@ -11868,7 +9699,7 @@ var createInternal = internalMutation({
11868
9699
  });
11869
9700
  await ctx.scheduler.runAfter(
11870
9701
  0,
11871
- api2.embeddingActions.generateEpistemicNodeEmbedding,
9702
+ api.embeddingActions.generateEpistemicNodeEmbedding,
11872
9703
  {
11873
9704
  nodeId,
11874
9705
  projectId: topicId,
@@ -13498,6 +11329,7 @@ var create6 = mutation({
13498
11329
  sourceUrl: v.optional(v.string()),
13499
11330
  sourceQuestionId: v.optional(v.string()),
13500
11331
  userId: v.string(),
11332
+ rationale: v.string(),
13501
11333
  // Classification fields (from AI tools)
13502
11334
  methodology: v.optional(v.string()),
13503
11335
  informationAsymmetry: v.optional(v.string()),
@@ -13555,6 +11387,7 @@ var create6 = mutation({
13555
11387
  externalSourceType: args.externalSourceType,
13556
11388
  sourceUrl: args.sourceUrl,
13557
11389
  sourceQuestionId: args.sourceQuestionId,
11390
+ rationale: args.rationale,
13558
11391
  linkedBeliefNodeId: args.linkedBeliefNodeId,
13559
11392
  evidenceRelation: args.evidenceRelation,
13560
11393
  confidence: args.confidence,
@@ -13608,6 +11441,7 @@ var create6 = mutation({
13608
11441
  changedBy: args.userId,
13609
11442
  isAgent: false,
13610
11443
  projectId: scope.projectId,
11444
+ rationale: args.rationale,
13611
11445
  newState: {
13612
11446
  text: args.text.slice(0, 200),
13613
11447
  kind,
@@ -13892,21 +11726,21 @@ var internalGetByProject2 = internalQuery({
13892
11726
  return [];
13893
11727
  }
13894
11728
  const audienceMode = args.audienceMode ?? "internal";
13895
- const project2 = await resolveGraphPrimitivesAppResolvers().getProject(
11729
+ const project3 = await resolveGraphPrimitivesAppResolvers().getProject(
13896
11730
  ctx,
13897
11731
  scope.topicId ? String(scope.topicId) : scope.projectId
13898
11732
  );
13899
11733
  const registryRows = await listAudienceRegistryRows(ctx, {
13900
- tenantId: project2?.tenantId,
13901
- workspaceId: project2?.workspaceId
11734
+ tenantId: project3?.tenantId,
11735
+ workspaceId: project3?.workspaceId
13902
11736
  });
13903
11737
  const resolveAudienceClass = createEvidenceAudienceResolver(registryRows);
13904
11738
  const viewerClass = resolveAudienceClass(audienceMode, "public");
13905
11739
  const nodes = await getEvidenceNodesForScope(ctx, scope, { scanLimit });
13906
11740
  const workspaceScopedNodes = nodes.filter(
13907
11741
  (node) => nodeMatchesWorkspaceReasoningScope(node, {
13908
- tenantId: project2?.tenantId,
13909
- workspaceId: project2?.workspaceId
11742
+ tenantId: project3?.tenantId,
11743
+ workspaceId: project3?.workspaceId
13910
11744
  })
13911
11745
  );
13912
11746
  return workspaceScopedNodes.filter(
@@ -14014,6 +11848,7 @@ var internalCreate2 = internalMutation({
14014
11848
  sourceUrl: v.optional(v.string()),
14015
11849
  sourceQuestionId: v.optional(v.string()),
14016
11850
  userId: v.string(),
11851
+ rationale: v.string(),
14017
11852
  linkedBeliefNodeId: v.optional(v.id("epistemicNodes")),
14018
11853
  evidenceRelation: v.optional(v.string()),
14019
11854
  confidence: v.optional(v.number()),
@@ -14077,6 +11912,7 @@ var internalCreate2 = internalMutation({
14077
11912
  externalSourceType: args.externalSourceType,
14078
11913
  sourceUrl: args.sourceUrl,
14079
11914
  sourceQuestionId: args.sourceQuestionId,
11915
+ rationale: args.rationale,
14080
11916
  linkedBeliefNodeId: args.linkedBeliefNodeId,
14081
11917
  evidenceRelation: args.evidenceRelation,
14082
11918
  confidence: args.confidence,
@@ -14091,6 +11927,7 @@ var internalCreate2 = internalMutation({
14091
11927
  changedBy: args.userId,
14092
11928
  isAgent: false,
14093
11929
  projectId: scope.projectId,
11930
+ rationale: args.rationale,
14094
11931
  newState: {
14095
11932
  text: args.text.slice(0, 200),
14096
11933
  kind,
@@ -15716,7 +13553,7 @@ function isScoredBeliefNode(node) {
15716
13553
  if (numericConfidence) {
15717
13554
  return true;
15718
13555
  }
15719
- return hasResolvedPredictionOutcome2(node.predictionMeta) || hasResolvedPredictionOutcome2(metadata?.predictionMeta);
13556
+ return hasResolvedPredictionOutcome(node.predictionMeta) || hasResolvedPredictionOutcome(metadata?.predictionMeta);
15720
13557
  }
15721
13558
  function getForbiddenMetadataKeys(metadata) {
15722
13559
  if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
@@ -16937,38 +14774,7 @@ __export(epistemicQuestions_exports, {
16937
14774
  updateStatus: () => updateStatus4
16938
14775
  });
16939
14776
 
16940
- // ../worktrees/src/v1/engine/scopeBridge.ts
16941
- function normalizeString2(value) {
16942
- if (typeof value !== "string") {
16943
- return void 0;
16944
- }
16945
- const trimmed = value.trim();
16946
- return trimmed.length > 0 ? trimmed : void 0;
16947
- }
16948
- function requireScopeId(...ids) {
16949
- for (const id of ids) {
16950
- const normalized = normalizeString2(id);
16951
- if (normalized) {
16952
- return normalized;
16953
- }
16954
- }
16955
- throw new Error("No scope identifier provided (topicId or projectId required)");
16956
- }
16957
- async function resolveTopicProjectScope2(ctx, args) {
16958
- const resolved = await resolveTopicProjectScope(ctx, {
16959
- topicId: normalizeString2(args.topicId),
16960
- projectId: normalizeString2(args.projectId)
16961
- });
16962
- const topicId = normalizeString2(resolved.topicId);
16963
- const projectId = requireScopeId(
16964
- resolved.projectId,
16965
- args.projectId,
16966
- topicId
16967
- );
16968
- return { projectId, ...topicId ? { topicId } : {} };
16969
- }
16970
-
16971
- // ../worktrees/src/v1/engine/worktreeWorkflowBridge.ts
14777
+ // src/workflowBridge.ts
16972
14778
  function isLegacySprintDoc(doc) {
16973
14779
  if (!doc || typeof doc !== "object") {
16974
14780
  return false;
@@ -16994,7 +14800,7 @@ async function findPairedWorktreeForSprint(ctx, sprint) {
16994
14800
  let topicId = getStringField(sprint, "topicId");
16995
14801
  if (!topicId) {
16996
14802
  try {
16997
- const scope = await resolveTopicProjectScope2(ctx, {
14803
+ const scope = await resolveTopicProjectScope(ctx, {
16998
14804
  topicId: getStringField(sprint, "topicId"),
16999
14805
  projectId: getStringField(sprint, "projectId")
17000
14806
  });
@@ -17854,13 +15660,13 @@ var internalGetByProject3 = internalQuery({
17854
15660
  if (!projectScopeId) {
17855
15661
  return [];
17856
15662
  }
17857
- const project2 = await resolveGraphPrimitivesAppResolvers().getProject(
15663
+ const project3 = await resolveGraphPrimitivesAppResolvers().getProject(
17858
15664
  ctx,
17859
15665
  projectScopeId
17860
15666
  );
17861
15667
  const registryRows = await listAudienceRegistryRows(ctx, {
17862
- tenantId: project2?.tenantId,
17863
- workspaceId: project2?.workspaceId
15668
+ tenantId: project3?.tenantId,
15669
+ workspaceId: project3?.workspaceId
17864
15670
  });
17865
15671
  const audienceClassByKey = new Map(
17866
15672
  registryRows.map((row) => [
@@ -17879,8 +15685,8 @@ var internalGetByProject3 = internalQuery({
17879
15685
  const nodes = await getQuestionNodesForScope(ctx, scope, { scanLimit });
17880
15686
  const workspaceScopedNodes = nodes.filter(
17881
15687
  (node) => nodeMatchesWorkspaceReasoningScope(node, {
17882
- tenantId: project2?.tenantId,
17883
- workspaceId: project2?.workspaceId
15688
+ tenantId: project3?.tenantId,
15689
+ workspaceId: project3?.workspaceId
17884
15690
  })
17885
15691
  );
17886
15692
  const visibleNodes = workspaceScopedNodes.filter(
@@ -19768,7 +17574,7 @@ function throwStructuredSourceError(args) {
19768
17574
  error.details = args.details;
19769
17575
  throw error;
19770
17576
  }
19771
- function normalizeString3(value) {
17577
+ function normalizeString(value) {
19772
17578
  if (typeof value !== "string") {
19773
17579
  return void 0;
19774
17580
  }
@@ -19796,7 +17602,7 @@ function generateSourceContentHash(identity) {
19796
17602
  return Math.abs(hash).toString(16).padStart(8, "0");
19797
17603
  }
19798
17604
  function normalizeSourceUrl(url) {
19799
- const trimmed = normalizeString3(url);
17605
+ const trimmed = normalizeString(url);
19800
17606
  if (!trimmed) {
19801
17607
  throwStructuredSourceError({
19802
17608
  message: "Source URL is required.",
@@ -19839,10 +17645,10 @@ async function findSourceByIdentity(ctx, args) {
19839
17645
  let shaMatch = null;
19840
17646
  for (const node of sourceNodes) {
19841
17647
  const metadata = asRecord2(node.metadata);
19842
- if (args.normalizedUrl && normalizeString3(metadata.url) === args.normalizedUrl && !urlMatch) {
17648
+ if (args.normalizedUrl && normalizeString(metadata.url) === args.normalizedUrl && !urlMatch) {
19843
17649
  urlMatch = node;
19844
17650
  }
19845
- if (args.sha && normalizeString3(metadata.contentSha) === args.sha && !shaMatch) {
17651
+ if (args.sha && normalizeString(metadata.contentSha) === args.sha && !shaMatch) {
19846
17652
  shaMatch = node;
19847
17653
  }
19848
17654
  if (urlMatch && (!args.sha || shaMatch)) {
@@ -19888,10 +17694,10 @@ function buildSourceMetadata(args) {
19888
17694
  }
19889
17695
  function sourceEmbeddingText(args) {
19890
17696
  const lines = [
19891
- normalizeString3(args.title),
19892
- normalizeString3(args.url),
17697
+ normalizeString(args.title),
17698
+ normalizeString(args.url),
19893
17699
  args.kind,
19894
- normalizeString3(args.metadata.sourceDescription)
17700
+ normalizeString(args.metadata.sourceDescription)
19895
17701
  ].filter((value) => Boolean(value));
19896
17702
  return lines.join("\n");
19897
17703
  }
@@ -19908,8 +17714,8 @@ var upsertSource = mutation({
19908
17714
  },
19909
17715
  returns: permissiveReturn,
19910
17716
  handler: async (ctx, args) => {
19911
- const normalizedUrl = normalizeString3(args.url) ? normalizeSourceUrl(args.url) : void 0;
19912
- const sha = normalizeString3(args.sha);
17717
+ const normalizedUrl = normalizeString(args.url) ? normalizeSourceUrl(args.url) : void 0;
17718
+ const sha = normalizeString(args.sha);
19913
17719
  if (!normalizedUrl && !sha) {
19914
17720
  throwStructuredSourceError({
19915
17721
  message: "Source identity requires a URL or content SHA.",
@@ -19934,7 +17740,7 @@ var upsertSource = mutation({
19934
17740
  });
19935
17741
  }
19936
17742
  const existingMetadata = asRecord2(existing.metadata);
19937
- const existingSha = normalizeString3(existingMetadata.contentSha);
17743
+ const existingSha = normalizeString(existingMetadata.contentSha);
19938
17744
  if (sha && existingSha && existingSha !== sha) {
19939
17745
  throwStructuredSourceError({
19940
17746
  message: "Same URL cannot be reused with a different content hash.",
@@ -19960,7 +17766,7 @@ var upsertSource = mutation({
19960
17766
  metadata: nextMetadata2,
19961
17767
  updatedAt: now
19962
17768
  };
19963
- const title2 = normalizeString3(args.title);
17769
+ const title2 = normalizeString(args.title);
19964
17770
  if (title2) {
19965
17771
  patch.title = title2;
19966
17772
  patch.canonicalText = title2;
@@ -19989,7 +17795,7 @@ var upsertSource = mutation({
19989
17795
  });
19990
17796
  return await ctx.db.get(existing._id) ?? existing;
19991
17797
  }
19992
- if (!normalizeString3(args.topicId)) {
17798
+ if (!normalizeString(args.topicId)) {
19993
17799
  throwStructuredSourceError({
19994
17800
  message: "topicId is required when creating a new source.",
19995
17801
  status: 400,
@@ -20010,7 +17816,7 @@ var upsertSource = mutation({
20010
17816
  await requireProjectAccess(ctx, scope.projectId, args.userId);
20011
17817
  }
20012
17818
  const globalId = generateGlobalId();
20013
- const title = normalizeString3(args.title);
17819
+ const title = normalizeString(args.title);
20014
17820
  const nextMetadata = buildSourceMetadata({
20015
17821
  normalizedUrl,
20016
17822
  sha,
@@ -20109,7 +17915,7 @@ var findBySha = query({
20109
17915
  },
20110
17916
  returns: permissiveReturn,
20111
17917
  handler: async (ctx, args) => {
20112
- const sha = normalizeString3(args.sha);
17918
+ const sha = normalizeString(args.sha);
20113
17919
  if (!sha) {
20114
17920
  return null;
20115
17921
  }
@@ -20195,374 +18001,6 @@ __export(ontology_matching_exports, {
20195
18001
  scoreEntityTypeMatch: () => scoreEntityTypeMatch
20196
18002
  });
20197
18003
 
20198
- // ../../packages/contracts/src/text-matching.contract.ts
20199
- var TOKEN_SPLIT_REGEX = /[^a-z0-9]+/;
20200
- var NON_ALPHANUMERIC_REGEX = /[^a-z0-9]/g;
20201
- var STOP_WORDS = /* @__PURE__ */ new Set([
20202
- "the",
20203
- "a",
20204
- "an",
20205
- "and",
20206
- "or",
20207
- "but",
20208
- "in",
20209
- "on",
20210
- "at",
20211
- "to",
20212
- "for",
20213
- "of",
20214
- "with",
20215
- "by",
20216
- "from",
20217
- "is",
20218
- "it",
20219
- "as",
20220
- "be",
20221
- "was",
20222
- "are",
20223
- "this",
20224
- "that",
20225
- "has",
20226
- "had",
20227
- "have",
20228
- "not",
20229
- "all",
20230
- "can",
20231
- "do",
20232
- "its",
20233
- "may",
20234
- "will",
20235
- "how",
20236
- "what",
20237
- "which",
20238
- "who",
20239
- "when",
20240
- "where",
20241
- "than",
20242
- "then",
20243
- "each",
20244
- "into",
20245
- "such",
20246
- "any",
20247
- "been",
20248
- "if",
20249
- "would",
20250
- "about",
20251
- "should",
20252
- "these",
20253
- "those",
20254
- "their",
20255
- "we",
20256
- "our",
20257
- "so"
20258
- ]);
20259
- function tokenizeSearchText(text) {
20260
- return text.toLowerCase().split(TOKEN_SPLIT_REGEX).filter((token) => token.length >= 2 && !STOP_WORDS.has(token));
20261
- }
20262
- function stemToken(word) {
20263
- if (word.length <= 4) {
20264
- return word;
20265
- }
20266
- if (word.endsWith("ation")) {
20267
- return word.slice(0, -5);
20268
- }
20269
- if (word.endsWith("ment")) {
20270
- return word.slice(0, -4);
20271
- }
20272
- if (word.endsWith("ness")) {
20273
- return word.slice(0, -4);
20274
- }
20275
- if (word.endsWith("ical")) {
20276
- return word.slice(0, -4);
20277
- }
20278
- if (word.endsWith("tion")) {
20279
- return word.slice(0, -4);
20280
- }
20281
- if (word.endsWith("sion")) {
20282
- return word.slice(0, -4);
20283
- }
20284
- if (word.endsWith("ing")) {
20285
- return word.slice(0, -3);
20286
- }
20287
- if (word.endsWith("ous")) {
20288
- return word.slice(0, -3);
20289
- }
20290
- if (word.endsWith("ive")) {
20291
- return word.slice(0, -3);
20292
- }
20293
- if (word.endsWith("ity")) {
20294
- return word.slice(0, -3);
20295
- }
20296
- if (word.endsWith("ics")) {
20297
- return word.slice(0, -3);
20298
- }
20299
- if (word.endsWith("ly")) {
20300
- return word.slice(0, -2);
20301
- }
20302
- if (word.endsWith("ed")) {
20303
- return word.slice(0, -2);
20304
- }
20305
- if (word.endsWith("er")) {
20306
- return word.slice(0, -2);
20307
- }
20308
- if (word.endsWith("es")) {
20309
- return word.slice(0, -2);
20310
- }
20311
- if (word.endsWith("al")) {
20312
- return word.slice(0, -2);
20313
- }
20314
- if (word.endsWith("ic")) {
20315
- return word.slice(0, -2);
20316
- }
20317
- if (word.endsWith("s") && !word.endsWith("ss")) {
20318
- return word.slice(0, -1);
20319
- }
20320
- return word;
20321
- }
20322
- function tokenOverlapScore(queryTokens, textTokens) {
20323
- if (queryTokens.length === 0 || textTokens.length === 0) {
20324
- return 0;
20325
- }
20326
- const stemmedText = new Set(textTokens.map(stemToken));
20327
- let matchCount = 0;
20328
- for (const queryToken of queryTokens) {
20329
- const stemmedQuery = stemToken(queryToken);
20330
- if (stemmedText.has(stemmedQuery)) {
20331
- matchCount += 1;
20332
- continue;
20333
- }
20334
- for (const textToken of stemmedText) {
20335
- if (textToken.startsWith(stemmedQuery) || stemmedQuery.startsWith(textToken)) {
20336
- matchCount += 0.5;
20337
- break;
20338
- }
20339
- }
20340
- }
20341
- return matchCount / queryTokens.length;
20342
- }
20343
- function bigramTokenize(text) {
20344
- const normalized = text.toLowerCase().replace(NON_ALPHANUMERIC_REGEX, "");
20345
- const bigrams = /* @__PURE__ */ new Set();
20346
- for (let i = 0; i < normalized.length - 1; i++) {
20347
- bigrams.add(normalized.slice(i, i + 2));
20348
- }
20349
- return bigrams;
20350
- }
20351
- function wordTokenize(text) {
20352
- return text.toLowerCase().split(TOKEN_SPLIT_REGEX).filter((token) => token.length > 1);
20353
- }
20354
- function jaccardSimilarity(setA, setB) {
20355
- if (setA.size === 0 && setB.size === 0) {
20356
- return 0;
20357
- }
20358
- let intersectionSize = 0;
20359
- const smaller = setA.size <= setB.size ? setA : setB;
20360
- const larger = setA.size <= setB.size ? setB : setA;
20361
- for (const item of smaller) {
20362
- if (larger.has(item)) {
20363
- intersectionSize++;
20364
- }
20365
- }
20366
- const unionSize = setA.size + setB.size - intersectionSize;
20367
- return unionSize === 0 ? 0 : intersectionSize / unionSize;
20368
- }
20369
- function wordOverlapScore(inputWords, typeWords) {
20370
- if (typeWords.length === 0) {
20371
- return 0;
20372
- }
20373
- let matches = 0;
20374
- for (const word of typeWords) {
20375
- if (inputWords.includes(word)) {
20376
- matches++;
20377
- }
20378
- }
20379
- return matches / typeWords.length;
20380
- }
20381
- function prepareLexicalQuery(query2) {
20382
- return {
20383
- raw: query2,
20384
- tokens: tokenizeSearchText(query2),
20385
- words: wordTokenize(query2),
20386
- bigrams: bigramTokenize(query2)
20387
- };
20388
- }
20389
- function scoreLexicalSignal(query2, signal) {
20390
- const text = signal.text?.trim();
20391
- if (!text) {
20392
- return 0;
20393
- }
20394
- switch (signal.strategy ?? "tokenOverlap") {
20395
- case "bigramJaccard":
20396
- return jaccardSimilarity(query2.bigrams, bigramTokenize(text));
20397
- case "wordOverlap":
20398
- return wordOverlapScore(query2.words, wordTokenize(text));
20399
- default:
20400
- return tokenOverlapScore(query2.tokens, tokenizeSearchText(text));
20401
- }
20402
- }
20403
- function scoreLexicalSignals(query2, signals) {
20404
- let weightedScore = 0;
20405
- let totalWeight = 0;
20406
- for (const signal of signals) {
20407
- if (!signal.text?.trim() || signal.weight <= 0) {
20408
- continue;
20409
- }
20410
- weightedScore += scoreLexicalSignal(query2, signal) * signal.weight;
20411
- totalWeight += signal.weight;
20412
- }
20413
- return totalWeight === 0 ? 0 : weightedScore / totalWeight;
20414
- }
20415
- function rankWindowScore(index, total) {
20416
- if (total <= 1) {
20417
- return 1;
20418
- }
20419
- const clampedIndex = Math.max(0, Math.min(index, total - 1));
20420
- return 1 - clampedIndex / (total - 1);
20421
- }
20422
- function rerankLexicalWindow(query2, items, getText, options) {
20423
- const preparedQuery = prepareLexicalQuery(query2);
20424
- if (preparedQuery.tokens.length === 0 || items.length <= 1) {
20425
- return items;
20426
- }
20427
- const lexicalWeight = options?.lexicalWeight ?? 0.65;
20428
- const rankWeight = options?.rankWeight ?? 0.35;
20429
- return items.map((item, index) => {
20430
- const lexicalScore = scoreLexicalSignals(preparedQuery, [
20431
- { text: getText(item) ?? "", weight: 1, strategy: "tokenOverlap" }
20432
- ]);
20433
- const rankScore = rankWindowScore(index, items.length);
20434
- return {
20435
- item,
20436
- combinedScore: lexicalScore * lexicalWeight + rankScore * rankWeight
20437
- };
20438
- }).sort((left, right) => right.combinedScore - left.combinedScore).map(({ item }) => item);
20439
- }
20440
-
20441
- // ../../packages/contracts/src/v1/ontologies/v1.ts
20442
- var MATCH_WEIGHTS = {
20443
- tokenOverlap: 0.35,
20444
- bigramSimilarity: 0.25,
20445
- wordOverlap: 0.2,
20446
- descriptionBonus: 0.2
20447
- };
20448
- function scoreEntityTypeMatch(inputText, entityType) {
20449
- const preparedQuery = prepareLexicalQuery(inputText);
20450
- const labelText = `${entityType.label} ${entityType.value}`;
20451
- const tokenScore = scoreLexicalSignals(preparedQuery, [
20452
- { text: labelText, weight: 1, strategy: "tokenOverlap" }
20453
- ]);
20454
- const labelBigrams = bigramTokenize(entityType.label);
20455
- const bigramScore = jaccardSimilarity(preparedQuery.bigrams, labelBigrams);
20456
- const labelWords = wordTokenize(labelText);
20457
- const wordScore = wordOverlapScore(preparedQuery.words, labelWords);
20458
- let descScore = 0;
20459
- if (entityType.description) {
20460
- descScore = scoreLexicalSignals(preparedQuery, [
20461
- { text: entityType.description, weight: 1, strategy: "tokenOverlap" }
20462
- ]);
20463
- }
20464
- let subtypeBonus = 0;
20465
- if (entityType.subtypes && entityType.subtypes.length > 0) {
20466
- for (const subtype of entityType.subtypes) {
20467
- const subtypeScore = scoreLexicalSignals(preparedQuery, [
20468
- {
20469
- text: `${subtype.label} ${subtype.value} ${subtype.description || ""}`,
20470
- weight: 1,
20471
- strategy: "tokenOverlap"
20472
- }
20473
- ]);
20474
- subtypeBonus = Math.max(subtypeBonus, subtypeScore * 0.3);
20475
- }
20476
- }
20477
- const score = Math.min(
20478
- 1,
20479
- tokenScore * MATCH_WEIGHTS.tokenOverlap + bigramScore * MATCH_WEIGHTS.bigramSimilarity + wordScore * MATCH_WEIGHTS.wordOverlap + descScore * MATCH_WEIGHTS.descriptionBonus + subtypeBonus
20480
- );
20481
- const reasons = [];
20482
- if (tokenScore > 0.3) {
20483
- reasons.push(`stem match: ${(tokenScore * 100).toFixed(0)}%`);
20484
- }
20485
- if (bigramScore > 0.3) {
20486
- reasons.push(`text similarity: ${(bigramScore * 100).toFixed(0)}%`);
20487
- }
20488
- if (wordScore > 0.3) {
20489
- reasons.push(`word match: ${(wordScore * 100).toFixed(0)}%`);
20490
- }
20491
- if (descScore > 0.2) {
20492
- reasons.push("description match");
20493
- }
20494
- if (subtypeBonus > 0.05) {
20495
- reasons.push("subtype match");
20496
- }
20497
- const reason = reasons.length > 0 ? reasons.join(", ") : "low similarity";
20498
- return {
20499
- entityType: entityType.value,
20500
- label: entityType.label,
20501
- score,
20502
- reason
20503
- };
20504
- }
20505
- function rankEntityTypeMatches(inputText, entityTypes, options) {
20506
- const minScore = options?.minScore ?? 0.05;
20507
- const limit = options?.limit ?? 10;
20508
- const matches = entityTypes.map((et) => scoreEntityTypeMatch(inputText, et)).filter((m) => m.score >= minScore).sort((a, b) => b.score - a.score).slice(0, limit);
20509
- return matches;
20510
- }
20511
- function scoreEntityConnection(nodeText, candidate, options) {
20512
- const preparedQuery = prepareLexicalQuery(nodeText);
20513
- const connectivityWeight = options?.connectivityWeight ?? 0.3;
20514
- const textWeight = 1 - connectivityWeight;
20515
- const candidateText = `${candidate.title} ${candidate.canonicalText}`;
20516
- const tokenScore = scoreLexicalSignals(preparedQuery, [
20517
- { text: candidateText, weight: 1, strategy: "tokenOverlap" }
20518
- ]);
20519
- const textScore = scoreLexicalSignals(preparedQuery, [
20520
- { text: candidateText, weight: 1, strategy: "bigramJaccard" }
20521
- ]);
20522
- const wordScore = scoreLexicalSignals(preparedQuery, [
20523
- { text: candidateText, weight: 1, strategy: "wordOverlap" }
20524
- ]);
20525
- const maxConnections = Math.max(
20526
- 1,
20527
- candidate.connectedBeliefCount + candidate.connectedEvidenceCount
20528
- );
20529
- const connectivityScore = Math.min(1, maxConnections / 10);
20530
- const combinedTextScore = tokenScore * 0.45 + textScore * 0.35 + wordScore * 0.2;
20531
- const score = combinedTextScore * textWeight + connectivityScore * connectivityWeight;
20532
- const suggestedEdgeType = suggestEdgeType(candidate.entityType);
20533
- const reason = tokenScore > 0.3 ? `stem match: ${(tokenScore * 100).toFixed(0)}%` : textScore > 0.2 ? `name similarity: ${(textScore * 100).toFixed(0)}%` : wordScore > 0.2 ? `keyword match: ${(wordScore * 100).toFixed(0)}%` : `connectivity: ${candidate.connectedBeliefCount} beliefs`;
20534
- return {
20535
- entityNodeId: candidate.nodeId,
20536
- entityType: candidate.entityType,
20537
- title: candidate.title,
20538
- score,
20539
- suggestedEdgeType,
20540
- reason
20541
- };
20542
- }
20543
- function suggestEdgeType(entityType) {
20544
- switch (entityType) {
20545
- case "company":
20546
- case "person":
20547
- case "investor":
20548
- return "contains";
20549
- case "function":
20550
- case "value_chain":
20551
- return "impacts";
20552
- default:
20553
- return "contains";
20554
- }
20555
- }
20556
- function rankEntityConnections(nodeText, candidates, options) {
20557
- const minScore = options?.minScore ?? 0.05;
20558
- const limit = options?.limit ?? 10;
20559
- return candidates.map(
20560
- (c) => scoreEntityConnection(nodeText, c, {
20561
- connectivityWeight: options?.connectivityWeight
20562
- })
20563
- ).filter((m) => m.score >= minScore).sort((a, b) => b.score - a.score).slice(0, limit);
20564
- }
20565
-
20566
18004
  // src/ontologyRegistry.ts
20567
18005
  var ontologyRegistry_exports = {};
20568
18006
  __export(ontologyRegistry_exports, {