@lucern/graph-primitives 1.0.22 → 1.0.24
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 +49 -0
- package/dist/beliefDecay.js.map +1 -1
- package/dist/beliefEvidenceLinks.js +99 -5
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/beliefEvidenceLinks.operational.js +50 -5
- package/dist/beliefEvidenceLinks.operational.js.map +1 -1
- package/dist/contradictions.js +46 -0
- package/dist/contradictions.js.map +1 -1
- package/dist/edgeValidation.js +66 -1
- package/dist/edgeValidation.js.map +1 -1
- package/dist/entityBridge.js +66 -1
- package/dist/entityBridge.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 +149 -39
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/epistemicAnswers.js +64 -11
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.admin.js +63 -6
- package/dist/epistemicBeliefs.admin.js.map +1 -1
- package/dist/epistemicBeliefs.backfills.js +59 -2
- package/dist/epistemicBeliefs.backfills.js.map +1 -1
- package/dist/epistemicBeliefs.confidence.d.ts +1 -1
- package/dist/epistemicBeliefs.confidence.js +70 -12
- package/dist/epistemicBeliefs.confidence.js.map +1 -1
- package/dist/epistemicBeliefs.core.js +120 -17
- package/dist/epistemicBeliefs.core.js.map +1 -1
- package/dist/epistemicBeliefs.d.ts +1 -1
- package/dist/epistemicBeliefs.forkEvidence.js +13 -2
- package/dist/epistemicBeliefs.forkEvidence.js.map +1 -1
- package/dist/epistemicBeliefs.helpers.d.ts +18 -3
- package/dist/epistemicBeliefs.helpers.js +66 -6
- package/dist/epistemicBeliefs.helpers.js.map +1 -1
- package/dist/epistemicBeliefs.internal.js +115 -12
- package/dist/epistemicBeliefs.internal.js.map +1 -1
- package/dist/epistemicBeliefs.js +132 -28
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicBeliefs.lifecycle.js +70 -12
- package/dist/epistemicBeliefs.lifecycle.js.map +1 -1
- package/dist/epistemicBeliefs.links.js +111 -10
- package/dist/epistemicBeliefs.links.js.map +1 -1
- package/dist/epistemicBeliefs.topicAnchor.js +48 -8
- package/dist/epistemicBeliefs.topicAnchor.js.map +1 -1
- package/dist/epistemicContracts.evaluators.js +70 -12
- package/dist/epistemicContracts.evaluators.js.map +1 -1
- package/dist/epistemicContracts.handlers.js +71 -16
- package/dist/epistemicContracts.handlers.js.map +1 -1
- package/dist/epistemicContracts.js +71 -16
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicEdges.d.ts +1 -1
- package/dist/epistemicEdges.handlers.js +57 -3
- package/dist/epistemicEdges.handlers.js.map +1 -1
- package/dist/epistemicEdges.helpers.d.ts +2 -2
- package/dist/epistemicEdges.js +174 -4
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEdges.mutations.js +115 -1
- package/dist/epistemicEdges.mutations.js.map +1 -1
- package/dist/epistemicEdges.queries.js +46 -0
- package/dist/epistemicEdges.queries.js.map +1 -1
- package/dist/epistemicEdges.types.d.ts +1 -1
- package/dist/epistemicEvidence.d.ts +1 -1
- package/dist/epistemicEvidence.js +180 -14
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicEvidenceHelpers.d.ts +1 -1
- package/dist/epistemicEvidenceHelpers.js +49 -0
- package/dist/epistemicEvidenceHelpers.js.map +1 -1
- package/dist/epistemicEvidenceMutations.js +180 -14
- package/dist/epistemicEvidenceMutations.js.map +1 -1
- package/dist/epistemicEvidenceQueries.js +49 -0
- package/dist/epistemicEvidenceQueries.js.map +1 -1
- package/dist/epistemicHelpers.js +11 -6
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicInsert.d.ts +8 -0
- package/dist/epistemicInsert.js +54 -0
- package/dist/epistemicInsert.js.map +1 -0
- package/dist/epistemicNodeCreation.js +11 -6
- package/dist/epistemicNodeCreation.js.map +1 -1
- package/dist/epistemicNodes.helpers.d.ts +1 -1
- package/dist/epistemicNodes.internal.js +53 -1
- package/dist/epistemicNodes.internal.js.map +1 -1
- package/dist/epistemicNodes.js +56 -4
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicNodes.mutations.js +55 -3
- package/dist/epistemicNodes.mutations.js.map +1 -1
- package/dist/epistemicNodes.queries.js +46 -0
- package/dist/epistemicNodes.queries.js.map +1 -1
- package/dist/epistemicNodes.validators.d.ts +1 -1
- package/dist/epistemicQuestions.conviction.js +49 -0
- package/dist/epistemicQuestions.conviction.js.map +1 -1
- package/dist/epistemicQuestions.create.js +61 -7
- package/dist/epistemicQuestions.create.js.map +1 -1
- package/dist/epistemicQuestions.d.ts +1 -1
- package/dist/epistemicQuestions.evidence.js +56 -2
- package/dist/epistemicQuestions.evidence.js.map +1 -1
- package/dist/epistemicQuestions.helpers.d.ts +1 -1
- package/dist/epistemicQuestions.helpers.js +49 -0
- package/dist/epistemicQuestions.helpers.js.map +1 -1
- package/dist/epistemicQuestions.js +63 -9
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicQuestions.lifecycle.js +49 -0
- package/dist/epistemicQuestions.lifecycle.js.map +1 -1
- package/dist/epistemicQuestions.queries.js +49 -0
- package/dist/epistemicQuestions.queries.js.map +1 -1
- package/dist/epistemicQuestions.sprint.js +46 -0
- package/dist/epistemicQuestions.sprint.js.map +1 -1
- package/dist/epistemicQuestions.tail.js +56 -2
- package/dist/epistemicQuestions.tail.js.map +1 -1
- package/dist/epistemicSources.js +53 -2
- package/dist/epistemicSources.js.map +1 -1
- package/dist/helpers.js +66 -1
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +379 -115
- package/dist/index.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/questionEvidenceLinks.js +49 -0
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/resolvers.js +3 -0
- package/dist/resolvers.js.map +1 -1
- package/dist/scopeResolverCompat.d.ts +1 -1
- package/dist/scopeResolverCompat.js +46 -0
- package/dist/scopeResolverCompat.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/dist/{topicScope-By_zp4tt.d.ts → topicScope-7zhyeGl7.d.ts} +1 -1
- package/dist/topicScope.d.ts +1 -1
- package/dist/topicScope.js +46 -0
- package/dist/topicScope.js.map +1 -1
- package/dist/workflowBridge.js +46 -0
- package/dist/workflowBridge.js.map +1 -1
- package/dist/workspaceIsolation.d.ts +1 -1
- package/dist/workspaceIsolation.js +46 -0
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { v } from 'convex/values';
|
|
1
|
+
import { v, ConvexError } from 'convex/values';
|
|
2
2
|
import { checkScopeAccess, checkProjectAccess } from '@lucern/access-control/access';
|
|
3
3
|
import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
|
|
4
4
|
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
@@ -7,7 +7,8 @@ import { normalizeTupleContradictionPolicy, createInheritedContractRecord, confi
|
|
|
7
7
|
import '@lucern/access-control/audience';
|
|
8
8
|
import { getCurrentUserId } from '@lucern/access-control/auth';
|
|
9
9
|
import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
10
|
-
import { generateGlobalId, generateUuidV7 } from '@lucern/contracts/ids';
|
|
10
|
+
import { generateGlobalId, assertUuidV7Identity, generateUuidV7, assertStorageEdgeVocabulary, assertUuidShapedEdgeEndpoint } from '@lucern/contracts/ids';
|
|
11
|
+
import { assertEdgePolicyAllowed, edgePolicyManifest } from '@lucern/contracts';
|
|
11
12
|
|
|
12
13
|
// src/epistemicBeliefs.core.ts
|
|
13
14
|
|
|
@@ -272,6 +273,9 @@ function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
|
272
273
|
type: mapProjectType(topic, metadata),
|
|
273
274
|
description: readNonEmptyString(topic.description),
|
|
274
275
|
ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
|
|
276
|
+
// FR.7 creator-grant: surface the principal-shaped owner field (column-first,
|
|
277
|
+
// metadata fallback for legacy rows that recorded it in metadata).
|
|
278
|
+
ownerPrincipalId: readNonEmptyString(topic.ownerPrincipalId) || readNonEmptyString(metadata.ownerPrincipalId),
|
|
275
279
|
sharedWith: readStringArray(metadata.sharedWith),
|
|
276
280
|
visibility,
|
|
277
281
|
tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
|
|
@@ -466,6 +470,35 @@ function resolveGraphPrimitivesAppResolvers(_ctx) {
|
|
|
466
470
|
};
|
|
467
471
|
}
|
|
468
472
|
var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
|
|
473
|
+
async function resolveTopicNodeScopeOrNull(ctx, ref) {
|
|
474
|
+
if (!ctx?.db || typeof ctx.db.query !== "function") {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
let node = null;
|
|
478
|
+
try {
|
|
479
|
+
const byGlobalId = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", ref)).first();
|
|
480
|
+
if (byGlobalId && byGlobalId.nodeType === "topic") {
|
|
481
|
+
node = byGlobalId;
|
|
482
|
+
}
|
|
483
|
+
} catch (error) {
|
|
484
|
+
debugGraphPrimitiveFallback(
|
|
485
|
+
"[topicScope] topic-node scope lookup by globalId failed",
|
|
486
|
+
{ error, ref }
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
if (!node) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
const scopeKey = normalizeScopeValue(node.topicId) ?? normalizeScopeValue(node.globalId);
|
|
493
|
+
if (!scopeKey) {
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
topicId: scopeKey,
|
|
498
|
+
projectId: asMappedProjectId(node),
|
|
499
|
+
source: "topic_node"
|
|
500
|
+
};
|
|
501
|
+
}
|
|
469
502
|
function asMappedProjectId(topic) {
|
|
470
503
|
if (!topic) {
|
|
471
504
|
return;
|
|
@@ -606,6 +639,13 @@ async function resolveTopicProjectScope(ctx, args) {
|
|
|
606
639
|
) ?? null;
|
|
607
640
|
}
|
|
608
641
|
if (!topic) {
|
|
642
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
643
|
+
ctx,
|
|
644
|
+
String(args.topicId)
|
|
645
|
+
);
|
|
646
|
+
if (nodeScope) {
|
|
647
|
+
return nodeScope;
|
|
648
|
+
}
|
|
609
649
|
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
610
650
|
}
|
|
611
651
|
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
@@ -676,6 +716,16 @@ async function resolveTopicProjectScope(ctx, args) {
|
|
|
676
716
|
source: "project_mapped_topic"
|
|
677
717
|
};
|
|
678
718
|
}
|
|
719
|
+
const nodeScope = await resolveTopicNodeScopeOrNull(
|
|
720
|
+
ctx,
|
|
721
|
+
String(args.projectId)
|
|
722
|
+
);
|
|
723
|
+
if (nodeScope) {
|
|
724
|
+
return {
|
|
725
|
+
...nodeScope,
|
|
726
|
+
projectId: nodeScope.projectId ?? String(args.projectId)
|
|
727
|
+
};
|
|
728
|
+
}
|
|
679
729
|
throw new Error(
|
|
680
730
|
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
681
731
|
);
|
|
@@ -759,7 +809,18 @@ var DEFAULT_CONFIDENCE_POLICY = {
|
|
|
759
809
|
tupleContradiction: normalizeTupleContradictionPolicy()
|
|
760
810
|
};
|
|
761
811
|
function throwStructuredMutationError(args) {
|
|
762
|
-
const
|
|
812
|
+
const data = {
|
|
813
|
+
structuredMutationError: true,
|
|
814
|
+
message: args.message,
|
|
815
|
+
status: args.status,
|
|
816
|
+
code: args.code,
|
|
817
|
+
invariantCode: args.invariantCode,
|
|
818
|
+
suggestion: args.suggestion,
|
|
819
|
+
details: args.details
|
|
820
|
+
};
|
|
821
|
+
const error = new ConvexError(
|
|
822
|
+
data
|
|
823
|
+
);
|
|
763
824
|
error.status = args.status;
|
|
764
825
|
error.code = args.code;
|
|
765
826
|
error.invariantCode = args.invariantCode;
|
|
@@ -917,12 +978,12 @@ async function requireProjectWriteAccess(ctx, projectId, userId) {
|
|
|
917
978
|
);
|
|
918
979
|
if (!hasAccess) {
|
|
919
980
|
throwStructuredMutationError({
|
|
920
|
-
message:
|
|
981
|
+
message: `Project write access denied for topic ${projectId}.`,
|
|
921
982
|
status: 403,
|
|
922
|
-
code: "
|
|
983
|
+
code: "PROJECT_ACCESS_DENIED",
|
|
923
984
|
invariantCode: "policy.scope_required",
|
|
924
|
-
suggestion: "
|
|
925
|
-
details: { projectId, userId }
|
|
985
|
+
suggestion: "The acting principal lacks project-write access to this topic. Request a topic grant (or, if the principal created this topic, run the creator-grant backfill) and retry.",
|
|
986
|
+
details: { topicId: projectId, principalId: userId }
|
|
926
987
|
});
|
|
927
988
|
}
|
|
928
989
|
}
|
|
@@ -1023,6 +1084,52 @@ async function resolveForkTriggerEvidence(ctx, args) {
|
|
|
1023
1084
|
}
|
|
1024
1085
|
return { evidenceNodeId: args.triggeringEvidenceId, relation };
|
|
1025
1086
|
}
|
|
1087
|
+
async function insertEpistemicNode(ctx, doc) {
|
|
1088
|
+
assertUuidV7Identity("epistemicNodes", doc.globalId);
|
|
1089
|
+
return ctx.db.insert("epistemicNodes", doc);
|
|
1090
|
+
}
|
|
1091
|
+
async function assertExistingNodeEndpoint(ctx, endpointRole, endpoint) {
|
|
1092
|
+
assertUuidShapedEdgeEndpoint(endpointRole, endpoint);
|
|
1093
|
+
const node = await ctx.db.query("epistemicNodes").withIndex("by_globalId", (q) => q.eq("globalId", endpoint)).first();
|
|
1094
|
+
if (!node) {
|
|
1095
|
+
throw new Error(
|
|
1096
|
+
`edge_endpoint_not_canonical: epistemicEdges insert requires ${endpointRole} to be the globalId of an existing epistemicNodes row, received ${endpoint} (no node with that globalId)`
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
async function insertEpistemicEdge(ctx, doc) {
|
|
1101
|
+
assertUuidV7Identity("epistemicEdges", doc.globalId);
|
|
1102
|
+
assertStorageEdgeVocabulary(doc.edgeType);
|
|
1103
|
+
if (!doc.fromNodeId || typeof doc.fromNodeId !== "string") {
|
|
1104
|
+
throw new Error(
|
|
1105
|
+
"edge_endpoint_missing: epistemicEdges insert requires a non-empty fromNodeId"
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
if (!doc.toNodeId || typeof doc.toNodeId !== "string") {
|
|
1109
|
+
throw new Error(
|
|
1110
|
+
"edge_endpoint_missing: epistemicEdges insert requires a non-empty toNodeId"
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
await assertExistingNodeEndpoint(ctx, "fromNodeId", doc.fromNodeId);
|
|
1114
|
+
await assertExistingNodeEndpoint(ctx, "toNodeId", doc.toNodeId);
|
|
1115
|
+
if (doc.fromNodeType && doc.toNodeType && doc.edgeType !== "extracted_from") {
|
|
1116
|
+
assertEdgePolicyAllowed(
|
|
1117
|
+
edgePolicyManifest,
|
|
1118
|
+
doc.edgeType,
|
|
1119
|
+
{
|
|
1120
|
+
kind: "epistemic_node",
|
|
1121
|
+
nodeId: doc.fromNodeId,
|
|
1122
|
+
nodeType: doc.fromNodeType
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
kind: "epistemic_node",
|
|
1126
|
+
nodeId: doc.toNodeId,
|
|
1127
|
+
nodeType: doc.toNodeType
|
|
1128
|
+
}
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
return ctx.db.insert("epistemicEdges", doc);
|
|
1132
|
+
}
|
|
1026
1133
|
|
|
1027
1134
|
// src/epistemicBeliefs.topicAnchor.ts
|
|
1028
1135
|
function cleanString(value) {
|
|
@@ -1074,18 +1181,15 @@ async function createRequiredBeliefTopicEdge(ctx, args) {
|
|
|
1074
1181
|
const now = Date.now();
|
|
1075
1182
|
const existingEdges = await ctx.db.query("epistemicEdges").withIndex(
|
|
1076
1183
|
"by_from_to",
|
|
1077
|
-
(q) => q.eq("fromNodeId",
|
|
1078
|
-
"toNodeId",
|
|
1079
|
-
String(args.topicNode._id)
|
|
1080
|
-
)
|
|
1184
|
+
(q) => q.eq("fromNodeId", args.beliefGlobalId).eq("toNodeId", topicGlobalId)
|
|
1081
1185
|
).collect();
|
|
1082
1186
|
const existing = existingEdges.find((edge) => edge.edgeType === "belongs_to");
|
|
1083
1187
|
const edgeGlobalId = cleanString(existing?.globalId) ?? generateUuidV7();
|
|
1084
1188
|
if (!existing) {
|
|
1085
|
-
await ctx
|
|
1189
|
+
await insertEpistemicEdge(ctx, {
|
|
1086
1190
|
globalId: edgeGlobalId,
|
|
1087
|
-
fromNodeId:
|
|
1088
|
-
toNodeId:
|
|
1191
|
+
fromNodeId: args.beliefGlobalId,
|
|
1192
|
+
toNodeId: topicGlobalId,
|
|
1089
1193
|
sourceGlobalId: args.beliefGlobalId,
|
|
1090
1194
|
targetGlobalId: topicGlobalId,
|
|
1091
1195
|
edgeType: "belongs_to",
|
|
@@ -1264,7 +1368,7 @@ var create = mutation({
|
|
|
1264
1368
|
const pillar = normalizePillar(args.pillar);
|
|
1265
1369
|
const additionalMeta = args.metadata || {};
|
|
1266
1370
|
const beliefGlobalId = generateGlobalId();
|
|
1267
|
-
const nodeId = await ctx
|
|
1371
|
+
const nodeId = await insertEpistemicNode(ctx, {
|
|
1268
1372
|
globalId: beliefGlobalId,
|
|
1269
1373
|
nodeType: "belief",
|
|
1270
1374
|
epistemicLayer: "L3",
|
|
@@ -1322,7 +1426,6 @@ var create = mutation({
|
|
|
1322
1426
|
})
|
|
1323
1427
|
);
|
|
1324
1428
|
await createRequiredBeliefTopicEdge(ctx, {
|
|
1325
|
-
beliefNodeId: nodeId,
|
|
1326
1429
|
beliefGlobalId,
|
|
1327
1430
|
topicNode,
|
|
1328
1431
|
createdBy: authenticatedUserId
|
|
@@ -1737,7 +1840,7 @@ var forkBelief = mutation({
|
|
|
1737
1840
|
});
|
|
1738
1841
|
}
|
|
1739
1842
|
const newBeliefGlobalId = generateGlobalId();
|
|
1740
|
-
const newNodeId = await ctx
|
|
1843
|
+
const newNodeId = await insertEpistemicNode(ctx, {
|
|
1741
1844
|
globalId: newBeliefGlobalId,
|
|
1742
1845
|
nodeType: "belief",
|
|
1743
1846
|
epistemicLayer: "L3",
|