@lucern/graph-primitives 1.0.50 → 1.0.53

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 (67) hide show
  1. package/dist/beliefDecay.js +34 -186
  2. package/dist/beliefEvidenceLinks.js +32 -187
  3. package/dist/contradictions.js +34 -187
  4. package/dist/entityLifecycle.js +88 -205
  5. package/dist/epistemicAnswers.js +35 -187
  6. package/dist/epistemicBeliefs.admin.js +34 -187
  7. package/dist/epistemicBeliefs.backfills.js +34 -188
  8. package/dist/epistemicBeliefs.confidence.d.ts +1 -1
  9. package/dist/epistemicBeliefs.confidence.js +32 -188
  10. package/dist/epistemicBeliefs.core.js +37 -187
  11. package/dist/epistemicBeliefs.d.ts +1 -1
  12. package/dist/epistemicBeliefs.helpers.d.ts +1 -1
  13. package/dist/epistemicBeliefs.helpers.js +34 -186
  14. package/dist/epistemicBeliefs.internal.js +37 -187
  15. package/dist/epistemicBeliefs.js +37 -187
  16. package/dist/epistemicBeliefs.lifecycle.js +32 -188
  17. package/dist/epistemicBeliefs.links.js +34 -188
  18. package/dist/epistemicContracts.evaluators.js +34 -188
  19. package/dist/epistemicContracts.handlers.js +34 -188
  20. package/dist/epistemicContracts.js +34 -188
  21. package/dist/epistemicEdges.d.ts +1 -1
  22. package/dist/epistemicEdges.helpers.d.ts +1 -1
  23. package/dist/epistemicEdges.js +32 -187
  24. package/dist/epistemicEdges.mutations.js +34 -186
  25. package/dist/epistemicEdges.queries.js +35 -188
  26. package/dist/epistemicEdges.types.d.ts +1 -1
  27. package/dist/epistemicEvidence.d.ts +1 -1
  28. package/dist/epistemicEvidence.js +37 -187
  29. package/dist/epistemicEvidenceHelpers.d.ts +1 -1
  30. package/dist/epistemicEvidenceHelpers.js +34 -186
  31. package/dist/epistemicEvidenceMutations.js +37 -187
  32. package/dist/epistemicEvidenceQueries.js +34 -186
  33. package/dist/epistemicHelpers.js +4 -1
  34. package/dist/epistemicInsert.js +4 -1
  35. package/dist/epistemicNodeCreation.js +4 -1
  36. package/dist/epistemicNodes.helpers.d.ts +1 -1
  37. package/dist/epistemicNodes.internal.js +35 -188
  38. package/dist/epistemicNodes.js +37 -188
  39. package/dist/epistemicNodes.mutations.js +35 -188
  40. package/dist/epistemicNodes.queries.js +35 -188
  41. package/dist/epistemicQuestions.conviction.js +34 -186
  42. package/dist/epistemicQuestions.create.js +37 -187
  43. package/dist/epistemicQuestions.d.ts +1 -1
  44. package/dist/epistemicQuestions.evidence.js +37 -187
  45. package/dist/epistemicQuestions.helpers.d.ts +1 -1
  46. package/dist/epistemicQuestions.helpers.js +34 -186
  47. package/dist/epistemicQuestions.js +37 -187
  48. package/dist/epistemicQuestions.lifecycle.js +34 -186
  49. package/dist/epistemicQuestions.queries.js +34 -186
  50. package/dist/epistemicQuestions.sprint.js +35 -188
  51. package/dist/epistemicQuestions.tail.js +37 -187
  52. package/dist/epistemicSources.js +35 -188
  53. package/dist/index.d.ts +1 -1
  54. package/dist/index.js +98 -213
  55. package/dist/proof-attestation.json +1 -1
  56. package/dist/questionEvidenceLinks.js +34 -187
  57. package/dist/scopeResolverCompat.d.ts +1 -1
  58. package/dist/scopeResolverCompat.js +32 -193
  59. package/dist/topicOntologyResolver.d.ts +3 -3
  60. package/dist/topicOntologyResolver.js +57 -18
  61. package/dist/{topicScope-DJVa0mLa.d.ts → topicScope-CL1IVOmv.d.ts} +2 -2
  62. package/dist/topicScope.d.ts +1 -1
  63. package/dist/topicScope.js +32 -193
  64. package/dist/workflowBridge.js +32 -193
  65. package/dist/workspaceIsolation.d.ts +1 -1
  66. package/dist/workspaceIsolation.js +32 -193
  67. package/package.json +4 -4
@@ -3,6 +3,7 @@ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
3
3
  import { v } from 'convex/values';
4
4
  import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
5
5
  import { componentsGeneric, mutationGeneric, queryGeneric } from 'convex/server';
6
+ import { isUuidV7 } from '@lucern/contracts/ids';
6
7
 
7
8
  // src/epistemicQuestions.conviction.ts
8
9
  var unsafeApi = unsafeConvexAnyApi(
@@ -419,6 +420,8 @@ function resolveGraphPrimitivesAppResolvers(_ctx) {
419
420
  ...resolverOverrides
420
421
  };
421
422
  }
423
+
424
+ // src/topicScope.ts
422
425
  var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
423
426
  async function resolveTopicNodeScopeOrNull(ctx, ref) {
424
427
  if (!ctx?.db || typeof ctx.db.query !== "function") {
@@ -439,16 +442,36 @@ async function resolveTopicNodeScopeOrNull(ctx, ref) {
439
442
  if (!node) {
440
443
  return null;
441
444
  }
442
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
445
+ const scopeKey = canonicalTopicGlobalId(node);
443
446
  if (!scopeKey) {
444
- return null;
447
+ throw new Error(
448
+ `topic.uuidv7_identity_required: topic node ${ref} is missing a UUIDv7 globalId.`
449
+ );
445
450
  }
451
+ const metadata = node.metadata ?? {};
446
452
  return {
447
453
  topicId: scopeKey,
448
454
  projectId: asMappedProjectId(node),
449
- source: "topic_node"
455
+ source: "topic_node",
456
+ tenantId: normalizeScopeValue(node.tenantId) ?? normalizeScopeValue(metadata.tenantId),
457
+ workspaceId: normalizeScopeValue(node.workspaceId) ?? normalizeScopeValue(metadata.workspaceId)
450
458
  };
451
459
  }
460
+ function canonicalTopicGlobalId(node) {
461
+ const globalId = normalizeScopeValue(node.globalId);
462
+ if (globalId && isUuidV7(globalId)) {
463
+ return globalId;
464
+ }
465
+ const topicId = normalizeScopeValue(node.topicId);
466
+ return topicId && isUuidV7(topicId) ? topicId : null;
467
+ }
468
+ function requireUuidV7TopicScope(field, value) {
469
+ if (!isUuidV7(value)) {
470
+ throw new Error(
471
+ `topic.uuidv7_required: ${field} must be a UUIDv7 public topic identifier.`
472
+ );
473
+ }
474
+ }
452
475
  function asMappedProjectId(topic) {
453
476
  if (!topic) {
454
477
  return;
@@ -470,200 +493,25 @@ function normalizeScopeValue(value) {
470
493
  const normalized = value.trim();
471
494
  return normalized.length > 0 ? normalized : void 0;
472
495
  }
473
- function pickPrimaryTopic(candidates) {
474
- return [...candidates].sort((a, b) => {
475
- const depthA = a.depth ?? 9999;
476
- const depthB = b.depth ?? 9999;
477
- if (depthA !== depthB) {
478
- return depthA - depthB;
479
- }
480
- const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
481
- const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
482
- if (createdA !== createdB) {
483
- return createdA - createdB;
484
- }
485
- return String(a.name || "").localeCompare(String(b.name || ""));
486
- })[0];
487
- }
488
- async function findTopicsByScopeAlias(ctx, scopeId) {
489
- const query2 = ctx.db.query("topics");
490
- try {
491
- return await query2.withIndex(
492
- "by_graph_scope_project",
493
- (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
494
- ).collect();
495
- } catch (error) {
496
- debugGraphPrimitiveFallback(
497
- "[topicScope] Failed to resolve scope alias via index",
498
- {
499
- error,
500
- scopeId
501
- }
502
- );
503
- const topics = await query2.collect();
504
- return topics.filter((topic) => {
505
- const normalizedGlobalId = normalizeScopeValue(topic.globalId);
506
- const mappedProjectId = asMappedProjectId(topic);
507
- return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
508
- });
509
- }
510
- }
511
- async function tryResolveHostTopicById(ctx, topicId) {
512
- if (typeof ctx.runQuery !== "function") {
513
- return null;
514
- }
515
- try {
516
- return await ctx.runQuery(api.topics.get, {
517
- id: topicId
518
- }) ?? null;
519
- } catch (error) {
520
- debugGraphPrimitiveFallback(
521
- "[topicScope] Failed to resolve topic by host query",
522
- {
523
- error,
524
- topicId
525
- }
526
- );
527
- return null;
528
- }
529
- }
530
- async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
531
- if (typeof ctx.runQuery !== "function") {
532
- return null;
533
- }
534
- try {
535
- return await ctx.runQuery(api.topics.getByLegacyScopeId, {
536
- projectId: legacyScopeId
537
- }) ?? null;
538
- } catch (error) {
539
- debugGraphPrimitiveFallback(
540
- "[topicScope] Failed to resolve topic by legacy scope",
541
- {
542
- error,
543
- legacyScopeId
544
- }
545
- );
546
- return null;
547
- }
548
- }
549
- async function resolveInheritedWorkspaceScope(ctx, topic) {
550
- const MAX_DEPTH = 10;
551
- let tenantId = normalizeScopeValue(topic.tenantId);
552
- let workspaceId = normalizeScopeValue(topic.workspaceId);
553
- if (tenantId && workspaceId) {
554
- return { tenantId, workspaceId };
555
- }
556
- let current = topic;
557
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
558
- current = await ctx.db.get(current.parentTopicId);
559
- if (!current) {
560
- break;
561
- }
562
- if (!tenantId) {
563
- tenantId = normalizeScopeValue(current.tenantId);
564
- }
565
- if (!workspaceId) {
566
- workspaceId = normalizeScopeValue(current.workspaceId);
567
- }
568
- if (tenantId && workspaceId) {
569
- break;
570
- }
571
- }
572
- return { tenantId, workspaceId };
573
- }
574
496
  async function resolveTopicProjectScope(ctx, args) {
575
497
  if (args.topicId) {
576
498
  return await resolveScopeFromTopicId(ctx, args.topicId);
577
499
  }
578
500
  if (args.projectId) {
579
- return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
501
+ throw new Error(
502
+ "topic.uuidv7_required: projectId scope aliases are retired; pass topicId as the UUIDv7 topic globalId."
503
+ );
580
504
  }
581
- throw new Error(
582
- "Missing scope: provide topicId (preferred) or legacy projectId alias."
583
- );
505
+ throw new Error("topic.uuidv7_required: Missing scope: provide topicId.");
584
506
  }
585
507
  async function resolveScopeFromTopicId(ctx, topicId) {
586
- const topic = await resolveTopicDocFromTopicId(ctx, topicId);
587
- if (topic) {
588
- return await buildTopicScope(ctx, topic, "topic");
589
- }
590
- const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
508
+ const topicGlobalId = String(topicId);
509
+ requireUuidV7TopicScope("topicId", topicGlobalId);
510
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, topicGlobalId);
591
511
  if (nodeScope) {
592
512
  return nodeScope;
593
513
  }
594
- throw new Error(`Topic not found: ${String(topicId)}`);
595
- }
596
- async function resolveTopicDocFromTopicId(ctx, topicId) {
597
- const direct = await tryReadTopicDoc(ctx, topicId, {
598
- failureLog: "[topicScope] Failed to load topic by direct id",
599
- idLogKey: "topicId"
600
- });
601
- if (direct) {
602
- return direct;
603
- }
604
- const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
605
- if (hostTopic) {
606
- return hostTopic;
607
- }
608
- return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
609
- }
610
- async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
611
- const directTopic = await resolveDirectLegacyProjectTopic(
612
- ctx,
613
- legacyProjectId
614
- );
615
- if (directTopic) {
616
- return await buildTopicScope(ctx, directTopic, "topic_inferred", {
617
- fallbackProjectId: legacyProjectId
618
- });
619
- }
620
- const primary = pickPrimaryTopic(
621
- await findTopicsByScopeAlias(ctx, legacyProjectId)
622
- );
623
- if (primary) {
624
- return await buildTopicScope(ctx, primary, "project_mapped_topic", {
625
- fallbackProjectId: legacyProjectId
626
- });
627
- }
628
- const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
629
- if (nodeScope) {
630
- return {
631
- ...nodeScope,
632
- projectId: nodeScope.projectId ?? legacyProjectId
633
- };
634
- }
635
- throw new Error(
636
- `Legacy project scope ${legacyProjectId} has no mapped topic.`
637
- );
638
- }
639
- async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
640
- const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
641
- failureLog: "[topicScope] Failed to load direct project topic",
642
- idLogKey: "projectId"
643
- });
644
- return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
645
- }
646
- async function tryReadTopicDoc(ctx, id, log) {
647
- try {
648
- return await ctx.db.get(id);
649
- } catch (error) {
650
- debugGraphPrimitiveFallback(log.failureLog, {
651
- error,
652
- [log.idLogKey]: id
653
- });
654
- return null;
655
- }
656
- }
657
- async function buildTopicScope(ctx, topic, source, options = {}) {
658
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
659
- const mapped = asMappedProjectId(topic);
660
- return {
661
- topicId: topic._id,
662
- ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
663
- tenantId: inherited.tenantId,
664
- workspaceId: inherited.workspaceId,
665
- source
666
- };
514
+ throw new Error(`Topic not found: ${topicGlobalId}`);
667
515
  }
668
516
  ({
669
517
  projectId: v.optional(v.string()),
@@ -3,7 +3,7 @@ import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
3
3
  import { v } from 'convex/values';
4
4
  import { unsafeConvexAnyApi } from '@lucern/contracts/convex/unsafeAnyApi';
5
5
  import { componentsGeneric, mutationGeneric, internalMutationGeneric } from 'convex/server';
6
- import { generateGlobalId, assertUuidV7Identity } from '@lucern/contracts/ids';
6
+ import { generateGlobalId, assertUuidV7Identity, assertUuidV7Reference, isUuidV7 } from '@lucern/contracts/ids';
7
7
  import '@lucern/contracts/manifests/edge-policy-manifest';
8
8
  import '@lucern/contracts/manifests/edge-policy-manifest.data';
9
9
  import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
@@ -57,6 +57,9 @@ async function scheduleEmbeddingGeneration(args) {
57
57
  }
58
58
  function insertEpistemicNode(ctx, doc) {
59
59
  assertUuidV7Identity("epistemicNodes", doc.globalId);
60
+ if (doc.topicId !== void 0 && doc.topicId !== null) {
61
+ assertUuidV7Reference("epistemicNodes.topicId", doc.topicId);
62
+ }
60
63
  return ctx.db.insert("epistemicNodes", doc);
61
64
  }
62
65
 
@@ -434,6 +437,8 @@ function resolveGraphPrimitivesAppResolvers(_ctx) {
434
437
  ...resolverOverrides
435
438
  };
436
439
  }
440
+
441
+ // src/topicScope.ts
437
442
  var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
438
443
  async function resolveTopicNodeScopeOrNull(ctx, ref) {
439
444
  if (!ctx?.db || typeof ctx.db.query !== "function") {
@@ -454,16 +459,36 @@ async function resolveTopicNodeScopeOrNull(ctx, ref) {
454
459
  if (!node) {
455
460
  return null;
456
461
  }
457
- const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
462
+ const scopeKey = canonicalTopicGlobalId(node);
458
463
  if (!scopeKey) {
459
- return null;
464
+ throw new Error(
465
+ `topic.uuidv7_identity_required: topic node ${ref} is missing a UUIDv7 globalId.`
466
+ );
460
467
  }
468
+ const metadata = node.metadata ?? {};
461
469
  return {
462
470
  topicId: scopeKey,
463
471
  projectId: asMappedProjectId(node),
464
- source: "topic_node"
472
+ source: "topic_node",
473
+ tenantId: normalizeScopeValue(node.tenantId) ?? normalizeScopeValue(metadata.tenantId),
474
+ workspaceId: normalizeScopeValue(node.workspaceId) ?? normalizeScopeValue(metadata.workspaceId)
465
475
  };
466
476
  }
477
+ function canonicalTopicGlobalId(node) {
478
+ const globalId = normalizeScopeValue(node.globalId);
479
+ if (globalId && isUuidV7(globalId)) {
480
+ return globalId;
481
+ }
482
+ const topicId = normalizeScopeValue(node.topicId);
483
+ return topicId && isUuidV7(topicId) ? topicId : null;
484
+ }
485
+ function requireUuidV7TopicScope(field, value) {
486
+ if (!isUuidV7(value)) {
487
+ throw new Error(
488
+ `topic.uuidv7_required: ${field} must be a UUIDv7 public topic identifier.`
489
+ );
490
+ }
491
+ }
467
492
  function asMappedProjectId(topic) {
468
493
  if (!topic) {
469
494
  return;
@@ -485,200 +510,25 @@ function normalizeScopeValue(value) {
485
510
  const normalized = value.trim();
486
511
  return normalized.length > 0 ? normalized : void 0;
487
512
  }
488
- function pickPrimaryTopic(candidates) {
489
- return [...candidates].sort((a, b) => {
490
- const depthA = a.depth ?? 9999;
491
- const depthB = b.depth ?? 9999;
492
- if (depthA !== depthB) {
493
- return depthA - depthB;
494
- }
495
- const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
496
- const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
497
- if (createdA !== createdB) {
498
- return createdA - createdB;
499
- }
500
- return String(a.name || "").localeCompare(String(b.name || ""));
501
- })[0];
502
- }
503
- async function findTopicsByScopeAlias(ctx, scopeId) {
504
- const query2 = ctx.db.query("topics");
505
- try {
506
- return await query2.withIndex(
507
- "by_graph_scope_project",
508
- (q) => q.eq(LEGACY_SCOPE_FIELD2, scopeId)
509
- ).collect();
510
- } catch (error) {
511
- debugGraphPrimitiveFallback(
512
- "[topicScope] Failed to resolve scope alias via index",
513
- {
514
- error,
515
- scopeId
516
- }
517
- );
518
- const topics = await query2.collect();
519
- return topics.filter((topic) => {
520
- const normalizedGlobalId = normalizeScopeValue(topic.globalId);
521
- const mappedProjectId = asMappedProjectId(topic);
522
- return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
523
- });
524
- }
525
- }
526
- async function tryResolveHostTopicById(ctx, topicId) {
527
- if (typeof ctx.runQuery !== "function") {
528
- return null;
529
- }
530
- try {
531
- return await ctx.runQuery(api.topics.get, {
532
- id: topicId
533
- }) ?? null;
534
- } catch (error) {
535
- debugGraphPrimitiveFallback(
536
- "[topicScope] Failed to resolve topic by host query",
537
- {
538
- error,
539
- topicId
540
- }
541
- );
542
- return null;
543
- }
544
- }
545
- async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
546
- if (typeof ctx.runQuery !== "function") {
547
- return null;
548
- }
549
- try {
550
- return await ctx.runQuery(api.topics.getByLegacyScopeId, {
551
- projectId: legacyScopeId
552
- }) ?? null;
553
- } catch (error) {
554
- debugGraphPrimitiveFallback(
555
- "[topicScope] Failed to resolve topic by legacy scope",
556
- {
557
- error,
558
- legacyScopeId
559
- }
560
- );
561
- return null;
562
- }
563
- }
564
- async function resolveInheritedWorkspaceScope(ctx, topic) {
565
- const MAX_DEPTH = 10;
566
- let tenantId = normalizeScopeValue(topic.tenantId);
567
- let workspaceId = normalizeScopeValue(topic.workspaceId);
568
- if (tenantId && workspaceId) {
569
- return { tenantId, workspaceId };
570
- }
571
- let current = topic;
572
- for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
573
- current = await ctx.db.get(current.parentTopicId);
574
- if (!current) {
575
- break;
576
- }
577
- if (!tenantId) {
578
- tenantId = normalizeScopeValue(current.tenantId);
579
- }
580
- if (!workspaceId) {
581
- workspaceId = normalizeScopeValue(current.workspaceId);
582
- }
583
- if (tenantId && workspaceId) {
584
- break;
585
- }
586
- }
587
- return { tenantId, workspaceId };
588
- }
589
513
  async function resolveTopicProjectScope(ctx, args) {
590
514
  if (args.topicId) {
591
515
  return await resolveScopeFromTopicId(ctx, args.topicId);
592
516
  }
593
517
  if (args.projectId) {
594
- return await resolveScopeFromLegacyProjectId(ctx, args.projectId);
518
+ throw new Error(
519
+ "topic.uuidv7_required: projectId scope aliases are retired; pass topicId as the UUIDv7 topic globalId."
520
+ );
595
521
  }
596
- throw new Error(
597
- "Missing scope: provide topicId (preferred) or legacy projectId alias."
598
- );
522
+ throw new Error("topic.uuidv7_required: Missing scope: provide topicId.");
599
523
  }
600
524
  async function resolveScopeFromTopicId(ctx, topicId) {
601
- const topic = await resolveTopicDocFromTopicId(ctx, topicId);
602
- if (topic) {
603
- return await buildTopicScope(ctx, topic, "topic");
604
- }
605
- const nodeScope = await resolveTopicNodeScopeOrNull(ctx, String(topicId));
525
+ const topicGlobalId = String(topicId);
526
+ requireUuidV7TopicScope("topicId", topicGlobalId);
527
+ const nodeScope = await resolveTopicNodeScopeOrNull(ctx, topicGlobalId);
606
528
  if (nodeScope) {
607
529
  return nodeScope;
608
530
  }
609
- throw new Error(`Topic not found: ${String(topicId)}`);
610
- }
611
- async function resolveTopicDocFromTopicId(ctx, topicId) {
612
- const direct = await tryReadTopicDoc(ctx, topicId, {
613
- failureLog: "[topicScope] Failed to load topic by direct id",
614
- idLogKey: "topicId"
615
- });
616
- if (direct) {
617
- return direct;
618
- }
619
- const hostTopic = await tryResolveHostTopicById(ctx, String(topicId));
620
- if (hostTopic) {
621
- return hostTopic;
622
- }
623
- return pickPrimaryTopic(await findTopicsByScopeAlias(ctx, String(topicId))) ?? null;
624
- }
625
- async function resolveScopeFromLegacyProjectId(ctx, legacyProjectId) {
626
- const directTopic = await resolveDirectLegacyProjectTopic(
627
- ctx,
628
- legacyProjectId
629
- );
630
- if (directTopic) {
631
- return await buildTopicScope(ctx, directTopic, "topic_inferred", {
632
- fallbackProjectId: legacyProjectId
633
- });
634
- }
635
- const primary = pickPrimaryTopic(
636
- await findTopicsByScopeAlias(ctx, legacyProjectId)
637
- );
638
- if (primary) {
639
- return await buildTopicScope(ctx, primary, "project_mapped_topic", {
640
- fallbackProjectId: legacyProjectId
641
- });
642
- }
643
- const nodeScope = await resolveTopicNodeScopeOrNull(ctx, legacyProjectId);
644
- if (nodeScope) {
645
- return {
646
- ...nodeScope,
647
- projectId: nodeScope.projectId ?? legacyProjectId
648
- };
649
- }
650
- throw new Error(
651
- `Legacy project scope ${legacyProjectId} has no mapped topic.`
652
- );
653
- }
654
- async function resolveDirectLegacyProjectTopic(ctx, legacyProjectId) {
655
- const directTopic = await tryReadTopicDoc(ctx, legacyProjectId, {
656
- failureLog: "[topicScope] Failed to load direct project topic",
657
- idLogKey: "projectId"
658
- });
659
- return directTopic ?? tryResolveHostTopicByLegacyScope(ctx, legacyProjectId);
660
- }
661
- async function tryReadTopicDoc(ctx, id, log) {
662
- try {
663
- return await ctx.db.get(id);
664
- } catch (error) {
665
- debugGraphPrimitiveFallback(log.failureLog, {
666
- error,
667
- [log.idLogKey]: id
668
- });
669
- return null;
670
- }
671
- }
672
- async function buildTopicScope(ctx, topic, source, options = {}) {
673
- const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
674
- const mapped = asMappedProjectId(topic);
675
- return {
676
- topicId: topic._id,
677
- ...mapped || options.fallbackProjectId ? { projectId: mapped ?? options.fallbackProjectId } : {},
678
- tenantId: inherited.tenantId,
679
- workspaceId: inherited.workspaceId,
680
- source
681
- };
531
+ throw new Error(`Topic not found: ${topicGlobalId}`);
682
532
  }
683
533
  var optionalScopeArgs = {
684
534
  projectId: v.optional(v.string()),
@@ -7,7 +7,7 @@ export { getByCategory, getById, getByProject, getByTopic, getForBelief, interna
7
7
  export { getForSprintCluster, getInConviction } from './epistemicQuestions.sprint.js';
8
8
  export { consolidate, deleteQuestion, getByPillar, getQuestionClusterPositions, list, markAnsweredWithArtifact } from './epistemicQuestions.tail.js';
9
9
  import '@lucern/access-control/convex.js';
10
- import './topicScope-DJVa0mLa.js';
10
+ import './topicScope-CL1IVOmv.js';
11
11
  import 'convex/values';
12
12
  import './convex.js';
13
13
  import '@lucern/access-control/convex';