Repository navigation
fix: removed geospatial filters no longer crash test() - #84
Merged
Merged
Conversation
boost-geospatial-index used to leave some removed shapes in its tree; their ids kept coming back from queries without a subfilter behind them, and test() threw "subfilters is not iterable" (reproduced on 4.7.0). Seeded: 2 000 geoDistance filters, half removed, 5 000 tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
boost-geospatial-index 1.5.0-beta.1 → 1.5.0-beta.2, whose remove() no longer leaves shapes behind in its tree (kuzzleio/boost-geospatial-index#29). Those leftovers came back from queries without a subfilter, and test() threw "subfilters is not iterable" once geospatial filters had been unregistered (62 of 5 000 tests on Node 22, 460 on Node 24, with 2 000 geoDistance filters of which half removed; reproduced on 4.7.0). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
🎉 This PR is included in version 4.8.0-beta.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
github-actions Bot
pushed a commit
to kuzzleio/kuzzle
that referenced
this pull request
Sep 27, 2026
## [2.57.0-beta.2](v2.57.0-beta.1...v2.57.0-beta.2) (2026-09-27) ### Features * native addons from prebuilt binaries, no compiler at install time ([4643d45](4643d45)), closes [#2839](#2839) ### Bug Fixes * realtime matching no longer throws after geospatial unsubscriptions ([eca6292](eca6292)), closes [kuzzleio/boost-geospatial-index#29](kuzzleio/boost-geospatial-index#29) [kuzzleio/koncorde#84](kuzzleio/koncorde#84) [Koncorde#test](https://github.com/kuzzleio/Koncorde/issues/test)
Merged
|
🎉 This PR is included in version 4.8.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
github-actions Bot
pushed a commit
to kuzzleio/kuzzle
that referenced
this pull request
Sep 30, 2026
## [2.57.0](v2.56.0...v2.57.0) (2026-09-30) ### Features * **apiKeys:** allow an api key to be deleted by the key itself or its fingerprint ([#2683](#2683)) ([e172c73](e172c73)) * **ci:** ratchet implicit any, and count `as unknown as` as any ([34e29d9](34e29d9)) * **cluster:** retransmit lost sync messages before evicting ([#2785](#2785)) ([0807880](0807880)) * **h4:** convert lib/core/validation/validation.js to TypeScript ([787cfd7](787cfd7)) * **h5:** convert plugin.js and pluginsManager.js to TypeScript ([acb958e](acb958e)) * **h6:** convert entryPoint.js and httpwsProtocol.js to TypeScript ([5d0ef6d](5d0ef6d)), closes [#2749](#2749) * **i1:** convert the four lib/kuzzle leaves to TypeScript ([1990a22](1990a22)) * **i2:** convert internalIndexHandler and dumpGenerator to TypeScript ([f7b9ff3](f7b9ff3)) * native addons from prebuilt binaries, no compiler at install time ([4643d45](4643d45)), closes [#2839](#2839) * setup claude ([7de8020](7de8020)) * **skills:** add /wrapup skill for end-of-session handoff ([bc49d3a](bc49d3a)) * **td-43:** charge for a type assertion — a sixth ratchet, `casts` ([3f8be8c](3f8be8c)), closes [#2730](#2730) * **td-56:** fail on a declaration that lies, adopted or not ([b415d7f](b415d7f)) * **td-61:** make a conversion report the strict count it leaves behind ([e21fbf1](e21fbf1)) * **ts:** flip strict on, and split the test code into its own program ([e400320](e400320)) * use new kuzzle vault algorithm ([dcea521](dcea521)) * **utils:** distributed reentrant mutex ([#2664](#2664)) ([cda3514](cda3514)) * **vault:** use old encryption algorithm unless configured otherwise ([7eeec62](7eeec62)) ### Bug Fixes * API keys can be deleted by key or fingerprint on upgraded installs ([99b87a7](99b87a7)) * **api:** declare RateLimiter's limit without a dead initialiser ([0130222](0130222)) * **bin:** --enable-plugins skips a missing plugin with a warning (step 15, D-4) ([dfec664](dfec664)) * **cache:** copy the Redis config with cloneDeep, not structuredClone (step 15, F-07) ([1702cb1](1702cb1)), closes [#2676](#2676) * **cache:** keep the receiver when calling a hoisted command ([b7b7234](b7b7234)) * **changelog:** resolve leftover merge-conflict markers ([3ce76fc](3ce76fc)) * **ci:** anchor the strict-check adopted-path match ([622531a](622531a)) * **ci:** let the preflight conversion reminder see uncommitted work ([a72c6b1](a72c6b1)), closes [#2774](#2774) * **ci:** make the implicit-any and casts ratchets fail closed ([83f6601](83f6601)), closes [#2731](#2731) * **ci:** normalise the coverage reports before SonarCloud reads them ([d3870be](d3870be)) * **ci:** resolve .js targets in the tests/ mirror convention ([8c11613](8c11613)), closes [#2771](#2771) * **ci:** restore coverage measurement on TypeScript (TD-24, [#2692](#2692)) ([b90eac9](b90eac9)), closes [#2658](#2658) * **ci:** stop the local docker unit runner rewriting the host's node_modules ([e8ae7af](e8ae7af)), closes [#2793](#2793) [#2790](#2790) * **ci:** wait-kuzzle's fourteenth call site, and the prune that removed its runner ([ff50dda](ff50dda)) * **cluster:** a joining node no longer evicts itself for a message it already has (step 15, F-12) ([cceefe8](cceefe8)), closes [#2777](#2777) [#2781](#2781) * **cluster:** answer a joining node's handshake within its timeout (step 15, F-03) ([5b4b8e9](5b4b8e9)), closes [2777/#2781](https://github.com/2777/kuzzle/issues/2781) * **cluster:** answer the rules node.ts's rename re-scored ([17ce162](17ce162)) * **cluster:** answer the three rules the J3a rename re-scored ([e78f566](e78f566)) * **cluster:** close TD-33's cluster half — TD-65 and TD-67 ([c753464](c753464)), closes [#2773](#2773) [#2776](#2776) * **cluster:** do not evict a peer for heartbeats queued behind a recovery (step 15, F-04) ([212183d](212183d)), closes [#2896](#2896) * **cluster:** fork the ID card worker by the extension it actually has ([690de4d](690de4d)) * **cluster:** inline SubscriberState, the last S6564 on the slice ([84d9a7c](84d9a7c)) * **cluster:** prove the subscription is live in addNode too ([f6def54](f6def54)) * **cluster:** satisfy the TS-only rules the subscriber rename exposed ([998e727](998e727)) * **cluster:** satisfy the two TS-only rules the rename exposed ([afae7af](afae7af)) * **cluster:** shutdown before the handshake still disposes (step 15, F-11) ([ef882ef](ef882ef)), closes [#2803](#2803) * **cluster:** the publisher's history is readonly ([fdb944e](fdb944e)) * **cluster:** use Object.hasOwn in isSyncTopic ([0d56164](0d56164)) * **core:** a node that exits frees the locks it holds (step 15, F-13) ([6ab73f3](6ab73f3)) * **deps:** depend on the stable releases of koncorde and dumpme ([52cc8cc](52cc8cc)) * **deps:** withLock on redis-semaphore, which supports Node 20 (step 15, D-3) ([6a2f9ae](6a2f9ae)) * **document:** export accepts an array sort (step 15, F-02) ([45c2966](45c2966)), closes [#2666](#2666) * **dump:** check suffix against a regexp to sanitize user input ([#2665](#2665)) ([79c9adf](79c9adf)) * **dump:** keep handled-error dumps valid and never unhandled (step 15, F-05) ([4356506](4356506)) * **errors:** restore v2.56.0's client-facing text for plugin and WebSocket parsing errors (step 15, F-10) ([fdd0512](fdd0512)), closes [#2803](#2803) [#2803](#2803) [#2752](#2752) * **export-csv:** use sort args is provided in the query ([422ae64](422ae64)) * **h5:** put the plugin config NOSONAR on the line Sonar flags ([525203b](525203b)) * **i1:** clear the five minor smells the renames re-scored ([e88ca2d](e88ca2d)) * **i2:** clear the five minor smells the renames re-scored ([ec07d91](ec07d91)), closes [#2688](#2688) * **kerror:** drop the "probably not a Kuzzle error" suffix from plugin errors ([3b030e4](3b030e4)) * **kerror:** only an object literal given last is the options object (step 15, F-08) ([3c8dbf1](3c8dbf1)), closes [#2803](#2803) * **kerror:** survive being loaded as ESM ([71b8c11](71b8c11)) * **kuzzle:** close TD-69 — the mappings-import lock race ([d37b391](d37b391)) * **kuzzle:** flush the application logger on shutdown ([2730955](2730955)), closes [#2747](#2747) * **kuzzle:** justify the deprecated Mutex on the import lock ([6af2921](6af2921)), closes [#2688](#2688) * **lint:** three unused/shadowed bindings left by K4 and K5 ([facf9c5](facf9c5)) * logstash access logs carry the request headers once ([b8b05c8](b8b05c8)) * **network:** enforce the multipart file-size limit and populate connection headers ([47c62cf](47c62cf)), closes [#2749](#2749) * **network:** Protocol.init takes any falsy first argument again (step 15, F-11) ([0202c89](0202c89)), closes [#2737](#2737) * **plugin:** accessors.execute takes a null callback as absent (step 15, F-06) ([9a8d036](9a8d036)), closes [#2803](#2803) * **plugin:** context.constructors.ESClient follows the configured major version ([0a6bc72](0a6bc72)) * **plugin:** strategy verify may return a then-only thenable (step 15, F-11) ([d89e323](d89e323)), closes [#2748](#2748) * published typings compile without dev dependencies ([2af8b4c](2af8b4c)) * realtime matching no longer throws after geospatial unsubscriptions ([eca6292](eca6292)), closes [kuzzleio/boost-geospatial-index#29](kuzzleio/boost-geospatial-index#29) [kuzzleio/koncorde#84](kuzzleio/koncorde#84) [Koncorde#test](https://github.com/kuzzleio/Koncorde/issues/test) * **sonar:** clear the 27 new-code violations on the network rename ([b858fc2](b858fc2)), closes [#2688](#2688) [#2722](#2722) * **sonar:** clear the 57 new-code minors the rename re-scored ([0b2ad1c](0b2ad1c)) * **sonar:** declare Profile._hash as an overloaded method, not a static field ([ffca3db](ffca3db)) * **sonar:** NOSONAR the two remaining awaits of a non-Promise (TD-26) ([85a22fc](85a22fc)), closes [#2697](#2697) * **sonar:** optional chaining in documentController + CPD-exclude the file ([899f73f](899f73f)) * **sonar:** resolve new-code smells in memoryStorageController (PR C) ([1ea5437](1ea5437)) * **sonar:** resolve new-code smells in serverController + documentExtractor (PR D) ([1d423e5](1d423e5)) * **sonar:** resolve the new-code smells the rename re-scored (PR G1) ([d96f77f](d96f77f)) * **sonar:** resolve the smells the clientAdapter rename re-scored ([5eee56f](5eee56f)), closes [#2688](#2688) * **sonar:** resolve the three smells the typing pass scored ([f396617](f396617)) * **sonar:** return null rather than Promise.resolve(null) in load() ([4c456e1](4c456e1)) * **sonar:** split the four functions the rename re-scored as too complex ([0efbea0](0efbea0)) * **sonar:** the last new-code minor on accessLogger ([e72a829](e72a829)) * **sonar:** the last three new-code minors on geoShape ([4be97a0](4be97a0)) * **step-03:** bin/start-kuzzle-server, whose every option was dead ([7006066](7006066)) * **step-14:** M7 — ts-node reads the test program's options, not its include ([2b6d4e5](2b6d4e5)) * **storage:** a missing document answers not_found again (step 15, F-01) ([2ad3541](2ad3541)) * **td-20:** configure takes a result, and the core stops calling setResult ([5824f88](5824f88)) * **td-20:** name the comma-separated array form instead of deprecating it ([6e17100](6e17100)), closes [#2721](#2721) * **td-20:** validation reads input.args instead of the deprecated input.resource ([7ae3126](7ae3126)) * **td-21:** guard _wrapError on the controller name, not the request ([65a9e09](65a9e09)), closes [#2687](#2687) * **td-26:** drop the five awaits of a non-Promise ([914341a](914341a)), closes [#2697](#2697) * **td-27:** normalize a controller's error where it is raised, not on the funnel ([563b183](563b183)), closes [#2703](#2703) * **td-28:** drop memoryStorageController's class-wide index signature ([4687d74](4687d74)), closes [#2702](#2702) [#2704](#2704) * **td-33:** gate the functional suite on cluster readiness, not on a handshake ([267f9d3](267f9d3)), closes [#2715](#2715) * **td-33:** keep the log dump armed through the test run ([f63f997](f63f997)) * **td-33:** make a cluster startup failure diagnose itself ([ad9fe4b](ad9fe4b)) * **td-33:** put fail-fast: false on the monkey matrix too ([7ae01af](7ae01af)) * **td-34:** correct Profile._hash's return type, and type its patch site ([a802d4a](a802d4a)), closes [#2712](#2712) [#2712](#2712) * **td-35:** run copy-binaries without a native binary, and gate the build payload ([389c2a0](389c2a0)), closes [#2713](#2713) * **td-36,td-37:** gate the artifact that is published, and derive the gate from `files` ([6fbb0ec](6fbb0ec)), closes [#2717](#2717) * **td-38,td-47:** gate a fork's PR on the build, and stop paying for superseded runs ([86e309d](86e309d)), closes [#2719](#2719) [#2725](#2725) [#2734](#2734) * **td-40:** declare the load path nullable, where it has always been nullable ([e08e9fd](e08e9fd)), closes [#2724](#2724) [#2727](#2727) * **td-41:** give Protocol.init the two overloads its union was standing in for ([859d162](859d162)), closes [#1645](#1645) [#2728](#2728) * **td-41:** normalise the entry point with `??` instead of a null ternary ([17e7ec1](17e7ec1)) * **td-42:** hold the coverage rule per converted file, not per block ([1c1bd58](1c1bd58)), closes [#2724](#2724) [#2723](#2723) [#2723](#2723) * **td-43:** keep `node:` on the import the autofix split in two ([0affee9](0affee9)) * **td-43:** make type-only imports explicit, repo-wide ([ddf66ac](ddf66ac)) * **td-44:** make the strict check fail closed when tsc does not run ([2059381](2059381)), closes [#2731](#2731) * **td-45:** count extensionless Node executables in the js ratchet ([f59a6a6](f59a6a6)), closes [#2719](#2719) [#2705](#2705) [#2732](#2732) * **td-46:** stop asserting an assignment to a stub the spec declared itself ([100f6e2](100f6e2)), closes [#2739](#2739) * **td-48:** assert that a stack trace never leaves the process ([f8b3b06](f8b3b06)) * **td-48:** keep the production node out of the cluster ([548bc48](548bc48)) * **td-49:** let the vitest tree load what reaches lib/api/controllers ([6c19eaa](6c19eaa)) * **td-50:** merge coverage as istanbul, not as V8 ranges ([6f095ed](6f095ed)), closes [#2744](#2744) * **td-55:** make waterfall ask the chain, not the value ([596a0f0](596a0f0)) * **td-56:** stop bindPluginMethod declaring a type it does not return ([818cb0d](818cb0d)), closes [#2757](#2757) * **td-57:** type vault's remembered key honestly, and test it ([4603d30](4603d30)) * **td-58:** count the messages that were actually lost ([910bc9a](910bc9a)), closes [#2715](#2715) * **td-58:** subtract message ids with Long, not with `-` ([a3091ec](a3091ec)) * **td-59:** give the cluster the id the process logs under ([191a4e7](191a4e7)), closes [#2757](#2757) * **td-59:** print both node ids when joining the cluster ([d7805c1](d7805c1)), closes [#2764](#2764) * **td-74:** the allowed-values statics are readonly ([643d70b](643d70b)) * **td-74:** users "out" and "none" no longer share a channel name ([324a6c4](324a6c4)) * **td-75:** the date type's specification has a type of its own ([53dec89](53dec89)) * **td-76:** declare PluginContext.constructors as constructors ([6d37959](6d37959)) * **td-77:** remove the two invalid_openapi_schema codes nothing raises ([c8cbc1d](c8cbc1d)) * **td-78:** the plugin hook and pipe types admit every form the runtime takes ([41c519e](41c519e)) * **td-79:** two config checker messages now say what they check ([f3fdc72](f3fdc72)) * **td-80:** give passport its `next`, and route every failure through one path ([9443c5b](9443c5b)) * **td-81:** release the dump lock on every path, and check arguments before taking it ([52932f0](52932f0)) * **test:** point cucumber's ts-node at the test program ([28828af](28828af)) * **tests:** close TD-70 — stop pinning the order of an unordered search ([c50751b](c50751b)), closes [#2783](#2783) * **ts-migration:** put the NOSONAR marker on the flagged line ([66449cb](66449cb)) * **ts-migration:** restore the receiver on dynamic cache-script calls ([f68aaf4](f68aaf4)) * **types:** authController — step 12, K5 ([7363d25](7363d25)) * **types:** configuration, controllers, generic events and repositories compile as against v2.56.0 (step 15, TY-04/07) ([afcb08d](afcb08d)) * **types:** declare accessors.execute's callback form as v2.56.0 did ([96f1fc8](96f1fc8)) * **types:** deprecate Token.connectionId, which no runtime token carries (ADR-0002, TD-07) ([4a04dc5](4a04dc5)) * **types:** ES7 storage service is strict-clean and adopted — step 12, K3 ([329692f](329692f)) * **types:** ES8 storage service is strict-clean and adopted — step 12, K3 ([9d80753](9d80753)) * **types:** export public types missing from the types barrel ([3dbb530](3dbb530)) * **types:** fix triple-l typo in adminController type filename ([e733094](e733094)) * **types:** funnel — step 12, K5 ([5a4cc05](5a4cc05)) * **types:** kerror — step 12, K5 ([1ee1d0a](1ee1d0a)) * **types:** let Error stringify a non-string KuzzleError message itself ([f611ac8](f611ac8)) * **types:** lib/core/network and the manifests — step 12, K5 ([d8d8826](d8d8826)) * **types:** lib/kuzzle — step 12, K5 ([1271750](1271750)) * **types:** make lib/api/request strict-clean — step 12, K2 ([a1eaab0](a1eaab0)) * **types:** make lib/kerror's error classes strict-clean — step 12, K1 ([7ebad7d](7ebad7d)) * **types:** make lib/types' small files and baseModel strict-clean — step 12, K1 ([1b9eea5](1b9eea5)) * **types:** make lib/util's small files strict-clean — step 12, K1 ([3978f0c](3978f0c)) * **types:** make nine lib/core files strict-clean — step 12, K1 ([cb1db7e](cb1db7e)) * **types:** make the last fifteen ≤ 5 files strict-clean — step 12, K1 ([2bbafeb](2bbafeb)) * **types:** memoryStorageController and the body assertion — step 12, K5 ([60a7dce](60a7dce)) * **types:** plugin context, accessors.execute and errors compile as against v2.56.0 (step 15, TY-01/02/05) ([0ad75fa](0ad75fa)) * **types:** plugin.ts, hotelClerk.ts and subscription.ts — step 12, K4 ([d37aeac](d37aeac)) * **types:** pluginContext, Backend and the debugger — step 12, K5 ([f778842](f778842)) * **types:** pluginsManager — step 12, K4 ([27e4c6a](27e4c6a)) * **types:** point Validation.validate JSDoc at KuzzleRequest ([d0484ab](d0484ab)) * **types:** queryTranslator and the redis adapter — step 12, K5 ([94469d7](94469d7)) * **types:** read the deprecated jwt section through one documented helper ([063fb76](063fb76)) * **types:** request getters, user and token read as against v2.56.0 (step 15, TY-03/06) ([fb4f550](fb4f550)), closes [#2801](#2801) [#2803](#2803) * **types:** split the three configuration shapes — step 12, K0 (TD-53) ([8b51997](8b51997)) * **types:** stop NativeController.constructor inferring never[] ([66e3ddc](66e3ddc)) * **types:** TD-62's model/security half and the repositories it moves into ([c07ad0f](c07ad0f)) * **types:** the cluster — step 12, K5 ([20ced7f](20ced7f)) * **types:** the last of lib/ — step 12, K5 ([aa5f4c2](aa5f4c2)) * **types:** the protocol stack — step 12, K4 ([1058067](1058067)) * **types:** the remaining controllers and documentExtractor — step 12, K5 ([3647a19](3647a19)) * **types:** the remaining declarations accept what v2.56.0's did (step 15, TY residuals) ([20f7a80](20f7a80)) * **types:** the token pair — step 12, K4 ([e7614a3](e7614a3)) * **types:** the two base classes and validation.ts — step 12, K4 (part 1) ([664d3e0](664d3e0)) * **util:** model Promback's settled value as `T | undefined` ([5f8e751](5f8e751)) * **validation:** a truthy non-boolean collection `strict` is strict again (step 15, F-09b) ([377c9f0](377c9f0)), closes [#2803](#2803) * **validation:** let plugin types provide BaseType members as getters or prototype values (step 15, F-09a) ([5eb24ba](5eb24ba)), closes [#2722](#2722) * **validation:** use ??= in the helper the move made new code ([02cfdfe](02cfdfe))
pull Bot
pushed a commit
to sorajate/kuzzle
that referenced
this pull request
Sep 30, 2026
koncorde 4.8.0-beta.1 → 4.8.0-beta.2, with boost-geospatial-index 1.5.0-beta.2 (kuzzleio/boost-geospatial-index#29, kuzzleio/koncorde#84). The geospatial index sometimes failed to remove a shape, whose id then kept matching without a subfilter behind it, and Koncorde#test threw "subfilters is not iterable". The notifier awaits that match on every document write (document:create → core:realtime:document:notify → notifyDocuments → _test), so the write request answered with an internal error after the document had been written, and no notification was sent. Reproduced on 2.56.0's koncorde 4.7.0: 2 000 geoDistance subscriptions, half removed, 5 000 documents → 62 throws on Node 22, 460 on Node 24. tests/util/koncordeCompat.test.ts runs that scenario through koncordeTest, the notifier's entry point. Co-Authored-By: Claude Opus 5.5 (1M context) <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.
Bug
After geospatial filters are unregistered,
Koncorde#testcan throwTypeError: subfilters is not iterable(testTables.addMatch, frommatchGeospatial). Reproduced on the published 4.7.0: 2 000geoDistancefilters, half removed, 5 000test()calls → 62 throws on Node 22, 460 on Node 24. In Kuzzle,test()runs on every document written to a collection with realtime subscriptions.Cause, in boost-geospatial-index: its R* tree sometimes failed to remove a shape, whose id then kept coming back from
queryPointwith no subfilter behind it. Fixed there — kuzzleio/boost-geospatial-index#29, published as 1.5.0-beta.2.What
boost-geospatial-index1.5.0-beta.1 → 1.5.0-beta.2test/keywords/geospatial.test.js: the seeded scenario above — no removed filter may match, andtest()must not throw. Fails on 1.5.0-beta.1 with theTypeError, passes on 1.5.0-beta.2.npm run test:lintclean,npm run test:unit423 passing locally. Merging publishes4.8.0-beta.2.🤖 Generated with Claude Code