Skip to content

test(db): fuzz visible includes relationship transitions - #1722

Open
KyleAMathews wants to merge 4 commits into
mainfrom
codex/includes-state-aware-transitions
Open

test(db): fuzz visible includes relationship transitions#1722
KyleAMathews wants to merge 4 commits into
mainfrom
codex/includes-state-aware-transitions

Conversation

@KyleAMathews

@KyleAMathews KyleAMathews commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

This adds state-aware property scenarios for visible includes relationship transitions across query depths and target levels. It expands recompute-oracle coverage and pins known divergences; it does not change runtime behavior or fix the bugs it exposes.

Approach

  • Build two fully connected, visible branches with generated, disjoint ID and relationship-key ranges.
  • Select an existing visible row at each target level, then either reparent it to the other branch or change its relationship key.
  • Add connected scalar updates before the transition and on the stable branch afterward so the generated traces exercise real query state instead of disconnected noise.
  • Enumerate depth and target-level pairs in the test matrix, while fuzzing source branch, row identities, relationship keys, scalar values, positions, and operation order.
  • Assert that the recomputed result changes at the forced transition before comparing incremental output with the oracle.

Known divergence boundaries

  • A visible rekey is an exact expected failure only when at least two descendant levels remain: targetLevel + 2 <= depth.
  • A deterministic depth-4 trace records a newly found bug: after a level-1 subtree is reparented, later scalar updates at levels 2 and 3 leave incremental output stale at checkpoint 8.

Each expected failure is pinned to the exact checkpoint. If the implementation stops failing there, the test fails and prompts us to turn the trace into a passing regression.

Key invariants

  • Every forced relationship transition targets a row that exists and is visible immediately before the transition.
  • Generated ID and relationship-key ranges cannot collide across branches or with rekey values.
  • Recomputation must observe a changed result at the forced transition.
  • The generated green corpus must match recomputation at every checkpoint.

Non-goals

  • Fix any relationship-routing or moved-subtree propagation bug.
  • Treat known divergences as passing behavior.
  • Randomize post-transition updates on the moved branch in the green corpus. That path exposes the separately pinned moved-subtree bug and can join the corpus after the runtime fix.

Trade-offs

The matrix enumerates all depth/target-level combinations and uses a small deterministic fuzz sample within each pair. This gives structural coverage without making the suite slow or leaving rare target levels to chance.

Verification

pnpm --filter @tanstack/db exec vitest run tests/query/includes-oracle.property.test.ts --maxWorkers=2 --coverage.enabled=false
pnpm --filter @tanstack/db test
pnpm exec eslint packages/db/tests/query/includes-oracle.property.test.ts
pnpm exec tsc --noEmit -p packages/db/tsconfig.json

Focused oracle tests: 40 passed. Package suite: 2,620 passed and 5 skipped.

Files changed

  • packages/db/tests/query/includes-oracle.property.test.ts — adds the state-aware relationship scenario builder, generated depth/level matrix, exact expected-failure boundaries, and the newly found moved-subtree trace.

Refs #1658

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of nested relationships when records are reparented, reorganized, or reassigned.
    • Preserved existing child relationships during full-row updates.
    • Improved consistency for relationship changes across different nesting levels and branches.
    • Added safeguards for reparented subtrees, key changes, and complex relationship transitions.
    • Improved validation for conflicting relationship keys and other invalid transitions.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b50fb558-e19f-4c88-844a-60c0fb6de563

📥 Commits

Reviewing files that changed from the base of the PR and between 789718f and fa63e88.

📒 Files selected for processing (1)
  • packages/db/tests/query/includes-oracle.property.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/db/tests/query/includes-oracle.property.test.ts

📝 Walkthrough

Walkthrough

The includes-oracle property tests now model configurable branches and relationship transitions at arbitrary depths. Full-row normalization preserves existing child relationships. Deterministic and property-based cases cover reparenting, rekeying, scalar updates, and expected deep-transition failures.

Changes

Nested relationship tests

Layer / File(s) Summary
Scenario normalization and branch modeling
packages/db/tests/query/includes-oracle.property.test.ts
Shared full-row updates handle root and child models. Connected batches accept configurable branches. Normalization preserves existing child relationships and uses the revised API.
Configurable relationship transitions
packages/db/tests/query/includes-oracle.property.test.ts
Generated scenarios support reparenting and rekeying at any target depth and source branch. Scenarios include scalar updates, disjoint-key validation, transition-only cases, and stateful cases.
Reparenting and rekeying regression coverage
packages/db/tests/query/includes-oracle.property.test.ts
Deterministic cases cover reparented subtrees and minimal rekeys. Tests validate overlapping-key rejection, descendant-update failures, and property behavior across target levels.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: ⚪ Minimal · up to fa63e

This test-only change does not alter runtime behavior, and no actionable merge-blocking risk remains after normal checks and review.

Possibly related PRs

  • TanStack/db#1669: Both modify nested includes-oracle regression and property coverage.
  • TanStack/db#1716: This extends the recomputation oracle and nested includes property-test harness.
  • TanStack/db#1720: Both expand deterministic and stateful nested relationship-transition testing.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the database test change and the relationship transitions covered by the PR.
Description check ✅ Passed The description explains the changes, verification, scope, known divergences, and non-goals, but it omits the required checklist and release-impact headings.
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 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/includes-state-aware-transitions

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.

@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.

🧹 Nitpick comments (2)
packages/db/tests/query/includes-oracle.property.test.ts (2)

1272-1281: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Generate the empty-noise case.

noise uses minLength: 1, so the scenario with no scalar updates around the transition is never generated. That case is the simplest and most valuable shrink target. Set minLength: 0.

Based on the retrieved learning "Test corner cases including: empty arrays/sets, single-element collections, undefined vs null values, resolved promises, async race conditions, and limit/offset edge cases".

♻️ Proposed change
-        { minLength: 1, maxLength: 10 },
+        { minLength: 0, maxLength: 10 },
🤖 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/db/tests/query/includes-oracle.property.test.ts` around lines 1272 -
1281, Update the noise array arbitrary in the property test to use minLength: 0
instead of minLength: 1, while preserving its existing maxLength and record
generation so empty-noise transition cases are generated and shrinkable.

Source: Learnings


1857-1897: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make seeds unique per combination and document the failure heuristic.

Two problems in this loop:

  1. seed: 1721 + depth + targetLevel collides across combinations. reparent and rekey share the same seed for the same (depth, targetLevel), and different pairs with equal sums collide too (depth 2 / level 2 and depth 3 / level 1 both give 1725). With numRuns: 4, the generated corpus repeats instead of widening coverage. Derive the seed from all three inputs.
  2. expectsFailure = transition === 'rekey' && targetLevel + 2 <= depth encodes a known defect without stating why. Add a short comment that a rekey disconnects descendants two or more levels below the changed row, so a reader knows what to delete when the defect is fixed.
♻️ Proposed change
       for (let targetLevel = 1; targetLevel <= depth; targetLevel++) {
+        // A rekey changes the parent key of the target row only. Descendants
+        // two or more levels below keep the stale `parentGroup`, which the
+        // incremental path currently fails to detach.
         const expectsFailure =
           transition === `rekey` && targetLevel + 2 <= depth
         fcTest.prop(
@@
           {
             numRuns: 4,
-            seed: 1721 + depth + targetLevel,
+            seed:
+              1721 +
+              depth * 100 +
+              targetLevel * 10 +
+              (transition === `rekey` ? 1 : 0),
           },
🤖 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/db/tests/query/includes-oracle.property.test.ts` around lines 1857 -
1897, Update the property-test loop around expectsFailure so the seed
incorporates transition, depth, and targetLevel, producing distinct seeds for
every combination rather than relying only on numeric inputs. Add a brief
comment beside the expectsFailure heuristic explaining that rekey disconnects
descendants two or more levels below the changed row, and retain the existing
failure behavior until that defect is fixed.
🤖 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.

Nitpick comments:
In `@packages/db/tests/query/includes-oracle.property.test.ts`:
- Around line 1272-1281: Update the noise array arbitrary in the property test
to use minLength: 0 instead of minLength: 1, while preserving its existing
maxLength and record generation so empty-noise transition cases are generated
and shrinkable.
- Around line 1857-1897: Update the property-test loop around expectsFailure so
the seed incorporates transition, depth, and targetLevel, producing distinct
seeds for every combination rather than relying only on numeric inputs. Add a
brief comment beside the expectsFailure heuristic explaining that rekey
disconnects descendants two or more levels below the changed row, and retain the
existing failure behavior until that defect is fixed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6077b4b5-a714-4fbd-b510-cab141cfa9ff

📥 Commits

Reviewing files that changed from the base of the PR and between dc53f0e and 8cb28cb.

📒 Files selected for processing (1)
  • packages/db/tests/query/includes-oracle.property.test.ts

@pkg-pr-new

pkg-pr-new Bot commented Aug 12, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@1722

@tanstack/browser-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/browser-db-sqlite-persistence@1722

@tanstack/capacitor-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/capacitor-db-sqlite-persistence@1722

@tanstack/cloudflare-durable-objects-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/cloudflare-durable-objects-db-sqlite-persistence@1722

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@1722

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@1722

@tanstack/db-sqlite-persistence-core

npm i https://pkg.pr.new/@tanstack/db-sqlite-persistence-core@1722

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@1722

@tanstack/electron-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/electron-db-sqlite-persistence@1722

@tanstack/expo-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/expo-db-sqlite-persistence@1722

@tanstack/node-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/node-db-sqlite-persistence@1722

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@1722

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@1722

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@1722

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@1722

@tanstack/react-native-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/react-native-db-sqlite-persistence@1722

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@1722

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@1722

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@1722

@tanstack/tauri-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/tauri-db-sqlite-persistence@1722

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@1722

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@1722

commit: fa63e88

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 132 kB

ℹ️ View Unchanged
Filename Size
packages/db/dist/esm/collection/change-events.js 1.44 kB
packages/db/dist/esm/collection/changes.js 1.51 kB
packages/db/dist/esm/collection/cleanup-queue.js 810 B
packages/db/dist/esm/collection/events.js 434 B
packages/db/dist/esm/collection/index.js 3.86 kB
packages/db/dist/esm/collection/indexes.js 1.99 kB
packages/db/dist/esm/collection/lifecycle.js 1.7 kB
packages/db/dist/esm/collection/mutations.js 2.47 kB
packages/db/dist/esm/collection/state.js 5.51 kB
packages/db/dist/esm/collection/subscription.js 3.77 kB
packages/db/dist/esm/collection/sync.js 3.05 kB
packages/db/dist/esm/collection/transaction-metadata.js 144 B
packages/db/dist/esm/deferred.js 207 B
packages/db/dist/esm/errors.js 5.16 kB
packages/db/dist/esm/event-emitter.js 748 B
packages/db/dist/esm/index.js 3.26 kB
packages/db/dist/esm/indexes/auto-index.js 829 B
packages/db/dist/esm/indexes/base-index.js 784 B
packages/db/dist/esm/indexes/basic-index.js 2.17 kB
packages/db/dist/esm/indexes/btree-index.js 2.29 kB
packages/db/dist/esm/indexes/index-registry.js 820 B
packages/db/dist/esm/indexes/reverse-index.js 557 B
packages/db/dist/esm/live-query-adapter.js 318 B
packages/db/dist/esm/live-query-observer.js 2.35 kB
packages/db/dist/esm/live-query-window-controller.js 3.04 kB
packages/db/dist/esm/local-only.js 916 B
packages/db/dist/esm/local-storage.js 2.12 kB
packages/db/dist/esm/optimistic-action.js 359 B
packages/db/dist/esm/paced-mutations.js 496 B
packages/db/dist/esm/proxy.js 3.75 kB
packages/db/dist/esm/query/builder/functions.js 1.47 kB
packages/db/dist/esm/query/builder/index.js 5.84 kB
packages/db/dist/esm/query/builder/ref-proxy.js 1.24 kB
packages/db/dist/esm/query/compiler/evaluators.js 1.89 kB
packages/db/dist/esm/query/compiler/expressions.js 430 B
packages/db/dist/esm/query/compiler/group-by.js 3.56 kB
packages/db/dist/esm/query/compiler/index.js 6.67 kB
packages/db/dist/esm/query/compiler/joins.js 2.5 kB
packages/db/dist/esm/query/compiler/lazy-targets.js 923 B
packages/db/dist/esm/query/compiler/order-by.js 1.74 kB
packages/db/dist/esm/query/compiler/select.js 1.53 kB
packages/db/dist/esm/query/effect.js 4.77 kB
packages/db/dist/esm/query/expression-helpers.js 1.43 kB
packages/db/dist/esm/query/ir.js 1.25 kB
packages/db/dist/esm/query/live-query-collection.js 360 B
packages/db/dist/esm/query/live/collection-config-builder.js 9.32 kB
packages/db/dist/esm/query/live/collection-registry.js 264 B
packages/db/dist/esm/query/live/collection-subscriber.js 1.95 kB
packages/db/dist/esm/query/live/internal.js 145 B
packages/db/dist/esm/query/live/utils.js 1.81 kB
packages/db/dist/esm/query/optimizer.js 2.92 kB
packages/db/dist/esm/query/predicate-utils.js 2.97 kB
packages/db/dist/esm/query/query-once.js 359 B
packages/db/dist/esm/query/subset-dedupe.js 960 B
packages/db/dist/esm/scheduler.js 1.3 kB
packages/db/dist/esm/SortedMap.js 1.3 kB
packages/db/dist/esm/strategies/debounceStrategy.js 247 B
packages/db/dist/esm/strategies/queueStrategy.js 428 B
packages/db/dist/esm/strategies/throttleStrategy.js 246 B
packages/db/dist/esm/transactions.js 3.04 kB
packages/db/dist/esm/utils.js 927 B
packages/db/dist/esm/utils/array-utils.js 273 B
packages/db/dist/esm/utils/browser-polyfills.js 304 B
packages/db/dist/esm/utils/btree.js 5.61 kB
packages/db/dist/esm/utils/comparison.js 1.15 kB
packages/db/dist/esm/utils/cursor.js 457 B
packages/db/dist/esm/utils/index-optimization.js 2.39 kB
packages/db/dist/esm/utils/type-guards.js 157 B
packages/db/dist/esm/utils/uuid.js 449 B
packages/db/dist/esm/virtual-props.js 360 B

compressed-size-action::db-package-size

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 3.79 kB

ℹ️ View Unchanged
Filename Size
packages/react-db/dist/esm/index.js 249 B
packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.29 kB
packages/react-db/dist/esm/useLiveQuery.js 920 B
packages/react-db/dist/esm/useLiveQueryEffect.js 355 B
packages/react-db/dist/esm/useLiveSuspenseQuery.js 567 B
packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

@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: 1

🧹 Nitpick comments (1)
packages/db/tests/query/includes-oracle.property.test.ts (1)

1304-1314: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add an explicit return type.

scalarNoiseArbitrary has no return type annotation. Add : fc.Arbitrary<VisibleScalarNoise>.

As per coding guidelines, “Always provide the most precise return type annotation.”

🤖 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/db/tests/query/includes-oracle.property.test.ts` around lines 1304 -
1314, Update the scalarNoiseArbitrary helper’s declaration to explicitly return
fc.Arbitrary<VisibleScalarNoise>, while preserving its existing parameters and
generated record behavior.

Source: Coding guidelines

🤖 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/db/tests/query/includes-oracle.property.test.ts`:
- Around line 1897-1911: Update the
rejects-overlapping-visible-relationship-keys fixture in fcTest to use disjoint
idBase values while retaining colliding groupBase values, so it specifically
exercises relationship-group overlap. Add a separate case where only rekeyGroup
collides with an existing group, ensuring ID keys remain disjoint.

---

Nitpick comments:
In `@packages/db/tests/query/includes-oracle.property.test.ts`:
- Around line 1304-1314: Update the scalarNoiseArbitrary helper’s declaration to
explicitly return fc.Arbitrary<VisibleScalarNoise>, while preserving its
existing parameters and generated record behavior.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8b01d34a-d5b2-4289-a867-45d7bc077cdb

📥 Commits

Reviewing files that changed from the base of the PR and between 77539d2 and 789718f.

📒 Files selected for processing (1)
  • packages/db/tests/query/includes-oracle.property.test.ts

Comment thread packages/db/tests/query/includes-oracle.property.test.ts Outdated
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.

1 participant