@lucern/graph-primitives 1.0.0 → 1.0.2
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/README.md +13 -12
- package/dist/beliefDecay.js +24 -17
- package/dist/beliefDecay.js.map +1 -1
- package/dist/beliefEvidenceLinks.js +32 -8
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/contradictions.js +32 -9
- package/dist/contradictions.js.map +1 -1
- package/dist/convex.d.ts +55 -12
- package/dist/convex.js.map +1 -1
- package/dist/edgeValidation.d.ts +25 -2
- package/dist/edges/index.d.ts +9 -2
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/propagationTypes.d.ts +2 -3
- package/dist/edges/propagationTypes.js.map +1 -1
- package/dist/entityBridge.js +10 -3
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityLifecycle.js +15 -3
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.d.ts +36 -0
- package/dist/epistemicBeliefs.admin.js +745 -0
- package/dist/epistemicBeliefs.admin.js.map +1 -0
- package/dist/epistemicBeliefs.backfills.d.ts +62 -0
- package/dist/epistemicBeliefs.backfills.js +1004 -0
- package/dist/epistemicBeliefs.backfills.js.map +1 -0
- package/dist/epistemicBeliefs.confidence.d.ts +45 -0
- package/dist/epistemicBeliefs.confidence.js +1285 -0
- package/dist/epistemicBeliefs.confidence.js.map +1 -0
- package/dist/epistemicBeliefs.core.d.ts +35 -0
- package/dist/epistemicBeliefs.core.js +1508 -0
- package/dist/epistemicBeliefs.core.js.map +1 -0
- package/dist/epistemicBeliefs.d.ts +12 -3
- package/dist/epistemicBeliefs.helpers.d.ts +168 -0
- package/dist/epistemicBeliefs.helpers.js +1060 -0
- package/dist/epistemicBeliefs.helpers.js.map +1 -0
- package/dist/epistemicBeliefs.internal.d.ts +30 -0
- package/dist/epistemicBeliefs.internal.js +1329 -0
- package/dist/epistemicBeliefs.internal.js.map +1 -0
- package/dist/epistemicBeliefs.js +1196 -1184
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.d.ts +19 -0
- package/dist/epistemicBeliefs.lifecycle.js +1608 -0
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -0
- package/dist/epistemicBeliefs.links.d.ts +30 -0
- package/dist/epistemicBeliefs.links.js +761 -0
- package/dist/epistemicBeliefs.links.js.map +1 -0
- package/dist/epistemicBeliefs.queries.d.ts +16 -0
- package/dist/epistemicBeliefs.queries.js +90 -0
- package/dist/epistemicBeliefs.queries.js.map +1 -0
- package/dist/epistemicContractHelpers.d.ts +1 -1
- package/dist/epistemicContractHelpers.js +1 -1
- package/dist/epistemicContracts.d.ts +5 -76
- package/dist/epistemicContracts.evaluators.d.ts +36 -0
- package/dist/epistemicContracts.evaluators.js +2506 -0
- package/dist/epistemicContracts.evaluators.js.map +1 -0
- package/dist/epistemicContracts.handlers.d.ts +40 -0
- package/dist/epistemicContracts.handlers.js +3029 -0
- package/dist/epistemicContracts.handlers.js.map +1 -0
- package/dist/epistemicContracts.js +2006 -5281
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicContracts.metrics.d.ts +26 -0
- package/dist/epistemicContracts.metrics.js +427 -0
- package/dist/epistemicContracts.metrics.js.map +1 -0
- package/dist/epistemicContracts.types.d.ts +159 -0
- package/dist/epistemicContracts.types.js +3 -0
- package/dist/epistemicContracts.types.js.map +1 -0
- package/dist/epistemicEdgeCreation.d.ts +73 -0
- package/dist/epistemicEdgeCreation.js +450 -0
- package/dist/epistemicEdgeCreation.js.map +1 -0
- package/dist/epistemicEdges-BF-cn4i3.d.ts +43 -0
- package/dist/epistemicEdges.d.ts +8 -1
- package/dist/epistemicEdges.handlers.d.ts +20 -0
- package/dist/epistemicEdges.handlers.js +289 -0
- package/dist/epistemicEdges.handlers.js.map +1 -0
- package/dist/epistemicEdges.helpers.d.ts +27 -0
- package/dist/epistemicEdges.helpers.js +162 -0
- package/dist/epistemicEdges.helpers.js.map +1 -0
- package/dist/epistemicEdges.js +797 -875
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.d.ts +39 -0
- package/dist/epistemicEdges.mutations.js +1365 -0
- package/dist/epistemicEdges.mutations.js.map +1 -0
- package/dist/epistemicEdges.queries.d.ts +95 -0
- package/dist/epistemicEdges.queries.js +851 -0
- package/dist/epistemicEdges.queries.js.map +1 -0
- package/dist/epistemicEdges.types.d.ts +32 -0
- package/dist/epistemicEdges.types.js +3 -0
- package/dist/epistemicEdges.types.js.map +1 -0
- package/dist/epistemicEvidence-DvfchNt7.d.ts +46 -0
- package/dist/epistemicEvidence.d.ts +5 -2
- package/dist/epistemicEvidence.js +801 -807
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +71 -0
- package/dist/epistemicEvidenceHelpers.js +769 -0
- package/dist/epistemicEvidenceHelpers.js.map +1 -0
- package/dist/epistemicEvidenceMutations.d.ts +10 -0
- package/dist/epistemicEvidenceMutations.js +1421 -0
- package/dist/epistemicEvidenceMutations.js.map +1 -0
- package/dist/epistemicEvidenceQueries.d.ts +10 -0
- package/dist/epistemicEvidenceQueries.js +1049 -0
- package/dist/epistemicEvidenceQueries.js.map +1 -0
- package/dist/epistemicHelpers.d.ts +4 -2
- package/dist/epistemicHelpers.js +132 -127
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicLayerRules.d.ts +138 -0
- package/dist/epistemicLayerRules.js +481 -0
- package/dist/epistemicLayerRules.js.map +1 -0
- package/dist/epistemicLinking.js +1 -1
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodeCreation.d.ts +101 -0
- package/dist/epistemicNodeCreation.js +709 -0
- package/dist/epistemicNodeCreation.js.map +1 -0
- package/dist/epistemicNodes-BCQxpYx_.d.ts +54 -0
- package/dist/epistemicNodes.d.ts +5 -1
- package/dist/epistemicNodes.helpers.d.ts +51 -0
- package/dist/epistemicNodes.helpers.js +73 -0
- package/dist/epistemicNodes.helpers.js.map +1 -0
- package/dist/epistemicNodes.internal.d.ts +34 -0
- package/dist/epistemicNodes.internal.js +658 -0
- package/dist/epistemicNodes.internal.js.map +1 -0
- package/dist/epistemicNodes.js +698 -693
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.d.ts +34 -0
- package/dist/epistemicNodes.mutations.js +1153 -0
- package/dist/epistemicNodes.mutations.js.map +1 -0
- package/dist/epistemicNodes.queries.d.ts +36 -0
- package/dist/epistemicNodes.queries.js +619 -0
- package/dist/epistemicNodes.queries.js.map +1 -0
- package/dist/epistemicNodes.validators.d.ts +23 -0
- package/dist/epistemicNodes.validators.js +105 -0
- package/dist/epistemicNodes.validators.js.map +1 -0
- package/dist/epistemicQuestions-bwHd2FWE.d.ts +68 -0
- package/dist/epistemicQuestions.conviction.d.ts +52 -0
- package/dist/epistemicQuestions.conviction.js +1389 -0
- package/dist/epistemicQuestions.conviction.js.map +1 -0
- package/dist/epistemicQuestions.create.d.ts +29 -0
- package/dist/epistemicQuestions.create.js +1300 -0
- package/dist/epistemicQuestions.create.js.map +1 -0
- package/dist/epistemicQuestions.d.ts +10 -2
- package/dist/epistemicQuestions.evidence.d.ts +22 -0
- package/dist/epistemicQuestions.evidence.js +929 -0
- package/dist/epistemicQuestions.evidence.js.map +1 -0
- package/dist/epistemicQuestions.helpers.d.ts +69 -0
- package/dist/epistemicQuestions.helpers.js +824 -0
- package/dist/epistemicQuestions.helpers.js.map +1 -0
- package/dist/epistemicQuestions.js +2435 -2430
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.d.ts +24 -0
- package/dist/epistemicQuestions.lifecycle.js +838 -0
- package/dist/epistemicQuestions.lifecycle.js.map +1 -0
- package/dist/epistemicQuestions.queries.d.ts +41 -0
- package/dist/epistemicQuestions.queries.js +1013 -0
- package/dist/epistemicQuestions.queries.js.map +1 -0
- package/dist/epistemicQuestions.sprint.d.ts +22 -0
- package/dist/epistemicQuestions.sprint.js +757 -0
- package/dist/epistemicQuestions.sprint.js.map +1 -0
- package/dist/epistemicQuestions.tail.d.ts +42 -0
- package/dist/epistemicQuestions.tail.js +1345 -0
- package/dist/epistemicQuestions.tail.js.map +1 -0
- package/dist/epistemicSources.js +6 -2
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.d.ts +2 -2
- package/dist/evaluators/index.js +45 -5320
- package/dist/evaluators/index.js.map +1 -1
- package/dist/evaluators/lintCheckerEvaluator.d.ts +1 -1
- package/dist/evaluators/sentryCheckerEvaluator.d.ts +1 -1
- package/dist/evaluators/testRunnerEvaluator.d.ts +1 -1
- package/dist/evaluators/tscCheckerEvaluator.d.ts +1 -1
- package/dist/{graphTypes-CpgIuCdo.d.ts → graphTypes-B8VaIjnl.d.ts} +1 -1
- package/dist/graphTypes.d.ts +1 -1
- package/dist/{helpers-BYHIk5vU.d.ts → helpers-DNYfg6mo.d.ts} +2 -3
- package/dist/helpers.d.ts +2 -2
- package/dist/helpers.js.map +1 -1
- package/dist/{index-Dq-7R-gi.d.ts → index-C-Kyd7hD.d.ts} +1 -1
- package/dist/index.d.ts +160 -14
- package/dist/index.js +12291 -13001
- package/dist/index.js.map +1 -1
- package/dist/logicalRoleInference.js.map +1 -1
- package/dist/ontologyApproval.js +1 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.js +25 -7
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/questionEvidenceLinks.js +28 -7
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.js.map +1 -1
- package/dist/topicProjectOverlay.js.map +1 -1
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -5
- package/dist/edgeValidation-CeI0wc0r.d.ts +0 -35
- package/dist/epistemicBeliefs-DzKjZAeC.d.ts +0 -377
- package/dist/epistemicEdges-CvlKnEyy.d.ts +0 -191
- package/dist/epistemicEvidence-xw6UUrwh.d.ts +0 -128
- package/dist/epistemicHelpers-DevrYgPN.d.ts +0 -329
- package/dist/epistemicNodes-DjSUfvyD.d.ts +0 -167
- package/dist/epistemicQuestions-B_nUclrH.d.ts +0 -214
- package/dist/index-Dct1T70K.d.ts +0 -25
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
import { v } from 'convex/values';
|
|
2
|
-
import { requireProjectAccess, checkScopeAccess, checkProjectAccess } from '@lucern/access-control/access';
|
|
3
1
|
import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
|
|
4
|
-
import {
|
|
2
|
+
import { componentsGeneric, anyApi, mutationGeneric, internalMutationGeneric, queryGeneric, internalQueryGeneric } from 'convex/server';
|
|
3
|
+
import { v } from 'convex/values';
|
|
4
|
+
import { requireProjectAccess, checkProjectAccess, checkScopeAccess } from '@lucern/access-control/access';
|
|
5
5
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
6
|
-
import { componentsGeneric, anyApi, mutationGeneric, queryGeneric, internalQueryGeneric, internalMutationGeneric } from 'convex/server';
|
|
7
6
|
import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
7
|
+
import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
|
|
8
8
|
|
|
9
|
-
// src/
|
|
10
|
-
var api = anyApi;
|
|
11
|
-
componentsGeneric();
|
|
12
|
-
var internal = anyApi;
|
|
13
|
-
var internalMutation = internalMutationGeneric;
|
|
14
|
-
var internalQuery = internalQueryGeneric;
|
|
15
|
-
var mutation = mutationGeneric;
|
|
16
|
-
var query = queryGeneric;
|
|
9
|
+
// src/epistemicEvidenceHelpers.ts
|
|
17
10
|
|
|
18
11
|
// src/debug.ts
|
|
19
12
|
function isGraphPrimitiveDebugEnabled() {
|
|
@@ -26,47 +19,13 @@ function debugGraphPrimitiveFallback(message, context) {
|
|
|
26
19
|
}
|
|
27
20
|
console.debug(message, context ?? {});
|
|
28
21
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
nodeId: args.nodeId,
|
|
38
|
-
projectId: args.projectId ? String(args.projectId) : void 0,
|
|
39
|
-
topicId: args.topicId ? String(args.topicId) : void 0,
|
|
40
|
-
createdBy: args.createdBy,
|
|
41
|
-
nodeType: args.nodeType,
|
|
42
|
-
text: args.text.slice(0, 2e4),
|
|
43
|
-
hasAnswer: args.hasAnswer,
|
|
44
|
-
confidence: args.confidence
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
} catch (error) {
|
|
48
|
-
debugGraphPrimitiveFallback(
|
|
49
|
-
"[embeddingTrigger] Failed to schedule embedding generation",
|
|
50
|
-
{
|
|
51
|
-
error,
|
|
52
|
-
nodeId: String(args.nodeId),
|
|
53
|
-
nodeType: args.nodeType
|
|
54
|
-
}
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// src/globalId.ts
|
|
60
|
-
function generateGlobalId() {
|
|
61
|
-
const bytes = new Uint8Array(16);
|
|
62
|
-
crypto.getRandomValues(bytes);
|
|
63
|
-
bytes[6] = bytes[6] & 15 | 64;
|
|
64
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
65
|
-
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(
|
|
66
|
-
""
|
|
67
|
-
);
|
|
68
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
69
|
-
}
|
|
22
|
+
var api = anyApi;
|
|
23
|
+
componentsGeneric();
|
|
24
|
+
var internal = anyApi;
|
|
25
|
+
var internalMutation = internalMutationGeneric;
|
|
26
|
+
var internalQuery = internalQueryGeneric;
|
|
27
|
+
var mutation = mutationGeneric;
|
|
28
|
+
var query = queryGeneric;
|
|
70
29
|
|
|
71
30
|
// src/topicProjectOverlay.ts
|
|
72
31
|
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
@@ -617,101 +576,12 @@ var optionalScopeArgs = {
|
|
|
617
576
|
projectId: v.optional(v.string()),
|
|
618
577
|
topicId: v.optional(v.string())
|
|
619
578
|
};
|
|
620
|
-
function normalizeScopeValue2(value) {
|
|
621
|
-
if (typeof value !== "string") {
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
const normalized = value.trim();
|
|
625
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
626
|
-
}
|
|
627
|
-
function throwWorkspaceIsolationError(args) {
|
|
628
|
-
const error = new Error(args.message);
|
|
629
|
-
error.status = 409;
|
|
630
|
-
error.code = "INVARIANT_VIOLATION";
|
|
631
|
-
error.invariantCode = args.invariantCode;
|
|
632
|
-
error.suggestion = args.suggestion;
|
|
633
|
-
error.details = args.details;
|
|
634
|
-
throw error;
|
|
635
|
-
}
|
|
636
|
-
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
637
|
-
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
638
|
-
if (layer === "ontological") {
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
|
|
642
|
-
if (workspaceId) {
|
|
643
|
-
return;
|
|
644
|
-
}
|
|
645
|
-
throwWorkspaceIsolationError({
|
|
646
|
-
message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
|
|
647
|
-
invariantCode: "workspace.scope_required_for_epistemic_nodes",
|
|
648
|
-
suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
|
|
649
|
-
details: {
|
|
650
|
-
mutationName: args.mutationName,
|
|
651
|
-
nodeType: args.nodeType,
|
|
652
|
-
topicId: args.scope.topicId,
|
|
653
|
-
projectId: args.scope.projectId
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
658
|
-
if (!node) {
|
|
659
|
-
return false;
|
|
660
|
-
}
|
|
661
|
-
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
662
|
-
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
663
|
-
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
664
|
-
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
665
|
-
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
666
|
-
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
667
|
-
return false;
|
|
668
|
-
}
|
|
669
|
-
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
670
|
-
return true;
|
|
671
|
-
}
|
|
672
|
-
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
673
|
-
return true;
|
|
674
|
-
}
|
|
675
|
-
if (!scopeWorkspaceId) {
|
|
676
|
-
return nodeWorkspaceId === void 0;
|
|
677
|
-
}
|
|
678
|
-
return scopeWorkspaceId === nodeWorkspaceId;
|
|
679
|
-
}
|
|
680
|
-
function resolveRuntimePackMutationContext(args) {
|
|
681
|
-
if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
return {
|
|
685
|
-
toolName: args.runtimeToolName,
|
|
686
|
-
packKey: args.runtimePackKey,
|
|
687
|
-
packInstallScope: args.runtimePackInstallScope
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
function assertTenantPackWorkspaceMutationAllowed(args) {
|
|
691
|
-
if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
695
|
-
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
696
|
-
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
throwWorkspaceIsolationError({
|
|
700
|
-
message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
|
|
701
|
-
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
702
|
-
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
703
|
-
details: {
|
|
704
|
-
mutationName: args.mutationName,
|
|
705
|
-
toolName: args.runtime.toolName,
|
|
706
|
-
packKey: args.runtime.packKey,
|
|
707
|
-
targetWorkspaceId,
|
|
708
|
-
targetNodeType: args.target.nodeType,
|
|
709
|
-
targetLayer
|
|
710
|
-
}
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
579
|
|
|
714
|
-
// src/
|
|
580
|
+
// src/epistemicEvidenceHelpers.ts
|
|
581
|
+
var optionalEvidenceScopeArgs = optionalScopeArgs;
|
|
582
|
+
var DEFAULT_EVIDENCE_PAGE_SIZE = 250;
|
|
583
|
+
var MAX_EVIDENCE_PAGE_SIZE = 1e3;
|
|
584
|
+
var LEGACY_SPRINT_LINK_KEY = "linkedSprintId";
|
|
715
585
|
function generateContentHash(text) {
|
|
716
586
|
const content = `evidence:${text.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 500)}`;
|
|
717
587
|
let hash = 5381;
|
|
@@ -773,10 +643,6 @@ async function markProjectGraphDirty(ctx, projectId, topicId) {
|
|
|
773
643
|
}
|
|
774
644
|
);
|
|
775
645
|
}
|
|
776
|
-
var DEFAULT_EVIDENCE_PAGE_SIZE = 250;
|
|
777
|
-
var MAX_EVIDENCE_PAGE_SIZE = 1e3;
|
|
778
|
-
var LEGACY_SPRINT_LINK_KEY = "linkedSprintId";
|
|
779
|
-
var optionalEvidenceScopeArgs = optionalScopeArgs;
|
|
780
646
|
function clampEvidenceLimit(limit, fallback = DEFAULT_EVIDENCE_PAGE_SIZE) {
|
|
781
647
|
if (!Number.isFinite(limit)) {
|
|
782
648
|
return fallback;
|
|
@@ -839,7 +705,7 @@ async function getEvidenceNodesForScope(ctx, scope, args) {
|
|
|
839
705
|
).order("desc").take(scanLimit) : ctx.db.query("epistemicNodes").withIndex(
|
|
840
706
|
"by_topic_type",
|
|
841
707
|
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
|
|
842
|
-
).collect());
|
|
708
|
+
).order("desc").collect());
|
|
843
709
|
return dedupeEvidenceNodes(topicNodes).filter(
|
|
844
710
|
(node) => evidenceMatchesScope(node, scope)
|
|
845
711
|
);
|
|
@@ -877,111 +743,572 @@ function flattenEvidenceNode(n) {
|
|
|
877
743
|
externalSourceType: meta.externalSourceType || void 0
|
|
878
744
|
};
|
|
879
745
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
746
|
+
function formatEvidenceNode(n) {
|
|
747
|
+
const metadata = n.metadata || {};
|
|
748
|
+
const linkedWorktreeId = resolveEvidenceLinkedWorktreeId(metadata);
|
|
749
|
+
return {
|
|
750
|
+
_id: n._id,
|
|
751
|
+
_epistemicNodeId: n._id,
|
|
752
|
+
_creationTime: n.createdAt,
|
|
753
|
+
projectId: n.projectId,
|
|
754
|
+
topicId: n.topicId,
|
|
755
|
+
text: n.canonicalText,
|
|
756
|
+
kind: metadata.kind || "observation",
|
|
757
|
+
tags: metadata.tags || [],
|
|
758
|
+
sourceType: n.sourceType,
|
|
759
|
+
externalSourceType: metadata.externalSourceType,
|
|
760
|
+
externalSourceUrl: metadata.sourceUrl,
|
|
761
|
+
sourceArtifactId: metadata.sourceArtifactId,
|
|
762
|
+
sourceQuestionId: metadata.sourceQuestionId,
|
|
763
|
+
linkedWorktreeId,
|
|
764
|
+
[LEGACY_SPRINT_LINK_KEY]: metadata[LEGACY_SPRINT_LINK_KEY] || void 0,
|
|
765
|
+
sourceAnchor: metadata.sourceAnchor,
|
|
766
|
+
aiProvider: metadata.aiProvider,
|
|
767
|
+
verificationStatus: metadata.verificationStatus,
|
|
768
|
+
status: n.status,
|
|
769
|
+
createdBy: n.createdBy,
|
|
770
|
+
createdAt: n.createdAt,
|
|
771
|
+
updatedAt: n.updatedAt
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/embeddingTrigger.ts
|
|
776
|
+
async function scheduleEmbeddingGeneration(args) {
|
|
777
|
+
try {
|
|
778
|
+
await args.ctx.scheduler.runAfter(
|
|
779
|
+
0,
|
|
780
|
+
"embeddingActions:generateEpistemicNodeEmbedding",
|
|
781
|
+
{
|
|
782
|
+
nodeId: args.nodeId,
|
|
783
|
+
projectId: args.projectId ? String(args.projectId) : void 0,
|
|
784
|
+
topicId: args.topicId ? String(args.topicId) : void 0,
|
|
785
|
+
createdBy: args.createdBy,
|
|
786
|
+
nodeType: args.nodeType,
|
|
787
|
+
text: args.text.slice(0, 2e4),
|
|
788
|
+
hasAnswer: args.hasAnswer,
|
|
789
|
+
confidence: args.confidence
|
|
790
|
+
}
|
|
791
|
+
);
|
|
792
|
+
} catch (error) {
|
|
793
|
+
debugGraphPrimitiveFallback(
|
|
794
|
+
"[embeddingTrigger] Failed to schedule embedding generation",
|
|
795
|
+
{
|
|
796
|
+
error,
|
|
797
|
+
nodeId: String(args.nodeId),
|
|
798
|
+
nodeType: args.nodeType
|
|
799
|
+
}
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// src/globalId.ts
|
|
805
|
+
function generateGlobalId() {
|
|
806
|
+
const bytes = new Uint8Array(16);
|
|
807
|
+
crypto.getRandomValues(bytes);
|
|
808
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
809
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
810
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(
|
|
811
|
+
""
|
|
812
|
+
);
|
|
813
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
814
|
+
}
|
|
815
|
+
function normalizeScopeValue2(value) {
|
|
816
|
+
if (typeof value !== "string") {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const normalized = value.trim();
|
|
820
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
821
|
+
}
|
|
822
|
+
function throwWorkspaceIsolationError(args) {
|
|
823
|
+
const error = new Error(args.message);
|
|
824
|
+
error.status = 409;
|
|
825
|
+
error.code = "INVARIANT_VIOLATION";
|
|
826
|
+
error.invariantCode = args.invariantCode;
|
|
827
|
+
error.suggestion = args.suggestion;
|
|
828
|
+
error.details = args.details;
|
|
829
|
+
throw error;
|
|
830
|
+
}
|
|
831
|
+
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
832
|
+
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
833
|
+
if (layer === "ontological") {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
const workspaceId = normalizeScopeValue2(args.scope.workspaceId);
|
|
837
|
+
if (workspaceId) {
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
throwWorkspaceIsolationError({
|
|
841
|
+
message: "Workspace-scoped reasoning isolation requires workspaceId on non-ontological node creation.",
|
|
842
|
+
invariantCode: "workspace.scope_required_for_epistemic_nodes",
|
|
843
|
+
suggestion: "Resolve the topic/project scope through a workspace-bound topic before creating epistemic nodes.",
|
|
844
|
+
details: {
|
|
845
|
+
mutationName: args.mutationName,
|
|
846
|
+
nodeType: args.nodeType,
|
|
847
|
+
topicId: args.scope.topicId,
|
|
848
|
+
projectId: args.scope.projectId
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
853
|
+
if (!node) {
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
const scopeTenantId = normalizeScopeValue2(scope.tenantId);
|
|
857
|
+
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
858
|
+
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
859
|
+
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
860
|
+
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
861
|
+
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
867
|
+
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
868
|
+
return true;
|
|
869
|
+
}
|
|
870
|
+
if (!scopeWorkspaceId) {
|
|
871
|
+
return nodeWorkspaceId === void 0;
|
|
872
|
+
}
|
|
873
|
+
return scopeWorkspaceId === nodeWorkspaceId;
|
|
874
|
+
}
|
|
875
|
+
function resolveRuntimePackMutationContext(args) {
|
|
876
|
+
if (!args.runtimeToolName && !args.runtimePackKey && !args.runtimePackInstallScope) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
return {
|
|
880
|
+
toolName: args.runtimeToolName,
|
|
881
|
+
packKey: args.runtimePackKey,
|
|
882
|
+
packInstallScope: args.runtimePackInstallScope
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function assertTenantPackWorkspaceMutationAllowed(args) {
|
|
886
|
+
if (!args.runtime?.packKey || args.runtime.packInstallScope !== "tenant") {
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
const targetWorkspaceId = normalizeScopeValue2(args.target.workspaceId);
|
|
890
|
+
const targetLayer = typeof args.target.epistemicLayer === "string" ? args.target.epistemicLayer : void 0;
|
|
891
|
+
if (!targetWorkspaceId || targetLayer === "ontological") {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
throwWorkspaceIsolationError({
|
|
895
|
+
message: `Tenant-scoped pack "${args.runtime.packKey}" cannot mutate workspace-scoped reasoning state.`,
|
|
896
|
+
invariantCode: "workspace.tenant_pack_reasoning_write_forbidden",
|
|
897
|
+
suggestion: "Use a workspace-scoped pack for workspace-local graph mutations, or route the change through tenant-global canonical entity flows.",
|
|
898
|
+
details: {
|
|
899
|
+
mutationName: args.mutationName,
|
|
900
|
+
toolName: args.runtime.toolName,
|
|
901
|
+
packKey: args.runtime.packKey,
|
|
902
|
+
targetWorkspaceId,
|
|
903
|
+
targetNodeType: args.target.nodeType,
|
|
904
|
+
targetLayer
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// src/epistemicEvidenceMutations.ts
|
|
910
|
+
var create = mutation({
|
|
911
|
+
args: {
|
|
912
|
+
...optionalEvidenceScopeArgs,
|
|
913
|
+
text: v.string(),
|
|
914
|
+
title: v.optional(v.string()),
|
|
915
|
+
content: v.optional(v.string()),
|
|
916
|
+
contentType: v.optional(v.string()),
|
|
917
|
+
kind: v.optional(v.string()),
|
|
918
|
+
tags: v.optional(v.array(v.string())),
|
|
919
|
+
sourceType: v.optional(v.string()),
|
|
920
|
+
externalSourceType: v.optional(v.string()),
|
|
921
|
+
sourceUrl: v.optional(v.string()),
|
|
922
|
+
sourceQuestionId: v.optional(v.string()),
|
|
923
|
+
userId: v.string(),
|
|
924
|
+
rationale: v.string(),
|
|
925
|
+
// Classification fields (from AI tools)
|
|
926
|
+
methodology: v.optional(v.string()),
|
|
927
|
+
informationAsymmetry: v.optional(v.string()),
|
|
928
|
+
sourceDescription: v.optional(v.string()),
|
|
929
|
+
metadata: v.optional(v.any()),
|
|
930
|
+
// Optional linking to beliefs
|
|
931
|
+
linkedBeliefNodeId: v.optional(v.id("epistemicNodes")),
|
|
932
|
+
evidenceRelation: v.optional(
|
|
933
|
+
v.union(v.literal("supports"), v.literal("contradicts"))
|
|
934
|
+
),
|
|
935
|
+
confidence: v.optional(v.number())
|
|
936
|
+
},
|
|
937
|
+
returns: permissiveReturn,
|
|
938
|
+
handler: async (ctx, args) => {
|
|
939
|
+
const scope = await resolveEvidenceScopeOrNull(ctx, args);
|
|
940
|
+
if (!scope) {
|
|
941
|
+
throw new Error("Invalid scope: projectId or topicId is required");
|
|
942
|
+
}
|
|
943
|
+
assertWorkspaceScopedEpistemicNodeScope({
|
|
944
|
+
scope,
|
|
945
|
+
nodeType: "evidence",
|
|
946
|
+
mutationName: "epistemicEvidence.create"
|
|
947
|
+
});
|
|
948
|
+
if (scope.projectId) {
|
|
949
|
+
await requireProjectAccess(ctx, scope.projectId, args.userId);
|
|
950
|
+
}
|
|
951
|
+
const now = Date.now();
|
|
952
|
+
const globalId = generateGlobalId();
|
|
953
|
+
const contentHash = generateContentHash(args.text);
|
|
954
|
+
const kind = normalizeKind(args.kind);
|
|
955
|
+
const sourceType = normalizeSourceType(args.sourceType);
|
|
956
|
+
const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
|
|
957
|
+
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
958
|
+
globalId,
|
|
959
|
+
topicId: scope.topicId,
|
|
960
|
+
projectId: scope.projectId,
|
|
961
|
+
tenantId: scope.tenantId,
|
|
962
|
+
workspaceId: scope.workspaceId,
|
|
963
|
+
nodeType: "evidence",
|
|
964
|
+
canonicalText: args.text,
|
|
965
|
+
contentHash,
|
|
966
|
+
...typeof args.title === "string" && args.title.trim().length > 0 ? { title: args.title.trim() } : {},
|
|
967
|
+
...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
|
|
968
|
+
...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
|
|
969
|
+
status: "active",
|
|
970
|
+
epistemicLayer: "L2",
|
|
971
|
+
sourceType,
|
|
972
|
+
createdAt: now,
|
|
973
|
+
updatedAt: now,
|
|
974
|
+
createdBy: args.userId,
|
|
975
|
+
metadata: {
|
|
976
|
+
kind,
|
|
977
|
+
tags: args.tags || [],
|
|
978
|
+
externalSourceType: args.externalSourceType,
|
|
979
|
+
sourceUrl: args.sourceUrl,
|
|
980
|
+
sourceQuestionId: args.sourceQuestionId,
|
|
981
|
+
rationale: args.rationale,
|
|
982
|
+
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
983
|
+
evidenceRelation: args.evidenceRelation,
|
|
984
|
+
confidence: args.confidence,
|
|
985
|
+
methodology: args.methodology,
|
|
986
|
+
informationAsymmetry: args.informationAsymmetry,
|
|
987
|
+
sourceDescription: args.sourceDescription,
|
|
988
|
+
...additionalMetadata
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
992
|
+
nodeId,
|
|
993
|
+
operation: "upsert"
|
|
994
|
+
});
|
|
995
|
+
await scheduleEmbeddingGeneration({
|
|
996
|
+
ctx,
|
|
997
|
+
nodeId,
|
|
998
|
+
projectId: scope.projectId,
|
|
999
|
+
topicId: scope.topicId,
|
|
1000
|
+
createdBy: args.userId,
|
|
1001
|
+
nodeType: "evidence",
|
|
1002
|
+
text: args.text
|
|
1003
|
+
});
|
|
1004
|
+
if (args.linkedBeliefNodeId && args.evidenceRelation) {
|
|
1005
|
+
const beliefNode = await ctx.db.get(args.linkedBeliefNodeId);
|
|
1006
|
+
if (beliefNode) {
|
|
1007
|
+
const weight = args.evidenceRelation === "supports" ? 1 : -1;
|
|
1008
|
+
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
1009
|
+
globalId: crypto.randomUUID(),
|
|
1010
|
+
fromGlobalId: globalId,
|
|
1011
|
+
toGlobalId: beliefNode.globalId,
|
|
1012
|
+
edgeType: "informs",
|
|
1013
|
+
weight: weight * (args.confidence || 0.7),
|
|
1014
|
+
createdBy: args.userId,
|
|
1015
|
+
topicId: scope.projectId ? String(scope.projectId) : void 0,
|
|
1016
|
+
fromNodeType: "evidence",
|
|
1017
|
+
toNodeType: "belief",
|
|
1018
|
+
fromLayer: "L2",
|
|
1019
|
+
toLayer: "L3",
|
|
1020
|
+
metadata: {
|
|
1021
|
+
relation: args.evidenceRelation,
|
|
1022
|
+
confidence: args.confidence
|
|
1023
|
+
}
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1028
|
+
entityType: "evidence",
|
|
1029
|
+
entityId: nodeId,
|
|
1030
|
+
changeType: "created",
|
|
1031
|
+
changedAt: now,
|
|
1032
|
+
changedBy: args.userId,
|
|
1033
|
+
isAgent: false,
|
|
1034
|
+
projectId: scope.projectId,
|
|
1035
|
+
rationale: args.rationale,
|
|
1036
|
+
newState: {
|
|
1037
|
+
text: args.text.slice(0, 200),
|
|
1038
|
+
kind,
|
|
1039
|
+
sourceType,
|
|
1040
|
+
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
1041
|
+
evidenceRelation: args.evidenceRelation
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
if (scope.projectId || scope.topicId) {
|
|
1045
|
+
await ctx.scheduler.runAfter(
|
|
1046
|
+
0,
|
|
1047
|
+
"embeddingActions:generateEpistemicNodeEmbedding",
|
|
1048
|
+
{
|
|
1049
|
+
nodeId,
|
|
1050
|
+
projectId: scope.projectId,
|
|
1051
|
+
topicId: scope.topicId ? String(scope.topicId) : void 0,
|
|
1052
|
+
createdBy: args.userId,
|
|
1053
|
+
nodeType: "evidence",
|
|
1054
|
+
text: args.text
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
if (scope.projectId || scope.topicId) {
|
|
1059
|
+
await ctx.scheduler.runAfter(
|
|
1060
|
+
2e3,
|
|
1061
|
+
internal.nodeClassification.scheduleClassification,
|
|
1062
|
+
{
|
|
1063
|
+
nodeId,
|
|
1064
|
+
nodeType: "evidence",
|
|
1065
|
+
projectId: scope.projectId,
|
|
1066
|
+
topicId: String(scope.topicId)
|
|
1067
|
+
}
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
|
|
1071
|
+
return { nodeId };
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
var createAndLink = mutation({
|
|
1075
|
+
args: {
|
|
1076
|
+
...optionalEvidenceScopeArgs,
|
|
1077
|
+
text: v.string(),
|
|
1078
|
+
kind: v.optional(v.string()),
|
|
1079
|
+
tags: v.optional(v.array(v.string())),
|
|
1080
|
+
sourceType: v.optional(v.string()),
|
|
1081
|
+
userId: v.string(),
|
|
1082
|
+
beliefNodeId: v.id("epistemicNodes"),
|
|
1083
|
+
relation: v.union(v.literal("supports"), v.literal("contradicts")),
|
|
1084
|
+
confidence: v.optional(v.number())
|
|
1085
|
+
},
|
|
1086
|
+
returns: permissiveReturn,
|
|
1087
|
+
handler: async (ctx, args) => {
|
|
1088
|
+
const scope = await resolveEvidenceScopeOrNull(ctx, args);
|
|
1089
|
+
if (!scope) {
|
|
1090
|
+
throw new Error("Invalid scope: projectId or topicId is required");
|
|
1091
|
+
}
|
|
1092
|
+
await requireProjectAccess(ctx, String(scope.topicId), args.userId);
|
|
1093
|
+
const now = Date.now();
|
|
1094
|
+
const globalId = generateGlobalId();
|
|
1095
|
+
const contentHash = generateContentHash(args.text);
|
|
1096
|
+
const kind = normalizeKind(args.kind);
|
|
1097
|
+
const sourceType = normalizeSourceType(args.sourceType);
|
|
1098
|
+
const confidence = args.confidence ?? 0.7;
|
|
1099
|
+
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
1100
|
+
globalId,
|
|
1101
|
+
topicId: scope.topicId,
|
|
1102
|
+
projectId: scope.projectId,
|
|
1103
|
+
tenantId: scope.tenantId,
|
|
1104
|
+
workspaceId: scope.workspaceId,
|
|
1105
|
+
nodeType: "evidence",
|
|
1106
|
+
canonicalText: args.text,
|
|
1107
|
+
contentHash,
|
|
1108
|
+
status: "active",
|
|
1109
|
+
epistemicLayer: "L2",
|
|
1110
|
+
sourceType,
|
|
1111
|
+
createdAt: now,
|
|
1112
|
+
updatedAt: now,
|
|
1113
|
+
createdBy: args.userId,
|
|
1114
|
+
metadata: {
|
|
1115
|
+
kind,
|
|
1116
|
+
tags: args.tags || [],
|
|
1117
|
+
linkedBeliefNodeId: args.beliefNodeId,
|
|
1118
|
+
evidenceRelation: args.relation,
|
|
1119
|
+
confidence
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1123
|
+
nodeId,
|
|
1124
|
+
operation: "upsert"
|
|
1125
|
+
});
|
|
1126
|
+
const beliefNode = await ctx.db.get(args.beliefNodeId);
|
|
1127
|
+
if (!beliefNode) {
|
|
1128
|
+
throw new Error("Belief node not found for edge creation");
|
|
1129
|
+
}
|
|
1130
|
+
const weight = args.relation === "supports" ? confidence : -confidence;
|
|
1131
|
+
const edgeGlobalId = crypto.randomUUID();
|
|
1132
|
+
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
1133
|
+
globalId: edgeGlobalId,
|
|
1134
|
+
fromGlobalId: globalId,
|
|
1135
|
+
toGlobalId: beliefNode.globalId,
|
|
1136
|
+
edgeType: "informs",
|
|
1137
|
+
weight,
|
|
1138
|
+
createdBy: args.userId,
|
|
1139
|
+
topicId: scope.projectId,
|
|
1140
|
+
fromNodeType: "evidence",
|
|
1141
|
+
toNodeType: "belief",
|
|
1142
|
+
fromLayer: "L2",
|
|
1143
|
+
toLayer: "L3",
|
|
1144
|
+
metadata: {
|
|
1145
|
+
relation: args.relation,
|
|
1146
|
+
confidence
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
|
|
1150
|
+
return { nodeId, edgeGlobalId };
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
var updateStatus = mutation({
|
|
1154
|
+
args: {
|
|
1155
|
+
nodeId: v.id("epistemicNodes"),
|
|
1156
|
+
status: v.union(
|
|
1157
|
+
v.literal("active"),
|
|
1158
|
+
v.literal("archived"),
|
|
1159
|
+
v.literal("acted_on")
|
|
1160
|
+
),
|
|
1161
|
+
userId: v.string()
|
|
1162
|
+
},
|
|
1163
|
+
returns: permissiveReturn,
|
|
1164
|
+
handler: async (ctx, args) => {
|
|
1165
|
+
const node = await ctx.db.get(args.nodeId);
|
|
1166
|
+
if (!node || node.nodeType !== "evidence") {
|
|
1167
|
+
throw new Error("Evidence not found");
|
|
1168
|
+
}
|
|
1169
|
+
const now = Date.now();
|
|
1170
|
+
await ctx.db.patch(args.nodeId, {
|
|
1171
|
+
status: args.status,
|
|
1172
|
+
updatedAt: now
|
|
1173
|
+
});
|
|
1174
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1175
|
+
entityType: "evidence",
|
|
1176
|
+
entityId: args.nodeId,
|
|
1177
|
+
changeType: "status_changed",
|
|
1178
|
+
changedAt: now,
|
|
1179
|
+
changedBy: args.userId,
|
|
1180
|
+
isAgent: false,
|
|
1181
|
+
projectId: node.projectId,
|
|
1182
|
+
previousState: { status: node.status },
|
|
1183
|
+
newState: { status: args.status }
|
|
1184
|
+
});
|
|
1185
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1186
|
+
nodeId: args.nodeId,
|
|
1187
|
+
operation: "upsert"
|
|
1188
|
+
});
|
|
1189
|
+
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1190
|
+
return { nodeId: args.nodeId };
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1193
|
+
var internalCreate = internalMutation({
|
|
1194
|
+
args: {
|
|
1195
|
+
...optionalEvidenceScopeArgs,
|
|
1196
|
+
text: v.string(),
|
|
1197
|
+
title: v.optional(v.string()),
|
|
1198
|
+
content: v.optional(v.string()),
|
|
1199
|
+
contentType: v.optional(v.string()),
|
|
1200
|
+
kind: v.optional(v.string()),
|
|
1201
|
+
tags: v.optional(v.array(v.string())),
|
|
1202
|
+
sourceType: v.optional(v.string()),
|
|
1203
|
+
externalSourceType: v.optional(v.string()),
|
|
1204
|
+
sourceUrl: v.optional(v.string()),
|
|
1205
|
+
sourceQuestionId: v.optional(v.string()),
|
|
1206
|
+
userId: v.string(),
|
|
1207
|
+
rationale: v.string(),
|
|
1208
|
+
linkedBeliefNodeId: v.optional(v.id("epistemicNodes")),
|
|
1209
|
+
evidenceRelation: v.optional(v.string()),
|
|
1210
|
+
confidence: v.optional(v.number()),
|
|
1211
|
+
metadata: v.optional(v.any()),
|
|
1212
|
+
runtimeToolName: v.optional(v.string()),
|
|
1213
|
+
runtimePackKey: v.optional(v.string()),
|
|
1214
|
+
runtimePackInstallScope: v.optional(
|
|
1215
|
+
v.union(v.literal("tenant"), v.literal("workspace"))
|
|
1216
|
+
)
|
|
1217
|
+
},
|
|
1218
|
+
returns: permissiveReturn,
|
|
1219
|
+
handler: async (ctx, args) => {
|
|
1220
|
+
const now = Date.now();
|
|
1221
|
+
const scope = await resolveEvidenceScopeOrNull(ctx, args);
|
|
1222
|
+
if (!scope) {
|
|
1223
|
+
throw new Error("Invalid scope: projectId or topicId is required");
|
|
1224
|
+
}
|
|
1225
|
+
assertWorkspaceScopedEpistemicNodeScope({
|
|
1226
|
+
scope,
|
|
1227
|
+
nodeType: "evidence",
|
|
1228
|
+
mutationName: "epistemicEvidence.internalCreate"
|
|
1229
|
+
});
|
|
1230
|
+
assertTenantPackWorkspaceMutationAllowed({
|
|
1231
|
+
runtime: resolveRuntimePackMutationContext(args),
|
|
1232
|
+
target: {
|
|
1233
|
+
tenantId: scope.tenantId,
|
|
1234
|
+
workspaceId: scope.workspaceId,
|
|
1235
|
+
nodeType: "evidence",
|
|
1236
|
+
epistemicLayer: "L2"
|
|
1237
|
+
},
|
|
1238
|
+
mutationName: "epistemicEvidence.internalCreate"
|
|
1239
|
+
});
|
|
1240
|
+
const globalId = generateGlobalId();
|
|
1241
|
+
const contentHash = generateContentHash(args.text);
|
|
1242
|
+
const kind = normalizeKind(args.kind);
|
|
1243
|
+
const sourceType = normalizeSourceType(args.sourceType);
|
|
1244
|
+
const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
|
|
1245
|
+
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
1246
|
+
globalId,
|
|
1247
|
+
topicId: scope.topicId,
|
|
1248
|
+
projectId: scope.projectId,
|
|
1249
|
+
tenantId: scope.tenantId,
|
|
1250
|
+
workspaceId: scope.workspaceId,
|
|
1251
|
+
nodeType: "evidence",
|
|
1252
|
+
canonicalText: args.text,
|
|
1253
|
+
contentHash,
|
|
1254
|
+
...typeof args.title === "string" && args.title.trim().length > 0 ? { title: args.title.trim() } : {},
|
|
1255
|
+
...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
|
|
1256
|
+
...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
|
|
1257
|
+
status: "active",
|
|
1258
|
+
epistemicLayer: "L2",
|
|
1259
|
+
sourceType,
|
|
1260
|
+
createdAt: now,
|
|
1261
|
+
updatedAt: now,
|
|
1262
|
+
createdBy: args.userId,
|
|
1263
|
+
metadata: {
|
|
1264
|
+
kind,
|
|
1265
|
+
tags: args.tags || [],
|
|
1266
|
+
externalSourceType: args.externalSourceType,
|
|
1267
|
+
sourceUrl: args.sourceUrl,
|
|
1268
|
+
sourceQuestionId: args.sourceQuestionId,
|
|
1269
|
+
rationale: args.rationale,
|
|
1270
|
+
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
1271
|
+
evidenceRelation: args.evidenceRelation,
|
|
1272
|
+
confidence: args.confidence,
|
|
1273
|
+
...additionalMetadata
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1277
|
+
entityType: "evidence",
|
|
1278
|
+
entityId: String(nodeId),
|
|
1279
|
+
changeType: "created",
|
|
1280
|
+
changedAt: now,
|
|
1281
|
+
changedBy: args.userId,
|
|
1282
|
+
isAgent: false,
|
|
1283
|
+
projectId: scope.projectId,
|
|
1284
|
+
rationale: args.rationale,
|
|
1285
|
+
newState: {
|
|
1286
|
+
text: args.text.slice(0, 200),
|
|
1287
|
+
kind,
|
|
1288
|
+
sourceType,
|
|
1289
|
+
externalSourceType: args.externalSourceType,
|
|
1290
|
+
sourceUrl: args.sourceUrl,
|
|
1291
|
+
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
1292
|
+
evidenceRelation: args.evidenceRelation,
|
|
1293
|
+
confidence: args.confidence
|
|
1294
|
+
},
|
|
1295
|
+
triggeringAction: "epistemicEvidence.internalCreate"
|
|
1296
|
+
});
|
|
1297
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1298
|
+
nodeId,
|
|
1299
|
+
operation: "upsert"
|
|
1300
|
+
});
|
|
1301
|
+
if (args.linkedBeliefNodeId && args.evidenceRelation) {
|
|
1302
|
+
const beliefNode = await ctx.db.get(args.linkedBeliefNodeId);
|
|
977
1303
|
if (beliefNode) {
|
|
978
|
-
const
|
|
1304
|
+
const confidence = args.confidence ?? 0.7;
|
|
1305
|
+
const weight = args.evidenceRelation === "supports" ? confidence : -confidence;
|
|
979
1306
|
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
980
1307
|
globalId: crypto.randomUUID(),
|
|
981
1308
|
fromGlobalId: globalId,
|
|
982
1309
|
toGlobalId: beliefNode.globalId,
|
|
983
1310
|
edgeType: "informs",
|
|
984
|
-
weight
|
|
1311
|
+
weight,
|
|
985
1312
|
createdBy: args.userId,
|
|
986
1313
|
topicId: scope.projectId ? String(scope.projectId) : void 0,
|
|
987
1314
|
fromNodeType: "evidence",
|
|
@@ -990,28 +1317,11 @@ var create = mutation({
|
|
|
990
1317
|
toLayer: "L3",
|
|
991
1318
|
metadata: {
|
|
992
1319
|
relation: args.evidenceRelation,
|
|
993
|
-
confidence
|
|
1320
|
+
confidence
|
|
994
1321
|
}
|
|
995
1322
|
});
|
|
996
1323
|
}
|
|
997
1324
|
}
|
|
998
|
-
await ctx.db.insert("epistemicAudit", {
|
|
999
|
-
entityType: "evidence",
|
|
1000
|
-
entityId: nodeId,
|
|
1001
|
-
changeType: "created",
|
|
1002
|
-
changedAt: now,
|
|
1003
|
-
changedBy: args.userId,
|
|
1004
|
-
isAgent: false,
|
|
1005
|
-
projectId: scope.projectId,
|
|
1006
|
-
rationale: args.rationale,
|
|
1007
|
-
newState: {
|
|
1008
|
-
text: args.text.slice(0, 200),
|
|
1009
|
-
kind,
|
|
1010
|
-
sourceType,
|
|
1011
|
-
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
1012
|
-
evidenceRelation: args.evidenceRelation
|
|
1013
|
-
}
|
|
1014
|
-
});
|
|
1015
1325
|
if (scope.projectId || scope.topicId) {
|
|
1016
1326
|
await ctx.scheduler.runAfter(
|
|
1017
1327
|
0,
|
|
@@ -1026,140 +1336,217 @@ var create = mutation({
|
|
|
1026
1336
|
}
|
|
1027
1337
|
);
|
|
1028
1338
|
}
|
|
1029
|
-
if (scope.projectId || scope.topicId) {
|
|
1030
|
-
await ctx.scheduler.runAfter(
|
|
1031
|
-
2e3,
|
|
1032
|
-
// 2 second delay
|
|
1033
|
-
internal.nodeClassification.scheduleClassification,
|
|
1034
|
-
{
|
|
1035
|
-
nodeId,
|
|
1036
|
-
nodeType: "evidence",
|
|
1037
|
-
projectId: scope.projectId,
|
|
1038
|
-
topicId: String(scope.topicId)
|
|
1039
|
-
}
|
|
1040
|
-
);
|
|
1041
|
-
}
|
|
1042
1339
|
await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
|
|
1043
1340
|
return { nodeId };
|
|
1044
1341
|
}
|
|
1045
1342
|
});
|
|
1046
|
-
var
|
|
1343
|
+
var updateVerificationStatus = mutation({
|
|
1047
1344
|
args: {
|
|
1048
|
-
|
|
1049
|
-
|
|
1345
|
+
nodeId: v.id("epistemicNodes"),
|
|
1346
|
+
verificationHash: v.string(),
|
|
1347
|
+
verificationStatus: v.string(),
|
|
1348
|
+
lastVerificationId: v.optional(v.id("verificationResults"))
|
|
1349
|
+
},
|
|
1350
|
+
returns: permissiveReturn,
|
|
1351
|
+
handler: async (ctx, args) => {
|
|
1352
|
+
const node = await ctx.db.get(args.nodeId);
|
|
1353
|
+
if (!node || node.nodeType !== "evidence") {
|
|
1354
|
+
throw new Error("Evidence node not found");
|
|
1355
|
+
}
|
|
1356
|
+
const metadata = node.metadata || {};
|
|
1357
|
+
await ctx.db.patch(args.nodeId, {
|
|
1358
|
+
metadata: {
|
|
1359
|
+
...metadata,
|
|
1360
|
+
verificationHash: args.verificationHash,
|
|
1361
|
+
verificationStatus: args.verificationStatus,
|
|
1362
|
+
lastVerificationId: args.lastVerificationId
|
|
1363
|
+
}
|
|
1364
|
+
});
|
|
1365
|
+
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1366
|
+
return { success: true };
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
var update = mutation({
|
|
1370
|
+
args: {
|
|
1371
|
+
nodeId: v.optional(v.id("epistemicNodes")),
|
|
1372
|
+
insightId: v.optional(v.string()),
|
|
1373
|
+
text: v.optional(v.string()),
|
|
1050
1374
|
kind: v.optional(v.string()),
|
|
1051
1375
|
tags: v.optional(v.array(v.string())),
|
|
1052
|
-
sourceType: v.optional(v.string()),
|
|
1053
1376
|
userId: v.string(),
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
confidence: v.optional(v.number())
|
|
1377
|
+
externalSourceUrl: v.optional(v.string()),
|
|
1378
|
+
verificationStatus: v.optional(v.string())
|
|
1057
1379
|
},
|
|
1058
1380
|
returns: permissiveReturn,
|
|
1059
1381
|
handler: async (ctx, args) => {
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
}
|
|
1064
|
-
await
|
|
1382
|
+
const resolvedId = args.nodeId ?? args.insightId;
|
|
1383
|
+
if (!resolvedId) {
|
|
1384
|
+
throw new Error("Either nodeId or insightId is required");
|
|
1385
|
+
}
|
|
1386
|
+
const node = await ctx.db.get(resolvedId);
|
|
1387
|
+
if (!node || node.nodeType !== "evidence") {
|
|
1388
|
+
throw new Error("Evidence node not found");
|
|
1389
|
+
}
|
|
1390
|
+
if (!node.projectId) {
|
|
1391
|
+
throw new Error("Evidence has no project scope");
|
|
1392
|
+
}
|
|
1393
|
+
await checkProjectAccess(ctx, node.projectId, args.userId);
|
|
1065
1394
|
const now = Date.now();
|
|
1066
|
-
const
|
|
1067
|
-
const
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
canonicalText: args.text,
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
epistemicLayer: "L2",
|
|
1082
|
-
sourceType,
|
|
1083
|
-
createdAt: now,
|
|
1084
|
-
updatedAt: now,
|
|
1085
|
-
createdBy: args.userId,
|
|
1086
|
-
metadata: {
|
|
1087
|
-
kind,
|
|
1088
|
-
tags: args.tags || [],
|
|
1089
|
-
linkedBeliefNodeId: args.beliefNodeId,
|
|
1090
|
-
evidenceRelation: args.relation,
|
|
1091
|
-
confidence
|
|
1092
|
-
}
|
|
1395
|
+
const existingMeta = node.metadata || {};
|
|
1396
|
+
const metaUpdates = { ...existingMeta };
|
|
1397
|
+
if (args.kind !== void 0) {
|
|
1398
|
+
metaUpdates.kind = args.kind;
|
|
1399
|
+
}
|
|
1400
|
+
if (args.tags !== void 0) {
|
|
1401
|
+
metaUpdates.tags = args.tags;
|
|
1402
|
+
}
|
|
1403
|
+
if (args.externalSourceUrl !== void 0) {
|
|
1404
|
+
metaUpdates.externalSourceUrl = args.externalSourceUrl;
|
|
1405
|
+
}
|
|
1406
|
+
await ctx.db.patch(resolvedId, {
|
|
1407
|
+
canonicalText: args.text ?? node.canonicalText,
|
|
1408
|
+
metadata: metaUpdates,
|
|
1409
|
+
updatedAt: now
|
|
1093
1410
|
});
|
|
1094
1411
|
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1095
|
-
nodeId,
|
|
1412
|
+
nodeId: resolvedId,
|
|
1096
1413
|
operation: "upsert"
|
|
1097
1414
|
});
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
edgeType: "informs",
|
|
1109
|
-
weight,
|
|
1110
|
-
createdBy: args.userId,
|
|
1111
|
-
topicId: scope.projectId,
|
|
1112
|
-
fromNodeType: "evidence",
|
|
1113
|
-
toNodeType: "belief",
|
|
1114
|
-
fromLayer: "L2",
|
|
1115
|
-
toLayer: "L3",
|
|
1116
|
-
metadata: {
|
|
1117
|
-
relation: args.relation,
|
|
1118
|
-
confidence
|
|
1119
|
-
}
|
|
1415
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1416
|
+
entityType: "evidence",
|
|
1417
|
+
entityId: resolvedId,
|
|
1418
|
+
changeType: "updated",
|
|
1419
|
+
changedAt: now,
|
|
1420
|
+
changedBy: args.userId,
|
|
1421
|
+
isAgent: false,
|
|
1422
|
+
projectId: node.projectId,
|
|
1423
|
+
previousState: { text: node.canonicalText?.slice(0, 200) },
|
|
1424
|
+
newState: { text: (args.text ?? node.canonicalText)?.slice(0, 200) }
|
|
1120
1425
|
});
|
|
1121
|
-
|
|
1122
|
-
|
|
1426
|
+
if (args.text !== void 0) {
|
|
1427
|
+
await ctx.scheduler.runAfter(
|
|
1428
|
+
0,
|
|
1429
|
+
"embeddingActions:generateEpistemicNodeEmbedding",
|
|
1430
|
+
{
|
|
1431
|
+
nodeId: resolvedId,
|
|
1432
|
+
topicId: node.projectId,
|
|
1433
|
+
createdBy: node.createdBy,
|
|
1434
|
+
nodeType: "evidence",
|
|
1435
|
+
text: args.text
|
|
1436
|
+
}
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1440
|
+
return { nodeId: resolvedId };
|
|
1123
1441
|
}
|
|
1124
1442
|
});
|
|
1125
|
-
var
|
|
1443
|
+
var flagAsIncorrect = mutation({
|
|
1126
1444
|
args: {
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1445
|
+
insightId: v.id("epistemicNodes"),
|
|
1446
|
+
reason: v.string(),
|
|
1447
|
+
suggestedCorrection: v.optional(v.string()),
|
|
1448
|
+
userId: v.string()
|
|
1449
|
+
},
|
|
1450
|
+
returns: permissiveReturn,
|
|
1451
|
+
handler: async (ctx, args) => {
|
|
1452
|
+
const now = Date.now();
|
|
1453
|
+
const node = await ctx.db.get(args.insightId);
|
|
1454
|
+
if (!node || node.nodeType !== "evidence") {
|
|
1455
|
+
throw new Error("Evidence not found in epistemic spine");
|
|
1456
|
+
}
|
|
1457
|
+
if (!node.projectId) {
|
|
1458
|
+
throw new Error("Evidence has no project scope");
|
|
1459
|
+
}
|
|
1460
|
+
await checkProjectAccess(ctx, node.projectId, args.userId);
|
|
1461
|
+
const existingMeta = node.metadata || {};
|
|
1462
|
+
await ctx.db.patch(node._id, {
|
|
1463
|
+
verificationStatus: "contradicted",
|
|
1464
|
+
metadata: {
|
|
1465
|
+
...existingMeta,
|
|
1466
|
+
contradictionReason: args.reason,
|
|
1467
|
+
suggestedCorrection: args.suggestedCorrection,
|
|
1468
|
+
contradictedBy: args.userId,
|
|
1469
|
+
contradictedAt: now
|
|
1470
|
+
},
|
|
1471
|
+
updatedAt: now
|
|
1472
|
+
});
|
|
1473
|
+
await ctx.db.insert("verificationResults", {
|
|
1474
|
+
targetType: "insight",
|
|
1475
|
+
targetId: node._id,
|
|
1476
|
+
claimText: node.canonicalText || "Evidence text not available",
|
|
1477
|
+
verdict: "contradicted",
|
|
1478
|
+
confidence: 1,
|
|
1479
|
+
sources: [],
|
|
1480
|
+
reasoning: args.reason,
|
|
1481
|
+
suggestedRevision: args.suggestedCorrection,
|
|
1482
|
+
caveats: [],
|
|
1483
|
+
mode: "deep_verify",
|
|
1484
|
+
verifiedAt: now,
|
|
1485
|
+
durationMs: 0,
|
|
1486
|
+
projectId: node.projectId,
|
|
1487
|
+
userId: args.userId
|
|
1488
|
+
});
|
|
1489
|
+
await ctx.db.insert("epistemicAudit", {
|
|
1490
|
+
entityType: "evidence",
|
|
1491
|
+
entityId: node._id,
|
|
1492
|
+
changeType: "updated",
|
|
1493
|
+
changedAt: now,
|
|
1494
|
+
changedBy: args.userId,
|
|
1495
|
+
isAgent: false,
|
|
1496
|
+
projectId: node.projectId,
|
|
1497
|
+
newState: {
|
|
1498
|
+
reason: args.reason,
|
|
1499
|
+
suggestedCorrection: args.suggestedCorrection
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1503
|
+
console.log(
|
|
1504
|
+
`[EpistemicEvidence] Evidence flagged as incorrect by ${args.userId}: "${args.insightId.slice(0, 20)}..."`
|
|
1505
|
+
);
|
|
1506
|
+
return { success: true };
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
var remove = mutation({
|
|
1510
|
+
args: {
|
|
1511
|
+
nodeId: v.optional(v.id("epistemicNodes")),
|
|
1512
|
+
insightId: v.optional(v.string()),
|
|
1133
1513
|
userId: v.string()
|
|
1134
1514
|
},
|
|
1135
1515
|
returns: permissiveReturn,
|
|
1136
1516
|
handler: async (ctx, args) => {
|
|
1137
|
-
const
|
|
1517
|
+
const resolvedId = args.nodeId ?? args.insightId;
|
|
1518
|
+
if (!resolvedId) {
|
|
1519
|
+
throw new Error("Either nodeId or insightId is required");
|
|
1520
|
+
}
|
|
1521
|
+
const node = await ctx.db.get(resolvedId);
|
|
1138
1522
|
if (!node || node.nodeType !== "evidence") {
|
|
1139
|
-
throw new Error("Evidence not found");
|
|
1523
|
+
throw new Error("Evidence node not found");
|
|
1524
|
+
}
|
|
1525
|
+
if (node.createdBy !== args.userId) {
|
|
1526
|
+
throw new Error("Only the creator can archive this evidence");
|
|
1140
1527
|
}
|
|
1141
1528
|
const now = Date.now();
|
|
1142
|
-
await ctx.db.patch(
|
|
1143
|
-
status:
|
|
1529
|
+
await ctx.db.patch(resolvedId, {
|
|
1530
|
+
status: "archived",
|
|
1144
1531
|
updatedAt: now
|
|
1145
1532
|
});
|
|
1533
|
+
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1534
|
+
nodeId: resolvedId,
|
|
1535
|
+
operation: "upsert"
|
|
1536
|
+
});
|
|
1146
1537
|
await ctx.db.insert("epistemicAudit", {
|
|
1147
1538
|
entityType: "evidence",
|
|
1148
|
-
entityId:
|
|
1149
|
-
changeType: "
|
|
1539
|
+
entityId: resolvedId,
|
|
1540
|
+
changeType: "archived",
|
|
1150
1541
|
changedAt: now,
|
|
1151
1542
|
changedBy: args.userId,
|
|
1152
1543
|
isAgent: false,
|
|
1153
1544
|
projectId: node.projectId,
|
|
1154
1545
|
previousState: { status: node.status },
|
|
1155
|
-
newState: { status:
|
|
1156
|
-
});
|
|
1157
|
-
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1158
|
-
nodeId: args.nodeId,
|
|
1159
|
-
operation: "upsert"
|
|
1546
|
+
newState: { status: "archived" }
|
|
1160
1547
|
});
|
|
1161
1548
|
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1162
|
-
return { nodeId:
|
|
1549
|
+
return { nodeId: resolvedId };
|
|
1163
1550
|
}
|
|
1164
1551
|
});
|
|
1165
1552
|
var getById = query({
|
|
@@ -1174,9 +1561,7 @@ var getById = query({
|
|
|
1174
1561
|
if (!id) {
|
|
1175
1562
|
return null;
|
|
1176
1563
|
}
|
|
1177
|
-
const node = await ctx.db.get(
|
|
1178
|
-
id
|
|
1179
|
-
);
|
|
1564
|
+
const node = await ctx.db.get(id);
|
|
1180
1565
|
if (!node || node.nodeType !== "evidence") {
|
|
1181
1566
|
return null;
|
|
1182
1567
|
}
|
|
@@ -1196,7 +1581,7 @@ var getByProject = query({
|
|
|
1196
1581
|
return [];
|
|
1197
1582
|
}
|
|
1198
1583
|
const pageSize = clampEvidenceLimit(args.limit);
|
|
1199
|
-
const scanLimit = Math.min(pageSize * 3,
|
|
1584
|
+
const scanLimit = Math.min(pageSize * 3, 1e3);
|
|
1200
1585
|
let scope;
|
|
1201
1586
|
try {
|
|
1202
1587
|
scope = await resolveTopicProjectScope(ctx, {
|
|
@@ -1245,7 +1630,7 @@ var getByTopic = query({
|
|
|
1245
1630
|
returns: permissiveReturn,
|
|
1246
1631
|
handler: async (ctx, args) => {
|
|
1247
1632
|
const pageSize = clampEvidenceLimit(args.limit);
|
|
1248
|
-
const scanLimit = Math.min(pageSize * 3,
|
|
1633
|
+
const scanLimit = Math.min(pageSize * 3, 1e3);
|
|
1249
1634
|
const scope = await resolveTopicProjectScope(ctx, {
|
|
1250
1635
|
topicId: args.topicId
|
|
1251
1636
|
});
|
|
@@ -1292,7 +1677,7 @@ var internalGetByProject = internalQuery({
|
|
|
1292
1677
|
returns: permissiveReturn,
|
|
1293
1678
|
handler: async (ctx, args) => {
|
|
1294
1679
|
const pageSize = clampEvidenceLimit(args.limit, 500);
|
|
1295
|
-
const scanLimit = Math.min(pageSize * 3,
|
|
1680
|
+
const scanLimit = Math.min(pageSize * 3, 1e3);
|
|
1296
1681
|
const scope = await resolveEvidenceScopeOrNull(ctx, args);
|
|
1297
1682
|
if (!scope) {
|
|
1298
1683
|
return [];
|
|
@@ -1356,264 +1741,58 @@ var internalGetByTopic = internalQuery({
|
|
|
1356
1741
|
returns: permissiveReturn,
|
|
1357
1742
|
handler: async (ctx, args) => {
|
|
1358
1743
|
const pageSize = clampEvidenceLimit(args.limit, 500);
|
|
1359
|
-
const scanLimit = Math.min(pageSize * 3,
|
|
1744
|
+
const scanLimit = Math.min(pageSize * 3, 1e3);
|
|
1360
1745
|
const audienceMode = args.audienceMode ?? "internal";
|
|
1361
1746
|
const scope = await resolveTopicProjectScope(ctx, {
|
|
1362
1747
|
topicId: args.topicId
|
|
1363
1748
|
});
|
|
1364
1749
|
const registryRows = await listAudienceRegistryRows(ctx, {
|
|
1365
|
-
tenantId: scope.tenantId,
|
|
1366
|
-
workspaceId: scope.workspaceId
|
|
1367
|
-
});
|
|
1368
|
-
const resolveAudienceClass = createEvidenceAudienceResolver(registryRows);
|
|
1369
|
-
const viewerClass = resolveAudienceClass(audienceMode, "public");
|
|
1370
|
-
const nodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
1371
|
-
"by_topic_type",
|
|
1372
|
-
(q) => q.eq("topicId", args.topicId).eq("nodeType", "evidence")
|
|
1373
|
-
).order("desc").take(scanLimit);
|
|
1374
|
-
const workspaceScopedNodes = nodes.filter(
|
|
1375
|
-
(node) => nodeMatchesWorkspaceReasoningScope(node, {
|
|
1376
|
-
tenantId: scope.tenantId,
|
|
1377
|
-
workspaceId: scope.workspaceId
|
|
1378
|
-
})
|
|
1379
|
-
);
|
|
1380
|
-
return workspaceScopedNodes.filter(
|
|
1381
|
-
(n) => canAudienceClassAccess(
|
|
1382
|
-
viewerClass,
|
|
1383
|
-
resolveAudienceClass(n.audienceLabel, "internal")
|
|
1384
|
-
) && (!args.status || n.status === args.status)
|
|
1385
|
-
).slice(0, pageSize).map((n) => {
|
|
1386
|
-
const metadata = n.metadata || {};
|
|
1387
|
-
return {
|
|
1388
|
-
_id: n._id,
|
|
1389
|
-
_creationTime: n.createdAt,
|
|
1390
|
-
projectId: n.projectId,
|
|
1391
|
-
topicId: n.topicId,
|
|
1392
|
-
text: n.canonicalText,
|
|
1393
|
-
kind: metadata.kind || "observation",
|
|
1394
|
-
tags: metadata.tags || [],
|
|
1395
|
-
sourceType: n.sourceType,
|
|
1396
|
-
externalSourceType: metadata.externalSourceType,
|
|
1397
|
-
sourceUrl: metadata.sourceUrl,
|
|
1398
|
-
status: n.status,
|
|
1399
|
-
createdBy: n.createdBy,
|
|
1400
|
-
createdAt: n.createdAt,
|
|
1401
|
-
updatedAt: n.updatedAt,
|
|
1402
|
-
audienceLabel: n.audienceLabel,
|
|
1403
|
-
policyTags: n.policyTags,
|
|
1404
|
-
sensitivityTier: n.sensitivityTier,
|
|
1405
|
-
exportClass: n.exportClass,
|
|
1406
|
-
anonymizationClass: n.anonymizationClass
|
|
1407
|
-
};
|
|
1408
|
-
});
|
|
1409
|
-
}
|
|
1410
|
-
});
|
|
1411
|
-
var internalCreate = internalMutation({
|
|
1412
|
-
args: {
|
|
1413
|
-
...optionalEvidenceScopeArgs,
|
|
1414
|
-
text: v.string(),
|
|
1415
|
-
title: v.optional(v.string()),
|
|
1416
|
-
content: v.optional(v.string()),
|
|
1417
|
-
contentType: v.optional(v.string()),
|
|
1418
|
-
kind: v.optional(v.string()),
|
|
1419
|
-
tags: v.optional(v.array(v.string())),
|
|
1420
|
-
sourceType: v.optional(v.string()),
|
|
1421
|
-
externalSourceType: v.optional(v.string()),
|
|
1422
|
-
sourceUrl: v.optional(v.string()),
|
|
1423
|
-
sourceQuestionId: v.optional(v.string()),
|
|
1424
|
-
userId: v.string(),
|
|
1425
|
-
rationale: v.string(),
|
|
1426
|
-
linkedBeliefNodeId: v.optional(v.id("epistemicNodes")),
|
|
1427
|
-
evidenceRelation: v.optional(v.string()),
|
|
1428
|
-
confidence: v.optional(v.number()),
|
|
1429
|
-
/** Optional extra metadata fields merged into the node's metadata object.
|
|
1430
|
-
* Use for domain overlays like coding intelligence (codeAnchors, failedApproach, etc.) */
|
|
1431
|
-
metadata: v.optional(v.any()),
|
|
1432
|
-
runtimeToolName: v.optional(v.string()),
|
|
1433
|
-
runtimePackKey: v.optional(v.string()),
|
|
1434
|
-
runtimePackInstallScope: v.optional(
|
|
1435
|
-
v.union(v.literal("tenant"), v.literal("workspace"))
|
|
1436
|
-
)
|
|
1437
|
-
},
|
|
1438
|
-
returns: permissiveReturn,
|
|
1439
|
-
handler: async (ctx, args) => {
|
|
1440
|
-
const now = Date.now();
|
|
1441
|
-
const scope = await resolveTopicProjectScope(ctx, {
|
|
1442
|
-
topicId: args.topicId,
|
|
1443
|
-
projectId: args.projectId
|
|
1444
|
-
});
|
|
1445
|
-
assertWorkspaceScopedEpistemicNodeScope({
|
|
1446
|
-
scope,
|
|
1447
|
-
nodeType: "evidence",
|
|
1448
|
-
mutationName: "epistemicEvidence.internalCreate"
|
|
1449
|
-
});
|
|
1450
|
-
assertTenantPackWorkspaceMutationAllowed({
|
|
1451
|
-
runtime: resolveRuntimePackMutationContext(args),
|
|
1452
|
-
target: {
|
|
1453
|
-
tenantId: scope.tenantId,
|
|
1454
|
-
workspaceId: scope.workspaceId,
|
|
1455
|
-
nodeType: "evidence",
|
|
1456
|
-
epistemicLayer: "L2"
|
|
1457
|
-
},
|
|
1458
|
-
mutationName: "epistemicEvidence.internalCreate"
|
|
1459
|
-
});
|
|
1460
|
-
const globalId = generateGlobalId();
|
|
1461
|
-
const contentHash = generateContentHash(args.text);
|
|
1462
|
-
const kind = normalizeKind(args.kind);
|
|
1463
|
-
const sourceType = normalizeSourceType(args.sourceType);
|
|
1464
|
-
const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
|
|
1465
|
-
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
1466
|
-
globalId,
|
|
1467
|
-
topicId: scope.topicId,
|
|
1468
|
-
projectId: scope.projectId,
|
|
1469
|
-
tenantId: scope.tenantId,
|
|
1470
|
-
workspaceId: scope.workspaceId,
|
|
1471
|
-
nodeType: "evidence",
|
|
1472
|
-
canonicalText: args.text,
|
|
1473
|
-
contentHash,
|
|
1474
|
-
...typeof args.title === "string" && args.title.trim().length > 0 ? { title: args.title.trim() } : {},
|
|
1475
|
-
...typeof args.content === "string" && args.content.length > 0 ? { content: args.content } : {},
|
|
1476
|
-
...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
|
|
1477
|
-
status: "active",
|
|
1478
|
-
epistemicLayer: "L2",
|
|
1479
|
-
sourceType,
|
|
1480
|
-
createdAt: now,
|
|
1481
|
-
updatedAt: now,
|
|
1482
|
-
createdBy: args.userId,
|
|
1483
|
-
metadata: {
|
|
1484
|
-
kind,
|
|
1485
|
-
tags: args.tags || [],
|
|
1486
|
-
externalSourceType: args.externalSourceType,
|
|
1487
|
-
sourceUrl: args.sourceUrl,
|
|
1488
|
-
sourceQuestionId: args.sourceQuestionId,
|
|
1489
|
-
rationale: args.rationale,
|
|
1490
|
-
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
1491
|
-
evidenceRelation: args.evidenceRelation,
|
|
1492
|
-
confidence: args.confidence,
|
|
1493
|
-
...additionalMetadata
|
|
1494
|
-
}
|
|
1495
|
-
});
|
|
1496
|
-
await ctx.db.insert("epistemicAudit", {
|
|
1497
|
-
entityType: "evidence",
|
|
1498
|
-
entityId: String(nodeId),
|
|
1499
|
-
changeType: "created",
|
|
1500
|
-
changedAt: now,
|
|
1501
|
-
changedBy: args.userId,
|
|
1502
|
-
isAgent: false,
|
|
1503
|
-
projectId: scope.projectId,
|
|
1504
|
-
rationale: args.rationale,
|
|
1505
|
-
newState: {
|
|
1506
|
-
text: args.text.slice(0, 200),
|
|
1507
|
-
kind,
|
|
1508
|
-
sourceType,
|
|
1509
|
-
externalSourceType: args.externalSourceType,
|
|
1510
|
-
sourceUrl: args.sourceUrl,
|
|
1511
|
-
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
1512
|
-
evidenceRelation: args.evidenceRelation,
|
|
1513
|
-
confidence: args.confidence
|
|
1514
|
-
},
|
|
1515
|
-
triggeringAction: "epistemicEvidence.internalCreate"
|
|
1516
|
-
});
|
|
1517
|
-
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1518
|
-
nodeId,
|
|
1519
|
-
operation: "upsert"
|
|
1520
|
-
});
|
|
1521
|
-
if (args.linkedBeliefNodeId && args.evidenceRelation) {
|
|
1522
|
-
const beliefNode = await ctx.db.get(args.linkedBeliefNodeId);
|
|
1523
|
-
if (beliefNode) {
|
|
1524
|
-
const confidence = args.confidence ?? 0.7;
|
|
1525
|
-
const weight = args.evidenceRelation === "supports" ? confidence : -confidence;
|
|
1526
|
-
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
1527
|
-
globalId: crypto.randomUUID(),
|
|
1528
|
-
fromGlobalId: globalId,
|
|
1529
|
-
toGlobalId: beliefNode.globalId,
|
|
1530
|
-
edgeType: "informs",
|
|
1531
|
-
weight,
|
|
1532
|
-
createdBy: args.userId,
|
|
1533
|
-
topicId: scope.projectId ? String(scope.projectId) : void 0,
|
|
1534
|
-
fromNodeType: "evidence",
|
|
1535
|
-
toNodeType: "belief",
|
|
1536
|
-
fromLayer: "L2",
|
|
1537
|
-
toLayer: "L3",
|
|
1538
|
-
metadata: {
|
|
1539
|
-
relation: args.evidenceRelation,
|
|
1540
|
-
confidence
|
|
1541
|
-
}
|
|
1542
|
-
});
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
if (scope.projectId || scope.topicId) {
|
|
1546
|
-
await ctx.scheduler.runAfter(
|
|
1547
|
-
0,
|
|
1548
|
-
"embeddingActions:generateEpistemicNodeEmbedding",
|
|
1549
|
-
{
|
|
1550
|
-
nodeId,
|
|
1551
|
-
projectId: scope.projectId,
|
|
1552
|
-
topicId: scope.topicId ? String(scope.topicId) : void 0,
|
|
1553
|
-
createdBy: args.userId,
|
|
1554
|
-
nodeType: "evidence",
|
|
1555
|
-
text: args.text
|
|
1556
|
-
}
|
|
1557
|
-
);
|
|
1558
|
-
}
|
|
1559
|
-
await markProjectGraphDirty(ctx, scope.projectId, String(scope.topicId));
|
|
1560
|
-
return { nodeId };
|
|
1561
|
-
}
|
|
1562
|
-
});
|
|
1563
|
-
var updateVerificationStatus = mutation({
|
|
1564
|
-
args: {
|
|
1565
|
-
nodeId: v.id("epistemicNodes"),
|
|
1566
|
-
verificationHash: v.string(),
|
|
1567
|
-
verificationStatus: v.string(),
|
|
1568
|
-
lastVerificationId: v.optional(v.id("verificationResults"))
|
|
1569
|
-
},
|
|
1570
|
-
returns: permissiveReturn,
|
|
1571
|
-
handler: async (ctx, args) => {
|
|
1572
|
-
const node = await ctx.db.get(args.nodeId);
|
|
1573
|
-
if (!node || node.nodeType !== "evidence") {
|
|
1574
|
-
throw new Error("Evidence node not found");
|
|
1575
|
-
}
|
|
1576
|
-
const metadata = node.metadata || {};
|
|
1577
|
-
await ctx.db.patch(args.nodeId, {
|
|
1578
|
-
metadata: {
|
|
1579
|
-
...metadata,
|
|
1580
|
-
verificationHash: args.verificationHash,
|
|
1581
|
-
verificationStatus: args.verificationStatus,
|
|
1582
|
-
lastVerificationId: args.lastVerificationId
|
|
1583
|
-
}
|
|
1750
|
+
tenantId: scope.tenantId,
|
|
1751
|
+
workspaceId: scope.workspaceId
|
|
1752
|
+
});
|
|
1753
|
+
const resolveAudienceClass = createEvidenceAudienceResolver(registryRows);
|
|
1754
|
+
const viewerClass = resolveAudienceClass(audienceMode, "public");
|
|
1755
|
+
const nodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
1756
|
+
"by_topic_type",
|
|
1757
|
+
(q) => q.eq("topicId", args.topicId).eq("nodeType", "evidence")
|
|
1758
|
+
).order("desc").take(scanLimit);
|
|
1759
|
+
const workspaceScopedNodes = nodes.filter(
|
|
1760
|
+
(node) => nodeMatchesWorkspaceReasoningScope(node, {
|
|
1761
|
+
tenantId: scope.tenantId,
|
|
1762
|
+
workspaceId: scope.workspaceId
|
|
1763
|
+
})
|
|
1764
|
+
);
|
|
1765
|
+
return workspaceScopedNodes.filter(
|
|
1766
|
+
(n) => canAudienceClassAccess(
|
|
1767
|
+
viewerClass,
|
|
1768
|
+
resolveAudienceClass(n.audienceLabel, "internal")
|
|
1769
|
+
) && (!args.status || n.status === args.status)
|
|
1770
|
+
).slice(0, pageSize).map((n) => {
|
|
1771
|
+
const metadata = n.metadata || {};
|
|
1772
|
+
return {
|
|
1773
|
+
_id: n._id,
|
|
1774
|
+
_creationTime: n.createdAt,
|
|
1775
|
+
projectId: n.projectId,
|
|
1776
|
+
topicId: n.topicId,
|
|
1777
|
+
text: n.canonicalText,
|
|
1778
|
+
kind: metadata.kind || "observation",
|
|
1779
|
+
tags: metadata.tags || [],
|
|
1780
|
+
sourceType: n.sourceType,
|
|
1781
|
+
externalSourceType: metadata.externalSourceType,
|
|
1782
|
+
sourceUrl: metadata.sourceUrl,
|
|
1783
|
+
status: n.status,
|
|
1784
|
+
createdBy: n.createdBy,
|
|
1785
|
+
createdAt: n.createdAt,
|
|
1786
|
+
updatedAt: n.updatedAt,
|
|
1787
|
+
audienceLabel: n.audienceLabel,
|
|
1788
|
+
policyTags: n.policyTags,
|
|
1789
|
+
sensitivityTier: n.sensitivityTier,
|
|
1790
|
+
exportClass: n.exportClass,
|
|
1791
|
+
anonymizationClass: n.anonymizationClass
|
|
1792
|
+
};
|
|
1584
1793
|
});
|
|
1585
|
-
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1586
|
-
return { success: true };
|
|
1587
1794
|
}
|
|
1588
1795
|
});
|
|
1589
|
-
function formatEvidenceNode(n) {
|
|
1590
|
-
const metadata = n.metadata || {};
|
|
1591
|
-
const linkedWorktreeId = resolveEvidenceLinkedWorktreeId(metadata);
|
|
1592
|
-
return {
|
|
1593
|
-
_id: n._id,
|
|
1594
|
-
_epistemicNodeId: n._id,
|
|
1595
|
-
_creationTime: n.createdAt,
|
|
1596
|
-
projectId: n.projectId,
|
|
1597
|
-
topicId: n.topicId,
|
|
1598
|
-
text: n.canonicalText,
|
|
1599
|
-
kind: metadata.kind || "observation",
|
|
1600
|
-
tags: metadata.tags || [],
|
|
1601
|
-
sourceType: n.sourceType,
|
|
1602
|
-
externalSourceType: metadata.externalSourceType,
|
|
1603
|
-
externalSourceUrl: metadata.sourceUrl,
|
|
1604
|
-
sourceArtifactId: metadata.sourceArtifactId,
|
|
1605
|
-
sourceQuestionId: metadata.sourceQuestionId,
|
|
1606
|
-
linkedWorktreeId,
|
|
1607
|
-
[LEGACY_SPRINT_LINK_KEY]: metadata[LEGACY_SPRINT_LINK_KEY] || void 0,
|
|
1608
|
-
sourceAnchor: metadata.sourceAnchor,
|
|
1609
|
-
aiProvider: metadata.aiProvider,
|
|
1610
|
-
verificationStatus: metadata.verificationStatus,
|
|
1611
|
-
status: n.status,
|
|
1612
|
-
createdBy: n.createdBy,
|
|
1613
|
-
createdAt: n.createdAt,
|
|
1614
|
-
updatedAt: n.updatedAt
|
|
1615
|
-
};
|
|
1616
|
-
}
|
|
1617
1796
|
var getByProjectSystem = query({
|
|
1618
1797
|
args: {
|
|
1619
1798
|
...optionalEvidenceScopeArgs,
|
|
@@ -1623,7 +1802,7 @@ var getByProjectSystem = query({
|
|
|
1623
1802
|
returns: permissiveReturn,
|
|
1624
1803
|
handler: async (ctx, args) => {
|
|
1625
1804
|
const pageSize = clampEvidenceLimit(args.limit, 500);
|
|
1626
|
-
const scanLimit = Math.min(pageSize * 3,
|
|
1805
|
+
const scanLimit = Math.min(pageSize * 3, 1e3);
|
|
1627
1806
|
const scope = await resolveEvidenceScopeOrNull(ctx, args);
|
|
1628
1807
|
if (!scope) {
|
|
1629
1808
|
return [];
|
|
@@ -1674,191 +1853,6 @@ var getEvidenceBalance = query({
|
|
|
1674
1853
|
return { supporting, challenging, total: evidenceEdges.length };
|
|
1675
1854
|
}
|
|
1676
1855
|
});
|
|
1677
|
-
var update = mutation({
|
|
1678
|
-
args: {
|
|
1679
|
-
// Accept both native and legacy-shaped IDs
|
|
1680
|
-
nodeId: v.optional(v.id("epistemicNodes")),
|
|
1681
|
-
insightId: v.optional(v.string()),
|
|
1682
|
-
text: v.optional(v.string()),
|
|
1683
|
-
kind: v.optional(v.string()),
|
|
1684
|
-
tags: v.optional(v.array(v.string())),
|
|
1685
|
-
userId: v.string(),
|
|
1686
|
-
externalSourceUrl: v.optional(v.string()),
|
|
1687
|
-
verificationStatus: v.optional(v.string())
|
|
1688
|
-
},
|
|
1689
|
-
returns: permissiveReturn,
|
|
1690
|
-
handler: async (ctx, args) => {
|
|
1691
|
-
const resolvedId = args.nodeId ?? args.insightId;
|
|
1692
|
-
if (!resolvedId) {
|
|
1693
|
-
throw new Error("Either nodeId or insightId is required");
|
|
1694
|
-
}
|
|
1695
|
-
const node = await ctx.db.get(resolvedId);
|
|
1696
|
-
if (!node || node.nodeType !== "evidence") {
|
|
1697
|
-
throw new Error("Evidence node not found");
|
|
1698
|
-
}
|
|
1699
|
-
if (!node.projectId) {
|
|
1700
|
-
throw new Error("Evidence has no project scope");
|
|
1701
|
-
}
|
|
1702
|
-
await checkProjectAccess(ctx, node.projectId, args.userId);
|
|
1703
|
-
const now = Date.now();
|
|
1704
|
-
const existingMeta = node.metadata || {};
|
|
1705
|
-
const metaUpdates = { ...existingMeta };
|
|
1706
|
-
if (args.kind !== void 0) {
|
|
1707
|
-
metaUpdates.kind = args.kind;
|
|
1708
|
-
}
|
|
1709
|
-
if (args.tags !== void 0) {
|
|
1710
|
-
metaUpdates.tags = args.tags;
|
|
1711
|
-
}
|
|
1712
|
-
if (args.externalSourceUrl !== void 0) {
|
|
1713
|
-
metaUpdates.externalSourceUrl = args.externalSourceUrl;
|
|
1714
|
-
}
|
|
1715
|
-
await ctx.db.patch(resolvedId, {
|
|
1716
|
-
canonicalText: args.text ?? node.canonicalText,
|
|
1717
|
-
metadata: metaUpdates,
|
|
1718
|
-
updatedAt: now
|
|
1719
|
-
});
|
|
1720
|
-
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1721
|
-
nodeId: resolvedId,
|
|
1722
|
-
operation: "upsert"
|
|
1723
|
-
});
|
|
1724
|
-
await ctx.db.insert("epistemicAudit", {
|
|
1725
|
-
entityType: "evidence",
|
|
1726
|
-
entityId: resolvedId,
|
|
1727
|
-
changeType: "updated",
|
|
1728
|
-
changedAt: now,
|
|
1729
|
-
changedBy: args.userId,
|
|
1730
|
-
isAgent: false,
|
|
1731
|
-
projectId: node.projectId,
|
|
1732
|
-
previousState: { text: node.canonicalText?.slice(0, 200) },
|
|
1733
|
-
newState: { text: (args.text ?? node.canonicalText)?.slice(0, 200) }
|
|
1734
|
-
});
|
|
1735
|
-
if (args.text !== void 0) {
|
|
1736
|
-
await ctx.scheduler.runAfter(
|
|
1737
|
-
0,
|
|
1738
|
-
"embeddingActions:generateEpistemicNodeEmbedding",
|
|
1739
|
-
{
|
|
1740
|
-
nodeId: resolvedId,
|
|
1741
|
-
topicId: node.projectId,
|
|
1742
|
-
createdBy: node.createdBy,
|
|
1743
|
-
nodeType: "evidence",
|
|
1744
|
-
text: args.text
|
|
1745
|
-
}
|
|
1746
|
-
);
|
|
1747
|
-
}
|
|
1748
|
-
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1749
|
-
return { nodeId: resolvedId };
|
|
1750
|
-
}
|
|
1751
|
-
});
|
|
1752
|
-
var flagAsIncorrect = mutation({
|
|
1753
|
-
args: {
|
|
1754
|
-
insightId: v.id("epistemicNodes"),
|
|
1755
|
-
reason: v.string(),
|
|
1756
|
-
suggestedCorrection: v.optional(v.string()),
|
|
1757
|
-
userId: v.string()
|
|
1758
|
-
},
|
|
1759
|
-
returns: permissiveReturn,
|
|
1760
|
-
handler: async (ctx, args) => {
|
|
1761
|
-
const now = Date.now();
|
|
1762
|
-
const node = await ctx.db.get(args.insightId);
|
|
1763
|
-
if (!node || node.nodeType !== "evidence") {
|
|
1764
|
-
throw new Error("Evidence not found in epistemic spine");
|
|
1765
|
-
}
|
|
1766
|
-
if (!node.projectId) {
|
|
1767
|
-
throw new Error("Evidence has no project scope");
|
|
1768
|
-
}
|
|
1769
|
-
await checkProjectAccess(ctx, node.projectId, args.userId);
|
|
1770
|
-
const existingMeta = node.metadata || {};
|
|
1771
|
-
await ctx.db.patch(node._id, {
|
|
1772
|
-
verificationStatus: "contradicted",
|
|
1773
|
-
metadata: {
|
|
1774
|
-
...existingMeta,
|
|
1775
|
-
contradictionReason: args.reason,
|
|
1776
|
-
suggestedCorrection: args.suggestedCorrection,
|
|
1777
|
-
contradictedBy: args.userId,
|
|
1778
|
-
contradictedAt: now
|
|
1779
|
-
},
|
|
1780
|
-
updatedAt: now
|
|
1781
|
-
});
|
|
1782
|
-
await ctx.db.insert("verificationResults", {
|
|
1783
|
-
targetType: "insight",
|
|
1784
|
-
targetId: node._id,
|
|
1785
|
-
claimText: node.canonicalText || "Evidence text not available",
|
|
1786
|
-
verdict: "contradicted",
|
|
1787
|
-
confidence: 1,
|
|
1788
|
-
sources: [],
|
|
1789
|
-
reasoning: args.reason,
|
|
1790
|
-
suggestedRevision: args.suggestedCorrection,
|
|
1791
|
-
caveats: [],
|
|
1792
|
-
mode: "deep_verify",
|
|
1793
|
-
verifiedAt: now,
|
|
1794
|
-
durationMs: 0,
|
|
1795
|
-
projectId: node.projectId,
|
|
1796
|
-
userId: args.userId
|
|
1797
|
-
});
|
|
1798
|
-
await ctx.db.insert("epistemicAudit", {
|
|
1799
|
-
entityType: "evidence",
|
|
1800
|
-
entityId: node._id,
|
|
1801
|
-
changeType: "updated",
|
|
1802
|
-
changedAt: now,
|
|
1803
|
-
changedBy: args.userId,
|
|
1804
|
-
isAgent: false,
|
|
1805
|
-
projectId: node.projectId,
|
|
1806
|
-
newState: {
|
|
1807
|
-
reason: args.reason,
|
|
1808
|
-
suggestedCorrection: args.suggestedCorrection
|
|
1809
|
-
}
|
|
1810
|
-
});
|
|
1811
|
-
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1812
|
-
console.log(
|
|
1813
|
-
`[EpistemicEvidence] Evidence flagged as incorrect by ${args.userId}: "${args.insightId.slice(0, 20)}..."`
|
|
1814
|
-
);
|
|
1815
|
-
return { success: true };
|
|
1816
|
-
}
|
|
1817
|
-
});
|
|
1818
|
-
var remove = mutation({
|
|
1819
|
-
args: {
|
|
1820
|
-
// Accept both native and legacy-shaped IDs
|
|
1821
|
-
nodeId: v.optional(v.id("epistemicNodes")),
|
|
1822
|
-
insightId: v.optional(v.string()),
|
|
1823
|
-
userId: v.string()
|
|
1824
|
-
},
|
|
1825
|
-
returns: permissiveReturn,
|
|
1826
|
-
handler: async (ctx, args) => {
|
|
1827
|
-
const resolvedId = args.nodeId ?? args.insightId;
|
|
1828
|
-
if (!resolvedId) {
|
|
1829
|
-
throw new Error("Either nodeId or insightId is required");
|
|
1830
|
-
}
|
|
1831
|
-
const node = await ctx.db.get(resolvedId);
|
|
1832
|
-
if (!node || node.nodeType !== "evidence") {
|
|
1833
|
-
throw new Error("Evidence node not found");
|
|
1834
|
-
}
|
|
1835
|
-
if (node.createdBy !== args.userId) {
|
|
1836
|
-
throw new Error("Only the creator can archive this evidence");
|
|
1837
|
-
}
|
|
1838
|
-
const now = Date.now();
|
|
1839
|
-
await ctx.db.patch(resolvedId, {
|
|
1840
|
-
status: "archived",
|
|
1841
|
-
updatedAt: now
|
|
1842
|
-
});
|
|
1843
|
-
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
1844
|
-
nodeId: resolvedId,
|
|
1845
|
-
operation: "upsert"
|
|
1846
|
-
});
|
|
1847
|
-
await ctx.db.insert("epistemicAudit", {
|
|
1848
|
-
entityType: "evidence",
|
|
1849
|
-
entityId: resolvedId,
|
|
1850
|
-
changeType: "archived",
|
|
1851
|
-
changedAt: now,
|
|
1852
|
-
changedBy: args.userId,
|
|
1853
|
-
isAgent: false,
|
|
1854
|
-
projectId: node.projectId,
|
|
1855
|
-
previousState: { status: node.status },
|
|
1856
|
-
newState: { status: "archived" }
|
|
1857
|
-
});
|
|
1858
|
-
await markProjectGraphDirty(ctx, node.projectId, node.topicId);
|
|
1859
|
-
return { nodeId: resolvedId };
|
|
1860
|
-
}
|
|
1861
|
-
});
|
|
1862
1856
|
|
|
1863
1857
|
export { create, createAndLink, flagAsIncorrect, flattenEvidenceNode, getById, getByProject, getByProjectSystem, getByTopic, getEvidenceBalance, getForBelief, internalCreate, internalGetByProject, internalGetByTopic, remove, resolveEvidenceLinkedWorktreeId, update, updateStatus, updateVerificationStatus };
|
|
1864
1858
|
//# sourceMappingURL=epistemicEvidence.js.map
|