Abstract
The Entity Management System is the central data model of the Prismatic Platform's due diligence capability. It provides typed, versioned, auditable representations of all subjects under investigation -- persons, companies, domains, email addresses, phone numbers, IP addresses, cryptocurrency wallets, and documents. Every entity instance maintains a complete provenance trail recording how it was discovered, which OSINT sources contributed data, the confidence level of each data point, and the temporal history of changes. This document describes the entity type system, the resolution algorithms that merge records across disparate sources into unified entity profiles, and the storage architecture that supports both full-text search and graph traversal across entity relationships.
Introduction
The Entity as Investigative Primitive
Due diligence investigations are fundamentally about entities and their relationships. An M&A analyst investigating a target company needs to understand not just the company itself, but its directors, shareholders, subsidiaries, contractors, domain registrations, email footprints, and financial connections. Each of these constitutes an entity that must be individually tracked, verified, and connected into the investigation's relationship graph.
The Prismatic Platform treats entities as first-class objects with defined types, schemas, and lifecycle management. Unlike generic document-oriented approaches where entity data is scattered across unstructured notes and reports, the platform's Entity Management System enforces structured representations that enable programmatic analysis, cross-source validation through the triple-check methodology, and graph traversal through the graph analysis engine.
Design Principles
The Entity Management System follows four design principles derived from the platform's NO MERCY, NO DOUBTS doctrine:
- Type Safety: Every entity has a defined type with a specific schema. There are no generic "entity" objects that could contain arbitrary unstructured data.
- Immutable History: Entity attributes are versioned, not overwritten. When a company's registered address changes, the previous address is preserved with full temporal metadata.
- Source Attribution: Every attribute value carries provenance metadata identifying which source provided it, when it was collected, and what confidence level was assigned.
- Resolution Transparency: When multiple source records are merged into a single entity, the resolution logic and merge decisions are recorded and auditable.
Entity Type System
Primary Entity Types
The platform supports eight primary entity types, each with a defined schema and specific identifier semantics:
| Entity Type | Primary Identifiers | Secondary Identifiers | Key Attributes |
|---|---|---|---|
| Person | Full name + date of birth | National ID, passport number | Roles, addresses, PEP status, sanctions matches |
| Company | ICO (Czech), DUNS, LEI | Trade name, DIC, registration number | Legal form, statutory bodies, registered capital, NACE codes |
| Domain | Domain name | Registrar, registrant ID | WHOIS data, DNS records, SSL certificates, hosting |
| Email address | Associated domain, mailserver | Breach status, reputation score, deliverability | |
| Phone | Phone number + country code | Carrier, line type | Carrier lookup, location, VoIP status |
| IP Address | IPv4 or IPv6 address | ASN, CIDR block | Geolocation, reputation, open ports, abuse reports |
| Cryptocurrency | Wallet address + chain | Exchange association | Transaction volume, risk score, cluster analysis |
| Document | Reference number + registry | Court case ID, filing number | Document type, parties, dates, status |
Entity Schema Definition
Each entity type is defined through an Elixir schema module that specifies required fields, optional fields, validation rules, and serialization formats. The schema system leverages Ecto changesets for validation and typespecs for compile-time type safety.
defmodule PrismaticDD.Entity.Company do
@type t :: %__MODULE__{
id: Ecto.UUID.t(),
ico: String.t(),
dic: String.t() | nil,
legal_name: String.t(),
trade_names: [String.t()],
legal_form: atom(),
registered_capital: Money.t() | nil,
statutory_bodies: [StatutoryBody.t()],
shareholders: [Shareholder.t()],
addresses: [Address.t()],
nace_codes: [String.t()],
formation_date: Date.t(),
dissolution_date: Date.t() | nil,
status: :active | :dissolved | :in_liquidation | :insolvent,
source_records: [SourceRecord.t()],
confidence: ConfidenceScore.t(),
metadata: map()
}
endEntity Lifecycle
Entities progress through a defined lifecycle within the investigation:
Discovery --> Enrichment --> Validation --> Verified --> Monitoring
| | | | |
Created Sources queried Triple-check Accepted Continuous
from seed data merged applied for report watch
-
Discovery: An entity is created either manually by an analyst or automatically through graph expansion from a related entity. At this stage, the entity may have minimal attributes (e.g., just a company name or ICO number).
-
Enrichment: The platform's orchestration engine triggers parallel queries across all relevant OSINT sources, collecting data from registries, databases, and intelligence feeds. Source records are normalized and attached to the entity.
-
Validation: The triple-check cross-validation methodology is applied to each attribute, computing confidence scores based on multi-source corroboration and temporal consistency.
-
Verified: Attributes that pass validation are marked as verified with their confidence scores. The entity is now eligible for inclusion in due diligence reports and risk assessments.
-
Monitoring: For ongoing investigations or post-deal monitoring, verified entities enter a monitoring state where the platform periodically re-queries sources and alerts analysts to material changes.
Entity Resolution
The Resolution Challenge
Entity resolution -- the process of determining whether two records from different sources refer to the same real-world entity -- is one of the most technically challenging aspects of due diligence automation. A Czech company might appear as:
- "Prismatic s.r.o." in ARES
- "PRISMATIC, spolecnost s rucenim omezenym" in Justice.cz
- "Prismatic SRO" in an international credit database
- "Prismatic Ltd" in English-language business directories
All four records refer to the same entity, but establishing this programmatically requires understanding Czech legal form abbreviations, case normalization, diacritical mark handling, and the relationship between Czech and international company naming conventions.
Resolution Algorithm
The platform's entity resolution engine uses a multi-stage approach:
Stage 1: Deterministic Matching: If two records share a strong identifier (ICO, DIC, LEI, DUNS), they are immediately linked. Strong identifiers are unique by design and provide certain matches.
Stage 2: Probabilistic Matching: For records without shared strong identifiers, the engine applies probabilistic matching across multiple attribute comparisons:
| Attribute | Matching Method | Weight |
|---|---|---|
| Legal name | Levenshtein distance + Czech normalization | 0.30 |
| Address | Address component parsing + geocode proximity | 0.20 |
| Formation date | Exact match + tolerance window | 0.15 |
| Legal form | Legal form equivalence mapping | 0.10 |
| Director names | Name matching with diacritical normalization | 0.15 |
| NACE codes | Set intersection similarity | 0.10 |
Records with a composite match score above 0.85 are automatically merged. Records scoring between 0.65 and 0.85 are flagged for analyst review. Records below 0.65 are treated as distinct entities.
Stage 3: Graph-Based Resolution: After initial matching, the graph analysis engine examines relationship patterns to identify potential matches that attribute-level comparison missed. If two company records share three or more directors, the same registered address, and similar NACE codes, the graph engine flags them as probable matches even if their names differ significantly (e.g., after a corporate renaming event).
Czech-Specific Normalization
Entity resolution in the Czech context requires specialized normalization rules:
- Legal form mapping: "s.r.o." = "spolecnost s rucenim omezenym" = "spol. s r.o." = "SRO"
- Diacritical handling: "Ceska" = "Ceska" for matching purposes, with the canonical form preserving diacritics
- Address normalization: Czech address formats vary significantly across registries; the platform parses addresses into structured components (street, house number, municipality, postal code, district) before comparison
- ICO validation: The platform validates ICO check digits to reject malformed identifiers before they enter the resolution pipeline
- Name prefixes/suffixes: Common prefixes ("Ing.", "Mgr.", "JUDr.") and suffixes ("CSc.", "PhD.") are stripped during person name matching
Storage Architecture
The Entity Management System uses a polyglot persistence architecture that leverages the strengths of multiple storage engines:
PostgreSQL: Primary Entity Store
PostgreSQL serves as the system of record for all entity data. Each entity type maps to a dedicated table with appropriate indexing, constraints, and audit triggers. The platform uses Ecto for schema management and query construction, with migrations tracking every schema evolution.
Key PostgreSQL features leveraged:
- JSONB columns: For flexible metadata and source-specific attributes that vary between records
- Temporal tables: For maintaining entity attribute history without overwriting previous values
- Full-text search: For basic entity search queries using PostgreSQL's built-in tsvector indexing
- Row-level security: For enforcing case-level access control on entity data
Meilisearch: Full-Text Search
Meilisearch provides the primary search interface for entity discovery, supporting typo-tolerant, real-time search across entity names, addresses, and descriptions. The search index is updated asynchronously from PostgreSQL change events, ensuring near-real-time search availability without impacting write performance.
KuzuDB: Graph Relationships
KuzuDB stores and traverses entity relationships -- ownership chains, director networks, address clusters, and inter-entity connections. The graph representation enables the relationship queries described in the graph analysis documentation, including multi-hop traversals that would be prohibitively expensive in relational SQL.
ETS: Real-Time Cache
ETS (Erlang Term Storage) provides in-memory caching for frequently accessed entity data, reducing database load during active investigation sessions where analysts repeatedly access the same entity profiles.
Audit Trail and Provenance
Every modification to an entity record generates an immutable audit trail entry recording:
| Field | Description |
|---|---|
| Entity ID | UUID of the affected entity |
| Attribute | Which attribute was modified |
| Previous value | The value before modification (nil for creation) |
| New value | The value after modification |
| Source | Which OSINT source or analyst provided the new value |
| Confidence | The confidence score assigned to the new value |
| Timestamp | UTC timestamp of the modification |
| Actor | The system process or user who triggered the change |
| Investigation ID | The case/investigation context |
The audit trail satisfies the Provenance Mandatory axiom from the NABLA framework, ensuring that every data point in the system can be traced to its origin. This is essential for regulatory compliance, where auditors may require evidence of how specific findings were derived.
Entity Discovery Patterns
Seed Expansion
Most investigations begin with a small set of seed entities -- typically the target company and its known principals. The platform's discovery engine expands from these seeds through systematic source querying:
- Direct enrichment: Query all relevant sources for the seed entity's identifiers
- Relational discovery: Extract related entities from source responses (e.g., directors, shareholders, subsidiaries from registry data)
- Graph expansion: For each newly discovered entity, repeat the enrichment process up to a configurable depth limit
- Deduplication: Apply entity resolution to merge records that refer to the same real-world entity
This expansion process typically discovers 10-50x more entities than the initial seed set, revealing the full network of relationships surrounding the investigation target.
Analyst-Directed Discovery
Beyond automated expansion, analysts can manually create entities and trigger targeted enrichment for specific investigation leads. The platform provides a LiveView interface for entity creation, with real-time feedback as OSINT sources return results and the validation pipeline processes new data.
Performance Characteristics
The Entity Management System is designed for the scale requirements of enterprise due diligence:
| Operation | Typical Latency | Throughput |
|---|---|---|
| Entity creation | <50ms | 100+ per second |
| Single-source enrichment | 200ms - 2s | Depends on source API |
| Full entity enrichment (all sources) | 5-30s | Parallel across sources |
| Entity resolution (pair) | <10ms | 10,000+ pairs per second |
| Graph expansion (1 hop) | <100ms | Depends on relationship density |
| Full-text search | <50ms | Supports 1,000+ concurrent queries |
Conclusion
The Entity Management System provides the structured, auditable, and type-safe data foundation that enables every other component of the Prismatic DD Intelligence platform -- from cross-validation through graph analysis to risk assessment. By treating entities as first-class objects with defined schemas, immutable history, and source attribution, the platform ensures that due diligence findings rest on a solid evidentiary base that satisfies both analytical and regulatory requirements.
References
- Triple-Check Methodology
- Graph Analysis Engine
- Czech Registry Integration
- OSINT Integration Framework
- Entity Resolution
- PostgreSQL Storage
- KuzuDB Graph Engine
- Meilisearch Search Engine
- Audit Trail
Connect & Contribute
Created by Tomáš Korcak (korczis) | Open Source under GHL