@lucern/graph-primitives 0.1.0-alpha.4 → 0.3.0-alpha.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/dist/beliefDecay.js +229 -1115
- package/dist/beliefDecay.js.map +1 -1
- package/dist/beliefEvidenceLinks.js +53 -834
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/confidencePropagationDispatch.d.ts +3 -3
- package/dist/confidencePropagationDispatch.js +30 -308
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/contradictions.js +5 -797
- package/dist/contradictions.js.map +1 -1
- package/dist/edges/contradicts.js +1 -122
- package/dist/edges/contradicts.js.map +1 -1
- package/dist/edges/dependsOn.js +14 -172
- package/dist/edges/dependsOn.js.map +1 -1
- package/dist/edges/elaborates.js +1 -49
- package/dist/edges/elaborates.js.map +1 -1
- package/dist/edges/index.js +14 -277
- package/dist/edges/index.js.map +1 -1
- package/dist/edges/informs.js +1 -62
- package/dist/edges/informs.js.map +1 -1
- package/dist/edges/propagationTypes.d.ts +2 -2
- package/dist/edges/propagationTypes.js.map +1 -1
- package/dist/edges/refutes.js +1 -62
- package/dist/edges/refutes.js.map +1 -1
- package/dist/edges/supports.js +1 -122
- package/dist/edges/supports.js.map +1 -1
- package/dist/edges/utils.d.ts +6 -6
- package/dist/edges/utils.js +1 -130
- package/dist/edges/utils.js.map +1 -1
- package/dist/entityBridge.js +2 -17
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityLifecycle.js +62 -848
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/epistemicAnswers.js +27 -838
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.js +186 -2214
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicContractHelpers.js +1 -318
- package/dist/epistemicContractHelpers.js.map +1 -1
- package/dist/epistemicContracts.js +163 -2467
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicEdges.js +60 -863
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEvidence.js +116 -1647
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicHelpers.js +3 -2
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicLinking.js +2 -785
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodes.js +34 -1427
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicQuestions.js +88 -1637
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicSources.js +28 -1421
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.js +163 -2467
- package/dist/evaluators/index.js.map +1 -1
- package/dist/index.js +486 -3649
- package/dist/index.js.map +1 -1
- package/dist/ontology-matching.js +1 -344
- package/dist/ontology-matching.js.map +1 -1
- package/dist/ontologyApproval.js +1 -13
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.js +2 -17
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyRegistry.js +2 -17
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/projectionReconciliation.js +2 -17
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/questionEvidenceLinks.js +242 -837
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/text-matching.js +1 -244
- package/dist/text-matching.js.map +1 -1
- package/dist/workflowBridge.d.ts +27 -0
- package/dist/workflowBridge.js +303 -0
- package/dist/workflowBridge.js.map +1 -0
- package/dist/workspaceIsolation.js +8 -609
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,1749 +1,22 @@
|
|
|
1
1
|
import { v } from 'convex/values';
|
|
2
|
-
import {
|
|
2
|
+
import { checkScopeAccess, checkProjectAccess } from '@lucern/access-control/access';
|
|
3
|
+
import { getCurrentUserId } from '@lucern/access-control/auth';
|
|
4
|
+
import { permissiveReturn } from '@lucern/contracts/schema-helpers/validators';
|
|
5
|
+
import { componentsGeneric, internalMutationGeneric, mutationGeneric, anyApi, queryGeneric, internalQueryGeneric } from 'convex/server';
|
|
6
|
+
import { normalizeTupleContradictionPolicy, mkOpinion, createInheritedContractRecord, confidenceFromSL, conditionalDeduction, project, dampedDependencyCascade, hasProjectedOpinionChanged, detectTupleContradiction, evaluateTupleContradictionTransition, readOpinionFromRecord, deriveContractModulationPlan, deriveContractStatus, trustDiscount, applyNegativeSupport, cumulativeFusion, applyNegativeEvidence, parseEvidentialEvaluatorConfig, compareMetricValue, buildEvidentialRationale, parseMetricCheckerConfig, getEvaluatorInputRecord, pickFiniteNumber, resolveComparisonResult, buildComparisonRationale, parseReferenceCheckCounterConfig, parseTemporalDeadlineConfig, parseMarketIndexComparatorConfig } from '@lucern/confidence';
|
|
7
|
+
import { canAudienceClassAccess, normalizeAudienceKey, classFromAudienceKey } from '@lucern/access-control/audience';
|
|
8
|
+
import { listAudienceRegistryRows } from '@lucern/access-control/audienceRegistry';
|
|
9
|
+
import { assertSchemaEnumValue } from '@lucern/contracts/schema-helpers/enumValidation';
|
|
10
|
+
import { isNodeType, getLayerForNodeType } from '@lucern/contracts/schema-helpers/spine/tables/epistemicNodes';
|
|
3
11
|
|
|
4
12
|
// src/epistemicContracts.ts
|
|
5
13
|
var api = anyApi;
|
|
6
14
|
componentsGeneric();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
const normalized = value.trim();
|
|
15
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
16
|
-
}
|
|
17
|
-
function readStringArray(value) {
|
|
18
|
-
if (!Array.isArray(value)) {
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
|
|
22
|
-
}
|
|
23
|
-
function readMetadata(topic) {
|
|
24
|
-
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
25
|
-
}
|
|
26
|
-
function readLegacyProjectId(value) {
|
|
27
|
-
if (!value) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
return readNonEmptyString(value[LEGACY_SCOPE_FIELD]);
|
|
31
|
-
}
|
|
32
|
-
function coerceVisibility(value) {
|
|
33
|
-
return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
|
|
34
|
-
}
|
|
35
|
-
function coerceStatus(value) {
|
|
36
|
-
return value === "active" || value === "archived" || value === "watching" ? value : void 0;
|
|
37
|
-
}
|
|
38
|
-
function mapProjectType(topic, metadata) {
|
|
39
|
-
const explicit = readNonEmptyString(metadata.projectType);
|
|
40
|
-
if (explicit) {
|
|
41
|
-
return explicit;
|
|
42
|
-
}
|
|
43
|
-
if (topic.type === "theme") {
|
|
44
|
-
return "thematic";
|
|
45
|
-
}
|
|
46
|
-
return readNonEmptyString(topic.type) || "general";
|
|
47
|
-
}
|
|
48
|
-
function isProjectLikeTopic(topic) {
|
|
49
|
-
const metadata = readMetadata(topic);
|
|
50
|
-
return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
|
|
51
|
-
}
|
|
52
|
-
async function resolveTopicDoc(ctx, scopeId) {
|
|
53
|
-
if (ctx?.db && typeof ctx.db.get === "function") {
|
|
54
|
-
try {
|
|
55
|
-
const directTopic = await ctx.db.get(scopeId);
|
|
56
|
-
if (directTopic) {
|
|
57
|
-
return directTopic;
|
|
58
|
-
}
|
|
59
|
-
} catch {
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (typeof ctx.runQuery !== "function") {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
const topic = await ctx.runQuery(api.topics.get, {
|
|
67
|
-
id: String(scopeId)
|
|
68
|
-
});
|
|
69
|
-
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
70
|
-
return topic;
|
|
71
|
-
}
|
|
72
|
-
} catch {
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
76
|
-
projectId: String(scopeId)
|
|
77
|
-
});
|
|
78
|
-
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
79
|
-
return topic;
|
|
80
|
-
}
|
|
81
|
-
} catch {
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
86
|
-
const metadata = readMetadata(topic);
|
|
87
|
-
const topicId = String(topic._id);
|
|
88
|
-
const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
|
|
89
|
-
const storageProjectId = legacyProjectId || topicId;
|
|
90
|
-
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
91
|
-
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
92
|
-
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
93
|
-
const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
|
|
94
|
-
const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
|
|
95
|
-
return {
|
|
96
|
-
...metadata,
|
|
97
|
-
_id: outwardId,
|
|
98
|
-
projectId: outwardId,
|
|
99
|
-
topicId,
|
|
100
|
-
storageProjectId,
|
|
101
|
-
legacyProjectId,
|
|
102
|
-
name: readNonEmptyString(topic.name) || "Untitled Theme",
|
|
103
|
-
type: mapProjectType(topic, metadata),
|
|
104
|
-
description: readNonEmptyString(topic.description),
|
|
105
|
-
ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
|
|
106
|
-
sharedWith: readStringArray(metadata.sharedWith),
|
|
107
|
-
visibility,
|
|
108
|
-
tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
|
|
109
|
-
workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
|
|
110
|
-
status,
|
|
111
|
-
tags: readStringArray(metadata.tags),
|
|
112
|
-
chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
|
|
113
|
-
artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
|
|
114
|
-
lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
|
|
115
|
-
_creationTime: typeof topic._creationTime === "number" ? topic._creationTime : createdAt,
|
|
116
|
-
createdAt,
|
|
117
|
-
updatedAt
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
|
|
121
|
-
const topic = await resolveTopicDoc(ctx, scopeId);
|
|
122
|
-
if (!topic) {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
return materializeTopicProjectOverlay(topic, options.idMode);
|
|
129
|
-
}
|
|
130
|
-
async function listTopicProjectOverlays(ctx, options = {}) {
|
|
131
|
-
let allTopics = [];
|
|
132
|
-
if (ctx?.db?.query && typeof ctx.db.query === "function") {
|
|
133
|
-
try {
|
|
134
|
-
allTopics = await ctx.db.query("topics").collect();
|
|
135
|
-
} catch {
|
|
136
|
-
allTopics = [];
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
|
|
140
|
-
allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
|
|
141
|
-
}
|
|
142
|
-
return allTopics.filter(
|
|
143
|
-
(topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
|
|
144
|
-
).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// ../access-control/src/projectGrantsBridge.ts
|
|
148
|
-
var PROJECT_GRANT_STATUSES = ["active", "revoked", "expired"];
|
|
149
|
-
function normalizeString(value) {
|
|
150
|
-
if (typeof value !== "string") {
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const trimmed = value.trim();
|
|
154
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
155
|
-
}
|
|
156
|
-
async function resolveGrantScopeIds(ctx, args) {
|
|
157
|
-
const topicId = normalizeString(args.topicId);
|
|
158
|
-
const projectId = normalizeString(args.projectId);
|
|
159
|
-
for (const scopeId of [topicId, projectId]) {
|
|
160
|
-
if (!scopeId) {
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
try {
|
|
164
|
-
const overlay = await resolveTopicProjectOverlay(ctx, scopeId, {
|
|
165
|
-
idMode: "legacy",
|
|
166
|
-
projectLikeOnly: false
|
|
167
|
-
});
|
|
168
|
-
if (overlay) {
|
|
169
|
-
return {
|
|
170
|
-
topicId: normalizeString(overlay.topicId) ?? topicId,
|
|
171
|
-
projectId: normalizeString(overlay.projectId) ?? projectId ?? scopeId
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
} catch {
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return { topicId, projectId };
|
|
178
|
-
}
|
|
179
|
-
async function normalizeProjectGrantRow(ctx, row) {
|
|
180
|
-
const scope = await resolveGrantScopeIds(ctx, {
|
|
181
|
-
topicId: row.topicId,
|
|
182
|
-
projectId: row.projectId
|
|
183
|
-
});
|
|
184
|
-
return {
|
|
185
|
-
...row,
|
|
186
|
-
...scope.topicId ? { topicId: scope.topicId } : {},
|
|
187
|
-
...scope.projectId ?? scope.topicId ? { projectId: scope.projectId ?? scope.topicId } : {}
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
async function normalizeProjectGrantRows(ctx, rows) {
|
|
191
|
-
return await Promise.all(rows.map((row) => normalizeProjectGrantRow(ctx, row)));
|
|
192
|
-
}
|
|
193
|
-
async function listProjectGrantsByPrincipal(ctx, principalId) {
|
|
194
|
-
const rows = await Promise.all(
|
|
195
|
-
PROJECT_GRANT_STATUSES.map(
|
|
196
|
-
(status) => ctx.db.query("projectGrants").withIndex(
|
|
197
|
-
"by_principal_status",
|
|
198
|
-
(q) => q.eq("principalId", principalId).eq("status", status)
|
|
199
|
-
).collect()
|
|
200
|
-
)
|
|
201
|
-
);
|
|
202
|
-
return await normalizeProjectGrantRows(ctx, rows.flat());
|
|
203
|
-
}
|
|
204
|
-
async function listProjectGrantsByGroup(ctx, groupId) {
|
|
205
|
-
const rows = await Promise.all(
|
|
206
|
-
PROJECT_GRANT_STATUSES.map(
|
|
207
|
-
(status) => ctx.db.query("projectGrants").withIndex(
|
|
208
|
-
"by_group_status",
|
|
209
|
-
(q) => q.eq("groupId", groupId).eq("status", status)
|
|
210
|
-
).collect()
|
|
211
|
-
)
|
|
212
|
-
);
|
|
213
|
-
return await normalizeProjectGrantRows(ctx, rows.flat());
|
|
214
|
-
}
|
|
215
|
-
function buildScopeMatchers(inputScopeId, resolved) {
|
|
216
|
-
return new Set(
|
|
217
|
-
[inputScopeId, resolved.topicId, resolved.projectId].map((value) => normalizeString(value)).filter((value) => Boolean(value))
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
function matchesResolvedScope(row, scopeIds) {
|
|
221
|
-
const rowTopicId = normalizeString(row.topicId);
|
|
222
|
-
const rowProjectId = normalizeString(row.projectId);
|
|
223
|
-
return rowTopicId !== void 0 && scopeIds.has(rowTopicId) || rowProjectId !== void 0 && scopeIds.has(rowProjectId);
|
|
224
|
-
}
|
|
225
|
-
async function bridgeListProjectGrantsByTopicAndPrincipal(ctx, topicId, principalId) {
|
|
226
|
-
const resolved = await resolveGrantScopeIds(ctx, { topicId });
|
|
227
|
-
const scopeIds = buildScopeMatchers(topicId, resolved);
|
|
228
|
-
const rows = await listProjectGrantsByPrincipal(ctx, principalId);
|
|
229
|
-
return rows.filter((row) => matchesResolvedScope(row, scopeIds));
|
|
230
|
-
}
|
|
231
|
-
async function bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId) {
|
|
232
|
-
const resolved = await resolveGrantScopeIds(ctx, { topicId });
|
|
233
|
-
const scopeIds = buildScopeMatchers(topicId, resolved);
|
|
234
|
-
const rows = await listProjectGrantsByGroup(ctx, groupId);
|
|
235
|
-
return rows.filter((row) => matchesResolvedScope(row, scopeIds));
|
|
236
|
-
}
|
|
237
|
-
async function bridgeListProjectGrantsByPrincipalStatus(ctx, principalId, status) {
|
|
238
|
-
const rows = await listProjectGrantsByPrincipal(ctx, principalId);
|
|
239
|
-
return rows.filter((row) => row.status === status);
|
|
240
|
-
}
|
|
241
|
-
async function bridgeListProjectGrantsByGroupStatus(ctx, groupId, status) {
|
|
242
|
-
const rows = await listProjectGrantsByGroup(ctx, groupId);
|
|
243
|
-
return rows.filter((row) => row.status === status);
|
|
244
|
-
}
|
|
245
|
-
async function bridgeInsertProjectGrant(ctx, value) {
|
|
246
|
-
const resolved = await resolveGrantScopeIds(ctx, value);
|
|
247
|
-
return await ctx.db.insert("projectGrants", {
|
|
248
|
-
...value,
|
|
249
|
-
...resolved.topicId ? { topicId: resolved.topicId } : {},
|
|
250
|
-
...resolved.projectId ?? resolved.topicId ? { projectId: resolved.projectId ?? resolved.topicId } : {}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// ../access-control/src/resolvers.ts
|
|
255
|
-
async function findUserByClerkId(ctx, clerkId) {
|
|
256
|
-
const normalizedClerkId = clerkId.trim();
|
|
257
|
-
if (!normalizedClerkId) {
|
|
258
|
-
return null;
|
|
259
|
-
}
|
|
260
|
-
if (typeof ctx.runQuery === "function") {
|
|
261
|
-
try {
|
|
262
|
-
const bridgedUser = await ctx.runQuery(api.users.getUserByClerkId, {
|
|
263
|
-
clerkId: normalizedClerkId
|
|
264
|
-
});
|
|
265
|
-
if (bridgedUser) {
|
|
266
|
-
return bridgedUser;
|
|
267
|
-
}
|
|
268
|
-
} catch {
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
try {
|
|
272
|
-
const users = await ctx.db.query("users").collect();
|
|
273
|
-
return users.find((user) => String(user.clerkId ?? "") === normalizedClerkId) ?? null;
|
|
274
|
-
} catch {
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
async function findUserByPrincipalId(ctx, principalId) {
|
|
279
|
-
const normalizedPrincipalId = principalId.trim();
|
|
280
|
-
if (!normalizedPrincipalId) {
|
|
281
|
-
return null;
|
|
282
|
-
}
|
|
283
|
-
try {
|
|
284
|
-
const users = await ctx.db.query("users").collect();
|
|
285
|
-
return users.find(
|
|
286
|
-
(user) => String(user.defaultPrincipalId ?? "") === normalizedPrincipalId
|
|
287
|
-
) ?? null;
|
|
288
|
-
} catch {
|
|
289
|
-
return null;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
async function findAgentByPrincipalId(ctx, principalId) {
|
|
293
|
-
const normalizedPrincipalId = principalId.trim();
|
|
294
|
-
if (!normalizedPrincipalId) {
|
|
295
|
-
return null;
|
|
296
|
-
}
|
|
297
|
-
if (typeof ctx.runQuery === "function") {
|
|
298
|
-
try {
|
|
299
|
-
const bridgedAgent = await ctx.runQuery(
|
|
300
|
-
api.agents.getAgentByPrincipalId,
|
|
301
|
-
{
|
|
302
|
-
principalId: normalizedPrincipalId
|
|
303
|
-
}
|
|
304
|
-
);
|
|
305
|
-
if (bridgedAgent) {
|
|
306
|
-
return bridgedAgent;
|
|
307
|
-
}
|
|
308
|
-
} catch {
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
try {
|
|
312
|
-
const agents = await ctx.db.query("agents").collect();
|
|
313
|
-
return agents.find(
|
|
314
|
-
(agent) => String(agent.principalId ?? "") === normalizedPrincipalId
|
|
315
|
-
) ?? null;
|
|
316
|
-
} catch {
|
|
317
|
-
return null;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
function defaultResolvers() {
|
|
321
|
-
return {
|
|
322
|
-
async getProject(ctx, topicId) {
|
|
323
|
-
return await resolveTopicProjectOverlay(ctx, topicId, {
|
|
324
|
-
idMode: "legacy",
|
|
325
|
-
projectLikeOnly: false
|
|
326
|
-
});
|
|
327
|
-
},
|
|
328
|
-
async listTopics(ctx) {
|
|
329
|
-
return await listTopicProjectOverlays(ctx, { idMode: "legacy" });
|
|
330
|
-
},
|
|
331
|
-
async listTopicsByOwner(ctx, ownerId) {
|
|
332
|
-
const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
|
|
333
|
-
return topics.filter((topic) => topic.ownerId === ownerId);
|
|
334
|
-
},
|
|
335
|
-
async listTopicsByVisibility(ctx, visibility) {
|
|
336
|
-
const topics = await listTopicProjectOverlays(ctx, { idMode: "legacy" });
|
|
337
|
-
return topics.filter((topic) => topic.visibility === visibility);
|
|
338
|
-
},
|
|
339
|
-
async listProjectGrantsByProjectAndPrincipal(ctx, topicId, principalId) {
|
|
340
|
-
return await bridgeListProjectGrantsByTopicAndPrincipal(
|
|
341
|
-
ctx,
|
|
342
|
-
topicId,
|
|
343
|
-
principalId
|
|
344
|
-
);
|
|
345
|
-
},
|
|
346
|
-
async listProjectGrantsByProjectAndGroup(ctx, topicId, groupId) {
|
|
347
|
-
return await bridgeListProjectGrantsByTopicAndGroup(ctx, topicId, groupId);
|
|
348
|
-
},
|
|
349
|
-
async listProjectGrantsByPrincipalStatus(ctx, principalId, status) {
|
|
350
|
-
return await bridgeListProjectGrantsByPrincipalStatus(
|
|
351
|
-
ctx,
|
|
352
|
-
principalId,
|
|
353
|
-
status
|
|
354
|
-
);
|
|
355
|
-
},
|
|
356
|
-
async listProjectGrantsByGroupStatus(ctx, groupId, status) {
|
|
357
|
-
return await bridgeListProjectGrantsByGroupStatus(ctx, groupId, status);
|
|
358
|
-
},
|
|
359
|
-
async insertProjectGrant(ctx, value) {
|
|
360
|
-
return await bridgeInsertProjectGrant(ctx, value);
|
|
361
|
-
},
|
|
362
|
-
async getAgentByPrincipalId(ctx, principalId) {
|
|
363
|
-
return await findAgentByPrincipalId(ctx, principalId);
|
|
364
|
-
},
|
|
365
|
-
async getUserByClerkId(ctx, clerkId) {
|
|
366
|
-
return await findUserByClerkId(ctx, clerkId);
|
|
367
|
-
},
|
|
368
|
-
async getUserByPrincipalId(ctx, principalId) {
|
|
369
|
-
return await findUserByPrincipalId(ctx, principalId);
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
|
-
var resolverOverrides = {};
|
|
374
|
-
function resolveAccessControlAppResolvers(_ctx) {
|
|
375
|
-
return {
|
|
376
|
-
...defaultResolvers(),
|
|
377
|
-
...resolverOverrides
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// ../access-control/src/principalContext.ts
|
|
382
|
-
function requireCanonicalResolvedUser(user, clerkId) {
|
|
383
|
-
const resolved = user;
|
|
384
|
-
if (!resolved) {
|
|
385
|
-
throw new Error(
|
|
386
|
-
`[AccessControl] Canonical user identity required for ${clerkId}. Sync users.upsertUser before user-bound access checks.`
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
const { mcRole, defaultTenantId, defaultWorkspaceId, defaultPrincipalId } = resolved;
|
|
390
|
-
if (mcRole !== "platform_admin" && mcRole !== "tenant_admin" && mcRole !== "workspace_admin" && mcRole !== "editor" && mcRole !== "viewer" && mcRole !== "auditor" && mcRole !== "service_agent") {
|
|
391
|
-
throw new Error(
|
|
392
|
-
`[AccessControl] Canonical MC role required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
if (typeof defaultTenantId !== "string" || defaultTenantId.trim().length === 0) {
|
|
396
|
-
throw new Error(
|
|
397
|
-
`[AccessControl] Canonical home tenant required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
if (typeof defaultWorkspaceId !== "string" || defaultWorkspaceId.trim().length === 0) {
|
|
401
|
-
throw new Error(
|
|
402
|
-
`[AccessControl] Canonical home workspace required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
if (typeof defaultPrincipalId !== "string" || defaultPrincipalId.trim().length === 0) {
|
|
406
|
-
throw new Error(
|
|
407
|
-
`[AccessControl] Canonical federated principal required for ${clerkId}. Re-sync Master Control identity before user-bound access checks.`
|
|
408
|
-
);
|
|
409
|
-
}
|
|
410
|
-
return {
|
|
411
|
-
mcRole,
|
|
412
|
-
defaultTenantId: defaultTenantId.trim(),
|
|
413
|
-
defaultWorkspaceId: defaultWorkspaceId.trim(),
|
|
414
|
-
defaultPrincipalId: defaultPrincipalId.trim()
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
function isPrincipalIdInput(value) {
|
|
418
|
-
return value.startsWith("user:") || value.startsWith("group:") || value.startsWith("service:") || value.startsWith("agent:") || value.startsWith("external_viewer:");
|
|
419
|
-
}
|
|
420
|
-
async function resolveCanonicalUserRecord(ctx, actorId) {
|
|
421
|
-
const normalizedActorId = actorId.trim();
|
|
422
|
-
const clerkId = isPrincipalIdInput(normalizedActorId) && normalizedActorId.startsWith("user:") ? normalizedActorId.slice("user:".length) : normalizedActorId;
|
|
423
|
-
const resolvers = resolveAccessControlAppResolvers();
|
|
424
|
-
const resolvedByClerkId = await resolvers.getUserByClerkId(ctx, clerkId);
|
|
425
|
-
if (resolvedByClerkId) {
|
|
426
|
-
return {
|
|
427
|
-
resolvedUser: resolvedByClerkId,
|
|
428
|
-
clerkId,
|
|
429
|
-
contextClerkId: clerkId
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
const resolvedByPrincipalId = await resolvers.getUserByPrincipalId(
|
|
433
|
-
ctx,
|
|
434
|
-
normalizedActorId
|
|
435
|
-
);
|
|
436
|
-
return {
|
|
437
|
-
resolvedUser: resolvedByPrincipalId ?? null,
|
|
438
|
-
clerkId,
|
|
439
|
-
contextClerkId: normalizedActorId.startsWith("user:") && clerkId.length > 0 ? clerkId : normalizedActorId
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
function uniqRoles(roles) {
|
|
443
|
-
const roleSet = /* @__PURE__ */ new Set();
|
|
444
|
-
for (const role of roles) {
|
|
445
|
-
if (role === "platform_admin" || role === "tenant_admin" || role === "workspace_admin" || role === "editor" || role === "viewer" || role === "auditor" || role === "service_agent") {
|
|
446
|
-
roleSet.add(role);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
return [...roleSet];
|
|
450
|
-
}
|
|
451
|
-
function normalizeGroupIds(value) {
|
|
452
|
-
if (!Array.isArray(value)) {
|
|
453
|
-
return [];
|
|
454
|
-
}
|
|
455
|
-
return [...new Set(
|
|
456
|
-
value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean)
|
|
457
|
-
)];
|
|
458
|
-
}
|
|
459
|
-
function requireServiceAgentUser(user, actorId) {
|
|
460
|
-
const canonicalUser = requireCanonicalResolvedUser(user, actorId);
|
|
461
|
-
if (canonicalUser.mcRole !== "service_agent") {
|
|
462
|
-
throw new Error(
|
|
463
|
-
`[AccessControl] Canonical service_agent identity required for ${actorId}. Sync users.upsertUser before agent-bound access checks.`
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
return canonicalUser;
|
|
467
|
-
}
|
|
468
|
-
function requireCanonicalResolvedAgent(agent, actorId) {
|
|
469
|
-
const resolved = agent;
|
|
470
|
-
if (!resolved) {
|
|
471
|
-
throw new Error(
|
|
472
|
-
`[AccessControl] Agent "${actorId}" not found in agents or users table.`
|
|
473
|
-
);
|
|
474
|
-
}
|
|
475
|
-
if (typeof resolved.principalId !== "string" || resolved.principalId.trim().length === 0) {
|
|
476
|
-
throw new Error(
|
|
477
|
-
`[AccessControl] Canonical agent principalId required for ${actorId}.`
|
|
478
|
-
);
|
|
479
|
-
}
|
|
480
|
-
if (typeof resolved.tenantId !== "string" || resolved.tenantId.trim().length === 0) {
|
|
481
|
-
throw new Error(
|
|
482
|
-
`[AccessControl] Canonical home tenant required for ${actorId}.`
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
if (typeof resolved.workspaceId !== "string" || resolved.workspaceId.trim().length === 0) {
|
|
486
|
-
throw new Error(
|
|
487
|
-
`[AccessControl] Canonical home workspace required for ${actorId}.`
|
|
488
|
-
);
|
|
489
|
-
}
|
|
490
|
-
return {
|
|
491
|
-
principalId: resolved.principalId.trim(),
|
|
492
|
-
tenantId: resolved.tenantId.trim(),
|
|
493
|
-
workspaceId: resolved.workspaceId.trim(),
|
|
494
|
-
roles: uniqRoles(Array.isArray(resolved.roles) ? resolved.roles : []) ?? ["service_agent"],
|
|
495
|
-
groupIds: normalizeGroupIds(resolved.groupIds)
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
async function resolvePrincipalContext(ctx, actorId) {
|
|
499
|
-
if (actorId.startsWith("agent:")) {
|
|
500
|
-
const resolvers = resolveAccessControlAppResolvers();
|
|
501
|
-
const resolvedAgent = await resolvers.getAgentByPrincipalId(ctx, actorId);
|
|
502
|
-
if (resolvedAgent) {
|
|
503
|
-
const agent = requireCanonicalResolvedAgent(
|
|
504
|
-
resolvedAgent,
|
|
505
|
-
actorId
|
|
506
|
-
);
|
|
507
|
-
return {
|
|
508
|
-
principalId: agent.principalId,
|
|
509
|
-
principalType: "service",
|
|
510
|
-
clerkId: actorId,
|
|
511
|
-
tenantId: agent.tenantId,
|
|
512
|
-
workspaceId: agent.workspaceId,
|
|
513
|
-
roles: agent.roles.length > 0 ? agent.roles : ["service_agent"],
|
|
514
|
-
groupIds: agent.groupIds,
|
|
515
|
-
isPlatformAdmin: false,
|
|
516
|
-
isTenantAdmin: false,
|
|
517
|
-
isWorkspaceAdmin: false,
|
|
518
|
-
isSystemFallback: false
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
const resolvedUser2 = await resolvers.getUserByClerkId(
|
|
522
|
-
ctx,
|
|
523
|
-
actorId
|
|
524
|
-
);
|
|
525
|
-
if (!resolvedUser2) {
|
|
526
|
-
throw new Error(
|
|
527
|
-
`[AccessControl] Agent "${actorId}" not found in agents or users table.`
|
|
528
|
-
);
|
|
529
|
-
}
|
|
530
|
-
const user2 = requireServiceAgentUser(
|
|
531
|
-
resolvedUser2,
|
|
532
|
-
actorId
|
|
533
|
-
);
|
|
534
|
-
console.warn(
|
|
535
|
-
`[AccessControl] Deprecated legacy service-agent fallback for ${actorId}; migrate this principal into identity.agents.`
|
|
536
|
-
);
|
|
537
|
-
return {
|
|
538
|
-
principalId: user2.defaultPrincipalId,
|
|
539
|
-
principalType: "service",
|
|
540
|
-
clerkId: actorId,
|
|
541
|
-
tenantId: user2.defaultTenantId,
|
|
542
|
-
workspaceId: user2.defaultWorkspaceId,
|
|
543
|
-
roles: ["service_agent"],
|
|
544
|
-
groupIds: normalizeGroupIds(resolvedUser2?.principalGroupIds),
|
|
545
|
-
isPlatformAdmin: false,
|
|
546
|
-
isTenantAdmin: false,
|
|
547
|
-
isWorkspaceAdmin: false,
|
|
548
|
-
isSystemFallback: false
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
const {
|
|
552
|
-
resolvedUser,
|
|
553
|
-
contextClerkId
|
|
554
|
-
} = await resolveCanonicalUserRecord(ctx, actorId);
|
|
555
|
-
const user = requireCanonicalResolvedUser(
|
|
556
|
-
resolvedUser,
|
|
557
|
-
contextClerkId
|
|
558
|
-
);
|
|
559
|
-
if (!user.defaultPrincipalId) {
|
|
560
|
-
throw new Error(
|
|
561
|
-
`[AccessControl] Canonical federated principal required for ${contextClerkId}. Re-sync Master Control identity before user-bound access checks.`
|
|
562
|
-
);
|
|
563
|
-
}
|
|
564
|
-
if (user.mcRole === "service_agent") {
|
|
565
|
-
return {
|
|
566
|
-
principalId: user.defaultPrincipalId,
|
|
567
|
-
principalType: "service",
|
|
568
|
-
clerkId: contextClerkId,
|
|
569
|
-
tenantId: user.defaultTenantId,
|
|
570
|
-
workspaceId: user.defaultWorkspaceId,
|
|
571
|
-
roles: ["service_agent"],
|
|
572
|
-
groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
|
|
573
|
-
isPlatformAdmin: false,
|
|
574
|
-
isTenantAdmin: false,
|
|
575
|
-
isWorkspaceAdmin: false,
|
|
576
|
-
isSystemFallback: false
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
const principalId = user.defaultPrincipalId;
|
|
580
|
-
const effectiveRole = user.mcRole;
|
|
581
|
-
const roles = effectiveRole === "platform_admin" ? ["platform_admin", "tenant_admin"] : effectiveRole === "tenant_admin" ? ["tenant_admin"] : [effectiveRole];
|
|
582
|
-
const tenantId = user.defaultTenantId;
|
|
583
|
-
const workspaceId = user.defaultWorkspaceId;
|
|
584
|
-
const isPlatformAdmin = effectiveRole === "platform_admin";
|
|
585
|
-
return {
|
|
586
|
-
principalId,
|
|
587
|
-
principalType: "user",
|
|
588
|
-
clerkId: contextClerkId,
|
|
589
|
-
tenantId,
|
|
590
|
-
workspaceId,
|
|
591
|
-
roles: uniqRoles(roles),
|
|
592
|
-
groupIds: normalizeGroupIds(resolvedUser?.principalGroupIds),
|
|
593
|
-
isPlatformAdmin,
|
|
594
|
-
isTenantAdmin: isPlatformAdmin || effectiveRole === "tenant_admin",
|
|
595
|
-
isWorkspaceAdmin: isPlatformAdmin || effectiveRole === "tenant_admin" || effectiveRole === "workspace_admin",
|
|
596
|
-
isSystemFallback: false
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// ../access-control/src/access.ts
|
|
601
|
-
function isTopicInPrincipalTenant(topic, principalTenantId) {
|
|
602
|
-
if (!topic.tenantId) {
|
|
603
|
-
return false;
|
|
604
|
-
}
|
|
605
|
-
if (!principalTenantId) {
|
|
606
|
-
return false;
|
|
607
|
-
}
|
|
608
|
-
return String(topic.tenantId) === String(principalTenantId);
|
|
609
|
-
}
|
|
610
|
-
function isTopicInPrincipalWorkspace(topic, principalWorkspaceId) {
|
|
611
|
-
if (!topic.workspaceId) {
|
|
612
|
-
return false;
|
|
613
|
-
}
|
|
614
|
-
if (!principalWorkspaceId) {
|
|
615
|
-
return false;
|
|
616
|
-
}
|
|
617
|
-
return String(topic.workspaceId) === String(principalWorkspaceId);
|
|
618
|
-
}
|
|
619
|
-
function isLegacyUnscopedTopic(topic) {
|
|
620
|
-
return !topic.tenantId || !topic.workspaceId;
|
|
621
|
-
}
|
|
622
|
-
function isGrantScopeAlignedToTopic(topic, grant) {
|
|
623
|
-
if (topic.tenantId && grant.tenantId && String(topic.tenantId) !== String(grant.tenantId)) {
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
if (topic.workspaceId && grant.workspaceId && String(topic.workspaceId) !== String(grant.workspaceId)) {
|
|
627
|
-
return false;
|
|
628
|
-
}
|
|
629
|
-
return true;
|
|
630
|
-
}
|
|
631
|
-
function isGrantSourceAllowedForVisibility(visibility, source) {
|
|
632
|
-
if (source !== "external_share") {
|
|
633
|
-
return true;
|
|
634
|
-
}
|
|
635
|
-
return visibility === "external" || visibility === "public";
|
|
636
|
-
}
|
|
637
|
-
function isGrantActive(grant) {
|
|
638
|
-
if (grant.status !== "active") {
|
|
639
|
-
return false;
|
|
640
|
-
}
|
|
641
|
-
if (grant.expiresAt !== void 0 && grant.expiresAt <= Date.now()) {
|
|
642
|
-
return false;
|
|
643
|
-
}
|
|
644
|
-
return true;
|
|
645
|
-
}
|
|
646
|
-
async function hasPrincipalGrant(ctx, args) {
|
|
647
|
-
const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndPrincipal(
|
|
648
|
-
ctx,
|
|
649
|
-
args.topic._id,
|
|
650
|
-
args.principalId
|
|
651
|
-
);
|
|
652
|
-
if (grants.some(
|
|
653
|
-
(grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
|
|
654
|
-
args.topic.visibility,
|
|
655
|
-
grant.source
|
|
656
|
-
) && (!args.principalIsExternal || args.topic.visibility === "public" || grant.source === "external_share")
|
|
657
|
-
)) {
|
|
658
|
-
return true;
|
|
659
|
-
}
|
|
660
|
-
return false;
|
|
661
|
-
}
|
|
662
|
-
async function hasGroupGrant(ctx, args) {
|
|
663
|
-
if (args.groupIds.length === 0) {
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
for (const groupId of args.groupIds) {
|
|
667
|
-
const grants = await resolveAccessControlAppResolvers().listProjectGrantsByProjectAndGroup(ctx, args.topic._id, groupId);
|
|
668
|
-
if (grants.some(
|
|
669
|
-
(grant) => isGrantActive(grant) && isGrantScopeAlignedToTopic(args.topic, grant) && isGrantSourceAllowedForVisibility(
|
|
670
|
-
args.topic.visibility,
|
|
671
|
-
grant.source
|
|
672
|
-
)
|
|
673
|
-
)) {
|
|
674
|
-
return true;
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
return false;
|
|
678
|
-
}
|
|
679
|
-
function isExternalPrincipal(_ctx, _args) {
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
async function evaluateTopicAccessDetailed(ctx, args) {
|
|
683
|
-
if (args.legacyUserId) {
|
|
684
|
-
return {
|
|
685
|
-
hasAccess: true,
|
|
686
|
-
isAdmin: false,
|
|
687
|
-
isOwner: false,
|
|
688
|
-
isShared: false,
|
|
689
|
-
hasGrant: true,
|
|
690
|
-
isFirmVisible: true,
|
|
691
|
-
isExternalVisible: false,
|
|
692
|
-
isPublicVisible: false,
|
|
693
|
-
isTenantScopeMatch: true,
|
|
694
|
-
isWorkspaceScopeMatch: true,
|
|
695
|
-
isPrincipalExternal: false
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
const topic = await resolveAccessControlAppResolvers().getProject(
|
|
699
|
-
ctx,
|
|
700
|
-
args.topicId
|
|
701
|
-
);
|
|
702
|
-
if (!topic) {
|
|
703
|
-
return {
|
|
704
|
-
hasAccess: false,
|
|
705
|
-
isAdmin: false,
|
|
706
|
-
isOwner: false,
|
|
707
|
-
isShared: false,
|
|
708
|
-
hasGrant: false,
|
|
709
|
-
isFirmVisible: false,
|
|
710
|
-
isExternalVisible: false,
|
|
711
|
-
isPublicVisible: false,
|
|
712
|
-
isTenantScopeMatch: false,
|
|
713
|
-
isWorkspaceScopeMatch: false,
|
|
714
|
-
isPrincipalExternal: false
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
const { principalContext, legacyUserId } = args;
|
|
718
|
-
const userIsAdmin = principalContext.isPlatformAdmin;
|
|
719
|
-
const isOwner = topic.ownerId === legacyUserId;
|
|
720
|
-
const isShared = (topic.sharedWith ?? []).includes(legacyUserId);
|
|
721
|
-
const principalIsExternal = await isExternalPrincipal(ctx, {
|
|
722
|
-
groupIds: principalContext.groupIds,
|
|
723
|
-
topicTenantId: topic.tenantId,
|
|
724
|
-
topicWorkspaceId: topic.workspaceId
|
|
725
|
-
});
|
|
726
|
-
const hasPrincipalGrantResult = await hasPrincipalGrant(ctx, {
|
|
727
|
-
topic,
|
|
728
|
-
principalId: principalContext.principalId,
|
|
729
|
-
principalIsExternal
|
|
730
|
-
});
|
|
731
|
-
const hasGroupGrantResult = await hasGroupGrant(ctx, {
|
|
732
|
-
topic,
|
|
733
|
-
groupIds: principalContext.groupIds
|
|
734
|
-
});
|
|
735
|
-
const hasGrant = isShared || hasPrincipalGrantResult || hasGroupGrantResult;
|
|
736
|
-
const legacyUnscoped = isLegacyUnscopedTopic(topic);
|
|
737
|
-
const tenantScopeMatch = isTopicInPrincipalTenant(
|
|
738
|
-
topic,
|
|
739
|
-
principalContext.tenantId
|
|
740
|
-
);
|
|
741
|
-
const workspaceScopeMatch = isTopicInPrincipalWorkspace(
|
|
742
|
-
topic,
|
|
743
|
-
principalContext.workspaceId
|
|
744
|
-
);
|
|
745
|
-
const isPublicVisible = topic.visibility === "public";
|
|
746
|
-
const isFirmVisible = topic.visibility === "firm" && !legacyUnscoped && tenantScopeMatch && workspaceScopeMatch && !principalIsExternal;
|
|
747
|
-
const hasScopedGrant = hasGrant && (legacyUnscoped || tenantScopeMatch && workspaceScopeMatch);
|
|
748
|
-
const isExternalVisible = topic.visibility === "external" && hasScopedGrant;
|
|
749
|
-
const hasAccess = userIsAdmin || isOwner || hasScopedGrant || isPublicVisible || isFirmVisible;
|
|
750
|
-
return {
|
|
751
|
-
hasAccess,
|
|
752
|
-
isAdmin: userIsAdmin,
|
|
753
|
-
isOwner,
|
|
754
|
-
isShared,
|
|
755
|
-
hasGrant,
|
|
756
|
-
isFirmVisible,
|
|
757
|
-
isExternalVisible,
|
|
758
|
-
isPublicVisible,
|
|
759
|
-
isTenantScopeMatch: tenantScopeMatch,
|
|
760
|
-
isWorkspaceScopeMatch: workspaceScopeMatch,
|
|
761
|
-
isPrincipalExternal: principalIsExternal
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
async function checkTopicAccessDetailed(ctx, topicId, userId) {
|
|
765
|
-
const principalContext = await resolvePrincipalContext(ctx, userId);
|
|
766
|
-
return evaluateTopicAccessDetailed(ctx, {
|
|
767
|
-
topicId,
|
|
768
|
-
legacyUserId: userId,
|
|
769
|
-
principalContext
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
async function checkTopicAccess(ctx, topicId, userId) {
|
|
773
|
-
const result = await checkTopicAccessDetailed(ctx, topicId, userId);
|
|
774
|
-
return result.hasAccess;
|
|
775
|
-
}
|
|
776
|
-
async function checkScopeAccess(ctx, scopeId, userId) {
|
|
777
|
-
try {
|
|
778
|
-
const topic = await ctx.db.get(scopeId);
|
|
779
|
-
if (topic && topic.name !== void 0 && topic.type !== void 0) {
|
|
780
|
-
return true;
|
|
781
|
-
}
|
|
782
|
-
} catch {
|
|
783
|
-
}
|
|
784
|
-
try {
|
|
785
|
-
return await checkTopicAccess(ctx, scopeId, userId);
|
|
786
|
-
} catch {
|
|
787
|
-
return false;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
var checkProjectAccess = checkTopicAccess;
|
|
791
|
-
|
|
792
|
-
// ../access-control/src/auth.ts
|
|
793
|
-
async function getCurrentUserId(ctx) {
|
|
794
|
-
const identity = await ctx.auth.getUserIdentity();
|
|
795
|
-
return identity?.subject ?? null;
|
|
796
|
-
}
|
|
797
|
-
var permissiveReturn = v.optional(v.any());
|
|
798
|
-
var looseJsonObject = v.record(v.string(), v.any());
|
|
799
|
-
var looseJsonArray = v.array(v.any());
|
|
800
|
-
v.union(
|
|
801
|
-
v.string(),
|
|
802
|
-
v.number(),
|
|
803
|
-
v.boolean(),
|
|
804
|
-
v.null(),
|
|
805
|
-
looseJsonObject,
|
|
806
|
-
looseJsonArray
|
|
807
|
-
);
|
|
808
|
-
var api2 = anyApi;
|
|
809
|
-
componentsGeneric();
|
|
810
|
-
var internal = anyApi;
|
|
811
|
-
var internalMutation = internalMutationGeneric;
|
|
812
|
-
var internalQuery = internalQueryGeneric;
|
|
813
|
-
var mutation = mutationGeneric;
|
|
814
|
-
var query = queryGeneric;
|
|
815
|
-
|
|
816
|
-
// ../confidence/src/v1/operations/subjectiveLogic/index.ts
|
|
817
|
-
function opinion(belief, disbelief, uncertainty, baseRate = 0.5) {
|
|
818
|
-
const b = Math.max(0, Math.min(1, belief));
|
|
819
|
-
const d = Math.max(0, Math.min(1, disbelief));
|
|
820
|
-
const u = Math.max(0, Math.min(1, uncertainty));
|
|
821
|
-
const a = Math.max(0, Math.min(1, baseRate));
|
|
822
|
-
const sum = b + d + u;
|
|
823
|
-
if (sum === 0) {
|
|
824
|
-
return { b: 0, d: 0, u: 1, a };
|
|
825
|
-
}
|
|
826
|
-
return {
|
|
827
|
-
b: b / sum,
|
|
828
|
-
d: d / sum,
|
|
829
|
-
u: u / sum,
|
|
830
|
-
a
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
function vacuous(baseRate = 0.5) {
|
|
834
|
-
return { b: 0, d: 0, u: 1, a: baseRate };
|
|
835
|
-
}
|
|
836
|
-
function project(o) {
|
|
837
|
-
return o.b + o.a * o.u;
|
|
838
|
-
}
|
|
839
|
-
function cumulativeFusion(left, right) {
|
|
840
|
-
if (left.u === 0 && right.u === 0) {
|
|
841
|
-
return opinion(
|
|
842
|
-
(left.b + right.b) / 2,
|
|
843
|
-
(left.d + right.d) / 2,
|
|
844
|
-
0,
|
|
845
|
-
(left.a + right.a) / 2
|
|
846
|
-
);
|
|
847
|
-
}
|
|
848
|
-
const k = left.u + right.u - left.u * right.u;
|
|
849
|
-
if (k === 0) {
|
|
850
|
-
return vacuous((left.a + right.a) / 2);
|
|
851
|
-
}
|
|
852
|
-
return opinion(
|
|
853
|
-
(left.b * right.u + right.b * left.u) / k,
|
|
854
|
-
(left.d * right.u + right.d * left.u) / k,
|
|
855
|
-
left.u * right.u / k,
|
|
856
|
-
(left.a + right.a) / 2
|
|
857
|
-
);
|
|
858
|
-
}
|
|
859
|
-
function trustDiscount(sourceOpinion, trust) {
|
|
860
|
-
const weight = Math.max(0, Math.min(1, Math.abs(trust)));
|
|
861
|
-
return opinion(
|
|
862
|
-
weight * sourceOpinion.b,
|
|
863
|
-
weight * sourceOpinion.d,
|
|
864
|
-
1 - weight * (sourceOpinion.b + sourceOpinion.d),
|
|
865
|
-
sourceOpinion.a
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
var EPSILON = 1e-9;
|
|
869
|
-
function childBaseRateFallback(ifTrue, ifFalse, fallbackBaseRate) {
|
|
870
|
-
if (fallbackBaseRate !== void 0) {
|
|
871
|
-
return Math.max(0, Math.min(1, fallbackBaseRate));
|
|
872
|
-
}
|
|
873
|
-
if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {
|
|
874
|
-
return ifTrue.a;
|
|
875
|
-
}
|
|
876
|
-
return (ifTrue.a + ifFalse.a) / 2;
|
|
877
|
-
}
|
|
878
|
-
function computeConditionalDeductionBaseRate(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
|
|
879
|
-
const denominator = 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;
|
|
880
|
-
if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {
|
|
881
|
-
const baseRate = (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;
|
|
882
|
-
if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {
|
|
883
|
-
return Math.max(0, Math.min(1, baseRate));
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
return fallbackBaseRate;
|
|
887
|
-
}
|
|
888
|
-
function safeCorrectionTerm(numerator, denominator) {
|
|
889
|
-
if (Math.abs(denominator) <= EPSILON) {
|
|
890
|
-
return void 0;
|
|
891
|
-
}
|
|
892
|
-
const value = numerator / denominator;
|
|
893
|
-
if (!Number.isFinite(value)) {
|
|
894
|
-
return void 0;
|
|
895
|
-
}
|
|
896
|
-
return Math.max(0, value);
|
|
897
|
-
}
|
|
898
|
-
function conditionalDeduction(opinionA, ifTrue, ifFalse, fallbackBaseRate) {
|
|
899
|
-
const fallbackChildBaseRate = childBaseRateFallback(
|
|
900
|
-
ifTrue,
|
|
901
|
-
ifFalse,
|
|
902
|
-
fallbackBaseRate
|
|
903
|
-
);
|
|
904
|
-
const childBaseRate = computeConditionalDeductionBaseRate(
|
|
905
|
-
opinionA,
|
|
906
|
-
ifTrue,
|
|
907
|
-
ifFalse,
|
|
908
|
-
fallbackChildBaseRate
|
|
909
|
-
);
|
|
910
|
-
const projectedAntecedent = project(opinionA);
|
|
911
|
-
const projectedAntecedentComplement = 1 - projectedAntecedent;
|
|
912
|
-
const intermediateBelief = opinionA.b * ifTrue.b + opinionA.d * ifFalse.b + opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));
|
|
913
|
-
const intermediateDisbelief = opinionA.b * ifTrue.d + opinionA.d * ifFalse.d + opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));
|
|
914
|
-
const intermediateUncertainty = opinionA.b * ifTrue.u + opinionA.d * ifFalse.u + opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
|
|
915
|
-
const projectedVacuousDeduction = ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a) + childBaseRate * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));
|
|
916
|
-
const projectedConditionalA = ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);
|
|
917
|
-
let correction = 0;
|
|
918
|
-
if (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d || ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d) {
|
|
919
|
-
correction = 0;
|
|
920
|
-
} else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {
|
|
921
|
-
const beliefGap = ifTrue.b - ifFalse.b;
|
|
922
|
-
const disbeliefGap = ifFalse.d - ifTrue.d;
|
|
923
|
-
if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
|
|
924
|
-
correction = safeCorrectionTerm(
|
|
925
|
-
opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),
|
|
926
|
-
projectedAntecedent * childBaseRate
|
|
927
|
-
) ?? 0;
|
|
928
|
-
} else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
|
|
929
|
-
correction = safeCorrectionTerm(
|
|
930
|
-
opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
|
|
931
|
-
projectedAntecedentComplement * childBaseRate * disbeliefGap
|
|
932
|
-
) ?? 0;
|
|
933
|
-
} else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
|
|
934
|
-
correction = safeCorrectionTerm(
|
|
935
|
-
(1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
|
|
936
|
-
projectedAntecedent * (1 - childBaseRate) * beliefGap
|
|
937
|
-
) ?? 0;
|
|
938
|
-
} else {
|
|
939
|
-
correction = safeCorrectionTerm(
|
|
940
|
-
(1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),
|
|
941
|
-
projectedAntecedentComplement * (1 - childBaseRate)
|
|
942
|
-
) ?? 0;
|
|
943
|
-
}
|
|
944
|
-
} else {
|
|
945
|
-
const beliefGap = ifFalse.b - ifTrue.b;
|
|
946
|
-
const disbeliefGap = ifTrue.d - ifFalse.d;
|
|
947
|
-
if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent <= opinionA.a) {
|
|
948
|
-
correction = safeCorrectionTerm(
|
|
949
|
-
(1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,
|
|
950
|
-
projectedAntecedent * childBaseRate * disbeliefGap
|
|
951
|
-
) ?? 0;
|
|
952
|
-
} else if (projectedVacuousDeduction <= projectedConditionalA && projectedAntecedent > opinionA.a) {
|
|
953
|
-
correction = safeCorrectionTerm(
|
|
954
|
-
(1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),
|
|
955
|
-
projectedAntecedentComplement * childBaseRate
|
|
956
|
-
) ?? 0;
|
|
957
|
-
} else if (projectedVacuousDeduction > projectedConditionalA && projectedAntecedent <= opinionA.a) {
|
|
958
|
-
correction = safeCorrectionTerm(
|
|
959
|
-
opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),
|
|
960
|
-
projectedAntecedent * (1 - childBaseRate)
|
|
961
|
-
) ?? 0;
|
|
962
|
-
} else {
|
|
963
|
-
correction = safeCorrectionTerm(
|
|
964
|
-
opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b) * disbeliefGap,
|
|
965
|
-
projectedAntecedentComplement * (1 - childBaseRate) * beliefGap
|
|
966
|
-
) ?? 0;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
return opinion(
|
|
970
|
-
intermediateBelief - childBaseRate * correction,
|
|
971
|
-
intermediateDisbelief - (1 - childBaseRate) * correction,
|
|
972
|
-
intermediateUncertainty + correction,
|
|
973
|
-
childBaseRate
|
|
974
|
-
);
|
|
975
|
-
}
|
|
976
|
-
function negate(o) {
|
|
977
|
-
return { b: o.d, d: o.b, u: o.u, a: 1 - o.a };
|
|
978
|
-
}
|
|
979
|
-
function constraintFusion(left, right, mode = "pressure") {
|
|
980
|
-
if (mode === "redistribute") {
|
|
981
|
-
const leftProjected = project(left);
|
|
982
|
-
const rightProjected = project(right);
|
|
983
|
-
const total = leftProjected + rightProjected;
|
|
984
|
-
if (total <= 1) {
|
|
985
|
-
return { o1: left, o2: right };
|
|
986
|
-
}
|
|
987
|
-
const scale = 1 / total;
|
|
988
|
-
return {
|
|
989
|
-
o1: opinion(
|
|
990
|
-
left.b * scale,
|
|
991
|
-
left.d + left.b * (1 - scale),
|
|
992
|
-
left.u,
|
|
993
|
-
left.a
|
|
994
|
-
),
|
|
995
|
-
o2: opinion(
|
|
996
|
-
right.b * scale,
|
|
997
|
-
right.d + right.b * (1 - scale),
|
|
998
|
-
right.u,
|
|
999
|
-
right.a
|
|
1000
|
-
)
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
const pressureLeft = right.b * 0.5;
|
|
1004
|
-
const pressureRight = left.b * 0.5;
|
|
1005
|
-
return {
|
|
1006
|
-
o1: opinion(
|
|
1007
|
-
left.b - pressureLeft * 0.3,
|
|
1008
|
-
left.d + pressureLeft * 0.3,
|
|
1009
|
-
left.u,
|
|
1010
|
-
left.a
|
|
1011
|
-
),
|
|
1012
|
-
o2: opinion(
|
|
1013
|
-
right.b - pressureRight * 0.3,
|
|
1014
|
-
right.d + pressureRight * 0.3,
|
|
1015
|
-
right.u,
|
|
1016
|
-
right.a
|
|
1017
|
-
)
|
|
1018
|
-
};
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// ../confidence/src/v1/operations/scoring.ts
|
|
1022
|
-
function finiteNumber(value) {
|
|
1023
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1024
|
-
}
|
|
1025
|
-
function clamp01(value) {
|
|
1026
|
-
return Math.max(0, Math.min(1, value));
|
|
1027
|
-
}
|
|
1028
|
-
function confidenceFromOpinion(opinion2) {
|
|
1029
|
-
return clamp01(opinion2.b + opinion2.a * opinion2.u);
|
|
1030
|
-
}
|
|
1031
|
-
function confidenceFromSL(belief, _disbelief, uncertainty, baseRate = 0.5) {
|
|
1032
|
-
return confidenceFromOpinion({
|
|
1033
|
-
b: belief,
|
|
1034
|
-
u: uncertainty,
|
|
1035
|
-
a: baseRate
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
|
-
function readOpinionFromRecord(source, fallback = {}) {
|
|
1039
|
-
const record = source && typeof source === "object" ? source : {};
|
|
1040
|
-
return {
|
|
1041
|
-
b: finiteNumber(record.b) ?? finiteNumber(record.belief) ?? finiteNumber(record.slBelief) ?? finiteNumber(record.opinion_b) ?? fallback.b ?? 0,
|
|
1042
|
-
d: finiteNumber(record.d) ?? finiteNumber(record.disbelief) ?? finiteNumber(record.slDisbelief) ?? finiteNumber(record.opinion_d) ?? fallback.d ?? 0,
|
|
1043
|
-
u: finiteNumber(record.u) ?? finiteNumber(record.uncertainty) ?? finiteNumber(record.slUncertainty) ?? finiteNumber(record.opinion_u) ?? fallback.u ?? 1,
|
|
1044
|
-
a: finiteNumber(record.a) ?? finiteNumber(record.baseRate) ?? finiteNumber(record.slBaseRate) ?? finiteNumber(record.opinion_a) ?? fallback.a ?? 0.5
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
function hasProjectedOpinionChanged(current, next, tolerance = 0.01) {
|
|
1048
|
-
return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >= tolerance;
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
// ../confidence/src/v1/operations/contradiction/detectTupleContradiction.ts
|
|
1052
|
-
var DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD = 0.7;
|
|
1053
|
-
var DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD = 0.7;
|
|
1054
|
-
function normalizeTupleContradictionPolicy(policy = {}) {
|
|
1055
|
-
return {
|
|
1056
|
-
beliefThreshold: clamp01(
|
|
1057
|
-
policy.beliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD
|
|
1058
|
-
),
|
|
1059
|
-
disbeliefThreshold: clamp01(
|
|
1060
|
-
policy.disbeliefThreshold ?? DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD
|
|
1061
|
-
)
|
|
1062
|
-
};
|
|
1063
|
-
}
|
|
1064
|
-
function detectTupleContradiction(opinion2, tauB = DEFAULT_TUPLE_CONTRADICTION_BELIEF_THRESHOLD, tauD = DEFAULT_TUPLE_CONTRADICTION_DISBELIEF_THRESHOLD) {
|
|
1065
|
-
return opinion2.b > tauB && opinion2.d > tauD;
|
|
1066
|
-
}
|
|
1067
|
-
function evaluateTupleContradictionTransition(args) {
|
|
1068
|
-
const policy = normalizeTupleContradictionPolicy(args.policy);
|
|
1069
|
-
const tupleContradicted = detectTupleContradiction(
|
|
1070
|
-
args.opinion,
|
|
1071
|
-
policy.beliefThreshold,
|
|
1072
|
-
policy.disbeliefThreshold
|
|
1073
|
-
);
|
|
1074
|
-
const previousTupleContradicted = Boolean(args.previousTupleContradicted);
|
|
1075
|
-
return {
|
|
1076
|
-
tupleContradicted,
|
|
1077
|
-
crossedIntoTupleContradiction: !previousTupleContradicted && tupleContradicted,
|
|
1078
|
-
crossedOutOfTupleContradiction: previousTupleContradicted && !tupleContradicted,
|
|
1079
|
-
policy
|
|
1080
|
-
};
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
// ../confidence/src/v1/operations/dynamics/cascade.ts
|
|
1084
|
-
function dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode = "continuous", threshold = 0.3) {
|
|
1085
|
-
const dependencyProjection = project(dependencyOpinion);
|
|
1086
|
-
if (mode === "threshold") {
|
|
1087
|
-
if (dependencyProjection < threshold) {
|
|
1088
|
-
return opinion(
|
|
1089
|
-
0,
|
|
1090
|
-
beliefOpinion.d + beliefOpinion.b * 0.5,
|
|
1091
|
-
0.5,
|
|
1092
|
-
beliefOpinion.a
|
|
1093
|
-
);
|
|
1094
|
-
}
|
|
1095
|
-
return beliefOpinion;
|
|
1096
|
-
}
|
|
1097
|
-
const dampingFactor = Math.pow(dependencyProjection, 0.5);
|
|
1098
|
-
return opinion(
|
|
1099
|
-
beliefOpinion.b * dampingFactor,
|
|
1100
|
-
beliefOpinion.d + beliefOpinion.b * (1 - dampingFactor) * 0.3,
|
|
1101
|
-
beliefOpinion.u + beliefOpinion.b * (1 - dampingFactor) * 0.7,
|
|
1102
|
-
beliefOpinion.a
|
|
1103
|
-
);
|
|
1104
|
-
}
|
|
1105
|
-
function dampedDependencyCascade(dependencyOpinion, beliefOpinion, mode = "continuous") {
|
|
1106
|
-
return {
|
|
1107
|
-
opinion: dampedDependencyOpinion(dependencyOpinion, beliefOpinion, mode),
|
|
1108
|
-
operator: "dependency_cascade",
|
|
1109
|
-
rationale: `Damped dependency cascade (${mode}): prerequisite at ${project(
|
|
1110
|
-
dependencyOpinion
|
|
1111
|
-
).toFixed(2)}`
|
|
1112
|
-
};
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
// ../confidence/src/v1/operations/dynamics/defeat.ts
|
|
1116
|
-
function applyNegativeSupport(source, target, weight, metadata = {}) {
|
|
1117
|
-
if (metadata.constraint === "xor") {
|
|
1118
|
-
const result = constraintFusion(
|
|
1119
|
-
source,
|
|
1120
|
-
target,
|
|
1121
|
-
metadata.normalization ?? "pressure"
|
|
1122
|
-
);
|
|
1123
|
-
return {
|
|
1124
|
-
opinion: result.o2,
|
|
1125
|
-
operator: "constraint_fusion",
|
|
1126
|
-
rationale: `XOR constraint: source belief at ${project(source).toFixed(
|
|
1127
|
-
2
|
|
1128
|
-
)} pressures target`
|
|
1129
|
-
};
|
|
1130
|
-
}
|
|
1131
|
-
const discounted = trustDiscount(negate(source), Math.abs(weight));
|
|
1132
|
-
return {
|
|
1133
|
-
opinion: cumulativeFusion(target, discounted),
|
|
1134
|
-
operator: "cumulative_fusion",
|
|
1135
|
-
rationale: `Contradicting evidence (weight=${weight.toFixed(
|
|
1136
|
-
2
|
|
1137
|
-
)}) from source at ${project(source).toFixed(2)}`
|
|
1138
|
-
};
|
|
1139
|
-
}
|
|
1140
|
-
function applyNegativeEvidence(source, target, weight) {
|
|
1141
|
-
const discounted = trustDiscount(negate(source), Math.abs(weight));
|
|
1142
|
-
return {
|
|
1143
|
-
opinion: cumulativeFusion(target, discounted),
|
|
1144
|
-
operator: "cumulative_fusion",
|
|
1145
|
-
rationale: `Contradicting evidence (weight=${weight.toFixed(2)})`
|
|
1146
|
-
};
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
// ../confidence/src/v1/operations/contracts/epistemicContract.ts
|
|
1150
|
-
var BUILT_IN_METRIC_CHECKER = "metric_checker";
|
|
1151
|
-
var BUILT_IN_REFERENCE_CHECK_COUNTER = "reference_check_counter";
|
|
1152
|
-
var BUILT_IN_MARKET_INDEX_COMPARATOR = "market_index_comparator";
|
|
1153
|
-
function clampConfidence(value) {
|
|
1154
|
-
return Math.max(0, Math.min(1, value));
|
|
1155
|
-
}
|
|
1156
|
-
function generateContractId() {
|
|
1157
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
1158
|
-
return crypto.randomUUID();
|
|
1159
|
-
}
|
|
1160
|
-
return `contract-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1161
|
-
}
|
|
1162
|
-
function deriveContractStatus(result, currentStatus) {
|
|
1163
|
-
if (currentStatus === "archived") {
|
|
1164
|
-
return currentStatus;
|
|
1165
|
-
}
|
|
1166
|
-
switch (result) {
|
|
1167
|
-
case "confirmed":
|
|
1168
|
-
return "satisfied";
|
|
1169
|
-
case "disconfirmed":
|
|
1170
|
-
return "violated";
|
|
1171
|
-
case "expired":
|
|
1172
|
-
return "expired";
|
|
1173
|
-
default:
|
|
1174
|
-
return currentStatus === "satisfied" || currentStatus === "violated" || currentStatus === "expired" ? "active" : currentStatus;
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
function deriveVerificationTrigger(result) {
|
|
1178
|
-
switch (result) {
|
|
1179
|
-
case "confirmed":
|
|
1180
|
-
return "verification_confirmed";
|
|
1181
|
-
case "disconfirmed":
|
|
1182
|
-
return "verification_disconfirmed";
|
|
1183
|
-
case "expired":
|
|
1184
|
-
return "verification_expired";
|
|
1185
|
-
case "partial":
|
|
1186
|
-
return "verification_partial";
|
|
1187
|
-
default:
|
|
1188
|
-
return null;
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
function deriveContractModulationPlan(args) {
|
|
1192
|
-
const trigger = deriveVerificationTrigger(args.result);
|
|
1193
|
-
if (!trigger) {
|
|
1194
|
-
return null;
|
|
1195
|
-
}
|
|
1196
|
-
if (args.result === "confirmed") {
|
|
1197
|
-
const rawNext = args.currentConfidence + args.modulation.onConfirmed.delta;
|
|
1198
|
-
const confidenceAfter = clampConfidence(
|
|
1199
|
-
Math.min(
|
|
1200
|
-
args.modulation.onConfirmed.ceiling ?? Number.POSITIVE_INFINITY,
|
|
1201
|
-
rawNext
|
|
1202
|
-
)
|
|
1203
|
-
);
|
|
1204
|
-
return {
|
|
1205
|
-
trigger,
|
|
1206
|
-
confidenceBefore: args.currentConfidence,
|
|
1207
|
-
confidenceAfter,
|
|
1208
|
-
confidenceDelta: confidenceAfter - args.currentConfidence
|
|
1209
|
-
};
|
|
1210
|
-
}
|
|
1211
|
-
if (args.result === "disconfirmed") {
|
|
1212
|
-
const rawNext = args.currentConfidence + args.modulation.onDisconfirmed.delta;
|
|
1213
|
-
const confidenceAfter = clampConfidence(
|
|
1214
|
-
Math.max(args.modulation.onDisconfirmed.floor ?? 0, rawNext)
|
|
1215
|
-
);
|
|
1216
|
-
return {
|
|
1217
|
-
trigger,
|
|
1218
|
-
confidenceBefore: args.currentConfidence,
|
|
1219
|
-
confidenceAfter,
|
|
1220
|
-
confidenceDelta: confidenceAfter - args.currentConfidence
|
|
1221
|
-
};
|
|
1222
|
-
}
|
|
1223
|
-
if (args.result === "expired" && args.modulation.onExpired) {
|
|
1224
|
-
const confidenceAfter = clampConfidence(
|
|
1225
|
-
args.currentConfidence + args.modulation.onExpired.delta
|
|
1226
|
-
);
|
|
1227
|
-
return {
|
|
1228
|
-
trigger,
|
|
1229
|
-
confidenceBefore: args.currentConfidence,
|
|
1230
|
-
confidenceAfter,
|
|
1231
|
-
confidenceDelta: confidenceAfter - args.currentConfidence
|
|
1232
|
-
};
|
|
1233
|
-
}
|
|
1234
|
-
if (args.result === "partial" && args.modulation.onPartial) {
|
|
1235
|
-
if ((args.resultConfidence ?? 0) < args.modulation.onPartial.threshold) {
|
|
1236
|
-
return null;
|
|
1237
|
-
}
|
|
1238
|
-
const confidenceAfter = clampConfidence(
|
|
1239
|
-
args.currentConfidence + args.modulation.onPartial.delta
|
|
1240
|
-
);
|
|
1241
|
-
return {
|
|
1242
|
-
trigger,
|
|
1243
|
-
confidenceBefore: args.currentConfidence,
|
|
1244
|
-
confidenceAfter,
|
|
1245
|
-
confidenceDelta: confidenceAfter - args.currentConfidence
|
|
1246
|
-
};
|
|
1247
|
-
}
|
|
1248
|
-
return null;
|
|
1249
|
-
}
|
|
1250
|
-
function createInheritedContractRecord(contract, args) {
|
|
1251
|
-
return {
|
|
1252
|
-
beliefNodeId: args.beliefNodeId,
|
|
1253
|
-
contractId: generateContractId(),
|
|
1254
|
-
title: contract.title,
|
|
1255
|
-
description: contract.description,
|
|
1256
|
-
conditionType: contract.conditionType,
|
|
1257
|
-
direction: contract.direction,
|
|
1258
|
-
condition: contract.condition,
|
|
1259
|
-
deadline: contract.deadline,
|
|
1260
|
-
compositeOf: contract.compositeOf,
|
|
1261
|
-
compositeOperator: contract.compositeOperator,
|
|
1262
|
-
modulation: contract.modulation,
|
|
1263
|
-
evaluationSchedule: contract.evaluationSchedule,
|
|
1264
|
-
periodicIntervalMs: contract.periodicIntervalMs,
|
|
1265
|
-
status: "active",
|
|
1266
|
-
lineageSource: "inherited",
|
|
1267
|
-
inheritedFromContractId: contract.contractId,
|
|
1268
|
-
inheritedFromBeliefNodeId: contract.beliefNodeId,
|
|
1269
|
-
inheritedAt: args.now,
|
|
1270
|
-
topicId: args.topicId,
|
|
1271
|
-
createdAt: args.now,
|
|
1272
|
-
createdBy: args.createdBy,
|
|
1273
|
-
updatedAt: args.now
|
|
1274
|
-
};
|
|
1275
|
-
}
|
|
1276
|
-
function normalizeEvidentialAction(value) {
|
|
1277
|
-
return value === "modulate_confidence" || value === "flag_review" || value === "archive" ? value : void 0;
|
|
1278
|
-
}
|
|
1279
|
-
function parseComparisonOperator(value, evaluatorName) {
|
|
1280
|
-
if (value === "gte" || value === "lte" || value === "eq" || value === "gt" || value === "lt") {
|
|
1281
|
-
return value;
|
|
1282
|
-
}
|
|
1283
|
-
throw new Error(
|
|
1284
|
-
`${evaluatorName} requires operator to be one of gte, lte, eq, gt, or lt.`
|
|
1285
|
-
);
|
|
1286
|
-
}
|
|
1287
|
-
function parseNumericThreshold(value, evaluatorName) {
|
|
1288
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1289
|
-
return value;
|
|
1290
|
-
}
|
|
1291
|
-
throw new Error(`${evaluatorName} requires a finite numeric threshold.`);
|
|
1292
|
-
}
|
|
1293
|
-
function pickFiniteNumber(config, keys) {
|
|
1294
|
-
for (const key of keys) {
|
|
1295
|
-
const value = config[key];
|
|
1296
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1297
|
-
return value;
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
return void 0;
|
|
1301
|
-
}
|
|
1302
|
-
function getEvaluatorInputRecord(inputData, nestedKey) {
|
|
1303
|
-
if (!inputData || typeof inputData !== "object") {
|
|
1304
|
-
return {};
|
|
1305
|
-
}
|
|
1306
|
-
const root = inputData;
|
|
1307
|
-
const nested = root[nestedKey];
|
|
1308
|
-
if (nested && typeof nested === "object") {
|
|
1309
|
-
return nested;
|
|
1310
|
-
}
|
|
1311
|
-
return root;
|
|
1312
|
-
}
|
|
1313
|
-
function parseEvidentialEvaluatorConfig(value) {
|
|
1314
|
-
if (!value || typeof value !== "object") {
|
|
1315
|
-
throw new Error(
|
|
1316
|
-
"Evidential contracts require condition.evaluatorConfig with metric/operator/threshold."
|
|
1317
|
-
);
|
|
1318
|
-
}
|
|
1319
|
-
const config = value;
|
|
1320
|
-
const metric = config.metric;
|
|
1321
|
-
const operator = config.operator;
|
|
1322
|
-
const threshold = config.threshold;
|
|
1323
|
-
if (metric !== "evidence_count" && metric !== "contradiction_status" && metric !== "edge_freshness" && metric !== "dependent_count") {
|
|
1324
|
-
throw new Error(`Unsupported evidential metric: ${String(metric)}`);
|
|
1325
|
-
}
|
|
1326
|
-
if (operator !== "gte" && operator !== "lte" && operator !== "eq" && operator !== "gt" && operator !== "lt") {
|
|
1327
|
-
throw new Error(`Unsupported evidential operator: ${String(operator)}`);
|
|
1328
|
-
}
|
|
1329
|
-
if (typeof threshold !== "number" || !Number.isFinite(threshold)) {
|
|
1330
|
-
throw new Error("Evidential contracts require a numeric threshold.");
|
|
1331
|
-
}
|
|
1332
|
-
const actionParams = config.actionParams && typeof config.actionParams === "object" && config.actionParams !== null ? config.actionParams : void 0;
|
|
1333
|
-
return {
|
|
1334
|
-
metric,
|
|
1335
|
-
operator,
|
|
1336
|
-
threshold,
|
|
1337
|
-
action: normalizeEvidentialAction(config.action),
|
|
1338
|
-
actionParams: actionParams && (typeof actionParams.targetConfidence === "number" || typeof actionParams.rationale === "string") ? {
|
|
1339
|
-
targetConfidence: typeof actionParams.targetConfidence === "number" ? actionParams.targetConfidence : void 0,
|
|
1340
|
-
rationale: typeof actionParams.rationale === "string" ? actionParams.rationale : void 0
|
|
1341
|
-
} : void 0
|
|
1342
|
-
};
|
|
1343
|
-
}
|
|
1344
|
-
function compareMetricValue(operator, left, right) {
|
|
1345
|
-
switch (operator) {
|
|
1346
|
-
case "gte":
|
|
1347
|
-
return left >= right;
|
|
1348
|
-
case "lte":
|
|
1349
|
-
return left <= right;
|
|
1350
|
-
case "eq":
|
|
1351
|
-
return left === right;
|
|
1352
|
-
case "gt":
|
|
1353
|
-
return left > right;
|
|
1354
|
-
case "lt":
|
|
1355
|
-
return left < right;
|
|
1356
|
-
default:
|
|
1357
|
-
return false;
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
function resolveComparisonResult(direction, comparisonSatisfied) {
|
|
1361
|
-
return direction === "falsifies" ? comparisonSatisfied ? "disconfirmed" : "confirmed" : comparisonSatisfied ? "confirmed" : "disconfirmed";
|
|
1362
|
-
}
|
|
1363
|
-
function buildComparisonRationale(args) {
|
|
1364
|
-
const renderedObserved = args.observedValue === null ? "no data" : `${args.observedValue}${args.unit ? ` ${args.unit}` : ""}`;
|
|
1365
|
-
const renderedThreshold = `${args.threshold}${args.unit ? ` ${args.unit}` : ""}`;
|
|
1366
|
-
const clause = `${args.label} observed ${renderedObserved} against ${args.operator} ${renderedThreshold}`;
|
|
1367
|
-
if (args.observedValue === null) {
|
|
1368
|
-
return `${clause}; evaluator returned ${args.result} because no current data was available.`;
|
|
1369
|
-
}
|
|
1370
|
-
return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
|
|
1371
|
-
}
|
|
1372
|
-
function buildEvidentialRationale(args) {
|
|
1373
|
-
const observed = args.snapshot.value === null ? "no data" : String(args.snapshot.value);
|
|
1374
|
-
const clause = `${args.snapshot.metric} observed ${observed} against ${args.config.operator} ${args.config.threshold}`;
|
|
1375
|
-
if (args.snapshot.value === null) {
|
|
1376
|
-
return `${clause}; evidential evaluator treated the comparison as unmet, resulting in ${args.result}.`;
|
|
1377
|
-
}
|
|
1378
|
-
return `${clause}; comparison ${args.comparisonSatisfied ? "passed" : "failed"}, resulting in ${args.result}.`;
|
|
1379
|
-
}
|
|
1380
|
-
function parseMetricCheckerConfig(value) {
|
|
1381
|
-
if (!value || typeof value !== "object") {
|
|
1382
|
-
throw new Error(
|
|
1383
|
-
"metric_checker requires condition.evaluatorConfig with observedValue/operator/threshold."
|
|
1384
|
-
);
|
|
1385
|
-
}
|
|
1386
|
-
const config = value;
|
|
1387
|
-
return {
|
|
1388
|
-
metric: typeof config.metric === "string" && config.metric.length > 0 ? config.metric : void 0,
|
|
1389
|
-
operator: parseComparisonOperator(config.operator, BUILT_IN_METRIC_CHECKER),
|
|
1390
|
-
threshold: parseNumericThreshold(config.threshold, BUILT_IN_METRIC_CHECKER),
|
|
1391
|
-
observedValue: pickFiniteNumber(config, ["observedValue", "value"]),
|
|
1392
|
-
currentValue: pickFiniteNumber(config, ["currentValue"]),
|
|
1393
|
-
metricValue: pickFiniteNumber(config, ["metricValue"]),
|
|
1394
|
-
unit: typeof config.unit === "string" && config.unit.length > 0 ? config.unit : void 0
|
|
1395
|
-
};
|
|
1396
|
-
}
|
|
1397
|
-
function parseReferenceCheckCounterConfig(value) {
|
|
1398
|
-
if (!value || typeof value !== "object") {
|
|
1399
|
-
throw new Error(
|
|
1400
|
-
"reference_check_counter requires condition.evaluatorConfig with tag/operator/threshold."
|
|
1401
|
-
);
|
|
1402
|
-
}
|
|
1403
|
-
const config = value;
|
|
1404
|
-
if (typeof config.tag !== "string" || config.tag.trim().length === 0) {
|
|
1405
|
-
throw new Error("reference_check_counter requires a non-empty tag.");
|
|
1406
|
-
}
|
|
1407
|
-
return {
|
|
1408
|
-
tag: config.tag.trim(),
|
|
1409
|
-
operator: parseComparisonOperator(
|
|
1410
|
-
config.operator,
|
|
1411
|
-
BUILT_IN_REFERENCE_CHECK_COUNTER
|
|
1412
|
-
),
|
|
1413
|
-
threshold: parseNumericThreshold(
|
|
1414
|
-
config.threshold,
|
|
1415
|
-
BUILT_IN_REFERENCE_CHECK_COUNTER
|
|
1416
|
-
),
|
|
1417
|
-
caseSensitive: config.caseSensitive === true
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
function parseTemporalDeadlineConfig(value) {
|
|
1421
|
-
if (!value || typeof value !== "object") {
|
|
1422
|
-
return {};
|
|
1423
|
-
}
|
|
1424
|
-
const config = value;
|
|
1425
|
-
return {
|
|
1426
|
-
label: typeof config.label === "string" && config.label.length > 0 ? config.label : void 0,
|
|
1427
|
-
completed: config.completed === true,
|
|
1428
|
-
completedAt: pickFiniteNumber(config, ["completedAt"]),
|
|
1429
|
-
observedAt: pickFiniteNumber(config, ["observedAt"]),
|
|
1430
|
-
satisfiedAt: pickFiniteNumber(config, ["satisfiedAt"]),
|
|
1431
|
-
achievedAt: pickFiniteNumber(config, ["achievedAt"])
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1434
|
-
function parseMarketIndexComparatorConfig(value) {
|
|
1435
|
-
if (!value || typeof value !== "object") {
|
|
1436
|
-
throw new Error(
|
|
1437
|
-
"market_index_comparator requires condition.evaluatorConfig with subjectValue/benchmarkValue/operator/threshold."
|
|
1438
|
-
);
|
|
1439
|
-
}
|
|
1440
|
-
const config = value;
|
|
1441
|
-
return {
|
|
1442
|
-
subject: typeof config.subject === "string" && config.subject.length > 0 ? config.subject : void 0,
|
|
1443
|
-
subjectValue: pickFiniteNumber(config, ["subjectValue", "leftValue"]),
|
|
1444
|
-
primaryValue: pickFiniteNumber(config, ["primaryValue"]),
|
|
1445
|
-
benchmark: typeof config.benchmark === "string" && config.benchmark.length > 0 ? config.benchmark : void 0,
|
|
1446
|
-
benchmarkValue: pickFiniteNumber(config, ["benchmarkValue", "rightValue"]),
|
|
1447
|
-
comparisonValue: pickFiniteNumber(config, ["comparisonValue"]),
|
|
1448
|
-
operator: parseComparisonOperator(
|
|
1449
|
-
config.operator,
|
|
1450
|
-
BUILT_IN_MARKET_INDEX_COMPARATOR
|
|
1451
|
-
),
|
|
1452
|
-
threshold: parseNumericThreshold(
|
|
1453
|
-
config.threshold,
|
|
1454
|
-
BUILT_IN_MARKET_INDEX_COMPARATOR
|
|
1455
|
-
)
|
|
1456
|
-
};
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
// ../access-control/src/audience.ts
|
|
1460
|
-
var AUDIENCE_CLASS_RANK = {
|
|
1461
|
-
public: 0,
|
|
1462
|
-
restricted_external: 1,
|
|
1463
|
-
internal: 2
|
|
1464
|
-
};
|
|
1465
|
-
function normalizeKey(key) {
|
|
1466
|
-
return (key ?? "").trim().toLowerCase().replace(/[^a-z0-9:_-]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
|
1467
|
-
}
|
|
1468
|
-
function normalizeAudienceKey(key) {
|
|
1469
|
-
return normalizeKey(key);
|
|
1470
|
-
}
|
|
1471
|
-
function classFromAudienceKey(audienceKey, fallback = "internal") {
|
|
1472
|
-
const key = normalizeKey(audienceKey);
|
|
1473
|
-
if (!key) {
|
|
1474
|
-
return fallback;
|
|
1475
|
-
}
|
|
1476
|
-
if (key === "internal") {
|
|
1477
|
-
return "internal";
|
|
1478
|
-
}
|
|
1479
|
-
if (key === "public") {
|
|
1480
|
-
return "public";
|
|
1481
|
-
}
|
|
1482
|
-
if (key === "lp" || key === "external" || key === "client" || key === "partner" || key === "portfolio" || key === "network" || key === "restricted_external") {
|
|
1483
|
-
return "restricted_external";
|
|
1484
|
-
}
|
|
1485
|
-
return fallback;
|
|
1486
|
-
}
|
|
1487
|
-
function canAudienceClassAccess(viewerClass, resourceClass) {
|
|
1488
|
-
return AUDIENCE_CLASS_RANK[viewerClass] >= AUDIENCE_CLASS_RANK[resourceClass];
|
|
1489
|
-
}
|
|
1490
|
-
|
|
1491
|
-
// ../access-control/src/audienceRegistry.ts
|
|
1492
|
-
var DEFAULT_AUDIENCES = [
|
|
1493
|
-
{
|
|
1494
|
-
audienceKey: "internal",
|
|
1495
|
-
audienceLabel: "Internal",
|
|
1496
|
-
audienceClass: "internal"
|
|
1497
|
-
},
|
|
1498
|
-
{
|
|
1499
|
-
audienceKey: "lp",
|
|
1500
|
-
audienceLabel: "Limited Partners",
|
|
1501
|
-
audienceClass: "restricted_external"
|
|
1502
|
-
},
|
|
1503
|
-
{
|
|
1504
|
-
audienceKey: "public",
|
|
1505
|
-
audienceLabel: "Public",
|
|
1506
|
-
audienceClass: "public"
|
|
1507
|
-
}
|
|
1508
|
-
];
|
|
1509
|
-
var AUDIENCE_CLASS_PRIORITY = {
|
|
1510
|
-
internal: 0,
|
|
1511
|
-
restricted_external: 1,
|
|
1512
|
-
public: 2
|
|
1513
|
-
};
|
|
1514
|
-
function normalizeRegistryRow(row) {
|
|
1515
|
-
return {
|
|
1516
|
-
audienceKey: normalizeAudienceKey(row.audienceKey),
|
|
1517
|
-
audienceLabel: row.audienceLabel,
|
|
1518
|
-
audienceClass: row.audienceClass,
|
|
1519
|
-
workspaceId: row.workspaceId
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
function dedupeRegistryRows(rows) {
|
|
1523
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
1524
|
-
for (const row of rows) {
|
|
1525
|
-
const key = normalizeAudienceKey(row.audienceKey);
|
|
1526
|
-
if (!key) {
|
|
1527
|
-
continue;
|
|
1528
|
-
}
|
|
1529
|
-
const existing = byKey.get(key);
|
|
1530
|
-
const isWorkspaceScoped = row.workspaceId !== void 0;
|
|
1531
|
-
const existingWorkspaceScoped = existing?.workspaceId !== void 0;
|
|
1532
|
-
if (!existing || isWorkspaceScoped && !existingWorkspaceScoped) {
|
|
1533
|
-
byKey.set(key, {
|
|
1534
|
-
...row,
|
|
1535
|
-
audienceKey: key
|
|
1536
|
-
});
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
const normalized = [...byKey.values()];
|
|
1540
|
-
normalized.sort((a, b) => {
|
|
1541
|
-
const classDelta = AUDIENCE_CLASS_PRIORITY[a.audienceClass] - AUDIENCE_CLASS_PRIORITY[b.audienceClass];
|
|
1542
|
-
if (classDelta !== 0) {
|
|
1543
|
-
return classDelta;
|
|
1544
|
-
}
|
|
1545
|
-
return a.audienceKey.localeCompare(b.audienceKey);
|
|
1546
|
-
});
|
|
1547
|
-
return normalized;
|
|
1548
|
-
}
|
|
1549
|
-
async function queryRegistryRows(ctx, args) {
|
|
1550
|
-
if (!args.tenantId) {
|
|
1551
|
-
return [...DEFAULT_AUDIENCES];
|
|
1552
|
-
}
|
|
1553
|
-
const rows = await ctx.db.query("platformAudiences").withIndex("by_tenantId", (q) => q.eq("tenantId", args.tenantId)).collect();
|
|
1554
|
-
const workspaceIdString = args.workspaceId ? String(args.workspaceId) : null;
|
|
1555
|
-
const tenantScoped = rows.filter((row) => row.status === "active");
|
|
1556
|
-
const applicable = tenantScoped.filter((row) => {
|
|
1557
|
-
if (!row.workspaceId) {
|
|
1558
|
-
return true;
|
|
1559
|
-
}
|
|
1560
|
-
if (!workspaceIdString) {
|
|
1561
|
-
return false;
|
|
1562
|
-
}
|
|
1563
|
-
return String(row.workspaceId) === workspaceIdString;
|
|
1564
|
-
});
|
|
1565
|
-
return dedupeRegistryRows([
|
|
1566
|
-
...DEFAULT_AUDIENCES,
|
|
1567
|
-
...applicable.map(
|
|
1568
|
-
(row) => normalizeRegistryRow({
|
|
1569
|
-
audienceKey: row.audienceKey,
|
|
1570
|
-
audienceLabel: row.audienceLabel,
|
|
1571
|
-
audienceClass: row.audienceClass,
|
|
1572
|
-
workspaceId: row.workspaceId
|
|
1573
|
-
})
|
|
1574
|
-
)
|
|
1575
|
-
]);
|
|
1576
|
-
}
|
|
1577
|
-
async function listAudienceRegistryRows(ctx, args) {
|
|
1578
|
-
return queryRegistryRows(ctx, args);
|
|
1579
|
-
}
|
|
1580
|
-
componentsGeneric();
|
|
1581
|
-
var internal2 = anyApi;
|
|
1582
|
-
|
|
1583
|
-
// ../schema-management/src/enumValidation.ts
|
|
1584
|
-
var BUILTIN_ENUM_FALLBACK = {
|
|
1585
|
-
topic_type: /* @__PURE__ */ new Set([
|
|
1586
|
-
"domain",
|
|
1587
|
-
"theme",
|
|
1588
|
-
"deal",
|
|
1589
|
-
"strategy",
|
|
1590
|
-
"constitution",
|
|
1591
|
-
"project",
|
|
1592
|
-
"portfolio",
|
|
1593
|
-
"architecture",
|
|
1594
|
-
"capability",
|
|
1595
|
-
"runtime",
|
|
1596
|
-
"interface",
|
|
1597
|
-
"governance",
|
|
1598
|
-
"operations",
|
|
1599
|
-
"security",
|
|
1600
|
-
"data"
|
|
1601
|
-
]),
|
|
1602
|
-
branch_schema: /* @__PURE__ */ new Set(["pillar", "track", "dimension", "axis", "phase"]),
|
|
1603
|
-
lens_perspective_type: /* @__PURE__ */ new Set([
|
|
1604
|
-
"investigation",
|
|
1605
|
-
"monitoring",
|
|
1606
|
-
"analysis",
|
|
1607
|
-
"comparison",
|
|
1608
|
-
"taxonomy"
|
|
1609
|
-
]),
|
|
1610
|
-
belief_type: /* @__PURE__ */ new Set([
|
|
1611
|
-
"belief",
|
|
1612
|
-
"hypothesis",
|
|
1613
|
-
"principle",
|
|
1614
|
-
"invariant",
|
|
1615
|
-
"assumption",
|
|
1616
|
-
"tenet",
|
|
1617
|
-
"prior",
|
|
1618
|
-
"preference",
|
|
1619
|
-
"goal",
|
|
1620
|
-
"forecast",
|
|
1621
|
-
"decision",
|
|
1622
|
-
"constraint",
|
|
1623
|
-
"tradeoff",
|
|
1624
|
-
"policy",
|
|
1625
|
-
"implementation_choice",
|
|
1626
|
-
// Coding intelligence domain
|
|
1627
|
-
"implementation_decision",
|
|
1628
|
-
"interface_contract",
|
|
1629
|
-
"migration_state",
|
|
1630
|
-
"code_pattern",
|
|
1631
|
-
"deprecation_notice"
|
|
1632
|
-
]),
|
|
1633
|
-
edge_type: /* @__PURE__ */ new Set([
|
|
1634
|
-
// === 6 CANONICAL EPISTEMIC TYPES ===
|
|
1635
|
-
"supports",
|
|
1636
|
-
// L3↔L3: belief bears on belief (weight -1 to +1)
|
|
1637
|
-
"informs",
|
|
1638
|
-
// L2→L3: evidence bears on belief
|
|
1639
|
-
"depends_on",
|
|
1640
|
-
// L3→L3, Q→Q: structural gate
|
|
1641
|
-
"derived_from",
|
|
1642
|
-
// Any→Any: provenance chain
|
|
1643
|
-
"contains",
|
|
1644
|
-
// Any→Any: hierarchy, scoping, membership
|
|
1645
|
-
"tests",
|
|
1646
|
-
// Q→L3: question interrogates belief
|
|
1647
|
-
// === STRUCTURAL / LIFECYCLE ===
|
|
1648
|
-
"supersedes",
|
|
1649
|
-
"responds_to",
|
|
1650
|
-
"belongs_to",
|
|
1651
|
-
"relates_to_thesis",
|
|
1652
|
-
// === ONTOLOGICAL (tenant-extensible) ===
|
|
1653
|
-
"works_at",
|
|
1654
|
-
"invested_in",
|
|
1655
|
-
"competes_with",
|
|
1656
|
-
"participates_in",
|
|
1657
|
-
"founded_by",
|
|
1658
|
-
"evaluates",
|
|
1659
|
-
"performs",
|
|
1660
|
-
"function_in",
|
|
1661
|
-
"impacts",
|
|
1662
|
-
"raised_from",
|
|
1663
|
-
"mentioned_in",
|
|
1664
|
-
"perspective_on",
|
|
1665
|
-
"plays_theme"
|
|
1666
|
-
]),
|
|
1667
|
-
worktree_type: /* @__PURE__ */ new Set([
|
|
1668
|
-
"belief_test",
|
|
1669
|
-
"existential",
|
|
1670
|
-
"contradiction",
|
|
1671
|
-
"refinement",
|
|
1672
|
-
"coverage",
|
|
1673
|
-
"discovery",
|
|
1674
|
-
"clarification",
|
|
1675
|
-
"confirmation"
|
|
1676
|
-
]),
|
|
1677
|
-
worktree_phase: /* @__PURE__ */ new Set([
|
|
1678
|
-
"cluster_mapping",
|
|
1679
|
-
"hypothesis_formation",
|
|
1680
|
-
"question_generation",
|
|
1681
|
-
"evidence_collection",
|
|
1682
|
-
"synthesis",
|
|
1683
|
-
"decision",
|
|
1684
|
-
"retrospective"
|
|
1685
|
-
]),
|
|
1686
|
-
activity_type: /* @__PURE__ */ new Set([
|
|
1687
|
-
"create",
|
|
1688
|
-
"update",
|
|
1689
|
-
"review",
|
|
1690
|
-
"merge",
|
|
1691
|
-
"archive",
|
|
1692
|
-
"comment",
|
|
1693
|
-
"status_change",
|
|
1694
|
-
"evidence_added",
|
|
1695
|
-
"question_added"
|
|
1696
|
-
])
|
|
1697
|
-
};
|
|
1698
|
-
function normalizeEnumValue(value) {
|
|
1699
|
-
return value.trim().toLowerCase();
|
|
1700
|
-
}
|
|
1701
|
-
async function validateSchemaEnumValue(ctx, args) {
|
|
1702
|
-
const normalized = normalizeEnumValue(args.value);
|
|
1703
|
-
if (!normalized) {
|
|
1704
|
-
return { valid: false, source: "none" };
|
|
1705
|
-
}
|
|
1706
|
-
try {
|
|
1707
|
-
const validFromSchema = await ctx.runQuery(
|
|
1708
|
-
internal2.schemaConfig.internalValidate,
|
|
1709
|
-
{
|
|
1710
|
-
category: args.category,
|
|
1711
|
-
value: normalized,
|
|
1712
|
-
tenantId: args.tenantId
|
|
1713
|
-
}
|
|
1714
|
-
);
|
|
1715
|
-
if (validFromSchema) {
|
|
1716
|
-
return { valid: true, source: "schema" };
|
|
1717
|
-
}
|
|
1718
|
-
} catch {
|
|
1719
|
-
}
|
|
1720
|
-
const fallback = BUILTIN_ENUM_FALLBACK[args.category];
|
|
1721
|
-
if (fallback.has(normalized)) {
|
|
1722
|
-
return { valid: true, source: "builtin" };
|
|
1723
|
-
}
|
|
1724
|
-
return { valid: false, source: "none" };
|
|
1725
|
-
}
|
|
1726
|
-
async function assertSchemaEnumValue(ctx, args) {
|
|
1727
|
-
if (typeof args.value !== "string") {
|
|
1728
|
-
return;
|
|
1729
|
-
}
|
|
1730
|
-
const normalized = normalizeEnumValue(args.value);
|
|
1731
|
-
if (!normalized) {
|
|
1732
|
-
return;
|
|
1733
|
-
}
|
|
1734
|
-
const validation = await validateSchemaEnumValue(ctx, {
|
|
1735
|
-
category: args.category,
|
|
1736
|
-
value: normalized,
|
|
1737
|
-
tenantId: args.tenantId
|
|
1738
|
-
});
|
|
1739
|
-
if (!validation.valid) {
|
|
1740
|
-
const tenantHint = args.tenantId ? ` for tenant ${args.tenantId}` : "";
|
|
1741
|
-
throw new Error(
|
|
1742
|
-
`[${args.context}] Invalid value "${normalized}" for category "${args.category}"${tenantHint}. Add it to schemaEnumConfig before use.`
|
|
1743
|
-
);
|
|
1744
|
-
}
|
|
1745
|
-
return normalized;
|
|
1746
|
-
}
|
|
15
|
+
var internal = anyApi;
|
|
16
|
+
var internalMutation = internalMutationGeneric;
|
|
17
|
+
var internalQuery = internalQueryGeneric;
|
|
18
|
+
var mutation = mutationGeneric;
|
|
19
|
+
var query = queryGeneric;
|
|
1747
20
|
|
|
1748
21
|
// src/beliefLifecycle.ts
|
|
1749
22
|
var BELIEF_STATUS_VALUES = [
|
|
@@ -1761,30 +34,30 @@ var RESOLVED_PREDICTION_OUTCOMES = [
|
|
|
1761
34
|
function isBeliefLifecycleStatus(value) {
|
|
1762
35
|
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
1763
36
|
}
|
|
1764
|
-
function normalizeBeliefConfidence(
|
|
1765
|
-
if (typeof
|
|
37
|
+
function normalizeBeliefConfidence(confidence) {
|
|
38
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
1766
39
|
return null;
|
|
1767
40
|
}
|
|
1768
|
-
if (
|
|
1769
|
-
return
|
|
41
|
+
if (confidence >= 0 && confidence <= 1) {
|
|
42
|
+
return confidence;
|
|
1770
43
|
}
|
|
1771
|
-
if (
|
|
1772
|
-
return
|
|
44
|
+
if (confidence > 1 && confidence <= 100) {
|
|
45
|
+
return confidence / 100;
|
|
1773
46
|
}
|
|
1774
47
|
return null;
|
|
1775
48
|
}
|
|
1776
|
-
function isResolvedByConfidence(
|
|
1777
|
-
const normalized = normalizeBeliefConfidence(
|
|
49
|
+
function isResolvedByConfidence(confidence) {
|
|
50
|
+
const normalized = normalizeBeliefConfidence(confidence);
|
|
1778
51
|
if (normalized === null) {
|
|
1779
52
|
return false;
|
|
1780
53
|
}
|
|
1781
54
|
return normalized <= 0 || normalized >= 1;
|
|
1782
55
|
}
|
|
1783
|
-
function hasResolvedPredictionOutcome(
|
|
1784
|
-
if (!
|
|
56
|
+
function hasResolvedPredictionOutcome(predictionMeta) {
|
|
57
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
1785
58
|
return false;
|
|
1786
59
|
}
|
|
1787
|
-
const outcome =
|
|
60
|
+
const outcome = predictionMeta.outcome;
|
|
1788
61
|
return typeof outcome === "string" && RESOLVED_PREDICTION_OUTCOMES.includes(outcome);
|
|
1789
62
|
}
|
|
1790
63
|
function getPredictionMetaFromMetadata(metadata) {
|
|
@@ -1847,8 +120,6 @@ var containsPropagationSpec = {
|
|
|
1847
120
|
operator: () => null,
|
|
1848
121
|
description: "Structural containment only. Traversed for explicit semantics, but it never propagates opinions."
|
|
1849
122
|
};
|
|
1850
|
-
|
|
1851
|
-
// src/edges/utils.ts
|
|
1852
123
|
function readEdgeMetadata(edge) {
|
|
1853
124
|
return {
|
|
1854
125
|
constraint: edge.constraint ?? void 0,
|
|
@@ -1925,8 +196,6 @@ var contradictsPropagationSpec = {
|
|
|
1925
196
|
},
|
|
1926
197
|
description: "Legacy contradiction edges move negative pressure in either direction, but never beyond one hop."
|
|
1927
198
|
};
|
|
1928
|
-
|
|
1929
|
-
// src/edges/dependsOn.ts
|
|
1930
199
|
var dependsOnPropagationSpec = {
|
|
1931
200
|
edgeType: "depends_on",
|
|
1932
201
|
direction: "incoming",
|
|
@@ -1942,8 +211,18 @@ var dependsOnPropagationSpec = {
|
|
|
1942
211
|
if (metadata.conditionalA && metadata.conditionalNotA) {
|
|
1943
212
|
const deducedOpinion = conditionalDeduction(
|
|
1944
213
|
dampedSource,
|
|
1945
|
-
|
|
1946
|
-
|
|
214
|
+
mkOpinion(
|
|
215
|
+
metadata.conditionalA.b,
|
|
216
|
+
metadata.conditionalA.d,
|
|
217
|
+
metadata.conditionalA.u,
|
|
218
|
+
metadata.conditionalA.a
|
|
219
|
+
),
|
|
220
|
+
mkOpinion(
|
|
221
|
+
metadata.conditionalNotA.b,
|
|
222
|
+
metadata.conditionalNotA.d,
|
|
223
|
+
metadata.conditionalNotA.u,
|
|
224
|
+
metadata.conditionalNotA.a
|
|
225
|
+
),
|
|
1947
226
|
targetOpinion.a
|
|
1948
227
|
);
|
|
1949
228
|
return annotateRationale(
|
|
@@ -2115,606 +394,17 @@ function getTraversalDirections(direction) {
|
|
|
2115
394
|
}
|
|
2116
395
|
return ["outgoing", "incoming"];
|
|
2117
396
|
}
|
|
2118
|
-
|
|
2119
|
-
v.union(
|
|
2120
|
-
v.literal("very_high"),
|
|
2121
|
-
// 0.9+
|
|
2122
|
-
v.literal("high"),
|
|
2123
|
-
// 0.7-0.9
|
|
2124
|
-
v.literal("medium"),
|
|
2125
|
-
// 0.4-0.7
|
|
2126
|
-
v.literal("low"),
|
|
2127
|
-
// 0.2-0.4
|
|
2128
|
-
v.literal("very_low")
|
|
2129
|
-
// 0-0.2
|
|
2130
|
-
);
|
|
2131
|
-
v.union(
|
|
2132
|
-
v.literal(1),
|
|
2133
|
-
// Critical
|
|
2134
|
-
v.literal(2),
|
|
2135
|
-
// High
|
|
2136
|
-
v.literal(3),
|
|
2137
|
-
// Medium
|
|
2138
|
-
v.literal(4),
|
|
2139
|
-
// Low
|
|
2140
|
-
v.literal(5)
|
|
2141
|
-
// Backlog
|
|
2142
|
-
);
|
|
2143
|
-
v.union(
|
|
2144
|
-
v.literal("critical"),
|
|
2145
|
-
v.literal("high"),
|
|
2146
|
-
v.literal("medium"),
|
|
2147
|
-
v.literal("low"),
|
|
2148
|
-
v.literal("backlog")
|
|
2149
|
-
);
|
|
2150
|
-
v.union(
|
|
2151
|
-
v.literal("active"),
|
|
2152
|
-
v.literal("paused"),
|
|
2153
|
-
v.literal("completed"),
|
|
2154
|
-
v.literal("archived")
|
|
2155
|
-
);
|
|
2156
|
-
v.union(
|
|
2157
|
-
v.literal("pending"),
|
|
2158
|
-
v.literal("processing"),
|
|
2159
|
-
v.literal("completed"),
|
|
2160
|
-
v.literal("failed")
|
|
2161
|
-
);
|
|
2162
|
-
v.object({
|
|
2163
|
-
crunchbaseId: v.optional(v.string()),
|
|
2164
|
-
linkedinUrl: v.optional(v.string()),
|
|
2165
|
-
pitchbookId: v.optional(v.string()),
|
|
2166
|
-
twitterUrl: v.optional(v.string()),
|
|
2167
|
-
domain: v.optional(v.string())
|
|
2168
|
-
});
|
|
2169
|
-
var sourceType = v.union(
|
|
2170
|
-
v.literal("proprietary"),
|
|
2171
|
-
// Internal Stack research
|
|
2172
|
-
v.literal("primary"),
|
|
2173
|
-
// Direct interviews, calls
|
|
2174
|
-
v.literal("secondary"),
|
|
2175
|
-
// Published sources
|
|
2176
|
-
v.literal("ai_generated"),
|
|
2177
|
-
// AI-synthesized
|
|
2178
|
-
v.literal("user_input"),
|
|
2179
|
-
// Manual user entry
|
|
2180
|
-
v.literal("inferred")
|
|
2181
|
-
// System inference
|
|
2182
|
-
);
|
|
2183
|
-
v.object({
|
|
2184
|
-
sourceType: v.optional(sourceType),
|
|
2185
|
-
sourceId: v.optional(v.string()),
|
|
2186
|
-
// Reference to source entity
|
|
2187
|
-
sourceUrl: v.optional(v.string()),
|
|
2188
|
-
sourceDate: v.optional(v.number()),
|
|
2189
|
-
sourceName: v.optional(v.string())
|
|
2190
|
-
});
|
|
2191
|
-
v.object({
|
|
2192
|
-
cursor: v.optional(v.string()),
|
|
2193
|
-
limit: v.optional(v.number())
|
|
2194
|
-
});
|
|
2195
|
-
v.object({
|
|
2196
|
-
hasMore: v.boolean(),
|
|
2197
|
-
nextCursor: v.optional(v.string()),
|
|
2198
|
-
totalCount: v.optional(v.number())
|
|
2199
|
-
});
|
|
2200
|
-
var richTextContent = v.object({
|
|
2201
|
-
type: v.literal("doc"),
|
|
2202
|
-
content: looseJsonArray
|
|
2203
|
-
});
|
|
2204
|
-
v.union(v.string(), richTextContent);
|
|
2205
|
-
v.object({
|
|
2206
|
-
promptTokens: v.optional(v.number()),
|
|
2207
|
-
completionTokens: v.optional(v.number()),
|
|
2208
|
-
totalTokens: v.optional(v.number())
|
|
2209
|
-
});
|
|
2210
|
-
v.object({
|
|
2211
|
-
fileName: v.optional(v.string()),
|
|
2212
|
-
fileSize: v.optional(v.number()),
|
|
2213
|
-
mimeType: v.optional(v.string()),
|
|
2214
|
-
storageId: v.optional(v.id("_storage")),
|
|
2215
|
-
externalUrl: v.optional(v.string())
|
|
2216
|
-
});
|
|
2217
|
-
|
|
2218
|
-
// ../schema-management/src/spine/tables/epistemicNodes.ts
|
|
2219
|
-
var nodeType = v.union(
|
|
2220
|
-
// --- L4: Audit Targets (decisions, outcomes) ---
|
|
2221
|
-
v.literal("decision"),
|
|
2222
|
-
// Investment decision with knowledge horizon snapshot
|
|
2223
|
-
// --- L3: Traversal Anchors (epistemic structure) ---
|
|
2224
|
-
v.literal("belief"),
|
|
2225
|
-
// Structured conviction (immutable formulation)
|
|
2226
|
-
v.literal("question"),
|
|
2227
|
-
// Unit of uncertainty
|
|
2228
|
-
v.literal("theme"),
|
|
2229
|
-
// Investment thesis / conviction cluster
|
|
2230
|
-
v.literal("deal"),
|
|
2231
|
-
// Investment evaluation process
|
|
2232
|
-
v.literal("topic"),
|
|
2233
|
-
// Hierarchical knowledge container
|
|
2234
|
-
// --- L2: Compression Boundary (minimum reasoning unit) ---
|
|
2235
|
-
v.literal("claim"),
|
|
2236
|
-
// Atomic assertion that can be true/false
|
|
2237
|
-
v.literal("evidence"),
|
|
2238
|
-
// Interpreted signal linked to beliefs
|
|
2239
|
-
v.literal("synthesis"),
|
|
2240
|
-
// Primers, deep research
|
|
2241
|
-
v.literal("answer"),
|
|
2242
|
-
// Immutable answer snapshot for a question
|
|
2243
|
-
// --- L1: Terminal Leaves (non-traversable, grounding) ---
|
|
2244
|
-
v.literal("atomic_fact"),
|
|
2245
|
-
// Raw fact from source (not interpreted)
|
|
2246
|
-
v.literal("excerpt"),
|
|
2247
|
-
// Direct quote from source document
|
|
2248
|
-
v.literal("source"),
|
|
2249
|
-
// News, documents, transcripts
|
|
2250
|
-
// --- Ontological Entities (things in the world) ---
|
|
2251
|
-
v.literal("company"),
|
|
2252
|
-
// Organization (subtype: private, corporate, portfolio)
|
|
2253
|
-
v.literal("person"),
|
|
2254
|
-
// Individual (founder, expert, LP, contact)
|
|
2255
|
-
v.literal("investor"),
|
|
2256
|
-
// Investment entity (subtype: vc, lp, cvc, pe, family_office, angel)
|
|
2257
|
-
v.literal("function"),
|
|
2258
|
-
// What a company does (from classifier)
|
|
2259
|
-
v.literal("value_chain")
|
|
2260
|
-
// Market structure / value flow
|
|
2261
|
-
);
|
|
2262
|
-
var epistemicLayer = v.union(
|
|
2263
|
-
v.literal("L4"),
|
|
2264
|
-
// Decisions, outcomes - audit targets
|
|
2265
|
-
v.literal("L3"),
|
|
2266
|
-
// Beliefs, questions, themes - traversal anchors
|
|
2267
|
-
v.literal("L2"),
|
|
2268
|
-
// Claims, evidence, synthesis - compression boundary
|
|
2269
|
-
v.literal("L1"),
|
|
2270
|
-
// Atomic facts, excerpts, sources - terminal leaves
|
|
2271
|
-
v.literal("ontological"),
|
|
2272
|
-
// Companies, people, etc - not epistemic
|
|
2273
|
-
v.literal("organizational")
|
|
2274
|
-
// Topics, lenses, worktrees — structural containers
|
|
2275
|
-
);
|
|
2276
|
-
var nodeStatus = v.union(
|
|
2277
|
-
v.literal("active"),
|
|
2278
|
-
v.literal("superseded"),
|
|
2279
|
-
// Replaced by newer version
|
|
2280
|
-
v.literal("archived"),
|
|
2281
|
-
v.literal("deleted")
|
|
2282
|
-
);
|
|
2283
|
-
var sourceType2 = v.union(
|
|
2284
|
-
v.literal("human"),
|
|
2285
|
-
// User created directly
|
|
2286
|
-
v.literal("ai_extracted"),
|
|
2287
|
-
// LLM extracted from a source
|
|
2288
|
-
v.literal("ai_generated"),
|
|
2289
|
-
// LLM synthesized/created
|
|
2290
|
-
v.literal("imported"),
|
|
2291
|
-
// External system import
|
|
2292
|
-
v.literal("system"),
|
|
2293
|
-
// System-generated (migrations, classifiers)
|
|
2294
|
-
v.literal("verified"),
|
|
2295
|
-
// Human-verified source
|
|
2296
|
-
v.literal("proprietary")
|
|
2297
|
-
// Proprietary/internal data
|
|
2298
|
-
);
|
|
2299
|
-
var verificationStatus = v.union(
|
|
2300
|
-
v.literal("unverified"),
|
|
2301
|
-
v.literal("human_verified"),
|
|
2302
|
-
v.literal("ai_verified"),
|
|
2303
|
-
v.literal("contradicted"),
|
|
2304
|
-
v.literal("outdated")
|
|
2305
|
-
);
|
|
2306
|
-
var syncStatus = v.union(
|
|
2307
|
-
v.literal("synced"),
|
|
2308
|
-
// Node and edges fully synced to Neo4j
|
|
2309
|
-
v.literal("pending_edges"),
|
|
2310
|
-
// Node created, edges being created
|
|
2311
|
-
v.literal("edge_creation_failed")
|
|
2312
|
-
// Edge creation failed, needs retry
|
|
2313
|
-
);
|
|
2314
|
-
var audienceLabel = v.string();
|
|
2315
|
-
var sensitivityTier = v.union(
|
|
2316
|
-
v.literal("low"),
|
|
2317
|
-
v.literal("medium"),
|
|
2318
|
-
v.literal("high"),
|
|
2319
|
-
v.literal("restricted")
|
|
2320
|
-
);
|
|
2321
|
-
var exportClass = v.union(
|
|
2322
|
-
v.literal("internal_only"),
|
|
2323
|
-
v.literal("client_safe"),
|
|
2324
|
-
v.literal("public_safe"),
|
|
2325
|
-
v.literal("restricted")
|
|
2326
|
-
);
|
|
2327
|
-
var anonymizationClass = v.union(
|
|
2328
|
-
v.literal("none"),
|
|
2329
|
-
v.literal("standard"),
|
|
2330
|
-
v.literal("strict")
|
|
2331
|
-
);
|
|
2332
|
-
var epistemicStatus = v.union(
|
|
2333
|
-
v.literal("hypothesis"),
|
|
2334
|
-
// Initial conjecture, low evidence
|
|
2335
|
-
v.literal("emerging"),
|
|
2336
|
-
// Building evidence, gaining traction
|
|
2337
|
-
v.literal("established"),
|
|
2338
|
-
// Well-evidenced, core to thesis
|
|
2339
|
-
v.literal("challenged"),
|
|
2340
|
-
// Contradicting evidence appeared
|
|
2341
|
-
v.literal("assumption"),
|
|
2342
|
-
// Taken as given, not actively tested
|
|
2343
|
-
v.literal("deprecated")
|
|
2344
|
-
// Superseded or abandoned
|
|
2345
|
-
);
|
|
2346
|
-
var beliefStatus = v.union(
|
|
2347
|
-
v.literal("assumption"),
|
|
2348
|
-
v.literal("hypothesis"),
|
|
2349
|
-
v.literal("belief"),
|
|
2350
|
-
v.literal("fact")
|
|
2351
|
-
);
|
|
2352
|
-
var reversibility = v.union(
|
|
2353
|
-
v.literal("irreversible"),
|
|
2354
|
-
// One-way door decision
|
|
2355
|
-
v.literal("hard_to_reverse"),
|
|
2356
|
-
// Significant cost to undo
|
|
2357
|
-
v.literal("reversible"),
|
|
2358
|
-
// Can change course with moderate effort
|
|
2359
|
-
v.literal("trivial")
|
|
2360
|
-
// Easy to adjust
|
|
2361
|
-
);
|
|
2362
|
-
var predictionOutcome = v.union(
|
|
2363
|
-
v.literal("pending"),
|
|
2364
|
-
v.literal("confirmed"),
|
|
2365
|
-
v.literal("disconfirmed"),
|
|
2366
|
-
v.literal("partial"),
|
|
2367
|
-
v.literal("expired")
|
|
2368
|
-
);
|
|
2369
|
-
var predictionMeta = v.object({
|
|
2370
|
-
isPrediction: v.boolean(),
|
|
2371
|
-
registeredAt: v.number(),
|
|
2372
|
-
// When prediction was made
|
|
2373
|
-
expectedBy: v.optional(v.number()),
|
|
2374
|
-
// When we expect resolution
|
|
2375
|
-
outcome: v.optional(predictionOutcome),
|
|
2376
|
-
outcomeRecordedAt: v.optional(v.number()),
|
|
2377
|
-
outcomeEvidenceId: v.optional(v.string()),
|
|
2378
|
-
// globalId of confirming evidence
|
|
2379
|
-
confidenceAtPrediction: v.optional(v.number()),
|
|
2380
|
-
// 0-1
|
|
2381
|
-
actualVsPredicted: v.optional(v.string())
|
|
2382
|
-
// Notes on how outcome compared
|
|
2383
|
-
});
|
|
2384
|
-
var methodology = v.union(
|
|
2385
|
-
// Primary Research (high value)
|
|
2386
|
-
v.literal("primary_research"),
|
|
2387
|
-
// Direct investigation
|
|
2388
|
-
v.literal("expert_interview"),
|
|
2389
|
-
// Expert call/interview
|
|
2390
|
-
v.literal("customer_interview"),
|
|
2391
|
-
// Customer research
|
|
2392
|
-
v.literal("field_observation"),
|
|
2393
|
-
// On-site observation
|
|
2394
|
-
v.literal("proprietary_data"),
|
|
2395
|
-
// Internal data analysis
|
|
2396
|
-
// Secondary Research
|
|
2397
|
-
v.literal("desk_research"),
|
|
2398
|
-
// Public sources
|
|
2399
|
-
v.literal("regulatory_filing"),
|
|
2400
|
-
// SEC, regulatory docs
|
|
2401
|
-
v.literal("news_article"),
|
|
2402
|
-
// News/press
|
|
2403
|
-
v.literal("academic_paper"),
|
|
2404
|
-
// Academic research
|
|
2405
|
-
// AI-Assisted
|
|
2406
|
-
v.literal("ai_synthesis"),
|
|
2407
|
-
// AI-generated synthesis
|
|
2408
|
-
v.literal("ai_extraction")
|
|
2409
|
-
// AI-extracted from source
|
|
2410
|
-
);
|
|
2411
|
-
var informationAsymmetry = v.union(
|
|
2412
|
-
v.literal("proprietary"),
|
|
2413
|
-
// Only we have this
|
|
2414
|
-
v.literal("early"),
|
|
2415
|
-
// We're early but others will get it
|
|
2416
|
-
v.literal("common")
|
|
2417
|
-
// Everyone has access
|
|
2418
|
-
);
|
|
2419
|
-
var temporalNature = v.union(
|
|
2420
|
-
v.literal("factual"),
|
|
2421
|
-
// Resolved outcome. Grounded in reality.
|
|
2422
|
-
v.literal("forecast"),
|
|
2423
|
-
// Prediction. Will resolve. Discounted weight.
|
|
2424
|
-
v.literal("unknown")
|
|
2425
|
-
// Not yet classified.
|
|
2426
|
-
);
|
|
2427
|
-
var questionType = v.union(
|
|
2428
|
-
v.literal("validation"),
|
|
2429
|
-
// Does evidence support this belief?
|
|
2430
|
-
v.literal("falsification"),
|
|
2431
|
-
// What would prove this belief wrong?
|
|
2432
|
-
v.literal("assumption_probe"),
|
|
2433
|
-
// Is this unstated assumption true?
|
|
2434
|
-
v.literal("prediction_test"),
|
|
2435
|
-
// Will this predicted outcome occur?
|
|
2436
|
-
v.literal("counterfactual"),
|
|
2437
|
-
// What would we expect if X were false?
|
|
2438
|
-
v.literal("discovery"),
|
|
2439
|
-
// What don't we know yet?
|
|
2440
|
-
v.literal("clarification"),
|
|
2441
|
-
// What does X actually mean?
|
|
2442
|
-
v.literal("comparison"),
|
|
2443
|
-
// How does X compare to Y?
|
|
2444
|
-
v.literal("causal"),
|
|
2445
|
-
// What caused X?
|
|
2446
|
-
v.literal("mechanism"),
|
|
2447
|
-
// How does X work?
|
|
2448
|
-
v.literal("general")
|
|
2449
|
-
// Unclassified
|
|
2450
|
-
);
|
|
2451
|
-
var questionPriority = v.union(
|
|
2452
|
-
v.literal("critical"),
|
|
2453
|
-
// Blocks decision-making
|
|
2454
|
-
v.literal("high"),
|
|
2455
|
-
// Important for thesis
|
|
2456
|
-
v.literal("medium"),
|
|
2457
|
-
// Would be nice to know
|
|
2458
|
-
v.literal("low")
|
|
2459
|
-
// Background/curiosity
|
|
2460
|
-
);
|
|
2461
|
-
var answerQuality = v.union(
|
|
2462
|
-
v.literal("definitive"),
|
|
2463
|
-
// Clear, well-supported
|
|
2464
|
-
v.literal("strong"),
|
|
2465
|
-
// Good evidence, high confidence
|
|
2466
|
-
v.literal("moderate"),
|
|
2467
|
-
// Some evidence
|
|
2468
|
-
v.literal("weak"),
|
|
2469
|
-
// Limited evidence
|
|
2470
|
-
v.literal("speculative"),
|
|
2471
|
-
// Mostly conjecture
|
|
2472
|
-
v.literal("unanswered")
|
|
2473
|
-
// No answer yet
|
|
2474
|
-
);
|
|
2475
|
-
var consensusView = v.union(
|
|
2476
|
-
v.literal("aligned"),
|
|
2477
|
-
// We agree with market consensus
|
|
2478
|
-
v.literal("ahead_of"),
|
|
2479
|
-
// We see this before consensus does
|
|
2480
|
-
v.literal("contrarian"),
|
|
2481
|
-
// We actively disagree with consensus
|
|
2482
|
-
v.literal("orthogonal"),
|
|
2483
|
-
// We're looking at something consensus isn't discussing
|
|
2484
|
-
v.literal("unknown")
|
|
2485
|
-
// We don't know what consensus thinks
|
|
2486
|
-
);
|
|
2487
|
-
var themeConviction = v.union(
|
|
2488
|
-
v.literal("high"),
|
|
2489
|
-
// Strong conviction, actively deploying
|
|
2490
|
-
v.literal("medium"),
|
|
2491
|
-
// Building conviction
|
|
2492
|
-
v.literal("low"),
|
|
2493
|
-
// Exploring, not convicted
|
|
2494
|
-
v.literal("negative")
|
|
2495
|
-
// Actively avoiding
|
|
2496
|
-
);
|
|
2497
|
-
var decisionType = v.union(
|
|
2498
|
-
v.literal("invest"),
|
|
2499
|
-
v.literal("pass"),
|
|
2500
|
-
v.literal("follow_on"),
|
|
2501
|
-
v.literal("exit"),
|
|
2502
|
-
v.literal("deep_dive"),
|
|
2503
|
-
v.literal("monitor"),
|
|
2504
|
-
v.literal("deprioritize"),
|
|
2505
|
-
v.literal("thesis_adopt"),
|
|
2506
|
-
v.literal("thesis_revise"),
|
|
2507
|
-
v.literal("thesis_abandon")
|
|
2508
|
-
);
|
|
2509
|
-
var decisionOutcome = v.union(
|
|
2510
|
-
v.literal("pending"),
|
|
2511
|
-
v.literal("successful"),
|
|
2512
|
-
v.literal("unsuccessful"),
|
|
2513
|
-
v.literal("mixed"),
|
|
2514
|
-
v.literal("unknown")
|
|
2515
|
-
);
|
|
2516
|
-
var externalIds2 = v.object({
|
|
2517
|
-
crunchbase: v.optional(v.string()),
|
|
2518
|
-
linkedin: v.optional(v.string()),
|
|
2519
|
-
pitchbook: v.optional(v.string()),
|
|
2520
|
-
twitter: v.optional(v.string()),
|
|
2521
|
-
website: v.optional(v.string())
|
|
2522
|
-
});
|
|
2523
|
-
defineTable({
|
|
2524
|
-
// === IDENTITY ===
|
|
2525
|
-
globalId: v.string(),
|
|
2526
|
-
// UUID - survives migration to Neo4j
|
|
2527
|
-
// === TYPE ===
|
|
2528
|
-
nodeType,
|
|
2529
|
-
// === EPISTEMIC LAYER ===
|
|
2530
|
-
epistemicLayer: v.optional(epistemicLayer),
|
|
2531
|
-
// === SUBTYPE (for typed entities) ===
|
|
2532
|
-
subtype: v.optional(v.string()),
|
|
2533
|
-
// company: private|corporate|portfolio, investor: vc|lp|cvc|pe|family_office|angel
|
|
2534
|
-
// === CONTENT ===
|
|
2535
|
-
canonicalText: v.string(),
|
|
2536
|
-
// The core content (belief statement, company name, etc.)
|
|
2537
|
-
contentHash: v.string(),
|
|
2538
|
-
// SHA256(nodeType + canonicalText) for deduplication
|
|
2539
|
-
// Extended content (for sources/syntheses)
|
|
2540
|
-
content: v.optional(v.string()),
|
|
2541
|
-
// Full text for documents/articles
|
|
2542
|
-
contentType: v.optional(v.string()),
|
|
2543
|
-
// "markdown", "html", "pdf", "text"
|
|
2544
|
-
// === METADATA ===
|
|
2545
|
-
title: v.optional(v.string()),
|
|
2546
|
-
// Display title
|
|
2547
|
-
tags: v.optional(v.array(v.string())),
|
|
2548
|
-
domain: v.optional(v.string()),
|
|
2549
|
-
// For companies: website domain
|
|
2550
|
-
// Type-specific metadata (flexible object - LEGACY)
|
|
2551
|
-
// New code should use the typed fields below when available
|
|
2552
|
-
metadata: v.optional(looseJsonObject),
|
|
2553
|
-
// === POLICY / ENTITLEMENT ===
|
|
2554
|
-
tenantId: v.optional(v.string()),
|
|
2555
|
-
workspaceId: v.optional(v.string()),
|
|
2556
|
-
ownerPrincipalId: v.optional(v.string()),
|
|
2557
|
-
audienceLabel: v.optional(audienceLabel),
|
|
2558
|
-
policyTags: v.optional(v.array(v.string())),
|
|
2559
|
-
sensitivityTier: v.optional(sensitivityTier),
|
|
2560
|
-
exportClass: v.optional(exportClass),
|
|
2561
|
-
anonymizationClass: v.optional(anonymizationClass),
|
|
2562
|
-
// === PUBLICATION (visibility-based, not copy-based) ===
|
|
2563
|
-
// Publication expands who can see a workspace-local node — the node stays
|
|
2564
|
-
// in its workspace, like a microservice exposing part of its API surface.
|
|
2565
|
-
// Rules-based: pack/tenant-level publicationRules auto-evaluate on
|
|
2566
|
-
// confidence changes and node creation. No manual click-by-click.
|
|
2567
|
-
publicationStatus: v.optional(
|
|
2568
|
-
v.union(
|
|
2569
|
-
v.literal("unpublished"),
|
|
2570
|
-
// Default: workspace-local only
|
|
2571
|
-
v.literal("published"),
|
|
2572
|
-
// Visible at tenant scope (rules matched)
|
|
2573
|
-
v.literal("suppressed")
|
|
2574
|
-
// Manually blocked even if rules match
|
|
2575
|
-
)
|
|
2576
|
-
),
|
|
2577
|
-
publishedAt: v.optional(v.number()),
|
|
2578
|
-
// When publication status last changed to published
|
|
2579
|
-
publishedBy: v.optional(v.string()),
|
|
2580
|
-
// userId or "system:publication_rules" for auto-publish
|
|
2581
|
-
// === TYPED METADATA FIELDS ===
|
|
2582
|
-
// --- Belief ---
|
|
2583
|
-
// Belief type — validated against schemaEnumConfig category "belief_type"
|
|
2584
|
-
// Platform core: hypothesis, belief, principle, invariant, assumption,
|
|
2585
|
-
// tenet, prior, preference, goal, forecast
|
|
2586
|
-
beliefType: v.optional(v.string()),
|
|
2587
|
-
beliefStatus: v.optional(beliefStatus),
|
|
2588
|
-
epistemicStatus: v.optional(epistemicStatus),
|
|
2589
|
-
reversibility: v.optional(reversibility),
|
|
2590
|
-
predictionMeta: v.optional(predictionMeta),
|
|
2591
|
-
// Consensus tracking (for non-consensus detection)
|
|
2592
|
-
consensusView: v.optional(consensusView),
|
|
2593
|
-
consensusConfidence: v.optional(v.number()),
|
|
2594
|
-
// 0-1: What we think consensus confidence is
|
|
2595
|
-
consensusSource: v.optional(v.string()),
|
|
2596
|
-
// Where we got the consensus view (twitter, reports, etc.)
|
|
2597
|
-
// --- Evidence ---
|
|
2598
|
-
methodology: v.optional(methodology),
|
|
2599
|
-
informationAsymmetry: v.optional(informationAsymmetry),
|
|
2600
|
-
temporalNature: v.optional(temporalNature),
|
|
2601
|
-
// --- Question ---
|
|
2602
|
-
questionType: v.optional(questionType),
|
|
2603
|
-
questionPriority: v.optional(questionPriority),
|
|
2604
|
-
answerQuality: v.optional(answerQuality),
|
|
2605
|
-
// --- Theme ---
|
|
2606
|
-
themeConviction: v.optional(themeConviction),
|
|
2607
|
-
// Market timing (for "early on theme" detection)
|
|
2608
|
-
marketAwarenessDate: v.optional(v.number()),
|
|
2609
|
-
// When this theme became broadly discussed
|
|
2610
|
-
marketAwarenessSource: v.optional(v.string()),
|
|
2611
|
-
// How we know (first major report, twitter volume spike, etc.)
|
|
2612
|
-
earlySignalIds: v.optional(v.array(v.string())),
|
|
2613
|
-
// globalIds of evidence we had before market awareness
|
|
2614
|
-
// --- Decision ---
|
|
2615
|
-
decisionType: v.optional(decisionType),
|
|
2616
|
-
decisionOutcome: v.optional(decisionOutcome),
|
|
2617
|
-
// === EXTERNAL IDS (for ontological entities) ===
|
|
2618
|
-
externalIds: v.optional(externalIds2),
|
|
2619
|
-
// === PROVENANCE ===
|
|
2620
|
-
sourceType: sourceType2,
|
|
2621
|
-
aiProvider: v.optional(v.string()),
|
|
2622
|
-
// "claude", "gemini", "gpt-4", etc.
|
|
2623
|
-
extractedFromNodeId: v.optional(v.id("epistemicNodes")),
|
|
2624
|
-
// Quick reference to source
|
|
2625
|
-
// === EXTRACTION CONTEXT ===
|
|
2626
|
-
extractionModel: v.optional(v.string()),
|
|
2627
|
-
// "claude-sonnet-4-20250514"
|
|
2628
|
-
extractionPromptName: v.optional(v.string()),
|
|
2629
|
-
// "lucern/extract-evidence"
|
|
2630
|
-
extractionPromptVersion: v.optional(v.number()),
|
|
2631
|
-
extractionTemperature: v.optional(v.number()),
|
|
2632
|
-
extractionLangfuseTraceId: v.optional(v.string()),
|
|
2633
|
-
// === GROUNDING VERIFICATION ===
|
|
2634
|
-
groundingVerified: v.optional(v.boolean()),
|
|
2635
|
-
groundingConfidence: v.optional(v.number()),
|
|
2636
|
-
// 0-1 match quality
|
|
2637
|
-
groundingMatchedText: v.optional(v.string()),
|
|
2638
|
-
// Actual text from source
|
|
2639
|
-
groundingStartOffset: v.optional(v.number()),
|
|
2640
|
-
groundingEndOffset: v.optional(v.number()),
|
|
2641
|
-
groundingRejectionReason: v.optional(v.string()),
|
|
2642
|
-
// === CONFIDENCE & VERIFICATION ===
|
|
2643
|
-
confidence: v.optional(v.number()),
|
|
2644
|
-
// 0-1 projected probability P(x) = b + a*u
|
|
2645
|
-
verificationStatus: v.optional(verificationStatus),
|
|
2646
|
-
// === SL OPINION (Subjective Logic — Kernel v2) ===
|
|
2647
|
-
// Replaces scalar confidence with rich epistemic state.
|
|
2648
|
-
// b + d + u = 1. P(x) = b + a*u is stored in `confidence` for backward compat.
|
|
2649
|
-
opinion_b: v.optional(v.number()),
|
|
2650
|
-
// Belief: evidence FOR (0-1)
|
|
2651
|
-
opinion_d: v.optional(v.number()),
|
|
2652
|
-
// Disbelief: evidence AGAINST (0-1)
|
|
2653
|
-
opinion_u: v.optional(v.number()),
|
|
2654
|
-
// Uncertainty: absence of evidence (0-1)
|
|
2655
|
-
opinion_a: v.optional(v.number()),
|
|
2656
|
-
// Base rate / prior probability (0-1)
|
|
2657
|
-
tupleContradicted: v.optional(v.boolean()),
|
|
2658
|
-
// Single-belief tuple-space contradiction flag
|
|
2659
|
-
// === LIFECYCLE ===
|
|
2660
|
-
status: nodeStatus,
|
|
2661
|
-
supersededBy: v.optional(v.id("epistemicNodes")),
|
|
2662
|
-
// === OWNERSHIP ===
|
|
2663
|
-
topicId: v.optional(v.string()),
|
|
2664
|
-
// Canonical scope container (topic-first model)
|
|
2665
|
-
projectId: v.optional(v.string()),
|
|
2666
|
-
// DEPRECATED: Use belongs_to edges
|
|
2667
|
-
createdBy: v.string(),
|
|
2668
|
-
// Clerk user ID
|
|
2669
|
-
createdAt: v.number(),
|
|
2670
|
-
updatedAt: v.number(),
|
|
2671
|
-
// === NEO4J SYNC STATUS ===
|
|
2672
|
-
syncStatus: v.optional(syncStatus),
|
|
2673
|
-
syncError: v.optional(v.string())
|
|
2674
|
-
// Error message if sync failed
|
|
2675
|
-
}).index("by_globalId", ["globalId"]).index("by_contentHash", ["contentHash"]).index("by_nodeType", ["nodeType"]).index("by_subtype", ["nodeType", "subtype"]).index("by_domain", ["domain"]).index("by_project", ["projectId"]).index("by_project_type", ["projectId", "nodeType"]).index("by_topic", ["topicId"]).index("by_topic_type", ["topicId", "nodeType"]).index("by_tenantId", ["tenantId"]).index("by_workspaceId", ["workspaceId"]).index("by_tenant_workspace", ["tenantId", "workspaceId"]).index("by_audienceLabel", ["audienceLabel"]).index("by_sensitivityTier", ["sensitivityTier"]).index("by_exportClass", ["exportClass"]).index("by_status", ["status"]).index("by_sourceType", ["sourceType"]).index("by_verification", ["verificationStatus"]).index("by_layer", ["epistemicLayer"]).index("by_layer_type", ["epistemicLayer", "nodeType"]).index("by_syncStatus", ["syncStatus"]).index("by_publicationStatus", ["publicationStatus"]).index("by_tenant_publicationStatus", ["tenantId", "publicationStatus"]).index("by_belief_status", ["nodeType", "beliefStatus"]).index("by_epistemic_status", ["nodeType", "epistemicStatus"]).index("by_temporal_nature", ["nodeType", "temporalNature"]).index("by_methodology", ["nodeType", "methodology"]).index("by_reversibility", ["nodeType", "reversibility"]).index("by_questionType", ["nodeType", "questionType"]).index("by_questionPriority", ["nodeType", "questionPriority"]).searchIndex("search_canonicalText", {
|
|
2676
|
-
searchField: "canonicalText",
|
|
2677
|
-
filterFields: ["nodeType", "projectId", "topicId", "status"]
|
|
2678
|
-
});
|
|
2679
|
-
function getLayerForNodeType(type) {
|
|
2680
|
-
switch (type) {
|
|
2681
|
-
case "decision":
|
|
2682
|
-
return "L4";
|
|
2683
|
-
case "belief":
|
|
2684
|
-
case "question":
|
|
2685
|
-
case "theme":
|
|
2686
|
-
case "deal":
|
|
2687
|
-
return "L3";
|
|
2688
|
-
case "claim":
|
|
2689
|
-
case "evidence":
|
|
2690
|
-
case "synthesis":
|
|
2691
|
-
case "answer":
|
|
2692
|
-
return "L2";
|
|
2693
|
-
case "atomic_fact":
|
|
2694
|
-
case "excerpt":
|
|
2695
|
-
case "source":
|
|
2696
|
-
return "L1";
|
|
2697
|
-
case "topic":
|
|
2698
|
-
return "organizational";
|
|
2699
|
-
case "company":
|
|
2700
|
-
case "person":
|
|
2701
|
-
case "investor":
|
|
2702
|
-
case "function":
|
|
2703
|
-
case "value_chain":
|
|
2704
|
-
return "ontological";
|
|
2705
|
-
}
|
|
2706
|
-
}
|
|
2707
|
-
var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
|
|
397
|
+
var LEGACY_SCOPE_FIELD = "graphScopeProjectId";
|
|
2708
398
|
function asMappedProjectId(topic) {
|
|
2709
399
|
if (!topic) {
|
|
2710
400
|
return;
|
|
2711
401
|
}
|
|
2712
|
-
const directLegacyProjectId = normalizeScopeValue(topic[
|
|
402
|
+
const directLegacyProjectId = normalizeScopeValue(topic[LEGACY_SCOPE_FIELD]);
|
|
2713
403
|
if (directLegacyProjectId) {
|
|
2714
404
|
return directLegacyProjectId;
|
|
2715
405
|
}
|
|
2716
406
|
const metadata = topic.metadata || {};
|
|
2717
|
-
const candidate = metadata[
|
|
407
|
+
const candidate = metadata[LEGACY_SCOPE_FIELD] || metadata.legacyProjectId || metadata.projectId || metadata.scopeProjectId;
|
|
2718
408
|
return candidate ? candidate : void 0;
|
|
2719
409
|
}
|
|
2720
410
|
function normalizeScopeValue(value) {
|
|
@@ -2743,7 +433,7 @@ async function findTopicsByScopeAlias(ctx, scopeId) {
|
|
|
2743
433
|
try {
|
|
2744
434
|
return await ctx.db.query("topics").withIndex(
|
|
2745
435
|
"by_graph_scope_project",
|
|
2746
|
-
(q) => q.eq(
|
|
436
|
+
(q) => q.eq(LEGACY_SCOPE_FIELD, scopeId)
|
|
2747
437
|
).collect();
|
|
2748
438
|
} catch {
|
|
2749
439
|
const topics = await ctx.db.query("topics").collect();
|
|
@@ -2759,7 +449,7 @@ async function tryResolveHostTopicById(ctx, topicId) {
|
|
|
2759
449
|
return null;
|
|
2760
450
|
}
|
|
2761
451
|
try {
|
|
2762
|
-
return await ctx.runQuery(
|
|
452
|
+
return await ctx.runQuery(api.topics.get, {
|
|
2763
453
|
id: topicId
|
|
2764
454
|
}) ?? null;
|
|
2765
455
|
} catch {
|
|
@@ -2771,7 +461,7 @@ async function tryResolveHostTopicByLegacyScope(ctx, legacyScopeId) {
|
|
|
2771
461
|
return null;
|
|
2772
462
|
}
|
|
2773
463
|
try {
|
|
2774
|
-
return await ctx.runQuery(
|
|
464
|
+
return await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
2775
465
|
projectId: legacyScopeId
|
|
2776
466
|
}) ?? null;
|
|
2777
467
|
} catch {
|
|
@@ -2909,7 +599,7 @@ function throwWorkspaceIsolationError(args) {
|
|
|
2909
599
|
throw error;
|
|
2910
600
|
}
|
|
2911
601
|
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
2912
|
-
const layer = getLayerForNodeType(args.nodeType);
|
|
602
|
+
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
2913
603
|
if (layer === "ontological") {
|
|
2914
604
|
return;
|
|
2915
605
|
}
|
|
@@ -2937,11 +627,11 @@ function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
|
2937
627
|
const scopeWorkspaceId = normalizeScopeValue2(scope.workspaceId);
|
|
2938
628
|
const nodeTenantId = normalizeScopeValue2(node.tenantId);
|
|
2939
629
|
const nodeWorkspaceId = normalizeScopeValue2(node.workspaceId);
|
|
2940
|
-
const
|
|
630
|
+
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
2941
631
|
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
2942
632
|
return false;
|
|
2943
633
|
}
|
|
2944
|
-
if (
|
|
634
|
+
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
2945
635
|
return true;
|
|
2946
636
|
}
|
|
2947
637
|
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
@@ -2969,11 +659,11 @@ function edgeMatchesWorkspaceReasoningScope(edge, scope) {
|
|
|
2969
659
|
return scopeWorkspaceId === edgeWorkspaceId;
|
|
2970
660
|
}
|
|
2971
661
|
async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
2972
|
-
const
|
|
662
|
+
const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
2973
663
|
const resolved = {
|
|
2974
664
|
tenantId: normalizeScopeValue2(node?.tenantId),
|
|
2975
665
|
workspaceId: normalizeScopeValue2(node?.workspaceId),
|
|
2976
|
-
epistemicLayer
|
|
666
|
+
epistemicLayer,
|
|
2977
667
|
nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
|
|
2978
668
|
};
|
|
2979
669
|
if (!node) {
|
|
@@ -3048,16 +738,17 @@ function resolveTraversalTargetNodeId(edge, direction) {
|
|
|
3048
738
|
}
|
|
3049
739
|
function readNodeOpinion(node) {
|
|
3050
740
|
const metadata = node.metadata ?? {};
|
|
3051
|
-
|
|
3052
|
-
{
|
|
741
|
+
try {
|
|
742
|
+
return readOpinionFromRecord({
|
|
3053
743
|
...metadata,
|
|
3054
744
|
opinion_b: node.opinion_b,
|
|
3055
745
|
opinion_d: node.opinion_d,
|
|
3056
746
|
opinion_u: node.opinion_u,
|
|
3057
747
|
opinion_a: node.opinion_a
|
|
3058
|
-
}
|
|
3059
|
-
|
|
3060
|
-
|
|
748
|
+
});
|
|
749
|
+
} catch {
|
|
750
|
+
return mkOpinion(0, 0, 1, 0.5);
|
|
751
|
+
}
|
|
3061
752
|
}
|
|
3062
753
|
async function collectConfidencePropagationDispatches(args) {
|
|
3063
754
|
const dispatchesByTargetId = /* @__PURE__ */ new Map();
|
|
@@ -3126,14 +817,20 @@ async function collectConfidencePropagationDispatches(args) {
|
|
|
3126
817
|
if (!result || !hasProjectedOpinionChanged(targetOpinion, result.opinion)) {
|
|
3127
818
|
continue;
|
|
3128
819
|
}
|
|
3129
|
-
|
|
820
|
+
const projectedOpinion = mkOpinion(
|
|
821
|
+
result.opinion.b,
|
|
822
|
+
result.opinion.d,
|
|
823
|
+
result.opinion.u,
|
|
824
|
+
result.opinion.a
|
|
825
|
+
);
|
|
826
|
+
opinionCache.set(cacheKey, projectedOpinion);
|
|
3130
827
|
const existingDispatch = dispatchesByTargetId.get(cacheKey);
|
|
3131
828
|
dispatchesByTargetId.set(cacheKey, {
|
|
3132
829
|
targetNodeId,
|
|
3133
830
|
edgeType: spec.edgeType,
|
|
3134
831
|
traversedDirection: direction,
|
|
3135
832
|
weight: edge.weight ?? 1,
|
|
3136
|
-
opinion:
|
|
833
|
+
opinion: projectedOpinion,
|
|
3137
834
|
operator: result.operator,
|
|
3138
835
|
rationale: existingDispatch ? `${existingDispatch.rationale}; ${result.rationale}` : result.rationale,
|
|
3139
836
|
hop: nextHop
|
|
@@ -3141,7 +838,7 @@ async function collectConfidencePropagationDispatches(args) {
|
|
|
3141
838
|
if (canContinueTransitively(spec, nextHop)) {
|
|
3142
839
|
queue.push({
|
|
3143
840
|
nodeId: targetNodeId,
|
|
3144
|
-
opinion:
|
|
841
|
+
opinion: projectedOpinion,
|
|
3145
842
|
hop: nextHop,
|
|
3146
843
|
visitedNodeIds: /* @__PURE__ */ new Set([
|
|
3147
844
|
...state.visitedNodeIds,
|
|
@@ -3256,48 +953,48 @@ async function getQuestionsAnsweredByEvidence(ctx, evidenceId) {
|
|
|
3256
953
|
}
|
|
3257
954
|
|
|
3258
955
|
// src/topicProjectOverlay.ts
|
|
3259
|
-
var
|
|
3260
|
-
function
|
|
956
|
+
var LEGACY_SCOPE_FIELD2 = "graphScopeProjectId";
|
|
957
|
+
function readNonEmptyString(value) {
|
|
3261
958
|
if (typeof value !== "string") {
|
|
3262
959
|
return;
|
|
3263
960
|
}
|
|
3264
961
|
const normalized = value.trim();
|
|
3265
962
|
return normalized.length > 0 ? normalized : void 0;
|
|
3266
963
|
}
|
|
3267
|
-
function
|
|
964
|
+
function readStringArray(value) {
|
|
3268
965
|
if (!Array.isArray(value)) {
|
|
3269
966
|
return [];
|
|
3270
967
|
}
|
|
3271
|
-
return value.map((entry) =>
|
|
968
|
+
return value.map((entry) => readNonEmptyString(entry)).filter((entry) => Boolean(entry));
|
|
3272
969
|
}
|
|
3273
|
-
function
|
|
970
|
+
function readMetadata(topic) {
|
|
3274
971
|
return topic.metadata && typeof topic.metadata === "object" ? topic.metadata : {};
|
|
3275
972
|
}
|
|
3276
|
-
function
|
|
973
|
+
function readLegacyProjectId(value) {
|
|
3277
974
|
if (!value) {
|
|
3278
975
|
return;
|
|
3279
976
|
}
|
|
3280
|
-
return
|
|
977
|
+
return readNonEmptyString(value[LEGACY_SCOPE_FIELD2]);
|
|
3281
978
|
}
|
|
3282
|
-
function
|
|
979
|
+
function coerceVisibility(value) {
|
|
3283
980
|
return value === "private" || value === "team" || value === "firm" || value === "external" || value === "public" ? value : void 0;
|
|
3284
981
|
}
|
|
3285
|
-
function
|
|
982
|
+
function coerceStatus(value) {
|
|
3286
983
|
return value === "active" || value === "archived" || value === "watching" ? value : void 0;
|
|
3287
984
|
}
|
|
3288
|
-
function
|
|
3289
|
-
const explicit =
|
|
985
|
+
function mapProjectType(topic, metadata) {
|
|
986
|
+
const explicit = readNonEmptyString(metadata.projectType);
|
|
3290
987
|
if (explicit) {
|
|
3291
988
|
return explicit;
|
|
3292
989
|
}
|
|
3293
990
|
if (topic.type === "theme") {
|
|
3294
991
|
return "thematic";
|
|
3295
992
|
}
|
|
3296
|
-
return
|
|
993
|
+
return readNonEmptyString(topic.type) || "general";
|
|
3297
994
|
}
|
|
3298
|
-
function
|
|
3299
|
-
const metadata =
|
|
3300
|
-
return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" ||
|
|
995
|
+
function isProjectLikeTopic(topic) {
|
|
996
|
+
const metadata = readMetadata(topic);
|
|
997
|
+
return topic.type === "theme" || topic.type === "thematic" || topic.type === "deal" || topic.type === "monitoring" || readLegacyProjectId(topic) !== void 0 || readNonEmptyString(metadata.projectType) !== void 0;
|
|
3301
998
|
}
|
|
3302
999
|
function isMissingLucernChildComponentError(error) {
|
|
3303
1000
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -3305,7 +1002,7 @@ function isMissingLucernChildComponentError(error) {
|
|
|
3305
1002
|
'Child component ComponentName(Identifier("lucern")) not found'
|
|
3306
1003
|
) || message.includes("Child component") && message.includes("lucern") && message.includes("not found");
|
|
3307
1004
|
}
|
|
3308
|
-
async function
|
|
1005
|
+
async function resolveTopicDoc(ctx, scopeId) {
|
|
3309
1006
|
if (ctx?.db && typeof ctx.db.get === "function") {
|
|
3310
1007
|
try {
|
|
3311
1008
|
const directTopic = await ctx.db.get(scopeId);
|
|
@@ -3319,7 +1016,7 @@ async function resolveTopicDoc2(ctx, scopeId) {
|
|
|
3319
1016
|
return null;
|
|
3320
1017
|
}
|
|
3321
1018
|
try {
|
|
3322
|
-
const topic = await ctx.runQuery(
|
|
1019
|
+
const topic = await ctx.runQuery(api.topics.get, {
|
|
3323
1020
|
id: String(scopeId)
|
|
3324
1021
|
});
|
|
3325
1022
|
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
@@ -3328,7 +1025,7 @@ async function resolveTopicDoc2(ctx, scopeId) {
|
|
|
3328
1025
|
} catch {
|
|
3329
1026
|
}
|
|
3330
1027
|
try {
|
|
3331
|
-
const topic = await ctx.runQuery(
|
|
1028
|
+
const topic = await ctx.runQuery(api.topics.getByLegacyScopeId, {
|
|
3332
1029
|
projectId: String(scopeId)
|
|
3333
1030
|
});
|
|
3334
1031
|
if (topic?.name !== void 0 && topic?.type !== void 0) {
|
|
@@ -3338,14 +1035,14 @@ async function resolveTopicDoc2(ctx, scopeId) {
|
|
|
3338
1035
|
}
|
|
3339
1036
|
return null;
|
|
3340
1037
|
}
|
|
3341
|
-
function
|
|
3342
|
-
const metadata =
|
|
1038
|
+
function materializeTopicProjectOverlay(topic, idMode = "legacy") {
|
|
1039
|
+
const metadata = readMetadata(topic);
|
|
3343
1040
|
const topicId = String(topic._id);
|
|
3344
|
-
const legacyProjectId =
|
|
1041
|
+
const legacyProjectId = readLegacyProjectId(topic) || readLegacyProjectId(metadata) || readNonEmptyString(metadata.legacyProjectId);
|
|
3345
1042
|
const storageProjectId = legacyProjectId || topicId;
|
|
3346
1043
|
const outwardId = idMode === "topic" ? topicId : storageProjectId;
|
|
3347
|
-
const visibility =
|
|
3348
|
-
const status =
|
|
1044
|
+
const visibility = coerceVisibility(topic.visibility) || coerceVisibility(metadata.visibility) || "private";
|
|
1045
|
+
const status = coerceStatus(topic.status) || coerceStatus(metadata.status) || "active";
|
|
3349
1046
|
const createdAt = typeof topic.createdAt === "number" ? topic.createdAt : typeof topic._creationTime === "number" ? topic._creationTime : 0;
|
|
3350
1047
|
const updatedAt = typeof topic.updatedAt === "number" ? topic.updatedAt : typeof metadata.updatedAt === "number" ? metadata.updatedAt : createdAt;
|
|
3351
1048
|
return {
|
|
@@ -3355,16 +1052,16 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
|
|
|
3355
1052
|
topicId,
|
|
3356
1053
|
storageProjectId,
|
|
3357
1054
|
legacyProjectId,
|
|
3358
|
-
name:
|
|
3359
|
-
type:
|
|
3360
|
-
description:
|
|
3361
|
-
ownerId:
|
|
3362
|
-
sharedWith:
|
|
1055
|
+
name: readNonEmptyString(topic.name) || "Untitled Theme",
|
|
1056
|
+
type: mapProjectType(topic, metadata),
|
|
1057
|
+
description: readNonEmptyString(topic.description),
|
|
1058
|
+
ownerId: readNonEmptyString(metadata.ownerId) || readNonEmptyString(topic.createdBy) || "system",
|
|
1059
|
+
sharedWith: readStringArray(metadata.sharedWith),
|
|
3363
1060
|
visibility,
|
|
3364
|
-
tenantId:
|
|
3365
|
-
workspaceId:
|
|
1061
|
+
tenantId: readNonEmptyString(topic.tenantId) || readNonEmptyString(metadata.tenantId),
|
|
1062
|
+
workspaceId: readNonEmptyString(topic.workspaceId) || readNonEmptyString(metadata.workspaceId),
|
|
3366
1063
|
status,
|
|
3367
|
-
tags:
|
|
1064
|
+
tags: readStringArray(metadata.tags),
|
|
3368
1065
|
chatCount: typeof metadata.chatCount === "number" ? metadata.chatCount : 0,
|
|
3369
1066
|
artifactCount: typeof metadata.artifactCount === "number" ? metadata.artifactCount : 0,
|
|
3370
1067
|
lastActivityAt: typeof metadata.lastActivityAt === "number" ? metadata.lastActivityAt : updatedAt,
|
|
@@ -3373,17 +1070,17 @@ function materializeTopicProjectOverlay2(topic, idMode = "legacy") {
|
|
|
3373
1070
|
updatedAt
|
|
3374
1071
|
};
|
|
3375
1072
|
}
|
|
3376
|
-
async function
|
|
3377
|
-
const topic = await
|
|
1073
|
+
async function resolveTopicProjectOverlay(ctx, scopeId, options = {}) {
|
|
1074
|
+
const topic = await resolveTopicDoc(ctx, scopeId);
|
|
3378
1075
|
if (!topic) {
|
|
3379
1076
|
return null;
|
|
3380
1077
|
}
|
|
3381
|
-
if (options.projectLikeOnly !== false && !
|
|
1078
|
+
if (options.projectLikeOnly !== false && !isProjectLikeTopic(topic)) {
|
|
3382
1079
|
return null;
|
|
3383
1080
|
}
|
|
3384
|
-
return
|
|
1081
|
+
return materializeTopicProjectOverlay(topic, options.idMode);
|
|
3385
1082
|
}
|
|
3386
|
-
async function
|
|
1083
|
+
async function listTopicProjectOverlays(ctx, options = {}) {
|
|
3387
1084
|
let allTopics = [];
|
|
3388
1085
|
if (ctx?.db?.query && typeof ctx.db.query === "function") {
|
|
3389
1086
|
try {
|
|
@@ -3393,18 +1090,18 @@ async function listTopicProjectOverlays2(ctx, options = {}) {
|
|
|
3393
1090
|
}
|
|
3394
1091
|
}
|
|
3395
1092
|
if (allTopics.length === 0 && typeof ctx.runQuery === "function") {
|
|
3396
|
-
allTopics = (await ctx.runQuery(
|
|
1093
|
+
allTopics = (await ctx.runQuery(api.topics.list, {}) ?? []) || [];
|
|
3397
1094
|
}
|
|
3398
1095
|
return allTopics.filter(
|
|
3399
|
-
(topic) => options.projectLikeOnly === false ||
|
|
3400
|
-
).map((topic) =>
|
|
1096
|
+
(topic) => options.projectLikeOnly === false || isProjectLikeTopic(topic)
|
|
1097
|
+
).map((topic) => materializeTopicProjectOverlay(topic, options.idMode));
|
|
3401
1098
|
}
|
|
3402
1099
|
async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
3403
|
-
const topic = await
|
|
1100
|
+
const topic = await resolveTopicDoc(ctx, scopeId);
|
|
3404
1101
|
if (!topic) {
|
|
3405
1102
|
return null;
|
|
3406
1103
|
}
|
|
3407
|
-
const nextMetadata = { ...
|
|
1104
|
+
const nextMetadata = { ...readMetadata(topic) };
|
|
3408
1105
|
const patch = {};
|
|
3409
1106
|
const topicUpdateArgs = {
|
|
3410
1107
|
id: String(topic._id)
|
|
@@ -3429,7 +1126,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
3429
1126
|
`patchTopicProjectOverlay cannot mutate ${key} via component-owned topics`
|
|
3430
1127
|
);
|
|
3431
1128
|
case "status": {
|
|
3432
|
-
const status =
|
|
1129
|
+
const status = coerceStatus(rawValue);
|
|
3433
1130
|
if (status) {
|
|
3434
1131
|
patch.status = status;
|
|
3435
1132
|
topicUpdateArgs.status = status;
|
|
@@ -3437,7 +1134,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
3437
1134
|
break;
|
|
3438
1135
|
}
|
|
3439
1136
|
case "visibility": {
|
|
3440
|
-
const visibility =
|
|
1137
|
+
const visibility = coerceVisibility(rawValue);
|
|
3441
1138
|
if (visibility) {
|
|
3442
1139
|
patch.visibility = visibility;
|
|
3443
1140
|
topicUpdateArgs.visibility = visibility;
|
|
@@ -3445,7 +1142,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
3445
1142
|
break;
|
|
3446
1143
|
}
|
|
3447
1144
|
case "type": {
|
|
3448
|
-
const projectType =
|
|
1145
|
+
const projectType = readNonEmptyString(rawValue);
|
|
3449
1146
|
if (projectType) {
|
|
3450
1147
|
nextMetadata.projectType = projectType;
|
|
3451
1148
|
} else {
|
|
@@ -3469,7 +1166,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
3469
1166
|
topicUpdateArgs.metadata = nextMetadata;
|
|
3470
1167
|
if (typeof ctx.runMutation === "function") {
|
|
3471
1168
|
try {
|
|
3472
|
-
await ctx.runMutation(
|
|
1169
|
+
await ctx.runMutation(api.topics.update, topicUpdateArgs);
|
|
3473
1170
|
} catch (error) {
|
|
3474
1171
|
if (!isMissingLucernChildComponentError(error) || !ctx?.db || typeof ctx.db.patch !== "function") {
|
|
3475
1172
|
throw error;
|
|
@@ -3483,7 +1180,7 @@ async function patchTopicProjectOverlay(ctx, scopeId, value) {
|
|
|
3483
1180
|
"Cannot patch topic without component adapter (ctx.runMutation unavailable)"
|
|
3484
1181
|
);
|
|
3485
1182
|
}
|
|
3486
|
-
return
|
|
1183
|
+
return materializeTopicProjectOverlay(
|
|
3487
1184
|
{
|
|
3488
1185
|
...topic,
|
|
3489
1186
|
...patch,
|
|
@@ -3516,10 +1213,10 @@ async function patchProjectWithTolerance(ctx, projectId, value) {
|
|
|
3516
1213
|
});
|
|
3517
1214
|
}
|
|
3518
1215
|
}
|
|
3519
|
-
function
|
|
1216
|
+
function defaultResolvers() {
|
|
3520
1217
|
return {
|
|
3521
1218
|
async getProject(ctx, projectId) {
|
|
3522
|
-
return await
|
|
1219
|
+
return await resolveTopicProjectOverlay(ctx, projectId, {
|
|
3523
1220
|
idMode: "legacy",
|
|
3524
1221
|
projectLikeOnly: false
|
|
3525
1222
|
});
|
|
@@ -3528,7 +1225,7 @@ function defaultResolvers2() {
|
|
|
3528
1225
|
await patchProjectWithTolerance(ctx, projectId, value);
|
|
3529
1226
|
},
|
|
3530
1227
|
async listTopics(ctx) {
|
|
3531
|
-
return await
|
|
1228
|
+
return await listTopicProjectOverlays(ctx, {
|
|
3532
1229
|
idMode: "legacy"
|
|
3533
1230
|
});
|
|
3534
1231
|
},
|
|
@@ -3537,11 +1234,11 @@ function defaultResolvers2() {
|
|
|
3537
1234
|
}
|
|
3538
1235
|
};
|
|
3539
1236
|
}
|
|
3540
|
-
var
|
|
1237
|
+
var resolverOverrides = {};
|
|
3541
1238
|
function resolveGraphPrimitivesAppResolvers(_ctx) {
|
|
3542
1239
|
return {
|
|
3543
|
-
...
|
|
3544
|
-
...
|
|
1240
|
+
...defaultResolvers(),
|
|
1241
|
+
...resolverOverrides
|
|
3545
1242
|
};
|
|
3546
1243
|
}
|
|
3547
1244
|
|
|
@@ -3566,7 +1263,7 @@ function throwStructuredMutationError(args) {
|
|
|
3566
1263
|
function readFiniteNumber(value) {
|
|
3567
1264
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3568
1265
|
}
|
|
3569
|
-
function
|
|
1266
|
+
function clamp01(value) {
|
|
3570
1267
|
return Math.max(0, Math.min(1, value));
|
|
3571
1268
|
}
|
|
3572
1269
|
function assertBaseRateInRange(baseRate, field = "baseRate") {
|
|
@@ -3616,20 +1313,14 @@ function deriveSyntheticBackfillOpinion(source) {
|
|
|
3616
1313
|
const uncertainty = readFiniteNumber(source.opinion_u) ?? readFiniteNumber(source.uncertainty);
|
|
3617
1314
|
const baseRate = readFiniteNumber(source.opinion_a) ?? readFiniteNumber(source.baseRate);
|
|
3618
1315
|
if (belief !== void 0 || disbelief !== void 0 || uncertainty !== void 0 || baseRate !== void 0) {
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
});
|
|
1316
|
+
try {
|
|
1317
|
+
return readOpinionFromRecord(source);
|
|
1318
|
+
} catch {
|
|
1319
|
+
return mkOpinion(0, 0, 1, 0.5);
|
|
1320
|
+
}
|
|
3625
1321
|
}
|
|
3626
|
-
const
|
|
3627
|
-
return
|
|
3628
|
-
b: confidence2,
|
|
3629
|
-
d: 1 - confidence2,
|
|
3630
|
-
u: 0,
|
|
3631
|
-
a: 0.5
|
|
3632
|
-
};
|
|
1322
|
+
const confidence = clamp01(readFiniteNumber(source.confidence) ?? 0);
|
|
1323
|
+
return mkOpinion(confidence, 1 - confidence, 0, 0.5);
|
|
3633
1324
|
}
|
|
3634
1325
|
function clampBeliefLimit(limit, fallback = DEFAULT_PROJECT_BELIEF_LIMIT) {
|
|
3635
1326
|
if (!Number.isFinite(limit)) {
|
|
@@ -3644,16 +1335,17 @@ function readTupleContradictedFlag(value) {
|
|
|
3644
1335
|
return typeof value === "boolean" ? value : void 0;
|
|
3645
1336
|
}
|
|
3646
1337
|
function readBeliefOpinionSnapshot(node, metadata) {
|
|
3647
|
-
|
|
3648
|
-
{
|
|
1338
|
+
try {
|
|
1339
|
+
return readOpinionFromRecord({
|
|
3649
1340
|
...metadata,
|
|
3650
1341
|
opinion_b: node.opinion_b,
|
|
3651
1342
|
opinion_d: node.opinion_d,
|
|
3652
1343
|
opinion_u: node.opinion_u,
|
|
3653
1344
|
opinion_a: node.opinion_a
|
|
3654
|
-
}
|
|
3655
|
-
|
|
3656
|
-
|
|
1345
|
+
});
|
|
1346
|
+
} catch {
|
|
1347
|
+
return mkOpinion(0, 0, 1, 0.5);
|
|
1348
|
+
}
|
|
3657
1349
|
}
|
|
3658
1350
|
function deriveTupleContradictionSeverity(node) {
|
|
3659
1351
|
const metadata = node.metadata || {};
|
|
@@ -3670,10 +1362,10 @@ function formatTupleContradictionDescription(args) {
|
|
|
3670
1362
|
return `Tuple-space contradiction detected: b=${args.opinion.b.toFixed(2)} > ${args.policy.beliefThreshold.toFixed(2)} and d=${args.opinion.d.toFixed(2)} > ${args.policy.disbeliefThreshold.toFixed(2)}.`;
|
|
3671
1363
|
}
|
|
3672
1364
|
function generateContentHash(text) {
|
|
3673
|
-
const
|
|
1365
|
+
const content = `belief:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
|
|
3674
1366
|
let hash = 5381;
|
|
3675
|
-
for (let i = 0; i <
|
|
3676
|
-
hash = (hash << 5) + hash +
|
|
1367
|
+
for (let i = 0; i < content.length; i++) {
|
|
1368
|
+
hash = (hash << 5) + hash + content.charCodeAt(i);
|
|
3677
1369
|
hash &= hash;
|
|
3678
1370
|
}
|
|
3679
1371
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
@@ -3750,8 +1442,8 @@ async function resolveBeliefScopeOrNull(ctx, args) {
|
|
|
3750
1442
|
}
|
|
3751
1443
|
async function getBeliefNodesForScope(ctx, scope, args) {
|
|
3752
1444
|
const baseQuery = ctx.db.query("epistemicNodes").withIndex(
|
|
3753
|
-
|
|
3754
|
-
(q) =>
|
|
1445
|
+
"by_topic_type",
|
|
1446
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
3755
1447
|
);
|
|
3756
1448
|
const nodes = typeof args?.scanLimit === "number" ? await baseQuery.order("desc").take(args.scanLimit) : await baseQuery.collect();
|
|
3757
1449
|
const scopedNodes = nodes.filter(
|
|
@@ -3902,7 +1594,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
3902
1594
|
}
|
|
3903
1595
|
}
|
|
3904
1596
|
const previousConfidence = node.confidence || 0.5;
|
|
3905
|
-
const
|
|
1597
|
+
const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
|
|
3906
1598
|
const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
|
|
3907
1599
|
const slB = args.belief;
|
|
3908
1600
|
const slD = args.disbelief;
|
|
@@ -3929,7 +1621,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
3929
1621
|
currentBeliefStatus,
|
|
3930
1622
|
{
|
|
3931
1623
|
confidence: derivedConfidence,
|
|
3932
|
-
predictionMeta
|
|
1624
|
+
predictionMeta,
|
|
3933
1625
|
metadata: existingMetadata
|
|
3934
1626
|
}
|
|
3935
1627
|
);
|
|
@@ -4101,12 +1793,12 @@ internalMutation({
|
|
|
4101
1793
|
},
|
|
4102
1794
|
returns: permissiveReturn,
|
|
4103
1795
|
handler: async (ctx, args) => {
|
|
4104
|
-
const sourceOpinion =
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
1796
|
+
const sourceOpinion = mkOpinion(
|
|
1797
|
+
args.opinion_b,
|
|
1798
|
+
args.opinion_d,
|
|
1799
|
+
args.opinion_u,
|
|
1800
|
+
args.opinion_a
|
|
1801
|
+
);
|
|
4110
1802
|
const sourceNode = await ctx.db.get(args.nodeId);
|
|
4111
1803
|
const sourceScope = await resolveNodeScopeForWorkspaceIsolation(
|
|
4112
1804
|
ctx,
|
|
@@ -4213,7 +1905,7 @@ mutation({
|
|
|
4213
1905
|
expectedBy: v.optional(v.number())
|
|
4214
1906
|
})
|
|
4215
1907
|
),
|
|
4216
|
-
baseRate: v.number(),
|
|
1908
|
+
baseRate: v.optional(v.number()),
|
|
4217
1909
|
metadata: v.optional(v.any())
|
|
4218
1910
|
// Additional metadata including isConditional
|
|
4219
1911
|
},
|
|
@@ -4244,7 +1936,7 @@ mutation({
|
|
|
4244
1936
|
);
|
|
4245
1937
|
}
|
|
4246
1938
|
const now = Date.now();
|
|
4247
|
-
const baseRate = assertBaseRateInRange(args.baseRate);
|
|
1939
|
+
const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
|
|
4248
1940
|
const initialBeliefStatus = args.worktreeId ? "hypothesis" : "assumption";
|
|
4249
1941
|
const initialEpistemicStatus = args.worktreeId ? "hypothesis" : "assumption";
|
|
4250
1942
|
const seedOpinion = {
|
|
@@ -4583,8 +2275,8 @@ query({
|
|
|
4583
2275
|
}
|
|
4584
2276
|
}
|
|
4585
2277
|
const query2 = ctx.db.query("epistemicNodes").withIndex(
|
|
4586
|
-
|
|
4587
|
-
(q) =>
|
|
2278
|
+
"by_topic_type",
|
|
2279
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
4588
2280
|
);
|
|
4589
2281
|
const nodes = await query2.order("desc").take(scanLimit);
|
|
4590
2282
|
const scopedNodes = nodes.filter(
|
|
@@ -4818,8 +2510,8 @@ mutation({
|
|
|
4818
2510
|
// d: evidence AGAINST [0,1]
|
|
4819
2511
|
uncertainty: v.number(),
|
|
4820
2512
|
// u: lack of evidence [0,1]
|
|
4821
|
-
baseRate: v.
|
|
4822
|
-
// a: prior probability [0,1]
|
|
2513
|
+
baseRate: v.number(),
|
|
2514
|
+
// a: prior probability [0,1]
|
|
4823
2515
|
trigger: v.union(
|
|
4824
2516
|
v.literal("evidence_added"),
|
|
4825
2517
|
v.literal("evidence_removed"),
|
|
@@ -5222,9 +2914,13 @@ query({
|
|
|
5222
2914
|
},
|
|
5223
2915
|
returns: permissiveReturn,
|
|
5224
2916
|
handler: async (ctx, args) => {
|
|
2917
|
+
const scope = await resolveBeliefScopeOrNull(ctx, args);
|
|
2918
|
+
if (!scope) {
|
|
2919
|
+
return { active: 0, superseded: 0, archived: 0, total: 0 };
|
|
2920
|
+
}
|
|
5225
2921
|
const nodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
5226
|
-
|
|
5227
|
-
(q) =>
|
|
2922
|
+
"by_topic_type",
|
|
2923
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
5228
2924
|
).collect();
|
|
5229
2925
|
const counts = {
|
|
5230
2926
|
active: 0,
|
|
@@ -5789,8 +3485,8 @@ query({
|
|
|
5789
3485
|
return [];
|
|
5790
3486
|
}
|
|
5791
3487
|
const nodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
5792
|
-
|
|
5793
|
-
(q) =>
|
|
3488
|
+
"by_topic_type",
|
|
3489
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
5794
3490
|
).collect();
|
|
5795
3491
|
return nodes.filter((n) => {
|
|
5796
3492
|
const metadata = n.metadata;
|
|
@@ -5966,7 +3662,7 @@ internalMutation({
|
|
|
5966
3662
|
args: {
|
|
5967
3663
|
...optionalBeliefScopeArgs,
|
|
5968
3664
|
formulation: v.string(),
|
|
5969
|
-
baseRate: v.number(),
|
|
3665
|
+
baseRate: v.optional(v.number()),
|
|
5970
3666
|
confidence: v.optional(
|
|
5971
3667
|
v.union(v.literal("high"), v.literal("medium"), v.literal("low"))
|
|
5972
3668
|
),
|
|
@@ -6002,7 +3698,7 @@ internalMutation({
|
|
|
6002
3698
|
returns: permissiveReturn,
|
|
6003
3699
|
handler: async (ctx, args) => {
|
|
6004
3700
|
const now = Date.now();
|
|
6005
|
-
const baseRate = assertBaseRateInRange(args.baseRate);
|
|
3701
|
+
const baseRate = assertBaseRateInRange(args.baseRate ?? 0.5);
|
|
6006
3702
|
const scope = await resolveTopicProjectScope(ctx, {
|
|
6007
3703
|
topicId: args.topicId,
|
|
6008
3704
|
projectId: args.projectId
|
|
@@ -6251,15 +3947,15 @@ internalMutation({
|
|
|
6251
3947
|
skippedHasHistory++;
|
|
6252
3948
|
continue;
|
|
6253
3949
|
}
|
|
6254
|
-
const
|
|
3950
|
+
const opinion = deriveSyntheticBackfillOpinion(node);
|
|
6255
3951
|
await ctx.db.insert(
|
|
6256
3952
|
"beliefConfidence",
|
|
6257
3953
|
buildBeliefConfidenceRow({
|
|
6258
3954
|
beliefId: node._id,
|
|
6259
|
-
belief:
|
|
6260
|
-
disbelief:
|
|
6261
|
-
uncertainty:
|
|
6262
|
-
baseRate:
|
|
3955
|
+
belief: opinion.b,
|
|
3956
|
+
disbelief: opinion.d,
|
|
3957
|
+
uncertainty: opinion.u,
|
|
3958
|
+
baseRate: opinion.a,
|
|
6263
3959
|
trigger: "backfill_synthetic",
|
|
6264
3960
|
rationale: "LK-6 backfill: synthesized t0 from node-level opinion fields (no prior beliefConfidence row found).",
|
|
6265
3961
|
assessedAt: readFiniteNumber(node.createdAt) ?? readFiniteNumber(node.updatedAt) ?? Date.now(),
|