Before you clean join keys, see which relationships the cleanup would create.
An experimental, read-only CLI and Python API for comparing CSV join-key policies. It reports exact match counts, newly introduced row pairs, raw-key collisions and source-record witnesses. It does not repair data, execute a joined export or decide whether two strings identify the same business entity.
Experimental preview. Python 3.11+, standard-library runtime. SQL, qsv and joinspy are strong alternatives; agent benefit is unmeasured.
Clone the source or install a wheel from Releases when available. The project is not distributed through PyPI at this stage.
git clone https://github.com/codex-improvement-lab/joindelta.git
cd joindelta
python -m pip install .
joindelta demo --out demo-case
joindelta compare orders.csv customers.csv --on account_id --plan trim --plan trim+nfkc+casefold --out join-case --jsonOpen report.html to compare policies. Output directories must be new. The report
includes keys from the input data; review it before sharing. No upload or telemetry.
Raw equality is always included. Repeat --on for composite keys, or use separate
--left-key and --right-key. For headerless files use --no-header and one-based
column numbers. --left-delimiter tab and --right-delimiter tab support TSV.
Empty strings are missing by default; --null-token adds literal missing tokens.
Null tokens are recognized before normalization and never match. A nonempty
key normalized to an empty string remains a key and is reported explicitly.
--empty-is-key changes the raw-empty policy. Numeric-looking keys stay textual,
so 001 is distinct from 1. Policies apply to both sides, in the listed order.
Samples are bounded; counts cover both complete accepted inputs without creating the Cartesian joined table. Logical record IDs exclude headers and blank lines; physical line ranges handle multiline fields. Key previews may be truncated, with an explicit marker and key digest. Digests identify input bytes, not authenticity.
Exit 0 means the comparison completed. With --expect, exit 1 means at least one
policy violates the declared relationship among matched records. Exit 2 is an
input/setup error. None of these establish business identity or semantic safety.
JSON stdout uses ASCII escaping to preserve Unicode through legacy console pipes;
decoding that JSON recovers the original text.
from joindelta.core import compare_files
report = compare_files('orders.csv', 'customers.csv',
left_keys=['account_id'], plans=['trim', 'trim+nfkc+casefold'])The default limits are 16 MB and 250,000 records per input. Exceeding a limit is an error, not a partial success. Python's CSV parser also limits field size. These are input limits, not a strict process-memory guarantee.
Validation and alternatives include the real public-data workflow and its independent SQL baseline. The demonstrated counts are not agent time/token savings. The HTML report is local and opens without a server.
python -m unittest discover -s tests -v
python -m pip wheel . --no-deps --wheel-dir dist
python scripts/package_smoke.py dist/joindelta-0.1.0a1-py3-none-any.whlRun source tests with the package installed or src on PYTHONPATH. Visual review
uses the development-only scripts/render_demo.mjs with an installed Playwright
module and generated report; Node/Playwright are not runtime dependencies.
MIT · Elias S.W. and Codex Improvement Lab.
