Skip to content

Conversation

@Segfaultd
Copy link
Contributor

@Segfaultd Segfaultd commented Nov 21, 2025

Introduction

This PR adds support for tracking events only during live indexing (when the chain is "ready"), skipping them during
historical backfill to improve indexing performance.

Problem / Issue

Some events (e.g., high-frequency Swap events) may only be relevant during live indexing and don't need historical data.
Currently, all configured events are fetched during the entire indexing process, including historical backfill via HyperSync, which can slow down indexing when historical data isn't needed.

Solution

Added a new optional only_when_ready field to event configuration that allows events to be tracked only after the chain completes historical synchronization.

Key Changes:

Configuration Schema:

  • Added only_when_ready: Option<bool> to EventConfig in human_config.rs
  • Defaults to false for backward compatibility
  • Updated JSON schemas with field documentation

Config Pipeline:

  • Propagated field through system_config.rs (Event struct)
  • Added to code generation in codegen_templates.rs (EventMod struct)
  • Generated runtime code includes onlyWhenReady: bool in Internal.eventConfig

Runtime Filtering:

  • Implemented in ChainFetcher.res during event config aggregation
  • Events with onlyWhenReady: true are filtered when timestampCaughtUpToHeadOrEndblock === None
  • No HyperSync queries are made for filtered events during historical sync
  • Events are automatically included once chain becomes ready

Testing:

  • Extended Mock.evmEventConfig helper with ~onlyWhenReady parameter
  • Added comprehensive unit tests in OnlyWhenReady_test.res covering:
    • Filtering when chain not ready
    • Including when chain ready
    • Regular events always included
    • Behavior with enableRawEvents mode

Example Usage:

contracts:
  - name: PoolManager
    events:
      - event: Initialize(...)
        only_when_ready: false  # Optional, default
      - event: Swap(...)
        only_when_ready: true   # Only tracked after historical sync

References

Internal feature request to optimize indexing performance for live-only events.

Summary by CodeRabbit

  • New Features

    • Per-event "only when ready" option added (defaults off) to configs and generated outputs; allows marking events/handlers to defer until a chain is ready.
  • Behavior

    • Runtime defers marked events and on-block handlers until the chain transitions to ready, then activates them; raw-events mode can bypass the readiness filter.
  • Tests

    • Added tests verifying deferred inclusion/exclusion and activation on readiness transition.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

Walkthrough

Adds a per-event readiness flag (only_when_ready / onlyWhenReady) end-to-end: schema, parsing, codegen, runtime, CLI prompts, mocks, and tests. Runtime defers events/on-block handlers when a chain is not ready and activates them when the chain becomes ready.

Changes

Cohort / File(s) Summary
Schema Definitions
codegenerator/cli/npm/envio/evm.schema.json, codegenerator/cli/npm/envio/fuel.schema.json
Add optional only_when_ready / onlyWhenReady property (boolean
Envio Internal Types
codegenerator/cli/npm/envio/src/Internal.res
Add onlyWhenReady: bool to eventConfig and onBlockConfig internal types.
Human Config Parsing
codegenerator/cli/src/config_parsing/human_config.rs
Add pub only_when_ready: Option<bool> to EventConfig for both evm and fuel (serde skip/default) and update tests to initialize as None.
System Config / Runtime Model
codegenerator/cli/src/config_parsing/system_config.rs
Add pub only_when_ready: bool to Event and set from event_config.only_when_ready.unwrap_or(false) in EVM/Fuel conversions.
CLI Init & Interactive Prompts
codegenerator/cli/src/cli_args/init_config.rs, codegenerator/cli/src/cli_args/interactive_init/fuel_prompts.rs, codegenerator/cli/src/config_parsing/graph_migration/mod.rs
Initialize only_when_ready: None where EventConfig instances are constructed.
Codegen Templates & Emitted Runtime
codegenerator/cli/src/hbs_templating/codegen_templates.rs, codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
Propagate only_when_ready/onlyWhenReady into EventMod and emitted configs; ChainFetcher computes readiness and gates event/onBlock inclusion, deferring those marked onlyWhenReady until activation; supports enableRawEvents override.
FetchState Runtime Logic
codegenerator/cli/npm/envio/src/FetchState.res
Add activateDeferredEventsAndHandlers to integrate deferred events/onBlock handlers into partitions and onBlockConfigs when activating deferred work.
GlobalState Transition Handling
codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
Detect chain transition to ready and call ChainFetcher/FetchState activation to enable deferred events/handlers.
Event Register (envio runtime)
codegenerator/cli/npm/envio/src/EventRegister.res
Add onlyWhenReady option to onBlock options schema and propagate into created onBlockConfig objects (default false).
Tests & Mocks
scenarios/test_codegen/config.yaml, scenarios/test_codegen/test/OnlyWhenReady_test.res, scenarios/test_codegen/test/helpers/Mock.res
Add OnlyWhenReadyEvent() with only_when_ready: true; new ChainFetcher tests validate inclusion/exclusion by readiness and enableRawEvents override; mock helpers extended with onlyWhenReady parameter/field.
Package / CLI plumbing
codegenerator/cli/npm/envio/src/EventRegister.res, codegenerator/cli/npm/envio/src/Internal.res, package.json, opam
Propagate new field through envio runtime package artifacts and internal type exports.

Sequence Diagram(s)

sequenceDiagram
    participant Config as Config file
    participant Parser as Human/System Parser
    participant CodeGen as Code generator
    participant Runtime as ChainFetcher/FetchState

    Config->>Parser: Read EventConfig (only_when_ready / onlyWhenReady)
    Parser->>CodeGen: Pass event with only_when_ready value
    CodeGen->>Runtime: Emit event definitions including onlyWhenReady flag

    rect rgb(247,250,255)
      note right of Runtime: Compute readiness from timestampCaughtUpToHeadOrEndblock
      Runtime->>Runtime: Compute isReady
    end

    alt isReady == true
        Runtime->>Runtime: Include all events and onBlock handlers
    else isReady == false
        alt enableRawEvents == true
            Runtime->>Runtime: Include event (raw override)
        else onlyWhenReady == false
            Runtime->>Runtime: Include event
        else onlyWhenReady == true
            Runtime->>Runtime: Defer event/onBlock handler (collect into deferred lists)
        end
    end

    note right of Runtime: On transition to ready -> FetchState.activateDeferredEventsAndHandlers -> integrate deferred events/handlers into partitions & onBlockConfigs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect FetchState.activateDeferredEventsAndHandlers partitioning logic and interactions with existing partition invariants.
  • Review ChainFetcher gating/filtering and ensure deferred lists are correctly populated and cleared on activation.
  • Verify GlobalState transition detection triggers activation exactly once and handles edge cases (reorgs, repeated transitions).
  • Confirm codegen templates emit correct boolean literals and tests cover enableRawEvents override.

Possibly related PRs

Suggested reviewers

  • JonoPrest
  • DZakh

Poem

"A little rabbit near the queue,
I wait for timestamps to turn true.
When backfill finishes, I spring—
fetch the events, dance and sing.
For now I nibble logs, patient and new." 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Optional event processing on historical indexing' accurately describes the main change: adding an optional only_when_ready flag to skip event processing during historical indexing and only track events during live indexing.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 0

🧹 Nitpick comments (3)
scenarios/test_codegen/config.yaml (1)

15-16: LGTM: Test event added for new feature.

The OnlyWhenReadyEvent with only_when_ready: true provides test coverage for the new functionality.

Consider adding additional test scenarios to cover:

  • Events with only_when_ready: false explicitly set
  • Multiple events with mixed only_when_ready values on the same contract
  • Interaction with raw_events: true configuration
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1)

80-95: Core logic is correct; consider simplification.

The filtering logic correctly implements the feature: events marked onlyWhenReady: true are excluded during historical sync (when !isReady), and always included once the chain is ready or when enableRawEvents is true.

The shouldIncludeBasedOnReadiness boolean logic can be simplified for clarity:

-        let shouldIncludeBasedOnReadiness = if onlyWhenReady && !isReady {
-          false
-        } else {
-          true
-        }
+        let shouldIncludeBasedOnReadiness = !onlyWhenReady || isReady

This is logically equivalent (De Morgan's law) and more concise.

codegenerator/cli/src/config_parsing/system_config.rs (1)

1419-1419: Approve with optional refactor suggestion.

The only_when_ready field is correctly set for all five Fuel event types (LogData, Mint, Burn, Transfer, Call) with proper backward-compatible defaults. The repetition follows the existing pattern used for field_selection.

Optional refactor: Consider extracting Event construction into a helper function to reduce the repetition across all five event type branches. However, the current explicit approach is acceptable and may be preferred for clarity.

Also applies to: 1427-1427, 1434-1434, 1441-1441, 1448-1448

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b2a34d and 2ac7b54.

⛔ Files ignored due to path filters (1)
  • scenarios/test_codegen/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • codegenerator/cli/npm/envio/evm.schema.json (1 hunks)
  • codegenerator/cli/npm/envio/fuel.schema.json (1 hunks)
  • codegenerator/cli/npm/envio/src/Internal.res (1 hunks)
  • codegenerator/cli/src/cli_args/init_config.rs (1 hunks)
  • codegenerator/cli/src/cli_args/interactive_init/fuel_prompts.rs (2 hunks)
  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1 hunks)
  • codegenerator/cli/src/config_parsing/human_config.rs (2 hunks)
  • codegenerator/cli/src/config_parsing/system_config.rs (3 hunks)
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs (6 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (2 hunks)
  • scenarios/test_codegen/config.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
codegenerator/cli/**

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

The Rust CLI lives in codegenerator/cli

Files:

  • codegenerator/cli/src/config_parsing/graph_migration/mod.rs
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/src/config_parsing/human_config.rs
  • codegenerator/cli/npm/envio/src/Internal.res
  • codegenerator/cli/npm/envio/fuel.schema.json
  • codegenerator/cli/src/cli_args/init_config.rs
  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
  • codegenerator/cli/src/cli_args/interactive_init/fuel_prompts.rs
  • codegenerator/cli/npm/envio/evm.schema.json
codegenerator/cli/templates/static/**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Static templates are raw ReScript files copied verbatim under codegenerator/cli/templates/static

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
{codegenerator/cli/templates/static/codegen/src/**,codegenerator/cli/templates/dynamic/codegen/src/**}

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Template versions of runtime live under templates/{static,dynamic}/codegen/src and are the recommended editing targets

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/npm/envio/src/Internal.res
codegenerator/cli/npm/envio/**

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Shared library-fied runtime lives in codegenerator/cli/npm/envio

Files:

  • codegenerator/cli/npm/envio/src/Internal.res
  • codegenerator/cli/npm/envio/fuel.schema.json
  • codegenerator/cli/npm/envio/evm.schema.json
codegenerator/cli/src/hbs_templating/codegen_templates.rs

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

hbs_templating/codegen_templates.rs feeds templates

Files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧠 Learnings (6)
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Verify tests by running `pnpm rescript` then `pnpm mocha`; use `_only` to focus tests

Applied to files:

  • scenarios/test_codegen/config.yaml
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/ChainFetcher.res : In generated runtime, ChainFetcher.res is part of the fetch side

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/ChainManager.res : In generated runtime, ChainManager.res is part of the fetch side

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/src/human_config.rs : human_config.rs reads user files and JSON schemas

Applied to files:

  • codegenerator/cli/src/config_parsing/human_config.rs
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/src/system_config.rs : system_config.rs converts to internal structs

Applied to files:

  • codegenerator/cli/src/config_parsing/system_config.rs
  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/src/hbs_templating/codegen_templates.rs : hbs_templating/codegen_templates.rs feeds templates

Applied to files:

  • codegenerator/cli/src/hbs_templating/codegen_templates.rs
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (15)
codegenerator/cli/npm/envio/fuel.schema.json (1)

146-152: LGTM: Schema field addition is well-defined.

The onlyWhenReady field is properly defined with clear documentation and correct typing (boolean | null for optional). The description accurately explains that events with this flag will only be tracked post-backfill.

codegenerator/cli/src/cli_args/init_config.rs (1)

61-61: LGTM: Consistent field initialization.

The only_when_ready: None initialization follows the established pattern for optional EventConfig fields.

codegenerator/cli/npm/envio/src/Internal.res (1)

106-108: LGTM: Internal type extension is correct.

The onlyWhenReady: bool field is appropriately typed as a non-optional boolean for the internal runtime representation (defaults will be applied during config parsing). The comment clearly explains the field's purpose.

codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1)

345-345: LGTM: Consistent initialization in migration path.

The only_when_ready: None initialization maintains consistency with other EventConfig construction paths.

codegenerator/cli/src/cli_args/interactive_init/fuel_prompts.rs (1)

137-137: LGTM: Field initialization in event creation paths.

Both EventConfig construction sites (lines 137 and 151) properly initialize only_when_ready: None, maintaining consistency across log-based and predefined event creation flows.

codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (2)

58-60: LGTM: Readiness check is clear.

The isReady computation based on timestampCaughtUpToHeadOrEndblock !== None correctly identifies when the chain has completed historical sync.


65-65: LGTM: Field destructuring added.

Extracting onlyWhenReady alongside isWildcard is clean and follows the existing pattern.

codegenerator/cli/src/config_parsing/human_config.rs (2)

545-553: LGTM: EVM EventConfig field addition is well-structured.

The only_when_ready field is properly defined with:

  • Appropriate type (Option<bool>)
  • Correct serde attributes to skip None during serialization
  • Clear, comprehensive schema documentation explaining behavior and default

713-721: LGTM: Fuel EventConfig field mirrors EVM implementation.

The Fuel module's only_when_ready field is consistently implemented with the same pattern as the EVM module, maintaining cross-ecosystem consistency.

codegenerator/cli/src/hbs_templating/codegen_templates.rs (3)

341-341: LGTM! Clean field addition to EventMod.

The only_when_ready field is correctly added as a public boolean field and will be propagated through the event code generation pipeline.


421-430: LGTM! Code generation correctly emits the onlyWhenReady field.

The logic cleanly converts the boolean value to a string literal ("true" or "false") and includes it in the generated event configuration code. The field will be available at runtime as Internal.eventConfig.onlyWhenReady.


661-661: LGTM! Field propagation is consistent across all event types.

The only_when_ready field is correctly propagated from config_event to EventMod in all construction paths:

  • Fuel supply events (line 661)
  • Fuel transfer events (line 689)
  • EVM events with params (line 753)
  • Fuel LogData events (line 782)

This ensures the field is available for all supported event kinds.

Also applies to: 689-689, 753-753, 782-782

codegenerator/cli/npm/envio/evm.schema.json (1)

208-214: LGTM! Well-documented schema addition.

The only_when_ready field is correctly defined as an optional boolean with a clear, comprehensive description. The nullable type ensures backward compatibility with existing configurations, and the description provides excellent guidance on the feature's purpose and use cases.

codegenerator/cli/src/config_parsing/system_config.rs (2)

1247-1247: LGTM! Event struct field addition is clean.

The only_when_ready boolean field is correctly added to the Event struct. The non-optional type is appropriate since the config parsing layer handles the default value (false when not specified).


1339-1339: LGTM! EVM event configuration correctly handles the optional field.

The unwrap_or(false) pattern provides proper backward compatibility—existing configurations without only_when_ready will default to false, maintaining current behavior. The field is cleanly integrated into the Event construction alongside field_selection.

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: 0

🧹 Nitpick comments (1)
scenarios/test_codegen/test/helpers/Mock.res (1)

671-671: Consider extending itemMock type for comprehensive integration testing.

The hardcoded onlyWhenReady: false value limits the ability to test event filtering behavior through the Source.make mock. While the dedicated unit tests (OnlyWhenReady_test.res) likely cover the core filtering logic, integration-style tests using Source.make cannot simulate events with onlyWhenReady: true.

If more comprehensive integration testing is needed, consider:

  1. Adding onlyWhenReady?: bool to the itemMock type (lines 469-474)
  2. Passing this value through to the event config construction on line 671

Apply this diff if integration testing via Source.make becomes necessary:

  type itemMock = {
    blockNumber: int,
    logIndex: int,
    handler?: Types.HandlerTypes.loader<unit, unit>,
    contractRegister?: Types.HandlerTypes.contractRegister<unit>,
+   onlyWhenReady?: bool,
  }

Then update line 671:

-                           onlyWhenReady: false,
+                           onlyWhenReady: item.onlyWhenReady->Option.getWithDefault(false),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a63c98a and a35f5d4.

📒 Files selected for processing (1)
  • scenarios/test_codegen/test/helpers/Mock.res (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly

Files:

  • scenarios/test_codegen/test/helpers/Mock.res
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (1)
scenarios/test_codegen/test/helpers/Mock.res (1)

763-792: LGTM! Parameter addition enables flexible test configurations.

The optional ~onlyWhenReady parameter with a default of false is correctly added to the evmEventConfig helper function and properly wired into the returned configuration object. This allows tests to create event configs with different readiness requirements while maintaining backward compatibility.

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: 0

🧹 Nitpick comments (4)
scenarios/test_codegen/test/OnlyWhenReady_test.res (4)

93-96: Consider making the assertion more explicit.

While the current assertion is correct (the length check ensures the array access is safe), you could make the test slightly more explicit by verifying the ID directly from the array.

Optional refactor to make the assertion more explicit:

     // Only the regular event should be included
     let eventConfigs = chainFetcher.fetchState.eventConfigs
     Assert.deep_equal(eventConfigs->Array.length, 1)
-    Assert.deep_equal(eventConfigs[0]->Option.getExn.id, "regular")
+    let eventIds = eventConfigs->Array.map(ec => ec.id)
+    Assert.deep_equal(eventIds, ["regular"])

This approach mirrors the pattern used in the second test case and avoids Option.getExn.


140-144: Consider simplifying the string comparison.

The sorting logic is correct but could be slightly more concise using String.compare if available, or by directly returning the comparison result.

Optional refactor:

     // Verify both event IDs are present
-    let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort((a, b) => {
-      if a < b { -1 } else if a > b { 1 } else { 0 }
-    })
+    let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort(String.compare)
     Assert.deep_equal(eventIds, ["onlyWhenReady", "regular"])

Note: Verify that String.compare is available in your ReScript version. The current implementation is correct if String.compare is not available.


240-242: Consider verifying the event ID for completeness.

While the length assertion confirms the event is included, explicitly verifying the event ID would make the test more thorough and self-documenting.

Optional enhancement:

     // Event should be included because raw events mode is enabled
     Assert.deep_equal(chainFetcher.fetchState.eventConfigs->Array.length, 1)
+    Assert.deep_equal(chainFetcher.fetchState.eventConfigs[0]->Option.getExn.id, "onlyWhenReady")

Additionally, you might consider adding a test case that verifies behavior when enableRawEvents=true AND the chain IS ready, to ensure the feature works correctly in all combinations.


55-243: Excellent test coverage for the core scenarios.

The test suite comprehensively covers the main use cases for the onlyWhenReady feature. Consider adding additional test cases for edge scenarios:

  1. Multiple onlyWhenReady events mixed with multiple regular events when the chain is not ready (to ensure filtering works correctly with larger event sets)
  2. Behavior when enableRawEvents=true and the chain transitions from not ready to ready
  3. Empty event configs array (if applicable)

These additional tests would further strengthen confidence in the feature's robustness.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between caecaad and 9a8746d.

📒 Files selected for processing (1)
  • scenarios/test_codegen/test/OnlyWhenReady_test.res (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly

Files:

  • scenarios/test_codegen/test/OnlyWhenReady_test.res
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (2)
scenarios/test_codegen/test/OnlyWhenReady_test.res (2)

1-7: LGTM!

The test suite setup and imports are correct. Standard ReScript test configuration with appropriate test helpers.


8-53: LGTM!

The helper functions are well-structured and provide good test data setup. They follow ReScript conventions with labeled arguments and sensible defaults.

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: 0

🧹 Nitpick comments (2)
scenarios/test_codegen/test/OnlyWhenReady_test.res (2)

141-143: Consider simplifying the sorting comparator.

The custom string comparison logic works correctly but could be more concise using ReScript's built-in String.compare.

Apply this diff to simplify the sorting:

-      let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort((a, b) => {
-        if a < b { -1 } else if a > b { 1 } else { 0 }
-      })
+      let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort(String.compare)

209-242: Consider testing enableRawEvents with mixed event types.

The test correctly verifies that enableRawEvents mode includes onlyWhenReady events even when the chain is not ready. For more comprehensive coverage, consider adding a test scenario with both regular and onlyWhenReady events to ensure both types are included in raw events mode.

Example enhancement:

let regularEvent = (Mock.evmEventConfig(
  ~id="regular",
  ~contractName="TestContract",
  ~onlyWhenReady=false,
) :> Internal.eventConfig)

let onlyWhenReadyEvent = (Mock.evmEventConfig(
  ~id="onlyWhenReady",
  ~contractName="TestContract",
  ~onlyWhenReady=true,
) :> Internal.eventConfig)

let chainConfig = makeChainConfig(~eventConfigs=[regularEvent, onlyWhenReadyEvent])
// ... rest of test
Assert.deep_equal(chainFetcher.fetchState.eventConfigs->Array.length, 2)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a8746d and d012cfc.

📒 Files selected for processing (1)
  • scenarios/test_codegen/test/OnlyWhenReady_test.res (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly

Files:

  • scenarios/test_codegen/test/OnlyWhenReady_test.res
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (3)
scenarios/test_codegen/test/OnlyWhenReady_test.res (3)

1-53: LGTM! Well-structured test helpers.

The helper functions provide clean, reusable test configuration builders that cover the necessary setup for ChainFetcher tests. The use of named parameters with defaults makes the test code readable and maintainable.


56-97: LGTM! Test correctly validates filtering behavior.

The test properly verifies that events marked with onlyWhenReady: true are filtered out during historical sync (when timestampCaughtUpToHeadOrEndblock is None), while regular events are included. The assertions are safe and comprehensive.


147-207: LGTM! Good explicit coverage for regular events.

The test explicitly verifies that regular events (with onlyWhenReady: false) are always included regardless of chain readiness state. This provides clear documentation of expected behavior and catches potential regressions in the default case.

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: 0

🧹 Nitpick comments (2)
scenarios/test_codegen/test/OnlyWhenReady_test.res (2)

126-172: LGTM! Consider simplifying the sort comparator.

The test correctly validates that both regular and onlyWhenReady events are included once the chain is ready. The assertion logic properly verifies the presence of both event types.

The inline sort comparator on lines 168-170 could be simplified:

-      let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort((a, b) => {
-        if a < b { -1 } else if a > b { 1 } else { 0 }
-      })
+      let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort(String.compare)

82-270: Consider reducing duplication and expanding edge case coverage.

While the test suite effectively covers the main scenarios, you could:

  1. Extract common ChainFetcher.make parameters into a helper function to reduce the repetitive boilerplate across tests.
  2. Add edge case tests such as:
    • All events marked as onlyWhenReady=true when the chain is not ready (should result in 0 events)
    • Mixed scenarios with multiple onlyWhenReady and regular events to validate correct filtering at scale

Example helper to reduce duplication:

let makeChainFetcherWithDefaults = (
  ~chainConfig,
  ~config,
  ~registrations,
  ~timestampCaughtUpToHeadOrEndblock,
) => {
  ChainFetcher.make(
    ~chainConfig,
    ~config,
    ~registrations,
    ~dynamicContracts=[],
    ~startBlock=0,
    ~endBlock=None,
    ~firstEventBlockNumber=None,
    ~progressBlockNumber=-1,
    ~timestampCaughtUpToHeadOrEndblock,
    ~numEventsProcessed=0,
    ~numBatchesFetched=0,
    ~targetBufferSize=5000,
    ~logger=Logging.logger,
    ~isInReorgThreshold=false,
    ~reorgCheckpoints=[],
    ~maxReorgDepth=100,
  )
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d012cfc and 28c5233.

📒 Files selected for processing (1)
  • scenarios/test_codegen/test/OnlyWhenReady_test.res (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Prefer reading ReScript .res modules directly

Files:

  • scenarios/test_codegen/test/OnlyWhenReady_test.res
🧠 Learnings (1)
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/ChainFetcher.res : In generated runtime, ChainFetcher.res is part of the fetch side

Applied to files:

  • scenarios/test_codegen/test/OnlyWhenReady_test.res
⏰ 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). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (4)
scenarios/test_codegen/test/OnlyWhenReady_test.res (4)

83-124: LGTM!

The test correctly validates that onlyWhenReady events are filtered out during historical sync (when the chain is not ready). The assertion logic is sound, and the test setup properly simulates the not-ready state.


174-234: LGTM!

This test properly validates that regular events (with onlyWhenReady=false) are always included regardless of the chain's ready state. The dual assertion approach effectively confirms consistent behavior across both states.


236-270: LGTM!

This test correctly validates that enableRawEvents mode overrides the onlyWhenReady filtering, ensuring events are included even when the chain is not ready. This is an important edge case that confirms the feature doesn't break raw events functionality.


13-15: The type-unsafe cast is actually safe in this test context.

The evmEventConfig type extends eventConfig using spread syntax, and the objects passed through the cast are actual evmEventConfig instances (created by Mock.evmEventConfig()) that contain all required fields. While using Utils.magic is not ideal style, it is safe here because the runtime objects do have the fields being accessed.

Copy link
Member

@DZakh DZakh left a comment

Choose a reason for hiding this comment

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

It looks like the implementation doesn't work correctly, since the ChainFetcher is only created on the application start up. So the filter won't be updated on switch from historical sync to realtime.

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: 0

🧹 Nitpick comments (2)
codegenerator/cli/npm/envio/src/FetchState.res (1)

1347-1354: Consider calling updateInternal to ensure derived values are recalculated.

The function returns a modified fetchState without calling updateInternal. While the partition changes may not affect latestFullyFetchedBlock, the newly added onBlockConfigs won't generate block items until the next updateInternal call (which happens during query result handling). This could cause a delay in block handler activation.

If immediate activation is desired, consider:

-    {
-      ...fetchState,
-      partitions: allPartitions,
-      nextPartitionIndex: fetchState.nextPartitionIndex + newPartitions->Array.length,
-      normalSelection: updatedNormalSelection,
-      onBlockConfigs: updatedOnBlockConfigs,
-    }
+    {
+      ...fetchState,
+      normalSelection: updatedNormalSelection,
+      onBlockConfigs: updatedOnBlockConfigs,
+    }->updateInternal(
+      ~partitions=allPartitions,
+      ~nextPartitionIndex=fetchState.nextPartitionIndex + newPartitions->Array.length,
+    )
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1)

172-184: Minor: Redundant iteration over onBlockConfigs array.

The code iterates over onBlockConfigs twice - once for filtering and once for collecting deferred handlers. Consider combining into a single pass for clarity:

-    // Filter out block handlers marked as onlyWhenReady if the chain is not ready yet
-    let filtered = onBlockConfigs->Array.keep(onBlockConfig => {
-      !onBlockConfig.onlyWhenReady || isReady
-    })
-    // Collect deferred block handlers
-    if !isReady {
-      onBlockConfigs->Array.forEach(onBlockConfig => {
-        if onBlockConfig.onlyWhenReady {
-          deferredOnBlockConfigs->Array.push(onBlockConfig)
-        }
-      })
-    }
+    // Filter and collect deferred block handlers in a single pass
+    let filtered = []
+    onBlockConfigs->Array.forEach(onBlockConfig => {
+      if !onBlockConfig.onlyWhenReady || isReady {
+        filtered->Array.push(onBlockConfig)
+      } else {
+        deferredOnBlockConfigs->Array.push(onBlockConfig)
+      }
+    })
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac0be3d and cb2ddd5.

📒 Files selected for processing (3)
  • codegenerator/cli/npm/envio/src/FetchState.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (8 hunks)
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
codegenerator/cli/templates/static/**/*.res

📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)

Static ReScript files must be placed in codegenerator/cli/templates/static/

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
**/*.{res,resi}

📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
Never use [| item |] to create an array. Use [ item ] instead
Must always use = for setting value to a field. Use := only for ref values created using ref function
Use records when working with structured data, and objects to conveniently pass payload data between functions
Never use %raw to access object fields if you know the type

Files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/npm/envio/src/FetchState.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
🧠 Learnings (3)
📚 Learning: 2025-11-25T12:41:23.343Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-11-25T12:41:23.343Z
Learning: Applies to codegenerator/cli/templates/static/shared/src/**/*.ts : Never hardcode chainId = 1; always use event.chainId for chain-specific operations

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-11-25T12:41:23.343Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-11-25T12:41:23.343Z
Learning: Applies to codegenerator/cli/templates/static/shared/src/**/*.ts : Prefix all entity IDs with chainId in multichain indexing: ${event.chainId}-${originalId}

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-11-25T12:41:23.343Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-11-25T12:41:23.343Z
Learning: Applies to codegenerator/cli/templates/static/shared/src/**/*.ts : Register dynamic contracts created by factory events using contractRegister above the handler (e.g., context.addPair(event.params.pair))

Applied to files:

  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
🔇 Additional comments (4)
codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (1)

292-343: LGTM! Clean implementation of the readiness transition detection.

The logic correctly captures the "was not ready" state before computing updates, then detects when the chain transitions to ready state to activate deferred events and handlers. The use of wasNotReady && isNowReady ensures activation happens exactly once at the transition point.

codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (2)

86-109: LGTM! Event filtering and deferral logic is correct.

The logic properly handles the three cases:

  1. Events that should be included now (registered and either not onlyWhenReady or chain is ready)
  2. Events that should be deferred (registered, onlyWhenReady, and chain not ready)
  3. Events that are skipped entirely (not registered and not enableRawEvents)

The separation ensures no events are lost and deferred events are correctly tracked for later activation.


503-526: LGTM! Clean activation function with proper cleanup.

The function correctly:

  1. Short-circuits when there's nothing to activate
  2. Delegates to FetchState.activateDeferredEventsAndHandlers for the actual work
  3. Clears the deferred arrays to prevent double-activation
codegenerator/cli/npm/envio/src/FetchState.res (1)

1271-1289: I'll verify the review comment by analyzing how contractConfigs is used and whether it needs to include deferred event contracts. Let me start by exploring the relevant code.
<function_calls>


#!/bin/bash

First, let's understand how contractConfigs is used in FetchState.res

rg -n "contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -A 2 -B 1 | head -100


</function_calls>

Let me also check the structure of the file and locate the make function that populates contractConfigs:
<function_calls>


#!/bin/bash

Find the make function in FetchState.res to understand contractConfigs initialization

rg -n "let make" codegenerator/cli/npm/envio/src/FetchState.res -A 15 | head -60


</function_calls>

Let me search more specifically for where contractConfigs is created and updated:
<function_calls>


#!/bin/bash

Search for contractConfigs field and its assignments

rg -n "contractConfigs\s*=" codegenerator/cli/npm/envio/src/FetchState.res -B 2 -A 2


</function_calls>

Now let me look at the actual file to understand the context better:
<function_calls>


#!/bin/bash

Get file size first

wc -l codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me read the key sections of the file:
<function_calls>


#!/bin/bash

Read the make function area to see how contractConfigs is populated

sed -n '980,1020p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Now let me check the activateDeferredEventsAndHandlers function and the surrounding context:
<function_calls>


#!/bin/bash

Read activateDeferredEventsAndHandlers function

sed -n '1265,1350p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me search for where contractConfigs is used after being set:
<function_calls>


#!/bin/bash

Look for all uses of contractConfigs to understand its purpose

rg -n ".contractConfigs|contractConfigs\s*:" codegenerator/cli/npm/envio/src/FetchState.res -B 2 -A 2 | head -120


</function_calls>

Now let me check the registerDynamicContracts function mentioned in the review comment:
<function_calls>


#!/bin/bash

Search for registerDynamicContracts function

rg -n "registerDynamicContracts|filterByAddresses" codegenerator/cli/npm/envio/src/FetchState.res -B 3 -A 3


</function_calls>

Let me look at how ChainFetcher processes eventConfigs to understand whether deferred events are filtered out:
<function_calls>


#!/bin/bash

Find ChainFetcher.make to see how it passes eventConfigs to FetchState

fd ChainFetcher.res codegenerator/cli/npm/envio/src/


</function_calls>

Let me search for where deferred events are handled:
<function_calls>


#!/bin/bash

Search for deferred event handling and filtering

rg -n "shouldBeIncluded|isDeferred" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 2


</function_calls>

Let me search more broadly for the eventConfig structure and deferred handling:
<function_calls>


#!/bin/bash

Look for eventConfig type definition and deferred field

rg -n "deferred|isDeferred" codegenerator/cli/npm/envio/src/ --type res -B 1 -A 1 | head -80


</function_calls>

Let me examine the Internal module to understand the eventConfig structure:
<function_calls>


#!/bin/bash

Find the Internal module that defines eventConfig

fd -e res codegenerator/cli/npm/envio/src/ | xargs rg -l "type eventConfig"


</function_calls>

Let me check the FetchState file itself for Internal module and eventConfig references:
<function_calls>


#!/bin/bash

Search within FetchState.res for eventConfig references and type definitions

sed -n '1,100p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me check what happens with the return value of activateDeferredEventsAndHandlers:
<function_calls>


#!/bin/bash

Search for calls to activateDeferredEventsAndHandlers to see how result is used

rg -n "activateDeferredEventsAndHandlers" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 5


</function_calls>

Let me look at the full activateDeferredEventsAndHandlers function more carefully:
<function_calls>


#!/bin/bash

Get the complete activateDeferredEventsAndHandlers function

sed -n '1271,1320p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Now let me look at the entire return block:
<function_calls>


#!/bin/bash

Get more lines to see the complete function

sed -n '1271,1400p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me search for the return statement pattern in this function:
<function_calls>


#!/bin/bash

Find the return statement in activateDeferredEventsAndHandlers

sed -n '1271,1500p' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "contractConfigs|return|...fetchState" -A 2 -B 2


</function_calls>

Let me read the complete function more carefully:
<function_calls>


#!/bin/bash

Read a larger section to capture the complete function

sed -n '1271,1450p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me search for where this function ends:
<function_calls>


#!/bin/bash

Find the end of activateDeferredEventsAndHandlers function

awk '/^let activateDeferredEventsAndHandlers = (/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | tail -100


</function_calls>

Now let me check how contractConfigs is actually used after being populated:
<function_calls>


#!/bin/bash

Search for where contractConfigs is accessed/used (not just assigned)

rg -n ".contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res | head -20


</function_calls>

Let me look at those specific uses to understand the impact:
<function_calls>


#!/bin/bash

Get context around contractConfigs usage

rg -n ".contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -B 5 -A 5


</function_calls>

Let me check the type definition of t to understand what fields exist:
<function_calls>


#!/bin/bash

Find the type t definition in FetchState.res

rg -n "type\s+t\s*=\s*{" codegenerator/cli/npm/envio/src/FetchState.res -A 30


</function_calls>

Let me search for the complete type definition more carefully:
<function_calls>


#!/bin/bash

Search for type t and get full definition

sed -n '1,200p' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "type t"


</function_calls>

Let me check the module structure:
<function_calls>


#!/bin/bash

Look at the beginning of FetchState module

head -300 codegenerator/cli/npm/envio/src/FetchState.res | tail -200


</function_calls>

Let me search for where the type t is defined more broadly:
<function_calls>


#!/bin/bash

Search more carefully for type t definition

rg -n "^\s*type t\b" codegenerator/cli/npm/envio/src/FetchState.res -A 50 | head -80


</function_calls>

Let me try ast-grep to find the type definition:
<function_calls>


#!/bin/bash

Use ast-grep to find type definitions

ast-grep --pattern 'type t = {
$$$
}'


</function_calls>

Let me read the first 1000 lines more systematically:
<function_calls>


#!/bin/bash

Read specific line ranges to find type t

sed -n '50,150p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Now let me check what the actual field names are in the return statement:
<function_calls>


#!/bin/bash

Look for return statements or {...fetchState} patterns

rg -n "...fetchState|{$" codegenerator/cli/npm/envio/src/FetchState.res -A 10 | head -80


</function_calls>

Let me check how make function constructs the return record:
<function_calls>


#!/bin/bash

Read around the make function return statement

sed -n '980,1050p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me try to understand the record structure from how it's used:
<function_calls>


#!/bin/bash

Look for all field accesses on fetchState

rg -n "fetchState." codegenerator/cli/npm/envio/src/FetchState.res | cut -d: -f3 | sort -u | head -40


</function_calls>

Now let me check the return structure of activateDeferredEventsAndHandlers more directly:
<function_calls>


#!/bin/bash

Extract the full function and look at its return value

awk '/^let activateDeferredEventsAndHandlers = (/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "contractConfigs|partitions|normalSelection" -B 2 -A 2


</function_calls>

Let me check how ChainFetcher prepares the eventConfigs passed to FetchState:
<function_calls>


#!/bin/bash

Find how ChainFetcher passes eventConfigs to FetchState.make

rg -n "FetchState.make" codegenerator/cli/npm/envio/src/ --type res -B 10 | head -80


</function_calls>

Let me check what fields eventConfig contains by looking at eventConfigs processing:
<function_calls>


#!/bin/bash

Search for where deferredEventConfigs are created/extracted

rg -n "deferredEventConfigs|~deferredEventConfigs" codegenerator/cli/npm/envio/src/ --type res -B 3 -A 3


</function_calls>

Let me search for where deferred events are separated:
<function_calls>


#!/bin/bash

Search for where eventConfigs might be filtered or split

rg -n "notDeferred|dependsOnAddresses|isDeferred" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 2 | head -100


</function_calls>

Let me check the eventConfig fields based on what's accessed:
<function_calls>


#!/bin/bash

Look at the snippet from the review comment to understand accessed fields

sed -n '1271,1289p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Now let me understand what contractName field is used for by searching through the code:
<function_calls>


#!/bin/bash

Search for how contractName is used in eventConfigs

rg -n ".contractName|ec.contractName" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 2 | head -60


</function_calls>

Let me search for where contractConfigs Map is built:
<function_calls>


#!/bin/bash

Search for contractConfigs construction

rg -n "contractConfigs.*=" codegenerator/cli/npm/envio/src/FetchState.res -B 2 -A 8 | head -100


</function_calls>

Let me look at that specific area:
<function_calls>


#!/bin/bash

Read the area where contractConfigs is assigned

sed -n '995,1020p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me read more of that section to see the full logic:
<function_calls>


#!/bin/bash

Get more context around contractConfigs assignment

sed -n '1000,1020p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Now let me check if there's any logic that depends on contractConfigs being present:
<function_calls>


#!/bin/bash

Look for Map operations on contractConfigs

rg -n "contractConfigs->Map." codegenerator/cli/npm/envio/src/FetchState.res -B 1 -A 3


</function_calls>

Let me check what happens in that line 360 mentioned in the scratchpad about registerDynamicContracts:
<function_calls>


#!/bin/bash

Check line 360 area

sed -n '355,375p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me get more context around that line:
<function_calls>


#!/bin/bash

Search for Map.has or Map.get on contractConfigs in that area

sed -n '350,380p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me search directly for how contractConfigs is queried:
<function_calls>


#!/bin/bash

Search for all uses of contractConfigs with Map operations

rg -n "contractConfigs->Map|Map.*contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -B 3 -A 3


</function_calls>

Let me look at the tests or usage examples to understand if this is a real issue:
<function_calls>


#!/bin/bash

Check if there are tests for activateDeferredEventsAndHandlers

fd -e res codegenerator/cli/npm/envio/ | xargs rg -l "activateDeferredEventsAndHandlers" 2>/dev/null


</function_calls>

Let me look at how partitions is updated to understand the pattern better:
<function_calls>


#!/bin/bash

Look at how partitions is handled in the return

sed -n '1271,1450p' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "partitions" -B 2 -A 2


</function_calls>

Let me extract and examine the complete return statement:
<function_calls>


#!/bin/bash

Get the complete return block of activateDeferredEventsAndHandlers

sed -n '1340,1380p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me search for the actual pattern of record construction in the function:
<function_calls>


#!/bin/bash

Look for {...fetchState pattern or explicit field assignments

awk '/^let activateDeferredEventsAndHandlers/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "partitions|normalSelection|contractConfigs" | tail -20


</function_calls>

Let me try a different approach - check if the function creates a new record or modifies existing:
<function_calls>


#!/bin/bash

Look at the complete function body more systematically

awk '/^let activateDeferredEventsAndHandlers = (/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | tail -50


</function_calls>

Let me read a large block and search within it:
<function_calls>


#!/bin/bash

Read a large block and find the return structure

sed -n '1330,1450p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n


</function_calls>

Now let me check what's actually in that return:
<function_calls>


#!/bin/bash

Get lines 1380-1400 which should be near the end

sed -n '1380,1400p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me find where the else block that handles the deferred events actually returns:
<function_calls>


#!/bin/bash

Search for the return statement in this function more carefully

rg -n "^\s+})" codegenerator/cli/npm/envio/src/FetchState.res | head -20


</function_calls>

Let me try a more direct Python approach to parse this:
<function_calls>


#!/bin/bash

Read entire activateDeferredEventsAndHandlers function

python3 << 'EOF'
with open('codegenerator/cli/npm/envio/src/FetchState.res', 'r') as f:
lines = f.readlines()

in_function = False
function_lines = []
brace_count = 0

for i, line in enumerate(lines[1270:1450], start=1271): # start from line 1271
function_lines.append(f"{i:4d}: {line.rstrip()}")
if 'activateDeferredEventsAndHandlers' in line and '(' in line:
in_function = True
if in_function:
brace_count += line.count('{') - line.count('}')
if brace_count == 0 and in_function:
print('\n'.join(function_lines))
break

EOF


</function_calls>

Let me search for what the function actually returns by looking at the entire implementation:
<function_calls>


#!/bin/bash

Get lines around the return statement

sed -n '1360,1395p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Let me check if contractConfigs should be updated by seeing how it's used downstream:
<function_calls>


#!/bin/bash

Search to understand what uses contractConfigs after activation

rg -n ".contractConfigs|contractConfigs->" codegenerator/cli/npm/envio/src/FetchState.res -B 5 -A 3 | head -150


</function_calls>

Let me look at the specific usage in context:
<function_calls>


#!/bin/bash

Look at one specific usage of contractConfigs

sed -n '1000,1030p' codegenerator/cli/npm/envio/src/FetchState.res


</function_calls>

Now let me create a comprehensive analysis by checking the initialization and usage:
<function_calls>


#!/bin/bash

Look for where contractConfigs might be used to filter or process events

rg -n "contractConfigs->Js.Dict|contractConfigs->Map" codegenerator/cli/npm/envio/src/FetchState.res -B 3 -A 5


</function_calls>

Let me search to see if there are any checks on contractConfigs after events are added:
<function_calls>


#!/bin/bash

Check what happens after partitions and normalSelection are updated

Look for any Map.get or Map.has on contractConfigs

rg -n "Map.get|Map.has|Dict.get" codegenerator/cli/npm/envio/src/FetchState.res | grep -i config


</function_calls>

Let me check how the returned fetchState from activateDeferredEventsAndHandlers is used:
<function_calls>


#!/bin/bash

Look at the callsite to see how result is used

rg -n "activateDeferredEventsAndHandlers" codegenerator/cli/npm/envio/src/ --type res -A 20 | head -80


</function_calls>

Now let me understand the actual concern - check if contractConfigs is truly used for validation or filtering:
<function_calls>


#!/bin/bash

Check what the comment in the initial code suggests about contractConfigs

rg -n "contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res | head -20


</function_calls>

Let me see the complete activation function one more time and check the return values more carefully:
<function_calls>


#!/bin/bash

Let's output the lines 1340-1380 which should show us the return

cat -n codegenerator/cli/npm/envio/src/FetchState.res | sed -n '1340,1380p'


</function_calls>

Based on the analysis, let me verify one more critical thing - whether deferred events are actually excluded from initial eventConfigs:
<function_calls>


#!/bin/bash

Search for where deferred events are separated or identified

Look in ChainFetcher or similar files

fd -e res codegenerator/cli/npm/envio/src/ -exec rg -l "deferred" {} ; | head -10


</function_calls>

Let me check the ChainFetcher specifically:
<function_calls>


#!/bin/bash

Search ChainFetcher files for deferred handling

fd ChainFetcher codegenerator/cli/npm/envio/src/ --type f


</function_calls>

Let me look for files that might handle deferred events:
<function_calls>


#!/bin/bash

List files in the src directory

ls -la codegenerator/cli/npm/envio/src/*.res | head -20


</function_calls>

Let me search across all ReScript files for deferred event handling:
<function_calls>


#!/bin/bash

Search all res files for deferred

find codegenerator/cli/npm/envio/src -name "*.res" -exec rg -l "deferred" {} ;


</function_calls>

Let me check if there's any code that would fail if a contract isn't in contractConfigs:
<function_calls>


#!/bin/bash

Search for any error handling or checks related to contractConfigs lookups

rg -n "contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -C 5 | grep -E "Map.|Option.|->|contract" -A 2 -B 2


</function_calls>

Let me check if contractConfigs is actually important for the deferral logic:
<function_calls>


#!/bin/bash

Look at the actual code to see how contractConfigs is used after being set

sed -n '1000,1050p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n


</function_calls>

Let me do a final check to see if missing contractConfigs entries actually cause failures:
<function_calls>


#!/bin/bash

Look at the complete contractConfigs initialization to understand its purpose

sed -n '998,1020p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n


</function_calls>

Let me check the practical impact by seeing how contractConfigs is used in partition operations:
<function_calls>


#!/bin/bash

Check the complete make function to see the full picture

sed -n '986,1100p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n


</function_calls>

Based on all my analysis, I now have enough information to provide the rewritten review comment. The key findings are:

  1. The activateDeferredEventsAndHandlers function does NOT update contractConfigs in its return statement
  2. contractConfigs is built only once from the initial eventConfigs passed to FetchState.make
  3. If deferred events are separate and not in the initial eventConfigs, their contracts won't be in contractConfigs
  4. The function successfully adds deferred events to partitions and normalSelection but leaves contractConfigs unchanged

However, I need to verify if this is actually an issue by checking what uses these fields afterward and whether contractConfigs needs to include deferred contracts.

contractConfigs is NOT updated when activating deferred events, but it may not need to be.

When activateDeferredEventsAndHandlers returns (lines 1355-1375), it updates partitions and normalSelection but leaves contractConfigs unchanged. Since contractConfigs is built during FetchState.make from the initial eventConfigs parameter, contracts from deferred events would only be included if they were part of that initial set.

However, contractConfigs appears to be used primarily during initialization for building the partition structure. The deferred events are added directly to partitions and normalSelection via Array.push operations, which doesn't depend on contractConfigs lookups. If contract configuration information for deferred events is needed later, it would need to be handled separately or included in the deferred event config itself.

Consider:

  • Verifying whether deferred event contracts need entries in contractConfigs for any downstream operations
  • If needed, updating contractConfigs when activating deferred events, or ensuring those contracts are included in the initial contractConfigs construction

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