@lucern/graph-primitives 1.0.23 → 1.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/beliefDecay.js +3 -0
- package/dist/beliefDecay.js.map +1 -1
- package/dist/beliefEvidenceLinks.js +15 -3
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.js +12 -3
- package/dist/beliefEvidenceLinks.operational.js.map +1 -1
- package/dist/entityCanonicalMatch.d.ts +40 -0
- package/dist/entityCanonicalMatch.js +33 -0
- package/dist/entityCanonicalMatch.js.map +1 -0
- package/dist/entityLifecycle.js +62 -37
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.js +17 -6
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.js +13 -2
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.js +17 -6
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.js +32 -9
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.forkEvidence.js +13 -2
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +16 -1
- package/dist/epistemicBeliefs.helpers.js +20 -6
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.js +28 -5
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +32 -9
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.js +17 -6
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.js +29 -9
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.js +12 -3
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
- package/dist/epistemicContracts.evaluators.js +17 -6
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.js +17 -6
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +17 -6
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicEdges.handlers.js +12 -3
- package/dist/epistemicEdges.handlers.js.map +1 -1
- package/dist/epistemicEdges.helpers.d.ts +2 -2
- package/dist/epistemicEdges.js +15 -3
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.js +3 -0
- package/dist/epistemicEdges.mutations.js.map +1 -1
- package/dist/epistemicEvidence.js +15 -3
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.js +3 -0
- package/dist/epistemicEvidenceHelpers.js.map +1 -1
- package/dist/epistemicEvidenceMutations.js +15 -3
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicEvidenceQueries.js +3 -0
- package/dist/epistemicEvidenceQueries.js.map +1 -1
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicInsert.js +12 -3
- package/dist/epistemicInsert.js.map +1 -1
- package/dist/epistemicNodeCreation.js.map +1 -1
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/epistemicNodes.validators.d.ts +2 -2
- package/dist/epistemicQuestions.conviction.js +3 -0
- package/dist/epistemicQuestions.conviction.js.map +1 -1
- package/dist/epistemicQuestions.create.js +3 -0
- package/dist/epistemicQuestions.create.js.map +1 -1
- package/dist/epistemicQuestions.evidence.js +3 -0
- package/dist/epistemicQuestions.evidence.js.map +1 -1
- package/dist/epistemicQuestions.helpers.js +3 -0
- package/dist/epistemicQuestions.helpers.js.map +1 -1
- package/dist/epistemicQuestions.js +3 -0
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.js +3 -0
- package/dist/epistemicQuestions.lifecycle.js.map +1 -1
- package/dist/epistemicQuestions.queries.js +3 -0
- package/dist/epistemicQuestions.queries.js.map +1 -1
- package/dist/epistemicQuestions.tail.js +3 -0
- package/dist/epistemicQuestions.tail.js.map +1 -1
- package/dist/epistemicSources.js.map +1 -1
- package/dist/index.js +78 -42
- package/dist/index.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/questionEvidenceLinks.js +3 -0
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/resolvers.js +3 -0
- package/dist/resolvers.js.map +1 -1
- package/dist/topicProjectOverlay.d.ts +4 -0
- package/dist/topicProjectOverlay.js +3 -0
- package/dist/topicProjectOverlay.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/convex.ts","../src/epistemicLayerRules.ts","../src/epistemicEdgeCreation.ts","../src/epistemicInsert.ts","../src/epistemicNodeCreation.ts"],"names":["contentHash","existing"],"mappings":"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","file":"epistemicNodeCreation.js","sourcesContent":["import {\n actionGeneric,\n anyApi,\n componentsGeneric,\n httpActionGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n mutationGeneric,\n queryGeneric,\n} from \"convex/server\";\nimport type { GenericId } from \"convex/values\";\n\nexport const api = anyApi as any;\nexport const components = componentsGeneric() as any;\nexport const internal = anyApi as any;\n\nexport type TableNames = string;\nexport type Id<TableName extends TableNames = string> = GenericId<TableName>;\nexport type Doc<TableName extends TableNames = string> = any;\nexport type DataModel = any;\ntype IndexRangeBuilder = {\n field(fieldName: string): string;\n eq(fieldName: string, value: unknown): IndexRangeBuilder;\n gt(fieldName: string, value: unknown): IndexRangeBuilder;\n gte(fieldName: string, value: unknown): IndexRangeBuilder;\n lt(fieldName: string, value: unknown): IndexRangeBuilder;\n lte(fieldName: string, value: unknown): IndexRangeBuilder;\n};\ntype FilterBuilder = {\n eq(left: unknown, right: unknown): unknown;\n neq(left: unknown, right: unknown): unknown;\n gt(left: unknown, right: unknown): unknown;\n gte(left: unknown, right: unknown): unknown;\n lt(left: unknown, right: unknown): unknown;\n lte(left: unknown, right: unknown): unknown;\n and(...clauses: unknown[]): unknown;\n or(...clauses: unknown[]): unknown;\n field(fieldName: string): unknown;\n};\ntype QueryInitializer<TableName extends TableNames> = {\n withIndex(\n indexName: string,\n range?: (q: any) => unknown\n ): QueryInitializer<TableName>;\n filter(predicate: (q: any) => unknown): QueryInitializer<TableName>;\n order(direction: \"asc\" | \"desc\"): QueryInitializer<TableName>;\n collect(): Promise<Doc<TableName>[]>;\n take(limit: number): Promise<Doc<TableName>[]>;\n first(): Promise<Doc<TableName> | null>;\n unique(): Promise<Doc<TableName> | null>;\n};\nexport type DatabaseReader = {\n get<TableName extends TableNames>(\n id: Id<TableName>\n ): Promise<Doc<TableName> | null>;\n query<TableName extends TableNames>(\n tableName: TableName\n ): QueryInitializer<TableName>;\n normalizeId?<TableName extends TableNames>(\n tableName: TableName,\n id: string\n ): Id<TableName> | null;\n};\nexport type DatabaseWriter = DatabaseReader & {\n insert<TableName extends TableNames>(\n tableName: TableName,\n value: Record<string, unknown>\n ): Promise<Id<TableName>>;\n patch<TableName extends TableNames>(\n id: Id<TableName>,\n value: Record<string, unknown>\n ): Promise<void>;\n replace<TableName extends TableNames>(\n id: Id<TableName>,\n value: Record<string, unknown>\n ): Promise<void>;\n delete<TableName extends TableNames>(id: Id<TableName>): Promise<void>;\n};\ntype Scheduler = {\n runAfter(delayMs: number, functionReference: unknown, args?: unknown): Promise<void>;\n};\ntype AuthReader = {\n getUserIdentity(): Promise<unknown>;\n};\ntype RuntimeInvoker = {\n runQuery(functionReference: unknown, args?: unknown): Promise<any>;\n runMutation(functionReference: unknown, args?: unknown): Promise<any>;\n runAction(functionReference: unknown, args?: unknown): Promise<any>;\n};\nexport type QueryCtx = RuntimeInvoker & {\n auth: AuthReader;\n db: DatabaseReader;\n scheduler: Scheduler;\n};\nexport type MutationCtx = RuntimeInvoker & {\n auth: AuthReader;\n db: DatabaseWriter;\n scheduler: Scheduler;\n};\nexport type ActionCtx = RuntimeInvoker & {\n auth: AuthReader;\n scheduler: Scheduler;\n};\n\ntype ConvexFunctionBuilder<Ctx> = <\n Definition extends { handler?: (ctx: Ctx, args: any) => any },\n>(\n definition: Definition\n) => any;\n\nexport const action = actionGeneric as unknown as ConvexFunctionBuilder<ActionCtx>;\nexport const httpAction =\n httpActionGeneric as unknown as ConvexFunctionBuilder<ActionCtx>;\nexport const internalAction =\n internalActionGeneric as unknown as ConvexFunctionBuilder<ActionCtx>;\nexport const internalMutation =\n internalMutationGeneric as unknown as ConvexFunctionBuilder<MutationCtx>;\nexport const internalQuery =\n internalQueryGeneric as unknown as ConvexFunctionBuilder<QueryCtx>;\nexport const mutation =\n mutationGeneric as unknown as ConvexFunctionBuilder<MutationCtx>;\nexport const query = queryGeneric as unknown as ConvexFunctionBuilder<QueryCtx>;\n","/**\n * Epistemic Spine helper module split from epistemicHelpers.ts.\n */\n\nimport type { Id } from \"./convex\";\n\n// =============================================================================\n// TYPE MAPPINGS\n// =============================================================================\n\ntype EpistemicNodeType =\n // L4: Audit targets\n | \"decision\"\n // L3: Traversal anchors\n | \"belief\"\n | \"question\"\n | \"theme\"\n | \"deal\"\n // L2: Compression boundary\n | \"claim\"\n | \"evidence\"\n | \"synthesis\"\n | \"answer\"\n // L1: Terminal leaves\n | \"atomic_fact\"\n | \"excerpt\"\n | \"source\";\n\ntype OntologicalNodeType =\n | \"company\"\n | \"person\"\n | \"investor\"\n | \"function\"\n | \"value_chain\";\n\ntype NodeType = EpistemicNodeType | OntologicalNodeType;\n\n// =============================================================================\n// EPISTEMIC LAYER ARCHITECTURE (Lucern Invariant Compliance)\n// =============================================================================\n\n/**\n * Epistemic Layer - governs traversal rules\n * L4 → L3 → L2 → L1 (never skip layers)\n */\nexport type EpistemicLayer =\n | \"L4\"\n | \"L3\"\n | \"L2\"\n | \"L1\"\n | \"ontological\"\n | \"organizational\";\n\n/**\n * Map nodeType to its epistemic layer\n *\n * Layer semantics:\n * - L4: Audit targets (decisions, outcomes) - what we committed to\n * - L3: Traversal anchors (beliefs, questions, themes) - epistemic structure\n * - L2: Compression boundary (claims, evidence, synthesis) - minimum reasoning unit\n * - L1: Terminal leaves (atomic_fact, excerpt, source) - non-traversable grounding\n * - ontological: Entities in the world (companies, people) - not epistemic\n * - organizational: Structural containers (topics, lenses, worktrees) - not epistemic\n */\nexport function getNodeLayer(nodeType: string): EpistemicLayer {\n switch (nodeType) {\n // L4: Audit targets\n case \"decision\":\n return \"L4\";\n\n // L3: Traversal anchors\n case \"belief\":\n case \"question\":\n case \"theme\":\n case \"deal\":\n return \"L3\";\n\n // L2: Compression boundary\n case \"claim\":\n case \"evidence\":\n case \"synthesis\":\n case \"answer\":\n return \"L2\";\n\n // L1: Terminal leaves\n case \"atomic_fact\":\n case \"excerpt\":\n case \"source\":\n return \"L1\";\n\n // Ontological entities\n case \"company\":\n case \"person\":\n case \"investor\":\n case \"function\":\n case \"value_chain\":\n return \"ontological\";\n\n // Organizational containers\n case \"topic\":\n return \"organizational\";\n\n default:\n // Unknown types default to L2 (safest for traversal)\n console.warn(\n `[EpistemicLayer] Unknown nodeType: ${nodeType}, defaulting to L2`\n );\n return \"L2\";\n }\n}\n\n/**\n * Layer traversal rules\n * Key constraint: Cannot skip layers during traversal\n */\nexport const LAYER_TRAVERSAL_RULES = {\n L4: {\n canReach: [\"L3\", \"L4\"], // Decisions can reach beliefs/questions\n mustPassThrough: \"L3\", // Must go through L3 to reach L2\n },\n L3: {\n canReach: [\"L2\", \"L3\", \"L4\"], // Beliefs can reach evidence, other beliefs, or decisions\n mustPassThrough: \"L2\", // Must go through L2 to reach L1\n },\n L2: {\n canReach: [\"L1\", \"L2\", \"L3\"], // Evidence can reach sources, other evidence, or beliefs\n mustPassThrough: null, // L2 can reach L1 directly\n },\n L1: {\n canReach: [\"L1\"], // Sources can only reach other sources\n mustPassThrough: null, // Terminal - no traversal beyond\n },\n ontological: {\n canReach: [\"L3\", \"L2\", \"ontological\"], // Entities can link to epistemic structure\n mustPassThrough: null, // No layer constraints for entities\n },\n organizational: {\n canReach: [\"L3\", \"L2\", \"organizational\"], // Containers scope epistemic structure + nest\n mustPassThrough: null, // No layer constraints for containers\n },\n} as const;\n\n/**\n * Check if a direct edge between two layers is allowed\n */\nexport function isValidLayerConnection(\n fromLayer: EpistemicLayer,\n toLayer: EpistemicLayer\n): boolean {\n const rules = LAYER_TRAVERSAL_RULES[fromLayer];\n return (rules.canReach as readonly string[]).includes(toLayer);\n}\n\n/**\n * Get layer hierarchy number (for comparison)\n * Higher number = higher layer\n */\nexport function getLayerDepth(layer: EpistemicLayer): number {\n switch (layer) {\n case \"L4\":\n return 4;\n case \"L3\":\n return 3;\n case \"L2\":\n return 2;\n case \"L1\":\n return 1;\n case \"ontological\":\n return 0; // Ontological exists outside the epistemic hierarchy\n case \"organizational\":\n return 0; // Organizational exists outside the epistemic hierarchy\n default:\n return 2;\n }\n}\n\n/**\n * Check if we can traverse from one layer to another\n * (considering intermediate layers)\n */\nexport function canTraverseToLayer(\n fromLayer: EpistemicLayer,\n toLayer: EpistemicLayer\n): boolean {\n const fromDepth = getLayerDepth(fromLayer);\n const toDepth = getLayerDepth(toLayer);\n\n // Ontological/organizational layers are special - use explicit rules\n if (\n fromLayer === \"ontological\" ||\n toLayer === \"ontological\" ||\n fromLayer === \"organizational\" ||\n toLayer === \"organizational\"\n ) {\n return isValidLayerConnection(fromLayer, toLayer);\n }\n\n // Can always stay at same layer\n if (fromDepth === toDepth) {\n return true;\n }\n\n // Can go up (L1→L2→L3→L4) or down (L4→L3→L2→L1)\n // But must respect layer rules\n return isValidLayerConnection(fromLayer, toLayer);\n}\n\n// =============================================================================\n// PHASE 2D: LAYER-AWARE TRAVERSAL\n// =============================================================================\n\n/**\n * Traversal mode - determines how to traverse the graph\n *\n * anchor_down: Start at L3 belief, traverse to L2 evidence, stop at L1 sources\n * anchor_up: Start at L2 evidence, traverse to L3 beliefs it supports\n * same_layer: Traverse within a single layer (e.g., belief → belief)\n * decision_trace: Start at L4 decision, traverse to L3 beliefs it was based on\n */\nexport type TraversalMode =\n | \"anchor_down\"\n | \"anchor_up\"\n | \"same_layer\"\n | \"decision_trace\";\n\n/**\n * Traversal options for layer-aware queries\n */\nexport type TraversalOptions = {\n /** Starting node ID */\n startNodeId: Id<\"epistemicNodes\">;\n /** Traversal mode */\n mode: TraversalMode;\n /** Edge types to follow (empty = all valid for mode) */\n allowedEdgeTypes?: string[];\n /** Maximum depth */\n maxDepth?: number;\n /** Minimum layer to stop at (L1 = 1, L4 = 4) */\n minLayer?: number;\n /** Maximum layer to reach */\n maxLayer?: number;\n};\n\n/**\n * Check if traversal should continue based on layer constraints\n */\nexport function shouldContinueTraversal(\n currentLayer: EpistemicLayer,\n targetLayer: EpistemicLayer,\n options: {\n mode: TraversalMode;\n minLayer?: number;\n maxLayer?: number;\n }\n): boolean {\n const currentDepth = getLayerDepth(currentLayer);\n const targetDepth = getLayerDepth(targetLayer);\n\n // Check min/max layer constraints\n if (options.minLayer !== undefined && targetDepth < options.minLayer) {\n return false; // Would go below minimum layer\n }\n if (options.maxLayer !== undefined && targetDepth > options.maxLayer) {\n return false; // Would go above maximum layer\n }\n\n // Mode-specific rules\n switch (options.mode) {\n case \"anchor_down\":\n // Can only go down (L4→L3→L2→L1)\n return targetDepth < currentDepth || targetDepth === currentDepth;\n\n case \"anchor_up\":\n // Can only go up (L1→L2→L3→L4)\n return targetDepth > currentDepth || targetDepth === currentDepth;\n\n case \"same_layer\":\n // Must stay at same layer\n return targetDepth === currentDepth;\n\n case \"decision_trace\":\n // Decisions (L4) can trace to beliefs (L3), stop there\n return currentDepth === 4\n ? targetDepth === 3\n : targetDepth === currentDepth;\n\n default:\n return true;\n }\n}\n\n/**\n * Get default minLayer for a traversal mode\n */\nexport function getDefaultMinLayer(mode: TraversalMode): number {\n switch (mode) {\n case \"anchor_down\":\n return 1; // Can go all the way to L1 sources\n case \"anchor_up\":\n return 2; // Start at L2 evidence minimum\n case \"same_layer\":\n return 1; // No constraint\n case \"decision_trace\":\n return 3; // Stop at L3 beliefs (don't go to L2 evidence)\n default:\n return 1;\n }\n}\n\n/**\n * Get allowed edge types for a traversal mode\n */\nexport function getDefaultEdgeTypesForMode(mode: TraversalMode): string[] {\n switch (mode) {\n case \"anchor_down\":\n // From beliefs/questions down to evidence and sources\n return [\n \"informs\", // evidence → belief (traverse backwards)\n \"derived_from\", // evidence → source (provenance) + evidence → question\n ];\n case \"anchor_up\":\n // From evidence up to beliefs\n return [\"informs\", \"derived_from\"];\n case \"same_layer\":\n // Within-layer relationships\n return [\n // L3: Belief ↔ Belief\n \"depends_on\",\n \"supports\",\n \"contains\",\n // L3: Question ↔ Question\n \"prerequisite_for\",\n \"parallel_to\",\n // L2: Evidence ↔ Evidence\n \"corroborates\",\n \"extends\",\n \"same_source_as\",\n \"same_theme_as\",\n ];\n case \"decision_trace\":\n // From decisions to beliefs\n return [\n \"derived_from\",\n \"depends_on\",\n \"contains\",\n ];\n default:\n return [];\n }\n}\n\n// =============================================================================\n// PHASE 2C: EDGE LAYER RULES\n// =============================================================================\n\n/**\n * Edge Layer Rules - defines valid layer combinations for each edge type\n *\n * Format: { from: [allowed source layers], to: [allowed target layers] }\n *\n * Key rules:\n * - L4 edges: Decision → L3 (beliefs, questions, themes)\n * - Cross-layer edges: L2 → L3 (evidence informs beliefs)\n * - Same-layer edges: L3 → L3, L2 → L2 (beliefs depend on beliefs)\n * - Downward edges: L2 → L1 (evidence extracted from source)\n * - Lifecycle edges: same layer only (supersedes)\n */\nexport const EDGE_LAYER_RULES: Record<\n string,\n { from: EpistemicLayer[]; to: EpistemicLayer[]; description: string }\n> = {\n // === L4 Decision Edges ===\n based_on_belief: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Belief (L4 → L3)\",\n },\n based_on_question: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Question (L4 → L3)\",\n },\n blocked_by_contradiction: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Contradiction (L4 → L3)\",\n },\n informed_by_theme: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Theme (L4 → L3)\",\n },\n\n // === Evidence Flow (L2 → L3, L2 → L1) ===\n derived_from: {\n from: [\"L2\", \"L3\", \"L4\"],\n to: [\"L1\", \"L2\", \"L3\"],\n description: \"A was produced from B (provenance chain)\",\n },\n answers: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Evidence → Question (L2 → L3)\",\n },\n responds_to: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Answer → Question (L2 → L3)\",\n },\n informs: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Evidence → Belief (L2 → L3)\",\n },\n qualifies: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Evidence → Belief (L2 → L3)\",\n },\n\n // === Question → Belief (L3 → L3) ===\n tests: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Question → Belief (L3 → L3)\",\n },\n explores: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Question → Belief assumption (L3 → L3)\",\n },\n\n // === Synthesis (L2 → L2, L2 → L1) ===\n based_on: {\n from: [\"L2\"],\n to: [\"L2\", \"L1\"],\n description: \"Synthesis → Evidence/Source (L2 → L2/L1)\",\n },\n\n // === Theme Relationships (L3 → L3) ===\n relates_to_thesis: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Belief → Theme (L3 → L3)\",\n },\n belongs_to: {\n from: [\"L3\", \"L2\"], // Can belong to theme from L3 or L2\n to: [\"L3\"],\n description: \"Any → Theme (L3/L2 → L3)\",\n },\n plays_theme: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Deal → Theme (L3 → L3)\",\n },\n\n // === Topic Hierarchy (L3 → organizational) ===\n scoped_by: {\n from: [\"L3\"],\n to: [\"organizational\"],\n description: \"Belief/Question → Topic (L3 → organizational)\",\n },\n\n // === Deal/Company ===\n evaluates: {\n from: [\"L3\"],\n to: [\"ontological\"],\n description: \"Deal → Company (L3 → ontological)\",\n },\n\n // === People (ontological → ontological, ontological → L3) ===\n perspective_on: {\n from: [\"ontological\"],\n to: [\"L3\"],\n description: \"Person → Belief/Theme (ontological → L3)\",\n },\n works_at: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Person → Company (ontological → ontological)\",\n },\n\n // === Value Chain (ontological) ===\n participates_in: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → ValueChain (ontological → ontological)\",\n },\n performs: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Function (ontological → ontological)\",\n },\n function_in: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Function → ValueChain (ontological → ontological)\",\n },\n impacts: {\n from: [\"L3\"],\n to: [\"ontological\"],\n description: \"Theme → ValueChain (L3 → ontological)\",\n },\n\n // === Investment (ontological) ===\n invested_in: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Investor → Company (ontological → ontological)\",\n },\n raised_from: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Investor (ontological → ontological)\",\n },\n\n // === Entity↔Belief Bridge (OE-B) ===\n about_entity: {\n from: [\"L3\"],\n to: [\"ontological\"],\n description: \"Belief/Question/Theme → Entity (L3 → ontological)\",\n },\n entity_referenced_in: {\n from: [\"ontological\"],\n to: [\"L2\"],\n description: \"Entity → Evidence (ontological → L2)\",\n },\n mentioned_in: {\n from: [\"ontological\"],\n to: [\"L1\"],\n description: \"Entity → Source document (ontological → L1)\",\n },\n founded_by: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Person (ontological → ontological)\",\n },\n competes_with: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Company (ontological → ontological)\",\n },\n contains: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"ValueChain → Function (ontological → ontological)\",\n },\n\n // === Lifecycle (same layer only) ===\n supersedes: {\n from: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n to: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n description: \"NewNode → OldNode (same layer only - validated separately)\",\n },\n same_as: {\n from: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n to: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n description: \"Duplicate detection (same layer only - validated separately)\",\n },\n\n // === Same-Type: Belief ↔ Belief (L3 → L3) ===\n depends_on: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Belief B requires Belief A (L3 → L3)\",\n },\n reinforces: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Beliefs strengthen each other (L3 → L3)\",\n },\n parent_of: {\n from: [\"L3\", \"organizational\"],\n to: [\"L3\", \"organizational\"],\n description:\n \"A is higher-level than B (L3 → L3, organizational → organizational)\",\n },\n child_of: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Belief A is more specific (L3 → L3)\",\n },\n\n // === Same-Type: Question ↔ Question (L3 → L3) ===\n prerequisite_for: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Question A must be answered first (L3 → L3)\",\n },\n parallel_to: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Same topic, different angles (L3 → L3)\",\n },\n\n // === Same-Type: Evidence ↔ Evidence (L2 → L2) ===\n corroborates: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Independent support (L2 → L2)\",\n },\n extends: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Adds depth (L2 → L2)\",\n },\n same_source_as: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Same document/study (L2 → L2)\",\n },\n same_theme_as: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Same topic/entity (L2 → L2)\",\n },\n\n // === NEW: Deep Epistemic Analysis Edges (Phase: Schema Upgrade) ===\n assumes: {\n from: [\"L3\"],\n to: [\"L3\"],\n description:\n \"Hidden dependency - Belief B implicitly assumes Belief A (L3 → L3)\",\n },\n would_predict: {\n from: [\"L3\"],\n to: [\"L2\"],\n description:\n \"Pre-registered prediction - If Belief true, expect Evidence (L3 → L2)\",\n },\n analogous_to: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Explicit analogy - Belief A is like Belief B (L3 → L3)\",\n },\n independent_of: {\n from: [\"L2\"],\n to: [\"L2\"],\n description:\n \"True evidence independence - Evidence A independent of B (L2 → L2)\",\n },\n\n // NOTE: Deprecated edge types (supports, contradicts, derived_from, cites,\n // summarizes, related_to, partially_answers, blocks, refines, branches_from)\n // have been REMOVED from the system. Use compliant alternatives instead.\n};\n\n/**\n * Validate an edge against layer rules\n *\n * Returns { valid: true } or { valid: false, reason: string }\n */\nexport function validateEdgeLayers(\n edgeType: string,\n fromLayer: EpistemicLayer,\n toLayer: EpistemicLayer\n): { valid: boolean; reason?: string } {\n const rules = EDGE_LAYER_RULES[edgeType];\n\n // Unknown edge type - allow but warn\n if (!rules) {\n console.warn(\n `[EdgeValidation] Unknown edge type: ${edgeType}, allowing by default`\n );\n return { valid: true };\n }\n\n // Special handling for same-layer edges (supersedes)\n if (edgeType === \"supersedes\") {\n if (fromLayer !== toLayer) {\n return {\n valid: false,\n reason: `${edgeType} edges must be between nodes of the same layer. Got ${fromLayer} → ${toLayer}`,\n };\n }\n return { valid: true };\n }\n\n // Check from layer\n if (!rules.from.includes(fromLayer)) {\n return {\n valid: false,\n reason: `Edge type '${edgeType}' does not allow source layer ${fromLayer}. Allowed: ${rules.from.join(\", \")}`,\n };\n }\n\n // Check to layer\n if (!rules.to.includes(toLayer)) {\n return {\n valid: false,\n reason: `Edge type '${edgeType}' does not allow target layer ${toLayer}. Allowed: ${rules.to.join(\", \")}`,\n };\n }\n\n return { valid: true };\n}\n\n","/**\n * Epistemic Spine helper module split from epistemicHelpers.ts.\n */\n\nimport { internal } from \"./convex\";\nimport type { Id, MutationCtx } from \"./convex\";\nimport { generateGlobalId } from \"./globalId\";\nimport { getNodeLayer, validateEdgeLayers } from \"./epistemicLayerRules\";\n\ntype NodeTypeIndexQuery = {\n eq(field: string, value: unknown): NodeTypeIndexQuery;\n};\n\n/**\n * Edge type union for createEpistemicEdge\n * Phase 2C: Updated to include L4 edges and modern edge types\n * Phase 3: Added full epistemic impact edges for confidence propagation\n */\ntype EpistemicEdgeType =\n // Canonical edge types (K-tier compliant)\n | \"derived_from\" // replaces: answers, extracted_from, based_on, same_as, based_on_belief, based_on_question\n | \"supports\" // replaces: reinforces, strengthened_by, validated_by, weakened_by, alternative_to, falsified_by, exclusive_with (with appropriate weight)\n | \"contains\" // replaces: parent_of, child_of, about_entity, entity_referenced_in, subsumes, informed_by_theme\n | \"depends_on\" // replaces: collapses_if, cascade_from, required_for, blocks, blocked_by_contradiction\n | \"informs\"\n | \"tests\" // replaces: explores\n | \"responds_to\"\n // Theme relationships\n | \"relates_to_thesis\"\n | \"belongs_to\"\n | \"plays_theme\"\n // Lifecycle\n | \"supersedes\"\n // Same-type: Belief - Cluster Mapping (Thesis Validation Sprints)\n | \"counterfactual_of\"\n | \"cascade_to\"\n | \"mutually_exclusive\"\n | \"correlates_with\"\n | \"amplifies\"\n | \"precondition_for\"\n | \"in_tension_with\"\n // Same-type: Belief - Deep Epistemic Analysis (Tier 2)\n | \"assumes\"\n | \"would_predict\"\n | \"analogous_to\"\n | \"independent_of\"\n // Same-type: Question\n | \"prerequisite_for\"\n | \"parallel_to\"\n // Same-type: Evidence\n | \"corroborates\"\n | \"extends\"\n | \"same_source_as\"\n | \"same_theme_as\"\n // Ontological\n | \"evaluates\"\n | \"perspective_on\"\n | \"works_at\"\n | \"participates_in\"\n | \"performs\"\n | \"function_in\"\n | \"impacts\"\n | \"invested_in\"\n | \"raised_from\"\n // People/Entity References\n | \"mentioned_in\"\n | \"founded_by\"\n | \"competes_with\";\n\n// NOTE: Deprecated edge types have been REMOVED from this type.\n// See schema.ts for the list of removed types and their compliant alternatives.\n\n// =============================================================================\n// CONFIDENCE NORMALIZATION\n// =============================================================================\n\n/**\n * Normalize confidence to a 0-1 number regardless of input format.\n *\n * Handles:\n * - number (0-1): returned as-is\n * - number (1-100): divided by 100\n * - string (\"high\"/\"medium\"/\"low\"): mapped to 0.8/0.5/0.3\n * - undefined/null/other: returns 0.5 default\n *\n * This is the canonical way to read confidence from any source.\n */\nexport function normalizeConfidence(confidence: unknown): number {\n if (typeof confidence === \"number\") {\n return confidence > 1 ? confidence / 100 : confidence;\n }\n if (typeof confidence === \"string\") {\n switch (confidence) {\n case \"high\":\n return 0.8;\n case \"medium\":\n return 0.5;\n case \"low\":\n return 0.3;\n default:\n return 0.5;\n }\n }\n return 0.5;\n}\n\n/**\n * Epistemic Edge Propagation Semantics\n *\n * Each edge type has specific propagation rules for confidence cascades:\n *\n * | Edge Type | Direction | Propagation Rule |\n * |-------------------|--------------|-----------------------------------------------------------|\n * | depends_on | B → A | A.conf = min(A.conf, B.conf + 0.2) |\n * | reinforces | A ↔ B | Both get boost when either validated |\n * | falsified_by | B → A | A.conf = 1 - B.conf (inverse) |\n * | exclusive_with | A ↔ B | A.conf + B.conf ≤ 1.0 (redistribute on evidence) |\n * | contradicts | A ↔ B | Creates tension - neither can be validated without fork |\n * | collapses_if | A → B | If A.conf < threshold, B.conf → 0 |\n * | cascade_from | A → B | B.conf_delta = A.conf_delta * damping_factor |\n * | strengthened_by | A → B | B.conf += A.conf_delta * correlation |\n * | weakened_by | A → B | B.conf -= A.conf_delta * correlation |\n * | alternative_to | A ↔ B | Evidence for A reduces B, and vice versa |\n * | subsumes | A → B | A.conf >= B.conf always |\n * | validated_by | A → B | If A validated, B gains confidence |\n * | required_for | A → B | B cannot be validated until A is validated |\n * | blocks | A → B | B resolution blocked until A resolved |\n */\n\n/**\n * Create an epistemic edge between two nodes\n *\n * Phase 1 (Graph Architecture): Writes to Neo4j directly - Neo4j is source of truth.\n * Returns globalId (string) instead of Convex edge ID.\n *\n * Phase 2C: Validates layer rules before creation\n */\nexport async function createEpistemicEdge(\n ctx: MutationCtx,\n params: {\n fromNodeId: Id<\"epistemicNodes\">;\n toNodeId: Id<\"epistemicNodes\">;\n edgeType: EpistemicEdgeType;\n weight?: number;\n confidence?: number;\n context?: string;\n // NOTE: 'relation' field has been removed. Use 'weight' instead.\n projectId?: string;\n createdBy: string;\n // Phase 2C: Allow skipping validation for migrations\n skipLayerValidation?: boolean;\n }\n): Promise<string> {\n const globalId = generateGlobalId();\n\n // Get node types for denormalization\n const fromNode = await ctx.db.get(params.fromNodeId);\n const toNode = await ctx.db.get(params.toNodeId);\n\n if (!fromNode || !toNode) {\n throw new Error(\"One or both nodes not found\");\n }\n\n // Phase 2C: Get layers (use stored or derive from nodeType)\n const fromLayer = fromNode.epistemicLayer || getNodeLayer(fromNode.nodeType);\n const toLayer = toNode.epistemicLayer || getNodeLayer(toNode.nodeType);\n\n // Phase 2C: Validate layer rules\n if (!params.skipLayerValidation) {\n const validation = validateEdgeLayers(params.edgeType, fromLayer, toLayer);\n if (!validation.valid) {\n throw new Error(\n `[EdgeValidation] Invalid edge: ${validation.reason}. ` +\n `Attempted: ${params.edgeType} from ${fromNode.nodeType}(${fromLayer}) → ${toNode.nodeType}(${toLayer})`\n );\n }\n }\n\n // Phase 1 (Graph Architecture): Write to Neo4j directly - Neo4j is source of truth\n await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {\n globalId,\n fromGlobalId: fromNode.globalId,\n toGlobalId: toNode.globalId,\n edgeType: params.edgeType,\n weight: params.weight,\n confidence: params.confidence,\n context: params.context,\n createdBy: params.createdBy,\n topicId: params.projectId ? String(params.projectId) : undefined,\n fromNodeType: fromNode.nodeType,\n toNodeType: toNode.nodeType,\n fromLayer,\n toLayer,\n });\n\n return globalId;\n}\n\n/**\n * Create an edge when linking an insight to a question\n * This creates a \"derived_from\" edge (evidence answers/informs question)\n */\nexport async function createEdgeForInsightQuestionLink(\n ctx: MutationCtx,\n questionId: Id<\"epistemicNodes\">,\n insightId: Id<\"epistemicNodes\">,\n createdBy: string\n): Promise<string | null> {\n console.log(\"[EpistemicSpine] Creating edge for insight-question link:\", {\n questionId: String(questionId),\n insightId: String(insightId),\n });\n\n // Find the epistemic nodes for both entities\n const questionNode = await findNodeByLegacyId(ctx, \"question\", questionId);\n const insightNode = await findNodeByLegacyId(ctx, \"insight\", insightId);\n\n console.log(\"[EpistemicSpine] Found nodes:\", {\n questionNode: questionNode ? String(questionNode) : null,\n insightNode: insightNode ? String(insightNode) : null,\n });\n\n if (!questionNode || !insightNode) {\n // Nodes don't exist yet - this can happen for legacy data\n // They'll be created during backfill\n console.log(\"[EpistemicSpine] Missing nodes, skipping edge creation\");\n return null;\n }\n\n // Get the question for projectId\n const question = await ctx.db.get(questionId);\n const projectId = question?.projectId;\n\n // Create the edge: Evidence -> Question\n // Use \"derived_from\" - canonical replacement for \"answers\" edge type\n return await createEpistemicEdge(ctx, {\n fromNodeId: insightNode,\n toNodeId: questionNode,\n edgeType: \"derived_from\",\n projectId,\n createdBy,\n context: \"Linked from questions workspace\",\n });\n}\n\n/**\n * Find an epistemic node by its legacy ID (stored in metadata)\n */\nasync function findNodeByLegacyId(\n ctx: MutationCtx,\n legacyType: \"insight\" | \"belief\" | \"question\" | \"artifact\",\n legacyId: Id<\"epistemicNodes\"> | Id<\"finalArtifacts\">\n): Promise<Id<\"epistemicNodes\"> | null> {\n // Query all nodes and find the one with matching legacy ID\n // This is not ideal for performance, but works for now\n // TODO: Add a dedicated index for legacy IDs\n const nodeType =\n legacyType === \"insight\"\n ? \"evidence\"\n : legacyType === \"artifact\"\n ? \"source\"\n : legacyType;\n\n const nodes = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_nodeType\", (q: NodeTypeIndexQuery) =>\n q.eq(\"nodeType\", nodeType),\n )\n .collect();\n\n const legacyKey = `legacy${legacyType.charAt(0).toUpperCase() + legacyType.slice(1)}Id`;\n\n // Convert legacyId to string for comparison (Convex Id objects need string comparison)\n const legacyIdStr = String(legacyId);\n\n const found = nodes.find((n) => {\n const metadata = n.metadata as Record<string, unknown> | undefined;\n const storedId = metadata?.[legacyKey];\n // Compare as strings to handle Convex Id serialization\n return storedId && String(storedId) === legacyIdStr;\n });\n\n if (!found) {\n console.log(\n `[EpistemicSpine] Node not found for ${legacyType}:${legacyIdStr}, searched ${nodes.length} ${nodeType} nodes`\n );\n }\n\n return found?._id ?? null;\n}\n","import type { WithoutSystemFields } from \"convex/server\";\nimport {\n assertUuidV7Identity,\n assertStorageEdgeVocabulary,\n assertCanonicalEdgeEndpoint,\n} from \"@lucern/contracts/ids\";\nimport {\n assertEdgePolicyAllowed,\n edgePolicyManifest,\n type EpistemicNodeType,\n} from \"@lucern/contracts\";\nimport type { Doc, Id, MutationCtx } from \"./convex\";\n\nexport async function insertEpistemicNode(\n ctx: MutationCtx,\n doc: WithoutSystemFields<Doc<\"epistemicNodes\">>,\n): Promise<Id<\"epistemicNodes\">> {\n assertUuidV7Identity(\"epistemicNodes\", doc.globalId);\n return ctx.db.insert(\"epistemicNodes\", doc);\n}\n\nexport async function insertEpistemicEdge(\n ctx: MutationCtx,\n doc: WithoutSystemFields<Doc<\"epistemicEdges\">>,\n): Promise<Id<\"epistemicEdges\">> {\n assertUuidV7Identity(\"epistemicEdges\", doc.globalId);\n\n // R1.1a — STORAGE-VOCABULARY MEMBERSHIP\n assertStorageEdgeVocabulary(doc.edgeType);\n\n // R1.1b — ENDPOINT PRESENCE\n if (!doc.fromNodeId || typeof doc.fromNodeId !== \"string\") {\n throw new Error(\n \"edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId\"\n );\n }\n if (!doc.toNodeId || typeof doc.toNodeId !== \"string\") {\n throw new Error(\n \"edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId\"\n );\n }\n\n // C2-RR.4 Defect E — ENDPOINT CANONICAL IDENTITY. Edge endpoints must be the\n // UUIDv7 globalIds of the connected nodes, never Convex doc ids or legacy\n // topic ids. This refuses the mixed _id/globalId endpoint writes at the floor.\n assertCanonicalEdgeEndpoint(\"fromNodeId\", doc.fromNodeId);\n assertCanonicalEdgeEndpoint(\"toNodeId\", doc.toNodeId);\n\n // R1.1c — FULL POLICY ASSERT (when nodeTypes are present and edgeType is in public manifest)\n if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== \"extracted_from\") {\n assertEdgePolicyAllowed(\n edgePolicyManifest,\n doc.edgeType,\n {\n kind: \"epistemic_node\",\n nodeId: doc.fromNodeId,\n nodeType: doc.fromNodeType as EpistemicNodeType,\n },\n {\n kind: \"epistemic_node\",\n nodeId: doc.toNodeId,\n nodeType: doc.toNodeType as EpistemicNodeType,\n }\n );\n }\n\n return ctx.db.insert(\"epistemicEdges\", doc);\n}\n","/**\n * Epistemic Spine helper module split from epistemicHelpers.ts.\n */\n\nimport type { Id, MutationCtx } from \"./convex\";\nimport { generateGlobalId } from \"./globalId\";\nimport { createEpistemicEdge } from \"./epistemicEdgeCreation\";\nimport { insertEpistemicNode } from \"./epistemicInsert.js\";\n\n// =============================================================================\n// CONTENT HASHING (Convex-compatible sync version)\n// =============================================================================\n\n/**\n * Generate a simple content hash for deduplication\n * Uses a basic hash since crypto.subtle isn't available in Convex runtime\n */\nfunction generateContentHash(nodeType: string, text: string): string {\n const content = `${nodeType}:${normalizeText(text)}`;\n\n // Simple hash function (djb2)\n let hash = 5381;\n for (let i = 0; i < content.length; i++) {\n hash = (hash << 5) + hash + content.charCodeAt(i);\n hash &= hash; // Convert to 32-bit integer\n }\n\n // Convert to hex string and pad to consistent length\n const hashHex = Math.abs(hash).toString(16).padStart(8, \"0\");\n // Add length and checksum for better uniqueness\n const lengthHex = content.length.toString(16).padStart(4, \"0\");\n const checksum = content\n .split(\"\")\n .reduce((a, c) => a + c.charCodeAt(0), 0)\n .toString(16)\n .padStart(8, \"0\");\n\n return `${hashHex}${lengthHex}${checksum}`;\n}\n\n/**\n * Normalize text for consistent hashing\n */\nfunction normalizeText(text: string): string {\n return text.trim().toLowerCase().replace(/\\s+/g, \" \");\n}\n\ntype EpistemicNodeType =\n | \"claim\"\n | \"evidence\"\n | \"synthesis\"\n | \"answer\"\n | \"atomic_fact\"\n | \"excerpt\"\n | \"source\";\n\ntype EpistemicSourceType =\n | \"human\"\n | \"ai_extracted\"\n | \"ai_generated\"\n | \"imported\";\ntype EpistemicVerificationStatus =\n | \"unverified\"\n | \"human_verified\"\n | \"ai_verified\"\n | \"contradicted\"\n | \"outdated\";\n\n/**\n * Map legacy insight sourceType to epistemic sourceType\n */\nfunction mapInsightSourceType(sourceType?: string): EpistemicSourceType {\n switch (sourceType) {\n case \"verified\":\n case \"proprietary\":\n return \"human\";\n case \"ai_generated\":\n return \"ai_generated\";\n default:\n return \"human\";\n }\n}\n\n/**\n * Map legacy verification status to epistemic verification status\n */\nfunction mapVerificationStatus(status?: string): EpistemicVerificationStatus {\n switch (status) {\n case \"manually_verified\":\n return \"human_verified\";\n case \"deep_verified\":\n case \"pre_screened\":\n return \"ai_verified\";\n default:\n return \"unverified\";\n }\n}\n\n// =============================================================================\n// DUAL-WRITE FUNCTIONS\n// =============================================================================\n\n/**\n * Create an epistemic node for an insight (evidence)\n * Called after inserting into the insights table\n */\nexport async function createEpistemicNodeForInsight(\n ctx: MutationCtx,\n _insightId: Id<\"epistemicNodes\">,\n insight: {\n projectId: string;\n text: string;\n kind: string;\n tags?: string[];\n sourceType?: string;\n aiProvider?: string;\n verificationStatus?: string;\n sourceArtifactId?: Id<\"finalArtifacts\">;\n sourceQuestionId?: Id<\"epistemicNodes\">; // If this evidence was created to answer a question\n sourceAnchor?: {\n artifactId: string;\n artifactType: string;\n artifactTitle?: string;\n sectionHeading?: string;\n selectedText?: string;\n startOffset?: number;\n endOffset?: number;\n pageNumber?: number;\n };\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n const contentHash = generateContentHash(\"evidence\", insight.text);\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n updatedAt: now,\n });\n return existing._id;\n }\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType: \"evidence\",\n epistemicLayer: \"L2\", // Evidence is at L2 (compression boundary)\n canonicalText: insight.text,\n contentHash,\n title:\n insight.text.slice(0, 100) + (insight.text.length > 100 ? \"...\" : \"\"),\n tags: insight.tags,\n metadata: {\n kind: insight.kind,\n pillar: insight.tags?.find((t) =>\n [\n \"market\",\n \"competition\",\n \"product\",\n \"team\",\n \"financials\",\n \"regulatory\",\n \"timing\",\n \"customer\",\n \"technology\",\n \"distribution\",\n ].includes(t)\n ),\n // Include sourceArtifactId for source document panel\n sourceArtifactId: insight.sourceArtifactId,\n // Include sourceQuestionId if this evidence was created to answer a question\n sourceQuestionId: insight.sourceQuestionId,\n // Include sourceAnchor for linking evidence back to source documents\n sourceAnchor: insight.sourceAnchor,\n },\n sourceType: mapInsightSourceType(insight.sourceType),\n aiProvider: insight.aiProvider,\n confidence:\n insight.verificationStatus === \"manually_verified\"\n ? 0.9\n : insight.verificationStatus === \"deep_verified\"\n ? 0.7\n : insight.verificationStatus === \"pre_screened\"\n ? 0.5\n : 0.3,\n verificationStatus: mapVerificationStatus(insight.verificationStatus),\n status: \"active\",\n topicId: insight.projectId,\n createdBy: insight.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n // If there's a source artifact, create a derived_from edge\n if (insight.sourceArtifactId) {\n // Find or create the source node\n const sourceNode = await findOrCreateSourceNode(\n ctx,\n insight.sourceArtifactId,\n insight.createdBy,\n insight.projectId\n );\n if (sourceNode) {\n await createEpistemicEdge(ctx, {\n fromNodeId: nodeId,\n toNodeId: sourceNode,\n edgeType: \"derived_from\",\n projectId: insight.projectId,\n createdBy: insight.createdBy,\n });\n }\n }\n\n return nodeId;\n}\n\n/**\n * Create an epistemic node for a belief\n * Called after inserting into the beliefs table\n */\nexport async function createEpistemicNodeForBelief(\n ctx: MutationCtx,\n beliefId: Id<\"epistemicNodes\">,\n belief: {\n projectId: string;\n belief: string;\n rationale?: string;\n confidence: string;\n topic?: string;\n sourceAnchor?: {\n artifactId: string;\n artifactType: string;\n artifactTitle?: string;\n sectionHeading?: string;\n selectedText?: string;\n startOffset?: number;\n endOffset?: number;\n };\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n const contentHash = generateContentHash(\"belief\", belief.belief);\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n metadata: {\n ...((existing.metadata as Record<string, unknown>) || {}),\n sourceBeliefId: beliefId,\n },\n updatedAt: now,\n });\n return existing._id;\n }\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType: \"belief\",\n epistemicLayer: \"L3\", // Beliefs are at L3 (traversal anchors)\n canonicalText: belief.belief,\n contentHash,\n content: belief.rationale,\n title:\n belief.belief.slice(0, 100) + (belief.belief.length > 100 ? \"...\" : \"\"),\n metadata: {\n sourceBeliefId: beliefId,\n beliefStatus: \"assumption\",\n topic: belief.topic, // Use 'topic' for consistency with legacy schema\n pillar: belief.topic, // Keep 'pillar' for backward compat with existing data\n // No confidence/confidenceLevel — only set after sprint completion\n rationale: belief.rationale,\n status: \"active\",\n // Include sourceAnchor for linking beliefs back to source documents\n sourceAnchor: belief.sourceAnchor,\n },\n beliefStatus: \"assumption\" as any,\n epistemicStatus: \"assumption\" as any,\n sourceType: \"human\",\n confidence: undefined, // No confidence until sprint completion\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: belief.projectId,\n createdBy: belief.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n\n/**\n * Create an epistemic node for a question\n * Called after inserting into the questions table\n */\nexport async function createEpistemicNodeForQuestion(\n ctx: MutationCtx,\n _questionId: Id<\"epistemicNodes\">,\n question: {\n projectId: string;\n question: string;\n category?: string;\n priority: string;\n source: string;\n sourceAnchor?: {\n artifactId: string;\n artifactType: string;\n artifactTitle?: string;\n sectionHeading?: string;\n selectedText?: string;\n startOffset?: number;\n endOffset?: number;\n };\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n const contentHash = generateContentHash(\"question\", question.question);\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n updatedAt: now,\n });\n return existing._id;\n }\n\n const sourceType: EpistemicSourceType =\n question.source === \"manual\"\n ? \"human\"\n : question.source === \"ai_suggested\"\n ? \"ai_generated\"\n : \"ai_extracted\";\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType: \"question\",\n epistemicLayer: \"L3\", // Questions are at L3 (traversal anchors)\n canonicalText: question.question,\n contentHash,\n title:\n question.question.slice(0, 100) +\n (question.question.length > 100 ? \"...\" : \"\"),\n metadata: {\n pillar: question.category,\n priority: question.priority,\n source: question.source,\n // Include sourceAnchor for linking questions back to source documents\n sourceAnchor: question.sourceAnchor,\n },\n sourceType,\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: question.projectId,\n createdBy: question.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n\n/**\n * Create an epistemic node for a synthesis artifact (primer or deep research).\n *\n * ⚠️ IMPORTANT: This function should NOT be called for primers/deep research\n * unless the node is being connected to evidence as a source.\n * Standalone synthesis nodes create orphans in the graph.\n *\n * The correct pattern is:\n * 1. Store the artifact in finalArtifacts (for UI display)\n * 2. Only create epistemic node when extracting evidence FROM the artifact\n * 3. Create edge: evidence -> derived_from -> synthesis\n *\n * @deprecated Consider removing automatic node creation for primers.\n * Use the artifact ID reference in evidence metadata instead.\n */\nexport async function createEpistemicNodeForArtifact(\n ctx: MutationCtx,\n artifactId: Id<\"finalArtifacts\">,\n artifact: {\n projectId?: string;\n title: string;\n content: string;\n type: string;\n isDeepResearch?: boolean;\n aiProvider?: string;\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n\n // Determine node type\n let nodeType: EpistemicNodeType = \"source\";\n const isSynthesis =\n artifact.isDeepResearch ||\n artifact.type.includes(\"deep\") ||\n artifact.type.includes(\"research\") ||\n artifact.type.includes(\"primer\");\n\n if (isSynthesis) {\n nodeType = \"synthesis\";\n\n // ⚠️ DO NOT create standalone synthesis nodes\n // Primers/deep research should be stored in finalArtifacts for UI display\n // Epistemic nodes should only be created when:\n // 1. Evidence is extracted FROM the artifact\n // 2. The node is connected via derived_from edge\n console.log(\n `[EpistemicHelpers] Skipping synthesis node creation for \"${artifact.type}\" - ` +\n \"will create when evidence is extracted\"\n );\n\n // Return a placeholder - callers should handle null\n // For backward compatibility, we check for existing node first\n const contentHash = generateContentHash(\n nodeType,\n artifact.title + artifact.content.slice(0, 500)\n );\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n return existing._id; // Return existing node if found\n }\n\n // Don't create new synthesis nodes - they become orphans\n // Throw to signal to callers that no node was created\n throw new Error(\"SKIP_SYNTHESIS_NODE_CREATION\");\n }\n\n const contentHash = generateContentHash(\n nodeType,\n artifact.title + artifact.content.slice(0, 500)\n );\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n metadata: {\n ...((existing.metadata as Record<string, unknown>) || {}),\n legacyArtifactId: artifactId,\n },\n updatedAt: now,\n });\n return existing._id;\n }\n\n // Source artifacts are L1 terminal leaves.\n const epistemicLayer = \"L1\";\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType,\n epistemicLayer, // Synthesis is L2, Source is L1\n canonicalText: artifact.title,\n contentHash,\n content: artifact.content,\n contentType: \"markdown\",\n title: artifact.title,\n metadata: {\n legacyArtifactId: artifactId,\n artifactType: artifact.type,\n },\n sourceType: \"ai_generated\",\n aiProvider:\n artifact.aiProvider || (artifact.isDeepResearch ? \"gemini\" : \"anthropic\"),\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: artifact.projectId,\n createdBy: artifact.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n\n/**\n * Find or create an epistemic node for a source artifact\n */\nasync function findOrCreateSourceNode(\n ctx: MutationCtx,\n artifactId: Id<\"finalArtifacts\">,\n createdBy: string,\n scopeProjectId?: string\n): Promise<Id<\"epistemicNodes\"> | null> {\n // Check if we already have a node for this artifact.\n // Scope by topicId when available; projectId indexes have been removed.\n const artifact = await ctx.db.get(artifactId);\n const effectiveProjectId = scopeProjectId || artifact?.projectId;\n const effectiveTopicId = (artifact as any)?.topicId as string | undefined;\n\n let existingNodes;\n if (effectiveTopicId) {\n existingNodes = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_topic\", (q: any) => q.eq(\"topicId\", effectiveTopicId))\n .collect();\n } else {\n // Last resort: scan by nodeType and filter below.\n existingNodes = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_nodeType\", (q) => q.eq(\"nodeType\", \"source\"))\n .collect();\n }\n\n const existing = existingNodes.find((n) => {\n if (effectiveProjectId && n.projectId && n.projectId !== effectiveProjectId) {\n return false;\n }\n const metadata = n.metadata as Record<string, unknown> | undefined;\n return metadata?.legacyArtifactId === artifactId;\n });\n\n if (existing) {\n return existing._id;\n }\n\n // artifact was already fetched above for scoping; recheck in case it was null\n if (!artifact) {\n return null;\n }\n\n const now = Date.now();\n const globalId = generateGlobalId();\n\n // Determine node type based on artifact metadata\n const artifactType =\n ((artifact.metadata as Record<string, unknown>)?.type as string) || \"\";\n const isDeepResearch = (artifact.metadata as Record<string, unknown>)\n ?.isDeepResearch as boolean;\n\n let nodeType: EpistemicNodeType = \"source\";\n if (\n isDeepResearch ||\n artifactType.includes(\"deep\") ||\n artifactType.includes(\"research\")\n ) {\n nodeType = \"synthesis\";\n } else if (artifactType.includes(\"primer\")) {\n nodeType = \"synthesis\";\n }\n\n const title =\n ((artifact.metadata as Record<string, unknown>)?.title as string) ||\n ((artifact.metadata as Record<string, unknown>)?.theme as string) ||\n \"Untitled\";\n\n const contentHash = generateContentHash(\n nodeType,\n title + (artifact.content?.slice(0, 500) || \"\")\n );\n\n // Determine layer based on nodeType\n const epistemicLayer = nodeType === \"synthesis\" ? \"L2\" : \"L1\";\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType,\n epistemicLayer, // Synthesis is L2, Source is L1\n canonicalText: title,\n contentHash,\n content: artifact.content,\n contentType: \"markdown\",\n title,\n metadata: {\n legacyArtifactId: artifactId,\n artifactType,\n stage: artifact.stage,\n },\n sourceType: isDeepResearch ? \"ai_generated\" : \"ai_extracted\",\n aiProvider: isDeepResearch ? \"gemini\" : \"anthropic\",\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: artifact.projectId,\n createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/convex.ts","../src/epistemicLayerRules.ts","../src/epistemicEdgeCreation.ts","../src/epistemicInsert.ts","../src/epistemicNodeCreation.ts"],"names":["contentHash","existing"],"mappings":"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","file":"epistemicNodeCreation.js","sourcesContent":["import {\n actionGeneric,\n anyApi,\n componentsGeneric,\n httpActionGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n mutationGeneric,\n queryGeneric,\n} from \"convex/server\";\nimport type { GenericId } from \"convex/values\";\n\nexport const api = anyApi as any;\nexport const components = componentsGeneric() as any;\nexport const internal = anyApi as any;\n\nexport type TableNames = string;\nexport type Id<TableName extends TableNames = string> = GenericId<TableName>;\nexport type Doc<TableName extends TableNames = string> = any;\nexport type DataModel = any;\ntype IndexRangeBuilder = {\n field(fieldName: string): string;\n eq(fieldName: string, value: unknown): IndexRangeBuilder;\n gt(fieldName: string, value: unknown): IndexRangeBuilder;\n gte(fieldName: string, value: unknown): IndexRangeBuilder;\n lt(fieldName: string, value: unknown): IndexRangeBuilder;\n lte(fieldName: string, value: unknown): IndexRangeBuilder;\n};\ntype FilterBuilder = {\n eq(left: unknown, right: unknown): unknown;\n neq(left: unknown, right: unknown): unknown;\n gt(left: unknown, right: unknown): unknown;\n gte(left: unknown, right: unknown): unknown;\n lt(left: unknown, right: unknown): unknown;\n lte(left: unknown, right: unknown): unknown;\n and(...clauses: unknown[]): unknown;\n or(...clauses: unknown[]): unknown;\n field(fieldName: string): unknown;\n};\ntype QueryInitializer<TableName extends TableNames> = {\n withIndex(\n indexName: string,\n range?: (q: any) => unknown\n ): QueryInitializer<TableName>;\n filter(predicate: (q: any) => unknown): QueryInitializer<TableName>;\n order(direction: \"asc\" | \"desc\"): QueryInitializer<TableName>;\n collect(): Promise<Doc<TableName>[]>;\n take(limit: number): Promise<Doc<TableName>[]>;\n first(): Promise<Doc<TableName> | null>;\n unique(): Promise<Doc<TableName> | null>;\n};\nexport type DatabaseReader = {\n get<TableName extends TableNames>(\n id: Id<TableName>\n ): Promise<Doc<TableName> | null>;\n query<TableName extends TableNames>(\n tableName: TableName\n ): QueryInitializer<TableName>;\n normalizeId?<TableName extends TableNames>(\n tableName: TableName,\n id: string\n ): Id<TableName> | null;\n};\nexport type DatabaseWriter = DatabaseReader & {\n insert<TableName extends TableNames>(\n tableName: TableName,\n value: Record<string, unknown>\n ): Promise<Id<TableName>>;\n patch<TableName extends TableNames>(\n id: Id<TableName>,\n value: Record<string, unknown>\n ): Promise<void>;\n replace<TableName extends TableNames>(\n id: Id<TableName>,\n value: Record<string, unknown>\n ): Promise<void>;\n delete<TableName extends TableNames>(id: Id<TableName>): Promise<void>;\n};\ntype Scheduler = {\n runAfter(delayMs: number, functionReference: unknown, args?: unknown): Promise<void>;\n};\ntype AuthReader = {\n getUserIdentity(): Promise<unknown>;\n};\ntype RuntimeInvoker = {\n runQuery(functionReference: unknown, args?: unknown): Promise<any>;\n runMutation(functionReference: unknown, args?: unknown): Promise<any>;\n runAction(functionReference: unknown, args?: unknown): Promise<any>;\n};\nexport type QueryCtx = RuntimeInvoker & {\n auth: AuthReader;\n db: DatabaseReader;\n scheduler: Scheduler;\n};\nexport type MutationCtx = RuntimeInvoker & {\n auth: AuthReader;\n db: DatabaseWriter;\n scheduler: Scheduler;\n};\nexport type ActionCtx = RuntimeInvoker & {\n auth: AuthReader;\n scheduler: Scheduler;\n};\n\ntype ConvexFunctionBuilder<Ctx> = <\n Definition extends { handler?: (ctx: Ctx, args: any) => any },\n>(\n definition: Definition\n) => any;\n\nexport const action = actionGeneric as unknown as ConvexFunctionBuilder<ActionCtx>;\nexport const httpAction =\n httpActionGeneric as unknown as ConvexFunctionBuilder<ActionCtx>;\nexport const internalAction =\n internalActionGeneric as unknown as ConvexFunctionBuilder<ActionCtx>;\nexport const internalMutation =\n internalMutationGeneric as unknown as ConvexFunctionBuilder<MutationCtx>;\nexport const internalQuery =\n internalQueryGeneric as unknown as ConvexFunctionBuilder<QueryCtx>;\nexport const mutation =\n mutationGeneric as unknown as ConvexFunctionBuilder<MutationCtx>;\nexport const query = queryGeneric as unknown as ConvexFunctionBuilder<QueryCtx>;\n","/**\n * Epistemic Spine helper module split from epistemicHelpers.ts.\n */\n\nimport type { Id } from \"./convex\";\n\n// =============================================================================\n// TYPE MAPPINGS\n// =============================================================================\n\ntype EpistemicNodeType =\n // L4: Audit targets\n | \"decision\"\n // L3: Traversal anchors\n | \"belief\"\n | \"question\"\n | \"theme\"\n | \"deal\"\n // L2: Compression boundary\n | \"claim\"\n | \"evidence\"\n | \"synthesis\"\n | \"answer\"\n // L1: Terminal leaves\n | \"atomic_fact\"\n | \"excerpt\"\n | \"source\";\n\ntype OntologicalNodeType =\n | \"company\"\n | \"person\"\n | \"investor\"\n | \"function\"\n | \"value_chain\";\n\ntype NodeType = EpistemicNodeType | OntologicalNodeType;\n\n// =============================================================================\n// EPISTEMIC LAYER ARCHITECTURE (Lucern Invariant Compliance)\n// =============================================================================\n\n/**\n * Epistemic Layer - governs traversal rules\n * L4 → L3 → L2 → L1 (never skip layers)\n */\nexport type EpistemicLayer =\n | \"L4\"\n | \"L3\"\n | \"L2\"\n | \"L1\"\n | \"ontological\"\n | \"organizational\";\n\n/**\n * Map nodeType to its epistemic layer\n *\n * Layer semantics:\n * - L4: Audit targets (decisions, outcomes) - what we committed to\n * - L3: Traversal anchors (beliefs, questions, themes) - epistemic structure\n * - L2: Compression boundary (claims, evidence, synthesis) - minimum reasoning unit\n * - L1: Terminal leaves (atomic_fact, excerpt, source) - non-traversable grounding\n * - ontological: Entities in the world (companies, people) - not epistemic\n * - organizational: Structural containers (topics, lenses, worktrees) - not epistemic\n */\nexport function getNodeLayer(nodeType: string): EpistemicLayer {\n switch (nodeType) {\n // L4: Audit targets\n case \"decision\":\n return \"L4\";\n\n // L3: Traversal anchors\n case \"belief\":\n case \"question\":\n case \"theme\":\n case \"deal\":\n return \"L3\";\n\n // L2: Compression boundary\n case \"claim\":\n case \"evidence\":\n case \"synthesis\":\n case \"answer\":\n return \"L2\";\n\n // L1: Terminal leaves\n case \"atomic_fact\":\n case \"excerpt\":\n case \"source\":\n return \"L1\";\n\n // Ontological entities\n case \"company\":\n case \"person\":\n case \"investor\":\n case \"function\":\n case \"value_chain\":\n return \"ontological\";\n\n // Organizational containers\n case \"topic\":\n return \"organizational\";\n\n default:\n // Unknown types default to L2 (safest for traversal)\n console.warn(\n `[EpistemicLayer] Unknown nodeType: ${nodeType}, defaulting to L2`\n );\n return \"L2\";\n }\n}\n\n/**\n * Layer traversal rules\n * Key constraint: Cannot skip layers during traversal\n */\nexport const LAYER_TRAVERSAL_RULES = {\n L4: {\n canReach: [\"L3\", \"L4\"], // Decisions can reach beliefs/questions\n mustPassThrough: \"L3\", // Must go through L3 to reach L2\n },\n L3: {\n canReach: [\"L2\", \"L3\", \"L4\"], // Beliefs can reach evidence, other beliefs, or decisions\n mustPassThrough: \"L2\", // Must go through L2 to reach L1\n },\n L2: {\n canReach: [\"L1\", \"L2\", \"L3\"], // Evidence can reach sources, other evidence, or beliefs\n mustPassThrough: null, // L2 can reach L1 directly\n },\n L1: {\n canReach: [\"L1\"], // Sources can only reach other sources\n mustPassThrough: null, // Terminal - no traversal beyond\n },\n ontological: {\n canReach: [\"L3\", \"L2\", \"ontological\"], // Entities can link to epistemic structure\n mustPassThrough: null, // No layer constraints for entities\n },\n organizational: {\n canReach: [\"L3\", \"L2\", \"organizational\"], // Containers scope epistemic structure + nest\n mustPassThrough: null, // No layer constraints for containers\n },\n} as const;\n\n/**\n * Check if a direct edge between two layers is allowed\n */\nexport function isValidLayerConnection(\n fromLayer: EpistemicLayer,\n toLayer: EpistemicLayer\n): boolean {\n const rules = LAYER_TRAVERSAL_RULES[fromLayer];\n return (rules.canReach as readonly string[]).includes(toLayer);\n}\n\n/**\n * Get layer hierarchy number (for comparison)\n * Higher number = higher layer\n */\nexport function getLayerDepth(layer: EpistemicLayer): number {\n switch (layer) {\n case \"L4\":\n return 4;\n case \"L3\":\n return 3;\n case \"L2\":\n return 2;\n case \"L1\":\n return 1;\n case \"ontological\":\n return 0; // Ontological exists outside the epistemic hierarchy\n case \"organizational\":\n return 0; // Organizational exists outside the epistemic hierarchy\n default:\n return 2;\n }\n}\n\n/**\n * Check if we can traverse from one layer to another\n * (considering intermediate layers)\n */\nexport function canTraverseToLayer(\n fromLayer: EpistemicLayer,\n toLayer: EpistemicLayer\n): boolean {\n const fromDepth = getLayerDepth(fromLayer);\n const toDepth = getLayerDepth(toLayer);\n\n // Ontological/organizational layers are special - use explicit rules\n if (\n fromLayer === \"ontological\" ||\n toLayer === \"ontological\" ||\n fromLayer === \"organizational\" ||\n toLayer === \"organizational\"\n ) {\n return isValidLayerConnection(fromLayer, toLayer);\n }\n\n // Can always stay at same layer\n if (fromDepth === toDepth) {\n return true;\n }\n\n // Can go up (L1→L2→L3→L4) or down (L4→L3→L2→L1)\n // But must respect layer rules\n return isValidLayerConnection(fromLayer, toLayer);\n}\n\n// =============================================================================\n// PHASE 2D: LAYER-AWARE TRAVERSAL\n// =============================================================================\n\n/**\n * Traversal mode - determines how to traverse the graph\n *\n * anchor_down: Start at L3 belief, traverse to L2 evidence, stop at L1 sources\n * anchor_up: Start at L2 evidence, traverse to L3 beliefs it supports\n * same_layer: Traverse within a single layer (e.g., belief → belief)\n * decision_trace: Start at L4 decision, traverse to L3 beliefs it was based on\n */\nexport type TraversalMode =\n | \"anchor_down\"\n | \"anchor_up\"\n | \"same_layer\"\n | \"decision_trace\";\n\n/**\n * Traversal options for layer-aware queries\n */\nexport type TraversalOptions = {\n /** Starting node ID */\n startNodeId: Id<\"epistemicNodes\">;\n /** Traversal mode */\n mode: TraversalMode;\n /** Edge types to follow (empty = all valid for mode) */\n allowedEdgeTypes?: string[];\n /** Maximum depth */\n maxDepth?: number;\n /** Minimum layer to stop at (L1 = 1, L4 = 4) */\n minLayer?: number;\n /** Maximum layer to reach */\n maxLayer?: number;\n};\n\n/**\n * Check if traversal should continue based on layer constraints\n */\nexport function shouldContinueTraversal(\n currentLayer: EpistemicLayer,\n targetLayer: EpistemicLayer,\n options: {\n mode: TraversalMode;\n minLayer?: number;\n maxLayer?: number;\n }\n): boolean {\n const currentDepth = getLayerDepth(currentLayer);\n const targetDepth = getLayerDepth(targetLayer);\n\n // Check min/max layer constraints\n if (options.minLayer !== undefined && targetDepth < options.minLayer) {\n return false; // Would go below minimum layer\n }\n if (options.maxLayer !== undefined && targetDepth > options.maxLayer) {\n return false; // Would go above maximum layer\n }\n\n // Mode-specific rules\n switch (options.mode) {\n case \"anchor_down\":\n // Can only go down (L4→L3→L2→L1)\n return targetDepth < currentDepth || targetDepth === currentDepth;\n\n case \"anchor_up\":\n // Can only go up (L1→L2→L3→L4)\n return targetDepth > currentDepth || targetDepth === currentDepth;\n\n case \"same_layer\":\n // Must stay at same layer\n return targetDepth === currentDepth;\n\n case \"decision_trace\":\n // Decisions (L4) can trace to beliefs (L3), stop there\n return currentDepth === 4\n ? targetDepth === 3\n : targetDepth === currentDepth;\n\n default:\n return true;\n }\n}\n\n/**\n * Get default minLayer for a traversal mode\n */\nexport function getDefaultMinLayer(mode: TraversalMode): number {\n switch (mode) {\n case \"anchor_down\":\n return 1; // Can go all the way to L1 sources\n case \"anchor_up\":\n return 2; // Start at L2 evidence minimum\n case \"same_layer\":\n return 1; // No constraint\n case \"decision_trace\":\n return 3; // Stop at L3 beliefs (don't go to L2 evidence)\n default:\n return 1;\n }\n}\n\n/**\n * Get allowed edge types for a traversal mode\n */\nexport function getDefaultEdgeTypesForMode(mode: TraversalMode): string[] {\n switch (mode) {\n case \"anchor_down\":\n // From beliefs/questions down to evidence and sources\n return [\n \"informs\", // evidence → belief (traverse backwards)\n \"derived_from\", // evidence → source (provenance) + evidence → question\n ];\n case \"anchor_up\":\n // From evidence up to beliefs\n return [\"informs\", \"derived_from\"];\n case \"same_layer\":\n // Within-layer relationships\n return [\n // L3: Belief ↔ Belief\n \"depends_on\",\n \"supports\",\n \"contains\",\n // L3: Question ↔ Question\n \"prerequisite_for\",\n \"parallel_to\",\n // L2: Evidence ↔ Evidence\n \"corroborates\",\n \"extends\",\n \"same_source_as\",\n \"same_theme_as\",\n ];\n case \"decision_trace\":\n // From decisions to beliefs\n return [\n \"derived_from\",\n \"depends_on\",\n \"contains\",\n ];\n default:\n return [];\n }\n}\n\n// =============================================================================\n// PHASE 2C: EDGE LAYER RULES\n// =============================================================================\n\n/**\n * Edge Layer Rules - defines valid layer combinations for each edge type\n *\n * Format: { from: [allowed source layers], to: [allowed target layers] }\n *\n * Key rules:\n * - L4 edges: Decision → L3 (beliefs, questions, themes)\n * - Cross-layer edges: L2 → L3 (evidence informs beliefs)\n * - Same-layer edges: L3 → L3, L2 → L2 (beliefs depend on beliefs)\n * - Downward edges: L2 → L1 (evidence extracted from source)\n * - Lifecycle edges: same layer only (supersedes)\n */\nexport const EDGE_LAYER_RULES: Record<\n string,\n { from: EpistemicLayer[]; to: EpistemicLayer[]; description: string }\n> = {\n // === L4 Decision Edges ===\n based_on_belief: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Belief (L4 → L3)\",\n },\n based_on_question: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Question (L4 → L3)\",\n },\n blocked_by_contradiction: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Contradiction (L4 → L3)\",\n },\n informed_by_theme: {\n from: [\"L4\"],\n to: [\"L3\"],\n description: \"Decision → Theme (L4 → L3)\",\n },\n\n // === Evidence Flow (L2 → L3, L2 → L1) ===\n derived_from: {\n from: [\"L2\", \"L3\", \"L4\"],\n to: [\"L1\", \"L2\", \"L3\"],\n description: \"A was produced from B (provenance chain)\",\n },\n answers: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Evidence → Question (L2 → L3)\",\n },\n responds_to: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Answer → Question (L2 → L3)\",\n },\n informs: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Evidence → Belief (L2 → L3)\",\n },\n qualifies: {\n from: [\"L2\"],\n to: [\"L3\"],\n description: \"Evidence → Belief (L2 → L3)\",\n },\n\n // === Question → Belief (L3 → L3) ===\n tests: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Question → Belief (L3 → L3)\",\n },\n explores: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Question → Belief assumption (L3 → L3)\",\n },\n\n // === Synthesis (L2 → L2, L2 → L1) ===\n based_on: {\n from: [\"L2\"],\n to: [\"L2\", \"L1\"],\n description: \"Synthesis → Evidence/Source (L2 → L2/L1)\",\n },\n\n // === Theme Relationships (L3 → L3) ===\n relates_to_thesis: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Belief → Theme (L3 → L3)\",\n },\n belongs_to: {\n from: [\"L3\", \"L2\"], // Can belong to theme from L3 or L2\n to: [\"L3\"],\n description: \"Any → Theme (L3/L2 → L3)\",\n },\n plays_theme: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Deal → Theme (L3 → L3)\",\n },\n\n // === Topic Hierarchy (L3 → organizational) ===\n scoped_by: {\n from: [\"L3\"],\n to: [\"organizational\"],\n description: \"Belief/Question → Topic (L3 → organizational)\",\n },\n\n // === Deal/Company ===\n evaluates: {\n from: [\"L3\"],\n to: [\"ontological\"],\n description: \"Deal → Company (L3 → ontological)\",\n },\n\n // === People (ontological → ontological, ontological → L3) ===\n perspective_on: {\n from: [\"ontological\"],\n to: [\"L3\"],\n description: \"Person → Belief/Theme (ontological → L3)\",\n },\n works_at: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Person → Company (ontological → ontological)\",\n },\n\n // === Value Chain (ontological) ===\n participates_in: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → ValueChain (ontological → ontological)\",\n },\n performs: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Function (ontological → ontological)\",\n },\n function_in: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Function → ValueChain (ontological → ontological)\",\n },\n impacts: {\n from: [\"L3\"],\n to: [\"ontological\"],\n description: \"Theme → ValueChain (L3 → ontological)\",\n },\n\n // === Investment (ontological) ===\n invested_in: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Investor → Company (ontological → ontological)\",\n },\n raised_from: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Investor (ontological → ontological)\",\n },\n\n // === Entity↔Belief Bridge (OE-B) ===\n about_entity: {\n from: [\"L3\"],\n to: [\"ontological\"],\n description: \"Belief/Question/Theme → Entity (L3 → ontological)\",\n },\n entity_referenced_in: {\n from: [\"ontological\"],\n to: [\"L2\"],\n description: \"Entity → Evidence (ontological → L2)\",\n },\n mentioned_in: {\n from: [\"ontological\"],\n to: [\"L1\"],\n description: \"Entity → Source document (ontological → L1)\",\n },\n founded_by: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Person (ontological → ontological)\",\n },\n competes_with: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"Company → Company (ontological → ontological)\",\n },\n contains: {\n from: [\"ontological\"],\n to: [\"ontological\"],\n description: \"ValueChain → Function (ontological → ontological)\",\n },\n\n // === Lifecycle (same layer only) ===\n supersedes: {\n from: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n to: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n description: \"NewNode → OldNode (same layer only - validated separately)\",\n },\n same_as: {\n from: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n to: [\"L4\", \"L3\", \"L2\", \"L1\", \"ontological\", \"organizational\"],\n description: \"Duplicate detection (same layer only - validated separately)\",\n },\n\n // === Same-Type: Belief ↔ Belief (L3 → L3) ===\n depends_on: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Belief B requires Belief A (L3 → L3)\",\n },\n reinforces: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Beliefs strengthen each other (L3 → L3)\",\n },\n parent_of: {\n from: [\"L3\", \"organizational\"],\n to: [\"L3\", \"organizational\"],\n description:\n \"A is higher-level than B (L3 → L3, organizational → organizational)\",\n },\n child_of: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Belief A is more specific (L3 → L3)\",\n },\n\n // === Same-Type: Question ↔ Question (L3 → L3) ===\n prerequisite_for: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Question A must be answered first (L3 → L3)\",\n },\n parallel_to: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Same topic, different angles (L3 → L3)\",\n },\n\n // === Same-Type: Evidence ↔ Evidence (L2 → L2) ===\n corroborates: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Independent support (L2 → L2)\",\n },\n extends: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Adds depth (L2 → L2)\",\n },\n same_source_as: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Same document/study (L2 → L2)\",\n },\n same_theme_as: {\n from: [\"L2\"],\n to: [\"L2\"],\n description: \"Same topic/entity (L2 → L2)\",\n },\n\n // === NEW: Deep Epistemic Analysis Edges (Phase: Schema Upgrade) ===\n assumes: {\n from: [\"L3\"],\n to: [\"L3\"],\n description:\n \"Hidden dependency - Belief B implicitly assumes Belief A (L3 → L3)\",\n },\n would_predict: {\n from: [\"L3\"],\n to: [\"L2\"],\n description:\n \"Pre-registered prediction - If Belief true, expect Evidence (L3 → L2)\",\n },\n analogous_to: {\n from: [\"L3\"],\n to: [\"L3\"],\n description: \"Explicit analogy - Belief A is like Belief B (L3 → L3)\",\n },\n independent_of: {\n from: [\"L2\"],\n to: [\"L2\"],\n description:\n \"True evidence independence - Evidence A independent of B (L2 → L2)\",\n },\n\n // NOTE: Deprecated edge types (supports, contradicts, derived_from, cites,\n // summarizes, related_to, partially_answers, blocks, refines, branches_from)\n // have been REMOVED from the system. Use compliant alternatives instead.\n};\n\n/**\n * Validate an edge against layer rules\n *\n * Returns { valid: true } or { valid: false, reason: string }\n */\nexport function validateEdgeLayers(\n edgeType: string,\n fromLayer: EpistemicLayer,\n toLayer: EpistemicLayer\n): { valid: boolean; reason?: string } {\n const rules = EDGE_LAYER_RULES[edgeType];\n\n // Unknown edge type - allow but warn\n if (!rules) {\n console.warn(\n `[EdgeValidation] Unknown edge type: ${edgeType}, allowing by default`\n );\n return { valid: true };\n }\n\n // Special handling for same-layer edges (supersedes)\n if (edgeType === \"supersedes\") {\n if (fromLayer !== toLayer) {\n return {\n valid: false,\n reason: `${edgeType} edges must be between nodes of the same layer. Got ${fromLayer} → ${toLayer}`,\n };\n }\n return { valid: true };\n }\n\n // Check from layer\n if (!rules.from.includes(fromLayer)) {\n return {\n valid: false,\n reason: `Edge type '${edgeType}' does not allow source layer ${fromLayer}. Allowed: ${rules.from.join(\", \")}`,\n };\n }\n\n // Check to layer\n if (!rules.to.includes(toLayer)) {\n return {\n valid: false,\n reason: `Edge type '${edgeType}' does not allow target layer ${toLayer}. Allowed: ${rules.to.join(\", \")}`,\n };\n }\n\n return { valid: true };\n}\n\n","/**\n * Epistemic Spine helper module split from epistemicHelpers.ts.\n */\n\nimport { internal } from \"./convex\";\nimport type { Id, MutationCtx } from \"./convex\";\nimport { generateGlobalId } from \"./globalId\";\nimport { getNodeLayer, validateEdgeLayers } from \"./epistemicLayerRules\";\n\ntype NodeTypeIndexQuery = {\n eq(field: string, value: unknown): NodeTypeIndexQuery;\n};\n\n/**\n * Edge type union for createEpistemicEdge\n * Phase 2C: Updated to include L4 edges and modern edge types\n * Phase 3: Added full epistemic impact edges for confidence propagation\n */\ntype EpistemicEdgeType =\n // Canonical edge types (K-tier compliant)\n | \"derived_from\" // replaces: answers, extracted_from, based_on, same_as, based_on_belief, based_on_question\n | \"supports\" // replaces: reinforces, strengthened_by, validated_by, weakened_by, alternative_to, falsified_by, exclusive_with (with appropriate weight)\n | \"contains\" // replaces: parent_of, child_of, about_entity, entity_referenced_in, subsumes, informed_by_theme\n | \"depends_on\" // replaces: collapses_if, cascade_from, required_for, blocks, blocked_by_contradiction\n | \"informs\"\n | \"tests\" // replaces: explores\n | \"responds_to\"\n // Theme relationships\n | \"relates_to_thesis\"\n | \"belongs_to\"\n | \"plays_theme\"\n // Lifecycle\n | \"supersedes\"\n // Same-type: Belief - Cluster Mapping (Thesis Validation Sprints)\n | \"counterfactual_of\"\n | \"cascade_to\"\n | \"mutually_exclusive\"\n | \"correlates_with\"\n | \"amplifies\"\n | \"precondition_for\"\n | \"in_tension_with\"\n // Same-type: Belief - Deep Epistemic Analysis (Tier 2)\n | \"assumes\"\n | \"would_predict\"\n | \"analogous_to\"\n | \"independent_of\"\n // Same-type: Question\n | \"prerequisite_for\"\n | \"parallel_to\"\n // Same-type: Evidence\n | \"corroborates\"\n | \"extends\"\n | \"same_source_as\"\n | \"same_theme_as\"\n // Ontological\n | \"evaluates\"\n | \"perspective_on\"\n | \"works_at\"\n | \"participates_in\"\n | \"performs\"\n | \"function_in\"\n | \"impacts\"\n | \"invested_in\"\n | \"raised_from\"\n // People/Entity References\n | \"mentioned_in\"\n | \"founded_by\"\n | \"competes_with\";\n\n// NOTE: Deprecated edge types have been REMOVED from this type.\n// See schema.ts for the list of removed types and their compliant alternatives.\n\n// =============================================================================\n// CONFIDENCE NORMALIZATION\n// =============================================================================\n\n/**\n * Normalize confidence to a 0-1 number regardless of input format.\n *\n * Handles:\n * - number (0-1): returned as-is\n * - number (1-100): divided by 100\n * - string (\"high\"/\"medium\"/\"low\"): mapped to 0.8/0.5/0.3\n * - undefined/null/other: returns 0.5 default\n *\n * This is the canonical way to read confidence from any source.\n */\nexport function normalizeConfidence(confidence: unknown): number {\n if (typeof confidence === \"number\") {\n return confidence > 1 ? confidence / 100 : confidence;\n }\n if (typeof confidence === \"string\") {\n switch (confidence) {\n case \"high\":\n return 0.8;\n case \"medium\":\n return 0.5;\n case \"low\":\n return 0.3;\n default:\n return 0.5;\n }\n }\n return 0.5;\n}\n\n/**\n * Epistemic Edge Propagation Semantics\n *\n * Each edge type has specific propagation rules for confidence cascades:\n *\n * | Edge Type | Direction | Propagation Rule |\n * |-------------------|--------------|-----------------------------------------------------------|\n * | depends_on | B → A | A.conf = min(A.conf, B.conf + 0.2) |\n * | reinforces | A ↔ B | Both get boost when either validated |\n * | falsified_by | B → A | A.conf = 1 - B.conf (inverse) |\n * | exclusive_with | A ↔ B | A.conf + B.conf ≤ 1.0 (redistribute on evidence) |\n * | contradicts | A ↔ B | Creates tension - neither can be validated without fork |\n * | collapses_if | A → B | If A.conf < threshold, B.conf → 0 |\n * | cascade_from | A → B | B.conf_delta = A.conf_delta * damping_factor |\n * | strengthened_by | A → B | B.conf += A.conf_delta * correlation |\n * | weakened_by | A → B | B.conf -= A.conf_delta * correlation |\n * | alternative_to | A ↔ B | Evidence for A reduces B, and vice versa |\n * | subsumes | A → B | A.conf >= B.conf always |\n * | validated_by | A → B | If A validated, B gains confidence |\n * | required_for | A → B | B cannot be validated until A is validated |\n * | blocks | A → B | B resolution blocked until A resolved |\n */\n\n/**\n * Create an epistemic edge between two nodes\n *\n * Phase 1 (Graph Architecture): Writes to Neo4j directly - Neo4j is source of truth.\n * Returns globalId (string) instead of Convex edge ID.\n *\n * Phase 2C: Validates layer rules before creation\n */\nexport async function createEpistemicEdge(\n ctx: MutationCtx,\n params: {\n fromNodeId: Id<\"epistemicNodes\">;\n toNodeId: Id<\"epistemicNodes\">;\n edgeType: EpistemicEdgeType;\n weight?: number;\n confidence?: number;\n context?: string;\n // NOTE: 'relation' field has been removed. Use 'weight' instead.\n projectId?: string;\n createdBy: string;\n // Phase 2C: Allow skipping validation for migrations\n skipLayerValidation?: boolean;\n }\n): Promise<string> {\n const globalId = generateGlobalId();\n\n // Get node types for denormalization\n const fromNode = await ctx.db.get(params.fromNodeId);\n const toNode = await ctx.db.get(params.toNodeId);\n\n if (!fromNode || !toNode) {\n throw new Error(\"One or both nodes not found\");\n }\n\n // Phase 2C: Get layers (use stored or derive from nodeType)\n const fromLayer = fromNode.epistemicLayer || getNodeLayer(fromNode.nodeType);\n const toLayer = toNode.epistemicLayer || getNodeLayer(toNode.nodeType);\n\n // Phase 2C: Validate layer rules\n if (!params.skipLayerValidation) {\n const validation = validateEdgeLayers(params.edgeType, fromLayer, toLayer);\n if (!validation.valid) {\n throw new Error(\n `[EdgeValidation] Invalid edge: ${validation.reason}. ` +\n `Attempted: ${params.edgeType} from ${fromNode.nodeType}(${fromLayer}) → ${toNode.nodeType}(${toLayer})`\n );\n }\n }\n\n // Phase 1 (Graph Architecture): Write to Neo4j directly - Neo4j is source of truth\n await ctx.scheduler.runAfter(0, internal.neo4jEdgeAPI.createEdge, {\n globalId,\n fromGlobalId: fromNode.globalId,\n toGlobalId: toNode.globalId,\n edgeType: params.edgeType,\n weight: params.weight,\n confidence: params.confidence,\n context: params.context,\n createdBy: params.createdBy,\n topicId: params.projectId ? String(params.projectId) : undefined,\n fromNodeType: fromNode.nodeType,\n toNodeType: toNode.nodeType,\n fromLayer,\n toLayer,\n });\n\n return globalId;\n}\n\n/**\n * Create an edge when linking an insight to a question\n * This creates a \"derived_from\" edge (evidence answers/informs question)\n */\nexport async function createEdgeForInsightQuestionLink(\n ctx: MutationCtx,\n questionId: Id<\"epistemicNodes\">,\n insightId: Id<\"epistemicNodes\">,\n createdBy: string\n): Promise<string | null> {\n console.log(\"[EpistemicSpine] Creating edge for insight-question link:\", {\n questionId: String(questionId),\n insightId: String(insightId),\n });\n\n // Find the epistemic nodes for both entities\n const questionNode = await findNodeByLegacyId(ctx, \"question\", questionId);\n const insightNode = await findNodeByLegacyId(ctx, \"insight\", insightId);\n\n console.log(\"[EpistemicSpine] Found nodes:\", {\n questionNode: questionNode ? String(questionNode) : null,\n insightNode: insightNode ? String(insightNode) : null,\n });\n\n if (!questionNode || !insightNode) {\n // Nodes don't exist yet - this can happen for legacy data\n // They'll be created during backfill\n console.log(\"[EpistemicSpine] Missing nodes, skipping edge creation\");\n return null;\n }\n\n // Get the question for projectId\n const question = await ctx.db.get(questionId);\n const projectId = question?.projectId;\n\n // Create the edge: Evidence -> Question\n // Use \"derived_from\" - canonical replacement for \"answers\" edge type\n return await createEpistemicEdge(ctx, {\n fromNodeId: insightNode,\n toNodeId: questionNode,\n edgeType: \"derived_from\",\n projectId,\n createdBy,\n context: \"Linked from questions workspace\",\n });\n}\n\n/**\n * Find an epistemic node by its legacy ID (stored in metadata)\n */\nasync function findNodeByLegacyId(\n ctx: MutationCtx,\n legacyType: \"insight\" | \"belief\" | \"question\" | \"artifact\",\n legacyId: Id<\"epistemicNodes\"> | Id<\"finalArtifacts\">\n): Promise<Id<\"epistemicNodes\"> | null> {\n // Query all nodes and find the one with matching legacy ID\n // This is not ideal for performance, but works for now\n // TODO: Add a dedicated index for legacy IDs\n const nodeType =\n legacyType === \"insight\"\n ? \"evidence\"\n : legacyType === \"artifact\"\n ? \"source\"\n : legacyType;\n\n const nodes = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_nodeType\", (q: NodeTypeIndexQuery) =>\n q.eq(\"nodeType\", nodeType),\n )\n .collect();\n\n const legacyKey = `legacy${legacyType.charAt(0).toUpperCase() + legacyType.slice(1)}Id`;\n\n // Convert legacyId to string for comparison (Convex Id objects need string comparison)\n const legacyIdStr = String(legacyId);\n\n const found = nodes.find((n) => {\n const metadata = n.metadata as Record<string, unknown> | undefined;\n const storedId = metadata?.[legacyKey];\n // Compare as strings to handle Convex Id serialization\n return storedId && String(storedId) === legacyIdStr;\n });\n\n if (!found) {\n console.log(\n `[EpistemicSpine] Node not found for ${legacyType}:${legacyIdStr}, searched ${nodes.length} ${nodeType} nodes`\n );\n }\n\n return found?._id ?? null;\n}\n","import type { WithoutSystemFields } from \"convex/server\";\nimport {\n assertUuidV7Identity,\n assertStorageEdgeVocabulary,\n assertUuidShapedEdgeEndpoint,\n} from \"@lucern/contracts/ids\";\nimport {\n assertEdgePolicyAllowed,\n edgePolicyManifest,\n type EpistemicNodeType,\n} from \"@lucern/contracts\";\nimport type { Doc, Id, MutationCtx } from \"./convex\";\n\nexport async function insertEpistemicNode(\n ctx: MutationCtx,\n doc: WithoutSystemFields<Doc<\"epistemicNodes\">>,\n): Promise<Id<\"epistemicNodes\">> {\n assertUuidV7Identity(\"epistemicNodes\", doc.globalId);\n return ctx.db.insert(\"epistemicNodes\", doc);\n}\n\n/**\n * C2-RR.4b — REFERENTIAL edge-endpoint canonicality (amends RR.4's FORMAT guard).\n *\n * Proves an endpoint is the `globalId` of an EXISTING `epistemicNodes` row, not\n * that it has a v7 shape. Refuses doc-ids and fabricated/unknown endpoints while\n * keeping legacy v4-`globalId` nodes (the established prod corpus) linkable.\n * SHAPE pre-filter accepts both v4 and v7; the indexed `by_globalId` lookup is\n * the referential authority (no full scan). v7-format stays enforced only at new\n * identity minting (`assertUuidV7Identity`). See c2-rr4b-endpoint-referential.\n */\nasync function assertExistingNodeEndpoint(\n ctx: MutationCtx,\n endpointRole: \"fromNodeId\" | \"toNodeId\",\n endpoint: string,\n): Promise<void> {\n assertUuidShapedEdgeEndpoint(endpointRole, endpoint);\n const node = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_globalId\", (q: any) => q.eq(\"globalId\", endpoint))\n .first();\n if (!node) {\n throw new Error(\n `edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`,\n );\n }\n}\n\nexport async function insertEpistemicEdge(\n ctx: MutationCtx,\n doc: WithoutSystemFields<Doc<\"epistemicEdges\">>,\n): Promise<Id<\"epistemicEdges\">> {\n assertUuidV7Identity(\"epistemicEdges\", doc.globalId);\n\n // R1.1a — STORAGE-VOCABULARY MEMBERSHIP\n assertStorageEdgeVocabulary(doc.edgeType);\n\n // R1.1b — ENDPOINT PRESENCE\n if (!doc.fromNodeId || typeof doc.fromNodeId !== \"string\") {\n throw new Error(\n \"edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId\"\n );\n }\n if (!doc.toNodeId || typeof doc.toNodeId !== \"string\") {\n throw new Error(\n \"edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId\"\n );\n }\n\n // C2-RR.4b Defect E (REFERENTIAL) — ENDPOINT CANONICAL IDENTITY. Edge\n // endpoints must each be the globalId of an EXISTING epistemicNodes row,\n // never a Convex doc id, a legacy topic id, or a fabricated/unknown uuid.\n // This refuses the mixed _id/globalId endpoint writes at the floor while\n // keeping legacy v4-globalId nodes linkable (RR.4b prod-incident cure).\n await assertExistingNodeEndpoint(ctx, \"fromNodeId\", doc.fromNodeId);\n await assertExistingNodeEndpoint(ctx, \"toNodeId\", doc.toNodeId);\n\n // R1.1c — FULL POLICY ASSERT (when nodeTypes are present and edgeType is in public manifest)\n if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== \"extracted_from\") {\n assertEdgePolicyAllowed(\n edgePolicyManifest,\n doc.edgeType,\n {\n kind: \"epistemic_node\",\n nodeId: doc.fromNodeId,\n nodeType: doc.fromNodeType as EpistemicNodeType,\n },\n {\n kind: \"epistemic_node\",\n nodeId: doc.toNodeId,\n nodeType: doc.toNodeType as EpistemicNodeType,\n }\n );\n }\n\n return ctx.db.insert(\"epistemicEdges\", doc);\n}\n","/**\n * Epistemic Spine helper module split from epistemicHelpers.ts.\n */\n\nimport type { Id, MutationCtx } from \"./convex\";\nimport { generateGlobalId } from \"./globalId\";\nimport { createEpistemicEdge } from \"./epistemicEdgeCreation\";\nimport { insertEpistemicNode } from \"./epistemicInsert.js\";\n\n// =============================================================================\n// CONTENT HASHING (Convex-compatible sync version)\n// =============================================================================\n\n/**\n * Generate a simple content hash for deduplication\n * Uses a basic hash since crypto.subtle isn't available in Convex runtime\n */\nfunction generateContentHash(nodeType: string, text: string): string {\n const content = `${nodeType}:${normalizeText(text)}`;\n\n // Simple hash function (djb2)\n let hash = 5381;\n for (let i = 0; i < content.length; i++) {\n hash = (hash << 5) + hash + content.charCodeAt(i);\n hash &= hash; // Convert to 32-bit integer\n }\n\n // Convert to hex string and pad to consistent length\n const hashHex = Math.abs(hash).toString(16).padStart(8, \"0\");\n // Add length and checksum for better uniqueness\n const lengthHex = content.length.toString(16).padStart(4, \"0\");\n const checksum = content\n .split(\"\")\n .reduce((a, c) => a + c.charCodeAt(0), 0)\n .toString(16)\n .padStart(8, \"0\");\n\n return `${hashHex}${lengthHex}${checksum}`;\n}\n\n/**\n * Normalize text for consistent hashing\n */\nfunction normalizeText(text: string): string {\n return text.trim().toLowerCase().replace(/\\s+/g, \" \");\n}\n\ntype EpistemicNodeType =\n | \"claim\"\n | \"evidence\"\n | \"synthesis\"\n | \"answer\"\n | \"atomic_fact\"\n | \"excerpt\"\n | \"source\";\n\ntype EpistemicSourceType =\n | \"human\"\n | \"ai_extracted\"\n | \"ai_generated\"\n | \"imported\";\ntype EpistemicVerificationStatus =\n | \"unverified\"\n | \"human_verified\"\n | \"ai_verified\"\n | \"contradicted\"\n | \"outdated\";\n\n/**\n * Map legacy insight sourceType to epistemic sourceType\n */\nfunction mapInsightSourceType(sourceType?: string): EpistemicSourceType {\n switch (sourceType) {\n case \"verified\":\n case \"proprietary\":\n return \"human\";\n case \"ai_generated\":\n return \"ai_generated\";\n default:\n return \"human\";\n }\n}\n\n/**\n * Map legacy verification status to epistemic verification status\n */\nfunction mapVerificationStatus(status?: string): EpistemicVerificationStatus {\n switch (status) {\n case \"manually_verified\":\n return \"human_verified\";\n case \"deep_verified\":\n case \"pre_screened\":\n return \"ai_verified\";\n default:\n return \"unverified\";\n }\n}\n\n// =============================================================================\n// DUAL-WRITE FUNCTIONS\n// =============================================================================\n\n/**\n * Create an epistemic node for an insight (evidence)\n * Called after inserting into the insights table\n */\nexport async function createEpistemicNodeForInsight(\n ctx: MutationCtx,\n _insightId: Id<\"epistemicNodes\">,\n insight: {\n projectId: string;\n text: string;\n kind: string;\n tags?: string[];\n sourceType?: string;\n aiProvider?: string;\n verificationStatus?: string;\n sourceArtifactId?: Id<\"finalArtifacts\">;\n sourceQuestionId?: Id<\"epistemicNodes\">; // If this evidence was created to answer a question\n sourceAnchor?: {\n artifactId: string;\n artifactType: string;\n artifactTitle?: string;\n sectionHeading?: string;\n selectedText?: string;\n startOffset?: number;\n endOffset?: number;\n pageNumber?: number;\n };\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n const contentHash = generateContentHash(\"evidence\", insight.text);\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n updatedAt: now,\n });\n return existing._id;\n }\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType: \"evidence\",\n epistemicLayer: \"L2\", // Evidence is at L2 (compression boundary)\n canonicalText: insight.text,\n contentHash,\n title:\n insight.text.slice(0, 100) + (insight.text.length > 100 ? \"...\" : \"\"),\n tags: insight.tags,\n metadata: {\n kind: insight.kind,\n pillar: insight.tags?.find((t) =>\n [\n \"market\",\n \"competition\",\n \"product\",\n \"team\",\n \"financials\",\n \"regulatory\",\n \"timing\",\n \"customer\",\n \"technology\",\n \"distribution\",\n ].includes(t)\n ),\n // Include sourceArtifactId for source document panel\n sourceArtifactId: insight.sourceArtifactId,\n // Include sourceQuestionId if this evidence was created to answer a question\n sourceQuestionId: insight.sourceQuestionId,\n // Include sourceAnchor for linking evidence back to source documents\n sourceAnchor: insight.sourceAnchor,\n },\n sourceType: mapInsightSourceType(insight.sourceType),\n aiProvider: insight.aiProvider,\n confidence:\n insight.verificationStatus === \"manually_verified\"\n ? 0.9\n : insight.verificationStatus === \"deep_verified\"\n ? 0.7\n : insight.verificationStatus === \"pre_screened\"\n ? 0.5\n : 0.3,\n verificationStatus: mapVerificationStatus(insight.verificationStatus),\n status: \"active\",\n topicId: insight.projectId,\n createdBy: insight.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n // If there's a source artifact, create a derived_from edge\n if (insight.sourceArtifactId) {\n // Find or create the source node\n const sourceNode = await findOrCreateSourceNode(\n ctx,\n insight.sourceArtifactId,\n insight.createdBy,\n insight.projectId\n );\n if (sourceNode) {\n await createEpistemicEdge(ctx, {\n fromNodeId: nodeId,\n toNodeId: sourceNode,\n edgeType: \"derived_from\",\n projectId: insight.projectId,\n createdBy: insight.createdBy,\n });\n }\n }\n\n return nodeId;\n}\n\n/**\n * Create an epistemic node for a belief\n * Called after inserting into the beliefs table\n */\nexport async function createEpistemicNodeForBelief(\n ctx: MutationCtx,\n beliefId: Id<\"epistemicNodes\">,\n belief: {\n projectId: string;\n belief: string;\n rationale?: string;\n confidence: string;\n topic?: string;\n sourceAnchor?: {\n artifactId: string;\n artifactType: string;\n artifactTitle?: string;\n sectionHeading?: string;\n selectedText?: string;\n startOffset?: number;\n endOffset?: number;\n };\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n const contentHash = generateContentHash(\"belief\", belief.belief);\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n metadata: {\n ...((existing.metadata as Record<string, unknown>) || {}),\n sourceBeliefId: beliefId,\n },\n updatedAt: now,\n });\n return existing._id;\n }\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType: \"belief\",\n epistemicLayer: \"L3\", // Beliefs are at L3 (traversal anchors)\n canonicalText: belief.belief,\n contentHash,\n content: belief.rationale,\n title:\n belief.belief.slice(0, 100) + (belief.belief.length > 100 ? \"...\" : \"\"),\n metadata: {\n sourceBeliefId: beliefId,\n beliefStatus: \"assumption\",\n topic: belief.topic, // Use 'topic' for consistency with legacy schema\n pillar: belief.topic, // Keep 'pillar' for backward compat with existing data\n // No confidence/confidenceLevel — only set after sprint completion\n rationale: belief.rationale,\n status: \"active\",\n // Include sourceAnchor for linking beliefs back to source documents\n sourceAnchor: belief.sourceAnchor,\n },\n beliefStatus: \"assumption\" as any,\n epistemicStatus: \"assumption\" as any,\n sourceType: \"human\",\n confidence: undefined, // No confidence until sprint completion\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: belief.projectId,\n createdBy: belief.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n\n/**\n * Create an epistemic node for a question\n * Called after inserting into the questions table\n */\nexport async function createEpistemicNodeForQuestion(\n ctx: MutationCtx,\n _questionId: Id<\"epistemicNodes\">,\n question: {\n projectId: string;\n question: string;\n category?: string;\n priority: string;\n source: string;\n sourceAnchor?: {\n artifactId: string;\n artifactType: string;\n artifactTitle?: string;\n sectionHeading?: string;\n selectedText?: string;\n startOffset?: number;\n endOffset?: number;\n };\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n const contentHash = generateContentHash(\"question\", question.question);\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n updatedAt: now,\n });\n return existing._id;\n }\n\n const sourceType: EpistemicSourceType =\n question.source === \"manual\"\n ? \"human\"\n : question.source === \"ai_suggested\"\n ? \"ai_generated\"\n : \"ai_extracted\";\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType: \"question\",\n epistemicLayer: \"L3\", // Questions are at L3 (traversal anchors)\n canonicalText: question.question,\n contentHash,\n title:\n question.question.slice(0, 100) +\n (question.question.length > 100 ? \"...\" : \"\"),\n metadata: {\n pillar: question.category,\n priority: question.priority,\n source: question.source,\n // Include sourceAnchor for linking questions back to source documents\n sourceAnchor: question.sourceAnchor,\n },\n sourceType,\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: question.projectId,\n createdBy: question.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n\n/**\n * Create an epistemic node for a synthesis artifact (primer or deep research).\n *\n * ⚠️ IMPORTANT: This function should NOT be called for primers/deep research\n * unless the node is being connected to evidence as a source.\n * Standalone synthesis nodes create orphans in the graph.\n *\n * The correct pattern is:\n * 1. Store the artifact in finalArtifacts (for UI display)\n * 2. Only create epistemic node when extracting evidence FROM the artifact\n * 3. Create edge: evidence -> derived_from -> synthesis\n *\n * @deprecated Consider removing automatic node creation for primers.\n * Use the artifact ID reference in evidence metadata instead.\n */\nexport async function createEpistemicNodeForArtifact(\n ctx: MutationCtx,\n artifactId: Id<\"finalArtifacts\">,\n artifact: {\n projectId?: string;\n title: string;\n content: string;\n type: string;\n isDeepResearch?: boolean;\n aiProvider?: string;\n createdBy: string;\n }\n): Promise<Id<\"epistemicNodes\">> {\n const now = Date.now();\n const globalId = generateGlobalId();\n\n // Determine node type\n let nodeType: EpistemicNodeType = \"source\";\n const isSynthesis =\n artifact.isDeepResearch ||\n artifact.type.includes(\"deep\") ||\n artifact.type.includes(\"research\") ||\n artifact.type.includes(\"primer\");\n\n if (isSynthesis) {\n nodeType = \"synthesis\";\n\n // ⚠️ DO NOT create standalone synthesis nodes\n // Primers/deep research should be stored in finalArtifacts for UI display\n // Epistemic nodes should only be created when:\n // 1. Evidence is extracted FROM the artifact\n // 2. The node is connected via derived_from edge\n console.log(\n `[EpistemicHelpers] Skipping synthesis node creation for \"${artifact.type}\" - ` +\n \"will create when evidence is extracted\"\n );\n\n // Return a placeholder - callers should handle null\n // For backward compatibility, we check for existing node first\n const contentHash = generateContentHash(\n nodeType,\n artifact.title + artifact.content.slice(0, 500)\n );\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n return existing._id; // Return existing node if found\n }\n\n // Don't create new synthesis nodes - they become orphans\n // Throw to signal to callers that no node was created\n throw new Error(\"SKIP_SYNTHESIS_NODE_CREATION\");\n }\n\n const contentHash = generateContentHash(\n nodeType,\n artifact.title + artifact.content.slice(0, 500)\n );\n\n // Check for duplicate\n const existing = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_contentHash\", (q) => q.eq(\"contentHash\", contentHash))\n .first();\n\n if (existing && existing.status === \"active\") {\n await ctx.db.patch(existing._id, {\n metadata: {\n ...((existing.metadata as Record<string, unknown>) || {}),\n legacyArtifactId: artifactId,\n },\n updatedAt: now,\n });\n return existing._id;\n }\n\n // Source artifacts are L1 terminal leaves.\n const epistemicLayer = \"L1\";\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType,\n epistemicLayer, // Synthesis is L2, Source is L1\n canonicalText: artifact.title,\n contentHash,\n content: artifact.content,\n contentType: \"markdown\",\n title: artifact.title,\n metadata: {\n legacyArtifactId: artifactId,\n artifactType: artifact.type,\n },\n sourceType: \"ai_generated\",\n aiProvider:\n artifact.aiProvider || (artifact.isDeepResearch ? \"gemini\" : \"anthropic\"),\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: artifact.projectId,\n createdBy: artifact.createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n\n/**\n * Find or create an epistemic node for a source artifact\n */\nasync function findOrCreateSourceNode(\n ctx: MutationCtx,\n artifactId: Id<\"finalArtifacts\">,\n createdBy: string,\n scopeProjectId?: string\n): Promise<Id<\"epistemicNodes\"> | null> {\n // Check if we already have a node for this artifact.\n // Scope by topicId when available; projectId indexes have been removed.\n const artifact = await ctx.db.get(artifactId);\n const effectiveProjectId = scopeProjectId || artifact?.projectId;\n const effectiveTopicId = (artifact as any)?.topicId as string | undefined;\n\n let existingNodes;\n if (effectiveTopicId) {\n existingNodes = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_topic\", (q: any) => q.eq(\"topicId\", effectiveTopicId))\n .collect();\n } else {\n // Last resort: scan by nodeType and filter below.\n existingNodes = await ctx.db\n .query(\"epistemicNodes\")\n .withIndex(\"by_nodeType\", (q) => q.eq(\"nodeType\", \"source\"))\n .collect();\n }\n\n const existing = existingNodes.find((n) => {\n if (effectiveProjectId && n.projectId && n.projectId !== effectiveProjectId) {\n return false;\n }\n const metadata = n.metadata as Record<string, unknown> | undefined;\n return metadata?.legacyArtifactId === artifactId;\n });\n\n if (existing) {\n return existing._id;\n }\n\n // artifact was already fetched above for scoping; recheck in case it was null\n if (!artifact) {\n return null;\n }\n\n const now = Date.now();\n const globalId = generateGlobalId();\n\n // Determine node type based on artifact metadata\n const artifactType =\n ((artifact.metadata as Record<string, unknown>)?.type as string) || \"\";\n const isDeepResearch = (artifact.metadata as Record<string, unknown>)\n ?.isDeepResearch as boolean;\n\n let nodeType: EpistemicNodeType = \"source\";\n if (\n isDeepResearch ||\n artifactType.includes(\"deep\") ||\n artifactType.includes(\"research\")\n ) {\n nodeType = \"synthesis\";\n } else if (artifactType.includes(\"primer\")) {\n nodeType = \"synthesis\";\n }\n\n const title =\n ((artifact.metadata as Record<string, unknown>)?.title as string) ||\n ((artifact.metadata as Record<string, unknown>)?.theme as string) ||\n \"Untitled\";\n\n const contentHash = generateContentHash(\n nodeType,\n title + (artifact.content?.slice(0, 500) || \"\")\n );\n\n // Determine layer based on nodeType\n const epistemicLayer = nodeType === \"synthesis\" ? \"L2\" : \"L1\";\n\n const nodeId = await insertEpistemicNode(ctx, {\n globalId,\n nodeType,\n epistemicLayer, // Synthesis is L2, Source is L1\n canonicalText: title,\n contentHash,\n content: artifact.content,\n contentType: \"markdown\",\n title,\n metadata: {\n legacyArtifactId: artifactId,\n artifactType,\n stage: artifact.stage,\n },\n sourceType: isDeepResearch ? \"ai_generated\" : \"ai_extracted\",\n aiProvider: isDeepResearch ? \"gemini\" : \"anthropic\",\n verificationStatus: \"unverified\",\n status: \"active\",\n topicId: artifact.projectId,\n createdBy,\n createdAt: now,\n updatedAt: now,\n });\n\n return nodeId;\n}\n"]}
|