fix: one field-resolution law across aggregation hooks, source.where, removeMany, and find() spellings
Four fixes from a consumer conformance report, one root disease — two field-resolution regimes where there must be one: - The delete/update aggregation hooks fed the engine a partial entity view (type/service/data/metadata only), so a reserved-field groupBy (subtype, visibility, ...) resolved to a nonexistent group on the way down: counts drifted upward forever after deletes, and updates moving an entity between reserved-field groups double-counted. The hooks now pass the full-fidelity view via entityForAggFromRawRecord (every reserved field top-level, mirroring the add path); the update sites pass the full get() view instead of a hand-rolled subset. - Aggregation source.where resolved fields only against the custom metadata bag, so where on a reserved field silently matched nothing. The matcher now resolves each filtered field through resolveEntityField — the same single source of truth groupBy uses. - removeMany() with no usable selector (bare array passed positionally, empty params, ids: []) resolved successfully having deleted nothing. All three now throw; the two legacy tests that pinned the silent no-op as 'graceful' now pin the refusal. - find() where keys accept both spellings: a metadata.-prefixed key falls back to its flattened spelling when the prefixed one is not indexed (metadata is flattened at index time). A literal nested custom key named metadata still wins when indexed as spelled. Five regression pins in aggregate-reserved-fields.test.ts (4 of 5 vary red on the unfixed code).
This commit is contained in:
parent
42037d0cd0
commit
945d92d29e
7 changed files with 303 additions and 45 deletions
26
RELEASES.md
26
RELEASES.md
|
|
@ -10,6 +10,32 @@ Full auto-generated changelog: `CHANGELOG.md` · Releases: https://github.com/so
|
|||
|
||||
---
|
||||
|
||||
## v8.8.2 — 2026-07-19 (one field-resolution law: reserved-field aggregates stop drifting)
|
||||
|
||||
Four fixes from a consumer conformance audit, all rooted in the same disease — two field-resolution
|
||||
regimes where there must be one:
|
||||
|
||||
- **Aggregates grouped by a RESERVED field (`subtype`, `visibility`, …) now decrement on
|
||||
delete.** The delete/update hooks fed the aggregation engine a partial entity view (type,
|
||||
service, data, metadata only), so a reserved-field `groupBy` resolved to a nonexistent group
|
||||
on the way DOWN — counts drifted upward forever after any delete, and updates that moved an
|
||||
entity between reserved-field groups double-counted it. The hooks now pass the full-fidelity
|
||||
entity view (every reserved field top-level, the same shape the add path uses). If your
|
||||
deployment derives stats from reserved-field aggregates, re-define those aggregates once
|
||||
after upgrading (a changed definition triggers one rescan) or run them fresh — the drifted
|
||||
persisted counts do not self-heal retroactively.
|
||||
- **Aggregation `source.where` on reserved fields now filters** instead of silently matching
|
||||
nothing: the matcher resolves fields through the same resolver `groupBy` uses (top-level
|
||||
standard fields + custom metadata), so `where: { subtype: 'note' }` means what it says.
|
||||
- **`removeMany()` refuses empty/invalid selectors loudly.** A bare array passed positionally
|
||||
(`removeMany([id])` instead of `removeMany({ ids: [id] })`), an empty params object, or
|
||||
`ids: []` used to resolve successfully having deleted nothing. All three now throw.
|
||||
- **`find()` accepts both where-key spellings.** Metadata is flattened at index time
|
||||
(`metadata.entry.title` indexes as `entry.title`); a `metadata.`-prefixed where key now
|
||||
falls back to its flattened spelling when the prefixed one isn't indexed — the
|
||||
"unindexed field(s), returning []" confusion for storage-shaped spellings is gone. (A
|
||||
literal nested custom key named `metadata` still wins when indexed as spelled.)
|
||||
|
||||
## v8.8.1 — 2026-07-18 (flush no longer walks the whole generation history + the import dedup off-switch is now honest)
|
||||
|
||||
### The flush-storm fix (production incident, reported by a long-running deployment)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue