Make count, isEmpty, first, entities and for-of honour tick filters - #5
Open
srikarsunchu wants to merge 1 commit into
Open
srikarsunchu wants to merge 1 commit into
srikarsunchu wants to merge 1 commit into
Conversation
On a Changed/Added/Removed query the scalar reads summed archetype rows and never consulted the RowFilter, so world.query(Changed(Position)).isEmpty answered the structural question while each() answered the filtered one. for-of and entities() had the same gap. Route them through a second RowFilter over the same terms, opened with peek() at the live filter's horizon: it accepts exactly the rows the next each() would visit, in the same order, and never advances lastSeen. That is the property that matters — `if (!q.isEmpty) q.each(…)` must not cost the run its events, and a read inside a running each() must not swap the bound columns from under it, which a shared filter would. Unfiltered queries keep their O(1) answers; a filtered read is the same scan each() already pays. Sorted views answer the reads through their own walk, which owns the filter their each() runs with; ordered views already delegate to the base. README and SPEC §8.3 say which operations consume the window. Fixes diffusionstudio#2 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2.
What
count,isEmpty,first,entities()andfor … ofon aChanged()/Added()/Removed()query now answer for the filter. The issue names the three scalar accessors; readingEntityIteratorshowedfor … ofandentities()were built from the archetype list alone and had the same gap, so all five read paths are covered together.How — option 1 from the issue, with one property pinned down
The reads must not consume the change window, or
if (!q.isEmpty) q.each(…)would cost the run its events. And a read inside a runningeach()must not swap the filter's bound columns from under it, which routing through the sharedRowFilterwould.So each result keeps a second
RowFilterover the same terms for reads.RowFilter.peek(ticks, horizon)opens it at the live filter'slastSeenwithout advancing anything;begin()is unchanged and now shares its body withpeek(). The probe walks archetypes and rows in the same back-to-front ordereach()uses, sofirstis the entityeach()would visit first.each()already pays.ListWalk, which owns the filter theireach()runs with (they used to delegatecount/isEmptyto the base, whose filter is a different instance with its ownlastSeen). Ordered views already delegate everything to the base, so they follow.accessor.test.ts › get is not a write) assertedquery.count === 1on aChangedquery as an incidental "still exists" check; it now asserts both facts explicitly (world.query(Position).count === 1,query.isEmpty).Tests
Six new cases in
tick-filters.test.ts: reads answer for the filter; reading does not consume whateach()is about to see (and after the run the window is closed);firstfollowseach()order;Added/Removed; sorted views; unfiltered reads untouched.npm test: 2348 passed across dev / prod / react / solid / types.tsc --noEmitand prettier clean.Not in this PR
#3 (a
Changedreader ordered before its writer) is a scheduling design choice between the options listed there; nothing here changesbegin()semantics.🤖 Generated with Claude Code