Skip to main content

EntityLinkage

EntityLinkage is a small Python library and command-line tool for linking external records to a canonical set of entities. It makes conservative, explainable decisions from configured identity rules and preserves ambiguity and missing data for review.

EntityLinkage was extracted from conservative identity-matching patterns developed for a real-world multi-source data pipeline.

Decisions stay conservative

  • resolved — exactly one candidate remains after all configured constraints.
  • ambiguous — multiple candidates remain; EntityLinkage does not pick one by score or order.
  • unresolved — no candidate remains. Reason codes distinguish missing identity information from usable values that matched nothing and from constraints that rejected candidates.
  • not_applicable — the record is explicitly outside the configured entity scope.

Every result includes candidate IDs, stable reason codes, and evidence for candidate rules, constraints, and any reviewed override. A declared alias is evidence supplied by the configuration; the tool does not invent aliases or use fuzzy matching, external services, or machine learning.

Install and try the examples

EntityLinkage requires Python 3.11 or newer. From a source checkout, install the locked development environment with uv:

uv sync --locked

You can also install the package from a checkout with python -m pip install .. PyYAML is the only runtime dependency.

Validate and link the synthetic basic example:

uv run --locked entitylinkage validate examples/basic
uv run --locked entitylinkage link examples/basic --output ./entitylinkage-output
uv run --locked entitylinkage inspect source-record-001 examples/basic

link writes linkage.json, linkage.csv, and summary.json. It returns success when the reports are written, even when records are ambiguous or unresolved. Use audit as a quality gate; it returns exit code 1 when either status occurs:

uv run --locked entitylinkage audit examples/basic

The examples under examples/ use fictional publication and catalog names. They demonstrate alias matching, a year constraint, ambiguity, an unmatched record, an out-of-scope record, and a reviewed manual decision.

Configuration

Each input is a YAML file or a directory containing entitylinkage.yaml. The top-level document has version: 1, entities, records, and matching, with an optional overrides list. See examples/basic/entitylinkage.yaml for a complete example.

An entity has a unique id, a canonical name, optional explicit string aliases, and optional flat scalar attributes. A record has a unique id, an optional name, flat attributes, and an optional applicable flag. Attribute keys are user-defined flat field names. Values may be strings, integers, finite floats, booleans, or null; nested mappings and lists are rejected. Quote date-like strings in YAML so they are not parsed as dates. Empty strings are present values for constraints, while omitted and null attribute values are missing.

matching.normalization requires case_fold and punctuation (preserve, remove, or space). Names are normalized with Unicode NFKC, configured punctuation handling, optional case folding, and whitespace collapse. The same settings apply to canonical names, aliases, and record names; normalized record names appear in inspection output.

At least one candidate rule is required:

  • normalized_name compares a record name with entity names and declared aliases.
  • exact_value compares configured name or attributes.<key> fields using type-sensitive equality. Empty identity values do not create candidates.

Candidate rules are OR-combined: every entity supported by any rule remains a candidate. Constraints are AND-combined and filter each candidate. The equal constraint compares fields exactly and requires missing: ignore or missing: reject. Ignoring a missing value keeps the candidate without treating missing data as match evidence; rejecting it removes the candidate.

Reviewed overrides

Overrides are intended for explicit reviewed decisions. Set matching.apply_overrides: true to enable them. A resolved override requires a known entity_id; a not_applicable override omits it. Both require a stable reason code such as reviewed_identity_match. Unknown IDs, duplicate override record IDs, invalid reason codes, disabled overrides, and overrides that contradict an input marked not applicable are rejected. When enabled, a valid override takes precedence over automatic matching and its reason appears in the result evidence.

Python API

from pathlib import Path

from entitylinkage import Linker
from entitylinkage.config import load_config

inputs = load_config(Path("examples/basic"))
results = Linker(inputs.config).link(inputs.entities, inputs.records)
for result in results:
    print(result.record_id, result.status, result.entity_id, result.reason_codes)

The core API accepts Entity, Record, and LinkageConfig values directly; configuration loading, file output, and command-line behavior remain separate from matching. load_config rejects duplicate YAML keys, unknown schema keys, malformed scalar values, invalid references, and duplicate normalized labels within one entity. Name or alias collisions across different entities are valid and result in ambiguity when both remain candidates.

Reports and inspection

The CLI provides four noninteractive commands:

entitylinkage validate PATH
entitylinkage link PATH [--output DIR]
entitylinkage audit PATH
entitylinkage inspect RECORD_ID PATH

JSON uses stable key ordering and compact encoding. CSV has the fixed columns record_id,status,entity_id,candidate_entity_ids,reason_codes,evidence; structured cells contain canonical JSON and rows end with LF. Reports include the EntityLinkage version and Unicode database version, contain no timestamps or filesystem paths, and are byte-identical for equivalent inputs under the same runtime versions. inspect shows the input record, normalized record name, rule evidence, candidate IDs, reasons, and final decision.

Scope and limitations

EntityLinkage performs deterministic exact matching; it does not infer dates, apply domain-specific substitutions, score similarity, or guarantee that declared data is true. Review the evidence and source provenance before using a manual override. Unicode normalization behavior can vary with the runtime's Unicode database version, which is recorded in report metadata.

EntityLinkage can produce mapping evidence for tools such as EvidenceMatrix, which analyzes entity-by-source evidence coverage. It does not require or replace EvidenceMatrix. It also does not provide LineageGuard's artifact provenance and chain-of-custody functions.

The public TWDisaster files currently include event-source relationships and observations already connected to events. Those mappings are not independent labels for validating a source-to-event resolver, so this project does not claim a TWDisaster dogfood result or copy TWDisaster data. See the read-only review.

Development

uv run --locked pytest
uv run --locked ruff check .
uv run --locked ruff format --check .

Metadata

Release files for entitylinkage 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for entitylinkage 0.1.0
File Size Uploaded
entitylinkage-0.1.0.tar.gz 50.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for entitylinkage 0.1.0
File Interpreter ABI Platform
entitylinkage-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 71.0 kB

Release files / entitylinkage-0.1.0.tar.gz

Download URL entitylinkage-0.1.0.tar.gz
Size 50.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b84b68c8b1f7002c978cb2a256aeb398f2ab31adb62aa324f68d85900d15362d
BLAKE2b-256 checksum
How to use checksums
2d3244da5ff08d65f66ae76f67e9d8b1065dcd024c8464a6a7a415a789942ab9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / entitylinkage-0.1.0-py3-none-any.whl

Download URL entitylinkage-0.1.0-py3-none-any.whl
Size 21.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
880f5a00c4a61478a1b0b759da841f686103458a9779a71b0f19781dd103ba0d
BLAKE2b-256 checksum
How to use checksums
199100c3e560e953df065feb3eaa208be8c4036414f0549ea623662e379da072
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page