Skip to content

Materialize vault deltas for balance sync - #2592

Merged
graphite-app[bot] merged 1 commit into
mainfrom
arda/derived-vault-deltas-standalone
May 26, 2026
Merged

Materialize vault deltas for balance sync#2592
graphite-app[bot] merged 1 commit into
mainfrom
arda/derived-vault-deltas-standalone

Conversation

@findolor

@findolor findolor commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add derived_vault_deltas as a pipeline-maintained read model for the existing vault_deltas view output
  • refresh derived vault deltas in the apply transaction before vault_balance_changes / running_vault_balances
  • switch vault balance maintenance SQL to read derived_vault_deltas instead of recomputing the view
  • include the table in required schema, clear/reset paths, export/import, and bump local DB schema version from 3 to 4

This PR is standalone on main and does not depend on the derived-trades stack.

Benchmarks

Measured with nix develop on a copied Base ST0x local DB, not the live DB.

Before this PR, the same balance maintenance path measured:

  • recent 10k window: ~13.38s combined vault upsert batch
  • busy window: upsert running_vault_balances alone hit ~184.54s

With derived_vault_deltas backfilled on the copy:

  • one-time full derived backfill: ~6.65s for 29,682 rows
  • recent 10k window: insert changes ~2.19ms, update running balances ~4.53ms
  • densest 10k window found: 644 derived rows, insert changes ~91.33ms, update running balances ~56.28ms

Tests

  • COMMIT_SHA=local nix develop -c cargo test -p raindex_common local_db::query --lib
  • COMMIT_SHA=local nix develop -c cargo test -p raindex_common local_db::pipeline::adapters::apply --lib
  • COMMIT_SHA=local nix develop -c cargo test -p raindex_common local_db::export --lib
  • COMMIT_SHA=local nix develop -c cargo test -p raindex_common raindex_client::local_db::pipeline::bootstrap --lib
  • COMMIT_SHA=local nix develop -c cargo test -p raindex_app_settings local_db_manifest --lib

Summary by CodeRabbit

  • New Features

    • Added a derived vault-deltas read model with windowed refreshes; pipeline now refreshes it during processing.
  • Bug Fixes / Behavior

    • Balance upserts now use derived deltas for consistent running balances and correct incremental updates.
    • Clear/reset operations now include derived deltas.
    • Sync scheduler marks chains as ready even when not leader.
  • Chores

    • Bumped DB schema to v4; tests/fixtures updated.
    • UI table shows an initial loading skeleton.
    • Updated registry URL.

Review Change Stack

findolor commented May 22, 2026

Copy link
Copy Markdown
Collaborator Author

How to use the Graphite Merge Queue

Add the label Raindex-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

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

Adds a maintained derived_vault_deltas read-model: schema + indexes, a delete+insert upsert batch with unit and SQLite integration tests, pipeline wiring (after decoded inserts, before vault-balance upserts), downstream query rewires, DB schema bump to v4 with test fixture updates, scheduler readiness changes, and UI/constant tweaks.

Changes

Derived Vault Deltas Read-Model

Layer / File(s) Summary
Schema definition & cleanup
crates/common/src/local_db/query/create_tables/query.sql, crates/common/src/local_db/query/create_tables/mod.rs, crates/common/src/local_db/query/clear_tables/query.sql, crates/common/src/local_db/query/clear_raindex_data/query.sql
Adds derived_vault_deltas table and indexes, registers it in required tables, and adds DROP/DELETE handling in clear_tables and clear_raindex_data.
Upsert batch function & tests
crates/common/src/local_db/query/upsert_derived_vault_deltas/*
Adds upsert_derived_vault_deltas_batch() producing a window-bounded DELETE then INSERT OR REPLACE; includes unit tests and SQLite integration tests for full and incremental rebuilds.
Module export
crates/common/src/local_db/query/mod.rs
Exports the new upsert_derived_vault_deltas query module.
Pipeline integration & ordering
crates/common/src/local_db/pipeline/adapters/apply.rs
Calls the upsert batch in ApplyPipeline::build_batch when start_block ≤ target_block, placed after decoded-event inserts and before vault-balance upserts; pipeline tests updated for ordering and empty-window emissions.
Downstream query rewrites
crates/common/src/local_db/query/upsert_vault_balances/*
Vault balance upserts now read deltas from derived_vault_deltas in filtered/latest-block CTEs and correlated subqueries.
Manifest schema bump & test fixtures
crates/settings/src/local_db_manifest.rs, crates/settings/src/remote/manifest.rs, crates/common/src/local_db/pipeline/runner/{environment,remotes}.rs, crates/cli/.../manifest.rs
Bumps DB_SCHEMA_VERSION to 4 and updates numerous YAML fixtures, mocked remote manifests, and unit tests to expect schema version 4.

Scheduler readiness

Layer / File(s) Summary
Native scheduler readiness
crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/native.rs
Marks chain ready and records readiness on RunOutcome::NotLeader; adjusts native test to expect readiness.
WASM scheduler readiness
crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/wasm.rs
Same readiness marking for wasm path and test updated to assert readiness observable post-NotLeader.

UI & constants

Layer / File(s) Summary
Table initial-loading handling
packages/ui-components/src/lib/components/TanstackAppTable.svelte, packages/ui-components/src/__tests__/TanstackAppTable.test.ts
Introduces isInitialLoading derived state to render a loading skeleton when query is initially loading; adds test to assert skeleton vs empty message.
Registry URL constant
packages/webapp/src/lib/constants.ts
Updates REGISTRY_URL to a different commit hash in the raw GitHub URL.

Sequence Diagram

sequenceDiagram
  participant ApplyPipeline
  participant UpsertBatch as upsert_derived_vault_deltas_batch
  participant DB
  participant VaultBalances as UpsertVaultBalances
  ApplyPipeline->>UpsertBatch: build_batch(start_block, target_block, raindex)
  UpsertBatch->>DB: DELETE FROM derived_vault_deltas WHERE block_number BETWEEN start..end
  UpsertBatch->>DB: INSERT OR REPLACE INTO derived_vault_deltas SELECT ... FROM vault_deltas vd WHERE block_number BETWEEN start..end
  ApplyPipeline->>VaultBalances: trigger vault balance upsert (reads derived_vault_deltas)
  VaultBalances->>DB: SELECT from derived_vault_deltas for running_balance computation
  DB->>VaultBalances: rows for balance aggregation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • rainlanguage/raindex#2583: Related to local-DB schema/version handling and bootstrap/reset behavior tied to schema changes.

Suggested reviewers

  • 0xgleb
  • JuaniRios
  • hardyjosh

Poem

🐰 A vault of deltas, derived and clean,
With blocks and indices in between,
The pipeline rebuilds each careful row,
Balances settle where the deltas go,
Hop—refresh—commit, and watch the numbers gleam!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.21% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Materialize vault deltas for balance sync' accurately summarizes the main change: adding a materialized table for vault deltas to improve balance synchronization performance.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 arda/derived-vault-deltas-standalone

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/ui-components/src/__tests__/TanstackAppTable.test.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: ESLint configuration in --config is invalid:

  • Unexpected top-level property "__esModule".

    at ConfigValidator.validateConfigSchema (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2177:19)
    at ConfigArrayFactory._normalizeConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3019:19)
    at ConfigArrayFactory._loadConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:21)
    at ConfigArrayFactory.loadFile (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
    at createCLIConfigArray (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)
    at new CascadingConfigArrayFactory (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3735:29)
    at new CLIEngine (/node_modules/eslint/lib/cli-engine/cli-engine.js:617:36)
    at new ESLint (/node_modules/eslint/lib/eslint/eslint.js:430:27)
    at Object.execute (/node_modules/eslint/lib/cli.js:410:24)
    at async main (/node_modules/eslint/bin/eslint.js:152:22)

packages/ui-components/src/lib/components/TanstackAppTable.svelte

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: ESLint configuration in --config is invalid:

  • Unexpected top-level property "__esModule".

    at ConfigValidator.validateConfigSchema (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2177:19)
    at ConfigArrayFactory._normalizeConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3019:19)
    at ConfigArrayFactory._loadConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:21)
    at ConfigArrayFactory.loadFile (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
    at createCLIConfigArray (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)
    at new CascadingConfigArrayFactory (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3735:29)
    at new CLIEngine (/node_modules/eslint/lib/cli-engine/cli-engine.js:617:36)
    at new ESLint (/node_modules/eslint/lib/eslint/eslint.js:430:27)
    at Object.execute (/node_modules/eslint/lib/cli.js:410:24)
    at async main (/node_modules/eslint/bin/eslint.js:152:22)

packages/webapp/src/lib/constants.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: ESLint configuration in --config is invalid:

  • Unexpected top-level property "__esModule".

    at ConfigValidator.validateConfigSchema (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2177:19)
    at ConfigArrayFactory._normalizeConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3019:19)
    at ConfigArrayFactory._loadConfigData (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2984:21)
    at ConfigArrayFactory.loadFile (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2850:40)
    at createCLIConfigArray (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3660:35)
    at new CascadingConfigArrayFactory (/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3735:29)
    at new CLIEngine (/node_modules/eslint/lib/cli-engine/cli-engine.js:617:36)
    at new ESLint (/node_modules/eslint/lib/eslint/eslint.js:430:27)
    at Object.execute (/node_modules/eslint/lib/cli.js:410:24)
    at async main (/node_modules/eslint/bin/eslint.js:152:22)


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 and usage tips.

@findolor findolor self-assigned this May 22, 2026
@findolor
findolor force-pushed the arda/derived-vault-deltas-standalone branch 2 times, most recently from d36008f to fbd5d6b Compare May 24, 2026 14:13

@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

🤖 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 `@crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs`:
- Around line 8-17: The batch builder upsert_derived_vault_deltas_batch must
guard against an inverted block window (start_block > end_block) so it doesn't
silently produce empty BETWEEN predicates; update
upsert_derived_vault_deltas_batch to check the window and either normalize it
(swap start/end) or return an explicit no-op SqlStatementBatch (empty) when
start_block > end_block, and ensure this check happens before calling
delete_derived_vault_deltas_stmt and insert_derived_vault_deltas_stmt to avoid
generating statements with empty ranges.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8605a942-d4e7-4348-8327-e65562aae98f

📥 Commits

Reviewing files that changed from the base of the PR and between c16b41a and fbd5d6b.

📒 Files selected for processing (15)
  • crates/cli/src/commands/local_db/pipeline/runner/manifest.rs
  • crates/common/src/local_db/pipeline/adapters/apply.rs
  • crates/common/src/local_db/pipeline/runner/environment.rs
  • crates/common/src/local_db/pipeline/runner/remotes.rs
  • crates/common/src/local_db/query/clear_raindex_data/query.sql
  • crates/common/src/local_db/query/clear_tables/query.sql
  • crates/common/src/local_db/query/create_tables/mod.rs
  • crates/common/src/local_db/query/create_tables/query.sql
  • crates/common/src/local_db/query/mod.rs
  • crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs
  • crates/common/src/local_db/query/upsert_derived_vault_deltas/query.sql
  • crates/common/src/local_db/query/upsert_vault_balances/insert_balance_changes.sql
  • crates/common/src/local_db/query/upsert_vault_balances/insert_running_balances.sql
  • crates/settings/src/local_db_manifest.rs
  • crates/settings/src/remote/manifest.rs
✅ Files skipped from review due to trivial changes (4)
  • crates/common/src/local_db/query/clear_raindex_data/query.sql
  • crates/common/src/local_db/query/mod.rs
  • crates/common/src/local_db/query/clear_tables/query.sql
  • crates/settings/src/remote/manifest.rs

Comment on lines +8 to +17
pub fn upsert_derived_vault_deltas_batch(
raindex_id: &RaindexIdentifier,
start_block: u64,
end_block: u64,
) -> SqlStatementBatch {
SqlStatementBatch::from(vec![
delete_derived_vault_deltas_stmt(raindex_id, start_block, end_block),
insert_derived_vault_deltas_stmt(raindex_id, start_block, end_block),
])
}

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against inverted block windows in batch construction.

If start_block > end_block, both BETWEEN ?3 AND ?4 predicates become empty and the rebuild silently does nothing, which can leave stale rows in derived_vault_deltas.

Suggested fix
 pub fn upsert_derived_vault_deltas_batch(
     raindex_id: &RaindexIdentifier,
     start_block: u64,
     end_block: u64,
 ) -> SqlStatementBatch {
+    let (start_block, end_block) = if start_block <= end_block {
+        (start_block, end_block)
+    } else {
+        (end_block, start_block)
+    };
+
     SqlStatementBatch::from(vec![
         delete_derived_vault_deltas_stmt(raindex_id, start_block, end_block),
         insert_derived_vault_deltas_stmt(raindex_id, start_block, end_block),
     ])
 }
🤖 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 `@crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs` around
lines 8 - 17, The batch builder upsert_derived_vault_deltas_batch must guard
against an inverted block window (start_block > end_block) so it doesn't
silently produce empty BETWEEN predicates; update
upsert_derived_vault_deltas_batch to check the window and either normalize it
(swap start/end) or return an explicit no-op SqlStatementBatch (empty) when
start_block > end_block, and ensure this check happens before calling
delete_derived_vault_deltas_stmt and insert_derived_vault_deltas_stmt to avoid
generating statements with empty ranges.

@findolor
findolor changed the base branch from main to graphite-base/2592 May 25, 2026 11:11
@findolor
findolor force-pushed the arda/derived-vault-deltas-standalone branch from fbd5d6b to 087150a Compare May 25, 2026 11:11
@findolor
findolor changed the base branch from graphite-base/2592 to local-db-manifest-urls May 25, 2026 11:11
@graphite-app
graphite-app Bot changed the base branch from local-db-manifest-urls to graphite-base/2592 May 26, 2026 06:13
@findolor
findolor force-pushed the arda/derived-vault-deltas-standalone branch from 087150a to 6f9e176 Compare May 26, 2026 07:22
@findolor
findolor force-pushed the graphite-base/2592 branch from 3f8691a to 7e32a38 Compare May 26, 2026 07:22
@findolor
findolor changed the base branch from graphite-base/2592 to local-db-manifest-urls May 26, 2026 07:22
@graphite-app
graphite-app Bot changed the base branch from local-db-manifest-urls to main May 26, 2026 07:41
@findolor
findolor force-pushed the arda/derived-vault-deltas-standalone branch from bab7d79 to d6970b6 Compare May 26, 2026 07:57

@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

♻️ Duplicate comments (1)
crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs (1)

8-16: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard inverted block windows before constructing statements.

If start_block > end_block, both BETWEEN ?3 AND ?4 clauses no-op and the targeted window is not refreshed.

Suggested fix
 pub fn upsert_derived_vault_deltas_batch(
     raindex_id: &RaindexIdentifier,
     start_block: u64,
     end_block: u64,
 ) -> SqlStatementBatch {
+    let (start_block, end_block) = if start_block <= end_block {
+        (start_block, end_block)
+    } else {
+        (end_block, start_block)
+    };
+
     SqlStatementBatch::from(vec![
         delete_derived_vault_deltas_stmt(raindex_id, start_block, end_block),
         insert_derived_vault_deltas_stmt(raindex_id, start_block, end_block),
     ])
 }
🤖 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 `@crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs` around
lines 8 - 16, In upsert_derived_vault_deltas_batch, guard against inverted block
windows by checking if start_block > end_block before building the statements
(the calls to delete_derived_vault_deltas_stmt and
insert_derived_vault_deltas_stmt); if the window is inverted, return an empty
SqlStatementBatch (or otherwise no-op) instead of constructing statements with
BETWEEN ?3 AND ?4 that will silently no-op, otherwise proceed to construct and
return the batch as before.
🤖 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/ui-components/src/lib/components/TanstackAppTable.svelte`:
- Around line 214-326: The PR is missing the required screenshot demonstrating
the frontend change in
packages/ui-components/src/lib/components/TanstackAppTable.svelte; please build
the app and capture a screenshot showing each visible state (loading skeleton -
element with data-testid="tableLoadingSkeleton", empty state -
data-testid="emptyMessage" showing emptyMessage text, populated table -
container data-testid="tanstackTableContainer" with rows rendered, and the "Load
More" button data-testid="loadMoreButton" in both enabled/disabled states as
applicable), then attach the image(s) to the pull request (or upload to the CI
artifacts for the build) so reviewers can verify the UI change.

---

Duplicate comments:
In `@crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs`:
- Around line 8-16: In upsert_derived_vault_deltas_batch, guard against inverted
block windows by checking if start_block > end_block before building the
statements (the calls to delete_derived_vault_deltas_stmt and
insert_derived_vault_deltas_stmt); if the window is inverted, return an empty
SqlStatementBatch (or otherwise no-op) instead of constructing statements with
BETWEEN ?3 AND ?4 that will silently no-op, otherwise proceed to construct and
return the batch as before.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 917aa396-bf81-413f-b5e3-a72aff005179

📥 Commits

Reviewing files that changed from the base of the PR and between fbd5d6b and d6970b6.

📒 Files selected for processing (20)
  • crates/cli/src/commands/local_db/pipeline/runner/manifest.rs
  • crates/common/src/local_db/pipeline/adapters/apply.rs
  • crates/common/src/local_db/pipeline/runner/environment.rs
  • crates/common/src/local_db/pipeline/runner/remotes.rs
  • crates/common/src/local_db/query/clear_raindex_data/query.sql
  • crates/common/src/local_db/query/clear_tables/query.sql
  • crates/common/src/local_db/query/create_tables/mod.rs
  • crates/common/src/local_db/query/create_tables/query.sql
  • crates/common/src/local_db/query/mod.rs
  • crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs
  • crates/common/src/local_db/query/upsert_derived_vault_deltas/query.sql
  • crates/common/src/local_db/query/upsert_vault_balances/insert_balance_changes.sql
  • crates/common/src/local_db/query/upsert_vault_balances/insert_running_balances.sql
  • crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/native.rs
  • crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/wasm.rs
  • crates/settings/src/local_db_manifest.rs
  • crates/settings/src/remote/manifest.rs
  • packages/ui-components/src/__tests__/TanstackAppTable.test.ts
  • packages/ui-components/src/lib/components/TanstackAppTable.svelte
  • packages/webapp/src/lib/constants.ts
✅ Files skipped from review due to trivial changes (2)
  • crates/common/src/local_db/query/clear_tables/query.sql
  • crates/cli/src/commands/local_db/pipeline/runner/manifest.rs

Comment thread packages/ui-components/src/lib/components/TanstackAppTable.svelte
@graphite-app

graphite-app Bot commented May 26, 2026

Copy link
Copy Markdown

Merge activity

## Summary
- add `derived_vault_deltas` as a pipeline-maintained read model for the existing `vault_deltas` view output
- refresh derived vault deltas in the apply transaction before `vault_balance_changes` / `running_vault_balances`
- switch vault balance maintenance SQL to read `derived_vault_deltas` instead of recomputing the view
- include the table in required schema, clear/reset paths, export/import, and bump local DB schema version from 3 to 4

This PR is standalone on `main` and does not depend on the derived-trades stack.

## Benchmarks
Measured with `nix develop` on a copied Base ST0x local DB, not the live DB.

Before this PR, the same balance maintenance path measured:
- recent 10k window: ~13.38s combined vault upsert batch
- busy window: `upsert running_vault_balances` alone hit ~184.54s

With `derived_vault_deltas` backfilled on the copy:
- one-time full derived backfill: ~6.65s for 29,682 rows
- recent 10k window: insert changes ~2.19ms, update running balances ~4.53ms
- densest 10k window found: 644 derived rows, insert changes ~91.33ms, update running balances ~56.28ms

## Tests
- `COMMIT_SHA=local nix develop -c cargo test -p raindex_common local_db::query --lib`
- `COMMIT_SHA=local nix develop -c cargo test -p raindex_common local_db::pipeline::adapters::apply --lib`
- `COMMIT_SHA=local nix develop -c cargo test -p raindex_common local_db::export --lib`
- `COMMIT_SHA=local nix develop -c cargo test -p raindex_common raindex_client::local_db::pipeline::bootstrap --lib`
- `COMMIT_SHA=local nix develop -c cargo test -p raindex_app_settings local_db_manifest --lib`

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added a derived vault-deltas read-model with windowed refreshes; pipeline now refreshes it during processing.

* **Bug Fixes / Behavior**
  * Balance upserts now use derived deltas for consistent running balances and correct incremental updates.
  * Clear/reset operations now include derived deltas.
  * Sync scheduler marks chains as ready even when not leader.

* **Chores**
  * Bumped DB schema to v4; tests/fixtures updated.
  * UI table now shows an initial loading skeleton.
  * Updated registry URL.

<!-- review_stack_entry_start -->

[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/rainlanguage/raindex/pull/2592?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@graphite-app
graphite-app Bot force-pushed the arda/derived-vault-deltas-standalone branch from ab3eb52 to 691e0ff Compare May 26, 2026 14:27

@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

Caution

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

⚠️ Outside diff range comments (1)
crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/wasm.rs (1)

512-513: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

The NotLeader readiness assertion is not isolated from leader recovery in this test.

With Line 512 including a succeeding Some(false) cycle, readiness at Line 559 can be set by the leader path rather than the NotLeader branch.

Proposed test hardening
-        let runner = RecordingRunner::new(
+        let runner = RecordingRunner::new(
             1,
             Rc::clone(&calls),
             Rc::clone(&failures),
-            vec![None, Some(false)],
+            vec![None],
         );

         spawn_network_loop(
             runner,
             noop_local_db(),
             Some(Rc::new(status_callback)),
             Rc::clone(&stop_flag),
-            1,
+            10_000,
             readiness.clone(),
             LocalDbSyncStatusStore::new(),
         );

-        TimeoutFuture::new(0).await;
-        TimeoutFuture::new(5).await;
+        while calls.get() < 1 {
+            TimeoutFuture::new(1).await;
+        }

         stop_flag.set(true);
         TimeoutFuture::new(5).await;

Also applies to: 528-529, 558-561

🤖 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
`@crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/native.rs`:
- Around line 584-586: The test network_loop_handles_not_leader is seeding
RecordingRunner with a single None so the runner can fall through to a later
success outcome instead of exercising the NotLeader readiness path; modify the
RecordingRunner::new invocation (and analogous calls around RecordingRunner
usage) to supply enough None entries or explicit NotLeader outcomes (e.g.,
vec![None, None, Some(NotLeader(...))] or explicit failure entries) to cover the
leader readiness check path so readiness at the place currently checked by the
test comes from the intended NotLeader scenario; update any related
stop_flag/runner setup to match the expanded outcome sequence so the test
deterministically exercises the NotLeader readiness branch.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f640014c-7d59-4ca3-abf6-4b341bce1ca9

📥 Commits

Reviewing files that changed from the base of the PR and between ab3eb52 and 691e0ff.

📒 Files selected for processing (20)
  • crates/cli/src/commands/local_db/pipeline/runner/manifest.rs
  • crates/common/src/local_db/pipeline/adapters/apply.rs
  • crates/common/src/local_db/pipeline/runner/environment.rs
  • crates/common/src/local_db/pipeline/runner/remotes.rs
  • crates/common/src/local_db/query/clear_raindex_data/query.sql
  • crates/common/src/local_db/query/clear_tables/query.sql
  • crates/common/src/local_db/query/create_tables/mod.rs
  • crates/common/src/local_db/query/create_tables/query.sql
  • crates/common/src/local_db/query/mod.rs
  • crates/common/src/local_db/query/upsert_derived_vault_deltas/mod.rs
  • crates/common/src/local_db/query/upsert_derived_vault_deltas/query.sql
  • crates/common/src/local_db/query/upsert_vault_balances/insert_balance_changes.sql
  • crates/common/src/local_db/query/upsert_vault_balances/insert_running_balances.sql
  • crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/native.rs
  • crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/wasm.rs
  • crates/settings/src/local_db_manifest.rs
  • crates/settings/src/remote/manifest.rs
  • packages/ui-components/src/__tests__/TanstackAppTable.test.ts
  • packages/ui-components/src/lib/components/TanstackAppTable.svelte
  • packages/webapp/src/lib/constants.ts
✅ Files skipped from review due to trivial changes (4)
  • crates/common/src/local_db/query/mod.rs
  • crates/common/src/local_db/query/clear_tables/query.sql
  • crates/common/src/local_db/query/upsert_vault_balances/insert_running_balances.sql
  • packages/webapp/src/lib/constants.ts

Comment on lines +584 to 586
let runner =
RecordingRunner::new(Arc::clone(&calls), Arc::clone(&failures), vec![None]);
let stop_flag = Arc::new(AtomicBool::new(false));

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

network_loop_handles_not_leader can pass without actually validating the NotLeader readiness path.

Line 585 only seeds one None, but the runner falls back to success once outcomes are exhausted; readiness at Line 609 can therefore come from a later leader cycle.

Proposed test hardening
-                let runner =
-                    RecordingRunner::new(Arc::clone(&calls), Arc::clone(&failures), vec![None]);
+                let runner =
+                    RecordingRunner::new(Arc::clone(&calls), Arc::clone(&failures), vec![None]);

                 tokio::task::spawn_local(run_network_loop(
                     runner,
                     noop_local_db(),
                     NativeNetworkLoopContext {
                         stop_flag: Arc::clone(&stop_flag),
-                        interval_ms: 1,
+                        interval_ms: 10_000,
                         network_key: "test".to_string(),
                         chain_id: 1,
                         sync_readiness: readiness.clone(),
                         status_store: LocalDbSyncStatusStore::new(),
                     },
                 ));

-                tokio::time::sleep(std::time::Duration::from_millis(30)).await;
+                for _ in 0..100 {
+                    if calls.load(Ordering::SeqCst) >= 1 {
+                        break;
+                    }
+                    tokio::time::sleep(std::time::Duration::from_millis(1)).await;
+                }
                 stop_flag.store(true, Ordering::SeqCst);
                 tokio::time::sleep(std::time::Duration::from_millis(10)).await;

-                assert!(calls.load(Ordering::SeqCst) >= 1);
+                assert_eq!(calls.load(Ordering::SeqCst), 1);

Also applies to: 606-610

🤖 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
`@crates/common/src/raindex_client/local_db/pipeline/runner/scheduler/native.rs`
around lines 584 - 586, The test network_loop_handles_not_leader is seeding
RecordingRunner with a single None so the runner can fall through to a later
success outcome instead of exercising the NotLeader readiness path; modify the
RecordingRunner::new invocation (and analogous calls around RecordingRunner
usage) to supply enough None entries or explicit NotLeader outcomes (e.g.,
vec![None, None, Some(NotLeader(...))] or explicit failure entries) to cover the
leader readiness check path so readiness at the place currently checked by the
test comes from the intended NotLeader scenario; update any related
stop_flag/runner setup to match the expanded outcome sequence so the test
deterministically exercises the NotLeader readiness branch.

@graphite-app
graphite-app Bot merged commit 691e0ff into main May 26, 2026
18 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

@coderabbitai assess this PR size classification for the totality of the PR with the following criterias and report it in your comment:

S/M/L PR Classification Guidelines:

This guide helps classify merged pull requests by effort and complexity rather than just line count. The goal is to assess the difficulty and scope of changes after they have been completed.

Small (S)

Characteristics:

  • Simple bug fixes, typos, or minor refactoring
  • Single-purpose changes affecting 1-2 files
  • Documentation updates
  • Configuration tweaks
  • Changes that require minimal context to review

Review Effort: Would have taken 5-10 minutes

Examples:

  • Fix typo in variable name
  • Update README with new instructions
  • Adjust configuration values
  • Simple one-line bug fixes
  • Import statement cleanup

Medium (M)

Characteristics:

  • Feature additions or enhancements
  • Refactoring that touches multiple files but maintains existing behavior
  • Breaking changes with backward compatibility
  • Changes requiring some domain knowledge to review

Review Effort: Would have taken 15-30 minutes

Examples:

  • Add new feature or component
  • Refactor common utility functions
  • Update dependencies with minor breaking changes
  • Add new component with tests
  • Performance optimizations
  • More complex bug fixes

Large (L)

Characteristics:

  • Major feature implementations
  • Breaking changes or API redesigns
  • Complex refactoring across multiple modules
  • New architectural patterns or significant design changes
  • Changes requiring deep context and multiple review rounds

Review Effort: Would have taken 45+ minutes

Examples:

  • Complete new feature with frontend/backend changes
  • Protocol upgrades or breaking changes
  • Major architectural refactoring
  • Framework or technology upgrades

Additional Factors to Consider

When deciding between sizes, also consider:

  • Test coverage impact: More comprehensive test changes lean toward larger classification
  • Risk level: Changes to critical systems bump up a size category
  • Team familiarity: Novel patterns or technologies increase complexity

Notes:

  • the assessment must be for the totality of the PR, that means comparing the base branch to the last commit of the PR
  • the assessment output must be exactly one of: S, M or L (single-line comment) in format of: SIZE={S/M/L}
  • do not include any additional text, only the size classification
  • your assessment comment must not include tips or additional sections
  • do NOT tag me or anyone else on your comment

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

SIZE=L

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.

3 participants