feat(pathfinding): .swb uniform-chunk elision (format v5) — Trammel 592→232 MB (#2465)

## Summary

Sub-project #1 of the `.swb` step-cache size-reduction roadmap (`dev-docs/pathfinding.md` § Future work). Adds **uniform-chunk elision** to the `StepCacheFile` format, bumping it **v4 → v5**.

A fully-uniform 16×16 chunk — no strata, **no swim layer**, all 19 base arrays constant (open ocean, Green Acres, void) — serializes to a **~28-byte record** (`KindUniform`) instead of ~5,393, and reconstructs **byte-identically** via `Array.Fill`. Non-uniform chunks use the existing v4 body (`KindFull`) with the swim-layer and strata trailers **fully preserved** — the Kind byte is just prepended.

## Calibrated result (measured, not projected)

Baked Trammel via `SaveToFile`:

| | |
|---|---:|
| Chunks | 114,688 |
| Uniform (swim-aware) → elided | 62.7% |
| Swim-layer chunks (stay Full) | 8.9% |
| Strata chunks (stay Full) | 1.8% |
| Baseline (full records) | 592.2 MB |
| **Actual v5 `.swb`** | **231.9 MB (−61%)** |

The residual is ~150 MB of non-uniform land Z-blocks (targeted by #2 predictive-Z) + ~81 MB of swim-layer trailers (#2/#3). #2 and #3 are separate follow-up PRs.

## Implementation

- `StepChunk.IsUniform()` — false if it has strata **or a swim layer**, else true only when all 19 base arrays are constant (the "all-same" check uses the SIMD-accelerated `ContainsAnyExcept`).
- `StepCacheFile` v5 — `Kind` byte (`KindFull=0`/`KindUniform=2`, 1 reserved); uniform write/read; `FormatVersion`/`MinSupportedVersion` → 5 (v4 files rejected on open and re-baked). No `StepCache`/algorithm/index changes; fingerprint logic untouched.

## Tests

7 `StepCacheFileV5Tests` (uniform round-trip + `<200 B` compactness, varied-full, swim-layer-full, strata-full, swim+strata combined, v4 version-gate rejection) + the existing StepCache/pathfinding suite — **70 pass**, including the prior `SwimLayer_RoundTrips`. An independent review verified write/read symmetry, cast round-tripping, swim/strata preservation, and the version gate (READY TO MERGE).
This commit is contained in:
Kamron Batman 2026-06-06 15:20:27 -07:00 committed by GitHub
parent 47bf2d1f13
commit c7697e1dc5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 324 additions and 9 deletions

View file

@ -196,7 +196,6 @@ exists to prove this (ratio ≈ 1.0 vs the vendored FastAStar baseline).
because the cache's `SourceZ` is computed under default-walker rules, so swim creatures fall
through to the slow path. Baking swim-aware source Z (or a swim stratum) would let them hit
the cache. Independent of the size-reduction work below.
### `.swb` size reduction (the ~565 MB → tens of MB roadmap)
The v2 format stores every 16×16 chunk as a flat ~5,393-byte record, uncompressed, with no
@ -226,3 +225,15 @@ whole-file) and bounded RAM (only touched chunks materialize, LRU-capped):
all-zero Z residuals?) to size the #1/#2 win before writing any format code. Each technique is a
clean v3 format bump; `MinSupportedVersion` already silently rejects + overwrites older files.
Validate size **and** read-latency vs the corpus in the benchmark repo after each.
**Measured headroom (Trammel).** Two measurements, both 2026-06-06:
- *Pre-swim audit (v2 spike, indicative):* directional-Z is **95.2% zero-residual for WalkZ**,
**38.1% for SwimZ** vs `SourceZ` (→ #2; swim wants its own predictor or leans on #3). The
spike's combined size projection double-counted and is superseded by the calibration below.
- *Calibrated on the real v4/v5 format (`SaveToFile`-measured):* 114,688 chunks; **62.7% fully
uniform** (swim-aware → #1 elides these), **8.9% carry a swim layer** and **1.8% strata**
(both stay Full). **#1 alone: 592.2 MB → 231.9 MB (61%), actual on-disk.** The residual is
~150 MB of non-uniform land Z-blocks (→ #2 predictive-Z) + ~81 MB of swim-layer trailers
(→ #2/#3). Confirms build order **#1#2#3**, with #1 the dominant, lowest-risk,
no-algorithm-change win (now shipped as format v5).