[Bug] Enforce complete source index coverage and track safe fallback pushdown #3201
Description
Problem and split scope
The independent correction is now PR #3243, current head 7f5a9173, based directly on master 2f827d6e. It contains no #2994 history. Design, migration guidance, diagram and exact validation record are maintained in Gist.
This issue now tracks two separate changes. They must not be delivered by copying all of #2994 into a new PR.
A. Generic source-query integrity, independently on master. At master 2f827d6e8c9c62ae858f2fc122b3a192d015e2f4, two vertex labels declare the same property, but only one has a usable property index. g.V().has("coverageName", "same") returns only the indexed label's vertex. A Memory regression on that unmodified master returned one ID when the complete data set contained two. No negative-label predicate or #2994 code is needed to reproduce this defect.
B. Selective pushdown in #2994's local-filtering fallback. This depends on #2994 and on a sound runtime coverage check from A. #2994 at 23cb5f07 deliberately restores the existing source-query behavior across ordinary adjacency with its supported standard suffixes; it does not fix A. Its direct/barrier/complex-context fallback remains a separate execution path.
Query contract for A
For property-index queries with type-compatible values, the implementation follows the existing indexed-property query policy with an explicit completeness requirement:
| Coverage for labels capable of satisfying the source predicates | Result |
|---|---|
| Every candidate label has compatible usable indexes | Return the complete indexed result |
| Some candidate labels lack compatible indexes | Raise NoIndexException; do not return only indexed labels |
| No compatible index exists | Retain the existing NoIndexException behavior |
This does not introduce automatic full scans for ordinary property queries. An explicit positive source label narrows the required coverage. Labels that cannot contain all required properties or are hidden by the outer query's visibility are not candidates. Normal queries exclude hidden, DELETING and UNDELETED labels; internal queries exposing them still require their coverage. Empty visible labels remain candidates. Explicit-ID and bounded adjacency lookups retain their existing paths. A schema's label-index flag is distinct from property-index coverage. Base-edge indexes may cover their sub-labels; fully covered sub-labels do not need an additional base index. Shared OLAP properties retain their cross-label treatment. A type-incompatible value can return an empty result after an index matches, before checking partial coverage; no matching index retains the index error. Complete labeled PRIMARY_KEY lookups retain their direct-ID path.
This is a user-visible compatibility correction. Existing queries that intentionally target one label should specify it; genuinely cross-label queries need compatible indexes for every candidate label. Merely creating a schema index with an incompatible predicate type is insufficient.
Acceptance: A, standalone master PR
- Reproduce an incomplete result on unmodified master and distinguish it from fix(server): clarify condition resolution semantics for label queries #2994's fallback behavior.
- Cover global vertex and edge sources, complete/partial/no coverage, explicit-label and explicit-ID controls, and downstream count/range/adjacency/child contexts.
- Use the actual single/composite/joint index matcher for equality, range and SEARCH compatibility; test base/sub-edge coverage and unrelated schema labels.
- Re-evaluate coverage at execution, including prepared traversals after schema changes and resumed pages after index removal. Exercise creation, rebuild and deletion statuses without caching an optimizer-time proof.
- Preserve resource limits and cursor behavior. State the stable-schema execution boundary explicitly; do not claim snapshot consistency across concurrent DDL or changing schema during a paging session.
- Respect outer-request label visibility before matching/validating foreground indexes. Cover vertex, edge and sub-label deletion after index removal,
UNDELETED, explicitshowDeleting, inherited origin flags, restoration/reindexing and paging with hidden labels. - Keep asynchronous stale-index cleanup independent of foreground-query coverage requirements.
- Run affected full core suites and query/cache checks, plus RocksDB/HStore comparisons with recorded source/build versions. Report skips and any untested distributed scenarios.
- Publish the independent PR with a migration note and validation evidence in Gist; link it here without closing the dependent work below.
Latest validation at 7f5a9173: the coverage class passed on Memory (22 run, 3 skipped) and RocksDB (22 run, no skips); complete RocksDB vertex/edge/coverage classes passed (460 run, 29 skipped). All had zero failures/errors. The actual Example1 cleanup ran with Java assertions enabled, and Java 17 compiled all 38 modules. Temporary integration with #2994 23cb5f07 passed 79 unique targeted RocksDB cases. HStore and full TinkerPop suites were not manually rerun at these heads; the test-* CI branch was updated without waiting for results.
Historical validation is bounded: the full Memory Core suite was not green (five Task-only failures/errors); four failures reproduced on unchanged master, while all 17 Task cases passed in the isolated patched run. The query-focused RocksDB, HStore and unit checks passed. HStore's standalone class used an external same-JVM transport-readiness suite after two plain runs encountered startup timeouts. The failed attempts, exact counts and harness are recorded in Gist; no query assertion or production timeout was weakened.
Acceptance: B, dependent fallback optimization
The compatibility-only integration checks and reproducible patch are recorded in the linked Gist. They keep #2994's fallback plan unchanged; selective pushdown itself is not implemented by #3243 or by the integration branch.
- Verify A + fix(server): clarify condition resolution semantics for label queries #2994 in a temporary integration branch before claiming compatibility. Keep this integration history out of the standalone master PR.
- Preserve complete local fallback for partial or unavailable coverage, and resume index pushdown only with complete predicate-compatible coverage at execution.
- Prove the lifecycle of any coverage decision across schema/index changes, cloning, serialization, graph rebinding and lazy iteration. Keep speculative indexed and fallback query state separate, including origin/context flags. Close rejected iterators and do not restart after returning a result prefix.
- Preserve traversal context, barriers, offset/limit ordering, count, side effects and SEARCH analyzer semantics. Do not infer element provenance solely from a step's output type.
- Keep paging plans/cursors stable, including empty filtered pages; explicitly bound any initially unsupported optimization shapes.
- Add plan/path assertions and identical-data measurements for covered and partially covered labels on RocksDB and HStore. Separate measured gains from expectations.
The issue remains open until the two tracks' acceptance conditions are met. #3196's CONTAINS conversion cache and coverage-report collection changes remain outside this issue. Explanatory documents and diagrams belong in Gist and are linked from the PRs, not committed into the code repository or linked through a contributor fork.
Activity
github-actions commentedon Sep 25, 2026
Due to the lack of activity, the current issue is marked as stale and will be closed after 20 days, any update will remove the stale label
[-][Improve] Restore selective property pushdown with complete label index coverage[/-][+][Bug] Enforce complete source index coverage and track safe fallback pushdown[/+]