# One logical history in Iceberg and Delta

This disposable local experiment uses Spark 3.5.6, Iceberg 1.9.2 and Delta Spark 3.3.2.
Iceberg uses a local Hadoop catalog, format v2 and copy-on-write updates/deletes.
Delta enables name-based column mapping at creation (reader 2, writer 5). It does not
use deletion vectors, change data feed or a REST catalog.

The sequence is: insert eight rows; append four; update ID 3 and delete ID 9 in two
separate commits; compact; rename score to reading; read the retained append version.
Both formats produce the same complete logical rows at every stage. Compaction changes
two active files into one. Rename preserves file bytes and field identities. The
retained read returns all twelve original rows and the historical score column.

```fish
uv run reproduce.py --output new-history
uv run reproduce.py --output new-history --verify
```

Use Java 17. The Python dependencies and native jars are pinned in the recipe.
Generation preserves existing output by refusing to overwrite it. Verification performs
a fresh native run, checks every answer against independent Polars rows, and verifies
the existing capture's metadata membership and logical records from original Parquet
files using field IDs or physical names. It also checks every recorded artifact hash,
file-count transition and the identities and bytes preserved through rename.

Snapshot IDs, file UUIDs and timestamps vary across fresh runs. Their original bytes
remain in the preserved capture. Iceberg metadata keeps its original absolute local
paths. The verifier resolves those paths against the recorded source location; it does
not fetch them from the network. The ZIP includes the Hadoop checksum dotfiles that
are omitted from loose static hosting. This small reader check is scoped to these
unpartitioned copy-on-write fixtures and does not implement general table execution.
