@lucern/graph-primitives 0.1.0-alpha.3 → 0.3.0-alpha.0
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 +199 -18
- package/dist/beliefDecay.js.map +1 -1
- package/dist/beliefEvidenceLinks.js.map +1 -1
- package/dist/confidencePropagationDispatch.js.map +1 -1
- package/dist/contradictions.js.map +1 -1
- package/dist/entityBridge.js.map +1 -1
- package/dist/entityLifecycle.js.map +1 -1
- package/dist/epistemicAnswers.js +21 -36
- package/dist/epistemicAnswers.js.map +1 -1
- package/dist/epistemicBeliefs.js +92 -651
- package/dist/epistemicBeliefs.js.map +1 -1
- package/dist/epistemicContracts.js +65 -624
- package/dist/epistemicContracts.js.map +1 -1
- package/dist/epistemicEdges.js.map +1 -1
- package/dist/epistemicEvidence.js +71 -630
- package/dist/epistemicEvidence.js.map +1 -1
- package/dist/epistemicHelpers.js +3 -2
- package/dist/epistemicHelpers.js.map +1 -1
- package/dist/epistemicLinking.js.map +1 -1
- package/dist/epistemicNodes.js +49 -585
- package/dist/epistemicNodes.js.map +1 -1
- package/dist/epistemicQuestions.js +46 -590
- package/dist/epistemicQuestions.js.map +1 -1
- package/dist/epistemicSources.js +29 -565
- package/dist/epistemicSources.js.map +1 -1
- package/dist/evaluators/index.js +65 -624
- package/dist/evaluators/index.js.map +1 -1
- package/dist/index.js +304 -905
- package/dist/index.js.map +1 -1
- package/dist/ontologyApproval.js.map +1 -1
- package/dist/ontologyDefinitions.js.map +1 -1
- package/dist/ontologyRegistry.js.map +1 -1
- package/dist/projectionReconciliation.js.map +1 -1
- package/dist/questionEvidenceLinks.js +188 -2
- package/dist/questionEvidenceLinks.js.map +1 -1
- package/dist/workspaceIsolation.js +30 -581
- package/dist/workspaceIsolation.js.map +1 -1
- package/package.json +5 -6
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { v } from 'convex/values';
|
|
2
|
-
import { componentsGeneric, queryGeneric, mutationGeneric, anyApi,
|
|
2
|
+
import { componentsGeneric, queryGeneric, mutationGeneric, anyApi, internalMutationGeneric, internalQueryGeneric, internalActionGeneric } from 'convex/server';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __export = (target, all) => {
|
|
@@ -533,23 +533,23 @@ var DEADLINE_URGENCY = {
|
|
|
533
533
|
action: "OVERDUE \u2014 must validate or archive immediately"
|
|
534
534
|
}
|
|
535
535
|
};
|
|
536
|
-
function normalizeBeliefConfidence(
|
|
537
|
-
if (typeof
|
|
536
|
+
function normalizeBeliefConfidence(confidence) {
|
|
537
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
538
538
|
return null;
|
|
539
539
|
}
|
|
540
|
-
if (
|
|
541
|
-
return
|
|
540
|
+
if (confidence >= 0 && confidence <= 1) {
|
|
541
|
+
return confidence;
|
|
542
542
|
}
|
|
543
|
-
if (
|
|
544
|
-
return
|
|
543
|
+
if (confidence > 1 && confidence <= 100) {
|
|
544
|
+
return confidence / 100;
|
|
545
545
|
}
|
|
546
546
|
return null;
|
|
547
547
|
}
|
|
548
|
-
function hasResolvedPredictionOutcome(
|
|
549
|
-
if (!
|
|
548
|
+
function hasResolvedPredictionOutcome(predictionMeta) {
|
|
549
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
550
550
|
return false;
|
|
551
551
|
}
|
|
552
|
-
const outcome =
|
|
552
|
+
const outcome = predictionMeta.outcome;
|
|
553
553
|
return outcome === "confirmed" || outcome === "disconfirmed" || outcome === "partial" || outcome === "expired";
|
|
554
554
|
}
|
|
555
555
|
function resolveLifecycleBucket(args) {
|
|
@@ -609,10 +609,10 @@ function computeDeadlineUrgency(expectedBy) {
|
|
|
609
609
|
isOverdue: daysToDeadline < 0
|
|
610
610
|
};
|
|
611
611
|
}
|
|
612
|
-
function computeEffectiveDecay(lastScoredAt, expectedBy,
|
|
612
|
+
function computeEffectiveDecay(lastScoredAt, expectedBy, beliefStatus) {
|
|
613
613
|
const base = computeBaseDecay(lastScoredAt);
|
|
614
614
|
const urgency = computeDeadlineUrgency(expectedBy);
|
|
615
|
-
const effectiveWeight = (urgency ? base.weight * urgency.urgencyMultiplier : base.weight) * lifecycleMultiplier(
|
|
615
|
+
const effectiveWeight = (urgency ? base.weight * urgency.urgencyMultiplier : base.weight) * lifecycleMultiplier(beliefStatus);
|
|
616
616
|
const urgencyRescoreDays = urgency?.urgencyTier.rescoreIntervalDays ?? Number.POSITIVE_INFINITY;
|
|
617
617
|
const rescoreInDays = Math.min(base.tier.rescoreInDays, urgencyRescoreDays);
|
|
618
618
|
const rescoreByDate = lastScoredAt + rescoreInDays * 24 * 60 * 60 * 1e3;
|
|
@@ -632,7 +632,7 @@ function computeEffectiveDecay(lastScoredAt, expectedBy, beliefStatus2) {
|
|
|
632
632
|
};
|
|
633
633
|
}
|
|
634
634
|
function getRescoringSchedule(opts) {
|
|
635
|
-
const
|
|
635
|
+
const lifecycleStatus = resolveLifecycleBucket({
|
|
636
636
|
beliefStatus: opts.beliefStatus,
|
|
637
637
|
confidence: opts.confidence,
|
|
638
638
|
predictionMeta: opts.predictionMeta
|
|
@@ -640,16 +640,16 @@ function getRescoringSchedule(opts) {
|
|
|
640
640
|
const decayState = computeEffectiveDecay(
|
|
641
641
|
opts.lastScoredAt,
|
|
642
642
|
opts.expectedBy,
|
|
643
|
-
|
|
643
|
+
lifecycleStatus
|
|
644
644
|
);
|
|
645
645
|
const daysUntilRescore = (decayState.rescoreByDate - Date.now()) / (1e3 * 60 * 60 * 24);
|
|
646
646
|
const isOverdue = daysUntilRescore < 0;
|
|
647
647
|
let priority;
|
|
648
648
|
let reason;
|
|
649
|
-
if (isOverdue &&
|
|
649
|
+
if (isOverdue && lifecycleStatus === "assumption") {
|
|
650
650
|
priority = "critical";
|
|
651
651
|
reason = `Untested assumption is stale (${Math.round(decayState.ageDays)}d) \u2014 validate or supersede`;
|
|
652
|
-
} else if (isOverdue &&
|
|
652
|
+
} else if (isOverdue && lifecycleStatus === "hypothesis" || lifecycleStatus === "hypothesis" && daysUntilRescore < 7) {
|
|
653
653
|
priority = "high";
|
|
654
654
|
reason = `Hypothesis aging without validation (${Math.round(decayState.ageDays)}d) \u2014 run/finish sprint testing`;
|
|
655
655
|
} else if (decayState.urgency?.isOverdue) {
|
|
@@ -2416,7 +2416,11 @@ var identifyBeliefsNeedingRescore = query({
|
|
|
2416
2416
|
},
|
|
2417
2417
|
returns: permissiveReturn,
|
|
2418
2418
|
handler: async (ctx, args) => {
|
|
2419
|
-
const {
|
|
2419
|
+
const { maxResults = 20, minPriority = "medium" } = args;
|
|
2420
|
+
const scope = await resolveTopicProjectScope(ctx, args).catch(() => null);
|
|
2421
|
+
if (!scope) {
|
|
2422
|
+
return [];
|
|
2423
|
+
}
|
|
2420
2424
|
const priorityRank = {
|
|
2421
2425
|
critical: 4,
|
|
2422
2426
|
high: 3,
|
|
@@ -2425,39 +2429,39 @@ var identifyBeliefsNeedingRescore = query({
|
|
|
2425
2429
|
};
|
|
2426
2430
|
const minRank = priorityRank[minPriority] ?? 2;
|
|
2427
2431
|
const beliefs = await ctx.db.query("epistemicNodes").withIndex(
|
|
2428
|
-
|
|
2429
|
-
(q) =>
|
|
2432
|
+
"by_topic_type",
|
|
2433
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
2430
2434
|
).collect();
|
|
2431
2435
|
const activeBeliefs = beliefs.filter((b) => b.status === "active");
|
|
2432
2436
|
const results = [];
|
|
2433
2437
|
for (const belief of activeBeliefs) {
|
|
2434
2438
|
const metadata = belief.metadata || {};
|
|
2435
|
-
const
|
|
2436
|
-
const
|
|
2437
|
-
const
|
|
2439
|
+
const predictionMeta = belief.predictionMeta;
|
|
2440
|
+
const temporalNature = belief.temporalNature || "unknown";
|
|
2441
|
+
const beliefStatus = belief.beliefStatus || metadata.beliefStatus || null;
|
|
2438
2442
|
const confidenceHistory = await ctx.db.query("beliefConfidence").withIndex("by_beliefId", (q) => q.eq("beliefId", belief._id)).collect();
|
|
2439
2443
|
const sorted = confidenceHistory.sort(
|
|
2440
2444
|
(a, b) => b.assessedAt - a.assessedAt
|
|
2441
2445
|
);
|
|
2442
2446
|
const lastEntry = sorted[0] ?? null;
|
|
2443
2447
|
const lastScoredAt = lastEntry?.assessedAt || belief.updatedAt || belief.createdAt || Date.now();
|
|
2444
|
-
const
|
|
2448
|
+
const confidence = lastEntry?.confidence ?? metadata.confidence ?? 0.5;
|
|
2445
2449
|
const schedule = getRescoringSchedule({
|
|
2446
2450
|
lastScoredAt,
|
|
2447
|
-
temporalNature
|
|
2448
|
-
expectedBy:
|
|
2449
|
-
predictionMeta:
|
|
2450
|
-
confidence
|
|
2451
|
-
beliefStatus
|
|
2451
|
+
temporalNature,
|
|
2452
|
+
expectedBy: predictionMeta?.expectedBy ?? null,
|
|
2453
|
+
predictionMeta: predictionMeta ?? null,
|
|
2454
|
+
confidence,
|
|
2455
|
+
beliefStatus
|
|
2452
2456
|
});
|
|
2453
2457
|
if (priorityRank[schedule.priority] >= minRank) {
|
|
2454
2458
|
results.push({
|
|
2455
2459
|
beliefId: belief._id,
|
|
2456
2460
|
beliefText: belief.canonicalText,
|
|
2457
|
-
confidence
|
|
2458
|
-
beliefStatus:
|
|
2459
|
-
temporalNature
|
|
2460
|
-
expectedBy:
|
|
2461
|
+
confidence,
|
|
2462
|
+
beliefStatus: beliefStatus ?? "assumption",
|
|
2463
|
+
temporalNature,
|
|
2464
|
+
expectedBy: predictionMeta?.expectedBy ?? null,
|
|
2461
2465
|
lastScoredAt,
|
|
2462
2466
|
daysSinceScoring: Math.round(schedule.decay.ageDays),
|
|
2463
2467
|
schedule
|
|
@@ -2516,34 +2520,29 @@ var getGlobalBeliefHealth = query({
|
|
|
2516
2520
|
);
|
|
2517
2521
|
const allResults = [];
|
|
2518
2522
|
for (const project2 of accessibleProjects.slice(0, 20)) {
|
|
2519
|
-
const
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
).
|
|
2528
|
-
|
|
2529
|
-
const beliefs = Array.from(
|
|
2530
|
-
new Map(
|
|
2531
|
-
[...topicBeliefs, ...projectBeliefs].map((b) => [String(b._id), b])
|
|
2532
|
-
).values()
|
|
2533
|
-
);
|
|
2523
|
+
const scope = await resolveTopicProjectScope(ctx, {
|
|
2524
|
+
projectId: String(project2._id)
|
|
2525
|
+
}).catch(() => null);
|
|
2526
|
+
if (!scope) {
|
|
2527
|
+
continue;
|
|
2528
|
+
}
|
|
2529
|
+
const beliefs = await ctx.db.query("epistemicNodes").withIndex(
|
|
2530
|
+
"by_topic_type",
|
|
2531
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
2532
|
+
).collect();
|
|
2534
2533
|
const activeBeliefs = beliefs.filter((b) => b.status === "active");
|
|
2535
2534
|
for (const belief of activeBeliefs) {
|
|
2536
2535
|
const metadata = belief.metadata || {};
|
|
2537
|
-
const
|
|
2538
|
-
const
|
|
2539
|
-
const
|
|
2536
|
+
const predictionMeta = belief.predictionMeta;
|
|
2537
|
+
const temporalNature = belief.temporalNature || "unknown";
|
|
2538
|
+
const confidence = belief.confidence ?? metadata.confidence ?? 0.5;
|
|
2540
2539
|
const lastScoredAt = belief.updatedAt || belief.createdAt || belief._creationTime;
|
|
2541
2540
|
const schedule = getRescoringSchedule({
|
|
2542
2541
|
lastScoredAt,
|
|
2543
|
-
temporalNature
|
|
2544
|
-
expectedBy:
|
|
2545
|
-
predictionMeta:
|
|
2546
|
-
confidence
|
|
2542
|
+
temporalNature,
|
|
2543
|
+
expectedBy: predictionMeta?.expectedBy ?? null,
|
|
2544
|
+
predictionMeta: predictionMeta ?? null,
|
|
2545
|
+
confidence,
|
|
2547
2546
|
beliefStatus: belief.beliefStatus || metadata.beliefStatus || null
|
|
2548
2547
|
});
|
|
2549
2548
|
if (priorityRank[schedule.priority] >= minRank) {
|
|
@@ -2552,9 +2551,9 @@ var getGlobalBeliefHealth = query({
|
|
|
2552
2551
|
projectName: project2.name,
|
|
2553
2552
|
beliefId: belief._id,
|
|
2554
2553
|
beliefText: belief.canonicalText,
|
|
2555
|
-
confidence
|
|
2556
|
-
temporalNature
|
|
2557
|
-
expectedBy:
|
|
2554
|
+
confidence,
|
|
2555
|
+
temporalNature,
|
|
2556
|
+
expectedBy: predictionMeta?.expectedBy ?? null,
|
|
2558
2557
|
daysSinceScoring: Math.round(schedule.decay.ageDays),
|
|
2559
2558
|
priority: schedule.priority,
|
|
2560
2559
|
reason: schedule.reason,
|
|
@@ -2608,27 +2607,27 @@ var getBeliefDecayInfo = query({
|
|
|
2608
2607
|
return null;
|
|
2609
2608
|
}
|
|
2610
2609
|
const metadata = belief.metadata || {};
|
|
2611
|
-
const
|
|
2612
|
-
const
|
|
2610
|
+
const predictionMeta = belief.predictionMeta;
|
|
2611
|
+
const temporalNature = belief.temporalNature || "unknown";
|
|
2613
2612
|
const confidenceHistory = await ctx.db.query("beliefConfidence").withIndex("by_beliefId", (q) => q.eq("beliefId", args.beliefId)).collect();
|
|
2614
2613
|
const sorted = confidenceHistory.sort(
|
|
2615
2614
|
(a, b) => b.assessedAt - a.assessedAt
|
|
2616
2615
|
);
|
|
2617
2616
|
const lastEntry = sorted[0] ?? null;
|
|
2618
2617
|
const lastScoredAt = lastEntry?.assessedAt || belief.updatedAt || belief.createdAt || Date.now();
|
|
2619
|
-
const
|
|
2618
|
+
const confidence = lastEntry?.confidence ?? metadata.confidence ?? 0.5;
|
|
2620
2619
|
const schedule = getRescoringSchedule({
|
|
2621
2620
|
lastScoredAt,
|
|
2622
|
-
temporalNature
|
|
2623
|
-
expectedBy:
|
|
2624
|
-
predictionMeta:
|
|
2625
|
-
confidence
|
|
2621
|
+
temporalNature,
|
|
2622
|
+
expectedBy: predictionMeta?.expectedBy ?? null,
|
|
2623
|
+
predictionMeta: predictionMeta ?? null,
|
|
2624
|
+
confidence,
|
|
2626
2625
|
beliefStatus: belief.beliefStatus || metadata.beliefStatus || null
|
|
2627
2626
|
});
|
|
2628
2627
|
const decay = schedule.decay;
|
|
2629
2628
|
return {
|
|
2630
|
-
confidence
|
|
2631
|
-
decayedConfidence:
|
|
2629
|
+
confidence,
|
|
2630
|
+
decayedConfidence: confidence * decay.effectiveWeight,
|
|
2632
2631
|
freshness: {
|
|
2633
2632
|
label: decay.baseTier.label,
|
|
2634
2633
|
ageDays: Math.round(decay.ageDays),
|
|
@@ -3402,30 +3401,30 @@ var RESOLVED_PREDICTION_OUTCOMES = [
|
|
|
3402
3401
|
function isBeliefLifecycleStatus(value) {
|
|
3403
3402
|
return typeof value === "string" && BELIEF_STATUS_VALUES.includes(value);
|
|
3404
3403
|
}
|
|
3405
|
-
function normalizeBeliefConfidence2(
|
|
3406
|
-
if (typeof
|
|
3404
|
+
function normalizeBeliefConfidence2(confidence) {
|
|
3405
|
+
if (typeof confidence !== "number" || !Number.isFinite(confidence)) {
|
|
3407
3406
|
return null;
|
|
3408
3407
|
}
|
|
3409
|
-
if (
|
|
3410
|
-
return
|
|
3408
|
+
if (confidence >= 0 && confidence <= 1) {
|
|
3409
|
+
return confidence;
|
|
3411
3410
|
}
|
|
3412
|
-
if (
|
|
3413
|
-
return
|
|
3411
|
+
if (confidence > 1 && confidence <= 100) {
|
|
3412
|
+
return confidence / 100;
|
|
3414
3413
|
}
|
|
3415
3414
|
return null;
|
|
3416
3415
|
}
|
|
3417
|
-
function isResolvedByConfidence(
|
|
3418
|
-
const normalized = normalizeBeliefConfidence2(
|
|
3416
|
+
function isResolvedByConfidence(confidence) {
|
|
3417
|
+
const normalized = normalizeBeliefConfidence2(confidence);
|
|
3419
3418
|
if (normalized === null) {
|
|
3420
3419
|
return false;
|
|
3421
3420
|
}
|
|
3422
3421
|
return normalized <= 0 || normalized >= 1;
|
|
3423
3422
|
}
|
|
3424
|
-
function hasResolvedPredictionOutcome2(
|
|
3425
|
-
if (!
|
|
3423
|
+
function hasResolvedPredictionOutcome2(predictionMeta) {
|
|
3424
|
+
if (!predictionMeta || typeof predictionMeta !== "object") {
|
|
3426
3425
|
return false;
|
|
3427
3426
|
}
|
|
3428
|
-
const outcome =
|
|
3427
|
+
const outcome = predictionMeta.outcome;
|
|
3429
3428
|
return typeof outcome === "string" && RESOLVED_PREDICTION_OUTCOMES.includes(outcome);
|
|
3430
3429
|
}
|
|
3431
3430
|
function getPredictionMetaFromMetadata(metadata) {
|
|
@@ -4392,7 +4391,7 @@ var EDGE_TYPE_TO_REL = {
|
|
|
4392
4391
|
about_entity: "ABOUT_ENTITY",
|
|
4393
4392
|
entity_referenced_in: "ENTITY_REFERENCED_IN"
|
|
4394
4393
|
};
|
|
4395
|
-
function getNodeLayer(
|
|
4394
|
+
function getNodeLayer(nodeType) {
|
|
4396
4395
|
const L4_TYPES = ["decision"];
|
|
4397
4396
|
const L3_TYPES = ["belief", "question", "theme", "deal"];
|
|
4398
4397
|
const L2_TYPES = ["claim", "evidence", "synthesis", "answer"];
|
|
@@ -4405,29 +4404,29 @@ function getNodeLayer(nodeType2) {
|
|
|
4405
4404
|
"value_chain"
|
|
4406
4405
|
];
|
|
4407
4406
|
const ORGANIZATIONAL_TYPES = ["topic"];
|
|
4408
|
-
if (L4_TYPES.includes(
|
|
4407
|
+
if (L4_TYPES.includes(nodeType)) {
|
|
4409
4408
|
return "L4";
|
|
4410
4409
|
}
|
|
4411
|
-
if (L3_TYPES.includes(
|
|
4410
|
+
if (L3_TYPES.includes(nodeType)) {
|
|
4412
4411
|
return "L3";
|
|
4413
4412
|
}
|
|
4414
|
-
if (L2_TYPES.includes(
|
|
4413
|
+
if (L2_TYPES.includes(nodeType)) {
|
|
4415
4414
|
return "L2";
|
|
4416
4415
|
}
|
|
4417
|
-
if (L1_TYPES.includes(
|
|
4416
|
+
if (L1_TYPES.includes(nodeType)) {
|
|
4418
4417
|
return "L1";
|
|
4419
4418
|
}
|
|
4420
|
-
if (ONTOLOGICAL_TYPES.includes(
|
|
4419
|
+
if (ONTOLOGICAL_TYPES.includes(nodeType)) {
|
|
4421
4420
|
return "ontological";
|
|
4422
4421
|
}
|
|
4423
|
-
if (ORGANIZATIONAL_TYPES.includes(
|
|
4422
|
+
if (ORGANIZATIONAL_TYPES.includes(nodeType)) {
|
|
4424
4423
|
return "organizational";
|
|
4425
4424
|
}
|
|
4426
|
-
console.warn(`[GraphTypes] Unknown nodeType "${
|
|
4425
|
+
console.warn(`[GraphTypes] Unknown nodeType "${nodeType}", defaulting to L2`);
|
|
4427
4426
|
return "L2";
|
|
4428
4427
|
}
|
|
4429
|
-
function getNeo4jLabel(
|
|
4430
|
-
return NODE_TYPE_TO_LABEL[
|
|
4428
|
+
function getNeo4jLabel(nodeType) {
|
|
4429
|
+
return NODE_TYPE_TO_LABEL[nodeType] || nodeType.charAt(0).toUpperCase() + nodeType.slice(1);
|
|
4431
4430
|
}
|
|
4432
4431
|
function getNeo4jRelType(edgeType) {
|
|
4433
4432
|
return EDGE_TYPE_TO_REL[edgeType] || edgeType.toUpperCase();
|
|
@@ -5103,14 +5102,14 @@ __export(entityValidation_exports, {
|
|
|
5103
5102
|
isRegisteredEntityType: () => isRegisteredEntityType,
|
|
5104
5103
|
validateEntityMetadata: () => validateEntityMetadata
|
|
5105
5104
|
});
|
|
5106
|
-
async function getEntityTypeSchema(ctx,
|
|
5105
|
+
async function getEntityTypeSchema(ctx, nodeType, tenantId) {
|
|
5107
5106
|
if (tenantId) {
|
|
5108
5107
|
const tenantEntry = await ctx.db.query("schemaEnumConfig").withIndex(
|
|
5109
5108
|
"by_tenant_category",
|
|
5110
5109
|
(q) => q.eq("tenantId", tenantId).eq("category", "entity_type")
|
|
5111
5110
|
).collect();
|
|
5112
5111
|
const tenantMatch = tenantEntry.find(
|
|
5113
|
-
(e) => e.value ===
|
|
5112
|
+
(e) => e.value === nodeType && e.status === "active"
|
|
5114
5113
|
);
|
|
5115
5114
|
if (tenantMatch?.metadata?.schema) {
|
|
5116
5115
|
return tenantMatch.metadata.schema;
|
|
@@ -5118,21 +5117,21 @@ async function getEntityTypeSchema(ctx, nodeType2, tenantId) {
|
|
|
5118
5117
|
}
|
|
5119
5118
|
const platformEntry = await ctx.db.query("schemaEnumConfig").withIndex(
|
|
5120
5119
|
"by_category_value",
|
|
5121
|
-
(q) => q.eq("category", "entity_type").eq("value",
|
|
5120
|
+
(q) => q.eq("category", "entity_type").eq("value", nodeType)
|
|
5122
5121
|
).first();
|
|
5123
5122
|
if (platformEntry?.metadata?.schema && platformEntry.status === "active") {
|
|
5124
5123
|
return platformEntry.metadata.schema;
|
|
5125
5124
|
}
|
|
5126
5125
|
return null;
|
|
5127
5126
|
}
|
|
5128
|
-
async function validateEntityMetadata(ctx,
|
|
5127
|
+
async function validateEntityMetadata(ctx, nodeType, metadata, tenantId) {
|
|
5129
5128
|
const errors = [];
|
|
5130
|
-
const schema = await getEntityTypeSchema(ctx,
|
|
5129
|
+
const schema = await getEntityTypeSchema(ctx, nodeType, tenantId);
|
|
5131
5130
|
if (!schema) {
|
|
5132
5131
|
return {
|
|
5133
5132
|
valid: false,
|
|
5134
5133
|
errors: [
|
|
5135
|
-
`No registered schema for entity type "${
|
|
5134
|
+
`No registered schema for entity type "${nodeType}". Register it in schemaEnumConfig (category="entity_type") before creating entities of this type.`
|
|
5136
5135
|
]
|
|
5137
5136
|
};
|
|
5138
5137
|
}
|
|
@@ -5165,8 +5164,8 @@ async function validateEntityMetadata(ctx, nodeType2, metadata, tenantId) {
|
|
|
5165
5164
|
errors
|
|
5166
5165
|
};
|
|
5167
5166
|
}
|
|
5168
|
-
async function isRegisteredEntityType(ctx,
|
|
5169
|
-
const schema = await getEntityTypeSchema(ctx,
|
|
5167
|
+
async function isRegisteredEntityType(ctx, nodeType, tenantId) {
|
|
5168
|
+
const schema = await getEntityTypeSchema(ctx, nodeType, tenantId);
|
|
5170
5169
|
return schema !== null;
|
|
5171
5170
|
}
|
|
5172
5171
|
|
|
@@ -5212,7 +5211,7 @@ async function resolveTopicOntologyInternal(ctx, topicId) {
|
|
|
5212
5211
|
"by_ontologyId",
|
|
5213
5212
|
(q) => q.eq("ontologyId", current?.ontologyId)
|
|
5214
5213
|
).collect();
|
|
5215
|
-
const published = versions.filter((
|
|
5214
|
+
const published = versions.filter((v21) => v21.status === "published").sort((a, b) => (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
|
|
5216
5215
|
const latestPublished = published[0] ?? null;
|
|
5217
5216
|
return {
|
|
5218
5217
|
ontologyId: ontologyDef._id,
|
|
@@ -5233,7 +5232,7 @@ async function resolveTopicOntologyInternal(ctx, topicId) {
|
|
|
5233
5232
|
}
|
|
5234
5233
|
return null;
|
|
5235
5234
|
}
|
|
5236
|
-
async function validateEntityTypeForTopic(ctx, topicId,
|
|
5235
|
+
async function validateEntityTypeForTopic(ctx, topicId, nodeType) {
|
|
5237
5236
|
const resolved = await resolveTopicOntologyInternal(ctx, topicId);
|
|
5238
5237
|
if (!resolved) {
|
|
5239
5238
|
return { valid: true };
|
|
@@ -5241,12 +5240,12 @@ async function validateEntityTypeForTopic(ctx, topicId, nodeType2) {
|
|
|
5241
5240
|
if (resolved.validEntityTypes.length === 0) {
|
|
5242
5241
|
return { valid: true };
|
|
5243
5242
|
}
|
|
5244
|
-
if (resolved.validEntityTypes.includes(
|
|
5243
|
+
if (resolved.validEntityTypes.includes(nodeType)) {
|
|
5245
5244
|
return { valid: true };
|
|
5246
5245
|
}
|
|
5247
5246
|
return {
|
|
5248
5247
|
valid: false,
|
|
5249
|
-
error: `Entity type "${
|
|
5248
|
+
error: `Entity type "${nodeType}" is not defined in the ontology "${resolved.ontologyKey}" (${resolved.ontologyName}). Valid entity types: ${resolved.validEntityTypes.join(", ")}. Source: ${resolved.source} from topic ${resolved.sourceTopicId}.`
|
|
5250
5249
|
};
|
|
5251
5250
|
}
|
|
5252
5251
|
|
|
@@ -5286,11 +5285,11 @@ async function requireProjectWriteAccess(ctx, projectId, userId) {
|
|
|
5286
5285
|
});
|
|
5287
5286
|
}
|
|
5288
5287
|
}
|
|
5289
|
-
function generateContentHash(
|
|
5290
|
-
const
|
|
5288
|
+
function generateContentHash(nodeType, text) {
|
|
5289
|
+
const content = `${nodeType}:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
|
|
5291
5290
|
let hash = 5381;
|
|
5292
|
-
for (let i = 0; i <
|
|
5293
|
-
hash = (hash << 5) + hash +
|
|
5291
|
+
for (let i = 0; i < content.length; i++) {
|
|
5292
|
+
hash = (hash << 5) + hash + content.charCodeAt(i);
|
|
5294
5293
|
hash &= hash;
|
|
5295
5294
|
}
|
|
5296
5295
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
@@ -5302,8 +5301,8 @@ var ONTOLOGICAL_NODE_TYPES = [
|
|
|
5302
5301
|
"function",
|
|
5303
5302
|
"value_chain"
|
|
5304
5303
|
];
|
|
5305
|
-
function isOntologicalNodeType(
|
|
5306
|
-
return ONTOLOGICAL_NODE_TYPES.includes(
|
|
5304
|
+
function isOntologicalNodeType(nodeType) {
|
|
5305
|
+
return ONTOLOGICAL_NODE_TYPES.includes(nodeType);
|
|
5307
5306
|
}
|
|
5308
5307
|
function normalizeCanonicalEntityText(value) {
|
|
5309
5308
|
return value.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -6103,10 +6102,8 @@ async function queryRegistryRows(ctx, args) {
|
|
|
6103
6102
|
async function listAudienceRegistryRows(ctx, args) {
|
|
6104
6103
|
return queryRegistryRows(ctx, args);
|
|
6105
6104
|
}
|
|
6106
|
-
componentsGeneric();
|
|
6107
|
-
var internal2 = anyApi;
|
|
6108
6105
|
|
|
6109
|
-
//
|
|
6106
|
+
// ../../packages/contracts/src/schema-helpers/enumValidation.ts
|
|
6110
6107
|
var BUILTIN_ENUM_FALLBACK = {
|
|
6111
6108
|
topic_type: /* @__PURE__ */ new Set([
|
|
6112
6109
|
"domain",
|
|
@@ -6149,7 +6146,6 @@ var BUILTIN_ENUM_FALLBACK = {
|
|
|
6149
6146
|
"tradeoff",
|
|
6150
6147
|
"policy",
|
|
6151
6148
|
"implementation_choice",
|
|
6152
|
-
// Coding intelligence domain
|
|
6153
6149
|
"implementation_decision",
|
|
6154
6150
|
"interface_contract",
|
|
6155
6151
|
"migration_state",
|
|
@@ -6157,25 +6153,16 @@ var BUILTIN_ENUM_FALLBACK = {
|
|
|
6157
6153
|
"deprecation_notice"
|
|
6158
6154
|
]),
|
|
6159
6155
|
edge_type: /* @__PURE__ */ new Set([
|
|
6160
|
-
// === 6 CANONICAL EPISTEMIC TYPES ===
|
|
6161
6156
|
"supports",
|
|
6162
|
-
// L3↔L3: belief bears on belief (weight -1 to +1)
|
|
6163
6157
|
"informs",
|
|
6164
|
-
// L2→L3: evidence bears on belief
|
|
6165
6158
|
"depends_on",
|
|
6166
|
-
// L3→L3, Q→Q: structural gate
|
|
6167
6159
|
"derived_from",
|
|
6168
|
-
// Any→Any: provenance chain
|
|
6169
6160
|
"contains",
|
|
6170
|
-
// Any→Any: hierarchy, scoping, membership
|
|
6171
6161
|
"tests",
|
|
6172
|
-
// Q→L3: question interrogates belief
|
|
6173
|
-
// === STRUCTURAL / LIFECYCLE ===
|
|
6174
6162
|
"supersedes",
|
|
6175
6163
|
"responds_to",
|
|
6176
6164
|
"belongs_to",
|
|
6177
6165
|
"relates_to_thesis",
|
|
6178
|
-
// === ONTOLOGICAL (tenant-extensible) ===
|
|
6179
6166
|
"works_at",
|
|
6180
6167
|
"invested_in",
|
|
6181
6168
|
"competes_with",
|
|
@@ -6224,27 +6211,12 @@ var BUILTIN_ENUM_FALLBACK = {
|
|
|
6224
6211
|
function normalizeEnumValue(value) {
|
|
6225
6212
|
return value.trim().toLowerCase();
|
|
6226
6213
|
}
|
|
6227
|
-
async function validateSchemaEnumValue(
|
|
6214
|
+
async function validateSchemaEnumValue(_ctx, args) {
|
|
6228
6215
|
const normalized = normalizeEnumValue(args.value);
|
|
6229
6216
|
if (!normalized) {
|
|
6230
6217
|
return { valid: false, source: "none" };
|
|
6231
6218
|
}
|
|
6232
|
-
|
|
6233
|
-
const validFromSchema = await ctx.runQuery(
|
|
6234
|
-
internal2.schemaConfig.internalValidate,
|
|
6235
|
-
{
|
|
6236
|
-
category: args.category,
|
|
6237
|
-
value: normalized,
|
|
6238
|
-
tenantId: args.tenantId
|
|
6239
|
-
}
|
|
6240
|
-
);
|
|
6241
|
-
if (validFromSchema) {
|
|
6242
|
-
return { valid: true, source: "schema" };
|
|
6243
|
-
}
|
|
6244
|
-
} catch {
|
|
6245
|
-
}
|
|
6246
|
-
const fallback = BUILTIN_ENUM_FALLBACK[args.category];
|
|
6247
|
-
if (fallback.has(normalized)) {
|
|
6219
|
+
if (BUILTIN_ENUM_FALLBACK[args.category].has(normalized)) {
|
|
6248
6220
|
return { valid: true, source: "builtin" };
|
|
6249
6221
|
}
|
|
6250
6222
|
return { valid: false, source: "none" };
|
|
@@ -6265,572 +6237,36 @@ async function assertSchemaEnumValue(ctx, args) {
|
|
|
6265
6237
|
if (!validation.valid) {
|
|
6266
6238
|
const tenantHint = args.tenantId ? ` for tenant ${args.tenantId}` : "";
|
|
6267
6239
|
throw new Error(
|
|
6268
|
-
`[${args.context}] Invalid value "${normalized}" for category "${args.category}"${tenantHint}. Add it to
|
|
6240
|
+
`[${args.context}] Invalid value "${normalized}" for category "${args.category}"${tenantHint}. Add it to the contracts schema enum manifest before use.`
|
|
6269
6241
|
);
|
|
6270
6242
|
}
|
|
6271
6243
|
return normalized;
|
|
6272
6244
|
}
|
|
6273
|
-
v.number();
|
|
6274
|
-
v.union(
|
|
6275
|
-
v.literal("very_high"),
|
|
6276
|
-
// 0.9+
|
|
6277
|
-
v.literal("high"),
|
|
6278
|
-
// 0.7-0.9
|
|
6279
|
-
v.literal("medium"),
|
|
6280
|
-
// 0.4-0.7
|
|
6281
|
-
v.literal("low"),
|
|
6282
|
-
// 0.2-0.4
|
|
6283
|
-
v.literal("very_low")
|
|
6284
|
-
// 0-0.2
|
|
6285
|
-
);
|
|
6286
|
-
v.union(
|
|
6287
|
-
v.literal(1),
|
|
6288
|
-
// Critical
|
|
6289
|
-
v.literal(2),
|
|
6290
|
-
// High
|
|
6291
|
-
v.literal(3),
|
|
6292
|
-
// Medium
|
|
6293
|
-
v.literal(4),
|
|
6294
|
-
// Low
|
|
6295
|
-
v.literal(5)
|
|
6296
|
-
// Backlog
|
|
6297
|
-
);
|
|
6298
|
-
v.union(
|
|
6299
|
-
v.literal("critical"),
|
|
6300
|
-
v.literal("high"),
|
|
6301
|
-
v.literal("medium"),
|
|
6302
|
-
v.literal("low"),
|
|
6303
|
-
v.literal("backlog")
|
|
6304
|
-
);
|
|
6305
|
-
v.union(
|
|
6306
|
-
v.literal("active"),
|
|
6307
|
-
v.literal("paused"),
|
|
6308
|
-
v.literal("completed"),
|
|
6309
|
-
v.literal("archived")
|
|
6310
|
-
);
|
|
6311
|
-
v.union(
|
|
6312
|
-
v.literal("pending"),
|
|
6313
|
-
v.literal("processing"),
|
|
6314
|
-
v.literal("completed"),
|
|
6315
|
-
v.literal("failed")
|
|
6316
|
-
);
|
|
6317
|
-
v.object({
|
|
6318
|
-
crunchbaseId: v.optional(v.string()),
|
|
6319
|
-
linkedinUrl: v.optional(v.string()),
|
|
6320
|
-
pitchbookId: v.optional(v.string()),
|
|
6321
|
-
twitterUrl: v.optional(v.string()),
|
|
6322
|
-
domain: v.optional(v.string())
|
|
6323
|
-
});
|
|
6324
|
-
var sourceType = v.union(
|
|
6325
|
-
v.literal("proprietary"),
|
|
6326
|
-
// Internal Stack research
|
|
6327
|
-
v.literal("primary"),
|
|
6328
|
-
// Direct interviews, calls
|
|
6329
|
-
v.literal("secondary"),
|
|
6330
|
-
// Published sources
|
|
6331
|
-
v.literal("ai_generated"),
|
|
6332
|
-
// AI-synthesized
|
|
6333
|
-
v.literal("user_input"),
|
|
6334
|
-
// Manual user entry
|
|
6335
|
-
v.literal("inferred")
|
|
6336
|
-
// System inference
|
|
6337
|
-
);
|
|
6338
|
-
v.object({
|
|
6339
|
-
sourceType: v.optional(sourceType),
|
|
6340
|
-
sourceId: v.optional(v.string()),
|
|
6341
|
-
// Reference to source entity
|
|
6342
|
-
sourceUrl: v.optional(v.string()),
|
|
6343
|
-
sourceDate: v.optional(v.number()),
|
|
6344
|
-
sourceName: v.optional(v.string())
|
|
6345
|
-
});
|
|
6346
|
-
v.object({
|
|
6347
|
-
cursor: v.optional(v.string()),
|
|
6348
|
-
limit: v.optional(v.number())
|
|
6349
|
-
});
|
|
6350
|
-
v.object({
|
|
6351
|
-
hasMore: v.boolean(),
|
|
6352
|
-
nextCursor: v.optional(v.string()),
|
|
6353
|
-
totalCount: v.optional(v.number())
|
|
6354
|
-
});
|
|
6355
|
-
var richTextContent = v.object({
|
|
6356
|
-
type: v.literal("doc"),
|
|
6357
|
-
content: looseJsonArray
|
|
6358
|
-
});
|
|
6359
|
-
v.union(v.string(), richTextContent);
|
|
6360
|
-
v.object({
|
|
6361
|
-
promptTokens: v.optional(v.number()),
|
|
6362
|
-
completionTokens: v.optional(v.number()),
|
|
6363
|
-
totalTokens: v.optional(v.number())
|
|
6364
|
-
});
|
|
6365
|
-
v.object({
|
|
6366
|
-
fileName: v.optional(v.string()),
|
|
6367
|
-
fileSize: v.optional(v.number()),
|
|
6368
|
-
mimeType: v.optional(v.string()),
|
|
6369
|
-
storageId: v.optional(v.id("_storage")),
|
|
6370
|
-
externalUrl: v.optional(v.string())
|
|
6371
|
-
});
|
|
6372
6245
|
|
|
6373
|
-
//
|
|
6374
|
-
var
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
// Immutable answer snapshot for a question
|
|
6398
|
-
// --- L1: Terminal Leaves (non-traversable, grounding) ---
|
|
6399
|
-
v.literal("atomic_fact"),
|
|
6400
|
-
// Raw fact from source (not interpreted)
|
|
6401
|
-
v.literal("excerpt"),
|
|
6402
|
-
// Direct quote from source document
|
|
6403
|
-
v.literal("source"),
|
|
6404
|
-
// News, documents, transcripts
|
|
6405
|
-
// --- Ontological Entities (things in the world) ---
|
|
6406
|
-
v.literal("company"),
|
|
6407
|
-
// Organization (subtype: private, corporate, portfolio)
|
|
6408
|
-
v.literal("person"),
|
|
6409
|
-
// Individual (founder, expert, LP, contact)
|
|
6410
|
-
v.literal("investor"),
|
|
6411
|
-
// Investment entity (subtype: vc, lp, cvc, pe, family_office, angel)
|
|
6412
|
-
v.literal("function"),
|
|
6413
|
-
// What a company does (from classifier)
|
|
6414
|
-
v.literal("value_chain")
|
|
6415
|
-
// Market structure / value flow
|
|
6416
|
-
);
|
|
6417
|
-
var epistemicLayer = v.union(
|
|
6418
|
-
v.literal("L4"),
|
|
6419
|
-
// Decisions, outcomes - audit targets
|
|
6420
|
-
v.literal("L3"),
|
|
6421
|
-
// Beliefs, questions, themes - traversal anchors
|
|
6422
|
-
v.literal("L2"),
|
|
6423
|
-
// Claims, evidence, synthesis - compression boundary
|
|
6424
|
-
v.literal("L1"),
|
|
6425
|
-
// Atomic facts, excerpts, sources - terminal leaves
|
|
6426
|
-
v.literal("ontological"),
|
|
6427
|
-
// Companies, people, etc - not epistemic
|
|
6428
|
-
v.literal("organizational")
|
|
6429
|
-
// Topics, lenses, worktrees — structural containers
|
|
6430
|
-
);
|
|
6431
|
-
var nodeStatus = v.union(
|
|
6432
|
-
v.literal("active"),
|
|
6433
|
-
v.literal("superseded"),
|
|
6434
|
-
// Replaced by newer version
|
|
6435
|
-
v.literal("archived"),
|
|
6436
|
-
v.literal("deleted")
|
|
6437
|
-
);
|
|
6438
|
-
var sourceType2 = v.union(
|
|
6439
|
-
v.literal("human"),
|
|
6440
|
-
// User created directly
|
|
6441
|
-
v.literal("ai_extracted"),
|
|
6442
|
-
// LLM extracted from a source
|
|
6443
|
-
v.literal("ai_generated"),
|
|
6444
|
-
// LLM synthesized/created
|
|
6445
|
-
v.literal("imported"),
|
|
6446
|
-
// External system import
|
|
6447
|
-
v.literal("system"),
|
|
6448
|
-
// System-generated (migrations, classifiers)
|
|
6449
|
-
v.literal("verified"),
|
|
6450
|
-
// Human-verified source
|
|
6451
|
-
v.literal("proprietary")
|
|
6452
|
-
// Proprietary/internal data
|
|
6453
|
-
);
|
|
6454
|
-
var verificationStatus = v.union(
|
|
6455
|
-
v.literal("unverified"),
|
|
6456
|
-
v.literal("human_verified"),
|
|
6457
|
-
v.literal("ai_verified"),
|
|
6458
|
-
v.literal("contradicted"),
|
|
6459
|
-
v.literal("outdated")
|
|
6460
|
-
);
|
|
6461
|
-
var syncStatus = v.union(
|
|
6462
|
-
v.literal("synced"),
|
|
6463
|
-
// Node and edges fully synced to Neo4j
|
|
6464
|
-
v.literal("pending_edges"),
|
|
6465
|
-
// Node created, edges being created
|
|
6466
|
-
v.literal("edge_creation_failed")
|
|
6467
|
-
// Edge creation failed, needs retry
|
|
6468
|
-
);
|
|
6469
|
-
var audienceLabel = v.string();
|
|
6470
|
-
var sensitivityTier = v.union(
|
|
6471
|
-
v.literal("low"),
|
|
6472
|
-
v.literal("medium"),
|
|
6473
|
-
v.literal("high"),
|
|
6474
|
-
v.literal("restricted")
|
|
6475
|
-
);
|
|
6476
|
-
var exportClass = v.union(
|
|
6477
|
-
v.literal("internal_only"),
|
|
6478
|
-
v.literal("client_safe"),
|
|
6479
|
-
v.literal("public_safe"),
|
|
6480
|
-
v.literal("restricted")
|
|
6481
|
-
);
|
|
6482
|
-
var anonymizationClass = v.union(
|
|
6483
|
-
v.literal("none"),
|
|
6484
|
-
v.literal("standard"),
|
|
6485
|
-
v.literal("strict")
|
|
6486
|
-
);
|
|
6487
|
-
var epistemicStatus = v.union(
|
|
6488
|
-
v.literal("hypothesis"),
|
|
6489
|
-
// Initial conjecture, low evidence
|
|
6490
|
-
v.literal("emerging"),
|
|
6491
|
-
// Building evidence, gaining traction
|
|
6492
|
-
v.literal("established"),
|
|
6493
|
-
// Well-evidenced, core to thesis
|
|
6494
|
-
v.literal("challenged"),
|
|
6495
|
-
// Contradicting evidence appeared
|
|
6496
|
-
v.literal("assumption"),
|
|
6497
|
-
// Taken as given, not actively tested
|
|
6498
|
-
v.literal("deprecated")
|
|
6499
|
-
// Superseded or abandoned
|
|
6500
|
-
);
|
|
6501
|
-
var beliefStatus = v.union(
|
|
6502
|
-
v.literal("assumption"),
|
|
6503
|
-
v.literal("hypothesis"),
|
|
6504
|
-
v.literal("belief"),
|
|
6505
|
-
v.literal("fact")
|
|
6506
|
-
);
|
|
6507
|
-
var reversibility = v.union(
|
|
6508
|
-
v.literal("irreversible"),
|
|
6509
|
-
// One-way door decision
|
|
6510
|
-
v.literal("hard_to_reverse"),
|
|
6511
|
-
// Significant cost to undo
|
|
6512
|
-
v.literal("reversible"),
|
|
6513
|
-
// Can change course with moderate effort
|
|
6514
|
-
v.literal("trivial")
|
|
6515
|
-
// Easy to adjust
|
|
6516
|
-
);
|
|
6517
|
-
var predictionOutcome = v.union(
|
|
6518
|
-
v.literal("pending"),
|
|
6519
|
-
v.literal("confirmed"),
|
|
6520
|
-
v.literal("disconfirmed"),
|
|
6521
|
-
v.literal("partial"),
|
|
6522
|
-
v.literal("expired")
|
|
6523
|
-
);
|
|
6524
|
-
var predictionMeta = v.object({
|
|
6525
|
-
isPrediction: v.boolean(),
|
|
6526
|
-
registeredAt: v.number(),
|
|
6527
|
-
// When prediction was made
|
|
6528
|
-
expectedBy: v.optional(v.number()),
|
|
6529
|
-
// When we expect resolution
|
|
6530
|
-
outcome: v.optional(predictionOutcome),
|
|
6531
|
-
outcomeRecordedAt: v.optional(v.number()),
|
|
6532
|
-
outcomeEvidenceId: v.optional(v.string()),
|
|
6533
|
-
// globalId of confirming evidence
|
|
6534
|
-
confidenceAtPrediction: v.optional(v.number()),
|
|
6535
|
-
// 0-1
|
|
6536
|
-
actualVsPredicted: v.optional(v.string())
|
|
6537
|
-
// Notes on how outcome compared
|
|
6538
|
-
});
|
|
6539
|
-
var methodology = v.union(
|
|
6540
|
-
// Primary Research (high value)
|
|
6541
|
-
v.literal("primary_research"),
|
|
6542
|
-
// Direct investigation
|
|
6543
|
-
v.literal("expert_interview"),
|
|
6544
|
-
// Expert call/interview
|
|
6545
|
-
v.literal("customer_interview"),
|
|
6546
|
-
// Customer research
|
|
6547
|
-
v.literal("field_observation"),
|
|
6548
|
-
// On-site observation
|
|
6549
|
-
v.literal("proprietary_data"),
|
|
6550
|
-
// Internal data analysis
|
|
6551
|
-
// Secondary Research
|
|
6552
|
-
v.literal("desk_research"),
|
|
6553
|
-
// Public sources
|
|
6554
|
-
v.literal("regulatory_filing"),
|
|
6555
|
-
// SEC, regulatory docs
|
|
6556
|
-
v.literal("news_article"),
|
|
6557
|
-
// News/press
|
|
6558
|
-
v.literal("academic_paper"),
|
|
6559
|
-
// Academic research
|
|
6560
|
-
// AI-Assisted
|
|
6561
|
-
v.literal("ai_synthesis"),
|
|
6562
|
-
// AI-generated synthesis
|
|
6563
|
-
v.literal("ai_extraction")
|
|
6564
|
-
// AI-extracted from source
|
|
6565
|
-
);
|
|
6566
|
-
var informationAsymmetry = v.union(
|
|
6567
|
-
v.literal("proprietary"),
|
|
6568
|
-
// Only we have this
|
|
6569
|
-
v.literal("early"),
|
|
6570
|
-
// We're early but others will get it
|
|
6571
|
-
v.literal("common")
|
|
6572
|
-
// Everyone has access
|
|
6573
|
-
);
|
|
6574
|
-
var temporalNature = v.union(
|
|
6575
|
-
v.literal("factual"),
|
|
6576
|
-
// Resolved outcome. Grounded in reality.
|
|
6577
|
-
v.literal("forecast"),
|
|
6578
|
-
// Prediction. Will resolve. Discounted weight.
|
|
6579
|
-
v.literal("unknown")
|
|
6580
|
-
// Not yet classified.
|
|
6581
|
-
);
|
|
6582
|
-
var questionType = v.union(
|
|
6583
|
-
v.literal("validation"),
|
|
6584
|
-
// Does evidence support this belief?
|
|
6585
|
-
v.literal("falsification"),
|
|
6586
|
-
// What would prove this belief wrong?
|
|
6587
|
-
v.literal("assumption_probe"),
|
|
6588
|
-
// Is this unstated assumption true?
|
|
6589
|
-
v.literal("prediction_test"),
|
|
6590
|
-
// Will this predicted outcome occur?
|
|
6591
|
-
v.literal("counterfactual"),
|
|
6592
|
-
// What would we expect if X were false?
|
|
6593
|
-
v.literal("discovery"),
|
|
6594
|
-
// What don't we know yet?
|
|
6595
|
-
v.literal("clarification"),
|
|
6596
|
-
// What does X actually mean?
|
|
6597
|
-
v.literal("comparison"),
|
|
6598
|
-
// How does X compare to Y?
|
|
6599
|
-
v.literal("causal"),
|
|
6600
|
-
// What caused X?
|
|
6601
|
-
v.literal("mechanism"),
|
|
6602
|
-
// How does X work?
|
|
6603
|
-
v.literal("general")
|
|
6604
|
-
// Unclassified
|
|
6605
|
-
);
|
|
6606
|
-
var questionPriority = v.union(
|
|
6607
|
-
v.literal("critical"),
|
|
6608
|
-
// Blocks decision-making
|
|
6609
|
-
v.literal("high"),
|
|
6610
|
-
// Important for thesis
|
|
6611
|
-
v.literal("medium"),
|
|
6612
|
-
// Would be nice to know
|
|
6613
|
-
v.literal("low")
|
|
6614
|
-
// Background/curiosity
|
|
6615
|
-
);
|
|
6616
|
-
var answerQuality = v.union(
|
|
6617
|
-
v.literal("definitive"),
|
|
6618
|
-
// Clear, well-supported
|
|
6619
|
-
v.literal("strong"),
|
|
6620
|
-
// Good evidence, high confidence
|
|
6621
|
-
v.literal("moderate"),
|
|
6622
|
-
// Some evidence
|
|
6623
|
-
v.literal("weak"),
|
|
6624
|
-
// Limited evidence
|
|
6625
|
-
v.literal("speculative"),
|
|
6626
|
-
// Mostly conjecture
|
|
6627
|
-
v.literal("unanswered")
|
|
6628
|
-
// No answer yet
|
|
6629
|
-
);
|
|
6630
|
-
var consensusView = v.union(
|
|
6631
|
-
v.literal("aligned"),
|
|
6632
|
-
// We agree with market consensus
|
|
6633
|
-
v.literal("ahead_of"),
|
|
6634
|
-
// We see this before consensus does
|
|
6635
|
-
v.literal("contrarian"),
|
|
6636
|
-
// We actively disagree with consensus
|
|
6637
|
-
v.literal("orthogonal"),
|
|
6638
|
-
// We're looking at something consensus isn't discussing
|
|
6639
|
-
v.literal("unknown")
|
|
6640
|
-
// We don't know what consensus thinks
|
|
6641
|
-
);
|
|
6642
|
-
var themeConviction = v.union(
|
|
6643
|
-
v.literal("high"),
|
|
6644
|
-
// Strong conviction, actively deploying
|
|
6645
|
-
v.literal("medium"),
|
|
6646
|
-
// Building conviction
|
|
6647
|
-
v.literal("low"),
|
|
6648
|
-
// Exploring, not convicted
|
|
6649
|
-
v.literal("negative")
|
|
6650
|
-
// Actively avoiding
|
|
6651
|
-
);
|
|
6652
|
-
var decisionType = v.union(
|
|
6653
|
-
v.literal("invest"),
|
|
6654
|
-
v.literal("pass"),
|
|
6655
|
-
v.literal("follow_on"),
|
|
6656
|
-
v.literal("exit"),
|
|
6657
|
-
v.literal("deep_dive"),
|
|
6658
|
-
v.literal("monitor"),
|
|
6659
|
-
v.literal("deprioritize"),
|
|
6660
|
-
v.literal("thesis_adopt"),
|
|
6661
|
-
v.literal("thesis_revise"),
|
|
6662
|
-
v.literal("thesis_abandon")
|
|
6663
|
-
);
|
|
6664
|
-
var decisionOutcome = v.union(
|
|
6665
|
-
v.literal("pending"),
|
|
6666
|
-
v.literal("successful"),
|
|
6667
|
-
v.literal("unsuccessful"),
|
|
6668
|
-
v.literal("mixed"),
|
|
6669
|
-
v.literal("unknown")
|
|
6670
|
-
);
|
|
6671
|
-
var externalIds2 = v.object({
|
|
6672
|
-
crunchbase: v.optional(v.string()),
|
|
6673
|
-
linkedin: v.optional(v.string()),
|
|
6674
|
-
pitchbook: v.optional(v.string()),
|
|
6675
|
-
twitter: v.optional(v.string()),
|
|
6676
|
-
website: v.optional(v.string())
|
|
6677
|
-
});
|
|
6678
|
-
defineTable({
|
|
6679
|
-
// === IDENTITY ===
|
|
6680
|
-
globalId: v.string(),
|
|
6681
|
-
// UUID - survives migration to Neo4j
|
|
6682
|
-
// === TYPE ===
|
|
6683
|
-
nodeType,
|
|
6684
|
-
// === EPISTEMIC LAYER ===
|
|
6685
|
-
epistemicLayer: v.optional(epistemicLayer),
|
|
6686
|
-
// === SUBTYPE (for typed entities) ===
|
|
6687
|
-
subtype: v.optional(v.string()),
|
|
6688
|
-
// company: private|corporate|portfolio, investor: vc|lp|cvc|pe|family_office|angel
|
|
6689
|
-
// === CONTENT ===
|
|
6690
|
-
canonicalText: v.string(),
|
|
6691
|
-
// The core content (belief statement, company name, etc.)
|
|
6692
|
-
contentHash: v.string(),
|
|
6693
|
-
// SHA256(nodeType + canonicalText) for deduplication
|
|
6694
|
-
// Extended content (for sources/syntheses)
|
|
6695
|
-
content: v.optional(v.string()),
|
|
6696
|
-
// Full text for documents/articles
|
|
6697
|
-
contentType: v.optional(v.string()),
|
|
6698
|
-
// "markdown", "html", "pdf", "text"
|
|
6699
|
-
// === METADATA ===
|
|
6700
|
-
title: v.optional(v.string()),
|
|
6701
|
-
// Display title
|
|
6702
|
-
tags: v.optional(v.array(v.string())),
|
|
6703
|
-
domain: v.optional(v.string()),
|
|
6704
|
-
// For companies: website domain
|
|
6705
|
-
// Type-specific metadata (flexible object - LEGACY)
|
|
6706
|
-
// New code should use the typed fields below when available
|
|
6707
|
-
metadata: v.optional(looseJsonObject),
|
|
6708
|
-
// === POLICY / ENTITLEMENT ===
|
|
6709
|
-
tenantId: v.optional(v.string()),
|
|
6710
|
-
workspaceId: v.optional(v.string()),
|
|
6711
|
-
ownerPrincipalId: v.optional(v.string()),
|
|
6712
|
-
audienceLabel: v.optional(audienceLabel),
|
|
6713
|
-
policyTags: v.optional(v.array(v.string())),
|
|
6714
|
-
sensitivityTier: v.optional(sensitivityTier),
|
|
6715
|
-
exportClass: v.optional(exportClass),
|
|
6716
|
-
anonymizationClass: v.optional(anonymizationClass),
|
|
6717
|
-
// === PUBLICATION (visibility-based, not copy-based) ===
|
|
6718
|
-
// Publication expands who can see a workspace-local node — the node stays
|
|
6719
|
-
// in its workspace, like a microservice exposing part of its API surface.
|
|
6720
|
-
// Rules-based: pack/tenant-level publicationRules auto-evaluate on
|
|
6721
|
-
// confidence changes and node creation. No manual click-by-click.
|
|
6722
|
-
publicationStatus: v.optional(
|
|
6723
|
-
v.union(
|
|
6724
|
-
v.literal("unpublished"),
|
|
6725
|
-
// Default: workspace-local only
|
|
6726
|
-
v.literal("published"),
|
|
6727
|
-
// Visible at tenant scope (rules matched)
|
|
6728
|
-
v.literal("suppressed")
|
|
6729
|
-
// Manually blocked even if rules match
|
|
6730
|
-
)
|
|
6731
|
-
),
|
|
6732
|
-
publishedAt: v.optional(v.number()),
|
|
6733
|
-
// When publication status last changed to published
|
|
6734
|
-
publishedBy: v.optional(v.string()),
|
|
6735
|
-
// userId or "system:publication_rules" for auto-publish
|
|
6736
|
-
// === TYPED METADATA FIELDS ===
|
|
6737
|
-
// --- Belief ---
|
|
6738
|
-
// Belief type — validated against schemaEnumConfig category "belief_type"
|
|
6739
|
-
// Platform core: hypothesis, belief, principle, invariant, assumption,
|
|
6740
|
-
// tenet, prior, preference, goal, forecast
|
|
6741
|
-
beliefType: v.optional(v.string()),
|
|
6742
|
-
beliefStatus: v.optional(beliefStatus),
|
|
6743
|
-
epistemicStatus: v.optional(epistemicStatus),
|
|
6744
|
-
reversibility: v.optional(reversibility),
|
|
6745
|
-
predictionMeta: v.optional(predictionMeta),
|
|
6746
|
-
// Consensus tracking (for non-consensus detection)
|
|
6747
|
-
consensusView: v.optional(consensusView),
|
|
6748
|
-
consensusConfidence: v.optional(v.number()),
|
|
6749
|
-
// 0-1: What we think consensus confidence is
|
|
6750
|
-
consensusSource: v.optional(v.string()),
|
|
6751
|
-
// Where we got the consensus view (twitter, reports, etc.)
|
|
6752
|
-
// --- Evidence ---
|
|
6753
|
-
methodology: v.optional(methodology),
|
|
6754
|
-
informationAsymmetry: v.optional(informationAsymmetry),
|
|
6755
|
-
temporalNature: v.optional(temporalNature),
|
|
6756
|
-
// --- Question ---
|
|
6757
|
-
questionType: v.optional(questionType),
|
|
6758
|
-
questionPriority: v.optional(questionPriority),
|
|
6759
|
-
answerQuality: v.optional(answerQuality),
|
|
6760
|
-
// --- Theme ---
|
|
6761
|
-
themeConviction: v.optional(themeConviction),
|
|
6762
|
-
// Market timing (for "early on theme" detection)
|
|
6763
|
-
marketAwarenessDate: v.optional(v.number()),
|
|
6764
|
-
// When this theme became broadly discussed
|
|
6765
|
-
marketAwarenessSource: v.optional(v.string()),
|
|
6766
|
-
// How we know (first major report, twitter volume spike, etc.)
|
|
6767
|
-
earlySignalIds: v.optional(v.array(v.string())),
|
|
6768
|
-
// globalIds of evidence we had before market awareness
|
|
6769
|
-
// --- Decision ---
|
|
6770
|
-
decisionType: v.optional(decisionType),
|
|
6771
|
-
decisionOutcome: v.optional(decisionOutcome),
|
|
6772
|
-
// === EXTERNAL IDS (for ontological entities) ===
|
|
6773
|
-
externalIds: v.optional(externalIds2),
|
|
6774
|
-
// === PROVENANCE ===
|
|
6775
|
-
sourceType: sourceType2,
|
|
6776
|
-
aiProvider: v.optional(v.string()),
|
|
6777
|
-
// "claude", "gemini", "gpt-4", etc.
|
|
6778
|
-
extractedFromNodeId: v.optional(v.id("epistemicNodes")),
|
|
6779
|
-
// Quick reference to source
|
|
6780
|
-
// === EXTRACTION CONTEXT ===
|
|
6781
|
-
extractionModel: v.optional(v.string()),
|
|
6782
|
-
// "claude-sonnet-4-20250514"
|
|
6783
|
-
extractionPromptName: v.optional(v.string()),
|
|
6784
|
-
// "lucern/extract-evidence"
|
|
6785
|
-
extractionPromptVersion: v.optional(v.number()),
|
|
6786
|
-
extractionTemperature: v.optional(v.number()),
|
|
6787
|
-
extractionLangfuseTraceId: v.optional(v.string()),
|
|
6788
|
-
// === GROUNDING VERIFICATION ===
|
|
6789
|
-
groundingVerified: v.optional(v.boolean()),
|
|
6790
|
-
groundingConfidence: v.optional(v.number()),
|
|
6791
|
-
// 0-1 match quality
|
|
6792
|
-
groundingMatchedText: v.optional(v.string()),
|
|
6793
|
-
// Actual text from source
|
|
6794
|
-
groundingStartOffset: v.optional(v.number()),
|
|
6795
|
-
groundingEndOffset: v.optional(v.number()),
|
|
6796
|
-
groundingRejectionReason: v.optional(v.string()),
|
|
6797
|
-
// === CONFIDENCE & VERIFICATION ===
|
|
6798
|
-
confidence: v.optional(v.number()),
|
|
6799
|
-
// 0-1 projected probability P(x) = b + a*u
|
|
6800
|
-
verificationStatus: v.optional(verificationStatus),
|
|
6801
|
-
// === SL OPINION (Subjective Logic — Kernel v2) ===
|
|
6802
|
-
// Replaces scalar confidence with rich epistemic state.
|
|
6803
|
-
// b + d + u = 1. P(x) = b + a*u is stored in `confidence` for backward compat.
|
|
6804
|
-
opinion_b: v.optional(v.number()),
|
|
6805
|
-
// Belief: evidence FOR (0-1)
|
|
6806
|
-
opinion_d: v.optional(v.number()),
|
|
6807
|
-
// Disbelief: evidence AGAINST (0-1)
|
|
6808
|
-
opinion_u: v.optional(v.number()),
|
|
6809
|
-
// Uncertainty: absence of evidence (0-1)
|
|
6810
|
-
opinion_a: v.optional(v.number()),
|
|
6811
|
-
// Base rate / prior probability (0-1)
|
|
6812
|
-
tupleContradicted: v.optional(v.boolean()),
|
|
6813
|
-
// Single-belief tuple-space contradiction flag
|
|
6814
|
-
// === LIFECYCLE ===
|
|
6815
|
-
status: nodeStatus,
|
|
6816
|
-
supersededBy: v.optional(v.id("epistemicNodes")),
|
|
6817
|
-
// === OWNERSHIP ===
|
|
6818
|
-
topicId: v.optional(v.string()),
|
|
6819
|
-
// Canonical scope container (topic-first model)
|
|
6820
|
-
projectId: v.optional(v.string()),
|
|
6821
|
-
// DEPRECATED: Use belongs_to edges
|
|
6822
|
-
createdBy: v.string(),
|
|
6823
|
-
// Clerk user ID
|
|
6824
|
-
createdAt: v.number(),
|
|
6825
|
-
updatedAt: v.number(),
|
|
6826
|
-
// === NEO4J SYNC STATUS ===
|
|
6827
|
-
syncStatus: v.optional(syncStatus),
|
|
6828
|
-
syncError: v.optional(v.string())
|
|
6829
|
-
// Error message if sync failed
|
|
6830
|
-
}).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", {
|
|
6831
|
-
searchField: "canonicalText",
|
|
6832
|
-
filterFields: ["nodeType", "projectId", "topicId", "status"]
|
|
6833
|
-
});
|
|
6246
|
+
// ../../packages/contracts/src/schema-helpers/spine/tables/epistemicNodes.ts
|
|
6247
|
+
var NODE_TYPES = [
|
|
6248
|
+
"decision",
|
|
6249
|
+
"belief",
|
|
6250
|
+
"question",
|
|
6251
|
+
"theme",
|
|
6252
|
+
"deal",
|
|
6253
|
+
"topic",
|
|
6254
|
+
"claim",
|
|
6255
|
+
"evidence",
|
|
6256
|
+
"synthesis",
|
|
6257
|
+
"answer",
|
|
6258
|
+
"atomic_fact",
|
|
6259
|
+
"excerpt",
|
|
6260
|
+
"source",
|
|
6261
|
+
"company",
|
|
6262
|
+
"person",
|
|
6263
|
+
"investor",
|
|
6264
|
+
"function",
|
|
6265
|
+
"value_chain"
|
|
6266
|
+
];
|
|
6267
|
+
function isNodeType(value) {
|
|
6268
|
+
return NODE_TYPES.includes(value);
|
|
6269
|
+
}
|
|
6834
6270
|
function getLayerForNodeType(type) {
|
|
6835
6271
|
switch (type) {
|
|
6836
6272
|
case "decision":
|
|
@@ -6878,7 +6314,7 @@ function throwWorkspaceIsolationError(args) {
|
|
|
6878
6314
|
throw error;
|
|
6879
6315
|
}
|
|
6880
6316
|
function assertWorkspaceScopedEpistemicNodeScope(args) {
|
|
6881
|
-
const layer = getLayerForNodeType(args.nodeType);
|
|
6317
|
+
const layer = isNodeType(args.nodeType) ? getLayerForNodeType(args.nodeType) : void 0;
|
|
6882
6318
|
if (layer === "ontological") {
|
|
6883
6319
|
return;
|
|
6884
6320
|
}
|
|
@@ -6906,11 +6342,11 @@ function nodeMatchesWorkspaceReasoningScope(node, scope) {
|
|
|
6906
6342
|
const scopeWorkspaceId = normalizeScopeValue3(scope.workspaceId);
|
|
6907
6343
|
const nodeTenantId = normalizeScopeValue3(node.tenantId);
|
|
6908
6344
|
const nodeWorkspaceId = normalizeScopeValue3(node.workspaceId);
|
|
6909
|
-
const
|
|
6345
|
+
const epistemicLayer = typeof node.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
6910
6346
|
if (scopeTenantId && nodeTenantId && scopeTenantId !== nodeTenantId) {
|
|
6911
6347
|
return false;
|
|
6912
6348
|
}
|
|
6913
|
-
if (
|
|
6349
|
+
if (epistemicLayer === "ontological" && nodeWorkspaceId === void 0) {
|
|
6914
6350
|
return true;
|
|
6915
6351
|
}
|
|
6916
6352
|
if (!scopeWorkspaceId && node.publicationStatus === "published") {
|
|
@@ -6938,11 +6374,11 @@ function edgeMatchesWorkspaceReasoningScope(edge, scope) {
|
|
|
6938
6374
|
return scopeWorkspaceId === edgeWorkspaceId;
|
|
6939
6375
|
}
|
|
6940
6376
|
async function resolveNodeScopeForWorkspaceIsolation(ctx, node) {
|
|
6941
|
-
const
|
|
6377
|
+
const epistemicLayer = typeof node?.epistemicLayer === "string" ? node.epistemicLayer : void 0;
|
|
6942
6378
|
const resolved = {
|
|
6943
6379
|
tenantId: normalizeScopeValue3(node?.tenantId),
|
|
6944
6380
|
workspaceId: normalizeScopeValue3(node?.workspaceId),
|
|
6945
|
-
epistemicLayer
|
|
6381
|
+
epistemicLayer,
|
|
6946
6382
|
nodeType: typeof node?.nodeType === "string" ? node.nodeType : void 0
|
|
6947
6383
|
};
|
|
6948
6384
|
if (!node) {
|
|
@@ -7294,10 +6730,10 @@ function deriveSyntheticBackfillOpinion(source) {
|
|
|
7294
6730
|
a: 0.5
|
|
7295
6731
|
});
|
|
7296
6732
|
}
|
|
7297
|
-
const
|
|
6733
|
+
const confidence = clamp014(readFiniteNumber(source.confidence) ?? 0);
|
|
7298
6734
|
return {
|
|
7299
|
-
b:
|
|
7300
|
-
d: 1 -
|
|
6735
|
+
b: confidence,
|
|
6736
|
+
d: 1 - confidence,
|
|
7301
6737
|
u: 0,
|
|
7302
6738
|
a: 0.5
|
|
7303
6739
|
};
|
|
@@ -7341,10 +6777,10 @@ function formatTupleContradictionDescription(args) {
|
|
|
7341
6777
|
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)}.`;
|
|
7342
6778
|
}
|
|
7343
6779
|
function generateContentHash2(text) {
|
|
7344
|
-
const
|
|
6780
|
+
const content = `belief:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
|
|
7345
6781
|
let hash = 5381;
|
|
7346
|
-
for (let i = 0; i <
|
|
7347
|
-
hash = (hash << 5) + hash +
|
|
6782
|
+
for (let i = 0; i < content.length; i++) {
|
|
6783
|
+
hash = (hash << 5) + hash + content.charCodeAt(i);
|
|
7348
6784
|
hash &= hash;
|
|
7349
6785
|
}
|
|
7350
6786
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
@@ -7421,8 +6857,8 @@ async function resolveBeliefScopeOrNull(ctx, args) {
|
|
|
7421
6857
|
}
|
|
7422
6858
|
async function getBeliefNodesForScope(ctx, scope, args) {
|
|
7423
6859
|
const baseQuery = ctx.db.query("epistemicNodes").withIndex(
|
|
7424
|
-
|
|
7425
|
-
(q) =>
|
|
6860
|
+
"by_topic_type",
|
|
6861
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
7426
6862
|
);
|
|
7427
6863
|
const nodes = typeof args?.scanLimit === "number" ? await baseQuery.order("desc").take(args.scanLimit) : await baseQuery.collect();
|
|
7428
6864
|
const scopedNodes = nodes.filter(
|
|
@@ -7573,7 +7009,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
7573
7009
|
}
|
|
7574
7010
|
}
|
|
7575
7011
|
const previousConfidence = node.confidence || 0.5;
|
|
7576
|
-
const
|
|
7012
|
+
const predictionMeta = node.predictionMeta || existingMetadata.predictionMeta;
|
|
7577
7013
|
const previousOpinion = readBeliefOpinionSnapshot(node, existingMetadata);
|
|
7578
7014
|
const slB = args.belief;
|
|
7579
7015
|
const slD = args.disbelief;
|
|
@@ -7600,7 +7036,7 @@ async function applyBeliefConfidenceChange(ctx, args) {
|
|
|
7600
7036
|
currentBeliefStatus,
|
|
7601
7037
|
{
|
|
7602
7038
|
confidence: derivedConfidence,
|
|
7603
|
-
predictionMeta
|
|
7039
|
+
predictionMeta,
|
|
7604
7040
|
metadata: existingMetadata
|
|
7605
7041
|
}
|
|
7606
7042
|
);
|
|
@@ -8254,8 +7690,8 @@ var getByProject3 = query({
|
|
|
8254
7690
|
}
|
|
8255
7691
|
}
|
|
8256
7692
|
const query2 = ctx.db.query("epistemicNodes").withIndex(
|
|
8257
|
-
|
|
8258
|
-
(q) =>
|
|
7693
|
+
"by_topic_type",
|
|
7694
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
8259
7695
|
);
|
|
8260
7696
|
const nodes = await query2.order("desc").take(scanLimit);
|
|
8261
7697
|
const scopedNodes = nodes.filter(
|
|
@@ -8893,9 +8329,13 @@ var getCountByStatus = query({
|
|
|
8893
8329
|
},
|
|
8894
8330
|
returns: permissiveReturn,
|
|
8895
8331
|
handler: async (ctx, args) => {
|
|
8332
|
+
const scope = await resolveBeliefScopeOrNull(ctx, args);
|
|
8333
|
+
if (!scope) {
|
|
8334
|
+
return { active: 0, superseded: 0, archived: 0, total: 0 };
|
|
8335
|
+
}
|
|
8896
8336
|
const nodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
8897
|
-
|
|
8898
|
-
(q) =>
|
|
8337
|
+
"by_topic_type",
|
|
8338
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
8899
8339
|
).collect();
|
|
8900
8340
|
const counts = {
|
|
8901
8341
|
active: 0,
|
|
@@ -9460,8 +8900,8 @@ var getByPillar = query({
|
|
|
9460
8900
|
return [];
|
|
9461
8901
|
}
|
|
9462
8902
|
const nodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
9463
|
-
|
|
9464
|
-
(q) =>
|
|
8903
|
+
"by_topic_type",
|
|
8904
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
9465
8905
|
).collect();
|
|
9466
8906
|
return nodes.filter((n) => {
|
|
9467
8907
|
const metadata = n.metadata;
|
|
@@ -12117,10 +11557,10 @@ __export(epistemicAnswers_exports, {
|
|
|
12117
11557
|
getVersionHistory: () => getVersionHistory
|
|
12118
11558
|
});
|
|
12119
11559
|
function generateContentHash3(text) {
|
|
12120
|
-
const
|
|
11560
|
+
const content = `answer:${text.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 500)}`;
|
|
12121
11561
|
let hash = 5381;
|
|
12122
|
-
for (let i = 0; i <
|
|
12123
|
-
hash = (hash << 5) + hash +
|
|
11562
|
+
for (let i = 0; i < content.length; i++) {
|
|
11563
|
+
hash = (hash << 5) + hash + content.charCodeAt(i);
|
|
12124
11564
|
hash &= hash;
|
|
12125
11565
|
}
|
|
12126
11566
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
@@ -12312,9 +11752,9 @@ var create4 = mutation({
|
|
|
12312
11752
|
});
|
|
12313
11753
|
}
|
|
12314
11754
|
}
|
|
12315
|
-
const
|
|
11755
|
+
const answerQuality = args.confidence || "moderate";
|
|
12316
11756
|
await ctx.db.patch(args.questionNodeId, {
|
|
12317
|
-
answerQuality
|
|
11757
|
+
answerQuality,
|
|
12318
11758
|
updatedAt: now
|
|
12319
11759
|
});
|
|
12320
11760
|
await ctx.db.insert("epistemicAudit", {
|
|
@@ -12329,7 +11769,7 @@ var create4 = mutation({
|
|
|
12329
11769
|
answerText: args.answerText.slice(0, 200),
|
|
12330
11770
|
versionNumber,
|
|
12331
11771
|
questionNodeId: String(args.questionNodeId),
|
|
12332
|
-
confidence:
|
|
11772
|
+
confidence: answerQuality
|
|
12333
11773
|
}
|
|
12334
11774
|
});
|
|
12335
11775
|
return { nodeId, globalId, versionNumber };
|
|
@@ -12513,9 +11953,9 @@ var createInternal = internalMutation({
|
|
|
12513
11953
|
});
|
|
12514
11954
|
}
|
|
12515
11955
|
}
|
|
12516
|
-
const
|
|
11956
|
+
const answerQuality = args.confidence || "moderate";
|
|
12517
11957
|
await ctx.db.patch(args.questionNodeId, {
|
|
12518
|
-
answerQuality
|
|
11958
|
+
answerQuality,
|
|
12519
11959
|
updatedAt: now
|
|
12520
11960
|
});
|
|
12521
11961
|
await ctx.db.insert("epistemicAudit", {
|
|
@@ -12548,12 +11988,12 @@ var getByQuestion = query({
|
|
|
12548
11988
|
return [];
|
|
12549
11989
|
}
|
|
12550
11990
|
const topicId = questionNode.topicId;
|
|
12551
|
-
|
|
11991
|
+
if (!topicId) {
|
|
11992
|
+
return [];
|
|
11993
|
+
}
|
|
11994
|
+
const answers = await ctx.db.query("epistemicNodes").withIndex(
|
|
12552
11995
|
"by_topic_type",
|
|
12553
11996
|
(q) => q.eq("topicId", topicId).eq("nodeType", "answer")
|
|
12554
|
-
).collect() : await ctx.db.query("epistemicNodes").withIndex(
|
|
12555
|
-
"by_project_type",
|
|
12556
|
-
(q) => q.eq("projectId", questionNode.projectId).eq("nodeType", "answer")
|
|
12557
11997
|
).collect();
|
|
12558
11998
|
const questionIdStr = String(args.questionNodeId);
|
|
12559
11999
|
const filtered = answers.filter((a) => {
|
|
@@ -12581,18 +12021,13 @@ var getLatestForQuestion = query({
|
|
|
12581
12021
|
if (!questionNode || questionNode.nodeType !== "question") {
|
|
12582
12022
|
return null;
|
|
12583
12023
|
}
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
answers = await ctx.db.query("epistemicNodes").withIndex(
|
|
12587
|
-
"by_topic_type",
|
|
12588
|
-
(q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
|
|
12589
|
-
).filter((q) => q.eq(q.field("status"), "active")).collect();
|
|
12590
|
-
} else {
|
|
12591
|
-
answers = await ctx.db.query("epistemicNodes").withIndex(
|
|
12592
|
-
"by_project_type",
|
|
12593
|
-
(q) => q.eq("projectId", questionNode.projectId).eq("nodeType", "answer")
|
|
12594
|
-
).filter((q) => q.eq(q.field("status"), "active")).collect();
|
|
12024
|
+
if (!questionNode.topicId) {
|
|
12025
|
+
return null;
|
|
12595
12026
|
}
|
|
12027
|
+
const answers = await ctx.db.query("epistemicNodes").withIndex(
|
|
12028
|
+
"by_topic_type",
|
|
12029
|
+
(q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
|
|
12030
|
+
).filter((q) => q.eq(q.field("status"), "active")).collect();
|
|
12596
12031
|
const questionIdStr = String(args.questionNodeId);
|
|
12597
12032
|
const latest = answers.find((a) => {
|
|
12598
12033
|
const meta = a.metadata || {};
|
|
@@ -12611,28 +12046,18 @@ var getVersionHistory = query({
|
|
|
12611
12046
|
if (!questionNode || questionNode.nodeType !== "question") {
|
|
12612
12047
|
return [];
|
|
12613
12048
|
}
|
|
12614
|
-
|
|
12615
|
-
|
|
12616
|
-
answers = await ctx.db.query("epistemicNodes").withIndex(
|
|
12617
|
-
"by_topic_type",
|
|
12618
|
-
(q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
|
|
12619
|
-
).filter(
|
|
12620
|
-
(q) => q.or(
|
|
12621
|
-
q.eq(q.field("status"), "active"),
|
|
12622
|
-
q.eq(q.field("status"), "superseded")
|
|
12623
|
-
)
|
|
12624
|
-
).collect();
|
|
12625
|
-
} else {
|
|
12626
|
-
answers = await ctx.db.query("epistemicNodes").withIndex(
|
|
12627
|
-
"by_project_type",
|
|
12628
|
-
(q) => q.eq("projectId", questionNode.projectId).eq("nodeType", "answer")
|
|
12629
|
-
).filter(
|
|
12630
|
-
(q) => q.or(
|
|
12631
|
-
q.eq(q.field("status"), "active"),
|
|
12632
|
-
q.eq(q.field("status"), "superseded")
|
|
12633
|
-
)
|
|
12634
|
-
).collect();
|
|
12049
|
+
if (!questionNode.topicId) {
|
|
12050
|
+
return [];
|
|
12635
12051
|
}
|
|
12052
|
+
const answers = await ctx.db.query("epistemicNodes").withIndex(
|
|
12053
|
+
"by_topic_type",
|
|
12054
|
+
(q) => q.eq("topicId", questionNode.topicId).eq("nodeType", "answer")
|
|
12055
|
+
).filter(
|
|
12056
|
+
(q) => q.or(
|
|
12057
|
+
q.eq(q.field("status"), "active"),
|
|
12058
|
+
q.eq(q.field("status"), "superseded")
|
|
12059
|
+
)
|
|
12060
|
+
).collect();
|
|
12636
12061
|
const questionIdStr = String(args.questionNodeId);
|
|
12637
12062
|
const history = answers.filter((a) => {
|
|
12638
12063
|
const meta = a.metadata || {};
|
|
@@ -13903,10 +13328,10 @@ __export(epistemicEvidence_exports, {
|
|
|
13903
13328
|
updateVerificationStatus: () => updateVerificationStatus
|
|
13904
13329
|
});
|
|
13905
13330
|
function generateContentHash4(text) {
|
|
13906
|
-
const
|
|
13331
|
+
const content = `evidence:${text.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 500)}`;
|
|
13907
13332
|
let hash = 5381;
|
|
13908
|
-
for (let i = 0; i <
|
|
13909
|
-
hash = (hash << 5) + hash +
|
|
13333
|
+
for (let i = 0; i < content.length; i++) {
|
|
13334
|
+
hash = (hash << 5) + hash + content.charCodeAt(i);
|
|
13910
13335
|
hash &= hash;
|
|
13911
13336
|
}
|
|
13912
13337
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
@@ -13925,9 +13350,9 @@ function normalizeKind(kind) {
|
|
|
13925
13350
|
];
|
|
13926
13351
|
return validKinds.find((k) => kind.toLowerCase() === k) || "observation";
|
|
13927
13352
|
}
|
|
13928
|
-
function normalizeSourceType(
|
|
13929
|
-
if (
|
|
13930
|
-
return
|
|
13353
|
+
function normalizeSourceType(sourceType) {
|
|
13354
|
+
if (sourceType === "proprietary" || sourceType === "verified") {
|
|
13355
|
+
return sourceType;
|
|
13931
13356
|
}
|
|
13932
13357
|
return "ai_generated";
|
|
13933
13358
|
}
|
|
@@ -14015,23 +13440,14 @@ async function resolveEvidenceScopeOrNull(ctx, args) {
|
|
|
14015
13440
|
}
|
|
14016
13441
|
async function getEvidenceNodesForScope(ctx, scope, args) {
|
|
14017
13442
|
const scanLimit = typeof args?.scanLimit === "number" ? args.scanLimit : void 0;
|
|
14018
|
-
const
|
|
14019
|
-
|
|
14020
|
-
|
|
14021
|
-
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
scope.projectId ? scanLimit ? ctx.db.query("epistemicNodes").withIndex(
|
|
14027
|
-
"by_project_type",
|
|
14028
|
-
(q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
|
|
14029
|
-
).order("desc").take(scanLimit) : ctx.db.query("epistemicNodes").withIndex(
|
|
14030
|
-
"by_project_type",
|
|
14031
|
-
(q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
|
|
14032
|
-
).collect() : Promise.resolve([])
|
|
14033
|
-
]);
|
|
14034
|
-
return dedupeEvidenceNodes([...topicNodes, ...projectNodes]).filter(
|
|
13443
|
+
const topicNodes = await (scanLimit ? ctx.db.query("epistemicNodes").withIndex(
|
|
13444
|
+
"by_topic_type",
|
|
13445
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
|
|
13446
|
+
).order("desc").take(scanLimit) : ctx.db.query("epistemicNodes").withIndex(
|
|
13447
|
+
"by_topic_type",
|
|
13448
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
|
|
13449
|
+
).collect());
|
|
13450
|
+
return dedupeEvidenceNodes(topicNodes).filter(
|
|
14035
13451
|
(node) => evidenceMatchesScope(node, scope)
|
|
14036
13452
|
);
|
|
14037
13453
|
}
|
|
@@ -14112,7 +13528,7 @@ var create6 = mutation({
|
|
|
14112
13528
|
const globalId = generateGlobalId();
|
|
14113
13529
|
const contentHash = generateContentHash4(args.text);
|
|
14114
13530
|
const kind = normalizeKind(args.kind);
|
|
14115
|
-
const
|
|
13531
|
+
const sourceType = normalizeSourceType(args.sourceType);
|
|
14116
13532
|
const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
|
|
14117
13533
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
14118
13534
|
globalId,
|
|
@@ -14129,7 +13545,7 @@ var create6 = mutation({
|
|
|
14129
13545
|
status: "active",
|
|
14130
13546
|
epistemicLayer: "L2",
|
|
14131
13547
|
// L2: Compression Boundary (Evidence/Claims)
|
|
14132
|
-
sourceType
|
|
13548
|
+
sourceType,
|
|
14133
13549
|
createdAt: now,
|
|
14134
13550
|
updatedAt: now,
|
|
14135
13551
|
createdBy: args.userId,
|
|
@@ -14195,7 +13611,7 @@ var create6 = mutation({
|
|
|
14195
13611
|
newState: {
|
|
14196
13612
|
text: args.text.slice(0, 200),
|
|
14197
13613
|
kind,
|
|
14198
|
-
sourceType
|
|
13614
|
+
sourceType,
|
|
14199
13615
|
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
14200
13616
|
evidenceRelation: args.evidenceRelation
|
|
14201
13617
|
}
|
|
@@ -14254,8 +13670,8 @@ var createAndLink = mutation({
|
|
|
14254
13670
|
const globalId = generateGlobalId();
|
|
14255
13671
|
const contentHash = generateContentHash4(args.text);
|
|
14256
13672
|
const kind = normalizeKind(args.kind);
|
|
14257
|
-
const
|
|
14258
|
-
const
|
|
13673
|
+
const sourceType = normalizeSourceType(args.sourceType);
|
|
13674
|
+
const confidence = args.confidence ?? 0.7;
|
|
14259
13675
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
14260
13676
|
globalId,
|
|
14261
13677
|
topicId: scope.topicId,
|
|
@@ -14267,7 +13683,7 @@ var createAndLink = mutation({
|
|
|
14267
13683
|
contentHash,
|
|
14268
13684
|
status: "active",
|
|
14269
13685
|
epistemicLayer: "L2",
|
|
14270
|
-
sourceType
|
|
13686
|
+
sourceType,
|
|
14271
13687
|
createdAt: now,
|
|
14272
13688
|
updatedAt: now,
|
|
14273
13689
|
createdBy: args.userId,
|
|
@@ -14276,7 +13692,7 @@ var createAndLink = mutation({
|
|
|
14276
13692
|
tags: args.tags || [],
|
|
14277
13693
|
linkedBeliefNodeId: args.beliefNodeId,
|
|
14278
13694
|
evidenceRelation: args.relation,
|
|
14279
|
-
confidence
|
|
13695
|
+
confidence
|
|
14280
13696
|
}
|
|
14281
13697
|
});
|
|
14282
13698
|
await ctx.scheduler.runAfter(0, internal.neo4jSync.syncNodeToNeo4j, {
|
|
@@ -14287,7 +13703,7 @@ var createAndLink = mutation({
|
|
|
14287
13703
|
if (!beliefNode) {
|
|
14288
13704
|
throw new Error("Belief node not found for edge creation");
|
|
14289
13705
|
}
|
|
14290
|
-
const weight = args.relation === "supports" ?
|
|
13706
|
+
const weight = args.relation === "supports" ? confidence : -confidence;
|
|
14291
13707
|
const edgeGlobalId = crypto.randomUUID();
|
|
14292
13708
|
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
14293
13709
|
globalId: edgeGlobalId,
|
|
@@ -14303,7 +13719,7 @@ var createAndLink = mutation({
|
|
|
14303
13719
|
toLayer: "L3",
|
|
14304
13720
|
metadata: {
|
|
14305
13721
|
relation: args.relation,
|
|
14306
|
-
confidence
|
|
13722
|
+
confidence
|
|
14307
13723
|
}
|
|
14308
13724
|
});
|
|
14309
13725
|
await markProjectGraphDirty2(ctx, scope.projectId, String(scope.topicId));
|
|
@@ -14404,20 +13820,13 @@ var getByProject5 = query({
|
|
|
14404
13820
|
return [];
|
|
14405
13821
|
}
|
|
14406
13822
|
}
|
|
14407
|
-
const
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
(q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
|
|
14415
|
-
).order("desc").take(scanLimit) : Promise.resolve([])
|
|
14416
|
-
]);
|
|
14417
|
-
const scopedNodes = dedupeEvidenceNodes([
|
|
14418
|
-
...topicNodes,
|
|
14419
|
-
...projectNodes
|
|
14420
|
-
]).filter((node) => evidenceMatchesScope(node, scope));
|
|
13823
|
+
const topicNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
13824
|
+
"by_topic_type",
|
|
13825
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
|
|
13826
|
+
).order("desc").take(scanLimit);
|
|
13827
|
+
const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
|
|
13828
|
+
(node) => evidenceMatchesScope(node, scope)
|
|
13829
|
+
);
|
|
14421
13830
|
const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
|
|
14422
13831
|
return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
|
|
14423
13832
|
}
|
|
@@ -14434,20 +13843,13 @@ var getByTopic3 = query({
|
|
|
14434
13843
|
const pageSize = clampEvidenceLimit(args.limit);
|
|
14435
13844
|
const scanLimit = Math.min(pageSize * 3, MAX_EVIDENCE_PAGE_SIZE);
|
|
14436
13845
|
const scope = await resolveTopicProjectScope(ctx, { topicId: args.topicId });
|
|
14437
|
-
const
|
|
14438
|
-
|
|
14439
|
-
|
|
14440
|
-
|
|
14441
|
-
|
|
14442
|
-
|
|
14443
|
-
|
|
14444
|
-
(q) => q.eq("projectId", scope.projectId).eq("nodeType", "evidence")
|
|
14445
|
-
).order("desc").take(scanLimit) : Promise.resolve([])
|
|
14446
|
-
]);
|
|
14447
|
-
const scopedNodes = dedupeEvidenceNodes([
|
|
14448
|
-
...topicNodes,
|
|
14449
|
-
...projectNodes
|
|
14450
|
-
]).filter((node) => evidenceMatchesScope(node, scope));
|
|
13846
|
+
const topicNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
13847
|
+
"by_topic_type",
|
|
13848
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "evidence")
|
|
13849
|
+
).order("desc").take(scanLimit);
|
|
13850
|
+
const scopedNodes = dedupeEvidenceNodes(topicNodes).filter(
|
|
13851
|
+
(node) => evidenceMatchesScope(node, scope)
|
|
13852
|
+
);
|
|
14451
13853
|
const filteredNodes = args.status ? scopedNodes.filter((node) => node.status === args.status) : scopedNodes;
|
|
14452
13854
|
return filteredNodes.map(flattenEvidenceNode).slice(0, pageSize);
|
|
14453
13855
|
}
|
|
@@ -14649,7 +14051,7 @@ var internalCreate2 = internalMutation({
|
|
|
14649
14051
|
const globalId = generateGlobalId();
|
|
14650
14052
|
const contentHash = generateContentHash4(args.text);
|
|
14651
14053
|
const kind = normalizeKind(args.kind);
|
|
14652
|
-
const
|
|
14054
|
+
const sourceType = normalizeSourceType(args.sourceType);
|
|
14653
14055
|
const additionalMetadata = args.metadata && typeof args.metadata === "object" ? args.metadata : {};
|
|
14654
14056
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
14655
14057
|
globalId,
|
|
@@ -14665,7 +14067,7 @@ var internalCreate2 = internalMutation({
|
|
|
14665
14067
|
...typeof args.contentType === "string" && args.contentType.trim().length > 0 ? { contentType: args.contentType.trim() } : {},
|
|
14666
14068
|
status: "active",
|
|
14667
14069
|
epistemicLayer: "L2",
|
|
14668
|
-
sourceType
|
|
14070
|
+
sourceType,
|
|
14669
14071
|
createdAt: now,
|
|
14670
14072
|
updatedAt: now,
|
|
14671
14073
|
createdBy: args.userId,
|
|
@@ -14692,7 +14094,7 @@ var internalCreate2 = internalMutation({
|
|
|
14692
14094
|
newState: {
|
|
14693
14095
|
text: args.text.slice(0, 200),
|
|
14694
14096
|
kind,
|
|
14695
|
-
sourceType
|
|
14097
|
+
sourceType,
|
|
14696
14098
|
externalSourceType: args.externalSourceType,
|
|
14697
14099
|
sourceUrl: args.sourceUrl,
|
|
14698
14100
|
linkedBeliefNodeId: args.linkedBeliefNodeId,
|
|
@@ -14708,8 +14110,8 @@ var internalCreate2 = internalMutation({
|
|
|
14708
14110
|
if (args.linkedBeliefNodeId && args.evidenceRelation) {
|
|
14709
14111
|
const beliefNode = await ctx.db.get(args.linkedBeliefNodeId);
|
|
14710
14112
|
if (beliefNode) {
|
|
14711
|
-
const
|
|
14712
|
-
const weight = args.evidenceRelation === "supports" ?
|
|
14113
|
+
const confidence = args.confidence ?? 0.7;
|
|
14114
|
+
const weight = args.evidenceRelation === "supports" ? confidence : -confidence;
|
|
14713
14115
|
await ctx.scheduler.runAfter(5e3, internal.neo4jEdgeAPI.createEdge, {
|
|
14714
14116
|
globalId: crypto.randomUUID(),
|
|
14715
14117
|
fromGlobalId: globalId,
|
|
@@ -14724,7 +14126,7 @@ var internalCreate2 = internalMutation({
|
|
|
14724
14126
|
toLayer: "L3",
|
|
14725
14127
|
metadata: {
|
|
14726
14128
|
relation: args.evidenceRelation,
|
|
14727
|
-
confidence
|
|
14129
|
+
confidence
|
|
14728
14130
|
}
|
|
14729
14131
|
});
|
|
14730
14132
|
}
|
|
@@ -15071,23 +14473,23 @@ __export(epistemicHelpers_exports, {
|
|
|
15071
14473
|
shouldContinueTraversal: () => shouldContinueTraversal2,
|
|
15072
14474
|
validateEdgeLayers: () => validateEdgeLayers2
|
|
15073
14475
|
});
|
|
15074
|
-
function generateContentHash5(
|
|
15075
|
-
const
|
|
14476
|
+
function generateContentHash5(nodeType, text) {
|
|
14477
|
+
const content = `${nodeType}:${normalizeText(text)}`;
|
|
15076
14478
|
let hash = 5381;
|
|
15077
|
-
for (let i = 0; i <
|
|
15078
|
-
hash = (hash << 5) + hash +
|
|
14479
|
+
for (let i = 0; i < content.length; i++) {
|
|
14480
|
+
hash = (hash << 5) + hash + content.charCodeAt(i);
|
|
15079
14481
|
hash &= hash;
|
|
15080
14482
|
}
|
|
15081
14483
|
const hashHex = Math.abs(hash).toString(16).padStart(8, "0");
|
|
15082
|
-
const lengthHex =
|
|
15083
|
-
const checksum =
|
|
14484
|
+
const lengthHex = content.length.toString(16).padStart(4, "0");
|
|
14485
|
+
const checksum = content.split("").reduce((a, c) => a + c.charCodeAt(0), 0).toString(16).padStart(8, "0");
|
|
15084
14486
|
return `${hashHex}${lengthHex}${checksum}`;
|
|
15085
14487
|
}
|
|
15086
14488
|
function normalizeText(text) {
|
|
15087
14489
|
return text.trim().toLowerCase().replace(/\s+/g, " ");
|
|
15088
14490
|
}
|
|
15089
|
-
function getNodeLayer2(
|
|
15090
|
-
switch (
|
|
14491
|
+
function getNodeLayer2(nodeType) {
|
|
14492
|
+
switch (nodeType) {
|
|
15091
14493
|
// L4: Audit targets
|
|
15092
14494
|
case "decision":
|
|
15093
14495
|
return "L4";
|
|
@@ -15120,7 +14522,7 @@ function getNodeLayer2(nodeType2) {
|
|
|
15120
14522
|
return "organizational";
|
|
15121
14523
|
default:
|
|
15122
14524
|
console.warn(
|
|
15123
|
-
`[EpistemicLayer] Unknown nodeType: ${
|
|
14525
|
+
`[EpistemicLayer] Unknown nodeType: ${nodeType}, defaulting to L2`
|
|
15124
14526
|
);
|
|
15125
14527
|
return "L2";
|
|
15126
14528
|
}
|
|
@@ -15562,8 +14964,8 @@ function validateEdgeLayers2(edgeType, fromLayer, toLayer) {
|
|
|
15562
14964
|
}
|
|
15563
14965
|
return { valid: true };
|
|
15564
14966
|
}
|
|
15565
|
-
function mapInsightSourceType(
|
|
15566
|
-
switch (
|
|
14967
|
+
function mapInsightSourceType(sourceType) {
|
|
14968
|
+
switch (sourceType) {
|
|
15567
14969
|
case "verified":
|
|
15568
14970
|
case "proprietary":
|
|
15569
14971
|
return "human";
|
|
@@ -15718,7 +15120,7 @@ async function createEpistemicNodeForQuestion(ctx, _questionId, question) {
|
|
|
15718
15120
|
});
|
|
15719
15121
|
return existing._id;
|
|
15720
15122
|
}
|
|
15721
|
-
const
|
|
15123
|
+
const sourceType = question.source === "manual" ? "human" : question.source === "ai_suggested" ? "ai_generated" : "ai_extracted";
|
|
15722
15124
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
15723
15125
|
globalId,
|
|
15724
15126
|
nodeType: "question",
|
|
@@ -15734,7 +15136,7 @@ async function createEpistemicNodeForQuestion(ctx, _questionId, question) {
|
|
|
15734
15136
|
// Include sourceAnchor for linking questions back to source documents
|
|
15735
15137
|
sourceAnchor: question.sourceAnchor
|
|
15736
15138
|
},
|
|
15737
|
-
sourceType
|
|
15139
|
+
sourceType,
|
|
15738
15140
|
verificationStatus: "unverified",
|
|
15739
15141
|
status: "active",
|
|
15740
15142
|
topicId: question.projectId,
|
|
@@ -15747,15 +15149,15 @@ async function createEpistemicNodeForQuestion(ctx, _questionId, question) {
|
|
|
15747
15149
|
async function createEpistemicNodeForArtifact(ctx, artifactId, artifact) {
|
|
15748
15150
|
const now = Date.now();
|
|
15749
15151
|
const globalId = generateGlobalId();
|
|
15750
|
-
let
|
|
15152
|
+
let nodeType = "source";
|
|
15751
15153
|
const isSynthesis = artifact.isDeepResearch || artifact.type.includes("deep") || artifact.type.includes("research") || artifact.type.includes("primer");
|
|
15752
15154
|
if (isSynthesis) {
|
|
15753
|
-
|
|
15155
|
+
nodeType = "synthesis";
|
|
15754
15156
|
console.log(
|
|
15755
15157
|
`[EpistemicHelpers] Skipping synthesis node creation for "${artifact.type}" - will create when evidence is extracted`
|
|
15756
15158
|
);
|
|
15757
15159
|
const contentHash2 = generateContentHash5(
|
|
15758
|
-
|
|
15160
|
+
nodeType,
|
|
15759
15161
|
artifact.title + artifact.content.slice(0, 500)
|
|
15760
15162
|
);
|
|
15761
15163
|
const existing2 = await ctx.db.query("epistemicNodes").withIndex("by_contentHash", (q) => q.eq("contentHash", contentHash2)).first();
|
|
@@ -15765,7 +15167,7 @@ async function createEpistemicNodeForArtifact(ctx, artifactId, artifact) {
|
|
|
15765
15167
|
throw new Error("SKIP_SYNTHESIS_NODE_CREATION");
|
|
15766
15168
|
}
|
|
15767
15169
|
const contentHash = generateContentHash5(
|
|
15768
|
-
|
|
15170
|
+
nodeType,
|
|
15769
15171
|
artifact.title + artifact.content.slice(0, 500)
|
|
15770
15172
|
);
|
|
15771
15173
|
const existing = await ctx.db.query("epistemicNodes").withIndex("by_contentHash", (q) => q.eq("contentHash", contentHash)).first();
|
|
@@ -15779,11 +15181,11 @@ async function createEpistemicNodeForArtifact(ctx, artifactId, artifact) {
|
|
|
15779
15181
|
});
|
|
15780
15182
|
return existing._id;
|
|
15781
15183
|
}
|
|
15782
|
-
const
|
|
15184
|
+
const epistemicLayer = "L1";
|
|
15783
15185
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
15784
15186
|
globalId,
|
|
15785
|
-
nodeType
|
|
15786
|
-
epistemicLayer
|
|
15187
|
+
nodeType,
|
|
15188
|
+
epistemicLayer,
|
|
15787
15189
|
// Synthesis is L2, Source is L1
|
|
15788
15190
|
canonicalText: artifact.title,
|
|
15789
15191
|
contentHash,
|
|
@@ -15812,12 +15214,13 @@ async function findOrCreateSourceNode(ctx, artifactId, createdBy, scopeProjectId
|
|
|
15812
15214
|
let existingNodes;
|
|
15813
15215
|
if (effectiveTopicId) {
|
|
15814
15216
|
existingNodes = await ctx.db.query("epistemicNodes").withIndex("by_topic", (q) => q.eq("topicId", effectiveTopicId)).collect();
|
|
15815
|
-
} else if (effectiveProjectId) {
|
|
15816
|
-
existingNodes = await ctx.db.query("epistemicNodes").withIndex("by_project", (q) => q.eq("projectId", effectiveProjectId)).collect();
|
|
15817
15217
|
} else {
|
|
15818
15218
|
existingNodes = await ctx.db.query("epistemicNodes").withIndex("by_nodeType", (q) => q.eq("nodeType", "source")).collect();
|
|
15819
15219
|
}
|
|
15820
15220
|
const existing = existingNodes.find((n) => {
|
|
15221
|
+
if (effectiveProjectId && n.projectId && n.projectId !== effectiveProjectId) {
|
|
15222
|
+
return false;
|
|
15223
|
+
}
|
|
15821
15224
|
const metadata = n.metadata;
|
|
15822
15225
|
return metadata?.legacyArtifactId === artifactId;
|
|
15823
15226
|
});
|
|
@@ -15831,22 +15234,22 @@ async function findOrCreateSourceNode(ctx, artifactId, createdBy, scopeProjectId
|
|
|
15831
15234
|
const globalId = generateGlobalId();
|
|
15832
15235
|
const artifactType = artifact.metadata?.type || "";
|
|
15833
15236
|
const isDeepResearch = artifact.metadata?.isDeepResearch;
|
|
15834
|
-
let
|
|
15237
|
+
let nodeType = "source";
|
|
15835
15238
|
if (isDeepResearch || artifactType.includes("deep") || artifactType.includes("research")) {
|
|
15836
|
-
|
|
15239
|
+
nodeType = "synthesis";
|
|
15837
15240
|
} else if (artifactType.includes("primer")) {
|
|
15838
|
-
|
|
15241
|
+
nodeType = "synthesis";
|
|
15839
15242
|
}
|
|
15840
15243
|
const title = artifact.metadata?.title || artifact.metadata?.theme || "Untitled";
|
|
15841
15244
|
const contentHash = generateContentHash5(
|
|
15842
|
-
|
|
15245
|
+
nodeType,
|
|
15843
15246
|
title + (artifact.content?.slice(0, 500) || "")
|
|
15844
15247
|
);
|
|
15845
|
-
const
|
|
15248
|
+
const epistemicLayer = nodeType === "synthesis" ? "L2" : "L1";
|
|
15846
15249
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
15847
15250
|
globalId,
|
|
15848
|
-
nodeType
|
|
15849
|
-
epistemicLayer
|
|
15251
|
+
nodeType,
|
|
15252
|
+
epistemicLayer,
|
|
15850
15253
|
// Synthesis is L2, Source is L1
|
|
15851
15254
|
canonicalText: title,
|
|
15852
15255
|
contentHash,
|
|
@@ -15869,12 +15272,12 @@ async function findOrCreateSourceNode(ctx, artifactId, createdBy, scopeProjectId
|
|
|
15869
15272
|
});
|
|
15870
15273
|
return nodeId;
|
|
15871
15274
|
}
|
|
15872
|
-
function normalizeConfidence(
|
|
15873
|
-
if (typeof
|
|
15874
|
-
return
|
|
15275
|
+
function normalizeConfidence(confidence) {
|
|
15276
|
+
if (typeof confidence === "number") {
|
|
15277
|
+
return confidence > 1 ? confidence / 100 : confidence;
|
|
15875
15278
|
}
|
|
15876
|
-
if (typeof
|
|
15877
|
-
switch (
|
|
15279
|
+
if (typeof confidence === "string") {
|
|
15280
|
+
switch (confidence) {
|
|
15878
15281
|
case "high":
|
|
15879
15282
|
return 0.8;
|
|
15880
15283
|
case "medium":
|
|
@@ -15948,8 +15351,8 @@ async function createEdgeForInsightQuestionLink(ctx, questionId, insightId, crea
|
|
|
15948
15351
|
});
|
|
15949
15352
|
}
|
|
15950
15353
|
async function findNodeByLegacyId(ctx, legacyType, legacyId) {
|
|
15951
|
-
const
|
|
15952
|
-
const nodes = await ctx.db.query("epistemicNodes").withIndex("by_nodeType", (q) => q.eq("nodeType",
|
|
15354
|
+
const nodeType = legacyType === "insight" ? "evidence" : legacyType === "artifact" ? "source" : legacyType;
|
|
15355
|
+
const nodes = await ctx.db.query("epistemicNodes").withIndex("by_nodeType", (q) => q.eq("nodeType", nodeType)).collect();
|
|
15953
15356
|
const legacyKey = `legacy${legacyType.charAt(0).toUpperCase() + legacyType.slice(1)}Id`;
|
|
15954
15357
|
const legacyIdStr = String(legacyId);
|
|
15955
15358
|
const found = nodes.find((n) => {
|
|
@@ -15959,7 +15362,7 @@ async function findNodeByLegacyId(ctx, legacyType, legacyId) {
|
|
|
15959
15362
|
});
|
|
15960
15363
|
if (!found) {
|
|
15961
15364
|
console.log(
|
|
15962
|
-
`[EpistemicSpine] Node not found for ${legacyType}:${legacyIdStr}, searched ${nodes.length} ${
|
|
15365
|
+
`[EpistemicSpine] Node not found for ${legacyType}:${legacyIdStr}, searched ${nodes.length} ${nodeType} nodes`
|
|
15963
15366
|
);
|
|
15964
15367
|
}
|
|
15965
15368
|
return found?._id ?? null;
|
|
@@ -16665,8 +16068,8 @@ var getByProjectAndTypeLite = query({
|
|
|
16665
16068
|
const pageSize = clampNodeLimit(args.limit);
|
|
16666
16069
|
const scanLimit = Math.min(pageSize * 3, MAX_NODE_PAGE_SIZE);
|
|
16667
16070
|
const query2 = ctx.db.query("epistemicNodes").withIndex(
|
|
16668
|
-
|
|
16669
|
-
(q) =>
|
|
16071
|
+
"by_topic_type",
|
|
16072
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", args.nodeType)
|
|
16670
16073
|
);
|
|
16671
16074
|
const nodes = await query2.order("desc").take(scanLimit);
|
|
16672
16075
|
const statusFiltered = args.status ? nodes.filter((n) => n.status === args.status) : nodes.filter((n) => n.status === "active");
|
|
@@ -16872,7 +16275,7 @@ var create7 = mutation({
|
|
|
16872
16275
|
if (existing && existing.status === "active") {
|
|
16873
16276
|
return { nodeId: existing._id, isDuplicate: true };
|
|
16874
16277
|
}
|
|
16875
|
-
const
|
|
16278
|
+
const epistemicLayer = getNodeLayer(args.nodeType);
|
|
16876
16279
|
const resolvedScope = args.topicId || args.projectId ? await resolveTopicProjectScope(ctx, {
|
|
16877
16280
|
topicId: args.topicId,
|
|
16878
16281
|
projectId: args.projectId
|
|
@@ -16889,11 +16292,11 @@ var create7 = mutation({
|
|
|
16889
16292
|
tenantId: resolvedScope.tenantId,
|
|
16890
16293
|
workspaceId: resolvedScope.workspaceId,
|
|
16891
16294
|
nodeType: args.nodeType,
|
|
16892
|
-
epistemicLayer
|
|
16295
|
+
epistemicLayer
|
|
16893
16296
|
},
|
|
16894
16297
|
mutationName: "epistemicNodes.create"
|
|
16895
16298
|
});
|
|
16896
|
-
} else if (
|
|
16299
|
+
} else if (epistemicLayer !== "ontological") {
|
|
16897
16300
|
throw new Error(
|
|
16898
16301
|
"Workspace-scoped reasoning isolation requires topicId or projectId for non-ontological node creation."
|
|
16899
16302
|
);
|
|
@@ -16901,7 +16304,7 @@ var create7 = mutation({
|
|
|
16901
16304
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
16902
16305
|
globalId: args.globalId,
|
|
16903
16306
|
nodeType: args.nodeType,
|
|
16904
|
-
epistemicLayer
|
|
16307
|
+
epistemicLayer,
|
|
16905
16308
|
// Phase 2B: Auto-derived from nodeType
|
|
16906
16309
|
subtype: args.subtype,
|
|
16907
16310
|
canonicalText: args.canonicalText,
|
|
@@ -17062,11 +16465,11 @@ var supersede = mutation({
|
|
|
17062
16465
|
mutationName: "epistemicNodes.supersede"
|
|
17063
16466
|
});
|
|
17064
16467
|
const now = Date.now();
|
|
17065
|
-
const
|
|
16468
|
+
const epistemicLayer = oldNode.epistemicLayer || getNodeLayer(oldNode.nodeType);
|
|
17066
16469
|
const newNodeId = await ctx.db.insert("epistemicNodes", {
|
|
17067
16470
|
globalId: args.newGlobalId,
|
|
17068
16471
|
nodeType: oldNode.nodeType,
|
|
17069
|
-
epistemicLayer
|
|
16472
|
+
epistemicLayer,
|
|
17070
16473
|
// Phase 2B: Inherit layer (supersession is same-layer only)
|
|
17071
16474
|
canonicalText: args.newCanonicalText,
|
|
17072
16475
|
contentHash: args.newContentHash,
|
|
@@ -17299,14 +16702,14 @@ var batchCreate2 = mutation({
|
|
|
17299
16702
|
nodeType: node.nodeType,
|
|
17300
16703
|
mutationName: "epistemicNodes.batchCreate"
|
|
17301
16704
|
});
|
|
17302
|
-
const
|
|
16705
|
+
const epistemicLayer = getNodeLayer(node.nodeType);
|
|
17303
16706
|
const resolvedScope = node.topicId || node.projectId ? await resolveTopicProjectScope(ctx, {
|
|
17304
16707
|
topicId: node.topicId,
|
|
17305
16708
|
projectId: node.projectId
|
|
17306
16709
|
}).catch(() => void 0) : void 0;
|
|
17307
16710
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
17308
16711
|
...node,
|
|
17309
|
-
epistemicLayer
|
|
16712
|
+
epistemicLayer,
|
|
17310
16713
|
// Phase 2B: Auto-derived from nodeType
|
|
17311
16714
|
verificationStatus: node.verificationStatus ?? "unverified",
|
|
17312
16715
|
status: "active",
|
|
@@ -17390,11 +16793,11 @@ var createInternal2 = internalMutation({
|
|
|
17390
16793
|
projectId: args.projectId
|
|
17391
16794
|
}).catch(() => void 0) : void 0;
|
|
17392
16795
|
const contentHash = args.contentHash || `${args.nodeType}:${args.canonicalText}`.slice(0, 64);
|
|
17393
|
-
const
|
|
16796
|
+
const epistemicLayer = args.epistemicLayer || getNodeLayer(args.nodeType);
|
|
17394
16797
|
const nodeId = await ctx.db.insert("epistemicNodes", {
|
|
17395
16798
|
globalId: args.globalId,
|
|
17396
16799
|
nodeType: args.nodeType,
|
|
17397
|
-
epistemicLayer
|
|
16800
|
+
epistemicLayer,
|
|
17398
16801
|
subtype: args.subtype,
|
|
17399
16802
|
canonicalText: args.canonicalText,
|
|
17400
16803
|
contentHash,
|
|
@@ -17666,10 +17069,10 @@ async function resolveWorkflowBridgeDoc(ctx, workflowId) {
|
|
|
17666
17069
|
|
|
17667
17070
|
// src/epistemicQuestions.ts
|
|
17668
17071
|
function generateContentHash6(text) {
|
|
17669
|
-
const
|
|
17072
|
+
const content = `question:${text.trim().toLowerCase().replace(/\s+/g, " ")}`;
|
|
17670
17073
|
let hash = 5381;
|
|
17671
|
-
for (let i = 0; i <
|
|
17672
|
-
hash = (hash << 5) + hash +
|
|
17074
|
+
for (let i = 0; i < content.length; i++) {
|
|
17075
|
+
hash = (hash << 5) + hash + content.charCodeAt(i);
|
|
17673
17076
|
hash &= hash;
|
|
17674
17077
|
}
|
|
17675
17078
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
@@ -17773,21 +17176,13 @@ async function resolveQuestionScopeOrNull(ctx, args) {
|
|
|
17773
17176
|
}
|
|
17774
17177
|
async function getQuestionNodesForScope(ctx, scope, args) {
|
|
17775
17178
|
const fetchNodes = (query2) => typeof args?.scanLimit === "number" ? query2.order("desc").take(args.scanLimit) : query2.collect();
|
|
17776
|
-
const
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
scope.projectId ? fetchNodes(
|
|
17784
|
-
ctx.db.query("epistemicNodes").withIndex(
|
|
17785
|
-
"by_project_type",
|
|
17786
|
-
(q) => q.eq("projectId", scope.projectId).eq("nodeType", "question")
|
|
17787
|
-
)
|
|
17788
|
-
) : Promise.resolve([])
|
|
17789
|
-
]);
|
|
17790
|
-
return dedupeQuestionNodes([...topicNodes, ...projectNodes]).filter(
|
|
17179
|
+
const topicNodes = await fetchNodes(
|
|
17180
|
+
ctx.db.query("epistemicNodes").withIndex(
|
|
17181
|
+
"by_topic_type",
|
|
17182
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
|
|
17183
|
+
)
|
|
17184
|
+
);
|
|
17185
|
+
return dedupeQuestionNodes(topicNodes).filter(
|
|
17791
17186
|
(node) => questionMatchesScope(node, scope)
|
|
17792
17187
|
);
|
|
17793
17188
|
}
|
|
@@ -19953,8 +19348,8 @@ var getByPillar2 = query({
|
|
|
19953
19348
|
return { questions: [], beliefs: [] };
|
|
19954
19349
|
}
|
|
19955
19350
|
const allBeliefNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
19956
|
-
|
|
19957
|
-
(q) =>
|
|
19351
|
+
"by_topic_type",
|
|
19352
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "belief")
|
|
19958
19353
|
).collect();
|
|
19959
19354
|
const beliefs = allBeliefNodes.filter((n) => {
|
|
19960
19355
|
const meta = n.metadata || {};
|
|
@@ -20320,8 +19715,8 @@ var getQuestionClusterPositions = query({
|
|
|
20320
19715
|
};
|
|
20321
19716
|
}
|
|
20322
19717
|
const questionNodes = await ctx.db.query("epistemicNodes").withIndex(
|
|
20323
|
-
|
|
20324
|
-
(q) =>
|
|
19718
|
+
"by_topic_type",
|
|
19719
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
|
|
20325
19720
|
).collect();
|
|
20326
19721
|
const activeQuestionNodes = questionNodes.filter(isActiveQuestionNode);
|
|
20327
19722
|
const positions = {};
|
|
@@ -20331,8 +19726,8 @@ var getQuestionClusterPositions = query({
|
|
|
20331
19726
|
for (const question of activeQuestionNodes) {
|
|
20332
19727
|
const id = question._id.toString();
|
|
20333
19728
|
const meta = question.metadata || {};
|
|
20334
|
-
const
|
|
20335
|
-
if (
|
|
19729
|
+
const questionType = typeof question.questionType === "string" ? question.questionType : typeof meta.questionType === "string" ? meta.questionType : void 0;
|
|
19730
|
+
if (questionType === "belief_test" || meta.testType) {
|
|
20336
19731
|
positions[id] = "cluster";
|
|
20337
19732
|
clusterCount++;
|
|
20338
19733
|
} else if (resolveLinkedWorktreeId(meta)) {
|
|
@@ -20392,10 +19787,10 @@ function normalizeMetadata(metadata) {
|
|
|
20392
19787
|
return rest;
|
|
20393
19788
|
}
|
|
20394
19789
|
function generateSourceContentHash(identity) {
|
|
20395
|
-
const
|
|
19790
|
+
const content = `source:${identity.trim().toLowerCase()}`;
|
|
20396
19791
|
let hash = 5381;
|
|
20397
|
-
for (let index = 0; index <
|
|
20398
|
-
hash = (hash << 5) + hash +
|
|
19792
|
+
for (let index = 0; index < content.length; index += 1) {
|
|
19793
|
+
hash = (hash << 5) + hash + content.charCodeAt(index);
|
|
20399
19794
|
hash &= hash;
|
|
20400
19795
|
}
|
|
20401
19796
|
return Math.abs(hash).toString(16).padStart(8, "0");
|
|
@@ -22205,11 +21600,15 @@ var getByProject8 = query({
|
|
|
22205
21600
|
if (!hasAccess) {
|
|
22206
21601
|
return [];
|
|
22207
21602
|
}
|
|
21603
|
+
const scope = await resolveTopicProjectScope(ctx, args).catch(() => null);
|
|
21604
|
+
if (!scope) {
|
|
21605
|
+
return [];
|
|
21606
|
+
}
|
|
22208
21607
|
const pageSize = Math.max(1, Math.min(Math.floor(args.limit ?? 300), 1e3));
|
|
22209
21608
|
const questionScanLimit = Math.min(pageSize * 2, 1e3);
|
|
22210
21609
|
const questions = await ctx.db.query("epistemicNodes").withIndex(
|
|
22211
|
-
|
|
22212
|
-
(q) =>
|
|
21610
|
+
"by_topic_type",
|
|
21611
|
+
(q) => q.eq("topicId", scope.topicId).eq("nodeType", "question")
|
|
22213
21612
|
).order("desc").take(questionScanLimit);
|
|
22214
21613
|
const questionIds = questions.slice(0, pageSize).map((q) => q._id);
|
|
22215
21614
|
const allLinks = await Promise.all(
|