Skip to content

fix: parallel-test race on process-global platform version in contract to_value - #4395

Merged
QuantumExplorer merged 3 commits into
v4.2-devfrom
fix/data-contract-to-value-version-race
Aug 13, 2026
Merged

fix: parallel-test race on process-global platform version in contract to_value#4395
QuantumExplorer merged 3 commits into
v4.2-devfrom
fix/data-contract-to-value-version-race

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Aug 13, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

cargo test -p drive-abci --lib (full suite) reproducibly failed data_contract_create::tests::keywords::test_data_contract_creation_fails_with_more_than_fifty_keywords, while the same test passed in isolation and at module scope. The assertion expected TooManyKeywordsError but got DataContractConfigUpdateError("config version 0 is not supported, minimum version is 1").

This is a parallel-test race on the process-wide current platform version:

  • Every test platform build (Platform::open_with_client_no_saved_state / open_with_client_saved_state) calls PlatformVersion::set_current, a process-global.
  • DataContract's serde Serialize impl picks the serialization format from that global (get_version_or_current_or_latest(None)).
  • So a test round-tripping a contract through platform_value::to_value(&contract) while another test concurrently builds a platform at an old protocol version (e.g. with_initial_protocol_version(8)) serializes the contract in the old V0 format with a v0 config. Deserializing and validating at the latest version then rejects the v0 config before the code under test is ever reached.

What was done?

Threaded an explicit platform version through the round-trip path instead of serializing via the global:

  • Added DataContractValueConversionMethodsV0::to_value(&self, platform_version) (implemented for DataContract, DataContractV0, DataContractV1), which serializes through the existing DataContractInSerializationFormat conversion at the explicit version — same wire shape as the serde path, no global read. The serde impl itself is intentionally left untouched (its behavior is pinned by the data_contract_serde_pins_critical_4 tests).
  • Switched all 11 serde-to_value contract round-trip sites in the drive-abci tests to the new method: 7 in data_contract_create (keywords + descriptions) and 4 in data_contract_update, which had the identical latent race.
  • Updated the serde module docs to point at the new stateless alternative.

Note: the set_current global itself remains (it is load-bearing for production paths); this removes the dependence on it from these test code paths.

How Has This Been Tested?

  • 3 consecutive full cargo test -p drive-abci --lib runs: 2671 passed / 0 failed each (previously reproducibly 1 failure per run).
  • rs-dpp serde behavior-pin tests pass; dpp, drive, wasm-dpp, wasm-dpp2 compile against the trait change; clippy on dpp shows only pre-existing warnings.

Breaking Changes

None (test-only behavior plus an additive API; no consensus or serialization changes at any given platform version).

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

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added platform-version-aware data contract serialization for more consistent conversion across supported contract types.
    • Added support for selecting serialization formats explicitly.
  • Bug Fixes

    • Improved reliability when serializing and deserializing contracts across platform versions.
    • Updated contract validation scenarios to use version-aware conversion, preserving existing behavior.

…t to_value

Every test platform build calls PlatformVersion::set_current (a process-wide
global), and DataContract's serde Serialize impl reads that global to pick the
serialization format. Tests that round-trip a contract through
platform_value::to_value while another test concurrently builds a platform at
an old protocol version (e.g. with_initial_protocol_version(8)) observe the
old version mid-test: the contract serializes in the V0 format (config v0),
which latest-version validation then rejects with
DataContractConfigUpdateError instead of the expected error. This reproducibly
failed test_data_contract_creation_fails_with_more_than_fifty_keywords in full
`cargo test -p drive-abci --lib` runs while passing in isolation.

Add DataContractValueConversionMethodsV0::to_value(&self, platform_version)
which serializes through DataContractInSerializationFormat at an explicit
platform version, and switch the data_contract_create / data_contract_update
tests to it so their round-trip path no longer reads the global at all.

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

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@QuantumExplorer, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 38cf3ee1-23b2-4c4b-9389-ba6215d80b7f

📥 Commits

Reviewing files that changed from the base of the PR and between af3574e and 2e0c6dc.

📒 Files selected for processing (1)
  • packages/rs-dpp/src/data_contract/mod.rs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 47956c8f-224e-4e0b-85a0-4aeb4f2539b4

📥 Commits

Reviewing files that changed from the base of the PR and between 0cb4bad and af3574e.

📒 Files selected for processing (5)
  • packages/rs-dpp/src/data_contract/conversion/serde/mod.rs
  • packages/rs-dpp/src/data_contract/conversion/value/mod.rs
  • packages/rs-dpp/src/data_contract/conversion/value/v0/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs
  • packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs

📝 Walkthrough

Walkthrough

The PR adds explicit platform-version contract serialization through DataContractValueConversionMethodsV0::to_value. It adds format-selection and round-trip tests, updates validation fixtures, and documents the distinction from process-global serde serialization.

Changes

Contract serialization

Layer / File(s) Summary
Version-aware serialization API
packages/rs-dpp/src/data_contract/conversion/value/v0/mod.rs, packages/rs-dpp/src/data_contract/conversion/serde/mod.rs
The conversion trait now serializes supported contracts with an explicit PlatformVersion. Documentation distinguishes this path from global-version serde serialization.
Serialization format and round-trip tests
packages/rs-dpp/src/data_contract/conversion/value/mod.rs
Tests verify format 0 and format 1 output and preserve contract fields through round-trip conversion.
Validation fixture migration
packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_create/mod.rs, packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs
Contract creation and update fixtures use the platform-version-aware conversion method.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to af357

The change makes contract test round-trips use an explicit platform version instead of shared process-wide state, without changing production serialization behavior; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: shumkov

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: fixing a parallel-test race caused by the process-global platform version during contract serialization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 fix/data-contract-to-value-version-race

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

@thepastaclaw

thepastaclaw commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit 2e0c6dc)

@github-actions github-actions Bot added this to the v4.2.0 milestone Aug 13, 2026
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.38554% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.86%. Comparing base (806890c) to head (2e0c6dc).
⚠️ Report is 5 commits behind head on v4.2-dev.

Files with missing lines Patch % Lines
...s/rs-dpp/src/data_contract/conversion/value/mod.rs 94.73% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           v4.2-dev    #4395      +/-   ##
============================================
- Coverage     86.81%   85.86%   -0.95%     
============================================
  Files          2647     2658      +11     
  Lines        340850   347979    +7129     
============================================
+ Hits         295913   298804    +2891     
- Misses        44937    49175    +4238     
Components Coverage Δ
dpp 86.44% <95.45%> (-0.21%) ⬇️
drive 84.61% <ø> (-1.19%) ⬇️
drive-abci 87.26% <100.00%> (-1.47%) ⬇️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.92% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 48.02% <ø> (ø)
🚀 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.

@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 explicit conversion path removes the affected test round-trips from process-global platform-version selection, but adding a required method to the existing public, unsealed conversion trait is a source-breaking API change and must be addressed or declared as such. The new stateless API also needs focused version-selection coverage, and the central DataContract guidance should no longer recommend the global-dependent path. Source: reviewer backend gpt-5.6-sol; final verifier backend gpt-5.6-sol. Orchestration-only: openclaw-agent/cliproxy/gpt-5.6-sol (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 | 🟡 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-dpp/src/data_contract/conversion/value/v0/mod.rs`:
- [BLOCKING] packages/rs-dpp/src/data_contract/conversion/value/v0/mod.rs:30-32: Adding a required trait method is a breaking API change
  `DataContractValueConversionMethodsV0` is a publicly reachable, unsealed trait, and it was already shipped in the v4.1.0 history. Downstream crates may implement it for their own local types, so adding the required `to_value` method makes every such implementation fail to compile. This contradicts the PR's declaration that the API change is additive and has no breaking changes. Preserve source compatibility by putting `to_value` on a separate output extension trait implemented for `DataContract`, `DataContractV0`, and `DataContractV1`; otherwise mark and version this as a breaking change.

In `packages/rs-dpp/src/data_contract/conversion/value/mod.rs`:
- [SUGGESTION] packages/rs-dpp/src/data_contract/conversion/value/mod.rs:38-41: Add deterministic coverage for explicit version selection
  The changed drive-abci tests exercise the new method through `DataContract`, generally using the latest platform version, while the new `DataContractV0` and `DataContractV1` implementations have no direct coverage. Add focused rs-dpp tests that invoke the explicit API with platform versions selecting serialization formats 0 and 1, assert the resulting top-level `$formatVersion` and expected shape, and cover all three concrete implementations. That directly pins the guarantee introduced by this fix instead of relying on parallel test scheduling to expose an incorrect global-version read.

In `packages/rs-dpp/src/data_contract/mod.rs`:
- [SUGGESTION] packages/rs-dpp/src/data_contract/mod.rs:127-130: Update the primary DataContract documentation to recommend the stateless API
  This conversion guidance still directs callers to `platform_value::to_value(&dc)`, even though that path reads the mutable process-global platform version and is the source of the race fixed by this PR. The new explicit conversion API makes the comment stale. Recommend `DataContractValueConversionMethodsV0::to_value` whenever a platform version is available and explain that the serde-based alternatives retain global-dependent behavior.

Comment thread packages/rs-dpp/src/data_contract/conversion/value/v0/mod.rs Outdated
Comment thread packages/rs-dpp/src/data_contract/conversion/value/mod.rs Outdated
Review follow-up: DataContractValueConversionMethodsV0 is public and
unsealed, so a required to_value method would break downstream
implementations. Make it a provided method instead, defaulted (with a
where-clause) for any implementor convertible to
DataContractInSerializationFormat — existing DataContract/V0/V1 callers are
unchanged and foreign implementors keep compiling without providing it.

Also add rs-dpp tests pinning that to_value selects the serialization format
($formatVersion 0 vs 1) from the passed platform version for DataContract,
DataContractV0, and DataContractV1, and round-trips through from_value at the
same version.

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 explicit conversion API correctly selects serialization from the supplied PlatformVersion, and the provided trait method plus focused tests resolve the previous compatibility and coverage findings. The central DataContract conversion guidance still recommends the process-global serialization path, leaving one documentation suggestion. Source: reviewer backend model gpt-5.6-sol; final verifier backend model gpt-5.6-sol; orchestration-only: openclaw-agent/cliproxy/gpt-5.6-sol (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)
  • 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)

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-dpp/src/data_contract/mod.rs`:
- [SUGGESTION] packages/rs-dpp/src/data_contract/mod.rs:127-128: Update the primary DataContract documentation to recommend the stateless API
  The primary DataContract conversion guidance still directs callers to `platform_value::to_value(&dc)`, even though that path selects its format through the mutable process-global platform version and caused the race fixed by this PR. The new explicit API is documented only in lower-level conversion modules, so callers following this central guidance can continue introducing nondeterministic conversions. Recommend `DataContractValueConversionMethodsV0::to_value` whenever a `PlatformVersion` is available and identify the serde-based alternatives as global-dependent.

…dance

Review follow-up: the DataContract conversion note still pointed callers at
the serde serialization path, which selects its format from the process-global
current platform version. Recommend
DataContractValueConversionMethodsV0::to_value(&dc, pv) whenever a
PlatformVersion is in hand and flag the serde alternatives as
global-dependent.

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 explicit conversion path uses the supplied PlatformVersion, preserves source compatibility through a default trait method, and has focused coverage for format selection and round trips. The central DataContract documentation now recommends the explicit-version API and clearly identifies the process-global behavior of serde alternatives; no in-scope defects remain.
Source: reviewer backend gpt-5.6-sol; final verifier backend gpt-5.6-sol. Orchestration-only: openclaw-agent/cliproxy/gpt-5.6-sol (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)
  • 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)

@QuantumExplorer

Copy link
Copy Markdown
Member Author

Reviewed

@QuantumExplorer
QuantumExplorer merged commit 49d3ce1 into v4.2-dev Aug 13, 2026
31 checks passed
@QuantumExplorer
QuantumExplorer deleted the fix/data-contract-to-value-version-race branch August 13, 2026 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants