Skip to main content

@happyvertical/smrt-facts — Specification

Reconcile Algorithm​

The reconcile() method is the primary entry point for ingesting new knowledge. It determines whether incoming text represents a new fact, corroborates an existing one, or contradicts it.

Input​

interface ReconcileOptions {
rawInput: string; // Text to reconcile
similarityThreshold?: number; // Auto-merge threshold (default: 0.85)
conflictThreshold?: number; // Minimum similarity to consider (default: 0.60)
decisionMergeProbabilityThreshold?: number; // Typed-decision merge threshold (default: 0.75)
type?: FactType; // Classification (default: 'assertion')
domain?: string; // Domain scope
source?: { // Optional provenance
sourceType?: string;
sourceUrl?: string;
sourceTitle?: string;
credibility?: number;
};
}

Decision Flow​

semanticSearch(rawInput, limit=5, minSimilarity=conflictThreshold)
│
├─ No match above conflictThreshold (0.60)
│ └─ CREATE new fact (status: active)
│
├─ Top match >= similarityThreshold (0.85)
│ └─ MERGE: increment sourceCount, update textRaw
│
└─ Ambiguous zone (0.60 - 0.85)
└─ Typed choice decision when configured; otherwise legacy AI text disambiguation
├─ Typed "merge" at selected merge probability >= 0.75 and above branch → MERGE
├─ Typed "branch", low selected merge probability, malformed response, or provider error → BRANCH
└─ Legacy text containing "branch" → BRANCH; other successful text → MERGE

The typed-decision merge probability threshold is a conservative operating threshold, not a calibrated assurance score. It is independent from the cosine-similarity thresholds that select the reconciliation zone. Registered reconciliation prompts and tenant or instance overrides supply the typed decision instructions. Values outside [0, 1] are rejected before a configured provider is called.

After the action, if source metadata was provided, a FactSource record is created. On merge with a source, recalculateConfidence() is called to update the fact's confidence score.

Output​

interface ReconcileResult {
action: 'created' | 'merged' | 'branched';
fact: Fact; // The resulting fact
source?: FactSource; // Created source record
similarity?: number; // Best match similarity
matchedFact?: Fact; // Existing fact that was matched
}

Confidence Formula​

Version 1 uses a simple weighted sum clamped to [0, 1]:

confidence = base + sourceBoost + credibilityBoost + recencyBoost + corroborationBoost

Where:
base = 0.5
sourceBoost = min(sourceCount / 10, 0.3)
credibilityBoost = avgSourceCredibility * 0.2
recencyBoost = max(0, 0.1 - daysSinceLastSource * 0.01)
corroborationBoost = corroborationScore * 0.1

Result: max(0, min(1, confidence))

Defaults (when no sources exist): avgSourceCredibility = 0.5, daysSinceLastSource = 0, corroborationScore = 0 — yielding a baseline confidence of 0.7.

The recalculateConfidence() method loads all FactSource records, computes averages, and saves the updated confidence and sourceCount to the fact.

Evolution Semantics​

Facts form directed acyclic graphs via parentId. Each child has an evolutionType:

TypeMeaningParent status change
originalRoot fact, no parent—
correctionFixes an error in parentParent → superseded
refinementImproves wording/precisionNo change
contradictionDirectly contradicts parentParent → superseded
extensionAdds new information to parentNo change
mergeCombines multiple factsNo change

Evolution Methods​

  • getEvolutionChain(factId): Walk up via parentId to root. Returns [root, ..., factId]. Uses visited-ID Set for cycle safety.
  • getLatestInChain(factId): Walk down children, always picking highest confidence. Returns the leaf. Uses visited-ID Set for cycle safety.
  • getEvolutionTree(factId): Find root via getEvolutionChain, then BFS all descendants. Returns flat array of entire tree.
  • branch(parentId, data, evolutionType): Create child fact, generate embeddings, and if evolution type is correction or contradiction, mark parent as superseded.

Entity Briefing​

getEntityBriefing(entityType, entityId) aggregates all facts linked to an entity via FactSubject:

interface EntityBriefing {
entityType: string;
entityId: string;
facts: Fact[];
totalCount: number;
byType: Record<string, number>; // e.g., { assertion: 5, observation: 2 }
byStatus: Record<string, number>; // e.g., { active: 6, superseded: 1 }
}

Type Reference​

FactType​

assertion | observation | measurement | definition | relationship | event | opinion | prediction

FactStatus​

pending | active | disputed | superseded | archived | retracted

EvolutionType​

original | correction | refinement | contradiction | extension | merge

SubjectRole​

subject | object | source | location | participant | related

FactContentRelationship​

extracted_from | referenced_in | supports | contradicts | related

Future Work​

  • DispatchBus events: Emit fact.discovered events from reconcile() for reactive pipelines
  • interesting() integration: Use confidence + source count + recency to determine if a fact is noteworthy
  • Cross-gnode federation: Share facts between gnodes with provenance chains
  • Batch reconcile: Process multiple inputs in a single call with shared semantic search