HarperFast / HarperFast/harper
Stale index entries for @indexed @computed attributes survive invalidation
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Summary
`updateIndices` derives **both** sides of an index diff from `propertyResolvers` — the stored record's value is never consulted for a computed attribute. After `invalidate()` reduces a row to its indexed-attribute stub, the computed resolver runs over a stub whose *input* fields are gone and yields `NaN`/`undefined`, so on the next write `remove(, id)` never happens: the superseded index entry lingers.
## Repro
```
type P @table @export { id: ID @primaryKey, price: Float, discount: Float,
salePrice: Float @computed(from: "price - (discount || 0)") @indexed }
```
1. `PUT {price: 100, discount: 40}` → index has `[60, id]`
2. `invalidate(id)`
3. `PUT {price: 200, discount: 0}` → index now has **both** `[60, id]` and `[200, id]`
4. `?salePrice=60` returns the row, whose actual `salePrice` is 200.
## Notes
- **Pre-existing** — independent of #2368 (before it, this path crashed outright per #2359; #2368 makes the row readable again, which makes this observable). The resolver-derived diff has never been able to see what the invalidation stub used to hold.
- Silent: no error anywhere, just stale query results until the row's index entries are rebuilt.
- A fix probably wants the invalidation path to remove computed index entries using the *pre-invalidation* record (available at `_writeInvalidate` time), or to tolerate stub-derived `NaN` by falling back to the stored index scan for removal.
- Surfaced by the #2368 pre-push review (rounds 1/5, adjudicated pre-existing).
Contributor guide
Research direction
Start by tracing updateIndices, propertyResolvers, and the _writeInvalidate path described in the issue, then reproduce the PUT/invalidate/PUT sequence with the P example. Check how the pre-invalidation record and indexed entries are handled during removal. Done means the obsolete [60, id] entry is removed and querying salePrice=60 no longer returns the updated row.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100