# DocDelta
Compare two local Markdown or HTML files and get a bounded JSON report of section additions, removals, and changes, with anchors to the original input lines. Useful for reviewing document revisions or feeding changes into an existing workflow.
Requires Python 3.10+ on a POSIX system and its standard library. No installation or account is needed.
Download the [complete source ZIP](https://sha256eunicehash.com/product-docs/docdelta/source.zip) and extract it into a directory. It includes the CLI, MIT license, synthetic examples and all eight tests. The commands below use that complete directory layout.
## Quickstart
From this directory:
```sh
python3 -B docdelta.py examples/before.md examples/after.md
```
JSON is written to stdout. To save a report, explicitly redirect it:
```sh
python3 -B docdelta.py examples/before.md examples/after.md > report.json
```
Both inputs must be regular UTF-8 files, each at most **65,536 bytes**. Format detection uses `.html` or `.htm` for HTML and treats other suffixes as Markdown. Override either input independently:
```sh
python3 -B docdelta.py before.txt after.md --before-format html --after-format markdown
```
`--before-format` and `--after-format` each accept `auto`, `markdown`, or `html`.
## Report and limits
The JSON report contains `sections[]`. Each reported section has a `kind` of `added`, `removed`, or `changed`; its heading, level, and occurrence; old/new section anchors; and `edits[]` describing old/new `startLine`, `endLine`, and `text`. Line references point into the original files. Unchanged sections are omitted.
| Option | Default | Hard maximum |
| --- | ---: | ---: |
| `--max-changes` | 100 | 256 |
| `--max-output-bytes` | 32,768 | 65,536 |
The change limit applies separately to reported sections and the total number of edits. Invalid snapshots and exceeded comparison/output limits produce a JSON error and exit status `2`. Reports are never silently truncated or partially returned. A successful comparison exits `0`, including when changes are present.
The output cap counts the actual UTF-8 JSON bytes, including the final newline. NUL characters are rejected. A five-second processing alarm bounds comparisons on POSIX; ordinary stdout backpressure is outside that processing limit.
## Comparison rules and limitations
- Markdown supports ATX headings (`# Heading`) and conservatively handles fenced code. Body spacing, blank lines, and inline syntax are preserved. It is not a complete Markdown renderer.
- HTML collapses normal-flow presentation whitespace and ignores comments, `script`, `style`, and `template` content. It preserves code/preformatted whitespace, link `href` values, and resource URL targets, so target, code, and number changes remain observable.
- Duplicate headings stay separate and are matched by level, title, and ordinal occurrence. Renamed or moved sections may appear as additions and removals; inserting duplicate headings can affect later matches.
- Comparison does not infer meaning or semantic equivalence. HTML is parsed without browser rendering, CSS layout, or JavaScript execution.
- HTML reports compare visible text, headings, code, and selected URL attributes, rather than every DOM attribute. Cross-format comparisons can report syntax differences; normalized HTML is not a full Markdown conversion.
## Local operation
DocDelta reads the supplied input files and writes its result to stdout. It does not crawl, fetch linked resources, access the network, or keep a cache or persistent application state. Saving output through shell redirection is an explicit caller action.
## Examples and verification
The [before](examples/before.md) and [after](examples/after.md) documents are synthetic. Their [example output](examples/output.json) records an endpoint target, numeric limit, and code change, plus an added and removed section.
```sh
python3 -B -m unittest -v
```
The eight tests cover presentation whitespace, code/URL/number changes, section and duplicate-heading anchors, HTML entities and table cells, exact multibyte input/output boundaries, error handling, and operation with network access disabled by a socket guard. Test files are created temporarily inside this directory and removed afterward.
## License
[MIT](LICENSE).
SPDX-License-Identifier: MIT