docs: RELEASES.md entry for 8.3.2 (honest counters)

This commit is contained in:
David Snelling 2026-07-14 11:51:51 -07:00
parent 2e2ba9c9aa
commit 0932ecde37

View file

@ -10,6 +10,36 @@ Full auto-generated changelog: `CHANGELOG.md` · Releases: https://github.com/so
---
## v8.3.2 — 2026-07-14 (honest counters — the recount + removal-without-re-reading)
Completes 8.3.1's delete-hygiene story at the counter layer, from a production proof chain reported
by a downstream deployment: persisted entity totals were permanently **inflated** — deletes whose
count decrement was silently skipped — and because paginated `totalCount` serves
`Math.max(persistedTotal, scanned)`, the inflated number always won and **no disk cleanup could ever
lower it**.
- **A removal's count decrement no longer requires re-reading the record being removed.** The
decrement was sourced from re-reading the entity's metadata inside the delete; if that read
returned `null` (a replace race, or a ghost left by a pre-8.3.1 partial delete) the decrement was
silently skipped while the paired add had counted — minting drift on every write→delete→re-create
cycle. The caller's pre-delete read now rides through the whole delete path
(`remove()`/`removeMany()` → the delete operation → `deleteNoun`/`deleteVerb`
`deleteNounMetadata`/`deleteVerbMetadata`, both sides symmetric): a null internal read falls back
to the known prior record instead of skipping. The `StorageAdapter` signatures gain an optional
`priorMetadata` parameter (additive; existing adapters unaffected).
- **`repairIndex()` is the sanctioned counter recount — unconditional, and it actually persists.**
`rebuildTypeCounts()` previously rebuilt only the type-statistics arrays and computed the total
*just to log it* — the persisted scalar (`counts.json`) survived every "rebuild" untouched, so an
already-inflated brain could never be corrected. One canonical walk now rebuilds **every** counter
rollup — scalar totals, per-type maps, and type statistics — and persists them, and `repairIndex()`
runs it unconditionally (not only when orphan directories are found: counters can be inflated over
perfectly clean shelves). Brains with delete history should run `brain.repairIndex()` once after
upgrading; the correction survives reopen.
No API breaks (optional-parameter additions only). Regression tests cover the drift cycle, the
null-read decrement fallback, and the persisted recount across reopen.
## v8.3.1 — 2026-07-14 (full-removal deletes + family-scoped migration gate)
Two production-reported fixes in the write/index spine, plus an operator repair path. No API changes;