HarperFast / HarperFast/harper

randomAccessFields tables cannot recover rows contaminated with resolver-owned values

Open
#2,369 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
JavaScript
Stars
89
Forks
10
Avg merge
2d 6h
Merged PRs (30d)
200

Description

## Summary

The #2359 recovery path (shipped in #2368) reaches only records that decode as **plain objects**. On a table with `storage.randomAccessFields: true` (or the global `STORAGE_RANDOMACCESSFIELDS`), records decode as structon lazy typed-struct instances whose stored fields live as accessors on a structon-generated child prototype. For a row that an affected release (5.1.0–5.2.6) contaminated with a value under an `@computed`/`@enumerable @relationship` name:

- the child-prototype field accessor **shadows** the table's resolver on `structPrototype`, so reads return the stale stored value — silently, with no crash to announce it;
- neither recovery trigger fires (`toJSON` is structon's, not the table's surfaced projection; the colliding name is never an own key), so re-encodes re-persist the contamination — it never ages out.

## Expected

The resolver is authoritative over any stored value under its name, on every storage mode — the invariant #2368 establishes for plain-decode tables.

## Repro sketch

1. On 5.2.x, a `randomAccessFields: true` cache table with `salePrice: Float @computed(...)`; fill a record whose durable encode captured `salePrice` (any affected-release write).
2. Upgrade to a build with #2368.
3. Read the row: it reports the stale stored `salePrice`, and a subsequent write re-persists it.

`integrationTests/resources/cachedComputedAttribute.test.ts` has the probes (`PoisonedRecord`, `StoredKeys`); a fixture variant with `randomAccessFields: true` would settle it in one run — the mechanism is confirmed from structon's decode path (`struct.js` child-prototype accessors), but no end-to-end run has exercised it yet.

## Notes

Raised repeatedly by the #2368 pre-push review (rounds 1–5, adjudicated in-scope, deferred). A fix likely wants structon cooperation (the decoded instance knows its structure fields; harper knows the resolver-owned names) — either a decode-side skip list handed to structon, or materializing such rows to plain objects when the encoder has `resolvedAttributeNames`.

Contributor guide

Open the contributing guide

Research direction

Start with integrationTests/resources/cachedComputedAttribute.test.ts and the #2368 recovery path, then inspect struct.js child-prototype accessors involved in decoding randomAccessFields rows. Exercise a fixture variant with randomAccessFields: true using the existing PoisonedRecord and StoredKeys probes; done means the resolver wins over the stored value and subsequent writes no longer re-persist the contamination.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
database
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.