Skip to content

Conversation

@davidli1997
Copy link
Contributor

@davidli1997 davidli1997 commented Oct 27, 2025

Changelist

[Describe or list the changes made in this PR]

Test Plan

[Describe how this PR was tested (if applicable)]

Author/Reviewer Checklist

  • If this PR has changes that result in a different app state given the same prior state and transaction list, manually add the state-breaking label.
  • If the PR has breaking postgres changes to the indexer add the indexer-postgres-breaking label.
  • If this PR isn't state-breaking but has changes that modify behavior in PrepareProposal or ProcessProposal, manually add the label proposal-breaking.
  • If this PR is one of many that implement a specific feature, manually label them all feature:[feature-name].
  • If you wish to for mergify-bot to automatically create a PR to backport your change to a release branch, manually add the label backport/[branch-name].
  • Manually add any of the following labels: refactor, chore, bug.

Summary by CodeRabbit

  • New Features

    • Hourly and daily vault PnL materialized views with indexed aggregation.
    • Retrieve PnL for custom time windows and fetch latest PnL snapshot per vault.
    • Bulk insertion for PnL records.
    • Athena table definitions for PnL exports.
    • New public PnL view export and interval type for hour/day.
  • Tests

    • New tests validating hourly/daily aggregation, time-window rules, latest-PnL, and cross-validation with legacy view.
  • Chores

    • Refresh task updated to refresh legacy and new PnL views in parallel.
  • CI

    • Build workflows now trigger for an additional branch pattern.

@davidli1997 davidli1997 requested a review from a team as a code owner October 27, 2025 22:08
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 27, 2025

Walkthrough

Adds two new materialized views (hourly/daily) with migrations, a VaultPnl view store (refresh + query functions), bulk PnL insert helper, PnlInterval enum, tests for new views, updates roundtable refresh task to refresh old and new views in parallel, adds Athena DDL helpers for pnl, and adds CI branch trigger patterns.

Changes

Cohort / File(s) Summary
Migrations (materialized views)
indexer/packages/postgres/src/db/migrations/migration_files/20251027172540_create_vaults_hourly_pnl_v2.ts, indexer/packages/postgres/src/db/migrations/migration_files/20251027172547_create_vaults_daily_pnl_v2.ts
Add migrations creating materialized views vaults_hourly_pnl_v2 and vaults_daily_pnl_v2 (multi-CTE aggregation, dedupe by hour/day, recent-window filtering) and unique indexes on (subaccountId, createdAt); include down migrations to drop views.
Vault PnL view store & export
indexer/packages/postgres/src/stores/vault-pnl-view.ts, indexer/packages/postgres/src/index.ts
New store exposing refreshHourlyView(), refreshDailyView(), getVaultsPnl(), getLatestVaultPnl(); exported as VaultPnlView from package index.
PnL table store
indexer/packages/postgres/src/stores/pnl-table.ts
Add createMany(pnls, options) to bulk-insert multiple PnL records (transaction-aware) and return inserted rows.
Types
indexer/packages/postgres/src/types/pnl-types.ts
Add PnlInterval enum (`'hour'
Tests
indexer/packages/postgres/__tests__/stores/vault-pnl-view.test.ts, indexer/services/roundtable/__tests__/tasks/refresh-vault-pnl.test.ts
New test suite for VaultPnl view aggregation and latest-PnL retrieval; roundtable tests updated to seed and assert both old and new views and to refresh both views in afterEach.
Roundtable task & Athena
indexer/services/roundtable/src/tasks/refresh-vault-pnl.ts, indexer/services/roundtable/src/lib/athena-ddl-tables/pnl.ts, indexer/services/roundtable/src/tasks/update-research-environment.ts
Refresh task updated to refresh old (VaultPnlTicksView) and new (VaultPnlView) views in parallel; add Athena DDL helpers for pnl and register it in Athena table registry.
CI workflows
.github/workflows/indexer-build-and-push-dev-staging.yml, .github/workflows/protocol-build-and-push-snapshot.yml, .github/workflows/protocol-build-and-push.yml
Add new_vault_tables branch pattern to workflow push triggers.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Test as Test Suite
    participant PnlTable as PnL Table Store
    participant DB as Postgres
    participant VaultPnlView as VaultPnlView Module
    participant OldView as VaultPnlTicksView
    participant Roundtable as Refresh Task

    Test->>PnlTable: createMany(pnlRecords)
    PnlTable-->>DB: INSERT many rows
    DB-->>Test: insert result

    Test->>VaultPnlView: refreshHourlyView()
    VaultPnlView->>DB: REFRESH MATERIALIZED VIEW vaults_hourly_pnl_v2 CONCURRENTLY
    DB-->>VaultPnlView: refreshed

    Test->>VaultPnlView: refreshDailyView()
    VaultPnlView->>DB: REFRESH MATERIALIZED VIEW vaults_daily_pnl_v2 CONCURRENTLY
    DB-->>VaultPnlView: refreshed

    Note over Roundtable,VaultPnlView: Roundtable performs parallel refreshes for each view
    Roundtable->>VaultPnlView: refresh hourly & daily (Promise.all)
    Roundtable->>OldView: refresh hourly & daily (Promise.all)
    VaultPnlView->>DB: REFRESH MATERIALIZED VIEW ...
    OldView->>DB: REFRESH MATERIALIZED VIEW ...
    DB-->>Roundtable: both refreshed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas that may need extra attention:
    • SQL correctness, windowing, deduplication, and performance in both migration queries.
    • Time-bound filtering and ordering semantics in getVaultsPnl() and getLatestVaultPnl() (DISTINCT ON ordering).
    • Transaction handling and return-shape of createMany() in pnl-table.ts.
    • Concurrency and error handling when refreshing two views in parallel in refresh-vault-pnl.ts.
    • Tests: ensure test DB seeding/teardown cover both old and new tables consistently.

Possibly related PRs

Suggested reviewers

  • tqin7
  • Kefancao

Poem

🐇 I hopped through rows at break of light,
I indexed hours and days just right,
I refreshed each view with nimble paws,
Subaccounts tallied—no lost cause,
A rabbit cheers: the data’s bright!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description is largely incomplete. The Changelist and Test Plan sections contain only placeholder text ("[Describe or list the changes made in this PR]" and "[Describe how this PR was tested (if applicable)]"), meaning the primary sections are entirely unfilled. The Author/Reviewer Checklist is present but all items remain unchecked, with no labels manually added. This description provides virtually no meaningful information about what changed or how it was tested.
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "New Vault Pnl tables" directly aligns with the changeset, which introduces new materialized views (vaults_hourly_pnl_v2 and vaults_daily_pnl_v2), supporting infrastructure in vault-pnl-view.ts, new type definitions, and updates to existing tasks and tests to work with these views. The title is concise, clear, and accurately captures the primary change without unnecessary verbosity.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch new_vault_tables

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5496cbe and e2e433c.

📒 Files selected for processing (2)
  • .github/workflows/protocol-build-and-push-snapshot.yml (1 hunks)
  • .github/workflows/protocol-build-and-push.yml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (25)
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (go)
  • GitHub Check: (Dev4) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Staging) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Dev2) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: Summary
  • GitHub Check: build-and-push-staging
  • GitHub Check: build-and-push-snapshot-staging
  • GitHub Check: build-and-push-snapshot-dev
  • GitHub Check: build-and-push-snapshot-dev2
  • GitHub Check: build-and-push-dev4
  • GitHub Check: build-and-push-dev2
  • GitHub Check: build-and-push-dev
  • GitHub Check: build-and-push-snapshot-dev4
🔇 Additional comments (2)
.github/workflows/protocol-build-and-push-snapshot.yml (1)

9-9: Verify that the new_vault_tables branch trigger is intentional for permanent inclusion.

Adding a feature branch to the CI workflow triggers suggests this should remain permanent after merge. However, temporary feature branches typically shouldn't persist in workflow configurations post-merge. Please confirm whether:

  1. This branch trigger should be removed before merging to main, or
  2. This is an intentional permanent addition (e.g., if the branch will be long-lived for ongoing feature development).
.github/workflows/protocol-build-and-push.yml (1)

9-9: Verify that the new_vault_tables branch trigger is intentional for permanent inclusion.

Adding a feature branch to the CI workflow triggers suggests this should remain permanent after merge. However, temporary feature branches typically shouldn't persist in workflow configurations post-merge. Please confirm whether:

  1. This branch trigger should be removed before merging to main, or
  2. This is an intentional permanent addition (e.g., if the branch will be long-lived for ongoing feature development).

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (10)
indexer/packages/postgres/src/db/migrations/migration_files/20251027172540_create_vaults_hourly_pnl_v2.ts (4)

1-1: Prefer import { Knex } from 'knex' for types-only import.

Small consistency/readability nit for our migrations.

-import * as Knex from 'knex';
+import { Knex } from 'knex';

11-17: Hard-coded subaccount address — confirm intent and longevity.

The special address inclusion is duplicated across hourly/daily migrations. Confirm this is stable and intended to be permanently included; otherwise, consider documenting the reason in a comment for future maintainers.


34-34: Improve interval readability.

Use interval literals for clarity.

-  AND "createdAt" >= NOW() - interval '604800 second'
+  AND "createdAt" >= NOW() - interval '7 day'

40-43: Initial MV build vs. refresh strategy.

For very large pnl tables, consider:

  • CREATE MATERIALIZED VIEW ... WITH NO DATA
  • CREATE UNIQUE INDEX ...
  • REFRESH MATERIALIZED VIEW CONCURRENTLY ...

This reduces lock impact during the first population.

indexer/packages/postgres/src/db/migrations/migration_files/20251027172547_create_vaults_daily_pnl_v2.ts (4)

1-1: Prefer import { Knex } from 'knex' for types-only import.

-import * as Knex from 'knex';
+import { Knex } from 'knex';

11-17: Hard-coded subaccount address — confirm intent and longevity.

Same note as hourly migration; please document why this address is included and whether it should be configurable for future networks.


34-34: Improve interval readability.

Use a more readable interval literal.

-  AND "createdAt" >= NOW() - interval '7776000 second'
+  AND "createdAt" >= NOW() - interval '90 day'

40-46: Consider initial MV build pattern to minimize locks.

Same operational advice as hourly migration: WITH NO DATA + index + REFRESH CONCURRENTLY.

indexer/packages/postgres/src/stores/vault-pnl-view.ts (1)

12-19: Optional: add a statement timeout to refreshes.

Avoid long blocking refreshes under load by setting a conservative statement timeout via sqlOptions.

 export async function refreshHourlyView(): Promise<void> {
   await rawQuery(
     `REFRESH MATERIALIZED VIEW CONCURRENTLY ${VAULT_HOURLY_PNL_VIEW}`,
     {
       readReplica: false,
+      sqlOptions: { statement_timeout: 60000 }, // 60s; tune as needed
     },
   );
 }

Apply similarly to refreshDailyView.

indexer/packages/postgres/__tests__/stores/vault-pnl-view.test.ts (1)

95-117: LGTM! Test logic is sound, with a minor style suggestion.

The test correctly validates that getLatestVaultPnl returns the most recent PnL record for each subaccount. The expected equity values ('1100' for subaccount1, '200' for subaccount2) match the most recent records created by setupIntervalPnl.

Optional: Remove extra blank line for consistency.

Apply this diff to remove the extra blank line at line 104:

     const latestPnl: PnlFromDatabase[] = await VaultPnlView.getLatestVaultPnl();

     // Should return the most recent PNL for each subaccount
     expect(latestPnl).toHaveLength(2);
-    
+
     const subaccount1Pnl = latestPnl.find(
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55bdb1a and aefbdb5.

📒 Files selected for processing (6)
  • indexer/packages/postgres/__tests__/stores/vault-pnl-view.test.ts (1 hunks)
  • indexer/packages/postgres/src/db/migrations/migration_files/20251027172540_create_vaults_hourly_pnl_v2.ts (1 hunks)
  • indexer/packages/postgres/src/db/migrations/migration_files/20251027172547_create_vaults_daily_pnl_v2.ts (1 hunks)
  • indexer/packages/postgres/src/stores/pnl-table.ts (1 hunks)
  • indexer/packages/postgres/src/stores/vault-pnl-view.ts (1 hunks)
  • indexer/packages/postgres/src/types/pnl-types.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
indexer/packages/postgres/src/db/migrations/migration_files/20251027172547_create_vaults_daily_pnl_v2.ts (1)
indexer/packages/postgres/src/db/migrations/migration_files/20251027172540_create_vaults_hourly_pnl_v2.ts (2)
  • up (40-43)
  • down (45-47)
indexer/packages/postgres/src/stores/vault-pnl-view.ts (2)
indexer/packages/postgres/src/helpers/stores-helpers.ts (1)
  • rawQuery (62-80)
indexer/packages/postgres/src/types/db-model-types.ts (1)
  • PnlFromDatabase (358-365)
indexer/packages/postgres/__tests__/stores/vault-pnl-view.test.ts (4)
indexer/packages/postgres/src/helpers/db-helpers.ts (3)
  • migrate (176-178)
  • clearData (143-159)
  • teardown (180-186)
indexer/packages/postgres/__tests__/helpers/mock-generators.ts (1)
  • seedData (58-107)
indexer/packages/postgres/__tests__/helpers/constants.ts (5)
  • defaultWallet2 (197-201)
  • defaultSubaccountWithAlternateAddress (128-133)
  • defaultVault (1083-1089)
  • defaultSubaccount (85-90)
  • defaultSubaccountIdWithAlternateAddress (172-175)
indexer/packages/postgres/src/types/db-model-types.ts (1)
  • PnlFromDatabase (358-365)
indexer/packages/postgres/src/stores/pnl-table.ts (4)
indexer/packages/postgres/src/types/pnl-types.ts (1)
  • PnlCreateObject (10-17)
indexer/packages/postgres/src/types/utility-types.ts (1)
  • Options (15-25)
indexer/packages/postgres/src/types/db-model-types.ts (1)
  • PnlFromDatabase (358-365)
indexer/packages/postgres/src/models/pnl-model.ts (1)
  • PnlModel (8-64)
indexer/packages/postgres/src/db/migrations/migration_files/20251027172540_create_vaults_hourly_pnl_v2.ts (1)
indexer/packages/postgres/src/db/migrations/migration_files/20251027172547_create_vaults_daily_pnl_v2.ts (2)
  • up (40-43)
  • down (45-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (29)
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Mainnet) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: call-build-ecs-service-comlink / (comlink) Check docker image build
  • GitHub Check: call-build-ecs-service-vulcan / (vulcan) Check docker image build
  • GitHub Check: call-build-ecs-service-socks / (socks) Check docker image build
  • GitHub Check: call-build-ecs-service-roundtable / (roundtable) Check docker image build
  • GitHub Check: call-build-ecs-service-ender / (ender) Check docker image build
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-auxo-lambda / (auxo) Build and Push Lambda
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-roundtable / (roundtable) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-bazooka-lambda / (bazooka) Build and Push Lambda
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-socks / (socks) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-vulcan / (vulcan) Build and Push
  • GitHub Check: check-build-bazooka
  • GitHub Check: check-build-auxo
  • GitHub Check: test / run_command
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-ender / (ender) Build and Push
  • GitHub Check: (Public Testnet) Build and Push ECS Services / call-build-and-push-ecs-service-comlink / (comlink) Build and Push
  • GitHub Check: build-and-push-mainnet
  • GitHub Check: build-and-push-testnet
  • GitHub Check: lint
  • GitHub Check: run_command
  • GitHub Check: Summary
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (9)
indexer/packages/postgres/src/db/migrations/migration_files/20251027172540_create_vaults_hourly_pnl_v2.ts (1)

26-35: Row selection picks the earliest tick in each hour. Confirm requirement.

ROW_NUMBER() ORDER BY "createdAt" ASC yields the first (earliest) record per hour. If “end‑of‑hour” snapshots are desired, ORDER BY DESC would be more appropriate.

-      ORDER BY "createdAt"
+      -- Use DESC if latest-in-hour is desired:
+      ORDER BY "createdAt" DESC
indexer/packages/postgres/src/db/migrations/migration_files/20251027172547_create_vaults_daily_pnl_v2.ts (1)

26-35: Row selection picks the earliest tick in each day. Confirm requirement.

If “end‑of‑day” snapshots are desired, swap ordering to DESC.

-      ORDER BY "createdAt"
+      -- Use DESC if latest-in-day is desired:
+      ORDER BY "createdAt" DESC
indexer/packages/postgres/src/stores/vault-pnl-view.ts (1)

79-93: OK — DISTINCT ON pattern for latest per vault.

Query shape and ordering look correct for “latest per subaccountId” given the hourly MV.

Confirm that restricting to the hourly view is intended; if a vault has no rows in the last 7 days (MV horizon), it won’t appear. If that’s undesirable, consider switching to the daily MV or underlying table with a fallback.

indexer/packages/postgres/src/types/pnl-types.ts (1)

18-22: The review comment is incorrect—no action needed.

The types/index.ts barrel already re-exports PnlInterval via export * from './pnl-types', which automatically includes the enum. The import in vault-pnl-view.ts will resolve correctly. No additional export statement is required.

Likely an incorrect or invalid review comment.

indexer/packages/postgres/__tests__/stores/vault-pnl-view.test.ts (5)

1-17: LGTM! Clean imports.

The imports are well-organized and include all necessary dependencies for testing the vault PnL views.


19-46: LGTM! Proper test lifecycle management.

The test suite correctly sets up migrations, seeds fresh data before each test, and properly cleans up afterward.


119-126: LGTM! Time calculations are correct.

The helper function properly sets up test timestamps relative to the start of the current UTC day. The luxon API usage is correct—both singular and plural duration keys are accepted.


127-203: LGTM! Comprehensive test data setup.

The helper function creates a well-structured set of PnL records across different time periods for two subaccounts, providing good coverage for testing hourly/daily aggregation logic.


48-93: The review comment is based on an incorrect assumption about the parameter semantics.

The third parameter of getVaultsPnl is named earliestDate and documented as "The earliest date to fetch data from" (not an end time). This means it defines the START of the query window, not the end. The query window is [earliestDate, earliestDate + timeWindowSeconds].

The test correctly queries from createdPnl[8].createdAt + 1 second (2 days ago + 1 second) with a 1-week window, which includes all records created between 2 days ago and 5 days in the future. The expected results [7, 5, 2, 0] for hourly and [7, 2] for daily filtering are chronologically within this window and are correct. No issues exist with the test logic.

Likely an incorrect or invalid review comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development

Successfully merging this pull request may close these issues.

2 participants