# repo22 compact LZ4 root-cause verification

- Date: 2026-08-08 UTC
- Source parent: `c939c472134c69fa4665f52ab1aec9a17cd583b9`
- FreeBSD guest: 15.0-RELEASE-p8 amd64, QEMU TCG
- Image tool: erofs-utils 1.8.6
- Scope: the existing minimal compact LZ4 fixture only; no CI or wrapper was added

## Changes under verification

1. Accept incompat bit `0x8` for compressed HEAD2 while rejecting images with
   external device slots until true multi-device I/O exists.
2. Widen zmap `clusterofs` so the 64 KiB NONHEAD sentinel is representable.
3. Count compact indexes using the logical cluster size.
4. Apply leading zero padding according to the algorithm and the LZ4
   `0padding` feature instead of stripping it unconditionally for all streams.
5. Zero decompression targets and require exact output lengths.
6. Apply DEFLATE `windowbits` and ZSTD `windowlog` to the decoder calls.
7. Separate LZ4 full and partial completion rules and validate input/output
   boundaries.
8. Permit valid compact NONHEAD deltas to cross compact-pack boundaries.  The
   previous BSD-only restriction caused the first real image read to fail at
   the second compressed extent head.

## Build and module lifecycle

`./build.sh` completed successfully.  The resulting module had no unresolved
`bcmp` symbol and contained no temporary zmap/zdata diagnostic strings.

On the guest, all lifecycle operations succeeded:

```text
kldload_rc=0
mount_rc=0
umount_rc=0
md_detach_rc=0
kldunload_rc=0
```

## Real image result

The fixture was generated by the existing manual-test command:

```sh
mkfs.erofs -T0 --all-root --ignore-mtime -x-1 -Uclear \
  -zlz4 -C4096 lz4-root-compact-4k.erofs src-root-lz4
```

`dump.erofs` identifies `/test-lz4.txt` as layout 3 (compact), 1 MiB logical,
8 KiB on disk, with two compressed extents.  The same image previously failed
its first read with `EINTEGRITY` on `f2301295`.

Final FreeBSD results:

```text
SHA256 (/mnt/repo22-rootfix/test-lz4.txt) = 370eb0a8df86868c4842ca535ed64670f0277ea2ed47a703f089bbb13ee4ac52
SHA256 (source test-lz4.txt)               = 370eb0a8df86868c4842ca535ed64670f0277ea2ed47a703f089bbb13ee4ac52
SHA256 (first 4096 bytes from EROFS)       = 3d6d283a95f80b3e4a9c243cf82dc0644283910b6a3be931fede5d771e132b14
SHA256 (first 4096 bytes from source)      = 3d6d283a95f80b3e4a9c243cf82dc0644283910b6a3be931fede5d771e132b14
full_read_rc=0
first_4k_read_rc=0
```

Result: the minimal real compact LZ4 mount/read gate passes.

## Integration follow-up

The integration review after `6c9543892` found that the leading-padding
predicate still selected every non-LZ4 algorithm.  The predicate was narrowed
to LZ4 streams with the `0padding` incompat feature, matching the stated
algorithm-specific behavior.  `./build.sh` and the same FreeBSD 15 compact LZ4
mount/read lifecycle were rerun after this correction; the full-file SHA256
remained `370eb0a8df86868c4842ca535ed64670f0277ea2ed47a703f089bbb13ee4ac52`,
the first 4096-byte read returned 4096 bytes, and module unload succeeded.

## Remaining gaps

This batch does not claim runtime completion for legacy full indexes, 64 KiB
or larger pclusters, ztailpacking, interlaced pclusters, fragments, extents,
partial references, MicroLZMA, DEFLATE, or ZSTD images.  DEFLATE and ZSTD
configuration handling was corrected and the module loaded on this FreeBSD 15
kernel, but those algorithms were not image-tested in this converged batch.
The LZ4 partial-decoding branch was code-reviewed but is not exercised by the
current synchronous full-extent read path.
