@lucern/graph-primitives 0.3.0-alpha.9 → 1.0.1
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
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
import { v } from 'convex/values';
|
|
2
|
+
import { checkScopeAccess } from '@lucern/access-control/access';
|
|
3
|
+
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
4
|
+
import { componentsGeneric, queryGeneric, anyApi } from 'convex/server';
|
|
5
|
+
|
|
6
|
+
// src/epistemicQuestions.sprint.ts
|
|
7
|
+
var api = anyApi;
|
|
8
|
+
componentsGeneric();
|
|
9
|
+
var query = queryGeneric;
|
|
10
|
+
|
|
11
|
+
// src/debug.ts
|
|
12
|
+
function isGraphPrimitiveDebugEnabled() {
|
|
13
|
+
const env = globalThis.process?.env;
|
|
14
|
+
return env?.LUCERN_COMPAT_FALLBACK_DEBUG === "1" || env?.LUCERN_GRAPH_DEBUG === "1";
|
|
15
|
+
}
|
|
16
|
+
function formatGraphPrimitiveError(error) {
|
|
17
|
+
if (error instanceof Error) {
|
|
18
|
+
return `${error.name}: ${error.message}`;
|
|
19
|
+
}
|
|
20
|
+
if (typeof error === "string") {
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
if (error === null) {
|
|
24
|
+
return "null";
|
|
25
|
+
}
|
|
26
|
+
if (error === void 0) {
|
|
27
|
+
return "undefined";
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
return JSON.stringify(error);
|
|
31
|
+
} catch {
|
|
32
|
+
return Object.prototype.toString.call(error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function debugGraphPrimitiveFallback(message, context) {
|
|
36
|
+
if (!isGraphPrimitiveDebugEnabled()) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
console.debug(message, context ?? {});
|
|
40
|
+
}
|
|
41
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
42
|
+
function asMappedProjectId(topic) {
|
|
43
|
+
if (!topic) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
47
|
+
if (directLegacyProjectId) {
|
|
48
|
+
return directLegacyProjectId;
|
|
49
|
+
}
|
|
50
|
+
const metadata = topic.metadata || {};
|
|
51
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
52
|
+
return candidate ? candidate : void 0;
|
|
53
|
+
}
|
|
54
|
+
function normalizeScopeValue(value) {
|
|
55
|
+
if (typeof value !== "string") {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const normalized = value.trim();
|
|
59
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
60
|
+
}
|
|
61
|
+
function pickPrimaryTopic(candidates) {
|
|
62
|
+
return [...candidates].sort((a, b) => {
|
|
63
|
+
const depthA = a.depth ?? 9999;
|
|
64
|
+
const depthB = b.depth ?? 9999;
|
|
65
|
+
if (depthA !== depthB) {
|
|
66
|
+
return depthA - depthB;
|
|
67
|
+
}
|
|
68
|
+
const createdA = a.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
69
|
+
const createdB = b.createdAt ?? Number.MAX_SAFE_INTEGER;
|
|
70
|
+
if (createdA !== createdB) {
|
|
71
|
+
return createdA - createdB;
|
|
72
|
+
}
|
|
73
|
+
return String(a.name || "").localeCompare(String(b.name || ""));
|
|
74
|
+
})[0];
|
|
75
|
+
}
|
|
76
|
+
async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
77
|
+
try {
|
|
78
|
+
return await ctx.db.query("topics").withIndex(
|
|
79
|
+
"by_graph_scope_project",
|
|
80
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
81
|
+
).collect();
|
|
82
|
+
} catch (error) {
|
|
83
|
+
debugGraphPrimitiveFallback(
|
|
84
|
+
"[topicScope] Failed to resolve scope alias via index",
|
|
85
|
+
{
|
|
86
|
+
error,
|
|
87
|
+
scopeId
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
const topics = await ctx.db.query("topics").collect();
|
|
91
|
+
return topics.filter((topic) => {
|
|
92
|
+
const normalizedGlobalId = normalizeScopeValue(topic.globalId);
|
|
93
|
+
const mappedProjectId = asMappedProjectId(topic);
|
|
94
|
+
return String(topic._id) === scopeId || normalizedGlobalId === scopeId || mappedProjectId === scopeId;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function tryResolveHostTopicById(ctx, topicId) {
|
|
99
|
+
if (typeof ctx.runQuery !== "function") {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
return await ctx.runQuery(api.topics.get, {
|
|
104
|
+
id: topicId
|
|
105
|
+
}) ?? null;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
debugGraphPrimitiveFallback(
|
|
108
|
+
"[topicScope] Failed to resolve topic by host query",
|
|
109
|
+
{
|
|
110
|
+
error,
|
|
111
|
+
topicId
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
118
|
+
if (typeof ctx.runQuery !== "function") {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
123
|
+
projectId: legacyScopeId
|
|
124
|
+
}) ?? null;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
debugGraphPrimitiveFallback(
|
|
127
|
+
"[topicScope] Failed to resolve topic by legacy scope",
|
|
128
|
+
{
|
|
129
|
+
error,
|
|
130
|
+
legacyScopeId
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function resolveInheritedWorkspaceScope(ctx, topic) {
|
|
137
|
+
const MAX_DEPTH = 10;
|
|
138
|
+
let tenantId = normalizeScopeValue(topic.tenantId);
|
|
139
|
+
let workspaceId = normalizeScopeValue(topic.workspaceId);
|
|
140
|
+
if (tenantId && workspaceId) {
|
|
141
|
+
return { tenantId, workspaceId };
|
|
142
|
+
}
|
|
143
|
+
let current = topic;
|
|
144
|
+
for (let i = 0; i < MAX_DEPTH && current?.parentTopicId; i++) {
|
|
145
|
+
current = await ctx.db.get(current.parentTopicId);
|
|
146
|
+
if (!current) break;
|
|
147
|
+
if (!tenantId) {
|
|
148
|
+
tenantId = normalizeScopeValue(current.tenantId);
|
|
149
|
+
}
|
|
150
|
+
if (!workspaceId) {
|
|
151
|
+
workspaceId = normalizeScopeValue(current.workspaceId);
|
|
152
|
+
}
|
|
153
|
+
if (tenantId && workspaceId) break;
|
|
154
|
+
}
|
|
155
|
+
return { tenantId, workspaceId };
|
|
156
|
+
}
|
|
157
|
+
async function resolveTopicProjectScope(ctx, args) {
|
|
158
|
+
if (args.topicId) {
|
|
159
|
+
let topic = null;
|
|
160
|
+
try {
|
|
161
|
+
topic = await ctx.db.get(
|
|
162
|
+
args.topicId
|
|
163
|
+
);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
debugGraphPrimitiveFallback(
|
|
166
|
+
"[topicScope] Failed to load topic by direct id",
|
|
167
|
+
{
|
|
168
|
+
error,
|
|
169
|
+
topicId: args.topicId
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
if (!topic) {
|
|
174
|
+
topic = await tryResolveHostTopicById(ctx, String(args.topicId));
|
|
175
|
+
}
|
|
176
|
+
if (!topic) {
|
|
177
|
+
topic = pickPrimaryTopic(
|
|
178
|
+
await findTopicsByScopeAlias(ctx, String(args.topicId))
|
|
179
|
+
) ?? null;
|
|
180
|
+
}
|
|
181
|
+
if (!topic) {
|
|
182
|
+
throw new Error(`Topic not found: ${String(args.topicId)}`);
|
|
183
|
+
}
|
|
184
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, topic);
|
|
185
|
+
const mapped = asMappedProjectId(topic);
|
|
186
|
+
if (mapped) {
|
|
187
|
+
return {
|
|
188
|
+
topicId: topic._id,
|
|
189
|
+
projectId: mapped,
|
|
190
|
+
tenantId: inherited.tenantId,
|
|
191
|
+
workspaceId: inherited.workspaceId,
|
|
192
|
+
source: "topic"
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
topicId: topic._id,
|
|
197
|
+
tenantId: inherited.tenantId,
|
|
198
|
+
workspaceId: inherited.workspaceId,
|
|
199
|
+
source: "topic"
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (args.projectId) {
|
|
203
|
+
let directTopic = null;
|
|
204
|
+
try {
|
|
205
|
+
directTopic = await ctx.db.get(
|
|
206
|
+
args.projectId
|
|
207
|
+
);
|
|
208
|
+
} catch (error) {
|
|
209
|
+
debugGraphPrimitiveFallback(
|
|
210
|
+
"[topicScope] Failed to load direct project topic",
|
|
211
|
+
{
|
|
212
|
+
error,
|
|
213
|
+
projectId: args.projectId
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
if (directTopic) {
|
|
218
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
219
|
+
const mapped = asMappedProjectId(directTopic);
|
|
220
|
+
return {
|
|
221
|
+
topicId: directTopic._id,
|
|
222
|
+
projectId: mapped ?? args.projectId,
|
|
223
|
+
tenantId: inherited.tenantId,
|
|
224
|
+
workspaceId: inherited.workspaceId,
|
|
225
|
+
source: "topic_inferred"
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
directTopic = await tryResolveHostTopicByLegacyScope(ctx, args.projectId);
|
|
229
|
+
if (directTopic) {
|
|
230
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, directTopic);
|
|
231
|
+
const mapped = asMappedProjectId(directTopic);
|
|
232
|
+
return {
|
|
233
|
+
topicId: directTopic._id,
|
|
234
|
+
projectId: mapped ?? args.projectId,
|
|
235
|
+
tenantId: inherited.tenantId,
|
|
236
|
+
workspaceId: inherited.workspaceId,
|
|
237
|
+
source: "topic_inferred"
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const topics = await findTopicsByScopeAlias(ctx, args.projectId);
|
|
241
|
+
const primary = pickPrimaryTopic(topics);
|
|
242
|
+
if (primary) {
|
|
243
|
+
const inherited = await resolveInheritedWorkspaceScope(ctx, primary);
|
|
244
|
+
return {
|
|
245
|
+
topicId: primary._id,
|
|
246
|
+
projectId: args.projectId,
|
|
247
|
+
tenantId: inherited.tenantId,
|
|
248
|
+
workspaceId: inherited.workspaceId,
|
|
249
|
+
source: "project_mapped_topic"
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
throw new Error(
|
|
253
|
+
`Legacy project scope ${String(args.projectId)} has no mapped topic.`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
throw new Error(
|
|
257
|
+
"Missing scope: provide topicId (preferred) or legacy projectId alias."
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
({
|
|
261
|
+
projectId: v.optional(v.string()),
|
|
262
|
+
topicId: v.optional(v.string())
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// src/workflowBridge.ts
|
|
266
|
+
function isLegacySprintDoc(doc) {
|
|
267
|
+
if (!doc || typeof doc !== "object") {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
if ("metadata" in doc && doc.metadata?.pairedSprintId) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
return "sprintScope" in doc || "targetPillar" in doc || "pillarThesis" in doc || "synthesisState" in doc || "projectId" in doc && !("worktreeScope" in doc);
|
|
274
|
+
}
|
|
275
|
+
function getPairedSprintId(doc) {
|
|
276
|
+
const pairedSprintId = doc?.metadata?.pairedSprintId;
|
|
277
|
+
return typeof pairedSprintId === "string" && pairedSprintId.trim().length > 0 ? pairedSprintId : null;
|
|
278
|
+
}
|
|
279
|
+
function getStringField(doc, field) {
|
|
280
|
+
const value = doc?.[field];
|
|
281
|
+
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
282
|
+
}
|
|
283
|
+
async function findPairedWorktreeForSprint(ctx, sprint) {
|
|
284
|
+
const sprintId = typeof sprint._id === "string" && sprint._id.length > 0 ? sprint._id : null;
|
|
285
|
+
if (!sprintId || typeof ctx.db.query !== "function") {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
let topicId = getStringField(sprint, "topicId");
|
|
289
|
+
if (!topicId) {
|
|
290
|
+
try {
|
|
291
|
+
const scope = await resolveTopicProjectScope(ctx, {
|
|
292
|
+
topicId: getStringField(sprint, "topicId"),
|
|
293
|
+
projectId: getStringField(sprint, "projectId")
|
|
294
|
+
});
|
|
295
|
+
topicId = scope.topicId;
|
|
296
|
+
} catch {
|
|
297
|
+
topicId = void 0;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (!topicId) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
const worktrees = await ctx.db.query("worktrees").withIndex("by_topicId", (q) => q.eq("topicId", topicId)).collect();
|
|
304
|
+
return worktrees.find(
|
|
305
|
+
(worktree) => String(worktree?.metadata?.pairedSprintId || "") === sprintId
|
|
306
|
+
) ?? null;
|
|
307
|
+
}
|
|
308
|
+
async function resolveWorkflowBridgeDoc(ctx, workflowId) {
|
|
309
|
+
const empty = {
|
|
310
|
+
inputId: workflowId ?? null,
|
|
311
|
+
sprint: null,
|
|
312
|
+
worktree: null,
|
|
313
|
+
sprintId: null,
|
|
314
|
+
worktreeId: null
|
|
315
|
+
};
|
|
316
|
+
if (!workflowId) {
|
|
317
|
+
return empty;
|
|
318
|
+
}
|
|
319
|
+
let doc;
|
|
320
|
+
try {
|
|
321
|
+
doc = await ctx.db.get(workflowId);
|
|
322
|
+
} catch {
|
|
323
|
+
return empty;
|
|
324
|
+
}
|
|
325
|
+
if (!doc || typeof doc !== "object") {
|
|
326
|
+
return empty;
|
|
327
|
+
}
|
|
328
|
+
if (isLegacySprintDoc(doc)) {
|
|
329
|
+
const worktree2 = await findPairedWorktreeForSprint(ctx, doc);
|
|
330
|
+
return {
|
|
331
|
+
...empty,
|
|
332
|
+
sprint: doc,
|
|
333
|
+
worktree: worktree2,
|
|
334
|
+
sprintId: typeof doc._id === "string" && doc._id.length > 0 ? doc._id : workflowId,
|
|
335
|
+
worktreeId: worktree2 && typeof worktree2._id === "string" && worktree2._id.length > 0 ? worktree2._id : null,
|
|
336
|
+
topicId: getStringField(worktree2, "topicId") ?? getStringField(doc, "topicId"),
|
|
337
|
+
projectId: getStringField(doc, "projectId") ?? getStringField(worktree2, "projectId")
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
const worktree = doc;
|
|
341
|
+
const pairedSprintId = getPairedSprintId(worktree);
|
|
342
|
+
let sprint = null;
|
|
343
|
+
if (pairedSprintId) {
|
|
344
|
+
try {
|
|
345
|
+
const paired = await ctx.db.get(pairedSprintId);
|
|
346
|
+
if (isLegacySprintDoc(paired)) {
|
|
347
|
+
sprint = paired;
|
|
348
|
+
}
|
|
349
|
+
} catch {
|
|
350
|
+
sprint = null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
...empty,
|
|
355
|
+
worktree,
|
|
356
|
+
sprint,
|
|
357
|
+
worktreeId: typeof worktree._id === "string" && worktree._id.length > 0 ? worktree._id : workflowId,
|
|
358
|
+
sprintId: sprint && typeof sprint._id === "string" && sprint._id.length > 0 ? sprint._id : pairedSprintId,
|
|
359
|
+
topicId: getStringField(worktree, "topicId") ?? getStringField(sprint, "topicId"),
|
|
360
|
+
projectId: getStringField(sprint, "projectId") ?? getStringField(worktree, "projectId")
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/epistemicQuestions.helpers.ts
|
|
365
|
+
function dedupeQuestionNodes(nodes) {
|
|
366
|
+
const seen = /* @__PURE__ */ new Set();
|
|
367
|
+
const deduped = [];
|
|
368
|
+
for (const node of nodes) {
|
|
369
|
+
const id = String(node._id);
|
|
370
|
+
if (seen.has(id)) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
seen.add(id);
|
|
374
|
+
deduped.push(node);
|
|
375
|
+
}
|
|
376
|
+
return deduped;
|
|
377
|
+
}
|
|
378
|
+
function normalizeQuestionTopicId(topicId) {
|
|
379
|
+
return typeof topicId === "string" && topicId.trim().length > 0 ? topicId : void 0;
|
|
380
|
+
}
|
|
381
|
+
function resolveQuestionScopeId(scope) {
|
|
382
|
+
return normalizeQuestionTopicId(scope.topicId) ?? scope.projectId ?? void 0;
|
|
383
|
+
}
|
|
384
|
+
async function resolveQuestionScopeOrNull(ctx, args) {
|
|
385
|
+
if (!args.projectId && !args.topicId) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
try {
|
|
389
|
+
return await resolveTopicProjectScope(ctx, {
|
|
390
|
+
projectId: args.projectId ?? void 0,
|
|
391
|
+
topicId: args.topicId ?? void 0
|
|
392
|
+
});
|
|
393
|
+
} catch (error) {
|
|
394
|
+
debugGraphPrimitiveFallback(
|
|
395
|
+
"[epistemicQuestions] Failed to resolve question scope",
|
|
396
|
+
{
|
|
397
|
+
error: formatGraphPrimitiveError(error),
|
|
398
|
+
projectId: args.projectId,
|
|
399
|
+
topicId: args.topicId
|
|
400
|
+
}
|
|
401
|
+
);
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async function getQuestionNodesForScope(ctx, scope, args) {
|
|
406
|
+
const fetchNodes = (query2) => query2.collect();
|
|
407
|
+
const topicNodes = await fetchNodes(
|
|
408
|
+
ctx.db.query("epistemicNodes").withIndex(
|
|
409
|
+
"by_topic_type",
|
|
410
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
|
|
411
|
+
)
|
|
412
|
+
);
|
|
413
|
+
return dedupeQuestionNodes(topicNodes).filter(
|
|
414
|
+
(node) => questionMatchesScope(node, scope)
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
async function getQuestionEdgesForScope(ctx, scope) {
|
|
418
|
+
const query2 = ctx.db.query("epistemicEdges").withIndex(
|
|
419
|
+
"by_topic",
|
|
420
|
+
(q) => q.eq("topicId", scope.topicId || scope.projectId)
|
|
421
|
+
);
|
|
422
|
+
return await query2.collect();
|
|
423
|
+
}
|
|
424
|
+
function questionMatchesScope(node, scope) {
|
|
425
|
+
return scope.topicId !== void 0 && node.topicId === scope.topicId || scope.projectId !== void 0 && node.projectId === scope.projectId;
|
|
426
|
+
}
|
|
427
|
+
function resolveLinkedWorktreeId(meta) {
|
|
428
|
+
const linkedWorktreeId = meta.linkedWorktreeId;
|
|
429
|
+
return typeof linkedWorktreeId === "string" && linkedWorktreeId.trim() ? linkedWorktreeId : null;
|
|
430
|
+
}
|
|
431
|
+
function questionMatchesWorkflowLink(meta, workflow) {
|
|
432
|
+
const linkedWorktreeId = resolveLinkedWorktreeId(meta);
|
|
433
|
+
return Boolean(
|
|
434
|
+
linkedWorktreeId && (linkedWorktreeId === workflow.worktreeId || linkedWorktreeId === workflow.sprintId)
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/epistemicQuestions.sprint.ts
|
|
439
|
+
var getForSprintCluster = query({
|
|
440
|
+
args: {
|
|
441
|
+
sprintId: v.optional(v.string()),
|
|
442
|
+
worktreeId: v.optional(v.string()),
|
|
443
|
+
userId: v.string()
|
|
444
|
+
},
|
|
445
|
+
returns: permissiveReturn,
|
|
446
|
+
handler: async (ctx, args) => {
|
|
447
|
+
const docId = args.sprintId || args.worktreeId;
|
|
448
|
+
if (!docId) return [];
|
|
449
|
+
const workflow = await resolveWorkflowBridgeDoc(ctx, docId);
|
|
450
|
+
const scopeDoc = workflow.worktree ?? workflow.sprint;
|
|
451
|
+
if (!scopeDoc) {
|
|
452
|
+
return [];
|
|
453
|
+
}
|
|
454
|
+
const scope = await resolveQuestionScopeOrNull(ctx, {
|
|
455
|
+
projectId: workflow.projectId,
|
|
456
|
+
topicId: workflow.topicId
|
|
457
|
+
});
|
|
458
|
+
const scopeId = scope ? resolveQuestionScopeId(scope) : void 0;
|
|
459
|
+
if (!scope || !scopeId) {
|
|
460
|
+
return [];
|
|
461
|
+
}
|
|
462
|
+
const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
|
|
463
|
+
if (!hasAccess) {
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
const synthesisState = scopeDoc.synthesisState;
|
|
467
|
+
const hypothesisIds = new Set(
|
|
468
|
+
(synthesisState?.synthesizedBeliefIds || []).map(
|
|
469
|
+
(id) => String(id)
|
|
470
|
+
)
|
|
471
|
+
);
|
|
472
|
+
const rawBeliefIds = new Set(
|
|
473
|
+
(synthesisState?.originalBeliefIds || []).map(
|
|
474
|
+
(id) => String(id)
|
|
475
|
+
)
|
|
476
|
+
);
|
|
477
|
+
const clusterBeliefIds = new Set(hypothesisIds);
|
|
478
|
+
const edges = await getQuestionEdgesForScope(ctx, scope);
|
|
479
|
+
for (const edge of edges) {
|
|
480
|
+
const fromStr = String(edge.fromNodeId || "");
|
|
481
|
+
const toStr = String(edge.toNodeId || "");
|
|
482
|
+
if (hypothesisIds.has(fromStr) && !rawBeliefIds.has(toStr)) {
|
|
483
|
+
clusterBeliefIds.add(toStr);
|
|
484
|
+
}
|
|
485
|
+
if (hypothesisIds.has(toStr) && !rawBeliefIds.has(fromStr)) {
|
|
486
|
+
clusterBeliefIds.add(fromStr);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
const questionNodes = await getQuestionNodesForScope(ctx, scope);
|
|
490
|
+
const sprintQuestionIds = new Set(
|
|
491
|
+
(workflow.worktree?.targetQuestionIds || workflow.sprint?.targetQuestionIds || []).map((id) => String(id))
|
|
492
|
+
);
|
|
493
|
+
const clusterQuestions = questionNodes.filter((q) => {
|
|
494
|
+
if (sprintQuestionIds.has(String(q._id))) {
|
|
495
|
+
return true;
|
|
496
|
+
}
|
|
497
|
+
const meta = q.metadata || {};
|
|
498
|
+
const linkedId = String(meta.linkedBeliefNodeId || "");
|
|
499
|
+
if (linkedId && clusterBeliefIds.has(linkedId)) {
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
return edges.some(
|
|
503
|
+
(e) => String(e.fromNodeId) === String(q._id) && clusterBeliefIds.has(String(e.toNodeId || "")) || String(e.toNodeId) === String(q._id) && clusterBeliefIds.has(String(e.fromNodeId || ""))
|
|
504
|
+
);
|
|
505
|
+
});
|
|
506
|
+
const enrichedQuestions = await Promise.all(
|
|
507
|
+
clusterQuestions.map(async (q) => {
|
|
508
|
+
const meta = q.metadata || {};
|
|
509
|
+
const linkedBeliefNodeIds = /* @__PURE__ */ new Set();
|
|
510
|
+
const primaryBeliefId = String(meta.linkedBeliefNodeId || "");
|
|
511
|
+
if (primaryBeliefId) {
|
|
512
|
+
linkedBeliefNodeIds.add(primaryBeliefId);
|
|
513
|
+
}
|
|
514
|
+
for (const edge of edges) {
|
|
515
|
+
if (String(edge.fromNodeId) === String(q._id)) {
|
|
516
|
+
linkedBeliefNodeIds.add(String(edge.toNodeId || ""));
|
|
517
|
+
}
|
|
518
|
+
if (String(edge.toNodeId) === String(q._id)) {
|
|
519
|
+
linkedBeliefNodeIds.add(String(edge.fromNodeId || ""));
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
linkedBeliefNodeIds.delete("");
|
|
523
|
+
const linkedBeliefs = (await Promise.all(
|
|
524
|
+
Array.from(linkedBeliefNodeIds).map(async (nodeId) => {
|
|
525
|
+
const node = await ctx.db.get(nodeId);
|
|
526
|
+
if (!node || node.nodeType !== "belief") {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
const isHypothesis = hypothesisIds.has(nodeId);
|
|
530
|
+
const isRaw = rawBeliefIds.has(nodeId);
|
|
531
|
+
const isConditional = !isHypothesis && !isRaw && clusterBeliefIds.has(nodeId);
|
|
532
|
+
return {
|
|
533
|
+
beliefId: node._id,
|
|
534
|
+
beliefText: node.canonicalText || "",
|
|
535
|
+
isHypothesis,
|
|
536
|
+
isConditional,
|
|
537
|
+
isRaw,
|
|
538
|
+
isPrimaryTarget: isHypothesis
|
|
539
|
+
};
|
|
540
|
+
})
|
|
541
|
+
)).filter(Boolean);
|
|
542
|
+
return {
|
|
543
|
+
_id: q._id,
|
|
544
|
+
_creationTime: q._creationTime,
|
|
545
|
+
projectId: q.projectId,
|
|
546
|
+
topicId: q.topicId,
|
|
547
|
+
canonicalText: q.canonicalText,
|
|
548
|
+
question: q.canonicalText,
|
|
549
|
+
// legacy field name
|
|
550
|
+
questionType: q.questionType || meta.questionType || "general",
|
|
551
|
+
priority: meta.priority || "medium",
|
|
552
|
+
isKeyQuestion: meta.isKeyQuestion || false,
|
|
553
|
+
testType: meta.testType || "validates",
|
|
554
|
+
category: meta.category || "other",
|
|
555
|
+
status: q.status,
|
|
556
|
+
linkedBeliefs,
|
|
557
|
+
testLogic: meta.testType || "validates",
|
|
558
|
+
testRationale: meta.rationale || null,
|
|
559
|
+
beliefId: meta.linkedBeliefNodeId || null,
|
|
560
|
+
relatedBeliefIds: Array.from(linkedBeliefNodeIds),
|
|
561
|
+
// Conviction stage fields — needed by UI to show/hide action buttons
|
|
562
|
+
convictionStage: meta.convictionStage || null,
|
|
563
|
+
answer: meta.answer || null,
|
|
564
|
+
conviction: meta.conviction ?? null,
|
|
565
|
+
linkedWorktreeId: resolveLinkedWorktreeId(meta),
|
|
566
|
+
metadata: q.metadata
|
|
567
|
+
};
|
|
568
|
+
})
|
|
569
|
+
);
|
|
570
|
+
const seen = /* @__PURE__ */ new Set();
|
|
571
|
+
return enrichedQuestions.filter((q) => {
|
|
572
|
+
if (seen.has(String(q._id))) {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
seen.add(String(q._id));
|
|
576
|
+
return true;
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
var getInConviction = query({
|
|
581
|
+
args: {
|
|
582
|
+
sprintId: v.optional(v.string()),
|
|
583
|
+
worktreeId: v.optional(v.string()),
|
|
584
|
+
userId: v.string()
|
|
585
|
+
},
|
|
586
|
+
returns: permissiveReturn,
|
|
587
|
+
handler: async (ctx, args) => {
|
|
588
|
+
const docId = args.sprintId || args.worktreeId;
|
|
589
|
+
if (!docId) return [];
|
|
590
|
+
const workflow = await resolveWorkflowBridgeDoc(ctx, docId);
|
|
591
|
+
const scopeDoc = workflow.worktree ?? workflow.sprint;
|
|
592
|
+
if (!scopeDoc) {
|
|
593
|
+
return [];
|
|
594
|
+
}
|
|
595
|
+
const scope = await resolveQuestionScopeOrNull(ctx, {
|
|
596
|
+
projectId: workflow.projectId,
|
|
597
|
+
topicId: workflow.topicId
|
|
598
|
+
});
|
|
599
|
+
const scopeId = scope ? resolveQuestionScopeId(scope) : void 0;
|
|
600
|
+
if (!scope || !scopeId) {
|
|
601
|
+
return [];
|
|
602
|
+
}
|
|
603
|
+
const hasAccess = await checkScopeAccess(ctx, scopeId, args.userId);
|
|
604
|
+
if (!hasAccess) {
|
|
605
|
+
return [];
|
|
606
|
+
}
|
|
607
|
+
const allQuestions = await getQuestionNodesForScope(ctx, scope);
|
|
608
|
+
const convictionQuestions = allQuestions.filter((q) => {
|
|
609
|
+
const meta = q.metadata || {};
|
|
610
|
+
return meta.convictionStage === "in_conviction" || meta.convictionStage === "scored";
|
|
611
|
+
});
|
|
612
|
+
const sprintBeliefIds = /* @__PURE__ */ new Set([
|
|
613
|
+
...(scopeDoc.synthesisState?.synthesizedBeliefIds || []).map(
|
|
614
|
+
String
|
|
615
|
+
),
|
|
616
|
+
...(workflow.worktree?.targetBeliefIds || workflow.sprint?.targetBeliefIds || []).map(String)
|
|
617
|
+
]);
|
|
618
|
+
const sprintQuestions = convictionQuestions.filter((q) => {
|
|
619
|
+
const meta = q.metadata || {};
|
|
620
|
+
if (questionMatchesWorkflowLink(meta, workflow)) {
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
if (meta.linkedBeliefNodeId && sprintBeliefIds.has(String(meta.linkedBeliefNodeId))) {
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
if (meta.linkedBeliefId && sprintBeliefIds.has(String(meta.linkedBeliefId))) {
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
if (meta.beliefId && sprintBeliefIds.has(String(meta.beliefId))) {
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
const relatedIds = meta.relatedBeliefIds || [];
|
|
633
|
+
if (relatedIds.some((id) => sprintBeliefIds.has(String(id)))) {
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
return false;
|
|
637
|
+
});
|
|
638
|
+
const questionsWithDetails = await Promise.all(
|
|
639
|
+
sprintQuestions.map(async (q) => {
|
|
640
|
+
const meta = q.metadata || {};
|
|
641
|
+
const evidenceLinks = await ctx.db.query("questionEvidenceLinks").withIndex(
|
|
642
|
+
"by_questionId",
|
|
643
|
+
(qb) => qb.eq("questionId", q._id)
|
|
644
|
+
).collect();
|
|
645
|
+
const evidenceWithDetails = await Promise.all(
|
|
646
|
+
evidenceLinks.map(async (link) => {
|
|
647
|
+
const insight = await ctx.db.get(link.insightId);
|
|
648
|
+
const insightMeta = insight?.metadata || {};
|
|
649
|
+
const canonicalText = insight?.canonicalText;
|
|
650
|
+
const legacyText = insight?.text;
|
|
651
|
+
const contentText = insight?.content;
|
|
652
|
+
const titleText = insight?.title;
|
|
653
|
+
const snippetText = insightMeta.snippet;
|
|
654
|
+
return {
|
|
655
|
+
...link,
|
|
656
|
+
insightText: typeof canonicalText === "string" && canonicalText.trim() || typeof legacyText === "string" && legacyText.trim() || typeof contentText === "string" && contentText.trim() || typeof titleText === "string" && titleText.trim() || typeof snippetText === "string" && snippetText.trim() || "",
|
|
657
|
+
insightSource: insight?.sourceType || "unknown"
|
|
658
|
+
};
|
|
659
|
+
})
|
|
660
|
+
);
|
|
661
|
+
const beliefIds = [];
|
|
662
|
+
const relatedIds = meta.relatedBeliefIds || [];
|
|
663
|
+
if (meta.linkedBeliefNodeId) {
|
|
664
|
+
beliefIds.push(String(meta.linkedBeliefNodeId));
|
|
665
|
+
}
|
|
666
|
+
if (meta.linkedBeliefId) {
|
|
667
|
+
beliefIds.push(String(meta.linkedBeliefId));
|
|
668
|
+
}
|
|
669
|
+
if (meta.beliefId) {
|
|
670
|
+
beliefIds.push(String(meta.beliefId));
|
|
671
|
+
}
|
|
672
|
+
for (const id of relatedIds) {
|
|
673
|
+
if (!beliefIds.includes(String(id))) {
|
|
674
|
+
beliefIds.push(String(id));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
const beliefsWithDetails = await Promise.all(
|
|
678
|
+
beliefIds.map(async (beliefId) => {
|
|
679
|
+
try {
|
|
680
|
+
const node = await ctx.db.get(beliefId);
|
|
681
|
+
if (node && node.nodeType === "belief") {
|
|
682
|
+
return {
|
|
683
|
+
_id: node._id,
|
|
684
|
+
belief: node.canonicalText || "",
|
|
685
|
+
confidence: node.metadata?.confidence,
|
|
686
|
+
pillar: node.metadata?.category,
|
|
687
|
+
beliefType: node.status,
|
|
688
|
+
dependsOnCount: 0,
|
|
689
|
+
cascadesToCount: 0,
|
|
690
|
+
exclusiveWithCount: 0
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
} catch (error) {
|
|
694
|
+
debugGraphPrimitiveFallback(
|
|
695
|
+
"[epistemicQuestions] Failed to hydrate linked belief",
|
|
696
|
+
{
|
|
697
|
+
error: formatGraphPrimitiveError(error),
|
|
698
|
+
beliefId
|
|
699
|
+
}
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
return null;
|
|
703
|
+
})
|
|
704
|
+
);
|
|
705
|
+
return {
|
|
706
|
+
_id: q._id,
|
|
707
|
+
_creationTime: q._creationTime,
|
|
708
|
+
projectId: q.projectId,
|
|
709
|
+
question: q.canonicalText,
|
|
710
|
+
canonicalText: q.canonicalText,
|
|
711
|
+
category: meta.category || "other",
|
|
712
|
+
priority: meta.priority || "medium",
|
|
713
|
+
status: meta.questionStatus || q.status,
|
|
714
|
+
questionType: q.questionType || meta.questionType || "general",
|
|
715
|
+
testType: meta.testType || void 0,
|
|
716
|
+
importance: meta.importance || void 0,
|
|
717
|
+
isKeyQuestion: meta.isKeyQuestion || false,
|
|
718
|
+
conviction: meta.conviction,
|
|
719
|
+
convictionStage: meta.convictionStage,
|
|
720
|
+
convictionRationale: meta.convictionRationale,
|
|
721
|
+
convictionAdvancedAt: meta.convictionAdvancedAt,
|
|
722
|
+
convictionAdvancedBy: meta.convictionAdvancedBy,
|
|
723
|
+
convictionUpdatedAt: meta.convictionUpdatedAt,
|
|
724
|
+
convictionUpdatedBy: meta.convictionUpdatedBy,
|
|
725
|
+
answer: meta.answer,
|
|
726
|
+
answerStatus: meta.answerStatus,
|
|
727
|
+
answerCompleteness: meta.answerCompleteness,
|
|
728
|
+
whatWeNeed: meta.whatWeNeed,
|
|
729
|
+
linkedWorktreeId: resolveLinkedWorktreeId(meta) || void 0,
|
|
730
|
+
beliefId: meta.linkedBeliefNodeId || meta.beliefId || null,
|
|
731
|
+
linkedBeliefId: meta.linkedBeliefNodeId || meta.linkedBeliefId,
|
|
732
|
+
relatedBeliefIds: relatedIds,
|
|
733
|
+
evidenceCount: evidenceWithDetails.length,
|
|
734
|
+
evidence: evidenceWithDetails,
|
|
735
|
+
testedBeliefs: beliefsWithDetails.filter(Boolean),
|
|
736
|
+
createdAt: q.createdAt,
|
|
737
|
+
createdBy: q.createdBy,
|
|
738
|
+
updatedAt: q.updatedAt,
|
|
739
|
+
metadata: q.metadata
|
|
740
|
+
};
|
|
741
|
+
})
|
|
742
|
+
);
|
|
743
|
+
return questionsWithDetails.sort((a, b) => {
|
|
744
|
+
if (a.convictionStage === "in_conviction" && b.convictionStage === "scored") {
|
|
745
|
+
return -1;
|
|
746
|
+
}
|
|
747
|
+
if (a.convictionStage === "scored" && b.convictionStage === "in_conviction") {
|
|
748
|
+
return 1;
|
|
749
|
+
}
|
|
750
|
+
return (a.importance || 5) - (b.importance || 5);
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
export { getForSprintCluster, getInConviction };
|
|
756
|
+
//# sourceMappingURL=epistemicQuestions.sprint.js.map
|
|
757
|
+
//# sourceMappingURL=epistemicQuestions.sprint.js.map
|