Skip to content

feat!: add time-range indexes for trending/leaderboard queries - #3740

Merged
QuantumExplorer merged 20 commits into
v4.2-devfrom
time-range-indexes
Aug 26, 2026
Merged

feat!: add time-range indexes for trending/leaderboard queries#3740
QuantumExplorer merged 20 commits into
v4.2-devfrom
time-range-indexes

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented May 25, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

"Trending" / leaderboard queries — e.g. top hashtags by document count within the most recent time window — are not servable today: there is no index shape that groups documents by a time window, so a client cannot get a provable answer to "what happened in the last N hours".

This PR adds time-range indexes: a contract can declare a timeRange: {on, range, step, phase?} transform on an index, which buckets a timestamp property (e.g. $createdAt) into fixed-length, regularly-spaced, optionally overlapping windows (phase is a pure alignment offset, validated < step and < one year — the cap keeps the region before the grid's first bucket inside 1970–1971, so no consensus-validated timestamp can ever fall outside every window). Each grid gets its own index subtree — the storage level is keyed by the property name qualified with the grid ($createdAt#21600#7200) — so several grids may bucket the same timestamp side by side (e.g. a 3-hourly and a daily leaderboard over one $createdAt). A document is indexed under every bucket whose window contains its timestamp, per grid, and a new v1 IN_TIME_RANGE where-operator ("newest" / "oldest", plus a structured [selector, range, step(, phase)] operand naming a grid on multi-grid fields) selects a bucket from authoritative block time — making windowed count/sum/avg and document queries provable.

This branch is a from-scratch rebuild of the original implementation on top of v4.2-dev, fixing all review blockers (nullable-timestamp update handling, out-of-grid bucket semantics, aggregate proof verification, stale generated clients) plus the defects found in a full re-review.

What was done?

  • Units: the window parameters (range, step, phase) are declared in seconds. The finest meaningful granularity is a block — the target interval is 5s (block_spacing_ms: 5000) and IN_TIME_RANGE resolves its bucket from the committed block time — so millisecond parameters would be false precision (and made a 6-hour window read as 21600000). Bucket starts, index keys, and anything compared against a document's timestamp stay in milliseconds, since the source fields are millisecond timestamps; the transform converts at its range_ms() / step_ms() / phase_ms() accessors, and contract validation rejects parameters too large to scale.
  • Phase, not origin: the alignment parameter is a phase offset within one step (phase < step, larger values rejected as redundant spellings of phase % step), so the grid covers all of time — bucket starts are phase + k·step. There is no "beginning of time": since block time only moves forward, a past anchor could never exclude anything, and the scheduled-start use case wasn't worth the extra edge semantics. Only the sub-step sliver at the epoch sits outside every window, kept as a defensive rule (no entries, resolution refuses) that no real timestamp can reach.
  • Grid-qualified storage levels: a transformed first property's index level is keyed {name}#{range}#{step} (#{phase} appended iff non-zero — zero is spelled by omission everywhere: grammar, storage key, wire), single-sourced in TimeRangeTransform::storage_key and consumed via Index::level_key{,_for_property} by contract setup, the document walkers (through IndexLevel, whose levels now fork per grid), query path derivation, the uniqueness probe and proof verification. # can never appear in a schema property name, so qualified keys can't collide with plain levels; different grids fork into sibling subtrees (every 6h start is also a 3h start — unqualified, two grids' entries would interleave in one keyspace), and identical grids still share a level. This is what deletes the old "all indices sharing a first property must agree on the transform" restriction.
  • rs-dpp: TimeRangeTransform on Index/IndexLevel; meta-schema-v3 grammar + parsing; validation (range % step == 0, a versioned overlap-factor cap — SystemLimits::max_time_range_overlap_factor, 24 at PV14, i.e. a day-long window sliding hourly — enforced at registration since the factor is the index's per-document write amplification, transform source must be the index's first property and a required system timestamp — no user property type parses to a millisecond timestamp, so user-defined sources are rejected; non-contested/null-searchable/non-ranked; phase < step); update-immutability; bucket math (containing_buckets, newest_active_start/oldest_active_start).
  • Unique time-range indexes for non-overlapping windows: unique: true is allowed when range == step and the source is $createdAt — "at most one document per window per remaining key tuple" (e.g. one report per author per day). The uniqueness probe rewrites the source equality to the containing bucket start (carrying resolved provenance so index pinning admits the bucketed index), epoch-sliver timestamps skip the check, and the update walker handles both terminator layouts. Overlapping windows stay incompatible with uniqueness; mutable sources ($updatedAt/$transferredAt) are rejected because $createdAt's immutability is what keeps the validator's changed-tuple reasoning sound.
  • rs-drive: insert/delete/update index fan-out — one document → N overlapping bucket entries per grid (PV14 walkers: insert/delete v2, update v1); null timestamps keep a single ordinary null entry across insert, delete, and the update set-diff.
  • dapi-grpc: new v1 IN_TIME_RANGE where operator (v0 wire unchanged); regenerated JS/web/Obj-C/Python clients. The structured grid operand rides the existing DocumentFieldValue.ValueList — no message changes.
  • drive-abci: v1 getDocuments handler resolves IN_TIME_RANGE into a concrete bucket-start equality from committed block time; the bare selector on a multi-grid field is refused as ambiguous, a grid spec no index declares is refused, and an explicit zero phase on the wire is refused as a second spelling.
  • rs-sdk / wasm-sdk: with_time_range / with_time_range_grid / timeRange query builders; proof verification (documents AND count/sum/avg aggregates) re-derives the same bucket from the quorum-signed response metadata time.
  • Provenance-pinned index selection: the resolved clause is an ordinary equality, indistinguishable from a hand-written raw-timestamp lookup, so resolution records the field and the exact grid in resolved_time_ranges (ResolvedTimeRange; never parsed from the wire; DriveDocumentQuery + the aggregate request structs). One shared rule (index_admissible_for_resolved_time_range) filters index candidates everywhere — find_best_index (via new DocumentTypeV0Methods::index_for_types_matching) and the count/sum pickers admit a bucketed index only for a query that resolved exactly its grid, never for a raw query, and never for another grid's resolution (grids can share bucket-start values, so a field name alone wouldn't pin the tree); ranked indexes exclude transforms outright; two resolved fields are rejected. Without this, index selection was decided by index name order and could silently match bucket starts against raw timestamps (or vice versa), and aggregates could multi-count a document once per overlapping bucket — all with valid proofs, since the verifier re-runs the same selection.

Gating: part of the meta-schema-v3 grammar (protocol version 14) — the timeRange keyword is admitted by parser generation 3 only, and the storage fan-out lives in the PV14 walkers.

How Has This Been Tested?

  • New e2e tests in rs-drive (add_document_for_contract time-range module): bucket fan-out on insert/update/delete, update set-diff including null transitions, index-selection pinning (resolved query → bucketed index, raw query → plain index, both with asserted result sets), two-resolved-fields rejection, order-by steering rejection, raw-query-on-bucketed-only-index rejection.
  • New picker tests in drive_document_count_query/tests.rs: bucketed index admitted only with resolved provenance; raw IN/equality on the source refused.
  • Unit tests across rs-dpp for transform parsing/validation/bucket math; drive-abci v1 routing tests for IN_TIME_RANGE partitioning.
  • Uniqueness e2e: same-window collision via the bucket probe (fails if the probe compared raw timestamps), next-window acceptance, same-window different-suffix acceptance, self-update allow_original, epoch-sliver skip on a phased grid, and an update-path suffix move under the unique layout with a hard assertion the vacated slot is reusable.
  • Multi-grid coverage: a two-grid (6h/2h + 24h/24h) contract fans one document into each grid's own subtree and stays isolated on a bucket start that is the same number on both grids (a collapsed keyspace could not answer both counts); deletes empty both; the resolver refuses the bare selector as ambiguous, honors an exact grid spec, and refuses an undeclared one; wire-level tests prove each grid independently through the SDK FromProof entry points with the structured operand (counts 2 vs 3 by construction).
  • Phase validation: phase parses, phase >= step rejected, the removed origin key rejected as unknown; storage keys pinned ($createdAt#21600#7200, #3600 appended for a phased grid, distinct across grids).
  • Proof-level regression coverage for the time-range reconstruction sequence (resolve from signed metadata time → provenance/shape guard → transformed-index selection → GroveDB path verification): in rs-drive-abci v1 tests, real prove→verify round trips over an overlapping-window (factor 3) bucketed index — a COUNT that must count each document once despite it being stored under three bucket keys (the fixture's plain index deliberately sorts first, so index selection is proven to come from provenance rather than name order), a documents-route proof, and a tampered-time_ms case asserting a hard verification failure rather than a silently different count. In rs-sdk, offline tests pin resolution order and that the bucket derives from the signed metadata time (one step later ⇒ next bucket; epoch-sliver ⇒ refusal).
  • Full runs: cargo test -p dpp (3945), cargo test -p drive (3589), cargo test -p dash-sdk (327), cargo test -p dash-platform-queries (34), cargo test -p drive-abci document_query (105); cargo check --workspace --all-targets and cargo clippy --workspace --all-targets clean.

Breaking Changes

  • Consensus (protocol version 14): the v3 document meta-schema admits the timeRange index keyword and its validation rules (source restrictions, uniqueness rules, ranked exclusion), and the PV14 storage walkers fan documents into bucket entries. Existing protocol versions are unchanged, and the v0 query wire is untouched; the v1 wire gains the IN_TIME_RANGE operator (additive).
  • Rust API: Index::try_from_value_map gains a third required parameter (time_range_allowed); public structs gain required fields (Index::time_range, DriveDocumentQuery::resolved_time_ranges, DocumentQuery::time_range_clauses, resolved_time_ranges on the count/sum/average/ranked request structs), breaking downstream struct literals and exhaustive matches; the count/sum index pickers and resolve_time_range_bucket_clause have changed signatures.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

@QuantumExplorer
QuantumExplorer requested a review from shumkov as a code owner May 25, 2026 17:49
@github-actions github-actions Bot added this to the v3.1.0 milestone May 25, 2026
@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Time-range indexes define timestamp buckets, store documents under overlapping buckets, resolve v1 selectors with block time, and re-resolve selectors during proof verification with signed metadata time. SDK and WASM query APIs expose the feature.

Changes

Time-Range Index Feature

Layer / File(s) Summary
Protocol and contract validation
packages/dapi-grpc/..., packages/rs-dpp/...
Adds IN_TIME_RANGE, the v3 timeRange schema, transform calculations, parser gates, source validation, overlap checks, and immutable index configuration.
Bucket storage and document updates
packages/rs-drive/src/drive/document/...
Generates bucket keys during insertion, deletion, and timestamp updates.
Drive query resolution and index selection
packages/rs-drive-abci/src/query/..., packages/rs-drive/src/query/...
Resolves selectors with committed block time, tracks provenance, validates clause shapes, and filters incompatible indexes.
SDK, WASM, and proof verification
packages/rs-sdk/..., packages/wasm-sdk/..., packages/wasm-drive-verify/...
Adds query inputs and v1 encoding. Proof verification resolves selectors with signed metadata time.
Regression coverage and compatibility updates
packages/rs-drive/src/.../tests.rs, packages/rs-drive-abci/..., packages/rs-platform-wallet/...
Updates query fixtures and tests for bucket fan-out, updates, deletion, index selection, and propagated query state.

Estimated code review effort: 5 (Critical) | ~120 minutes

Mergeability Score: 🟡 Moderate · up to 3d356

A multi-IN query with ordering can bypass time-range source validation and select a bucketed index, risking incorrect document results or aggregates; this path should apply the same provenance guard before the PR merges.

Possibly related PRs

Suggested reviewers: shumkov, lklimek, llbartekll, zocolini

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding time-range indexes for trending and leaderboard queries.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch time-range-indexes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented May 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.33858% with 1542 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.47%. Comparing base (bea4122) to head (1cb58ee).
⚠️ Report is 16 commits behind head on v4.2-dev.

Files with missing lines Patch % Lines
...s-dpp/src/data_contract/document_type/index/mod.rs 60.70% 325 Missing ⚠️
...h-platform-queries/src/documents/document_query.rs 33.62% 227 Missing ⚠️
packages/rs-drive/src/query/mod.rs 62.21% 150 Missing ⚠️
.../update_document_for_contract_operations/v1/mod.rs 72.06% 88 Missing ⚠️
...ve-abci/src/query/document_query/v1/conversions.rs 36.11% 69 Missing ⚠️
...s/rs-drive-abci/src/query/document_query/v1/mod.rs 59.42% 56 Missing ⚠️
packages/rs-drive/src/query/canonicalize.rs 32.46% 52 Missing ⚠️
...t_type/class_methods/try_from_schema/common/mod.rs 54.63% 44 Missing ⚠️
...query/drive_document_having_query/execute_range.rs 53.84% 42 Missing ⚠️
...query/drive_document_ranked_query/execute_top_k.rs 52.80% 42 Missing ⚠️
... and 55 more
Additional details and impacted files
@@             Coverage Diff              @@
##           v4.2-dev    #3740      +/-   ##
============================================
- Coverage     87.39%   84.47%   -2.93%     
============================================
  Files          2735     2751      +16     
  Lines        347804   363442   +15638     
============================================
+ Hits         303979   307007    +3028     
- Misses        43825    56435   +12610     
Components Coverage Δ
dpp 86.85% <77.51%> (-2.12%) ⬇️
drive 83.18% <78.60%> (-3.15%) ⬇️
drive-abci 86.07% <70.56%> (-3.66%) ⬇️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.92% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 48.53% <ø> (+1.12%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/rs-dpp/src/data_contract/document_type/index/time_range.rs`:
- Around line 85-97: The method containing_buckets currently uses
most_recent_start which saturates to origin_ms, causing t < origin_ms to
incorrectly return origin_ms; to fix, add an early check at the start of
containing_buckets: if t < self.origin_ms return an empty Vec, then proceed as
before (using overlap_factor, most_recent_start, step_ms) so only timestamps >=
origin_ms are considered for bucket computation; reference functions/fields:
containing_buckets, most_recent_start, origin_ms, overlap_factor, step_ms,
range_ms.

In `@packages/rs-drive-abci/src/query/document_query/v1/mod.rs`:
- Around line 468-536: The test helper validate_and_route_for_tests() no longer
mirrors query_documents_v1() because it decodes proto where-clauses without
stripping/resolving IN_TIME_RANGE clauses; update validate_and_route_for_tests()
to partition proto_where_clauses with conversions::is_time_range_clause, decode
normal_proto via conversions::where_clauses_from_proto into where_clauses, and
then handle time_range_proto the same way as query_documents_v1(): obtain
block_time_ms from platform_state.last_committed_block_time_ms(), resolve
contract_id and contract_fetch_info, get doc_type, and for each proto_wc call
conversions::time_range_clause_from_proto and
drive::query::resolve_time_range_bucket_clause to push resolved clauses into
where_clauses (or extract this shared logic into a helper used by both
query_documents_v1() and validate_and_route_for_tests()).

In
`@packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs`:
- Around line 775-806: The current encode_buckets closure maps None to an empty
Vec, losing the single empty-index-key convention used by insert/delete paths;
change the logic so that when the raw decoded timestamp is None (or the raw
encoded bytes represent an empty key) encode_buckets returns a Vec containing
one empty Vec (i.e., vec![vec![]]) so old_buckets/new_buckets preserve the
empty-key; update the use sites around get_raw_for_document_type,
DocumentPropertyType::decode_date_timestamp, transform.containing_buckets and
DocumentPropertyType::encode_date_timestamp accordingly and add a regression
test covering null ↔ non-null updates to ensure delete/insert of the empty-key
behaves correctly.

In `@packages/rs-drive/src/query/mod.rs`:
- Around line 539-571: resolve_time_range_bucket_clause currently returns only a
synthetic WhereClause (field == bucket_start) which loses the fact that this
came from a time-range index; change it to return the matched index/transform as
well (e.g. return a tuple or new struct like (WhereClause, IndexRef) or
(WhereClause, TimeRangeTransform)) so downstream index pickers can see the
original time-range index and avoid choosing a non-time-range index;
specifically, in resolve_time_range_bucket_clause locate the matched
index/transform (the variable transform found via
DocumentTypeRef::indexes().values().find_map), include that transform or the
index identifier in the function return value, and update all callers to accept
and thread that hint into the query planner so index selection uses the provided
time-range index rather than falling back to coverage-based selection.

In `@packages/rs-sdk/src/platform/documents/document_query.rs`:
- Around line 77-84: The conversion impl TryFrom<&DocumentQuery> for
DriveDocumentQuery currently ignores DocumentQuery::time_range_clauses; update
the impl(s) that build DriveDocumentQuery from a DocumentQuery (the
TryFrom<&DocumentQuery> for DriveDocumentQuery and the analogous conversion used
elsewhere) to detect non-empty time_range_clauses and return an Err immediately
instead of silently dropping them. Specifically, check
DocumentQuery::time_range_clauses at the start of the conversion, and if not
empty return a clear error (e.g., UnsupportedTimeRangeInDriveQuery) referencing
that the caller must use Self::with_time_range or a block-time-aware conversion
path; do this for every conversion path that currently only uses where_clauses
so the time-range filters are not lost.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0585dcb0-39b1-41af-af09-9ff3e81814c8

📥 Commits

Reviewing files that changed from the base of the PR and between 31e8af2 and 7425185.

📒 Files selected for processing (23)
  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/rs-dpp/schema/meta_schemas/document/v1/document-meta.json
  • packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v1/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/index/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/index/random_index.rs
  • packages/rs-dpp/src/data_contract/document_type/index/time_range.rs
  • packages/rs-dpp/src/data_contract/document_type/index_level/find_first_change.rs
  • packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs
  • packages/rs-drive-abci/src/query/document_query/v1/conversions.rs
  • packages/rs-drive-abci/src/query/document_query/v1/mod.rs
  • packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v1/mod.rs
  • packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs
  • packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v1/mod.rs
  • packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs
  • packages/rs-drive/src/query/drive_document_count_query/tests.rs
  • packages/rs-drive/src/query/drive_document_sum_query/tests.rs
  • packages/rs-drive/src/query/mod.rs
  • packages/rs-sdk/src/platform/dashpay/contact_request_queries.rs
  • packages/rs-sdk/src/platform/documents/document_query.rs
  • packages/rs-sdk/src/platform/dpns_usernames/mod.rs
  • packages/rs-sdk/src/platform/dpns_usernames/queries.rs
  • packages/wasm-sdk/src/dpns.rs
  • packages/wasm-sdk/src/queries/document.rs

Comment thread packages/rs-dpp/src/data_contract/document_type/index/time_range.rs
Comment thread packages/rs-drive-abci/src/query/document_query/v1/mod.rs Outdated
Comment thread packages/rs-drive/src/query/mod.rs
Comment thread packages/dash-platform-queries/src/documents/document_query.rs Outdated

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

I verified the reported issues against the checked-out SHA and confirmed four blocking problems. The time-range indexing and proof-verification changes are not internally consistent yet, and the protobuf wire addition was not propagated into the shipped generated platform clients.

🔴 4 blocking

4 finding(s)

blocking: Time-range updates drop null-key index entries instead of preserving the existing layout

packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v0/mod.rs (line 795)

update_time_range_index_for_contract_operations_v0() turns a missing/undecodable source timestamp into Vec::new() for both new_buckets and old_buckets. That is inconsistent with the insert and delete implementations, which explicitly keep a single ordinary key when the first indexed timestamp is null (None => vec![document_top_field.clone()] in add_indices_for_top_index_level_for_contract_operations_v1 and remove_indices_for_top_index_level_for_contract_operations_v1). Because the caller always routes time-range indexes into this helper, updates from null -> value, value -> null, or null -> null with later suffix changes skip the delete/reinsert work needed to maintain that null entry. The result is stale index state for valid documents with nullable timestamp fields.

blocking: Pre-origin timestamps are assigned to buckets that do not contain them

packages/rs-dpp/src/data_contract/document_type/index/time_range.rs (line 68)

most_recent_start() saturates t < origin_ms to origin_ms, and containing_buckets() then emits that start as long as it is >= origin_ms. For any contract with a nonzero origin_ms, a document timestamp earlier than the origin is therefore indexed into the origin_ms bucket even though the documented bucket interval is [start, start + range_ms) and does not contain that timestamp. The same saturation also makes newest_active_start() and oldest_active_start() report an active bucket before any range has actually started. Contract validation does not reject nonzero origins, so this is a reachable correctness bug for valid contracts.

blocking: Aggregate proof verification never resolves time-range selectors before mode and index selection

packages/rs-sdk/src/platform/documents/count_proof_helpers.rs (line 140)

verify_count_query() reads request.where_clauses directly when it computes the count mode and picks the covering index, but DocumentQuery::with_time_range() stores its selector in request.time_range_clauses until verification time. The document proof path already resolves those selectors into concrete equality clauses using the quorum-signed metadata time before rebuilding the drive query, but this helper does not do that, and the same omission is duplicated in sum_proof_helpers.rs and average_proof_helpers.rs. As a result, aggregate COUNT/SUM/AVG proof verification for with_time_range(...) queries is rebuilt from a different query shape than the prover used, so valid proofs can be rejected or verified against the wrong path/query layout.

blocking: The new `IN_TIME_RANGE` enum value was not regenerated into shipped platform clients

packages/dapi-grpc/protos/platform/v0/platform.proto (line 601)

The proto adds IN_TIME_RANGE = 11, and the Rust SDK/server code already uses it, but the checked-in generated platform clients still stop at STARTS_WITH = 10. This is visible in packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js:19601-19614, packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js:24583-24595, packages/dapi-grpc/clients/platform/v0/web/platform_pb.js:24583-24594, and packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h:381-393. packages/dapi-grpc/node.js exports those generated bindings, so consumers of the published JS/web/Objective-C platform clients cannot construct or recognize the new enum through the typed API at this SHA.

Inline posting hit GitHub HTTP 422, so I posted the same verified findings as a top-level review body.

@thephez thephez added the dapi-endpoint DAPI endpoint addition or modification label May 26, 2026
@QuantumExplorer QuantumExplorer modified the milestones: v4.0.0, v4.1.0 Jun 1, 2026
@thepastaclaw

thepastaclaw commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

🔍 Review in progress — actively reviewing now (commit 1cb58ee)
Stage: Codex precheck starting
ETA: complete ~21:02 UTC (median 17m across 30 recent reviews)
Running 4m · Last checked: 2026-08-26 20:50 UTC

@shumkov
shumkov changed the base branch from v4.0-dev to v4.1-dev July 2, 2026 08:12
@shumkov
shumkov requested a review from lklimek as a code owner July 2, 2026 08:12
@QuantumExplorer
QuantumExplorer changed the base branch from v4.1-dev to v4.2-dev July 24, 2026 20:09
@github-actions github-actions Bot modified the milestones: v4.1.0, v4.2.0 Jul 24, 2026
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
packages/rs-drive/src/query/drive_document_sum_query/tests.rs (1)

34-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add picker tests for bucketed-index admission.

The updated tests only cover time_range: None with an empty resolved-field list. Add cases that verify raw queries reject bucketed indexes, matching resolved fields accept the matching bucketed index, and mismatched resolved fields reject it. Cover both point-lookup and range pickers.

Also applies to: 103-253

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/rs-drive/src/query/drive_document_sum_query/tests.rs` around lines
34 - 68, Extend the picker tests around the existing point-lookup and range
picker cases to cover bucketed indexes with a non-empty time_range. Verify raw
queries reject them, matching resolved fields select the corresponding bucketed
index, and mismatched resolved fields reject it. Apply these scenarios to both
picker types while preserving the existing unbucketed coverage.
packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs (1)

1029-1061: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate rule with IndexLevel::try_from_indices_v0; confirm the intended error surface.

This block enforces the same first-property agreement rule that IndexLevel::try_from_indices_v0 now enforces in index_level/mod.rs (lines 291-316). Under full_validation this block runs first, so the caller sees DataContractError::InvalidContractStructure through consensus_or_protocol_data_contract_error. Without full_validation only the IndexLevel check runs and returns ProtocolError::DataContractError. Two copies of one consensus-relevant rule can drift apart. Consider keeping only the IndexLevel check, or extract one shared helper both call.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs`
around lines 1029 - 1061, The first-property timeRange agreement rule is
duplicated between the validation block and IndexLevel::try_from_indices_v0,
producing different error surfaces depending on full_validation. Remove the
duplicate block from the surrounding schema conversion flow and rely on
IndexLevel::try_from_indices_v0 as the single enforcement point, or extract a
shared helper used by both paths while preserving consistent validation and
error behavior.
packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v1/mod.rs (1)

789-806: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider asserting the non-unique invariant this method depends on.

The doc comment at lines 783-784 states that time-range indexes are validated to be non-unique and non-contested, so lines 1013-1029 write only the non-unique terminator layout …/<value>/[0]/<doc_id>. The dispatch at line 343 does not re-check index.unique. Contract validation lives in the Protocol, Schema, and Contract Validation layer, so the invariant holds today. A debug_assert! documents the dependency in code and fails fast in tests if that validation ever changes.

♻️ Proposed guard
     ) -> Result<(), Error> {
         let drive_version = &platform_version.drive;
+        // Time-range indexes are validated non-unique upstream; this method
+        // only writes the non-unique terminator layout below.
+        debug_assert!(
+            !index.unique,
+            "time-range index '{}' must be non-unique",
+            index.name
+        );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v1/mod.rs`
around lines 789 - 806, Add a debug_assert! at the start of
update_time_range_index_for_contract_operations_v1 to verify that index.unique
is false, documenting the non-unique invariant this method relies on while
leaving production behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/rs-dpp/src/data_contract/document_type/index/mod.rs`:
- Around line 1337-1414: Update Index::try_from_value_map to reject timeRange
indexes when ranked indexing flags are enabled, using the existing ranked-flag
validation pattern and returning InvalidContractStructure. Place the check in
the time_range validation block and preserve support for non-ranked timeRange
indexes; do not add bucket-aware query behavior.

In
`@packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v1/mod.rs`:
- Around line 1040-1043: Update the inline comment in the old-entry deletion
loop near the `entry_key` check to point to the insert/refresh loop above,
replacing the incorrect “refreshed below” direction. Do not change the skip
condition or loop ordering.

In
`@packages/rs-drive/src/query/drive_document_sum_query/executors/per_in_value.rs`:
- Line 32: Validate resolved_time_range_fields before iterating in the executor
handling the raw In clause, and reject the request when it contains
in_clause.field. Ensure IN_TIME_RANGE resolution only proceeds when it can
produce an Equal clause, preventing the unchanged provenance from enabling
bucketed index selection for client-supplied In queries.

---

Nitpick comments:
In
`@packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs`:
- Around line 1029-1061: The first-property timeRange agreement rule is
duplicated between the validation block and IndexLevel::try_from_indices_v0,
producing different error surfaces depending on full_validation. Remove the
duplicate block from the surrounding schema conversion flow and rely on
IndexLevel::try_from_indices_v0 as the single enforcement point, or extract a
shared helper used by both paths while preserving consistent validation and
error behavior.

In
`@packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v1/mod.rs`:
- Around line 789-806: Add a debug_assert! at the start of
update_time_range_index_for_contract_operations_v1 to verify that index.unique
is false, documenting the non-unique invariant this method relies on while
leaving production behavior unchanged.

In `@packages/rs-drive/src/query/drive_document_sum_query/tests.rs`:
- Around line 34-68: Extend the picker tests around the existing point-lookup
and range picker cases to cover bucketed indexes with a non-empty time_range.
Verify raw queries reject them, matching resolved fields select the
corresponding bucketed index, and mismatched resolved fields reject it. Apply
these scenarios to both picker types while preserving the existing unbucketed
coverage.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ea65bbf-2d89-4e66-a5d6-9e76f7ce7f09

📥 Commits

Reviewing files that changed from the base of the PR and between 806890c and de4599d.

📒 Files selected for processing (99)
  • packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m
  • packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/rs-dpp/schema/meta_schemas/document/v3/document-meta.json
  • packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v1/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v3/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/index/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/index/random_index.rs
  • packages/rs-dpp/src/data_contract/document_type/index/time_range.rs
  • packages/rs-dpp/src/data_contract/document_type/index_level/find_first_change.rs
  • packages/rs-dpp/src/data_contract/document_type/index_level/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/methods/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/methods/versioned_methods.rs
  • packages/rs-dpp/src/data_contract/methods/registration_cost/v1/mod.rs
  • packages/rs-drive-abci/src/execution/platform_events/fee_pool_outwards_distribution/fetch_reward_shares_list_for_masternode/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v1/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v1/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_documents.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/dpns.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs
  • packages/rs-drive-abci/src/query/document_query/v0/mod.rs
  • packages/rs-drive-abci/src/query/document_query/v1/conversions.rs
  • packages/rs-drive-abci/src/query/document_query/v1/mod.rs
  • packages/rs-drive-proof-verifier/tests/vectors_documents.rs
  • packages/rs-drive/benches/document_count_worst_case.rs
  • packages/rs-drive/benches/document_sum_worst_case.rs
  • packages/rs-drive/src/drive/contract/insert/insert_contract/v0/tests/range_countable_index_e2e_tests.rs
  • packages/rs-drive/src/drive/contract/insert/insert_contract/v0/tests/ranked_index_e2e_tests.rs
  • packages/rs-drive/src/drive/document/delete/remove_indices_for_top_index_level_for_contract_operations/v2/mod.rs
  • packages/rs-drive/src/drive/document/index_level_tree_types.rs
  • packages/rs-drive/src/drive/document/index_uniqueness/internal/validate_uniqueness_of_data/v0/mod.rs
  • packages/rs-drive/src/drive/document/index_uniqueness/internal/validate_uniqueness_of_data/v1/mod.rs
  • packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs
  • packages/rs-drive/src/drive/document/insert/add_indices_for_top_index_level_for_contract_operations/v2/mod.rs
  • packages/rs-drive/src/drive/document/update/internal/update_document_for_contract_operations/v1/mod.rs
  • packages/rs-drive/src/drive/document/update/mod.rs
  • packages/rs-drive/src/drive/identity/withdrawals/document/fetch_oldest_withdrawal_documents_by_status/v0/mod.rs
  • packages/rs-drive/src/drive/identity/withdrawals/document/find_withdrawal_documents_by_status_and_transaction_indices/v0/mod.rs
  • packages/rs-drive/src/query/drive_document_average_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/drive_document_average_query/mod.rs
  • packages/rs-drive/src/query/drive_document_count_and_sum_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/drive_document_count_and_sum_query/executors/per_in_value.rs
  • packages/rs-drive/src/query/drive_document_count_and_sum_query/executors/range_no_proof.rs
  • packages/rs-drive/src/query/drive_document_count_and_sum_query/executors/total.rs
  • packages/rs-drive/src/query/drive_document_count_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/drive_document_count_query/executors/per_in_value.rs
  • packages/rs-drive/src/query/drive_document_count_query/executors/point_lookup_proof.rs
  • packages/rs-drive/src/query/drive_document_count_query/executors/range_aggregate_carrier_proof.rs
  • packages/rs-drive/src/query/drive_document_count_query/executors/range_distinct_proof.rs
  • packages/rs-drive/src/query/drive_document_count_query/executors/range_no_proof.rs
  • packages/rs-drive/src/query/drive_document_count_query/executors/range_proof.rs
  • packages/rs-drive/src/query/drive_document_count_query/executors/total.rs
  • packages/rs-drive/src/query/drive_document_count_query/index_picker.rs
  • packages/rs-drive/src/query/drive_document_count_query/tests.rs
  • packages/rs-drive/src/query/drive_document_ranked_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/drive_document_ranked_query/index_picker.rs
  • packages/rs-drive/src/query/drive_document_ranked_query/tests.rs
  • packages/rs-drive/src/query/drive_document_sum_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/drive_document_sum_query/executors/per_in_value.rs
  • packages/rs-drive/src/query/drive_document_sum_query/executors/point_lookup_proof.rs
  • packages/rs-drive/src/query/drive_document_sum_query/executors/range_aggregate_carrier_proof.rs
  • packages/rs-drive/src/query/drive_document_sum_query/executors/range_distinct_proof.rs
  • packages/rs-drive/src/query/drive_document_sum_query/executors/range_no_proof.rs
  • packages/rs-drive/src/query/drive_document_sum_query/executors/range_proof.rs
  • packages/rs-drive/src/query/drive_document_sum_query/executors/total.rs
  • packages/rs-drive/src/query/drive_document_sum_query/index_picker.rs
  • packages/rs-drive/src/query/drive_document_sum_query/mod.rs
  • packages/rs-drive/src/query/drive_document_sum_query/path_query.rs
  • packages/rs-drive/src/query/drive_document_sum_query/tests.rs
  • packages/rs-drive/src/query/mod.rs
  • packages/rs-drive/src/verify/document/verify_proof/mod.rs
  • packages/rs-drive/src/verify/document/verify_proof_keep_serialized/mod.rs
  • packages/rs-drive/src/verify/document/verify_start_at_document_in_proof/mod.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/contact_info.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/dpns_marketplace.rs
  • packages/rs-platform-wallet/src/wallet/identity/network/profile.rs
  • packages/rs-sdk/src/platform/dashpay/contact_request_queries.rs
  • packages/rs-sdk/src/platform/documents/average_proof_helpers.rs
  • packages/rs-sdk/src/platform/documents/count_proof_helpers.rs
  • packages/rs-sdk/src/platform/documents/document_query.rs
  • packages/rs-sdk/src/platform/documents/ranked_proof_helpers.rs
  • packages/rs-sdk/src/platform/documents/sum_proof_helpers.rs
  • packages/rs-sdk/src/platform/dpns_usernames/mod.rs
  • packages/rs-sdk/src/platform/dpns_usernames/queries.rs
  • packages/rs-sdk/tests/fetch/document.rs
  • packages/wasm-drive-verify/src/document/verify_proof.rs
  • packages/wasm-drive-verify/src/document/verify_proof_keep_serialized.rs
  • packages/wasm-drive-verify/src/document/verify_start_at_document_in_proof.rs
  • packages/wasm-sdk/src/dpns.rs
  • packages/wasm-sdk/src/queries/document.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/wasm-sdk/src/dpns.rs
  • packages/rs-sdk/src/platform/dpns_usernames/mod.rs
  • packages/rs-sdk/src/platform/dashpay/contact_request_queries.rs
  • packages/rs-dpp/src/data_contract/document_type/index/random_index.rs
  • packages/rs-sdk/src/platform/dpns_usernames/queries.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/rs-drive-abci/src/query/document_query/v1/conversions.rs
  • packages/rs-dpp/src/data_contract/document_type/index_level/find_first_change.rs
  • packages/wasm-sdk/src/queries/document.rs

Comment thread packages/rs-dpp/src/data_contract/document_type/index/mod.rs
Comment thread packages/rs-drive/src/query/drive_document_sum_query/executors/per_in_value.rs Outdated

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The four prior blocking findings are fixed at the exact head, and both current CodeRabbit comments are non-issues because time-range provenance is centrally pinned and clause shapes are validated before aggregate dispatch. One blocking contract-validation defect remains: valid user schemas cannot produce DocumentPropertyType::Date, so the custom timestamp fields advertised by this PR are unusable.
Source: reviewer backend model gpt-5.6-sol; final verifier backend model gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs`:
- [BLOCKING] packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/common/mod.rs:874-880: User-defined timestamp fields can never satisfy the time-range validation
  This validation accepts a non-system time-range source only when the flattened schema property is `DocumentPropertyType::Date`, but the document-schema parser cannot produce that variant. `DocumentPropertyType::try_from_value_map()` maps every `type: "string"` property, including `format: "date-time"`, to `DocumentPropertyType::String`, while its accepted schema types have no `"date"` branch. The v3 meta-schema uses the standard JSON Schema `type` grammar, so a user cannot work around this with `type: "date"`. As a result, every valid custom date-time or millisecond-integer property is rejected here, and time-range indexes work only with `$createdAt`, `$updatedAt`, or `$transferredAt`. Add a reachable and consistently encoded schema representation for custom millisecond timestamps, including parser and validation coverage, or remove the advertised custom-Date capability.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/rs-drive/src/query/non_primary_key_path_query/v1/mod.rs (1)

132-133: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve resolved time-range validation in the direct multi-In path.

At line 133, get_non_primary_key_multiple_in_path_query calls find_best_index_for_multiple_in_clauses without the resolved-source guard in find_best_index. Therefore, a query with multiple In clauses and orderBy on a resolved time-range source can reach the v1 lowering and use the bucketed index. Apply the same guard before this call or share one validator.

🤖 Prompt for AI Agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

In `@packages/rs-drive/src/query/non_primary_key_path_query/v1/mod.rs` around
lines 132 - 133, Update get_non_primary_key_multiple_in_path_query to apply the
resolved time-range source validation before calling
find_best_index_for_multiple_in_clauses, matching the guard used by
find_best_index; alternatively, reuse a shared validator so multiple In clauses
with orderBy on a resolved time-range source cannot proceed to v1 lowering or
the bucketed index.
🤖 Prompt for all review comments with AI agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

Outside diff comments:
In `@packages/rs-drive/src/query/non_primary_key_path_query/v1/mod.rs`:
- Around line 132-133: Update get_non_primary_key_multiple_in_path_query to
apply the resolved time-range source validation before calling
find_best_index_for_multiple_in_clauses, matching the guard used by
find_best_index; alternatively, reuse a shared validator so multiple In clauses
with orderBy on a resolved time-range source cannot proceed to v1 lowering or
the bucketed index.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6808791e-ac52-4d69-984d-e4799f7433be

📥 Commits

Reviewing files that changed from the base of the PR and between 5399361 and 3d356b5.

📒 Files selected for processing (29)
  • packages/rs-dpp/schema/meta_schemas/document/v3/document-meta.json
  • packages/rs-drive-abci/src/execution/platform_events/fee_pool_outwards_distribution/fetch_reward_shares_list_for_masternode/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v1/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v1/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_documents.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/dpns.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs
  • packages/rs-drive-abci/src/query/document_query/v0/mod.rs
  • packages/rs-drive/benches/document_count_worst_case.rs
  • packages/rs-drive/benches/document_sum_worst_case.rs
  • packages/rs-drive/src/drive/document/index_uniqueness/internal/validate_uniqueness_of_data/v0/mod.rs
  • packages/rs-drive/src/drive/document/index_uniqueness/internal/validate_uniqueness_of_data/v1/mod.rs
  • packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs
  • packages/rs-drive/src/drive/document/update/mod.rs
  • packages/rs-drive/src/drive/identity/withdrawals/document/fetch_oldest_withdrawal_documents_by_status/v0/mod.rs
  • packages/rs-drive/src/drive/identity/withdrawals/document/find_withdrawal_documents_by_status_and_transaction_indices/v0/mod.rs
  • packages/rs-drive/src/drive/identity/withdrawals/document/find_withdrawal_documents_by_status_and_transaction_indices/v1/mod.rs
  • packages/rs-drive/src/query/drive_document_count_and_sum_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/drive_document_count_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/drive_document_sum_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/mod.rs
  • packages/rs-drive/src/query/non_primary_key_path_query/v1/mod.rs
  • packages/rs-drive/tests/query_tests.rs
  • packages/rs-sdk/src/platform/documents/document_query.rs
  • packages/wasm-drive-verify/src/document/verify_proof.rs
  • packages/wasm-drive-verify/src/document/verify_proof_keep_serialized.rs
  • packages/wasm-drive-verify/src/document/verify_start_at_document_in_proof.rs
🚧 Files skipped from review as they are similar to previous changes (26)
  • packages/rs-drive/src/drive/document/index_uniqueness/internal/validate_uniqueness_of_data/v1/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v1/mod.rs
  • packages/wasm-drive-verify/src/document/verify_proof_keep_serialized.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v1/mod.rs
  • packages/rs-drive/src/drive/document/index_uniqueness/internal/validate_uniqueness_of_data/v0/mod.rs
  • packages/rs-drive/src/query/drive_document_count_and_sum_query/drive_dispatcher.rs
  • packages/wasm-drive-verify/src/document/verify_start_at_document_in_proof.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs
  • packages/wasm-drive-verify/src/document/verify_proof.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/withdrawals/v0/mod.rs
  • packages/rs-drive/src/query/drive_document_sum_query/drive_dispatcher.rs
  • packages/rs-drive/src/drive/identity/withdrawals/document/find_withdrawal_documents_by_status_and_transaction_indices/v0/mod.rs
  • packages/rs-drive/src/drive/identity/withdrawals/document/fetch_oldest_withdrawal_documents_by_status/v0/mod.rs
  • packages/rs-drive/src/drive/document/update/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/tests/document/dpns.rs
  • packages/rs-drive-abci/src/execution/platform_events/fee_pool_outwards_distribution/fetch_reward_shares_list_for_masternode/v0/mod.rs
  • packages/rs-dpp/schema/meta_schemas/document/v3/document-meta.json
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/state/v0/fetch_documents.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dpns/v0/mod.rs
  • packages/rs-drive/benches/document_sum_worst_case.rs
  • packages/rs-drive-abci/src/query/document_query/v0/mod.rs
  • packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs
  • packages/rs-drive/src/query/drive_document_count_query/drive_dispatcher.rs
  • packages/rs-drive/src/query/mod.rs
  • packages/rs-drive/benches/document_count_worst_case.rs
  • packages/rs-sdk/src/platform/documents/document_query.rs

QuantumExplorer and others added 4 commits August 26, 2026 11:17
…edes the first bucket

phase < step alone was insufficient: on a huge step (e.g. range = step
= 2_000_000_000s) a sub-step phase of 1_900_000_000s puts the grid's
first bucket around 2030, so every present-day timestamp fell in the
uncovered region — unindexed, and free to bypass a unique time-range
constraint until the phase passed. phase must now also be under one
year (MAX_TIME_RANGE_PHASE_SECONDS, structural like range % step), so
the uncovered region stays inside 1970–1971, unreachable for
consensus-validated timestamps, while a year covers every alignment
use case.

Also from review: index admissibility now binds the provenance field
to the transform's source (a fabricated pair — a real transform under
a different field — could satisfy the shape guard on the wrong clause
while a raw equality rode into the bucketed index), with a mismatch
regression; the WASM query surface gains the optional grid
({ range, step, phase? }) so JS callers can address multi-grid fields
at all; and the estimated-cost KeySize fan-out gets direct tests
(exact bounded count, distinct unique_ids so grovedb cannot collapse
them, untouched max_size, clamp above the versioned cap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rfaces end to end

Both surfaces pin plain ranked indexes with equality prefixes, and both
pickers exclude transformed indexes — so a resolved bucket-start
equality reaching them selects a plain index over raw timestamps, and a
proof over it authenticates boundary-timestamp matches instead of
window membership. The server's ranked route already refused the
provenance; the HAVING route dropped it on the dispatch floor, and both
SDK verifiers resolved the selector and then discarded the provenance,
accepting request shapes every honest server rejects — a malicious
node's validly-proven wrong answer.

DocumentHavingRequest now carries resolved_time_ranges and drive
rejects it non-empty (same drive-owns-the-rejection pattern as the
ranked request); the routing layer threads it through. The ranked and
HAVING verifiers normalize through the shared helper and refuse
non-empty provenance with the matching message.

Also from review: the Drive-to-DocumentQuery conversions (both From
impls and new_with_drive_query) are now fallible and refuse a query
carrying resolution provenance — the resolved bucket equality would
silently demote to a raw-timestamp predicate, and the original
selector is not reconstructible.

Tests: the HAVING route refuses IN_TIME_RANGE at the handler; both
verifier entry points refuse before authenticating any proof; the
conversion refuses a provenance-carrying drive query.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rage

Review follow-ups: the time-range storage and uniqueness tests now
derive every owner/document/contract identifier deterministically from
the fixture's own inputs (fixture_bytes marker+timestamp+tag) instead
of OS entropy — a failing GroveDB fixture reproduces identically
run-to-run and the getrandom unwrap leaves consensus-sensitive tests.
The WASM parse_time_range_clause boundary — the only converter from
the public JS { field, selector, grid? } shape — gains direct parser
tests: bare selector, zero-phase-by-omission and explicit-phase grids,
invalid selectors, malformed grids, and negative/fractional members.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread packages/rs-dpp/src/data_contract/document_type/index/mod.rs
Comment thread packages/dash-platform-queries/src/documents/document_query.rs Outdated

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Codex/Sol only (Phase 2 disabled)

The exact head fixes both prior test-quality findings: time-range storage fixtures are deterministic, and the WASM parser now has direct multi-grid coverage. Two in-scope API correctness suggestions remain: unique-index conflict checks still compare raw timestamps instead of bucket keys, and version-aware encoding permits IN_TIME_RANGE before its protocol-v14 activation. Source: Codex reviewer backend model gpt-5.6-sol (general, security-auditor, and rust-quality); final verifier backend model gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated zero-blocker Codex/Sol precheck evidence was promoted to final because Phase 2 (Sonnet/Opus) is temporarily disabled. This is Codex/Sol-only final validation, not Codex + Sonnet/Opus coverage.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet/Opus: not run (Phase 2 disabled — temporary Codex/Sol-only final)
  • Secondary pass: disabled (temporary_phase2_sonnet_disable)

🟡 2 suggestion(s)

2 additional finding(s) omitted (not in diff).

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-dpp/src/data_contract/document_type/index/mod.rs`:
- [SUGGESTION] packages/rs-dpp/src/data_contract/document_type/index/mod.rs:520-533: Compare bucket keys in unique-index conflict checks
  `Index::objects_are_conflicting` still compares every indexed property as a raw value, but this PR changes the equality semantics of valid unique time-range indexes. For a non-overlapping unique index such as `($createdAt, author)`, two different timestamps in the same daily bucket with the same author occupy the same unique GroveDB slot; Drive correctly rejects the second document after rewriting the timestamp to its bucket start, while this public DPP helper returns `false` because the raw timestamps differ. Compare the transformed source values by containing bucket start while preserving the existing missing/null behavior, and add same-bucket and adjacent-bucket tests.

In `packages/dash-platform-queries/src/documents/document_query.rs`:
- [SUGGESTION] packages/dash-platform-queries/src/documents/document_query.rs:723-735: Gate IN_TIME_RANGE encoding on protocol-v14 activation
  This dispatch treats document-query wire version 1 as sufficient to emit `IN_TIME_RANGE`, but protocol versions 12 and 13 also use `DRIVE_ABCI_QUERY_VERSIONS_V1`. Their contract grammar cannot declare a time-range index: `SystemLimits::max_time_range_overlap_factor` is `None` before protocol version 14 and its documentation explicitly identifies that state as predating the feature. A query built with `with_time_range` is therefore encoded for versions where it cannot be served, and the native and WASM documentation incorrectly advertises Platform v3.1+ as sufficient. Reject non-empty `time_range_clauses` unless the supplied platform version exposes the time-range capability, update the public documentation to name protocol version 14, and test v13 rejection versus v14 acceptance.

Review follow-ups on the current head, none consensus-visible before
protocol v14 activates:

- Move validate_and_canonicalize_where_clauses (+ range-pair merge) from
  the count dispatcher into shared drive::query::canonicalize, and run it
  in the sum dispatcher, the average prove path, and the SDK count / sum /
  average proof verifiers — a [f > A, f < B] pair now behaves identically
  on every aggregate route and its proofs verify client-side.
- Port sum's strict prefix-coverage guard to count's carrier-arm index
  picker: an equality on a field the index does not carry no longer
  silently drops (over-broad per-group counts that even verified).
- Collapse the duplicated bucketed-source shape guards into one
  DriveDocumentQuery::validate_resolved_source_shape, run on both
  find_best_index and the multiple-In selection — the multi-In execution
  lowering previously bypassed the guard entirely (direct-Rust-only hole).
- Gate IN_TIME_RANGE emission on the v14 contract grammar generation and
  correct the "Platform v3.1+" doc/error text (the operator otherwise
  reached PV12/13 servers as an unknown discriminant); tests pin v13
  refusal vs v14 acceptance.
- Derive the fee re-parser's ranked/timeRange grammar admissions from a
  shared IndexGrammarAdmissions::for_schema_generation mapping also used
  by the schema parsers, so fee and validation parsing cannot drift.
- Fix two #[cfg] gates orphaned by inserted imports in the sum/average
  query modules (warnings under --no-default-features --features verify).
- Replace the overlap-factor clamp(1, max) with min/max (Ord::clamp
  panics if a future limits table carries Some(0)).
- Make Index::objects_are_conflicting compare bucket starts for a
  time-range source (same-bucket/adjacent-bucket/sliver tests).
- Fail loudly in the uniqueness probe on a non-timestamp source value
  instead of silently skipping the index's check; treat non-8-byte values
  as undecodable in entry_keys_for_raw (no truncated-prefix bucketing).
- Fetch the contract once per v1 document query: shared fetch helper +
  PrefetchedContract threaded into the aggregate dispatchers (after their
  cheap shape guards, preserving error precedence), replacing five copies
  of the parse → fetch → not-found block and the resolution re-fetch;
  guard the where-clause partition behind an .any() check.
- Drop per-bucket path clones in the insert/delete v2 walkers (dead
  path_key_info clone; final bucket takes ownership of index_path).
- Document the wasm-drive-verify time-range limitation and extend the
  no-covering-index error to name bucketed indexes when one exists.
- Readability: import instead of inline-qualifying multi-segment paths at
  call sites (normalize_time_range_clauses_with_metadata_time and
  friends).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Codex/Sol only (Phase 2 disabled)

At exact head b3bb244, both prior findings are fixed, and the substantive CodeRabbit reports are either fixed or superseded by the current provenance-pinning implementation. The only retained issue is a non-blocking test-quality suggestion to assert the protocol gate's typed error variant instead of relying solely on Display text. Source: Codex reviewer backend model gpt-5.6-sol (general, rust-quality, security-auditor); final verifier backend model gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated zero-blocker Codex/Sol precheck evidence was promoted to final because Phase 2 (Sonnet/Opus) is temporarily disabled. This is Codex/Sol-only final validation, not Codex + Sonnet/Opus coverage.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — rust-quality (completed), gpt-5.6-sol — security-auditor (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet/Opus: not run (Phase 2 disabled — temporary Codex/Sol-only final)
  • Secondary pass: disabled (temporary_phase2_sonnet_disable)

🟡 1 suggestion(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/dash-platform-queries/src/documents/document_query.rs`:
- [SUGGESTION] packages/dash-platform-queries/src/documents/document_query.rs:1440-1443: Assert the protocol gate's typed error variant
  This regression test checks only the error's Display text. It would still pass if an unrelated error variant happened to mention protocol version 14, and a harmless formatting change could break it despite unchanged behavior. Match `Error::Config` first and then check its payload so the test pins both the typed failure contract and the version-floor message.

Comment thread packages/dash-platform-queries/src/documents/document_query.rs
QuantumExplorer and others added 2 commits August 26, 2026 16:37
…ment comparisons

Drive stamps $contractVersion on stored documents from protocol v14
(the requiredSince serialization format), so a fetched document carries
it while a locally created one never does — every created-vs-fetched
deep-equal in the suite fails on the stamp alone. Strip it in the
comparison helpers exactly like the other server-assigned metadata.
The regression came in with the requiredSince merge but only PR runs
execute the functional suite, so the dev-branch push never surfaced it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v13 refusal test only inspected Display text, so it would pass on
any error mentioning protocol version 14 and break on a harmless
rewording. Match Error::Config first, then check the version-floor
message on its payload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The time-range implementation is broadly consistent across validation, storage fan-out, provenance-pinned index selection, and proof reconstruction. One blocking pagination defect remains: a cursor inside a selected bucket is compared as a raw timestamp against the bucket-start key, which can produce a validly proven empty page. Two non-blocking API-boundary improvements would also prevent internal parser state and inconsistent provenance from becoming downstream compatibility obligations.
Source: Codex reviewers gpt-5.6-sol (general, security-auditor, rust-quality); final verifier gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking | 🟡 2 suggestion(s)

1 additional finding(s) omitted (not in diff).

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive/src/query/non_primary_key_path_query/single_in_path_query/v0/mod.rs`:
- [BLOCKING] packages/rs-drive/src/query/non_primary_key_path_query/single_in_path_query/v0/mod.rs:462-472: Do not compare a time-range cursor's raw timestamp to the bucket key
  For a single-property time-range index, the resolved bucket equality is the last clause and there are no leftover index properties. This branch therefore passes the cursor document to `WhereClause::to_path_query`, which reads the cursor's raw source timestamp and compares it with the resolved bucket-start key. For example, an included cursor created at 07:00 inside a bucket beginning at 06:00 suppresses the 06:00 key because 07:00 is ordered after it, yielding an empty page even when later document IDs exist in that bucket. Proof reconstruction repeats the same lowering and consequently accepts the empty result. Do not apply the cursor at the transformed source level; the existing recursive terminator/document-ID query should apply it instead. Add a regression with an included cursor whose timestamp lies inside, but not exactly at the start of, the selected bucket.

In `packages/rs-dpp/src/data_contract/document_type/index/mod.rs`:
- [SUGGESTION] packages/rs-dpp/src/data_contract/document_type/index/mod.rs:525-542: Keep the grammar-admission mapping crate-private
  `IndexGrammarAdmissions` is an internal mapping shared by DPP's schema parser and registration-cost calculation, and all repository uses remain inside the `dpp` crate. Making the type, fields, and constructor public exposes parser-generation internals as downstream API and creates an unnecessary compatibility obligation. `pub(crate)` preserves all current sibling-module uses while preventing external consumers from coupling to this implementation detail.

In `packages/rs-drive/src/query/mod.rs`:
- [SUGGESTION] packages/rs-drive/src/query/mod.rs:659-664: Make inconsistent time-range provenance unrepresentable
  `ResolvedTimeRange` publicly stores the source field both in `field` and in `transform.source`, allowing external Rust callers to construct contradictory provenance. The current admissibility guard correctly rejects the known mismatch, but every future consumer must remember to enforce the same invariant. Use `transform.source` as the single source of truth, or make the fields private and provide a constructor and accessors that guarantee consistency.

Comment thread packages/rs-dpp/src/data_contract/document_type/index/mod.rs Outdated
Comment thread packages/rs-drive/src/query/mod.rs
QuantumExplorer and others added 6 commits August 26, 2026 18:12
… the bucket-keyed level

A time-range index's transformed first level stores bucket starts, so
when the resolved bucket equality is the query's last clause with no
left-over index properties (a single-property time-range index), the
cursor document's raw timestamp was compared against the bucket-start
key: an included cursor created mid-bucket orders after the key,
suppresses it, and validly proves an empty page while later document
ids still exist in the bucket — proof reconstruction repeats the same
lowering, so verification accepts it. Withhold the cursor from the
bucket-keyed level and apply it by bucket membership instead: a cursor
inside the selected bucket continues the document-id walk (for a
unique index the bucket holds exactly the cursor document, so excluded
means the page is exhausted); a cursor from outside the bucket cannot
order within it and serves the full bucket. Regression: three posts in
one bucket, an included and an excluded mid-bucket cursor return the
id-ordered continuation instead of an empty page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ResolvedTimeRange stored the source field both directly and inside its
transform, so a direct Rust caller could fabricate a pair naming a
field the grid does not bucket, and every consumer had to guard the
mismatch. The transform is now the single source of truth — field() is
an accessor over transform.source — which makes inconsistent provenance
unrepresentable, and the admissibility guard reduces to transform
equality. The count picker's fabricated-mismatch test becomes a
fabricated-grid test, the only inconsistency still expressible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
IndexGrammarAdmissions is an internal generation-to-keywords mapping
shared by the schema parsers and the registration-cost re-parse; every
use is inside the dpp crate, so pub(crate) keeps the sharing without
exposing parser internals as downstream API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…b's unified PathQuery surface (#4488)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The unified-PathQuery grovedb pin (#4488) changed
rollback_to_savepoint()'s error type so the RocksDBError wrap went
away, leaving |e| StorageError(e) closures that clippy 1.92 rejects
as redundant_closure under CI's -D warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Codex/Sol only (Phase 2 disabled)

All three prior verified findings and the substantive CodeRabbit reports are fixed at the exact head; no blocking correctness issue remains. Two non-blocking test-maintainability gaps remain around the cursor regression and the 1,553-line inline integration-test module.
Source: Codex reviewer backend model gpt-5.6-sol (general, security-auditor, rust-quality); final verifier backend model gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated zero-blocker Codex/Sol precheck evidence was promoted to final because Phase 2 (Sonnet/Opus) is temporarily disabled. This is Codex/Sol-only final validation, not Codex + Sonnet/Opus coverage.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet/Opus: not run (Phase 2 disabled — temporary Codex/Sol-only final)
  • Secondary pass: disabled (temporary_phase2_sonnet_disable)

🟡 2 suggestion(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs`:
- [SUGGESTION] packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs:864-881: Assert cursor identities and cover the unique terminal layout
  The cursor regression exercises only the non-unique arm and compares result counts rather than returned document IDs. With the deterministic early/mid/late IDs used here, an implementation returning the wrong side of the cursor could still produce the expected lengths of two and one. The production fix also has separate behavior for a unique single-property time-range index: an included cursor must retain the bucket's sole document, while an excluded cursor must empty the page. Deserialize the results and compare their IDs with the exact sorted suffix, then add a valid unique `$createdAt` fixture with `range == step` that exercises both included and excluded cursors.
- [SUGGESTION] packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs:66-1617: Move the time-range integration fixtures into a dedicated test module
  This PR places 1,553 lines of fixture builders, contracts, query helpers, and integration tests directly below a 64-line production dispatcher. That obscures the versioned entry point and makes the test fixture difficult to navigate or extend. Move the module into a sibling `time_range_index_e2e_tests.rs` file and retain only `#[cfg(test)] mod time_range_index_e2e_tests;` here; the sibling module preserves the same private access and test-only compilation.

Comment thread packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs Outdated
Comment thread packages/rs-drive/src/drive/document/insert/add_document_for_contract/mod.rs Outdated
QuantumExplorer and others added 2 commits August 26, 2026 21:08
…ds and the unique layout

- Move the 1,550-line time_range_index_e2e_tests module out of
  add_document_for_contract/mod.rs into a sibling file, leaving the
  64-line versioned dispatcher readable.
- The in-bucket cursor regression now asserts the exact returned id
  sequence (deserialized), not just result counts.
- New coverage for the unique arm of the in-bucket cursor rule: on a
  unique single-property grid an included cursor retains the bucket's
  sole document and an excluded cursor empties the page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… rule

Two comments still justified behavior by the pre-multi-grid "indexes
sharing a first property must agree on the transform" validation, which
the grid-qualified level keys deleted. The update walker's insertion
cache is safe because it keys on the full qualified path; a plain index
may lead with a bucketed field, and safety comes from provenance-pinned
index selection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Codex/Sol only (Phase 2 disabled)

The reported $transferredAt blocker is a false positive because the production create-action conversion initializes every required system timestamp, including $transferredAt, from authoritative block information before storage serialization. One non-blocking test gap remains: the altered-metadata COUNT/SUM/AVG tests can stop at signature verification without exercising reconstruction of a different proof path. Both prior verified findings are fixed at the exact head.
Source: reviewer backend model gpt-5.6-sol (general, security-auditor, and rust-quality); final verifier backend model gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and not reviewer evidence.

Validated zero-blocker Codex/Sol precheck evidence was promoted to final because Phase 2 (Sonnet/Opus) is temporarily disabled. This is Codex/Sol-only final validation, not Codex + Sonnet/Opus coverage.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — rust-quality (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet/Opus: not run (Phase 2 disabled — temporary Codex/Sol-only final)
  • Secondary pass: disabled (temporary_phase2_sonnet_disable)

🟡 1 suggestion(s)

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/rs-drive-abci/src/query/document_query/v1/tests.rs`:
- [SUGGESTION] packages/rs-drive-abci/src/query/document_query/v1/tests.rs:4988-5002: Re-sign altered metadata before asserting proof-path rejection
  The COUNT, SUM, and AVG negative entry-point tests change `time_ms` after `prove_and_sign` signs the original metadata, while `assert_proof_or_signature_rejection` explicitly accepts `InvalidSignature`. Those tests can therefore succeed before demonstrating that the entry point normalized the selector to the later bucket, propagated its exact-grid provenance, selected the transformed index, and rejected the stale GroveDB proof path. Re-sign the unchanged proof and root against the one-step-later metadata with the fixture quorum key, then require a GroveDB/Drive proof-query mismatch. Keep a separate unsigned-tampering assertion if signature binding also needs coverage.

Comment thread packages/rs-drive-abci/src/query/document_query/v1/tests.rs
…proof path

The COUNT/SUM/AVG tampered-metadata tests altered time_ms after
signing and accepted InvalidSignature, so they could not distinguish
which layer rejected. They now re-sign the altered metadata with the
fixture quorum key and require a GroveDB/Drive proof-path rejection:
the verifier resolves the selector one step later, reconstructs the
next bucket's path query, and refuses the stale bucket's proof.
(Verification reconstructs the proof path before the signature check;
signature binding stays pinned by the trust-boundary tests.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@QuantumExplorer

Copy link
Copy Markdown
Member Author

Reviewed

@QuantumExplorer
QuantumExplorer merged commit 45dc3ca into v4.2-dev Aug 26, 2026
42 of 43 checks passed
@QuantumExplorer
QuantumExplorer deleted the time-range-indexes branch August 26, 2026 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dapi-endpoint DAPI endpoint addition or modification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants