Frontmatter
| id | 9066 |
| title | Bug: Store Sorting inconsistencies with Turbo Mode (Lazy Records) |
| state | Closed |
| labels | bugcore |
| assignees | tobiu |
| createdAt | Feb 9, 2026, 1:36 AM |
| updatedAt | Feb 9, 2026, 2:26 AM |
| githubUrl | https://github.com/neomjs/neo/issues/9066 |
| author | tobiu |
| commentsCount | 2 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Feb 9, 2026, 2:26 AM |
Bug: Store Sorting inconsistencies with Turbo Mode (Lazy Records)

Input from Gemini 3 Pro:
✦ ### Architectural Decision: "Soft Hydration" for Turbo Mode Sorting
We analyzed the trade-off between Full Record Instantiation and Lazy Property Injection ("Soft Hydration") for sorting in Turbo Mode (
autoInitRecords: false).The Problem:
Neo.collection.Base#doSortuses direct property access (item[prop]). In Turbo Mode, items are raw JSON. If sorting by a Model-only field (calculated or mapped), the sort fails because the property doesn't exist on the raw object.The Solution: We will implement "Soft Hydration" in
Neo.data.Store#doSort. Before sorting, the Store will ensure that the sort field exists on the raw item. If missing, it will calculate/resolve the value using the Model definition and cache it on the raw object.Why this wins:
- Memory: Raw objects + a few cached properties are significantly lighter than 100k full Class instances. Full instantiation hits a browser memory wall for large datasets.
- Latency: Full instantiation causes a massive initial UI freeze. Soft Hydration is "pay-as-you-go" and amortizes the cost.
- Caching: By writing the resolved value back to the raw object, subsequent sorts on the same field become O(1) lookups, matching the performance of instantiated records.
Implementation Plan:
- Override
doSortinNeo.data.Store.- Iterate items and check for the sort property.
- If missing, invoke a helper (e.g.,
RecordFactory.resolveValue) to compute and assign it.- Proceed with standard
Collectionsort.

Input from Gemini 3 Pro:
✦ I have implemented the "Soft Hydration" strategy to fix sorting in Turbo Mode (
autoInitRecords: false).Core Changes:
Neo.data.Store#doSortOverride: When sorting in Turbo Mode, the store now iterates the raw items and "soft hydrates" them by resolving the sort property (using Model logic) and caching it directly on the raw object. This ensures subsequent sorts are O(1).Neo.data.Store#resolveField: Added a helper to resolve fields (Mapping, Calculate, Convert) from raw data.- Model Hardening: Updated
Contributor.mjstotal_commitscalculation to be "Turbo-Safe". It now polymorphically checks for either the canonical name (commits_array) OR the raw key (cy), ensuring it works in both Record and Raw contexts.Documentation: Added comprehensive JSDoc to
resolveFieldand the Model explaining the "Soft Hydration" architecture and its limitations (recursive dependencies must be handled manually in the model).Result: Sorting by "Commits Only" (which uses the calculated
total_commitsfield) now works correctly even when records are not instantiated, preserving the performance benefits of Turbo Mode.
Investigate and fix sorting behavior in
Neo.data.Storewhen "Turbo Mode" (autoInitRecords: false) is active.Symptom: In DevRank, toggling the "Commits Only" checkbox triggers a sort on a different field (
total_commitsvstotal_contributions). The user observed that "only the mounted row-range gets resorted".Hypothesis: When
autoInitRecordsis false, the Store holds a mix ofNeo.data.Modelinstances (for accessed records) and raw JSON objects (for unaccessed records). If the Sorter uses a property that exists on the Model (e.g. a calculated field liketotal_commits) but not on the raw JSON, the sort logic might fail or produce inconsistent results for the uninitialized records.Task:
Neo.data.Store.doSortandNeo.collection.Sorter.