jsonl-diff 0.1.0__tar.gz → 0.1.2__tar.gz

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.
@@ -0,0 +1,310 @@
1
+ Metadata-Version: 2.4
2
+ Name: jsonl-diff
3
+ Version: 0.1.2
4
+ Summary: A lightweight, pure-Python tool for comparing large JSONL/NDJSON datasets without loading them entirely into memory.
5
+ Author-email: rmoralespp <rmoralespp@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2026 Rolando Morales Perez
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Source, https://github.com/rmoralespp/jsonl-diff
29
+ Project-URL: Homepage, https://github.com/rmoralespp/jsonl-diff
30
+ Project-URL: Changelog, https://github.com/rmoralespp/jsonl-diff/blob/main/CHANGELOG.md
31
+ Project-URL: Issues, https://github.com/rmoralespp/jsonl-diff/issues
32
+ Project-URL: Documentation, https://rmoralespp.github.io/jsonl-diff/
33
+ Keywords: jsonlines,ndjson,jsonl,json,gzip,bzip2,xz,zst,utilities,serialization,deserialization,diff,json-diff,cli
34
+ Classifier: Programming Language :: Python
35
+ Classifier: Programming Language :: Python :: 3 :: Only
36
+ Classifier: Programming Language :: Python :: 3.8
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Programming Language :: Python :: 3.14
43
+ Classifier: Intended Audience :: Developers
44
+ Classifier: Intended Audience :: Information Technology
45
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
46
+ Classifier: Topic :: Internet
47
+ Classifier: Topic :: Utilities
48
+ Classifier: Topic :: File Formats :: JSON
49
+ Requires-Python: >=3.8
50
+ Description-Content-Type: text/markdown
51
+ License-File: LICENSE
52
+ Requires-Dist: py-jsonl==1.5.2
53
+ Requires-Dist: jmespath>=1.0.0
54
+ Dynamic: license-file
55
+
56
+ # jsonl-diff
57
+
58
+ <p>
59
+ <img src="https://img.shields.io/pypi/v/jsonl-diff.svg" alt="PyPI">
60
+ <img src="https://img.shields.io/pypi/pyversions/jsonl-diff.svg" alt="Python">
61
+ <img src="https://github.com/rmoralespp/jsonl-diff/workflows/CI/badge.svg" alt="CI">
62
+ <img src="https://codecov.io/gh/rmoralespp/jsonl-diff/branch/main/graph/badge.svg" alt="Coverage">
63
+ <img src="https://img.shields.io/github/license/rmoralespp/jsonl-diff.svg" alt="License">
64
+ </p>
65
+
66
+ Compare large JSONL/NDJSON datasets **by record identity instead of line
67
+ position**, without loading the complete inputs into memory.
68
+
69
+ `jsonl-diff` matches records using one or more top-level fields and reports:
70
+ `equal`, `added`, `deleted`, `modified`, and tolerated duplicates in each
71
+ source.
72
+
73
+ It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
74
+
75
+ > For line-level, field-level, JSON Patch, or visual diffs, use a tool designed for those purposes instead.
76
+
77
+ ## Installation
78
+
79
+ ```bash
80
+ pip install jsonl-diff
81
+ ```
82
+
83
+ ## Quick start
84
+
85
+ Given:
86
+
87
+ ```jsonl
88
+ {"id":1,"name":"Ada"}
89
+ {"id":2,"name":"Grace"}
90
+ ```
91
+
92
+ and:
93
+
94
+ ```jsonl
95
+ {"id":2,"name":"Grace Hopper"}
96
+ {"name":"Ada","id":1}
97
+ {"id":3,"name":"Linus"}
98
+ ```
99
+
100
+ compare them by `id`:
101
+
102
+ ```bash
103
+ jsonl-diff old.jsonl new.jsonl --key id
104
+ ```
105
+
106
+ ```text
107
+ Records:
108
+ equal: 1
109
+ added: 1
110
+ deleted: 0
111
+ modified: 1
112
+ OLD duplicates: 0
113
+ NEW duplicates: 0
114
+ ```
115
+
116
+ Record order does not matter.
117
+
118
+ ## Features
119
+
120
+ * Single or composite top-level identities.
121
+ * Disk-backed comparison for large datasets ([architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md)).
122
+ * Optional **JMESPath** filtering with `--where`.
123
+ * Configurable duplicate handling with counts and diagnostics: `error`, `first`, or `last`.
124
+ * Exact **RFC 6901** JSON Pointer ignores.
125
+ * Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
126
+ * Semantic number comparison using `Decimal`.
127
+ * Deterministic summaries and change iteration.
128
+ * Original OLD/NEW physical line numbers.
129
+ * Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
130
+ * Local, HTTP/HTTPS, file-like, and supported compressed sources.
131
+ * CLI and Python API using the same comparison engine.
132
+
133
+ ## CLI
134
+
135
+ ```text
136
+ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
137
+ [--duplicates {error,first,last}] [--details FILE] [--quiet]
138
+ [--schema-diff] [--schema-ignore POINTER] [--max-temp MAX_TEMP]
139
+ old new
140
+ ```
141
+
142
+ | Option | Description |
143
+ | --------------------- | ------------------------------------------------------------------------------ |
144
+ | `old`, `new` | Local path, HTTP/HTTPS source, or `-` for stdin |
145
+ | `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
146
+ | `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
147
+ | `--where EXPRESSION` | JMESPath filter applied to each record |
148
+ | `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
149
+ | `--details FILE` | Write deterministic machine-readable JSONL changes |
150
+ | `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
151
+ | `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
152
+ | `--quiet` | Suppress the normal summary |
153
+ | `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
154
+
155
+ Examples:
156
+
157
+ ```bash
158
+ # Composite identity
159
+ jsonl-diff old.jsonl new.jsonl --key country,customerId,type
160
+
161
+ # Ignore volatile fields
162
+ jsonl-diff old.jsonl new.jsonl \
163
+ --key id \
164
+ --ignore /updated_at \
165
+ --ignore /metadata/request_id
166
+
167
+ # Filter records
168
+ jsonl-diff old.jsonl new.jsonl \
169
+ --key id \
170
+ --where 'deleted_at == `null`'
171
+
172
+ # Detect observed schema drift
173
+ jsonl-diff old.jsonl new.jsonl \
174
+ --key id \
175
+ --schema-diff \
176
+ --schema-ignore /metadata
177
+
178
+ # Compressed input
179
+ jsonl-diff old.jsonl.xz new.jsonl.gz --key id
180
+ ```
181
+
182
+ ### Exit codes
183
+
184
+ | Code | Meaning |
185
+ | ---: | ---------------------------------------------------------- |
186
+ | `0` | No record, duplicate, or requested observed-schema issues |
187
+ | `1` | Record differences, tolerated duplicates, or schema changes |
188
+ | `2` | Input, resource, output, or runtime error |
189
+ | `3` | Invalid CLI configuration or usage |
190
+
191
+ ## Python API
192
+
193
+ ```python
194
+ from jsonl_diff import ChangeOperation, diff
195
+
196
+ with diff(
197
+ "old.jsonl.gz",
198
+ "new.jsonl.gz",
199
+ key=("country", "customerId"),
200
+ ignore=("/updated_at",),
201
+ where='country == `"ES"`',
202
+ schema_diff=True,
203
+ ) as result:
204
+ print(result.summary)
205
+
206
+ for change in result.changes(ChangeOperation.MODIFIED):
207
+ print(change.key, change.old_line, change.new_line)
208
+
209
+ for change in result.schema_changes():
210
+ print(change.operation, change.path)
211
+ ```
212
+
213
+ `diff()` returns a disk-backed `DiffResult`, used as a context manager.
214
+ Results are streamed lazily through `changes()` rather than materialized in
215
+ memory.
216
+
217
+ The main result models are:
218
+
219
+ ```python
220
+ Summary(equal=10, added=2, deleted=1, modified=3)
221
+ ```
222
+
223
+ and immutable `Change` objects containing the operation, typed identity, and
224
+ OLD/NEW source locations.
225
+
226
+ The public exception hierarchy is rooted at `JsonlDiffError`:
227
+
228
+ * `ConfigurationError`
229
+ * `InputError`
230
+ * `DuplicateKeyError`
231
+ * `ResourceError`
232
+
233
+ See the [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) for the full callable
234
+ signature, result models, `Decimal` key semantics, and error hierarchy.
235
+
236
+ ## Comparison semantics
237
+
238
+ `jsonl-diff` is intentionally strict:
239
+
240
+ * Every input line must contain exactly one valid top-level JSON object.
241
+ * Blank lines, malformed JSON, duplicate properties, `NaN`, and infinities are rejected.
242
+ * Identity fields must be top-level scalar values (`null` allowed only as one component of a composite key).
243
+ * Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
244
+ * Duplicate identities fail by default; `--duplicates first`/`last` select one
245
+ occurrence, report every discarded occurrence, and return exit code `1`.
246
+ * Object property order is ignored; array order is significant.
247
+ * Numbers are compared by mathematical value: `1`, `1.0`, and `1e0` are equal.
248
+ * Unicode strings are compared without normalization.
249
+ * Changes are reported in deterministic identity order.
250
+
251
+ `--where` selects which records participate; `--key` defines identity;
252
+ `--ignore` removes fields from content comparison. With `--schema-diff`,
253
+ `--schema-ignore` independently removes fields from observed-schema profiling.
254
+ See
255
+ [Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) for the full rules,
256
+ including duplicate handling, ignore-pointer edge cases, `--where` evaluation
257
+ order, and canonical number formatting.
258
+
259
+ ## Sources & compression
260
+
261
+ Supported sources include local paths and HTTP/HTTPS URLs. The Python API
262
+ also accepts file-like objects.
263
+
264
+ Supported compression:
265
+
266
+ * gzip
267
+ * bzip2
268
+ * xz
269
+ * Zstandard on Python 3.14
270
+
271
+ See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
272
+ support matrix and how sources are delegated to `py-jsonl`.
273
+
274
+ ## Limitations
275
+
276
+ `jsonl-diff` does **not** provide:
277
+
278
+ * line/position-based diffs
279
+ * field-level diffs or JSON Patch
280
+ * move/rename detection
281
+ * nested identities or automatic key detection
282
+ * fuzzy matching or numeric tolerances
283
+ * unordered-array comparison
284
+ * validation against a declared schema or input repair
285
+ * ZIP, database, or cloud-provider inputs
286
+ * GUI or HTML reports
287
+
288
+ It is a **dataset reconciliation tool**, not a general-purpose visual JSON diff.
289
+
290
+ ## Further reading
291
+
292
+ * [Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
293
+ * [Disk-backed architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
294
+ * [Details JSONL format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md) — machine-readable `--details` output schema.
295
+ * [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) — full signature, result models, and error hierarchy.
296
+
297
+ ## Development
298
+
299
+ ```bash
300
+ uv sync --group test --group lint
301
+
302
+ uv run pytest
303
+ uv run ruff check --quiet --output-format=concise .
304
+ ```
305
+
306
+ The test suite covers CLI behavior, identity/canonicalization, validation, details output, sources, compression, temporary limits, and cleanup.
307
+
308
+ ## License
309
+
310
+ See [LICENSE](LICENSE).
@@ -0,0 +1,255 @@
1
+ # jsonl-diff
2
+
3
+ <p>
4
+ <img src="https://img.shields.io/pypi/v/jsonl-diff.svg" alt="PyPI">
5
+ <img src="https://img.shields.io/pypi/pyversions/jsonl-diff.svg" alt="Python">
6
+ <img src="https://github.com/rmoralespp/jsonl-diff/workflows/CI/badge.svg" alt="CI">
7
+ <img src="https://codecov.io/gh/rmoralespp/jsonl-diff/branch/main/graph/badge.svg" alt="Coverage">
8
+ <img src="https://img.shields.io/github/license/rmoralespp/jsonl-diff.svg" alt="License">
9
+ </p>
10
+
11
+ Compare large JSONL/NDJSON datasets **by record identity instead of line
12
+ position**, without loading the complete inputs into memory.
13
+
14
+ `jsonl-diff` matches records using one or more top-level fields and reports:
15
+ `equal`, `added`, `deleted`, `modified`, and tolerated duplicates in each
16
+ source.
17
+
18
+ It is useful for snapshots, ETL validation, migrations, exports, and CI checks.
19
+
20
+ > For line-level, field-level, JSON Patch, or visual diffs, use a tool designed for those purposes instead.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install jsonl-diff
26
+ ```
27
+
28
+ ## Quick start
29
+
30
+ Given:
31
+
32
+ ```jsonl
33
+ {"id":1,"name":"Ada"}
34
+ {"id":2,"name":"Grace"}
35
+ ```
36
+
37
+ and:
38
+
39
+ ```jsonl
40
+ {"id":2,"name":"Grace Hopper"}
41
+ {"name":"Ada","id":1}
42
+ {"id":3,"name":"Linus"}
43
+ ```
44
+
45
+ compare them by `id`:
46
+
47
+ ```bash
48
+ jsonl-diff old.jsonl new.jsonl --key id
49
+ ```
50
+
51
+ ```text
52
+ Records:
53
+ equal: 1
54
+ added: 1
55
+ deleted: 0
56
+ modified: 1
57
+ OLD duplicates: 0
58
+ NEW duplicates: 0
59
+ ```
60
+
61
+ Record order does not matter.
62
+
63
+ ## Features
64
+
65
+ * Single or composite top-level identities.
66
+ * Disk-backed comparison for large datasets ([architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md)).
67
+ * Optional **JMESPath** filtering with `--where`.
68
+ * Configurable duplicate handling with counts and diagnostics: `error`, `first`, or `last`.
69
+ * Exact **RFC 6901** JSON Pointer ignores.
70
+ * Optional disk-backed observed-schema diff for fields, types, nullability, and requiredness.
71
+ * Semantic number comparison using `Decimal`.
72
+ * Deterministic summaries and change iteration.
73
+ * Original OLD/NEW physical line numbers.
74
+ * Machine-readable JSONL change log with `--details` ([format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md)).
75
+ * Local, HTTP/HTTPS, file-like, and supported compressed sources.
76
+ * CLI and Python API using the same comparison engine.
77
+
78
+ ## CLI
79
+
80
+ ```text
81
+ jsonl-diff [-h] --key KEY [--ignore IGNORE] [--where EXPRESSION]
82
+ [--duplicates {error,first,last}] [--details FILE] [--quiet]
83
+ [--schema-diff] [--schema-ignore POINTER] [--max-temp MAX_TEMP]
84
+ old new
85
+ ```
86
+
87
+ | Option | Description |
88
+ | --------------------- | ------------------------------------------------------------------------------ |
89
+ | `old`, `new` | Local path, HTTP/HTTPS source, or `-` for stdin |
90
+ | `--key KEY` | Required top-level identity field; repeat or comma-separate for composite keys |
91
+ | `--ignore POINTER` | RFC 6901 pointer to exclude from content comparison |
92
+ | `--where EXPRESSION` | JMESPath filter applied to each record |
93
+ | `--duplicates POLICY` | `error` (default), or select and report duplicates with `first`/`last` |
94
+ | `--details FILE` | Write deterministic machine-readable JSONL changes |
95
+ | `--schema-diff` | Compare observed fields, types, nullability, and requiredness |
96
+ | `--schema-ignore` | RFC 6901 pointer to exclude from observed-schema profiling |
97
+ | `--quiet` | Suppress the normal summary |
98
+ | `--max-temp BYTES` | Best-effort budget for `jsonl-diff` workspace temporary storage |
99
+
100
+ Examples:
101
+
102
+ ```bash
103
+ # Composite identity
104
+ jsonl-diff old.jsonl new.jsonl --key country,customerId,type
105
+
106
+ # Ignore volatile fields
107
+ jsonl-diff old.jsonl new.jsonl \
108
+ --key id \
109
+ --ignore /updated_at \
110
+ --ignore /metadata/request_id
111
+
112
+ # Filter records
113
+ jsonl-diff old.jsonl new.jsonl \
114
+ --key id \
115
+ --where 'deleted_at == `null`'
116
+
117
+ # Detect observed schema drift
118
+ jsonl-diff old.jsonl new.jsonl \
119
+ --key id \
120
+ --schema-diff \
121
+ --schema-ignore /metadata
122
+
123
+ # Compressed input
124
+ jsonl-diff old.jsonl.xz new.jsonl.gz --key id
125
+ ```
126
+
127
+ ### Exit codes
128
+
129
+ | Code | Meaning |
130
+ | ---: | ---------------------------------------------------------- |
131
+ | `0` | No record, duplicate, or requested observed-schema issues |
132
+ | `1` | Record differences, tolerated duplicates, or schema changes |
133
+ | `2` | Input, resource, output, or runtime error |
134
+ | `3` | Invalid CLI configuration or usage |
135
+
136
+ ## Python API
137
+
138
+ ```python
139
+ from jsonl_diff import ChangeOperation, diff
140
+
141
+ with diff(
142
+ "old.jsonl.gz",
143
+ "new.jsonl.gz",
144
+ key=("country", "customerId"),
145
+ ignore=("/updated_at",),
146
+ where='country == `"ES"`',
147
+ schema_diff=True,
148
+ ) as result:
149
+ print(result.summary)
150
+
151
+ for change in result.changes(ChangeOperation.MODIFIED):
152
+ print(change.key, change.old_line, change.new_line)
153
+
154
+ for change in result.schema_changes():
155
+ print(change.operation, change.path)
156
+ ```
157
+
158
+ `diff()` returns a disk-backed `DiffResult`, used as a context manager.
159
+ Results are streamed lazily through `changes()` rather than materialized in
160
+ memory.
161
+
162
+ The main result models are:
163
+
164
+ ```python
165
+ Summary(equal=10, added=2, deleted=1, modified=3)
166
+ ```
167
+
168
+ and immutable `Change` objects containing the operation, typed identity, and
169
+ OLD/NEW source locations.
170
+
171
+ The public exception hierarchy is rooted at `JsonlDiffError`:
172
+
173
+ * `ConfigurationError`
174
+ * `InputError`
175
+ * `DuplicateKeyError`
176
+ * `ResourceError`
177
+
178
+ See the [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) for the full callable
179
+ signature, result models, `Decimal` key semantics, and error hierarchy.
180
+
181
+ ## Comparison semantics
182
+
183
+ `jsonl-diff` is intentionally strict:
184
+
185
+ * Every input line must contain exactly one valid top-level JSON object.
186
+ * Blank lines, malformed JSON, duplicate properties, `NaN`, and infinities are rejected.
187
+ * Identity fields must be top-level scalar values (`null` allowed only as one component of a composite key).
188
+ * Identity types remain significant: `"1"` ≠ `1`, `true` ≠ `1`.
189
+ * Duplicate identities fail by default; `--duplicates first`/`last` select one
190
+ occurrence, report every discarded occurrence, and return exit code `1`.
191
+ * Object property order is ignored; array order is significant.
192
+ * Numbers are compared by mathematical value: `1`, `1.0`, and `1e0` are equal.
193
+ * Unicode strings are compared without normalization.
194
+ * Changes are reported in deterministic identity order.
195
+
196
+ `--where` selects which records participate; `--key` defines identity;
197
+ `--ignore` removes fields from content comparison. With `--schema-diff`,
198
+ `--schema-ignore` independently removes fields from observed-schema profiling.
199
+ See
200
+ [Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) for the full rules,
201
+ including duplicate handling, ignore-pointer edge cases, `--where` evaluation
202
+ order, and canonical number formatting.
203
+
204
+ ## Sources & compression
205
+
206
+ Supported sources include local paths and HTTP/HTTPS URLs. The Python API
207
+ also accepts file-like objects.
208
+
209
+ Supported compression:
210
+
211
+ * gzip
212
+ * bzip2
213
+ * xz
214
+ * Zstandard on Python 3.14
215
+
216
+ See [architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) for the full source/compression
217
+ support matrix and how sources are delegated to `py-jsonl`.
218
+
219
+ ## Limitations
220
+
221
+ `jsonl-diff` does **not** provide:
222
+
223
+ * line/position-based diffs
224
+ * field-level diffs or JSON Patch
225
+ * move/rename detection
226
+ * nested identities or automatic key detection
227
+ * fuzzy matching or numeric tolerances
228
+ * unordered-array comparison
229
+ * validation against a declared schema or input repair
230
+ * ZIP, database, or cloud-provider inputs
231
+ * GUI or HTML reports
232
+
233
+ It is a **dataset reconciliation tool**, not a general-purpose visual JSON diff.
234
+
235
+ ## Further reading
236
+
237
+ * [Comparison semantics](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/comparison-semantics.md) — identity, duplicates, ignores, `--where`, canonical numbers, determinism.
238
+ * [Disk-backed architecture](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/architecture.md) — SQLite index, `max_temp`, cleanup, sources and compression.
239
+ * [Details JSONL format](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/details-format.md) — machine-readable `--details` output schema.
240
+ * [Python API reference](https://github.com/rmoralespp/jsonl-diff/blob/main/docs/python-api.md) — full signature, result models, and error hierarchy.
241
+
242
+ ## Development
243
+
244
+ ```bash
245
+ uv sync --group test --group lint
246
+
247
+ uv run pytest
248
+ uv run ruff check --quiet --output-format=concise .
249
+ ```
250
+
251
+ The test suite covers CLI behavior, identity/canonicalization, validation, details output, sources, compression, temporary limits, and cleanup.
252
+
253
+ ## License
254
+
255
+ See [LICENSE](LICENSE).