@lucern/graph-primitives 0.1.0-alpha.3 → 0.3.0-alpha.0

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 (38) hide show
  1. package/dist/beliefDecay.js +199 -18
  2. package/dist/beliefDecay.js.map +1 -1
  3. package/dist/beliefEvidenceLinks.js.map +1 -1
  4. package/dist/confidencePropagationDispatch.js.map +1 -1
  5. package/dist/contradictions.js.map +1 -1
  6. package/dist/entityBridge.js.map +1 -1
  7. package/dist/entityLifecycle.js.map +1 -1
  8. package/dist/epistemicAnswers.js +21 -36
  9. package/dist/epistemicAnswers.js.map +1 -1
  10. package/dist/epistemicBeliefs.js +92 -651
  11. package/dist/epistemicBeliefs.js.map +1 -1
  12. package/dist/epistemicContracts.js +65 -624
  13. package/dist/epistemicContracts.js.map +1 -1
  14. package/dist/epistemicEdges.js.map +1 -1
  15. package/dist/epistemicEvidence.js +71 -630
  16. package/dist/epistemicEvidence.js.map +1 -1
  17. package/dist/epistemicHelpers.js +3 -2
  18. package/dist/epistemicHelpers.js.map +1 -1
  19. package/dist/epistemicLinking.js.map +1 -1
  20. package/dist/epistemicNodes.js +49 -585
  21. package/dist/epistemicNodes.js.map +1 -1
  22. package/dist/epistemicQuestions.js +46 -590
  23. package/dist/epistemicQuestions.js.map +1 -1
  24. package/dist/epistemicSources.js +29 -565
  25. package/dist/epistemicSources.js.map +1 -1
  26. package/dist/evaluators/index.js +65 -624
  27. package/dist/evaluators/index.js.map +1 -1
  28. package/dist/index.js +304 -905
  29. package/dist/index.js.map +1 -1
  30. package/dist/ontologyApproval.js.map +1 -1
  31. package/dist/ontologyDefinitions.js.map +1 -1
  32. package/dist/ontologyRegistry.js.map +1 -1
  33. package/dist/projectionReconciliation.js.map +1 -1
  34. package/dist/questionEvidenceLinks.js +188 -2
  35. package/dist/questionEvidenceLinks.js.map +1 -1
  36. package/dist/workspaceIsolation.js +30 -581
  37. package/dist/workspaceIsolation.js.map +1 -1
  38. package/package.json +5 -6
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { v } from 'convex/values';
2
- import { componentsGeneric, queryGeneric, mutationGeneric, anyApi, defineTable, internalMutationGeneric, internalQueryGeneric, internalActionGeneric } from 'convex/server';
2
+ import { componentsGeneric, queryGeneric, mutationGeneric, anyApi, internalMutationGeneric, internalQueryGeneric, internalActionGeneric } from 'convex/server';
3
3
 
4
4
  var __defProp = Object.defineProperty;
5
5
  var __export = (target, all) => {
@@ -533,23 +533,23 @@ var DEADLINE_URGENCY = {
533
533
  action: "OVERDUE \u2014 must validate or archive immediately"
534
534
  }
535
535
  };
536
- function normalizeBeliefConfidence(confidence2) {
537
- if (typeof confidence2 !== "number" || !Number.isFinite(confidence2)) {
536
+ function normalizeBeliefConfidence(confidence) {
537
+ if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
538
538
  return null;
539
539
  }
540
- if (confidence2 >= 0 && confidence2 <= 1) {
541
- return confidence2;
540
+ if (confidence >= 0 && confidence <= 1) {
541
+ return confidence;
542
542
  }
543
- if (confidence2 > 1 && confidence2 <= 100) {
544
- return confidence2 / 100;
543
+ if (confidence > 1 && confidence <= 100) {
544
+ return confidence / 100;
545
545
  }
546
546
  return null;
547
547
  }
548
- function hasResolvedPredictionOutcome(predictionMeta2) {
549
- if (!predictionMeta2 || typeof predictionMeta2 !== "object") {
548
+ function hasResolvedPredictionOutcome(predictionMeta) {
549
+ if (!predictionMeta || typeof predictionMeta !== "object") {
550
550
  return false;
551
551
  }
552
- const outcome = predictionMeta2.outcome;
552
+ const outcome = predictionMeta.outcome;
553
553
  return outcome === "confirmed" || outcome === "disconfirmed" || outcome === "partial" || outcome === "expired";
554
554
  }
555
555
  function resolveLifecycleBucket(args) {
@@ -609,10 +609,10 @@ function computeDeadlineUrgency(expectedBy) {
609
609
  isOverdue: daysToDeadline < 0
610
610
  };
611
611
  }
612
- function computeEffectiveDecay(lastScoredAt, expectedBy, beliefStatus2) {
612
+ function computeEffectiveDecay(lastScoredAt, expectedBy, beliefStatus) {
613
613
  const base = computeBaseDecay(lastScoredAt);
614
614
  const urgency = computeDeadlineUrgency(expectedBy);
615
- const effectiveWeight = (urgency ? base.weight * urgency.urgencyMultiplier : base.weight) * lifecycleMultiplier(beliefStatus2);
615
+ const effectiveWeight = (urgency ? base.weight * urgency.urgencyMultiplier : base.weight) * lifecycleMultiplier(beliefStatus);
616
616
  const urgencyRescoreDays = urgency?.urgencyTier.rescoreIntervalDays ?? Number.POSITIVE_INFINITY;
617
617
  const rescoreInDays = Math.min(base.tier.rescoreInDays, urgencyRescoreDays);
618
618
  const rescoreByDate = lastScoredAt + rescoreInDays * 24 * 60 * 60 * 1e3;
@@ -632,7 +632,7 @@ function computeEffectiveDecay(lastScoredAt, expectedBy, beliefStatus2) {
632
632
  };
633
633
  }
634
634
  function getRescoringSchedule(opts) {
635
- const lifecycleStatus2 = resolveLifecycleBucket({
635
+ const lifecycleStatus = resolveLifecycleBucket({
636
636
  beliefStatus: opts.beliefStatus,
637
637
  confidence: opts.confidence,
638
638
  predictionMeta: opts.predictionMeta
@@ -640,16 +640,16 @@ function getRescoringSchedule(opts) {
640
640
  const decayState = computeEffectiveDecay(
641
641
  opts.lastScoredAt,
642
642
  opts.expectedBy,
643
- lifecycleStatus2
643
+ lifecycleStatus
644
644
  );
645
645
  const daysUntilRescore = (decayState.rescoreByDate - Date.now()) / (1e3 * 60 * 60 * 24);
646
646
  const isOverdue = daysUntilRescore < 0;
647
647
  let priority;
648
648
  let reason;
649
- if (isOverdue && lifecycleStatus2 === "assumption") {
649
+ if (isOverdue && lifecycleStatus === "assumption") {
650
650
  priority = "critical";
651
651
  reason = `Untested assumption is stale (${Math.round(decayState.ageDays)}d) \u2014 validate or supersede`;
652
- } else if (isOverdue && lifecycleStatus2 === "hypothesis" || lifecycleStatus2 === "hypothesis" && daysUntilRescore < 7) {
652
+ } else if (isOverdue && lifecycleStatus === "hypothesis" || lifecycleStatus === "hypothesis" && daysUntilRescore < 7) {
653
653
  priority = "high";
654
654
  reason = `Hypothesis aging without validation (${Math.round(decayState.ageDays)}d) \u2014 run/finish sprint testing`;
655
655
  } else if (decayState.urgency?.isOverdue) {
@@ -2416,7 +2416,11 @@ var identifyBeliefsNeedingRescore = query({
2416
2416
  },
2417
2417
  returns: permissiveReturn,
2418
2418
  handler: async (ctx, args) => {
2419
- const { projectId, maxResults = 20, minPriority = "medium" } = args;
2419
+ const { maxResults = 20, minPriority = "medium" } = args;
2420
+ const scope = await resolveTopicProjectScope(ctx, args).catch(() => null);
2421
+ if (!scope) {
2422
+ return [];
2423
+ }
2420
2424
  const priorityRank = {
2421
2425
  critical: 4,
2422
2426
  high: 3,
@@ -2425,39 +2429,39 @@ var identifyBeliefsNeedingRescore = query({
2425
2429
  };
2426
2430
  const minRank = priorityRank[minPriority] ?? 2;
2427
2431
  const beliefs = await ctx.db.query("epistemicNodes").withIndex(
2428
- args.topicId ? "by_topic_type" : "by_project_type",
2429
- (q) => args.topicId ? q.eq("topicId", args.topicId).eq("nodeType", "belief") : q.eq("projectId", projectId).eq("nodeType", "belief")
2432
+ "by_topic_type",
2433
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
2430
2434
  ).collect();
2431
2435
  const activeBeliefs = beliefs.filter((b) => b.status === "active");
2432
2436
  const results = [];
2433
2437
  for (const belief of activeBeliefs) {
2434
2438
  const metadata = belief.metadata || {};
2435
- const predictionMeta2 = belief.predictionMeta;
2436
- const temporalNature2 = belief.temporalNature || "unknown";
2437
- const beliefStatus2 = belief.beliefStatus || metadata.beliefStatus || null;
2439
+ const predictionMeta = belief.predictionMeta;
2440
+ const temporalNature = belief.temporalNature || "unknown";
2441
+ const beliefStatus = belief.beliefStatus || metadata.beliefStatus || null;
2438
2442
  const confidenceHistory = await ctx.db.query("beliefConfidence").withIndex("by_beliefId", (q) => q.eq("beliefId", belief._id)).collect();
2439
2443
  const sorted = confidenceHistory.sort(
2440
2444
  (a, b) => b.assessedAt - a.assessedAt
2441
2445
  );
2442
2446
  const lastEntry = sorted[0] ?? null;
2443
2447
  const lastScoredAt = lastEntry?.assessedAt || belief.updatedAt || belief.createdAt || Date.now();
2444
- const confidence2 = lastEntry?.confidence ?? metadata.confidence ?? 0.5;
2448
+ const confidence = lastEntry?.confidence ?? metadata.confidence ?? 0.5;
2445
2449
  const schedule = getRescoringSchedule({
2446
2450
  lastScoredAt,
2447
- temporalNature: temporalNature2,
2448
- expectedBy: predictionMeta2?.expectedBy ?? null,
2449
- predictionMeta: predictionMeta2 ?? null,
2450
- confidence: confidence2,
2451
- beliefStatus: beliefStatus2
2451
+ temporalNature,
2452
+ expectedBy: predictionMeta?.expectedBy ?? null,
2453
+ predictionMeta: predictionMeta ?? null,
2454
+ confidence,
2455
+ beliefStatus
2452
2456
  });
2453
2457
  if (priorityRank[schedule.priority] >= minRank) {
2454
2458
  results.push({
2455
2459
  beliefId: belief._id,
2456
2460
  beliefText: belief.canonicalText,
2457
- confidence: confidence2,
2458
- beliefStatus: beliefStatus2 ?? "assumption",
2459
- temporalNature: temporalNature2,
2460
- expectedBy: predictionMeta2?.expectedBy ?? null,
2461
+ confidence,
2462
+ beliefStatus: beliefStatus ?? "assumption",
2463
+ temporalNature,
2464
+ expectedBy: predictionMeta?.expectedBy ?? null,
2461
2465
  lastScoredAt,
2462
2466
  daysSinceScoring: Math.round(schedule.decay.ageDays),
2463
2467
  schedule
@@ -2516,34 +2520,29 @@ var getGlobalBeliefHealth = query({
2516
2520
  );
2517
2521
  const allResults = [];
2518
2522
  for (const project2 of accessibleProjects.slice(0, 20)) {
2519
- const [topicBeliefs, projectBeliefs] = await Promise.all([
2520
- ctx.db.query("epistemicNodes").withIndex(
2521
- "by_topic_type",
2522
- (q) => q.eq("topicId", project2._id).eq("nodeType", "belief")
2523
- ).collect(),
2524
- ctx.db.query("epistemicNodes").withIndex(
2525
- "by_project_type",
2526
- (q) => q.eq("projectId", project2._id).eq("nodeType", "belief")
2527
- ).collect()
2528
- ]);
2529
- const beliefs = Array.from(
2530
- new Map(
2531
- [...topicBeliefs, ...projectBeliefs].map((b) => [String(b._id), b])
2532
- ).values()
2533
- );
2523
+ const scope = await resolveTopicProjectScope(ctx, {
2524
+ projectId: String(project2._id)
2525
+ }).catch(() => null);
2526
+ if (!scope) {
2527
+ continue;
2528
+ }
2529
+ const beliefs = await ctx.db.query("epistemicNodes").withIndex(
2530
+ "by_topic_type",
2531
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
2532
+ ).collect();
2534
2533
  const activeBeliefs = beliefs.filter((b) => b.status === "active");
2535
2534
  for (const belief of activeBeliefs) {
2536
2535
  const metadata = belief.metadata || {};
2537
- const predictionMeta2 = belief.predictionMeta;
2538
- const temporalNature2 = belief.temporalNature || "unknown";
2539
- const confidence2 = belief.confidence ?? metadata.confidence ?? 0.5;
2536
+ const predictionMeta = belief.predictionMeta;
2537
+ const temporalNature = belief.temporalNature || "unknown";
2538
+ const confidence = belief.confidence ?? metadata.confidence ?? 0.5;
2540
2539
  const lastScoredAt = belief.updatedAt || belief.createdAt || belief._creationTime;
2541
2540
  const schedule = getRescoringSchedule({
2542
2541
  lastScoredAt,
2543
- temporalNature: temporalNature2,
2544
- expectedBy: predictionMeta2?.expectedBy ?? null,
2545
- predictionMeta: predictionMeta2 ?? null,
2546
- confidence: confidence2,
2542
+ temporalNature,
2543
+ expectedBy: predictionMeta?.expectedBy ?? null,
2544
+ predictionMeta: predictionMeta ?? null,
2545
+ confidence,
2547
2546
  beliefStatus: belief.beliefStatus || metadata.beliefStatus || null
2548
2547
  });
2549
2548
  if (priorityRank[schedule.priority] >= minRank) {
@@ -2552,9 +2551,9 @@ var getGlobalBeliefHealth = query({
2552
2551
  projectName: project2.name,
2553
2552
  beliefId: belief._id,
2554
2553
  beliefText: belief.canonicalText,
2555
- confidence: confidence2,
2556
- temporalNature: temporalNature2,
2557
- expectedBy: predictionMeta2?.expectedBy ?? null,
2554
+ confidence,
2555
+ temporalNature,
2556
+ expectedBy: predictionMeta?.expectedBy ?? null,
2558
2557
  daysSinceScoring: Math.round(schedule.decay.ageDays),
2559
2558
  priority: schedule.priority,
2560
2559
  reason: schedule.reason,
@@ -2608,27 +2607,27 @@ var getBeliefDecayInfo = query({
2608
2607
  return null;
2609
2608
  }
2610
2609
  const metadata = belief.metadata || {};
2611
- const predictionMeta2 = belief.predictionMeta;
2612
- const temporalNature2 = belief.temporalNature || "unknown";
2610
+ const predictionMeta = belief.predictionMeta;
2611
+ const temporalNature = belief.temporalNature || "unknown";
2613
2612
  const confidenceHistory = await ctx.db.query("beliefConfidence").withIndex("by_beliefId", (q) => q.eq("beliefId", args.beliefId)).collect();
2614
2613
  const sorted = confidenceHistory.sort(
2615
2614
  (a, b) => b.assessedAt - a.assessedAt
2616
2615
  );
2617
2616
  const lastEntry = sorted[0] ?? null;
2618
2617
  const lastScoredAt = lastEntry?.assessedAt || belief.updatedAt || belief.createdAt || Date.now();
2619
- const confidence2 = lastEntry?.confidence ?? metadata.confidence ?? 0.5;
2618
+ const confidence = lastEntry?.confidence ?? metadata.confidence ?? 0.5;
2620
2619
  const schedule = getRescoringSchedule({
2621
2620
  lastScoredAt,
2622
- temporalNature: temporalNature2,
2623
- expectedBy: predictionMeta2?.expectedBy ?? null,
2624
- predictionMeta: predictionMeta2 ?? null,
2625
- confidence: confidence2,
2621
+ temporalNature,
2622
+ expectedBy: predictionMeta?.expectedBy ?? null,
2623
+ predictionMeta: predictionMeta ?? null,
2624
+ confidence,
2626
2625
  beliefStatus: belief.beliefStatus || metadata.beliefStatus || null
2627
2626
  });
2628
2627
  const decay = schedule.decay;
2629
2628
  return {
2630
- confidence: confidence2,
2631
- decayedConfidence: confidence2 * decay.effectiveWeight,
2629
+ confidence,
2630
+ decayedConfidence: confidence * decay.effectiveWeight,
2632
2631
  freshness: {
2633
2632
  label: decay.baseTier.label,
2634
2633
  ageDays: Math.round(decay.ageDays),
@@ -3402,30 +3401,30 @@ var RESOLVED_PREDICTION_OUTCOMES = [
3402
3401
  function isBeliefLifecycleStatus(value) {
3403
3402
  return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
3404
3403
  }
3405
- function normalizeBeliefConfidence2(confidence2) {
3406
- if (typeof confidence2 !== "number" || !Number.isFinite(confidence2)) {
3404
+ function normalizeBeliefConfidence2(confidence) {
3405
+ if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
3407
3406
  return null;
3408
3407
  }
3409
- if (confidence2 >= 0 && confidence2 <= 1) {
3410
- return confidence2;
3408
+ if (confidence >= 0 && confidence <= 1) {
3409
+ return confidence;
3411
3410
  }
3412
- if (confidence2 > 1 && confidence2 <= 100) {
3413
- return confidence2 / 100;
3411
+ if (confidence > 1 && confidence <= 100) {
3412
+ return confidence / 100;
3414
3413
  }
3415
3414
  return null;
3416
3415
  }
3417
- function isResolvedByConfidence(confidence2) {
3418
- const normalized = normalizeBeliefConfidence2(confidence2);
3416
+ function isResolvedByConfidence(confidence) {
3417
+ const normalized = normalizeBeliefConfidence2(confidence);
3419
3418
  if (normalized === null) {
3420
3419
  return false;
3421
3420
  }
3422
3421
  return normalized <= 0 || normalized >= 1;
3423
3422
  }
3424
- function hasResolvedPredictionOutcome2(predictionMeta2) {
3425
- if (!predictionMeta2 || typeof predictionMeta2 !== "object") {
3423
+ function hasResolvedPredictionOutcome2(predictionMeta) {
3424
+ if (!predictionMeta || typeof predictionMeta !== "object") {
3426
3425
  return false;
3427
3426
  }
3428
- const outcome = predictionMeta2.outcome;
3427
+ const outcome = predictionMeta.outcome;
3429
3428
  return typeof outcome === "string" && RESOLVED_PREDICTION_OUTCOMES.includes(outcome);
3430
3429
  }
3431
3430
  function getPredictionMetaFromMetadata(metadata) {
@@ -4392,7 +4391,7 @@ var EDGE_TYPE_TO_REL = {
4392
4391
  about_entity: "ABOUT_ENTITY",
4393
4392
  entity_referenced_in: "ENTITY_REFERENCED_IN"
4394
4393
  };
4395
- function getNodeLayer(nodeType2) {
4394
+ function getNodeLayer(nodeType) {
4396
4395
  const L4_TYPES = ["decision"];
4397
4396
  const L3_TYPES = ["belief", "question", "theme", "deal"];
4398
4397
  const L2_TYPES = ["claim", "evidence", "synthesis", "answer"];
@@ -4405,29 +4404,29 @@ function getNodeLayer(nodeType2) {
4405
4404
  "value_chain"
4406
4405
  ];
4407
4406
  const ORGANIZATIONAL_TYPES = ["topic"];
4408
- if (L4_TYPES.includes(nodeType2)) {
4407
+ if (L4_TYPES.includes(nodeType)) {
4409
4408
  return "L4";
4410
4409
  }
4411
- if (L3_TYPES.includes(nodeType2)) {
4410
+ if (L3_TYPES.includes(nodeType)) {
4412
4411
  return "L3";
4413
4412
  }
4414
- if (L2_TYPES.includes(nodeType2)) {
4413
+ if (L2_TYPES.includes(nodeType)) {
4415
4414
  return "L2";
4416
4415
  }
4417
- if (L1_TYPES.includes(nodeType2)) {
4416
+ if (L1_TYPES.includes(nodeType)) {
4418
4417
  return "L1";
4419
4418
  }
4420
- if (ONTOLOGICAL_TYPES.includes(nodeType2)) {
4419
+ if (ONTOLOGICAL_TYPES.includes(nodeType)) {
4421
4420
  return "ontological";
4422
4421
  }
4423
- if (ORGANIZATIONAL_TYPES.includes(nodeType2)) {
4422
+ if (ORGANIZATIONAL_TYPES.includes(nodeType)) {
4424
4423
  return "organizational";
4425
4424
  }
4426
- console.warn(`[GraphTypes] Unknown nodeType "${nodeType2}", defaulting to L2`);
4425
+ console.warn(`[GraphTypes] Unknown nodeType "${nodeType}", defaulting to L2`);
4427
4426
  return "L2";
4428
4427
  }
4429
- function getNeo4jLabel(nodeType2) {
4430
- return NODE_TYPE_TO_LABEL[nodeType2] || nodeType2.charAt(0).toUpperCase() + nodeType2.slice(1);
4428
+ function getNeo4jLabel(nodeType) {
4429
+ return NODE_TYPE_TO_LABEL[nodeType] || nodeType.charAt(0).toUpperCase() + nodeType.slice(1);
4431
4430
  }
4432
4431
  function getNeo4jRelType(edgeType) {
4433
4432
  return EDGE_TYPE_TO_REL[edgeType] || edgeType.toUpperCase();
@@ -5103,14 +5102,14 @@ __export(entityValidation_exports, {
5103
5102
  isRegisteredEntityType: () => isRegisteredEntityType,
5104
5103
  validateEntityMetadata: () => validateEntityMetadata
5105
5104
  });
5106
- async function getEntityTypeSchema(ctx, nodeType2, tenantId) {
5105
+ async function getEntityTypeSchema(ctx, nodeType, tenantId) {
5107
5106
  if (tenantId) {
5108
5107
  const tenantEntry = await ctx.db.query("schemaEnumConfig").withIndex(
5109
5108
  "by_tenant_category",
5110
5109
  (q) => q.eq("tenantId", tenantId).eq("category", "entity_type")
5111
5110
  ).collect();
5112
5111
  const tenantMatch = tenantEntry.find(
5113
- (e) => e.value === nodeType2 && e.status === "active"
5112
+ (e) => e.value === nodeType && e.status === "active"
5114
5113
  );
5115
5114
  if (tenantMatch?.metadata?.schema) {
5116
5115
  return tenantMatch.metadata.schema;
@@ -5118,21 +5117,21 @@ async function getEntityTypeSchema(ctx, nodeType2, tenantId) {
5118
5117
  }
5119
5118
  const platformEntry = await ctx.db.query("schemaEnumConfig").withIndex(
5120
5119
  "by_category_value",
5121
- (q) => q.eq("category", "entity_type").eq("value", nodeType2)
5120
+ (q) => q.eq("category", "entity_type").eq("value", nodeType)
5122
5121
  ).first();
5123
5122
  if (platformEntry?.metadata?.schema && platformEntry.status === "active") {
5124
5123
  return platformEntry.metadata.schema;
5125
5124
  }
5126
5125
  return null;
5127
5126
  }
5128
- async function validateEntityMetadata(ctx, nodeType2, metadata, tenantId) {
5127
+ async function validateEntityMetadata(ctx, nodeType, metadata, tenantId) {
5129
5128
  const errors = [];
5130
- const schema = await getEntityTypeSchema(ctx, nodeType2, tenantId);
5129
+ const schema = await getEntityTypeSchema(ctx, nodeType, tenantId);
5131
5130
  if (!schema) {
5132
5131
  return {
5133
5132
  valid: false,
5134
5133
  errors: [
5135
- `No registered schema for entity type "${nodeType2}". Register it in schemaEnumConfig (category="entity_type") before creating entities of this type.`
5134
+ `No registered schema for entity type "${nodeType}". Register it in schemaEnumConfig (category="entity_type") before creating entities of this type.`
5136
5135
  ]
5137
5136
  };
5138
5137
  }
@@ -5165,8 +5164,8 @@ async function validateEntityMetadata(ctx, nodeType2, metadata, tenantId) {
5165
5164
  errors
5166
5165
  };
5167
5166
  }
5168
- async function isRegisteredEntityType(ctx, nodeType2, tenantId) {
5169
- const schema = await getEntityTypeSchema(ctx, nodeType2, tenantId);
5167
+ async function isRegisteredEntityType(ctx, nodeType, tenantId) {
5168
+ const schema = await getEntityTypeSchema(ctx, nodeType, tenantId);
5170
5169
  return schema !== null;
5171
5170
  }
5172
5171
 
@@ -5212,7 +5211,7 @@ async function resolveTopicOntologyInternal(ctx, topicId) {
5212
5211
  "by_ontologyId",
5213
5212
  (q) => q.eq("ontologyId", current?.ontologyId)
5214
5213
  ).collect();
5215
- const published = versions.filter((v23) => v23.status === "published").sort((a, b) => (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
5214
+ const published = versions.filter((v21) => v21.status === "published").sort((a, b) => (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
5216
5215
  const latestPublished = published[0] ?? null;
5217
5216
  return {
5218
5217
  ontologyId: ontologyDef._id,
@@ -5233,7 +5232,7 @@ async function resolveTopicOntologyInternal(ctx, topicId) {
5233
5232
  }
5234
5233
  return null;
5235
5234
  }
5236
- async function validateEntityTypeForTopic(ctx, topicId, nodeType2) {
5235
+ async function validateEntityTypeForTopic(ctx, topicId, nodeType) {
5237
5236
  const resolved = await resolveTopicOntologyInternal(ctx, topicId);
5238
5237
  if (!resolved) {
5239
5238
  return { valid: true };
@@ -5241,12 +5240,12 @@ async function validateEntityTypeForTopic(ctx, topicId, nodeType2) {
5241
5240
  if (resolved.validEntityTypes.length === 0) {
5242
5241
  return { valid: true };
5243
5242
  }
5244
- if (resolved.validEntityTypes.includes(nodeType2)) {
5243
+ if (resolved.validEntityTypes.includes(nodeType)) {
5245
5244
  return { valid: true };
5246
5245
  }
5247
5246
  return {
5248
5247
  valid: false,
5249
- error: `Entity type "${nodeType2}" is not defined in the ontology "${resolved.ontologyKey}" (${resolved.ontologyName}). Valid entity types: ${resolved.validEntityTypes.join(", ")}. Source: ${resolved.source} from topic ${resolved.sourceTopicId}.`
5248
+ error: `Entity type "${nodeType}" is not defined in the ontology "${resolved.ontologyKey}" (${resolved.ontologyName}). Valid entity types: ${resolved.validEntityTypes.join(", ")}. Source: ${resolved.source} from topic ${resolved.sourceTopicId}.`
5250
5249
  };
5251
5250
  }
5252
5251
 
@@ -5286,11 +5285,11 @@ async function requireProjectWriteAccess(ctx, projectId, userId) {
5286
5285
  });
5287
5286
  }
5288
5287
  }
5289
- function generateContentHash(nodeType2, text) {
5290
- const content2 = `${nodeType2}:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
5288
+ function generateContentHash(nodeType, text) {
5289
+ const content = `${nodeType}:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
5291
5290
  let hash = 5381;
5292
- for (let i = 0; i < content2.length; i++) {
5293
- hash = (hash << 5) + hash + content2.charCodeAt(i);
5291
+ for (let i = 0; i < content.length; i++) {
5292
+ hash = (hash << 5) + hash + content.charCodeAt(i);
5294
5293
  hash &= hash;
5295
5294
  }
5296
5295
  return Math.abs(hash).toString(16).padStart(8, "0");
@@ -5302,8 +5301,8 @@ var ONTOLOGICAL_NODE_TYPES = [
5302
5301
  "function",
5303
5302
  "value_chain"
5304
5303
  ];
5305
- function isOntologicalNodeType(nodeType2) {
5306
- return ONTOLOGICAL_NODE_TYPES.includes(nodeType2);
5304
+ function isOntologicalNodeType(nodeType) {
5305
+ return ONTOLOGICAL_NODE_TYPES.includes(nodeType);
5307
5306
  }
5308
5307
  function normalizeCanonicalEntityText(value) {
5309
5308
  return value.trim().toLowerCase().replace(/\s+/g, " ");
@@ -6103,10 +6102,8 @@ async function queryRegistryRows(ctx, args) {
6103
6102
  async function listAudienceRegistryRows(ctx, args) {
6104
6103
  return queryRegistryRows(ctx, args);
6105
6104
  }
6106
- componentsGeneric();
6107
- var internal2 = anyApi;
6108
6105
 
6109
- // ../schema-management/src/enumValidation.ts
6106
+ // ../../packages/contracts/src/schema-helpers/enumValidation.ts
6110
6107
  var BUILTIN_ENUM_FALLBACK = {
6111
6108
  topic_type: /* @__PURE__ */ new Set([
6112
6109
  "domain",
@@ -6149,7 +6146,6 @@ var BUILTIN_ENUM_FALLBACK = {
6149
6146
  "tradeoff",
6150
6147
  "policy",
6151
6148
  "implementation_choice",
6152
- // Coding intelligence domain
6153
6149
  "implementation_decision",
6154
6150
  "interface_contract",
6155
6151
  "migration_state",
@@ -6157,25 +6153,16 @@ var BUILTIN_ENUM_FALLBACK = {
6157
6153
  "deprecation_notice"
6158
6154
  ]),
6159
6155
  edge_type: /* @__PURE__ */ new Set([
6160
- // === 6 CANONICAL EPISTEMIC TYPES ===
6161
6156
  "supports",
6162
- // L3↔L3: belief bears on belief (weight -1 to +1)
6163
6157
  "informs",
6164
- // L2→L3: evidence bears on belief
6165
6158
  "depends_on",
6166
- // L3→L3, Q→Q: structural gate
6167
6159
  "derived_from",
6168
- // Any→Any: provenance chain
6169
6160
  "contains",
6170
- // Any→Any: hierarchy, scoping, membership
6171
6161
  "tests",
6172
- // Q→L3: question interrogates belief
6173
- // === STRUCTURAL / LIFECYCLE ===
6174
6162
  "supersedes",
6175
6163
  "responds_to",
6176
6164
  "belongs_to",
6177
6165
  "relates_to_thesis",
6178
- // === ONTOLOGICAL (tenant-extensible) ===
6179
6166
  "works_at",
6180
6167
  "invested_in",
6181
6168
  "competes_with",
@@ -6224,27 +6211,12 @@ var BUILTIN_ENUM_FALLBACK = {
6224
6211
  function normalizeEnumValue(value) {
6225
6212
  return value.trim().toLowerCase();
6226
6213
  }
6227
- async function validateSchemaEnumValue(ctx, args) {
6214
+ async function validateSchemaEnumValue(_ctx, args) {
6228
6215
  const normalized = normalizeEnumValue(args.value);
6229
6216
  if (!normalized) {
6230
6217
  return { valid: false, source: "none" };
6231
6218
  }
6232
- try {
6233
- const validFromSchema = await ctx.runQuery(
6234
- internal2.schemaConfig.internalValidate,
6235
- {
6236
- category: args.category,
6237
- value: normalized,
6238
- tenantId: args.tenantId
6239
- }
6240
- );
6241
- if (validFromSchema) {
6242
- return { valid: true, source: "schema" };
6243
- }
6244
- } catch {
6245
- }
6246
- const fallback = BUILTIN_ENUM_FALLBACK[args.category];
6247
- if (fallback.has(normalized)) {
6219
+ if (BUILTIN_ENUM_FALLBACK[args.category].has(normalized)) {
6248
6220
  return { valid: true, source: "builtin" };
6249
6221
  }
6250
6222
  return { valid: false, source: "none" };
@@ -6265,572 +6237,36 @@ async function assertSchemaEnumValue(ctx, args) {
6265
6237
  if (!validation.valid) {
6266
6238
  const tenantHint = args.tenantId ? ` for tenant ${args.tenantId}` : "";
6267
6239
  throw new Error(
6268
- `[${args.context}] Invalid value "${normalized}" for category "${args.category}"${tenantHint}. Add it to schemaEnumConfig before use.`
6240
+ `[${args.context}] Invalid value "${normalized}" for category "${args.category}"${tenantHint}. Add it to the contracts schema enum manifest before use.`
6269
6241
  );
6270
6242
  }
6271
6243
  return normalized;
6272
6244
  }
6273
- v.number();
6274
- v.union(
6275
- v.literal("very_high"),
6276
- // 0.9+
6277
- v.literal("high"),
6278
- // 0.7-0.9
6279
- v.literal("medium"),
6280
- // 0.4-0.7
6281
- v.literal("low"),
6282
- // 0.2-0.4
6283
- v.literal("very_low")
6284
- // 0-0.2
6285
- );
6286
- v.union(
6287
- v.literal(1),
6288
- // Critical
6289
- v.literal(2),
6290
- // High
6291
- v.literal(3),
6292
- // Medium
6293
- v.literal(4),
6294
- // Low
6295
- v.literal(5)
6296
- // Backlog
6297
- );
6298
- v.union(
6299
- v.literal("critical"),
6300
- v.literal("high"),
6301
- v.literal("medium"),
6302
- v.literal("low"),
6303
- v.literal("backlog")
6304
- );
6305
- v.union(
6306
- v.literal("active"),
6307
- v.literal("paused"),
6308
- v.literal("completed"),
6309
- v.literal("archived")
6310
- );
6311
- v.union(
6312
- v.literal("pending"),
6313
- v.literal("processing"),
6314
- v.literal("completed"),
6315
- v.literal("failed")
6316
- );
6317
- v.object({
6318
- crunchbaseId: v.optional(v.string()),
6319
- linkedinUrl: v.optional(v.string()),
6320
- pitchbookId: v.optional(v.string()),
6321
- twitterUrl: v.optional(v.string()),
6322
- domain: v.optional(v.string())
6323
- });
6324
- var sourceType = v.union(
6325
- v.literal("proprietary"),
6326
- // Internal Stack research
6327
- v.literal("primary"),
6328
- // Direct interviews, calls
6329
- v.literal("secondary"),
6330
- // Published sources
6331
- v.literal("ai_generated"),
6332
- // AI-synthesized
6333
- v.literal("user_input"),
6334
- // Manual user entry
6335
- v.literal("inferred")
6336
- // System inference
6337
- );
6338
- v.object({
6339
- sourceType: v.optional(sourceType),
6340
- sourceId: v.optional(v.string()),
6341
- // Reference to source entity
6342
- sourceUrl: v.optional(v.string()),
6343
- sourceDate: v.optional(v.number()),
6344
- sourceName: v.optional(v.string())
6345
- });
6346
- v.object({
6347
- cursor: v.optional(v.string()),
6348
- limit: v.optional(v.number())
6349
- });
6350
- v.object({
6351
- hasMore: v.boolean(),
6352
- nextCursor: v.optional(v.string()),
6353
- totalCount: v.optional(v.number())
6354
- });
6355
- var richTextContent = v.object({
6356
- type: v.literal("doc"),
6357
- content: looseJsonArray
6358
- });
6359
- v.union(v.string(), richTextContent);
6360
- v.object({
6361
- promptTokens: v.optional(v.number()),
6362
- completionTokens: v.optional(v.number()),
6363
- totalTokens: v.optional(v.number())
6364
- });
6365
- v.object({
6366
- fileName: v.optional(v.string()),
6367
- fileSize: v.optional(v.number()),
6368
- mimeType: v.optional(v.string()),
6369
- storageId: v.optional(v.id("_storage")),
6370
- externalUrl: v.optional(v.string())
6371
- });
6372
6245
 
6373
- // ../schema-management/src/spine/tables/epistemicNodes.ts
6374
- var nodeType = v.union(
6375
- // --- L4: Audit Targets (decisions, outcomes) ---
6376
- v.literal("decision"),
6377
- // Investment decision with knowledge horizon snapshot
6378
- // --- L3: Traversal Anchors (epistemic structure) ---
6379
- v.literal("belief"),
6380
- // Structured conviction (immutable formulation)
6381
- v.literal("question"),
6382
- // Unit of uncertainty
6383
- v.literal("theme"),
6384
- // Investment thesis / conviction cluster
6385
- v.literal("deal"),
6386
- // Investment evaluation process
6387
- v.literal("topic"),
6388
- // Hierarchical knowledge container
6389
- // --- L2: Compression Boundary (minimum reasoning unit) ---
6390
- v.literal("claim"),
6391
- // Atomic assertion that can be true/false
6392
- v.literal("evidence"),
6393
- // Interpreted signal linked to beliefs
6394
- v.literal("synthesis"),
6395
- // Primers, deep research
6396
- v.literal("answer"),
6397
- // Immutable answer snapshot for a question
6398
- // --- L1: Terminal Leaves (non-traversable, grounding) ---
6399
- v.literal("atomic_fact"),
6400
- // Raw fact from source (not interpreted)
6401
- v.literal("excerpt"),
6402
- // Direct quote from source document
6403
- v.literal("source"),
6404
- // News, documents, transcripts
6405
- // --- Ontological Entities (things in the world) ---
6406
- v.literal("company"),
6407
- // Organization (subtype: private, corporate, portfolio)
6408
- v.literal("person"),
6409
- // Individual (founder, expert, LP, contact)
6410
- v.literal("investor"),
6411
- // Investment entity (subtype: vc, lp, cvc, pe, family_office, angel)
6412
- v.literal("function"),
6413
- // What a company does (from classifier)
6414
- v.literal("value_chain")
6415
- // Market structure / value flow
6416
- );
6417
- var epistemicLayer = v.union(
6418
- v.literal("L4"),
6419
- // Decisions, outcomes - audit targets
6420
- v.literal("L3"),
6421
- // Beliefs, questions, themes - traversal anchors
6422
- v.literal("L2"),
6423
- // Claims, evidence, synthesis - compression boundary
6424
- v.literal("L1"),
6425
- // Atomic facts, excerpts, sources - terminal leaves
6426
- v.literal("ontological"),
6427
- // Companies, people, etc - not epistemic
6428
- v.literal("organizational")
6429
- // Topics, lenses, worktrees — structural containers
6430
- );
6431
- var nodeStatus = v.union(
6432
- v.literal("active"),
6433
- v.literal("superseded"),
6434
- // Replaced by newer version
6435
- v.literal("archived"),
6436
- v.literal("deleted")
6437
- );
6438
- var sourceType2 = v.union(
6439
- v.literal("human"),
6440
- // User created directly
6441
- v.literal("ai_extracted"),
6442
- // LLM extracted from a source
6443
- v.literal("ai_generated"),
6444
- // LLM synthesized/created
6445
- v.literal("imported"),
6446
- // External system import
6447
- v.literal("system"),
6448
- // System-generated (migrations, classifiers)
6449
- v.literal("verified"),
6450
- // Human-verified source
6451
- v.literal("proprietary")
6452
- // Proprietary/internal data
6453
- );
6454
- var verificationStatus = v.union(
6455
- v.literal("unverified"),
6456
- v.literal("human_verified"),
6457
- v.literal("ai_verified"),
6458
- v.literal("contradicted"),
6459
- v.literal("outdated")
6460
- );
6461
- var syncStatus = v.union(
6462
- v.literal("synced"),
6463
- // Node and edges fully synced to Neo4j
6464
- v.literal("pending_edges"),
6465
- // Node created, edges being created
6466
- v.literal("edge_creation_failed")
6467
- // Edge creation failed, needs retry
6468
- );
6469
- var audienceLabel = v.string();
6470
- var sensitivityTier = v.union(
6471
- v.literal("low"),
6472
- v.literal("medium"),
6473
- v.literal("high"),
6474
- v.literal("restricted")
6475
- );
6476
- var exportClass = v.union(
6477
- v.literal("internal_only"),
6478
- v.literal("client_safe"),
6479
- v.literal("public_safe"),
6480
- v.literal("restricted")
6481
- );
6482
- var anonymizationClass = v.union(
6483
- v.literal("none"),
6484
- v.literal("standard"),
6485
- v.literal("strict")
6486
- );
6487
- var epistemicStatus = v.union(
6488
- v.literal("hypothesis"),
6489
- // Initial conjecture, low evidence
6490
- v.literal("emerging"),
6491
- // Building evidence, gaining traction
6492
- v.literal("established"),
6493
- // Well-evidenced, core to thesis
6494
- v.literal("challenged"),
6495
- // Contradicting evidence appeared
6496
- v.literal("assumption"),
6497
- // Taken as given, not actively tested
6498
- v.literal("deprecated")
6499
- // Superseded or abandoned
6500
- );
6501
- var beliefStatus = v.union(
6502
- v.literal("assumption"),
6503
- v.literal("hypothesis"),
6504
- v.literal("belief"),
6505
- v.literal("fact")
6506
- );
6507
- var reversibility = v.union(
6508
- v.literal("irreversible"),
6509
- // One-way door decision
6510
- v.literal("hard_to_reverse"),
6511
- // Significant cost to undo
6512
- v.literal("reversible"),
6513
- // Can change course with moderate effort
6514
- v.literal("trivial")
6515
- // Easy to adjust
6516
- );
6517
- var predictionOutcome = v.union(
6518
- v.literal("pending"),
6519
- v.literal("confirmed"),
6520
- v.literal("disconfirmed"),
6521
- v.literal("partial"),
6522
- v.literal("expired")
6523
- );
6524
- var predictionMeta = v.object({
6525
- isPrediction: v.boolean(),
6526
- registeredAt: v.number(),
6527
- // When prediction was made
6528
- expectedBy: v.optional(v.number()),
6529
- // When we expect resolution
6530
- outcome: v.optional(predictionOutcome),
6531
- outcomeRecordedAt: v.optional(v.number()),
6532
- outcomeEvidenceId: v.optional(v.string()),
6533
- // globalId of confirming evidence
6534
- confidenceAtPrediction: v.optional(v.number()),
6535
- // 0-1
6536
- actualVsPredicted: v.optional(v.string())
6537
- // Notes on how outcome compared
6538
- });
6539
- var methodology = v.union(
6540
- // Primary Research (high value)
6541
- v.literal("primary_research"),
6542
- // Direct investigation
6543
- v.literal("expert_interview"),
6544
- // Expert call/interview
6545
- v.literal("customer_interview"),
6546
- // Customer research
6547
- v.literal("field_observation"),
6548
- // On-site observation
6549
- v.literal("proprietary_data"),
6550
- // Internal data analysis
6551
- // Secondary Research
6552
- v.literal("desk_research"),
6553
- // Public sources
6554
- v.literal("regulatory_filing"),
6555
- // SEC, regulatory docs
6556
- v.literal("news_article"),
6557
- // News/press
6558
- v.literal("academic_paper"),
6559
- // Academic research
6560
- // AI-Assisted
6561
- v.literal("ai_synthesis"),
6562
- // AI-generated synthesis
6563
- v.literal("ai_extraction")
6564
- // AI-extracted from source
6565
- );
6566
- var informationAsymmetry = v.union(
6567
- v.literal("proprietary"),
6568
- // Only we have this
6569
- v.literal("early"),
6570
- // We're early but others will get it
6571
- v.literal("common")
6572
- // Everyone has access
6573
- );
6574
- var temporalNature = v.union(
6575
- v.literal("factual"),
6576
- // Resolved outcome. Grounded in reality.
6577
- v.literal("forecast"),
6578
- // Prediction. Will resolve. Discounted weight.
6579
- v.literal("unknown")
6580
- // Not yet classified.
6581
- );
6582
- var questionType = v.union(
6583
- v.literal("validation"),
6584
- // Does evidence support this belief?
6585
- v.literal("falsification"),
6586
- // What would prove this belief wrong?
6587
- v.literal("assumption_probe"),
6588
- // Is this unstated assumption true?
6589
- v.literal("prediction_test"),
6590
- // Will this predicted outcome occur?
6591
- v.literal("counterfactual"),
6592
- // What would we expect if X were false?
6593
- v.literal("discovery"),
6594
- // What don't we know yet?
6595
- v.literal("clarification"),
6596
- // What does X actually mean?
6597
- v.literal("comparison"),
6598
- // How does X compare to Y?
6599
- v.literal("causal"),
6600
- // What caused X?
6601
- v.literal("mechanism"),
6602
- // How does X work?
6603
- v.literal("general")
6604
- // Unclassified
6605
- );
6606
- var questionPriority = v.union(
6607
- v.literal("critical"),
6608
- // Blocks decision-making
6609
- v.literal("high"),
6610
- // Important for thesis
6611
- v.literal("medium"),
6612
- // Would be nice to know
6613
- v.literal("low")
6614
- // Background/curiosity
6615
- );
6616
- var answerQuality = v.union(
6617
- v.literal("definitive"),
6618
- // Clear, well-supported
6619
- v.literal("strong"),
6620
- // Good evidence, high confidence
6621
- v.literal("moderate"),
6622
- // Some evidence
6623
- v.literal("weak"),
6624
- // Limited evidence
6625
- v.literal("speculative"),
6626
- // Mostly conjecture
6627
- v.literal("unanswered")
6628
- // No answer yet
6629
- );
6630
- var consensusView = v.union(
6631
- v.literal("aligned"),
6632
- // We agree with market consensus
6633
- v.literal("ahead_of"),
6634
- // We see this before consensus does
6635
- v.literal("contrarian"),
6636
- // We actively disagree with consensus
6637
- v.literal("orthogonal"),
6638
- // We're looking at something consensus isn't discussing
6639
- v.literal("unknown")
6640
- // We don't know what consensus thinks
6641
- );
6642
- var themeConviction = v.union(
6643
- v.literal("high"),
6644
- // Strong conviction, actively deploying
6645
- v.literal("medium"),
6646
- // Building conviction
6647
- v.literal("low"),
6648
- // Exploring, not convicted
6649
- v.literal("negative")
6650
- // Actively avoiding
6651
- );
6652
- var decisionType = v.union(
6653
- v.literal("invest"),
6654
- v.literal("pass"),
6655
- v.literal("follow_on"),
6656
- v.literal("exit"),
6657
- v.literal("deep_dive"),
6658
- v.literal("monitor"),
6659
- v.literal("deprioritize"),
6660
- v.literal("thesis_adopt"),
6661
- v.literal("thesis_revise"),
6662
- v.literal("thesis_abandon")
6663
- );
6664
- var decisionOutcome = v.union(
6665
- v.literal("pending"),
6666
- v.literal("successful"),
6667
- v.literal("unsuccessful"),
6668
- v.literal("mixed"),
6669
- v.literal("unknown")
6670
- );
6671
- var externalIds2 = v.object({
6672
- crunchbase: v.optional(v.string()),
6673
- linkedin: v.optional(v.string()),
6674
- pitchbook: v.optional(v.string()),
6675
- twitter: v.optional(v.string()),
6676
- website: v.optional(v.string())
6677
- });
6678
- defineTable({
6679
- // === IDENTITY ===
6680
- globalId: v.string(),
6681
- // UUID - survives migration to Neo4j
6682
- // === TYPE ===
6683
- nodeType,
6684
- // === EPISTEMIC LAYER ===
6685
- epistemicLayer: v.optional(epistemicLayer),
6686
- // === SUBTYPE (for typed entities) ===
6687
- subtype: v.optional(v.string()),
6688
- // company: private|corporate|portfolio, investor: vc|lp|cvc|pe|family_office|angel
6689
- // === CONTENT ===
6690
- canonicalText: v.string(),
6691
- // The core content (belief statement, company name, etc.)
6692
- contentHash: v.string(),
6693
- // SHA256(nodeType + canonicalText) for deduplication
6694
- // Extended content (for sources/syntheses)
6695
- content: v.optional(v.string()),
6696
- // Full text for documents/articles
6697
- contentType: v.optional(v.string()),
6698
- // "markdown", "html", "pdf", "text"
6699
- // === METADATA ===
6700
- title: v.optional(v.string()),
6701
- // Display title
6702
- tags: v.optional(v.array(v.string())),
6703
- domain: v.optional(v.string()),
6704
- // For companies: website domain
6705
- // Type-specific metadata (flexible object - LEGACY)
6706
- // New code should use the typed fields below when available
6707
- metadata: v.optional(looseJsonObject),
6708
- // === POLICY / ENTITLEMENT ===
6709
- tenantId: v.optional(v.string()),
6710
- workspaceId: v.optional(v.string()),
6711
- ownerPrincipalId: v.optional(v.string()),
6712
- audienceLabel: v.optional(audienceLabel),
6713
- policyTags: v.optional(v.array(v.string())),
6714
- sensitivityTier: v.optional(sensitivityTier),
6715
- exportClass: v.optional(exportClass),
6716
- anonymizationClass: v.optional(anonymizationClass),
6717
- // === PUBLICATION (visibility-based, not copy-based) ===
6718
- // Publication expands who can see a workspace-local node — the node stays
6719
- // in its workspace, like a microservice exposing part of its API surface.
6720
- // Rules-based: pack/tenant-level publicationRules auto-evaluate on
6721
- // confidence changes and node creation. No manual click-by-click.
6722
- publicationStatus: v.optional(
6723
- v.union(
6724
- v.literal("unpublished"),
6725
- // Default: workspace-local only
6726
- v.literal("published"),
6727
- // Visible at tenant scope (rules matched)
6728
- v.literal("suppressed")
6729
- // Manually blocked even if rules match
6730
- )
6731
- ),
6732
- publishedAt: v.optional(v.number()),
6733
- // When publication status last changed to published
6734
- publishedBy: v.optional(v.string()),
6735
- // userId or "system:publication_rules" for auto-publish
6736
- // === TYPED METADATA FIELDS ===
6737
- // --- Belief ---
6738
- // Belief type — validated against schemaEnumConfig category "belief_type"
6739
- // Platform core: hypothesis, belief, principle, invariant, assumption,
6740
- // tenet, prior, preference, goal, forecast
6741
- beliefType: v.optional(v.string()),
6742
- beliefStatus: v.optional(beliefStatus),
6743
- epistemicStatus: v.optional(epistemicStatus),
6744
- reversibility: v.optional(reversibility),
6745
- predictionMeta: v.optional(predictionMeta),
6746
- // Consensus tracking (for non-consensus detection)
6747
- consensusView: v.optional(consensusView),
6748
- consensusConfidence: v.optional(v.number()),
6749
- // 0-1: What we think consensus confidence is
6750
- consensusSource: v.optional(v.string()),
6751
- // Where we got the consensus view (twitter, reports, etc.)
6752
- // --- Evidence ---
6753
- methodology: v.optional(methodology),
6754
- informationAsymmetry: v.optional(informationAsymmetry),
6755
- temporalNature: v.optional(temporalNature),
6756
- // --- Question ---
6757
- questionType: v.optional(questionType),
6758
- questionPriority: v.optional(questionPriority),
6759
- answerQuality: v.optional(answerQuality),
6760
- // --- Theme ---
6761
- themeConviction: v.optional(themeConviction),
6762
- // Market timing (for "early on theme" detection)
6763
- marketAwarenessDate: v.optional(v.number()),
6764
- // When this theme became broadly discussed
6765
- marketAwarenessSource: v.optional(v.string()),
6766
- // How we know (first major report, twitter volume spike, etc.)
6767
- earlySignalIds: v.optional(v.array(v.string())),
6768
- // globalIds of evidence we had before market awareness
6769
- // --- Decision ---
6770
- decisionType: v.optional(decisionType),
6771
- decisionOutcome: v.optional(decisionOutcome),
6772
- // === EXTERNAL IDS (for ontological entities) ===
6773
- externalIds: v.optional(externalIds2),
6774
- // === PROVENANCE ===
6775
- sourceType: sourceType2,
6776
- aiProvider: v.optional(v.string()),
6777
- // "claude", "gemini", "gpt-4", etc.
6778
- extractedFromNodeId: v.optional(v.id("epistemicNodes")),
6779
- // Quick reference to source
6780
- // === EXTRACTION CONTEXT ===
6781
- extractionModel: v.optional(v.string()),
6782
- // "claude-sonnet-4-20250514"
6783
- extractionPromptName: v.optional(v.string()),
6784
- // "lucern/extract-evidence"
6785
- extractionPromptVersion: v.optional(v.number()),
6786
- extractionTemperature: v.optional(v.number()),
6787
- extractionLangfuseTraceId: v.optional(v.string()),
6788
- // === GROUNDING VERIFICATION ===
6789
- groundingVerified: v.optional(v.boolean()),
6790
- groundingConfidence: v.optional(v.number()),
6791
- // 0-1 match quality
6792
- groundingMatchedText: v.optional(v.string()),
6793
- // Actual text from source
6794
- groundingStartOffset: v.optional(v.number()),
6795
- groundingEndOffset: v.optional(v.number()),
6796
- groundingRejectionReason: v.optional(v.string()),
6797
- // === CONFIDENCE & VERIFICATION ===
6798
- confidence: v.optional(v.number()),
6799
- // 0-1 projected probability P(x) = b + a*u
6800
- verificationStatus: v.optional(verificationStatus),
6801
- // === SL OPINION (Subjective Logic — Kernel v2) ===
6802
- // Replaces scalar confidence with rich epistemic state.
6803
- // b + d + u = 1. P(x) = b + a*u is stored in `confidence` for backward compat.
6804
- opinion_b: v.optional(v.number()),
6805
- // Belief: evidence FOR (0-1)
6806
- opinion_d: v.optional(v.number()),
6807
- // Disbelief: evidence AGAINST (0-1)
6808
- opinion_u: v.optional(v.number()),
6809
- // Uncertainty: absence of evidence (0-1)
6810
- opinion_a: v.optional(v.number()),
6811
- // Base rate / prior probability (0-1)
6812
- tupleContradicted: v.optional(v.boolean()),
6813
- // Single-belief tuple-space contradiction flag
6814
- // === LIFECYCLE ===
6815
- status: nodeStatus,
6816
- supersededBy: v.optional(v.id("epistemicNodes")),
6817
- // === OWNERSHIP ===
6818
- topicId: v.optional(v.string()),
6819
- // Canonical scope container (topic-first model)
6820
- projectId: v.optional(v.string()),
6821
- // DEPRECATED: Use belongs_to edges
6822
- createdBy: v.string(),
6823
- // Clerk user ID
6824
- createdAt: v.number(),
6825
- updatedAt: v.number(),
6826
- // === NEO4J SYNC STATUS ===
6827
- syncStatus: v.optional(syncStatus),
6828
- syncError: v.optional(v.string())
6829
- // Error message if sync failed
6830
- }).index("by_globalId", ["globalId"]).index("by_contentHash", ["contentHash"]).index("by_nodeType", ["nodeType"]).index("by_subtype", ["nodeType", "subtype"]).index("by_domain", ["domain"]).index("by_project", ["projectId"]).index("by_project_type", ["projectId", "nodeType"]).index("by_topic", ["topicId"]).index("by_topic_type", ["topicId", "nodeType"]).index("by_tenantId", ["tenantId"]).index("by_workspaceId", ["workspaceId"]).index("by_tenant_workspace", ["tenantId", "workspaceId"]).index("by_audienceLabel", ["audienceLabel"]).index("by_sensitivityTier", ["sensitivityTier"]).index("by_exportClass", ["exportClass"]).index("by_status", ["status"]).index("by_sourceType", ["sourceType"]).index("by_verification", ["verificationStatus"]).index("by_layer", ["epistemicLayer"]).index("by_layer_type", ["epistemicLayer", "nodeType"]).index("by_syncStatus", ["syncStatus"]).index("by_publicationStatus", ["publicationStatus"]).index("by_tenant_publicationStatus", ["tenantId", "publicationStatus"]).index("by_belief_status", ["nodeType", "beliefStatus"]).index("by_epistemic_status", ["nodeType", "epistemicStatus"]).index("by_temporal_nature", ["nodeType", "temporalNature"]).index("by_methodology", ["nodeType", "methodology"]).index("by_reversibility", ["nodeType", "reversibility"]).index("by_questionType", ["nodeType", "questionType"]).index("by_questionPriority", ["nodeType", "questionPriority"]).searchIndex("search_canonicalText", {
6831
- searchField: "canonicalText",
6832
- filterFields: ["nodeType", "projectId", "topicId", "status"]
6833
- });
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
+ }
6834
6270
  function getLayerForNodeType(type) {
6835
6271
  switch (type) {
6836
6272
  case "decision":
@@ -6878,7 +6314,7 @@ function throwWorkspaceIsolationError(args) {
6878
6314
  throw error;
6879
6315
  }
6880
6316
  function assertWorkspaceScopedEpistemicNodeScope(args) {
6881
- const layer = getLayerForNodeType(args.nodeType);
6317
+ const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
6882
6318
  if (layer === "ontological") {
6883
6319
  return;
6884
6320
  }
@@ -6906,11 +6342,11 @@ function nodeMatchesWorkspaceReasoningScope(node, scope) {
6906
6342
  const scopeWorkspaceId = normalizeScopeValue3(scope.workspaceId);
6907
6343
  const nodeTenantId = normalizeScopeValue3(node.tenantId);
6908
6344
  const nodeWorkspaceId = normalizeScopeValue3(node.workspaceId);
6909
- const epistemicLayer2 = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
6345
+ const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
6910
6346
  if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
6911
6347
  return false;
6912
6348
  }
6913
- if (epistemicLayer2 === "ontological" && nodeWorkspaceId === void 0) {
6349
+ if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
6914
6350
  return true;
6915
6351
  }
6916
6352
  if (!scopeWorkspaceId && node.publicationStatus === "published") {
@@ -6938,11 +6374,11 @@ function edgeMatchesWorkspaceReasoningScope(edge, scope) {
6938
6374
  return scopeWorkspaceId === edgeWorkspaceId;
6939
6375
  }
6940
6376
  async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
6941
- const epistemicLayer2 = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
6377
+ const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
6942
6378
  const resolved = {
6943
6379
  tenantId: normalizeScopeValue3(node?.tenantId),
6944
6380
  workspaceId: normalizeScopeValue3(node?.workspaceId),
6945
- epistemicLayer: epistemicLayer2,
6381
+ epistemicLayer,
6946
6382
  nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
6947
6383
  };
6948
6384
  if (!node) {
@@ -7294,10 +6730,10 @@ function deriveSyntheticBackfillOpinion(source) {
7294
6730
  a: 0.5
7295
6731
  });
7296
6732
  }
7297
- const confidence2 = clamp014(readFiniteNumber(source.confidence) ?? 0);
6733
+ const confidence = clamp014(readFiniteNumber(source.confidence) ?? 0);
7298
6734
  return {
7299
- b: confidence2,
7300
- d: 1 - confidence2,
6735
+ b: confidence,
6736
+ d: 1 - confidence,
7301
6737
  u: 0,
7302
6738
  a: 0.5
7303
6739
  };
@@ -7341,10 +6777,10 @@ function formatTupleContradictionDescription(args) {
7341
6777
  return `Tuple-space contradiction detected: b=${args.opinion.b.toFixed(2)} > ${args.policy.beliefThreshold.toFixed(2)} and d=${args.opinion.d.toFixed(2)} > ${args.policy.disbeliefThreshold.toFixed(2)}.`;
7342
6778
  }
7343
6779
  function generateContentHash2(text) {
7344
- const content2 = `belief:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
6780
+ const content = `belief:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
7345
6781
  let hash = 5381;
7346
- for (let i = 0; i < content2.length; i++) {
7347
- hash = (hash << 5) + hash + content2.charCodeAt(i);
6782
+ for (let i = 0; i < content.length; i++) {
6783
+ hash = (hash << 5) + hash + content.charCodeAt(i);
7348
6784
  hash &= hash;
7349
6785
  }
7350
6786
  return Math.abs(hash).toString(16).padStart(8, "0");
@@ -7421,8 +6857,8 @@ async function resolveBeliefScopeOrNull(ctx, args) {
7421
6857
  }
7422
6858
  async function getBeliefNodesForScope(ctx, scope, args) {
7423
6859
  const baseQuery = ctx.db.query("epistemicNodes").withIndex(
7424
- scope.topicId ? "by_topic_type" : "by_project_type",
7425
- (q) => scope.topicId ? q.eq("topicId", scope.topicId).eq("nodeType", "belief") : q.eq("projectId", scope.projectId).eq("nodeType", "belief")
6860
+ "by_topic_type",
6861
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
7426
6862
  );
7427
6863
  const nodes = typeof args?.scanLimit === "number" ? await baseQuery.order("desc").take(args.scanLimit) : await baseQuery.collect();
7428
6864
  const scopedNodes = nodes.filter(
@@ -7573,7 +7009,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
7573
7009
  }
7574
7010
  }
7575
7011
  const previousConfidence = node.confidence || 0.5;
7576
- const predictionMeta2 = node.predictionMeta || existingMetadata.predictionMeta;
7012
+ const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
7577
7013
  const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
7578
7014
  const slB = args.belief;
7579
7015
  const slD = args.disbelief;
@@ -7600,7 +7036,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
7600
7036
  currentBeliefStatus,
7601
7037
  {
7602
7038
  confidence: derivedConfidence,
7603
- predictionMeta: predictionMeta2,
7039
+ predictionMeta,
7604
7040
  metadata: existingMetadata
7605
7041
  }
7606
7042
  );
@@ -8254,8 +7690,8 @@ var getByProject3 = query({
8254
7690
  }
8255
7691
  }
8256
7692
  const query2 = ctx.db.query("epistemicNodes").withIndex(
8257
- scope.topicId ? "by_topic_type" : "by_project_type",
8258
- (q) => scope.topicId ? q.eq("topicId", scope.topicId).eq("nodeType", "belief") : q.eq("projectId", scope.projectId).eq("nodeType", "belief")
7693
+ "by_topic_type",
7694
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
8259
7695
  );
8260
7696
  const nodes = await query2.order("desc").take(scanLimit);
8261
7697
  const scopedNodes = nodes.filter(
@@ -8893,9 +8329,13 @@ var getCountByStatus = query({
8893
8329
  },
8894
8330
  returns: permissiveReturn,
8895
8331
  handler: async (ctx, args) => {
8332
+ const scope = await resolveBeliefScopeOrNull(ctx, args);
8333
+ if (!scope) {
8334
+ return { active: 0, superseded: 0, archived: 0, total: 0 };
8335
+ }
8896
8336
  const nodes = await ctx.db.query("epistemicNodes").withIndex(
8897
- args.topicId ? "by_topic_type" : "by_project_type",
8898
- (q) => args.topicId ? q.eq("topicId", args.topicId).eq("nodeType", "belief") : q.eq("projectId", args.projectId).eq("nodeType", "belief")
8337
+ "by_topic_type",
8338
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
8899
8339
  ).collect();
8900
8340
  const counts = {
8901
8341
  active: 0,
@@ -9460,8 +8900,8 @@ var getByPillar = query({
9460
8900
  return [];
9461
8901
  }
9462
8902
  const nodes = await ctx.db.query("epistemicNodes").withIndex(
9463
- scope.topicId ? "by_topic_type" : "by_project_type",
9464
- (q) => scope.topicId ? q.eq("topicId", scope.topicId).eq("nodeType", "belief") : q.eq("projectId", scope.projectId).eq("nodeType", "belief")
8903
+ "by_topic_type",
8904
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
9465
8905
  ).collect();
9466
8906
  return nodes.filter((n) => {
9467
8907
  const metadata = n.metadata;
@@ -12117,10 +11557,10 @@ __export(epistemicAnswers_exports, {
12117
11557
  getVersionHistory: () => getVersionHistory
12118
11558
  });
12119
11559
  function generateContentHash3(text) {
12120
- const content2 = `answer:${text.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 500)}`;
11560
+ const content = `answer:${text.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 500)}`;
12121
11561
  let hash = 5381;
12122
- for (let i = 0; i < content2.length; i++) {
12123
- hash = (hash << 5) + hash + content2.charCodeAt(i);
11562
+ for (let i = 0; i < content.length; i++) {
11563
+ hash = (hash << 5) + hash + content.charCodeAt(i);
12124
11564
  hash &= hash;
12125
11565
  }
12126
11566
  return Math.abs(hash).toString(16).padStart(8, "0");
@@ -12312,9 +11752,9 @@ var create4 = mutation({
12312
11752
  });
12313
11753
  }
12314
11754
  }
12315
- const answerQuality2 = args.confidence || "moderate";
11755
+ const answerQuality = args.confidence || "moderate";
12316
11756
  await ctx.db.patch(args.questionNodeId, {
12317
- answerQuality: answerQuality2,
11757
+ answerQuality,
12318
11758
  updatedAt: now
12319
11759
  });
12320
11760
  await ctx.db.insert("epistemicAudit", {
@@ -12329,7 +11769,7 @@ var create4 = mutation({
12329
11769
  answerText: args.answerText.slice(0, 200),
12330
11770
  versionNumber,
12331
11771
  questionNodeId: String(args.questionNodeId),
12332
- confidence: answerQuality2
11772
+ confidence: answerQuality
12333
11773
  }
12334
11774
  });
12335
11775
  return { nodeId, globalId, versionNumber };
@@ -12513,9 +11953,9 @@ var createInternal = internalMutation({
12513
11953
  });
12514
11954
  }
12515
11955
  }
12516
- const answerQuality2 = args.confidence || "moderate";
11956
+ const answerQuality = args.confidence || "moderate";
12517
11957
  await ctx.db.patch(args.questionNodeId, {
12518
- answerQuality: answerQuality2,
11958
+ answerQuality,
12519
11959
  updatedAt: now
12520
11960
  });
12521
11961
  await ctx.db.insert("epistemicAudit", {
@@ -12548,12 +11988,12 @@ var getByQuestion = query({
12548
11988
  return [];
12549
11989
  }
12550
11990
  const topicId = questionNode.topicId;
12551
- const answers = topicId ? await ctx.db.query("epistemicNodes").withIndex(
11991
+ if (!topicId) {
11992
+ return [];
11993
+ }
11994
+ const answers = await ctx.db.query("epistemicNodes").withIndex(
12552
11995
  "by_topic_type",
12553
11996
  (q) => q.eq("topicId", topicId).eq("nodeType", "answer")
12554
- ).collect() : await ctx.db.query("epistemicNodes").withIndex(
12555
- "by_project_type",
12556
- (q) => q.eq("projectId", questionNode.projectId).eq("nodeType", "answer")
12557
11997
  ).collect();
12558
11998
  const questionIdStr = String(args.questionNodeId);
12559
11999
  const filtered = answers.filter((a) => {
@@ -12581,18 +12021,13 @@ var getLatestForQuestion = query({
12581
12021
  if (!questionNode || questionNode.nodeType !== "question") {
12582
12022
  return null;
12583
12023
  }
12584
- let answers;
12585
- if (questionNode.topicId) {
12586
- answers = await ctx.db.query("epistemicNodes").withIndex(
12587
- "by_topic_type",
12588
- (q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
12589
- ).filter((q) => q.eq(q.field("status"), "active")).collect();
12590
- } else {
12591
- answers = await ctx.db.query("epistemicNodes").withIndex(
12592
- "by_project_type",
12593
- (q) => q.eq("projectId", questionNode.projectId).eq("nodeType", "answer")
12594
- ).filter((q) => q.eq(q.field("status"), "active")).collect();
12024
+ if (!questionNode.topicId) {
12025
+ return null;
12595
12026
  }
12027
+ const answers = await ctx.db.query("epistemicNodes").withIndex(
12028
+ "by_topic_type",
12029
+ (q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
12030
+ ).filter((q) => q.eq(q.field("status"), "active")).collect();
12596
12031
  const questionIdStr = String(args.questionNodeId);
12597
12032
  const latest = answers.find((a) => {
12598
12033
  const meta = a.metadata || {};
@@ -12611,28 +12046,18 @@ var getVersionHistory = query({
12611
12046
  if (!questionNode || questionNode.nodeType !== "question") {
12612
12047
  return [];
12613
12048
  }
12614
- let answers;
12615
- if (questionNode.topicId) {
12616
- answers = await ctx.db.query("epistemicNodes").withIndex(
12617
- "by_topic_type",
12618
- (q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
12619
- ).filter(
12620
- (q) => q.or(
12621
- q.eq(q.field("status"), "active"),
12622
- q.eq(q.field("status"), "superseded")
12623
- )
12624
- ).collect();
12625
- } else {
12626
- answers = await ctx.db.query("epistemicNodes").withIndex(
12627
- "by_project_type",
12628
- (q) => q.eq("projectId", questionNode.projectId).eq("nodeType", "answer")
12629
- ).filter(
12630
- (q) => q.or(
12631
- q.eq(q.field("status"), "active"),
12632
- q.eq(q.field("status"), "superseded")
12633
- )
12634
- ).collect();
12049
+ if (!questionNode.topicId) {
12050
+ return [];
12635
12051
  }
12052
+ const answers = await ctx.db.query("epistemicNodes").withIndex(
12053
+ "by_topic_type",
12054
+ (q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
12055
+ ).filter(
12056
+ (q) => q.or(
12057
+ q.eq(q.field("status"), "active"),
12058
+ q.eq(q.field("status"), "superseded")
12059
+ )
12060
+ ).collect();
12636
12061
  const questionIdStr = String(args.questionNodeId);
12637
12062
  const history = answers.filter((a) => {
12638
12063
  const meta = a.metadata || {};
@@ -13903,10 +13328,10 @@ __export(epistemicEvidence_exports, {
13903
13328
  updateVerificationStatus: () => updateVerificationStatus
13904
13329
  });
13905
13330
  function generateContentHash4(text) {
13906
- const content2 = `evidence:${text.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 500)}`;
13331
+ const content = `evidence:${text.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 500)}`;
13907
13332
  let hash = 5381;
13908
- for (let i = 0; i < content2.length; i++) {
13909
- hash = (hash << 5) + hash + content2.charCodeAt(i);
13333
+ for (let i = 0; i < content.length; i++) {
13334
+ hash = (hash << 5) + hash + content.charCodeAt(i);
13910
13335
  hash &= hash;
13911
13336
  }
13912
13337
  return Math.abs(hash).toString(16).padStart(8, "0");
@@ -13925,9 +13350,9 @@ function normalizeKind(kind) {
13925
13350
  ];
13926
13351
  return validKinds.find((k) => kind.toLowerCase() === k) || "observation";
13927
13352
  }
13928
- function normalizeSourceType(sourceType3) {
13929
- if (sourceType3 === "proprietary" || sourceType3 === "verified") {
13930
- return sourceType3;
13353
+ function normalizeSourceType(sourceType) {
13354
+ if (sourceType === "proprietary" || sourceType === "verified") {
13355
+ return sourceType;
13931
13356
  }
13932
13357
  return "ai_generated";
13933
13358
  }
@@ -14015,23 +13440,14 @@ async function resolveEvidenceScopeOrNull(ctx, args) {
14015
13440
  }
14016
13441
  async function getEvidenceNodesForScope(ctx, scope, args) {
14017
13442
  const scanLimit = typeof args?.scanLimit === "number" ? args.scanLimit : void 0;
14018
- const [topicNodes, projectNodes] = await Promise.all([
14019
- scope.topicId ? scanLimit ? ctx.db.query("epistemicNodes").withIndex(
14020
- "by_topic_type",
14021
- (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
14022
- ).order("desc").take(scanLimit) : ctx.db.query("epistemicNodes").withIndex(
14023
- "by_topic_type",
14024
- (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
14025
- ).collect() : Promise.resolve([]),
14026
- scope.projectId ? scanLimit ? ctx.db.query("epistemicNodes").withIndex(
14027
- "by_project_type",
14028
- (q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
14029
- ).order("desc").take(scanLimit) : ctx.db.query("epistemicNodes").withIndex(
14030
- "by_project_type",
14031
- (q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
14032
- ).collect() : Promise.resolve([])
14033
- ]);
14034
- return dedupeEvidenceNodes([...topicNodes, ...projectNodes]).filter(
13443
+ const topicNodes = await (scanLimit ? ctx.db.query("epistemicNodes").withIndex(
13444
+ "by_topic_type",
13445
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
13446
+ ).order("desc").take(scanLimit) : ctx.db.query("epistemicNodes").withIndex(
13447
+ "by_topic_type",
13448
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
13449
+ ).collect());
13450
+ return dedupeEvidenceNodes(topicNodes).filter(
14035
13451
  (node) => evidenceMatchesScope(node, scope)
14036
13452
  );
14037
13453
  }
@@ -14112,7 +13528,7 @@ var create6 = mutation({
14112
13528
  const globalId = generateGlobalId();
14113
13529
  const contentHash = generateContentHash4(args.text);
14114
13530
  const kind = normalizeKind(args.kind);
14115
- const sourceType3 = normalizeSourceType(args.sourceType);
13531
+ const sourceType = normalizeSourceType(args.sourceType);
14116
13532
  const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
14117
13533
  const nodeId = await ctx.db.insert("epistemicNodes", {
14118
13534
  globalId,
@@ -14129,7 +13545,7 @@ var create6 = mutation({
14129
13545
  status: "active",
14130
13546
  epistemicLayer: "L2",
14131
13547
  // L2: Compression Boundary (Evidence/Claims)
14132
- sourceType: sourceType3,
13548
+ sourceType,
14133
13549
  createdAt: now,
14134
13550
  updatedAt: now,
14135
13551
  createdBy: args.userId,
@@ -14195,7 +13611,7 @@ var create6 = mutation({
14195
13611
  newState: {
14196
13612
  text: args.text.slice(0, 200),
14197
13613
  kind,
14198
- sourceType: sourceType3,
13614
+ sourceType,
14199
13615
  linkedBeliefNodeId: args.linkedBeliefNodeId,
14200
13616
  evidenceRelation: args.evidenceRelation
14201
13617
  }
@@ -14254,8 +13670,8 @@ var createAndLink = mutation({
14254
13670
  const globalId = generateGlobalId();
14255
13671
  const contentHash = generateContentHash4(args.text);
14256
13672
  const kind = normalizeKind(args.kind);
14257
- const sourceType3 = normalizeSourceType(args.sourceType);
14258
- const confidence2 = args.confidence ?? 0.7;
13673
+ const sourceType = normalizeSourceType(args.sourceType);
13674
+ const confidence = args.confidence ?? 0.7;
14259
13675
  const nodeId = await ctx.db.insert("epistemicNodes", {
14260
13676
  globalId,
14261
13677
  topicId: scope.topicId,
@@ -14267,7 +13683,7 @@ var createAndLink = mutation({
14267
13683
  contentHash,
14268
13684
  status: "active",
14269
13685
  epistemicLayer: "L2",
14270
- sourceType: sourceType3,
13686
+ sourceType,
14271
13687
  createdAt: now,
14272
13688
  updatedAt: now,
14273
13689
  createdBy: args.userId,
@@ -14276,7 +13692,7 @@ var createAndLink = mutation({
14276
13692
  tags: args.tags || [],
14277
13693
  linkedBeliefNodeId: args.beliefNodeId,
14278
13694
  evidenceRelation: args.relation,
14279
- confidence: confidence2
13695
+ confidence
14280
13696
  }
14281
13697
  });
14282
13698
  await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
@@ -14287,7 +13703,7 @@ var createAndLink = mutation({
14287
13703
  if (!beliefNode) {
14288
13704
  throw new Error("Belief node not found for edge creation");
14289
13705
  }
14290
- const weight = args.relation === "supports" ? confidence2 : -confidence2;
13706
+ const weight = args.relation === "supports" ? confidence : -confidence;
14291
13707
  const edgeGlobalId = crypto.randomUUID();
14292
13708
  await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
14293
13709
  globalId: edgeGlobalId,
@@ -14303,7 +13719,7 @@ var createAndLink = mutation({
14303
13719
  toLayer: "L3",
14304
13720
  metadata: {
14305
13721
  relation: args.relation,
14306
- confidence: confidence2
13722
+ confidence
14307
13723
  }
14308
13724
  });
14309
13725
  await markProjectGraphDirty2(ctx, scope.projectId, String(scope.topicId));
@@ -14404,20 +13820,13 @@ var getByProject5 = query({
14404
13820
  return [];
14405
13821
  }
14406
13822
  }
14407
- const [topicNodes, projectNodes] = await Promise.all([
14408
- scope.topicId ? ctx.db.query("epistemicNodes").withIndex(
14409
- "by_topic_type",
14410
- (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
14411
- ).order("desc").take(scanLimit) : Promise.resolve([]),
14412
- scope.projectId ? ctx.db.query("epistemicNodes").withIndex(
14413
- "by_project_type",
14414
- (q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
14415
- ).order("desc").take(scanLimit) : Promise.resolve([])
14416
- ]);
14417
- const scopedNodes = dedupeEvidenceNodes([
14418
- ...topicNodes,
14419
- ...projectNodes
14420
- ]).filter((node) => evidenceMatchesScope(node, scope));
13823
+ const topicNodes = await ctx.db.query("epistemicNodes").withIndex(
13824
+ "by_topic_type",
13825
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
13826
+ ).order("desc").take(scanLimit);
13827
+ const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
13828
+ (node) => evidenceMatchesScope(node, scope)
13829
+ );
14421
13830
  const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
14422
13831
  return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
14423
13832
  }
@@ -14434,20 +13843,13 @@ var getByTopic3 = query({
14434
13843
  const pageSize = clampEvidenceLimit(args.limit);
14435
13844
  const scanLimit = Math.min(pageSize * 3, MAX_EVIDENCE_PAGE_SIZE);
14436
13845
  const scope = await resolveTopicProjectScope(ctx, { topicId: args.topicId });
14437
- const [topicNodes, projectNodes] = await Promise.all([
14438
- ctx.db.query("epistemicNodes").withIndex(
14439
- "by_topic_type",
14440
- (q) => q.eq("topicId", args.topicId).eq("nodeType", "evidence")
14441
- ).order("desc").take(scanLimit),
14442
- scope.projectId ? ctx.db.query("epistemicNodes").withIndex(
14443
- "by_project_type",
14444
- (q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
14445
- ).order("desc").take(scanLimit) : Promise.resolve([])
14446
- ]);
14447
- const scopedNodes = dedupeEvidenceNodes([
14448
- ...topicNodes,
14449
- ...projectNodes
14450
- ]).filter((node) => evidenceMatchesScope(node, scope));
13846
+ const topicNodes = await ctx.db.query("epistemicNodes").withIndex(
13847
+ "by_topic_type",
13848
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
13849
+ ).order("desc").take(scanLimit);
13850
+ const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
13851
+ (node) => evidenceMatchesScope(node, scope)
13852
+ );
14451
13853
  const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
14452
13854
  return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
14453
13855
  }
@@ -14649,7 +14051,7 @@ var internalCreate2 = internalMutation({
14649
14051
  const globalId = generateGlobalId();
14650
14052
  const contentHash = generateContentHash4(args.text);
14651
14053
  const kind = normalizeKind(args.kind);
14652
- const sourceType3 = normalizeSourceType(args.sourceType);
14054
+ const sourceType = normalizeSourceType(args.sourceType);
14653
14055
  const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
14654
14056
  const nodeId = await ctx.db.insert("epistemicNodes", {
14655
14057
  globalId,
@@ -14665,7 +14067,7 @@ var internalCreate2 = internalMutation({
14665
14067
  ...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
14666
14068
  status: "active",
14667
14069
  epistemicLayer: "L2",
14668
- sourceType: sourceType3,
14070
+ sourceType,
14669
14071
  createdAt: now,
14670
14072
  updatedAt: now,
14671
14073
  createdBy: args.userId,
@@ -14692,7 +14094,7 @@ var internalCreate2 = internalMutation({
14692
14094
  newState: {
14693
14095
  text: args.text.slice(0, 200),
14694
14096
  kind,
14695
- sourceType: sourceType3,
14097
+ sourceType,
14696
14098
  externalSourceType: args.externalSourceType,
14697
14099
  sourceUrl: args.sourceUrl,
14698
14100
  linkedBeliefNodeId: args.linkedBeliefNodeId,
@@ -14708,8 +14110,8 @@ var internalCreate2 = internalMutation({
14708
14110
  if (args.linkedBeliefNodeId && args.evidenceRelation) {
14709
14111
  const beliefNode = await ctx.db.get(args.linkedBeliefNodeId);
14710
14112
  if (beliefNode) {
14711
- const confidence2 = args.confidence ?? 0.7;
14712
- const weight = args.evidenceRelation === "supports" ? confidence2 : -confidence2;
14113
+ const confidence = args.confidence ?? 0.7;
14114
+ const weight = args.evidenceRelation === "supports" ? confidence : -confidence;
14713
14115
  await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
14714
14116
  globalId: crypto.randomUUID(),
14715
14117
  fromGlobalId: globalId,
@@ -14724,7 +14126,7 @@ var internalCreate2 = internalMutation({
14724
14126
  toLayer: "L3",
14725
14127
  metadata: {
14726
14128
  relation: args.evidenceRelation,
14727
- confidence: confidence2
14129
+ confidence
14728
14130
  }
14729
14131
  });
14730
14132
  }
@@ -15071,23 +14473,23 @@ __export(epistemicHelpers_exports, {
15071
14473
  shouldContinueTraversal: () => shouldContinueTraversal2,
15072
14474
  validateEdgeLayers: () => validateEdgeLayers2
15073
14475
  });
15074
- function generateContentHash5(nodeType2, text) {
15075
- const content2 = `${nodeType2}:${normalizeText(text)}`;
14476
+ function generateContentHash5(nodeType, text) {
14477
+ const content = `${nodeType}:${normalizeText(text)}`;
15076
14478
  let hash = 5381;
15077
- for (let i = 0; i < content2.length; i++) {
15078
- hash = (hash << 5) + hash + content2.charCodeAt(i);
14479
+ for (let i = 0; i < content.length; i++) {
14480
+ hash = (hash << 5) + hash + content.charCodeAt(i);
15079
14481
  hash &= hash;
15080
14482
  }
15081
14483
  const hashHex = Math.abs(hash).toString(16).padStart(8, "0");
15082
- const lengthHex = content2.length.toString(16).padStart(4, "0");
15083
- const checksum = content2.split("").reduce((a, c) => a + c.charCodeAt(0), 0).toString(16).padStart(8, "0");
14484
+ const lengthHex = content.length.toString(16).padStart(4, "0");
14485
+ const checksum = content.split("").reduce((a, c) => a + c.charCodeAt(0), 0).toString(16).padStart(8, "0");
15084
14486
  return `${hashHex}${lengthHex}${checksum}`;
15085
14487
  }
15086
14488
  function normalizeText(text) {
15087
14489
  return text.trim().toLowerCase().replace(/\s+/g, " ");
15088
14490
  }
15089
- function getNodeLayer2(nodeType2) {
15090
- switch (nodeType2) {
14491
+ function getNodeLayer2(nodeType) {
14492
+ switch (nodeType) {
15091
14493
  // L4: Audit targets
15092
14494
  case "decision":
15093
14495
  return "L4";
@@ -15120,7 +14522,7 @@ function getNodeLayer2(nodeType2) {
15120
14522
  return "organizational";
15121
14523
  default:
15122
14524
  console.warn(
15123
- `[EpistemicLayer] Unknown nodeType: ${nodeType2}, defaulting to L2`
14525
+ `[EpistemicLayer] Unknown nodeType: ${nodeType}, defaulting to L2`
15124
14526
  );
15125
14527
  return "L2";
15126
14528
  }
@@ -15562,8 +14964,8 @@ function validateEdgeLayers2(edgeType, fromLayer, toLayer) {
15562
14964
  }
15563
14965
  return { valid: true };
15564
14966
  }
15565
- function mapInsightSourceType(sourceType3) {
15566
- switch (sourceType3) {
14967
+ function mapInsightSourceType(sourceType) {
14968
+ switch (sourceType) {
15567
14969
  case "verified":
15568
14970
  case "proprietary":
15569
14971
  return "human";
@@ -15718,7 +15120,7 @@ async function createEpistemicNodeForQuestion(ctx, _questionId, question) {
15718
15120
  });
15719
15121
  return existing._id;
15720
15122
  }
15721
- const sourceType3 = question.source === "manual" ? "human" : question.source === "ai_suggested" ? "ai_generated" : "ai_extracted";
15123
+ const sourceType = question.source === "manual" ? "human" : question.source === "ai_suggested" ? "ai_generated" : "ai_extracted";
15722
15124
  const nodeId = await ctx.db.insert("epistemicNodes", {
15723
15125
  globalId,
15724
15126
  nodeType: "question",
@@ -15734,7 +15136,7 @@ async function createEpistemicNodeForQuestion(ctx, _questionId, question) {
15734
15136
  // Include sourceAnchor for linking questions back to source documents
15735
15137
  sourceAnchor: question.sourceAnchor
15736
15138
  },
15737
- sourceType: sourceType3,
15139
+ sourceType,
15738
15140
  verificationStatus: "unverified",
15739
15141
  status: "active",
15740
15142
  topicId: question.projectId,
@@ -15747,15 +15149,15 @@ async function createEpistemicNodeForQuestion(ctx, _questionId, question) {
15747
15149
  async function createEpistemicNodeForArtifact(ctx, artifactId, artifact) {
15748
15150
  const now = Date.now();
15749
15151
  const globalId = generateGlobalId();
15750
- let nodeType2 = "source";
15152
+ let nodeType = "source";
15751
15153
  const isSynthesis = artifact.isDeepResearch || artifact.type.includes("deep") || artifact.type.includes("research") || artifact.type.includes("primer");
15752
15154
  if (isSynthesis) {
15753
- nodeType2 = "synthesis";
15155
+ nodeType = "synthesis";
15754
15156
  console.log(
15755
15157
  `[EpistemicHelpers] Skipping synthesis node creation for "${artifact.type}" - will create when evidence is extracted`
15756
15158
  );
15757
15159
  const contentHash2 = generateContentHash5(
15758
- nodeType2,
15160
+ nodeType,
15759
15161
  artifact.title + artifact.content.slice(0, 500)
15760
15162
  );
15761
15163
  const existing2 = await ctx.db.query("epistemicNodes").withIndex("by_contentHash", (q) => q.eq("contentHash", contentHash2)).first();
@@ -15765,7 +15167,7 @@ async function createEpistemicNodeForArtifact(ctx, artifactId, artifact) {
15765
15167
  throw new Error("SKIP_SYNTHESIS_NODE_CREATION");
15766
15168
  }
15767
15169
  const contentHash = generateContentHash5(
15768
- nodeType2,
15170
+ nodeType,
15769
15171
  artifact.title + artifact.content.slice(0, 500)
15770
15172
  );
15771
15173
  const existing = await ctx.db.query("epistemicNodes").withIndex("by_contentHash", (q) => q.eq("contentHash", contentHash)).first();
@@ -15779,11 +15181,11 @@ async function createEpistemicNodeForArtifact(ctx, artifactId, artifact) {
15779
15181
  });
15780
15182
  return existing._id;
15781
15183
  }
15782
- const epistemicLayer2 = "L1";
15184
+ const epistemicLayer = "L1";
15783
15185
  const nodeId = await ctx.db.insert("epistemicNodes", {
15784
15186
  globalId,
15785
- nodeType: nodeType2,
15786
- epistemicLayer: epistemicLayer2,
15187
+ nodeType,
15188
+ epistemicLayer,
15787
15189
  // Synthesis is L2, Source is L1
15788
15190
  canonicalText: artifact.title,
15789
15191
  contentHash,
@@ -15812,12 +15214,13 @@ async function findOrCreateSourceNode(ctx, artifactId, createdBy, scopeProjectId
15812
15214
  let existingNodes;
15813
15215
  if (effectiveTopicId) {
15814
15216
  existingNodes = await ctx.db.query("epistemicNodes").withIndex("by_topic", (q) => q.eq("topicId", effectiveTopicId)).collect();
15815
- } else if (effectiveProjectId) {
15816
- existingNodes = await ctx.db.query("epistemicNodes").withIndex("by_project", (q) => q.eq("projectId", effectiveProjectId)).collect();
15817
15217
  } else {
15818
15218
  existingNodes = await ctx.db.query("epistemicNodes").withIndex("by_nodeType", (q) => q.eq("nodeType", "source")).collect();
15819
15219
  }
15820
15220
  const existing = existingNodes.find((n) => {
15221
+ if (effectiveProjectId && n.projectId && n.projectId !== effectiveProjectId) {
15222
+ return false;
15223
+ }
15821
15224
  const metadata = n.metadata;
15822
15225
  return metadata?.legacyArtifactId === artifactId;
15823
15226
  });
@@ -15831,22 +15234,22 @@ async function findOrCreateSourceNode(ctx, artifactId, createdBy, scopeProjectId
15831
15234
  const globalId = generateGlobalId();
15832
15235
  const artifactType = artifact.metadata?.type || "";
15833
15236
  const isDeepResearch = artifact.metadata?.isDeepResearch;
15834
- let nodeType2 = "source";
15237
+ let nodeType = "source";
15835
15238
  if (isDeepResearch || artifactType.includes("deep") || artifactType.includes("research")) {
15836
- nodeType2 = "synthesis";
15239
+ nodeType = "synthesis";
15837
15240
  } else if (artifactType.includes("primer")) {
15838
- nodeType2 = "synthesis";
15241
+ nodeType = "synthesis";
15839
15242
  }
15840
15243
  const title = artifact.metadata?.title || artifact.metadata?.theme || "Untitled";
15841
15244
  const contentHash = generateContentHash5(
15842
- nodeType2,
15245
+ nodeType,
15843
15246
  title + (artifact.content?.slice(0, 500) || "")
15844
15247
  );
15845
- const epistemicLayer2 = nodeType2 === "synthesis" ? "L2" : "L1";
15248
+ const epistemicLayer = nodeType === "synthesis" ? "L2" : "L1";
15846
15249
  const nodeId = await ctx.db.insert("epistemicNodes", {
15847
15250
  globalId,
15848
- nodeType: nodeType2,
15849
- epistemicLayer: epistemicLayer2,
15251
+ nodeType,
15252
+ epistemicLayer,
15850
15253
  // Synthesis is L2, Source is L1
15851
15254
  canonicalText: title,
15852
15255
  contentHash,
@@ -15869,12 +15272,12 @@ async function findOrCreateSourceNode(ctx, artifactId, createdBy, scopeProjectId
15869
15272
  });
15870
15273
  return nodeId;
15871
15274
  }
15872
- function normalizeConfidence(confidence2) {
15873
- if (typeof confidence2 === "number") {
15874
- return confidence2 > 1 ? confidence2 / 100 : confidence2;
15275
+ function normalizeConfidence(confidence) {
15276
+ if (typeof confidence === "number") {
15277
+ return confidence > 1 ? confidence / 100 : confidence;
15875
15278
  }
15876
- if (typeof confidence2 === "string") {
15877
- switch (confidence2) {
15279
+ if (typeof confidence === "string") {
15280
+ switch (confidence) {
15878
15281
  case "high":
15879
15282
  return 0.8;
15880
15283
  case "medium":
@@ -15948,8 +15351,8 @@ async function createEdgeForInsightQuestionLink(ctx, questionId, insightId, crea
15948
15351
  });
15949
15352
  }
15950
15353
  async function findNodeByLegacyId(ctx, legacyType, legacyId) {
15951
- const nodeType2 = legacyType === "insight" ? "evidence" : legacyType === "artifact" ? "source" : legacyType;
15952
- const nodes = await ctx.db.query("epistemicNodes").withIndex("by_nodeType", (q) => q.eq("nodeType", nodeType2)).collect();
15354
+ const nodeType = legacyType === "insight" ? "evidence" : legacyType === "artifact" ? "source" : legacyType;
15355
+ const nodes = await ctx.db.query("epistemicNodes").withIndex("by_nodeType", (q) => q.eq("nodeType", nodeType)).collect();
15953
15356
  const legacyKey = `legacy${legacyType.charAt(0).toUpperCase() + legacyType.slice(1)}Id`;
15954
15357
  const legacyIdStr = String(legacyId);
15955
15358
  const found = nodes.find((n) => {
@@ -15959,7 +15362,7 @@ async function findNodeByLegacyId(ctx, legacyType, legacyId) {
15959
15362
  });
15960
15363
  if (!found) {
15961
15364
  console.log(
15962
- `[EpistemicSpine] Node not found for ${legacyType}:${legacyIdStr}, searched ${nodes.length} ${nodeType2} nodes`
15365
+ `[EpistemicSpine] Node not found for ${legacyType}:${legacyIdStr}, searched ${nodes.length} ${nodeType} nodes`
15963
15366
  );
15964
15367
  }
15965
15368
  return found?._id ?? null;
@@ -16665,8 +16068,8 @@ var getByProjectAndTypeLite = query({
16665
16068
  const pageSize = clampNodeLimit(args.limit);
16666
16069
  const scanLimit = Math.min(pageSize * 3, MAX_NODE_PAGE_SIZE);
16667
16070
  const query2 = ctx.db.query("epistemicNodes").withIndex(
16668
- scope.topicId ? "by_topic_type" : "by_project_type",
16669
- (q) => scope.topicId ? q.eq("topicId", scope.topicId).eq("nodeType", args.nodeType) : q.eq("projectId", scope.projectId).eq("nodeType", args.nodeType)
16071
+ "by_topic_type",
16072
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", args.nodeType)
16670
16073
  );
16671
16074
  const nodes = await query2.order("desc").take(scanLimit);
16672
16075
  const statusFiltered = args.status ? nodes.filter((n) => n.status === args.status) : nodes.filter((n) => n.status === "active");
@@ -16872,7 +16275,7 @@ var create7 = mutation({
16872
16275
  if (existing && existing.status === "active") {
16873
16276
  return { nodeId: existing._id, isDuplicate: true };
16874
16277
  }
16875
- const epistemicLayer2 = getNodeLayer(args.nodeType);
16278
+ const epistemicLayer = getNodeLayer(args.nodeType);
16876
16279
  const resolvedScope = args.topicId || args.projectId ? await resolveTopicProjectScope(ctx, {
16877
16280
  topicId: args.topicId,
16878
16281
  projectId: args.projectId
@@ -16889,11 +16292,11 @@ var create7 = mutation({
16889
16292
  tenantId: resolvedScope.tenantId,
16890
16293
  workspaceId: resolvedScope.workspaceId,
16891
16294
  nodeType: args.nodeType,
16892
- epistemicLayer: epistemicLayer2
16295
+ epistemicLayer
16893
16296
  },
16894
16297
  mutationName: "epistemicNodes.create"
16895
16298
  });
16896
- } else if (epistemicLayer2 !== "ontological") {
16299
+ } else if (epistemicLayer !== "ontological") {
16897
16300
  throw new Error(
16898
16301
  "Workspace-scoped reasoning isolation requires topicId or projectId for non-ontological node creation."
16899
16302
  );
@@ -16901,7 +16304,7 @@ var create7 = mutation({
16901
16304
  const nodeId = await ctx.db.insert("epistemicNodes", {
16902
16305
  globalId: args.globalId,
16903
16306
  nodeType: args.nodeType,
16904
- epistemicLayer: epistemicLayer2,
16307
+ epistemicLayer,
16905
16308
  // Phase 2B: Auto-derived from nodeType
16906
16309
  subtype: args.subtype,
16907
16310
  canonicalText: args.canonicalText,
@@ -17062,11 +16465,11 @@ var supersede = mutation({
17062
16465
  mutationName: "epistemicNodes.supersede"
17063
16466
  });
17064
16467
  const now = Date.now();
17065
- const epistemicLayer2 = oldNode.epistemicLayer || getNodeLayer(oldNode.nodeType);
16468
+ const epistemicLayer = oldNode.epistemicLayer || getNodeLayer(oldNode.nodeType);
17066
16469
  const newNodeId = await ctx.db.insert("epistemicNodes", {
17067
16470
  globalId: args.newGlobalId,
17068
16471
  nodeType: oldNode.nodeType,
17069
- epistemicLayer: epistemicLayer2,
16472
+ epistemicLayer,
17070
16473
  // Phase 2B: Inherit layer (supersession is same-layer only)
17071
16474
  canonicalText: args.newCanonicalText,
17072
16475
  contentHash: args.newContentHash,
@@ -17299,14 +16702,14 @@ var batchCreate2 = mutation({
17299
16702
  nodeType: node.nodeType,
17300
16703
  mutationName: "epistemicNodes.batchCreate"
17301
16704
  });
17302
- const epistemicLayer2 = getNodeLayer(node.nodeType);
16705
+ const epistemicLayer = getNodeLayer(node.nodeType);
17303
16706
  const resolvedScope = node.topicId || node.projectId ? await resolveTopicProjectScope(ctx, {
17304
16707
  topicId: node.topicId,
17305
16708
  projectId: node.projectId
17306
16709
  }).catch(() => void 0) : void 0;
17307
16710
  const nodeId = await ctx.db.insert("epistemicNodes", {
17308
16711
  ...node,
17309
- epistemicLayer: epistemicLayer2,
16712
+ epistemicLayer,
17310
16713
  // Phase 2B: Auto-derived from nodeType
17311
16714
  verificationStatus: node.verificationStatus ?? "unverified",
17312
16715
  status: "active",
@@ -17390,11 +16793,11 @@ var createInternal2 = internalMutation({
17390
16793
  projectId: args.projectId
17391
16794
  }).catch(() => void 0) : void 0;
17392
16795
  const contentHash = args.contentHash || `${args.nodeType}:${args.canonicalText}`.slice(0, 64);
17393
- const epistemicLayer2 = args.epistemicLayer || getNodeLayer(args.nodeType);
16796
+ const epistemicLayer = args.epistemicLayer || getNodeLayer(args.nodeType);
17394
16797
  const nodeId = await ctx.db.insert("epistemicNodes", {
17395
16798
  globalId: args.globalId,
17396
16799
  nodeType: args.nodeType,
17397
- epistemicLayer: epistemicLayer2,
16800
+ epistemicLayer,
17398
16801
  subtype: args.subtype,
17399
16802
  canonicalText: args.canonicalText,
17400
16803
  contentHash,
@@ -17666,10 +17069,10 @@ async function resolveWorkflowBridgeDoc(ctx, workflowId) {
17666
17069
 
17667
17070
  // src/epistemicQuestions.ts
17668
17071
  function generateContentHash6(text) {
17669
- const content2 = `question:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
17072
+ const content = `question:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
17670
17073
  let hash = 5381;
17671
- for (let i = 0; i < content2.length; i++) {
17672
- hash = (hash << 5) + hash + content2.charCodeAt(i);
17074
+ for (let i = 0; i < content.length; i++) {
17075
+ hash = (hash << 5) + hash + content.charCodeAt(i);
17673
17076
  hash &= hash;
17674
17077
  }
17675
17078
  return Math.abs(hash).toString(16).padStart(8, "0");
@@ -17773,21 +17176,13 @@ async function resolveQuestionScopeOrNull(ctx, args) {
17773
17176
  }
17774
17177
  async function getQuestionNodesForScope(ctx, scope, args) {
17775
17178
  const fetchNodes = (query2) => typeof args?.scanLimit === "number" ? query2.order("desc").take(args.scanLimit) : query2.collect();
17776
- const [topicNodes, projectNodes] = await Promise.all([
17777
- scope.topicId ? fetchNodes(
17778
- ctx.db.query("epistemicNodes").withIndex(
17779
- "by_topic_type",
17780
- (q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
17781
- )
17782
- ) : Promise.resolve([]),
17783
- scope.projectId ? fetchNodes(
17784
- ctx.db.query("epistemicNodes").withIndex(
17785
- "by_project_type",
17786
- (q) => q.eq("projectId", scope.projectId).eq("nodeType", "question")
17787
- )
17788
- ) : Promise.resolve([])
17789
- ]);
17790
- return dedupeQuestionNodes([...topicNodes, ...projectNodes]).filter(
17179
+ const topicNodes = await fetchNodes(
17180
+ ctx.db.query("epistemicNodes").withIndex(
17181
+ "by_topic_type",
17182
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
17183
+ )
17184
+ );
17185
+ return dedupeQuestionNodes(topicNodes).filter(
17791
17186
  (node) => questionMatchesScope(node, scope)
17792
17187
  );
17793
17188
  }
@@ -19953,8 +19348,8 @@ var getByPillar2 = query({
19953
19348
  return { questions: [], beliefs: [] };
19954
19349
  }
19955
19350
  const allBeliefNodes = await ctx.db.query("epistemicNodes").withIndex(
19956
- scope.topicId ? "by_topic_type" : "by_project_type",
19957
- (q) => scope.topicId ? q.eq("topicId", scope.topicId).eq("nodeType", "belief") : q.eq("projectId", scope.projectId).eq("nodeType", "belief")
19351
+ "by_topic_type",
19352
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
19958
19353
  ).collect();
19959
19354
  const beliefs = allBeliefNodes.filter((n) => {
19960
19355
  const meta = n.metadata || {};
@@ -20320,8 +19715,8 @@ var getQuestionClusterPositions = query({
20320
19715
  };
20321
19716
  }
20322
19717
  const questionNodes = await ctx.db.query("epistemicNodes").withIndex(
20323
- scope.topicId ? "by_topic_type" : "by_project_type",
20324
- (q) => scope?.topicId ? q.eq("topicId", scope.topicId).eq("nodeType", "question") : q.eq("projectId", scope?.projectId).eq("nodeType", "question")
19718
+ "by_topic_type",
19719
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
20325
19720
  ).collect();
20326
19721
  const activeQuestionNodes = questionNodes.filter(isActiveQuestionNode);
20327
19722
  const positions = {};
@@ -20331,8 +19726,8 @@ var getQuestionClusterPositions = query({
20331
19726
  for (const question of activeQuestionNodes) {
20332
19727
  const id = question._id.toString();
20333
19728
  const meta = question.metadata || {};
20334
- const questionType2 = typeof question.questionType === "string" ? question.questionType : typeof meta.questionType === "string" ? meta.questionType : void 0;
20335
- if (questionType2 === "belief_test" || meta.testType) {
19729
+ const questionType = typeof question.questionType === "string" ? question.questionType : typeof meta.questionType === "string" ? meta.questionType : void 0;
19730
+ if (questionType === "belief_test" || meta.testType) {
20336
19731
  positions[id] = "cluster";
20337
19732
  clusterCount++;
20338
19733
  } else if (resolveLinkedWorktreeId(meta)) {
@@ -20392,10 +19787,10 @@ function normalizeMetadata(metadata) {
20392
19787
  return rest;
20393
19788
  }
20394
19789
  function generateSourceContentHash(identity) {
20395
- const content2 = `source:${identity.trim().toLowerCase()}`;
19790
+ const content = `source:${identity.trim().toLowerCase()}`;
20396
19791
  let hash = 5381;
20397
- for (let index = 0; index < content2.length; index += 1) {
20398
- hash = (hash << 5) + hash + content2.charCodeAt(index);
19792
+ for (let index = 0; index < content.length; index += 1) {
19793
+ hash = (hash << 5) + hash + content.charCodeAt(index);
20399
19794
  hash &= hash;
20400
19795
  }
20401
19796
  return Math.abs(hash).toString(16).padStart(8, "0");
@@ -22205,11 +21600,15 @@ var getByProject8 = query({
22205
21600
  if (!hasAccess) {
22206
21601
  return [];
22207
21602
  }
21603
+ const scope = await resolveTopicProjectScope(ctx, args).catch(() => null);
21604
+ if (!scope) {
21605
+ return [];
21606
+ }
22208
21607
  const pageSize = Math.max(1, Math.min(Math.floor(args.limit ?? 300), 1e3));
22209
21608
  const questionScanLimit = Math.min(pageSize * 2, 1e3);
22210
21609
  const questions = await ctx.db.query("epistemicNodes").withIndex(
22211
- args.topicId ? "by_topic_type" : "by_project_type",
22212
- (q) => args.topicId ? q.eq("topicId", args.topicId).eq("nodeType", "question") : q.eq("projectId", args.projectId).eq("nodeType", "question")
21610
+ "by_topic_type",
21611
+ (q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
22213
21612
  ).order("desc").take(questionScanLimit);
22214
21613
  const questionIds = questions.slice(0, pageSize).map((q) => q._id);
22215
21614
  const allLinks = await Promise.all(