Skip to content

Add envio data command for querying raw blockchain data#1254

Open
DZakh wants to merge 30 commits into
mainfrom
claude/amazing-thompson-IzI1M
Open

Add envio data command for querying raw blockchain data#1254
DZakh wants to merge 30 commits into
mainfrom
claude/amazing-thompson-IzI1M

Conversation

@DZakh
Copy link
Copy Markdown
Member

@DZakh DZakh commented May 29, 2026

Introduces a new envio data CLI command that enables querying raw blockchain data (blocks, logs, transactions) on EVM chains using the same where filter syntax as indexer definitions.

Summary

Users can now query blockchain data directly via the CLI without web-searching or manual API calls:

envio data block.number log.srcAddress --chain=base \
  --where='{ block: { number: { _gte: 1000 } }, log: { srcAddress: "0xabc" } }'

The command supports:

  • Field selection with flexible naming (camelCase, snake_case, all lowercase)
  • Block range filtering via _gte, _gt, _lte, _lt operators
  • Log/transaction filtering by address, topic, sighash
  • Chain resolution by name or numeric ID
  • Pagination hints for iterating through results
  • Special knownHeight field to query current archive height

Key Changes

  • New modules under packages/cli/src/data/:

    • mapping.rs: Field name normalization and type mapping (Block/Transaction/Log fields)
    • field_selection.rs: Parses positional field arguments with validation
    • where_filter.rs: Parses JSON5 --where filters and builds HyperSync queries
    • chain.rs: Resolves chain names/IDs to HyperSync endpoints
    • toon.rs: Renders Arrow response data in TOON (token-oriented) tabular format
  • New executor module (packages/cli/src/executor/data.rs):

    • Orchestrates token resolution, client setup, query execution
    • Handles pagination and renders next-page hints
  • Integration tests (packages/cli/tests/data_integration.rs):

    • End-to-end tests against live HyperSync endpoints (gated behind integration_tests feature)
    • Validates deterministic output for historical blocks
  • CLI integration:

    • Added Data(DataArgs) variant to CommandType enum
    • New DataArgs struct with fields, --chain, --where arguments
    • Updated command routing in executor
  • Documentation:

    • Added Claude skill definition at .claude/skills/envio-data/SKILL.md
    • Updated CommandLineHelp.md with new command
    • Removed outdated HyperSync curl instructions from indexer-testing skill

Implementation Details

  • Field lookup is case-insensitive and supports both camelCase and snake_case naming conventions
  • Block range operators are normalized to exclusive upper bounds internally (_lte: 2000to_block_exclusive: 2001)
  • JSON5 parsing allows unquoted keys and trailing commas for user convenience
  • Output uses TOON format: tableName[rowCount]{col1,col2}: row1,row2,...
  • Hex values are displayed with 0x prefix; large numbers use decimal representation
  • API token resolved from ENVIO_API_TOKEN env var or .env file

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA

Summary by CodeRabbit

  • New Features

    • Added envio data CLI to query EVM chain blocks/transactions/logs with selectable fields, chain resolution, JSON5-like --where filters (relaxed syntax), TOON tabular output, and known/archive height support (Solana not supported yet).
  • Documentation

    • CLI help, examples, and skill docs for envio data; added guidance to use full-value test assertions (avoid contains).
  • Tests

    • Unit and integration tests for parsing, filtering, rendering, and end-to-end CLI flows.
  • Chores

    • Dependency updates to enable data features.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Review Change Stack

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 an envio data CLI subcommand for querying raw blockchain data (blocks, logs, transactions) on EVM chains. Implements field/section typing, JSON5-style where parsing, chain resolution, Arrow→TOON rendering, executor wiring, integration tests, and documentation updates.

Changes

Data Query Subcommand

Layer / File(s) Summary
CLI subcommand registration
packages/cli/Cargo.toml, packages/cli/src/cli_args/clap_definitions.rs
Added data enum variant to CommandType and public DataArgs struct with fields, chain, and optional --where arguments; bumped strum/strum_macros to 0.27 and added json5 and arrow dependencies.
Field and section type system
packages/cli/src/data/mapping.rs, packages/cli/src/data/mod.rs
Defined Section (block/transaction/log) and ColumnFormat (decimal/hex) enums, TypedField wrapper, field normalization and lookup with alias support, camelCase conversion, and field validation across block, transaction, and log field variants.
Field selection parsing
packages/cli/src/data/field_selection.rs
Implemented Selection and Column structs to parse CLI positional field arguments, validate <section>.<field> format, handle knownHeight token, and convert to network FieldSelection by category.
Chain identifier resolution
packages/cli/src/data/chain.rs
Implemented Chain struct and resolve() function to parse numeric chain ids or network names, reject unsupported chains (Solana, Fuel), construct HyperSync base URLs, and provide detailed error messages.
Where-filter JSON5 parsing
packages/cli/src/data/where_filter.rs
Implemented WhereFilter struct and parsing to handle JSON5-relaxed --where syntax, block range operators (_gte, _gt, _lte, _lt), field filtering for logs and transactions, and conversion to hypersync_client Query with supported field subsets.
TOON table output rendering
packages/cli/src/data/toon.rs
Implemented TOON format output: deterministic comma-separated tables with escaped cells, section ordering by first appearance, Arrow-to-rows conversion, binary value formatting (decimal/hex), and height-only output modes.
Executor orchestration and API integration
packages/cli/src/executor/data.rs, packages/cli/src/executor/mod.rs, packages/cli/src/lib.rs
Implemented main async run() entry point that resolves API token, builds HyperSync client, orchestrates field/filter parsing, executes queries, renders output, and reports pagination state; updated command dispatch and module exports.
Command dispatch and example support
packages/cli/examples/script.rs
Updated example script to accept both script and data subcommands via example binary.
Integration tests
packages/cli/tests/data_integration.rs
Added end-to-end subprocess-based tests for height queries, deterministic block/log data, and pagination behavior; includes stderr templating for stable assertions across varying numeric values.
User documentation and guides
packages/cli/CommandLineHelp.md, packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md, packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md, packages/cli/src/template_dirs.rs
Added envio data to CLI help and created new SKILL.md template with usage, options, field examples, and filter operators; removed obsolete HyperSync instructions from indexer-testing SKILL; updated template directory test.
Testing guidelines
CLAUDE.md
Added directive prohibiting contains assertions in favor of full-value assertions using assert_eq! or insta::assert_snapshot!.

Sequence Diagram(s)

sequenceDiagram
  participant User as CLI
  participant Clap as ClapParser
  participant Executor as Executor::data
  participant Hypersync as hypersync_client
  participant TOON as toon::render

  User->>Clap: invoke `envio data` (fields, --chain, --where)
  Clap->>Executor: CommandType::Data(DataArgs)
  Executor->>Executor: resolve chain, parse selection, parse where
  Executor->>Hypersync: build client & send Query
  Hypersync-->>Executor: ArrowResponse (+ paging info)
  Executor->>TOON: render_arrow_response(selection, response)
  TOON-->>Executor: formatted TOON output
  Executor->>User: print stdout/stderr and paging hints
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested reviewers

  • DenhamPreen
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.92% 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 'Add envio data command for querying raw blockchain data' directly and clearly summarizes the main change in the PR, which introduces a new CLI command for querying blockchain data.
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.


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

Copy link
Copy Markdown
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: 1

🧹 Nitpick comments (3)
packages/cli/src/data/mapping.rs (2)

269-279: ⚡ Quick win

Replace contains assertions with full-value assertions/snapshots.

Line 271, Line 272, and Line 278 use contains, which weakens test specificity and violates the test-assertion rule. Assert the full vector value (or snapshot it) instead.

Suggested approach
 #[test]
 fn valid_names_use_camel_case() {
     let names = valid_indexer_names(Section::Block);
-    assert!(names.contains(&"gasLimit".to_string()), "{names:?}");
-    assert!(names.contains(&"baseFeePerGas".to_string()), "{names:?}");
+    insta::assert_debug_snapshot!(names);
 }
 
 #[test]
 fn valid_names_include_src_address() {
     let names = valid_indexer_names(Section::Log);
-    assert!(names.contains(&"srcAddress".to_string()), "{names:?}");
+    insta::assert_debug_snapshot!(names);
 }

As per coding guidelines: **/*.rs: Never use contains in test assertions — assert the full expected value. Use assert_eq! or insta::assert_snapshot! for error messages.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/data/mapping.rs` around lines 269 - 279, The tests
valid_names_use_camel_case and valid_names_include_src_address call
valid_indexer_names(Section::Block) and valid_indexer_names(Section::Log) and
then use contains(...) which is disallowed; replace those contains assertions
with full-value assertions by either asserting the exact Vec<String> returned
(using assert_eq!(names, expected_vec)) or by snapshotting the entire value with
insta::assert_snapshot! (or insta::assert_debug_snapshot!) so the test verifies
the complete ordering and content rather than a subset; update the test bodies
for functions valid_names_use_camel_case and valid_names_include_src_address to
construct the expected full vector (or snapshot) and compare it to names.

178-260: ⚡ Quick win

Use one assertion per test case by asserting the combined expected value.

Several tests (e.g., Line 180 onward) use multiple assertions in a single test body. Consolidate each case into one assertion over a tuple/aggregate result to keep failures atomic and align with repo test policy.

Suggested pattern
 #[test]
 fn lookup_camel_case() {
-    assert!(matches!(
-        lookup(Section::Block, "gasLimit"),
-        Some(TypedField::Block(BlockField::GasLimit))
-    ));
-    assert!(matches!(
-        lookup(Section::Transaction, "transactionIndex"),
-        Some(TypedField::Transaction(TransactionField::TransactionIndex))
-    ));
+    assert!(matches!(
+        (
+            lookup(Section::Block, "gasLimit"),
+            lookup(Section::Transaction, "transactionIndex"),
+        ),
+        (
+            Some(TypedField::Block(BlockField::GasLimit)),
+            Some(TypedField::Transaction(TransactionField::TransactionIndex))
+        )
+    ));
 }

As per coding guidelines: **/*.rs: Always use single assert to check the whole value instead of multiple asserts for every field.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/data/mapping.rs` around lines 178 - 260, Tests like
lookup_camel_case, lookup_snake_case, lookup_all_lowercase,
lookup_uppercase_mixed, lookup_src_address_alias, lookup_address_directly, and
lookup_topic_fields use multiple assert! calls; change each test to use a single
assertion that checks the combined result (e.g., build a tuple or aggregate of
the lookup(...) return values) and compare it once to the expected tuple of
TypedField variants (referencing lookup, TypedField, BlockField,
TransactionField, LogField, and the specific test names to find the cases).
packages/cli/src/data/where_filter.rs (1)

296-303: ⚡ Quick win

Use one full-value assertion per test case.

These tests split related expectations across multiple assertions; combine them into one assertion per case.

As per coding guidelines "**/*.rs: Always use single assert to check the whole value instead of multiple asserts for every field".

Also applies to: 374-377

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/data/where_filter.rs` around lines 296 - 303, The tests
currently use multiple assert_eq calls to check different fields of the same
value (e.g., assert_eq((f.from_block, f.to_block_exclusive), (...)) and
assert_eq((f.log_filters.len(), f.log_filters[0].indexer_name.as_str()), (...)))
— change each case to a single full-value assertion that compares the entire
expected struct/tuple to the actual (for example compare a constructed expected
WhereFilter or a full tuple representing all relevant fields to f), and do the
same for the other occurrence around lines 374-377 so each test uses one assert
per case.
🤖 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/cli/src/executor/data.rs`:
- Around line 54-58: Don't coerce response.archive_height to 0; keep it as an
Option and only render or use it when present. Replace the let archive_height =
response.archive_height.unwrap_or(0) with an Option binding (e.g., let
archive_height_opt = response.archive_height), change the rendering to call
toon::render_archive_height only when archive_height_opt.is_some() (or map to
i64 via archive_height_opt.map(|h| h as i64)), and update the
pagination/exhaustion checks to rely on archive_height_opt being Some rather
than comparing against 0; reference response.archive_height, archive_height_opt,
selection.known_height, and toon::render_archive_height when making the changes.

---

Nitpick comments:
In `@packages/cli/src/data/mapping.rs`:
- Around line 269-279: The tests valid_names_use_camel_case and
valid_names_include_src_address call valid_indexer_names(Section::Block) and
valid_indexer_names(Section::Log) and then use contains(...) which is
disallowed; replace those contains assertions with full-value assertions by
either asserting the exact Vec<String> returned (using assert_eq!(names,
expected_vec)) or by snapshotting the entire value with insta::assert_snapshot!
(or insta::assert_debug_snapshot!) so the test verifies the complete ordering
and content rather than a subset; update the test bodies for functions
valid_names_use_camel_case and valid_names_include_src_address to construct the
expected full vector (or snapshot) and compare it to names.
- Around line 178-260: Tests like lookup_camel_case, lookup_snake_case,
lookup_all_lowercase, lookup_uppercase_mixed, lookup_src_address_alias,
lookup_address_directly, and lookup_topic_fields use multiple assert! calls;
change each test to use a single assertion that checks the combined result
(e.g., build a tuple or aggregate of the lookup(...) return values) and compare
it once to the expected tuple of TypedField variants (referencing lookup,
TypedField, BlockField, TransactionField, LogField, and the specific test names
to find the cases).

In `@packages/cli/src/data/where_filter.rs`:
- Around line 296-303: The tests currently use multiple assert_eq calls to check
different fields of the same value (e.g., assert_eq((f.from_block,
f.to_block_exclusive), (...)) and assert_eq((f.log_filters.len(),
f.log_filters[0].indexer_name.as_str()), (...))) — change each case to a single
full-value assertion that compares the entire expected struct/tuple to the
actual (for example compare a constructed expected WhereFilter or a full tuple
representing all relevant fields to f), and do the same for the other occurrence
around lines 374-377 so each test uses one assert per case.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 32a26654-a124-437f-b047-4b860f9bf677

📥 Commits

Reviewing files that changed from the base of the PR and between 449af6a and df506dc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • CLAUDE.md
  • packages/cli/Cargo.toml
  • packages/cli/CommandLineHelp.md
  • packages/cli/examples/script.rs
  • packages/cli/src/cli_args/clap_definitions.rs
  • packages/cli/src/data/chain.rs
  • packages/cli/src/data/field_selection.rs
  • packages/cli/src/data/mapping.rs
  • packages/cli/src/data/mod.rs
  • packages/cli/src/data/toon.rs
  • packages/cli/src/data/where_filter.rs
  • packages/cli/src/executor/data.rs
  • packages/cli/src/executor/mod.rs
  • packages/cli/src/hypersync_source/query.rs
  • packages/cli/src/lib.rs
  • packages/cli/src/template_dirs.rs
  • packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md
  • packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md
  • packages/cli/tests/data_integration.rs
💤 Files with no reviewable changes (1)
  • packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md

Comment thread packages/cli/src/executor/data.rs Outdated
Comment on lines +54 to +58
let archive_height = response.archive_height.unwrap_or(0);

if selection.known_height {
out.push_str(&toon::render_archive_height(archive_height as i64));
}
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 | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="packages/cli/src/executor/data.rs"

echo "=== File header ==="
ls -la "$FILE" 2>/dev/null || true

echo
echo "=== Lines 1-140 (for context) ==="
sed -n '1,140p' "$FILE" | nl -ba | sed -n '1,140p'

echo
echo "=== Search: archive_height in file ==="
rg -n "archive_height" "$FILE" || true

echo
echo "=== Search: exhausted / to_block_exclusive / next_block ==="
rg -n "(exhausted|to_block_exclusive|next_block)" "$FILE" || true

Repository: enviodev/hyperindex

Length of output: 263


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="packages/cli/src/executor/data.rs"

echo "=== File header ==="
ls -la "$FILE" 2>/dev/null || true

echo
echo "=== Lines 1-220 (for context) ==="
# Use cat -n for line numbers (nl may not exist)
cat -n "$FILE" | sed -n '1,220p'

echo
echo "=== Search: archive_height in file ==="
rg -n "archive_height" "$FILE" || true

echo
echo "=== Search: exhausted / to_block_exclusive / next_block ==="
rg -n "(exhausted|to_block_exclusive|next_block)" "$FILE" || true

Repository: enviodev/hyperindex

Length of output: 7515


Don’t coerce missing archive_height to 0 for pagination/exhaustion decisions.

let archive_height = response.archive_height.unwrap_or(0);

if selection.known_height {
    out.push_str(&toon::render_archive_height(archive_height as i64));
}

unwrap_or(0) makes exhausted always true when response.archive_height is absent (next_block >= 0), breaking pagination (67-68), and can also emit misleading knownHeight=0 when selection.known_height is set (56-58).

Suggested fix
-    let archive_height = response.archive_height.unwrap_or(0);
+    let archive_height = response.archive_height;

     if selection.known_height {
-        out.push_str(&toon::render_archive_height(archive_height as i64));
+        if let Some(h) = archive_height {
+            out.push_str(&toon::render_archive_height(h as i64));
+        }
     }

@@
-    eprintln!("archive_height: {archive_height}");
+    match archive_height {
+        Some(h) => eprintln!("archive_height: {h}"),
+        None => eprintln!("archive_height: <unknown>"),
+    }

-    let exhausted = matches!(filter.to_block_exclusive, Some(end) if next_block >= end)
-        || next_block >= archive_height;
+    let exhausted = matches!(filter.to_block_exclusive, Some(end) if next_block >= end)
+        || archive_height.is_some_and(|h| next_block >= h);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/executor/data.rs` around lines 54 - 58, Don't coerce
response.archive_height to 0; keep it as an Option and only render or use it
when present. Replace the let archive_height =
response.archive_height.unwrap_or(0) with an Option binding (e.g., let
archive_height_opt = response.archive_height), change the rendering to call
toon::render_archive_height only when archive_height_opt.is_some() (or map to
i64 via archive_height_opt.map(|h| h as i64)), and update the
pagination/exhaustion checks to rely on archive_height_opt being Some rather
than comparing against 0; reference response.archive_height, archive_height_opt,
selection.known_height, and toon::render_archive_height when making the changes.

@DZakh DZakh force-pushed the claude/amazing-thompson-IzI1M branch from df506dc to 3d4cde5 Compare May 29, 2026 11:46
Copy link
Copy Markdown
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: 3

🧹 Nitpick comments (1)
packages/cli/src/data/field_selection.rs (1)

173-176: ⚡ Quick win

Strengthen these tests to assert full parsed values, not just count.

At Line 175 and Line 181, length-only assertions can miss incorrect section/field resolution. Please assert the full expected parsed output.

Proposed test tightening
 #[test]
 fn accepts_all_lowercase() {
     let sel = Selection::parse(&["block.gaslimit".into(), "log.blocknumber".into()]).unwrap();
-    assert_eq!(sel.columns.len(), 2);
+    let cols: Vec<(Section, &str)> = sel
+        .columns
+        .iter()
+        .map(|c| (c.section, c.indexer_name.as_str()))
+        .collect();
+    assert_eq!(
+        (cols, sel.known_height),
+        (
+            vec![(Section::Block, "gaslimit"), (Section::Log, "blocknumber")],
+            false,
+        ),
+    );
 }
 
 #[test]
 fn accepts_uppercase() {
     let sel = Selection::parse(&["block.GAS_LIMIT".into(), "log.TOPIC0".into()]).unwrap();
-    assert_eq!(sel.columns.len(), 2);
+    let cols: Vec<(Section, &str)> = sel
+        .columns
+        .iter()
+        .map(|c| (c.section, c.indexer_name.as_str()))
+        .collect();
+    assert_eq!(
+        (cols, sel.known_height),
+        (
+            vec![(Section::Block, "GAS_LIMIT"), (Section::Log, "TOPIC0")],
+            false,
+        ),
+    );
 }

As per coding guidelines, **/*.rs: “Always use single assert to check the whole value instead of multiple asserts for every field”.

Also applies to: 179-182

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/data/field_selection.rs` around lines 173 - 176, The test
accepts_all_lowercase currently only checks sel.columns.len(); instead assert
the full parsed output from Selection::parse for the inputs "block.gaslimit" and
"log.blocknumber" — e.g., compare sel.columns to the expected vector of parsed
section/field pairs (("block","gaslimit"), ("log","blocknumber")) or the
equivalent Column/Selection struct literal so the exact names and ordering are
validated; do the same tightening for the other test around lines 179-182 to
assert full parsed values instead of just length.
🤖 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/cli/CommandLineHelp.md`:
- Line 404: Replace the inconsistent level-6 headings (e.g., the literal string
"###### **Arguments:**" and the other similar occurrences noted) with the next
expected heading level (for example "### **Arguments:**") so the document uses a
consistent, valid heading hierarchy and fixes markdownlint MD001; update each
matching heading instance (the ones around the sections flagged) to the correct
level.
- Around line 412-414: The inline example for the --where flag is not fenced and
triggers markdownlint MD037; wrap the snippet starting with --where='{ block: {
number: { _gte: 1000, _lte: 2000 } }, log:   { srcAddress: "0xa0b8..." }, }' in
a fenced code block (use ```bash before and ``` after) so the example is
rendered as a code block and fixes the lint error and readability issues.

In `@packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md`:
- Around line 15-17: The fenced code block in SKILL.md that contains the command
example "envio data <field>... --chain=<id|name> [--where='<json5>']" is missing
a language tag; update the opening fence so it reads ```bash to satisfy MD040
and match other examples, i.e., add the bash language identifier to the fenced
code block in the file.

---

Nitpick comments:
In `@packages/cli/src/data/field_selection.rs`:
- Around line 173-176: The test accepts_all_lowercase currently only checks
sel.columns.len(); instead assert the full parsed output from Selection::parse
for the inputs "block.gaslimit" and "log.blocknumber" — e.g., compare
sel.columns to the expected vector of parsed section/field pairs
(("block","gaslimit"), ("log","blocknumber")) or the equivalent Column/Selection
struct literal so the exact names and ordering are validated; do the same
tightening for the other test around lines 179-182 to assert full parsed values
instead of just length.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a9408b13-bf78-423a-8a3e-7cfa7a1a691c

📥 Commits

Reviewing files that changed from the base of the PR and between df506dc and 3d4cde5.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • packages/cli/src/cli_args/snapshots/envio__cli_args__clap_definitions__test__envio_help_snapshot.snap is excluded by !**/*.snap
📒 Files selected for processing (18)
  • CLAUDE.md
  • packages/cli/Cargo.toml
  • packages/cli/CommandLineHelp.md
  • packages/cli/examples/script.rs
  • packages/cli/src/cli_args/clap_definitions.rs
  • packages/cli/src/data/chain.rs
  • packages/cli/src/data/field_selection.rs
  • packages/cli/src/data/mapping.rs
  • packages/cli/src/data/mod.rs
  • packages/cli/src/data/toon.rs
  • packages/cli/src/data/where_filter.rs
  • packages/cli/src/executor/data.rs
  • packages/cli/src/executor/mod.rs
  • packages/cli/src/lib.rs
  • packages/cli/src/template_dirs.rs
  • packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md
  • packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md
  • packages/cli/tests/data_integration.rs
✅ Files skipped from review due to trivial changes (4)
  • packages/cli/src/data/mod.rs
  • packages/cli/src/lib.rs
  • packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (11)
  • packages/cli/Cargo.toml
  • packages/cli/src/template_dirs.rs
  • packages/cli/examples/script.rs
  • packages/cli/src/executor/mod.rs
  • packages/cli/src/data/chain.rs
  • packages/cli/src/cli_args/clap_definitions.rs
  • packages/cli/src/executor/data.rs
  • packages/cli/tests/data_integration.rs
  • packages/cli/src/data/mapping.rs
  • packages/cli/src/data/toon.rs
  • packages/cli/src/data/where_filter.rs


**Usage:** `envio data [OPTIONS] --chain <CHAIN> [FIELD]...`

###### **Arguments:**
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

Use consistent heading increments in new sections.

These ###### headings skip levels and trigger markdownlint MD001. Please change them to the next expected level (e.g., ###) to keep heading structure valid.

Also applies to: 443-443, 456-456, 468-468

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 404-404: Heading levels should only increment by one level at a time
Expected: h3; Actual: h6

(MD001, heading-increment)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/CommandLineHelp.md` at line 404, Replace the inconsistent
level-6 headings (e.g., the literal string "###### **Arguments:**" and the other
similar occurrences noted) with the next expected heading level (for example
"### **Arguments:**") so the document uses a consistent, valid heading hierarchy
and fixes markdownlint MD001; update each matching heading instance (the ones
around the sections flagged) to the correct level.

Comment thread packages/cli/CommandLineHelp.md Outdated
Comment thread packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md Outdated
Copy link
Copy Markdown
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

🤖 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/cli/CommandLineHelp.md`:
- Line 396: The fenced code block is on a single line causing MD038; fix the
markdown by placing the opening ```text and closing ``` on their own lines and
move the command content between them, splitting long command arguments onto
separate indented lines (e.g., break after each backslash) so the command shown
(envio data block.number log.srcAddress log.transactionHash \ --chain=base \
--where='...') is on multiple lines between the fences.
- Line 400: The code fence and its content are on the same line for the example
with the command "envio data knownHeight --chain=arbitrum-one"; update the
markdown so the opening ```text and closing ``` are each on their own lines and
the command appears on the line(s) between them (i.e., change the single-line
"```text envio data knownHeight --chain=arbitrum-one ```" to a proper fenced
block with ```text on its own line, the command on the next line, and ``` on the
following line).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 88ea746a-1ac1-4d5c-b5bd-fc40b4928eb9

📥 Commits

Reviewing files that changed from the base of the PR and between 8d901ea and 1d7010a.

📒 Files selected for processing (2)
  • packages/cli/CommandLineHelp.md
  • packages/cli/src/cli_args/clap_definitions.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/cli_args/clap_definitions.rs

Comment thread packages/cli/CommandLineHelp.md Outdated
Comment thread packages/cli/CommandLineHelp.md Outdated

Current archive height:

```text envio data knownHeight --chain=arbitrum-one ```
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

Fix code fence formatting—content must be on separate lines.

Same issue as line 396: the fence and content are on one line.

📝 Proposed fix
-```text envio data knownHeight --chain=arbitrum-one ```
+```text
+envio data knownHeight --chain=arbitrum-one
+```
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```text envio data knownHeight --chain=arbitrum-one ```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 400-400: Spaces inside code span elements

(MD038, no-space-in-code)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/CommandLineHelp.md` at line 400, The code fence and its content
are on the same line for the example with the command "envio data knownHeight
--chain=arbitrum-one"; update the markdown so the opening ```text and closing
``` are each on their own lines and the command appears on the line(s) between
them (i.e., change the single-line "```text envio data knownHeight
--chain=arbitrum-one ```" to a proper fenced block with ```text on its own line,
the command on the next line, and ``` on the following line).

claude added 15 commits June 2, 2026 11:32
Wraps the HyperSync `/query` REST endpoint behind a CLI that uses the
same indexer-style `where` syntax as event filters and prints results
in TOON tabular form. Field selectors are indexer-side camelCase
(`block.number`, `log.srcAddress`, `transaction.transactionIndex`,
`receipt.contractId`) mapped to HS snake_case via a per-chain table
derived from `HyperSyncJsonApi.res` and `HyperFuelClient.res`.

Supports `--chain=<id|name>` for EVM chains and the special values
`fuel` / `fuel-testnet`; Solana errors with a friendly hint. `--where`
accepts YAML (default) or JSON, with `_gte/_gt/_lte/_lt` on the block
range collapsed into HS `from_block`/`to_block`. The `knownHeight`
pseudo-field hits `/height` directly when used alone, or appends the
archive height to a `/query` response when mixed with real fields.

After the data, prints `archive_height` + `next_block` and a
ready-to-run pagination hint to stderr so stdout stays pipeable.

Replaces the curl-based "Finding Block Ranges with HyperSync" recipe in
the indexer-testing skill with a pointer to a new `envio-data` skill.

Integration tests under `--features integration_tests` hit live
HyperSync (Base + Fuel testnet) end-to-end.
The where parser is now JSON5 — JSON-style braces with relaxed grammar
(unquoted keys, single quotes, trailing commas, `//` comments) — so
typical filters read like:

  --where='{
    block: { number: { _gte: 1000, _lte: 2000 } },
    log:   { srcAddress: "0xabc" },
  }'

The pagination hint is also emitted as a one-line JSON5 object so it
can be pasted straight back into --where. User-facing copy
(`envio data --help`, the envio-data skill, indexer-testing's block-
range section) now describes the feature as "blockchain data" rather
than naming the HyperSync backend.
Replace raw reqwest HTTP calls with the hypersync_client Rust crate for
EVM chains. The native client handles retries, rate limiting, payload-
too-large auto-splitting, and binary serialization — all free.

- mapping.rs: TypedField enum maps indexer names to net_types field
  enums (BlockField/TransactionField/LogField). Adds new EVM fields
  (blobGasUsed, l1Fee, yParity, etc.) from the crate's full enum set.
- field_selection.rs: build_net_field_selection() returns typed
  net_types::FieldSelection (BTreeSet) for the native client path.
- where_filter.rs: build_net_query() returns net_types::Query via the
  builder API with LogFilter/TransactionFilter.
- toon.rs: render_query_response() accepts typed QueryResponse and
  extracts values from simple_types structs using Hex::encode_hex().
- executor/data.rs: split into run_evm() (native client) and run_fuel()
  (reqwest fallback). User agent is envio-data/{version}.

Fuel chains remain on the reqwest + JSON path since hypersync_client is
EVM-only.

287 unit tests + 4 live integration tests pass.
Drop ChainKind enum and all Fuel/receipt/input/output code paths from
the data module. Fuel/fuel-testnet now errors with "not supported yet"
like Solana. This removes ~1000 lines: the FUEL_FIELDS mapping table,
the reqwest-based JSON query path (build_query_body, render_response,
fetch_height, post_query), and the Section::Receipt/Input/Output
variants.

Integration tests rewritten as end-to-end CLI invocations via
`cargo run --example script -- data ...` instead of calling internal
APIs. Tests cover: height query, block+log query, no-where pagination,
missing token error, unknown chain, solana hint, unknown field.
- Replace hs_name string with typed field enum directly: FieldEntry.field
  is now TypedField (non-optional), Column.hs_name and FieldFilter.hs_name
  removed — all dead code since the native client path uses typed enums.
- Add backtick fences around CLI examples in --help.
- Simplify FIELD help text (remove implementation details about /height).
- Add FIXME for Solana-specific field names in Selection::parse.
- Remove "Advanced: Finding Block Ranges" from indexer-testing skill.
- Revert test-indexer user agent logic from Main.res (keeping the
  ~userAgent plumbing in place for future use).
mapping.rs: Replace the 460-line hand-written FieldEntry table with
~40 lines that derive field lookups from strum's EnumString (camelCase
→ snake_case → from_str) and EnumIter (valid-names hint). Only alias:
srcAddress → address.

toon.rs: Replace 200 lines of per-field match arms (block_field_to_string,
tx_field_to_string, log_field_to_string) with a generic Arrow column
renderer. Uses get_arrow() instead of get() — columns are accessed by
name from RecordBatch, and a single cell_to_string handles all 4 Arrow
types (UInt64, UInt8, Boolean, Binary→hex).

Bump strum to 0.27 to match hypersync-net-types. Add arrow 57 as a
direct dep (already transitively present via hypersync-client).

Net: -489 lines.
…rAgent threading

- Replace all assert!(err.contains(...)) with insta::assert_snapshot!
  for exact error message coverage across chain, field_selection, and
  where_filter tests.
- Load ENVIO_API_TOKEN from .env file (via dotenvy) when the env var
  is not set, matching the runtime behavior.
- Update missing-token error wording to match the runtime's message.
- Remove Setup section from envio-data skill (the CLI prompts when
  the token is missing).
- Revert ~userAgent threading from all ReScript files (ChainManager,
  ChainFetcher, EvmChain, HyperSyncSource, HyperSyncClient, Main)
  back to main — keeping it for future use.
Normalize user input by lowercasing and stripping underscores, then
match against enum variants (whose strum Display names get the same
normalization). All of these now resolve to the same field:

  block.gasLimit  block.gas_limit  block.GASLIMIT  block.GAS_LIMIT

The approach uses strum EnumIter for exhaustiveness — any new variant
added upstream is automatically discoverable without manual mapping.

Output uses the user's original input verbatim (TOON column headers,
error messages). Help text uses camelCase matching the indexer.

Also stores the resolved TypedField in FieldFilter so build_net_query
matches on the typed enum instead of string comparison — fixing the
case where --where used non-canonical casing.
- Integration tests: replace all contains() checks with assert_eq! on
  the full error message. Extract error via "Caused by:" parsing,
  stopping at "Stack backtrace:".
- envio-data skill: cut from 87 to 47 lines. Removed setup section,
  output details, and verbose tips. Added knownHeight and case-
  insensitivity to description for better skill pickup.
- Clap help: moved TOON output line to its own paragraph so the
  one-liner in `envio --help` stays short.
- CLAUDE.md: added rule "Never use contains in test assertions".
- Quantity fields (gasLimit, timestamp, value, etc.) now render as
  decimal instead of hex. Added ColumnFormat enum (Decimal/Hex) to
  TypedField, classified per the hypersync schema. Binary columns
  use ruint::U256 for big-endian → decimal conversion.
- normalize_to_list now collects values from all operators (_eq, _in)
  instead of returning on the first match.
- Removed 4 duplicate error-case integration tests (already covered
  by unit test snapshots). Kept 3 network-dependent end-to-end tests.
- Added case-insensitive block range test for --where.
All assertion messages now include `{out}` which prints both stdout
and stderr via Display impl, so failures are immediately debuggable.
- query test: exact assert_eq on full stdout — 14 lines of deterministic
  data from ETH mainnet block 20000000 (11 USDT Transfer events).
  Verifies TOON format, decimal gasUsed, hex addresses, log indices.
- height test: asserts stdout structure (height[1]{value}: header +
  parseable number) and stderr message format.
- no_where test: asserts exact stdout (blocks[0]{number}:) and stderr
  structure (archive_height + next_block present).

Stderr contains live archive_height so it's checked structurally, not
by exact value.
- render_height/render_archive_height now emit `knownHeight[1]{value}:`
  matching the positional field name the user typed.
- All integration tests assert the full stderr content via a
  stderr_template() helper that replaces live numbers with <N>,
  so the exact message structure is verified while tolerating
  changing archive_height/next_block values.
- Use AsRefStr `as_ref()` instead of `to_string()` for field-enum
  comparisons (clippy::unnecessary_to_owned).
- Replace single-arm match with `if` for the srcAddress alias
  (clippy::single_match).
Rustdoc tried to compile the example shell commands inside the `Data`
variant's doc comment as Rust, failing CI's `cargo test --no-default-features`.
Use ```text fences so they're rendered as code without compilation.
@DZakh DZakh force-pushed the claude/amazing-thompson-IzI1M branch from 1d7010a to 7f5bf0b Compare June 2, 2026 11:36
Triple-backtick fences become single-line code blocks in the generated
help.md (clap-markdown collapses doc-comment lines), triggering MD038.
Inline single-backtick code spans render correctly as plain text in
the help and avoid both MD038 and rustdoc's doctest parsing.
Copy link
Copy Markdown
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.

♻️ Duplicate comments (4)
packages/cli/CommandLineHelp.md (3)

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

Use consistent heading increments.

The ###### **Arguments:** heading skips levels and triggers markdownlint MD001. This pattern appears throughout the file but should use ### to maintain proper heading hierarchy.

📝 Proposed fix
-###### **Arguments:**
+### **Arguments:**
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/CommandLineHelp.md` at line 404, Multiple headings like "######
**Arguments:**" use inconsistent heading levels and trigger markdownlint MD001;
replace those instances with a consistent level (e.g., "### **Arguments:**")
across CommandLineHelp.md so headings follow proper hierarchy, and scan the file
for other repeated "######" headings (such as any "###### **Options:**" or
similar) to normalize them to the chosen level to maintain consistent
increments.

412-414: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Format the --where example as a fenced code block.

The inline --where example triggers markdownlint MD037 and reduces readability. Wrapping it in a fenced code block will fix the linting issue and improve presentation.

📝 Proposed fix
-* `--where <WHERE_FILTER>` — Filter in indexer `where` form, as JSON5 — JSON-style braces with relaxed syntax: unquoted keys, single quotes, trailing commas, and `//` comments are all accepted. Example:
-
-   --where='{ block: { number: { _gte: 1000, _lte: 2000 } }, log:   { srcAddress: "0xa0b8..." }, }'
+* `--where <WHERE_FILTER>` — Filter in indexer `where` form, as JSON5 — JSON-style braces with relaxed syntax: unquoted keys, single quotes, trailing commas, and `//` comments are all accepted. Example:
+  ```bash
+  --where='{ block: { number: { _gte: 1000, _lte: 2000 } }, log: { srcAddress: "0xa0b8..." } }'
+  ```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/CommandLineHelp.md` around lines 412 - 414, Wrap the inline
--where example in a fenced code block (use triple backticks and specify bash)
so the example becomes a standalone code block; locate the line containing
"--where='{ block: { number: { _gte: 1000, _lte: 2000 } }, log:   { srcAddress:
"0xa0b8..." }, }'" and surround it with ```bash and ``` to satisfy markdownlint
MD037 and improve readability.

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

Fix code fence formatting—content must be on separate lines.

Both example code blocks have the opening fence, command text, and closing fence on a single line, triggering markdownlint MD038 and causing incorrect rendering.

📝 Proposed fix
-```text envio data block.number log.srcAddress log.transactionHash \ --chain=base \ --where='{ block: { number: { _gte: 0 } }, log: { srcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" }, }' ```
+```text
+envio data block.number log.srcAddress log.transactionHash \
+  --chain=base \
+  --where='{ block: { number: { _gte: 0 } }, log: { srcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" }, }'
+```
-```text envio data knownHeight --chain=arbitrum-one ```
+```text
+envio data knownHeight --chain=arbitrum-one
+```

Also applies to: 400-400

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/CommandLineHelp.md` at line 396, The code fence lines in
CommandLineHelp.md currently place the opening fence, content, and closing fence
on one line (triggering MD038); split each problematic inline fence into a
proper multi-line fenced code block by moving the command text onto its own
lines between ```text and ```, e.g., update the example block containing "envio
data block.number log.srcAddress log.transactionHash \ --chain=base \
--where=..." and the block with "envio data knownHeight --chain=arbitrum-one" so
the fence markers are on their own lines and the command lines (including
backslash continuations) sit between them, preserving indentation and trailing
backslashes as shown in the proposed fix.
packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md (1)

15-17: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language tag to fenced code block.

The command synopsis fence is missing a language identifier, triggering markdownlint MD040. Use bash for consistency with other command examples.

📝 Proposed fix
-```
+```bash
 envio data <field>... --chain=<id|name> [--where='<json5>']
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md
around lines 15 - 17, The fenced code block showing the command synopsis "envio
data ... --chain=<id|name> [--where='']" is missing a language
tag; update that fenced block to include the bash language identifier (i.e.,
change tobash) so markdownlint MD040 is satisfied and it matches other
command examples.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @packages/cli/CommandLineHelp.md:

  • Line 404: Multiple headings like "###### Arguments:" use inconsistent
    heading levels and trigger markdownlint MD001; replace those instances with a
    consistent level (e.g., "### Arguments:") across CommandLineHelp.md so
    headings follow proper hierarchy, and scan the file for other repeated "######"
    headings (such as any "###### Options:" or similar) to normalize them to the
    chosen level to maintain consistent increments.
  • Around line 412-414: Wrap the inline --where example in a fenced code block
    (use triple backticks and specify bash) so the example becomes a standalone code
    block; locate the line containing "--where='{ block: { number: { _gte: 1000,
    _lte: 2000 } }, log: { srcAddress: "0xa0b8..." }, }'" and surround it with
    bash and to satisfy markdownlint MD037 and improve readability.
  • Line 396: The code fence lines in CommandLineHelp.md currently place the
    opening fence, content, and closing fence on one line (triggering MD038); split
    each problematic inline fence into a proper multi-line fenced code block by
    moving the command text onto its own lines between text and , e.g., update
    the example block containing "envio data block.number log.srcAddress
    log.transactionHash \ --chain=base \ --where=..." and the block with "envio data
    knownHeight --chain=arbitrum-one" so the fence markers are on their own lines
    and the command lines (including backslash continuations) sit between them,
    preserving indentation and trailing backslashes as shown in the proposed fix.

In @packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md:

  • Around line 15-17: The fenced code block showing the command synopsis "envio
    data ... --chain=<id|name> [--where='']" is missing a language
    tag; update that fenced block to include the bash language identifier (i.e.,
    change tobash) so markdownlint MD040 is satisfied and it matches other
    command examples.

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Organization UI

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `376b17d9-2f36-4d06-975f-96fd9bf192db`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1d7010ad4e6a557e0881bb41d88a4f6d0baee478 and 7f5bf0b7026f74cfeaeac1a9e1e091710b228d98.

</details>

<details>
<summary>⛔ Files ignored due to path filters (2)</summary>

* `Cargo.lock` is excluded by `!**/*.lock`
* `packages/cli/src/cli_args/snapshots/envio__cli_args__clap_definitions__test__envio_help_snapshot.snap` is excluded by `!**/*.snap`

</details>

<details>
<summary>📒 Files selected for processing (18)</summary>

* `CLAUDE.md`
* `packages/cli/Cargo.toml`
* `packages/cli/CommandLineHelp.md`
* `packages/cli/examples/script.rs`
* `packages/cli/src/cli_args/clap_definitions.rs`
* `packages/cli/src/data/chain.rs`
* `packages/cli/src/data/field_selection.rs`
* `packages/cli/src/data/mapping.rs`
* `packages/cli/src/data/mod.rs`
* `packages/cli/src/data/toon.rs`
* `packages/cli/src/data/where_filter.rs`
* `packages/cli/src/executor/data.rs`
* `packages/cli/src/executor/mod.rs`
* `packages/cli/src/lib.rs`
* `packages/cli/src/template_dirs.rs`
* `packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md`
* `packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md`
* `packages/cli/tests/data_integration.rs`

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (2)</summary>

* packages/cli/src/lib.rs
* packages/cli/src/data/mod.rs

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (13)</summary>

* CLAUDE.md
* packages/cli/src/executor/mod.rs
* packages/cli/src/data/field_selection.rs
* packages/cli/examples/script.rs
* packages/cli/src/template_dirs.rs
* packages/cli/Cargo.toml
* packages/cli/src/data/chain.rs
* packages/cli/src/cli_args/clap_definitions.rs
* packages/cli/src/data/toon.rs
* packages/cli/tests/data_integration.rs
* packages/cli/src/data/mapping.rs
* packages/cli/src/executor/data.rs
* packages/cli/src/data/where_filter.rs

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

- Spell every BlockField/TransactionField/LogField variant so the
  compiler flags new variants instead of silently defaulting to Hex.
- Drop the archive_height/next_block stderr lines and the
  "Done — next_block ..." message; only print a pagination hint when
  the query is not exhausted.
- Rephrase the pagination hint to explain it shows the next query.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the chain-height aside from the normal next-page hint and reword
  it as "run the following command".
- When next_block reaches archive_height, emit a dedicated message
  explaining we hit the chain head and that rerunning the same command
  later picks up newly available data.
- Range-exhausted pagination stays silent.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
TOON scalars use 'key: value', not a single-row table — drop the
[1]{value} table form for both render_height and render_archive_height.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
Note that all block/log/transaction fields are supported, and that the
where syntax accepts the full operator set (_eq, _in, _gte, _lte, _gt,
_lt) — replace the standalone operators table with a one-liner.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the H1 intro that duplicated the frontmatter description; keep
  only the "do NOT web-search" emphasis as a standalone note.
- Replace "etc." with explicit "any EVM block/log/transaction field".
- Add an indexer-testing tip pointing at the envio-data skill for block
  range lookups.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the dead `indexer_name: String` field on both `Column` and
  `FieldFilter`; derive the user-facing name via a new
  `TypedField::camel_name()` helper, so the canonical camelCase is
  echoed back in TOON headers, pagination hints, and error messages
  regardless of the case the user typed.
- Delete `render_archive_height` (verbatim copy of `render_height`)
  and change `render_height` to take `u64`, matching the upstream
  types and removing the `as i64` casts at call sites.
- Factor the log/transaction filter setup into `apply_log_filter` and
  `apply_tx_filter` so the two halves of `build_net_query` no longer
  duplicate the `filter_values_as_strs` + `.as_str()` plumbing.
- Collapse the Solana/Fuel "not supported yet" branches in
  `chain::resolve` into a single match keyed on the chain family name.
- Replace the three booleans driving pagination output with a
  `PaginationState` enum and a single `match`, so the dispatch is
  exhaustive.
- Fold the empty-string token guard into `resolve_api_token`'s return
  filter instead of trimming after `ok_or_else`.
- Replace the hand-rolled digit walker in `stderr_template()` with a
  one-line regex (the crate already depends on `regex`).
- Tighten `data::*` module visibility to `pub(crate)` — none of these
  types cross the NAPI boundary.
- Drop the stale `// FIXME: EVM-specific` comment that violated the
  "don't narrate" convention.
- Promote `render_table` to take `&[impl AsRef<str>]` so callers can
  pass `Vec<String>` without a transient `Vec<&str>` allocation.
- Replace `_ => String::new()` in `cell_to_string` with an
  `unreachable!` — the column set is bounded, silently dropping
  unexpected arrow types would only mask bugs.
- Fix the `--where` documentation in the envio-data SKILL to reflect
  the actual filterable surface (block.number ranges, log addr/topic0-3,
  tx from/to/sighash) instead of claiming every field supports every
  operator.

All 313 unit tests still pass; clippy is clean with `-D warnings`.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
The `hypersync-health-check` CI job runs `cargo test` with a feature
flag intended only for pinging public hypersync endpoints. When the new
`envio data` integration tests were added they reused the same flag,
so the health-check job ended up running them too — and a flaky
"page from genesis" assertion broke the job on every push.

- Rename the existing `integration_tests` feature to `hypersync_health`
  so its scope is obvious from the name; update the gated module in
  `hypersync_endpoints.rs` and the CI workflow.
- Add a new `data_integration_tests` feature gating
  `tests/data_integration.rs`, so the data tests are runnable on their
  own (`cargo test --features data_integration_tests`) without being
  pulled into the health check.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the `data_integration_tests` feature gate from
  `tests/data_integration.rs` so the tests are picked up by
  `cargo test --no-default-features` (the cargo-test CI job).
- Add a `skip_without_token()` helper so each test silently skips when
  `ENVIO_API_TOKEN` is absent — keeps local `cargo test` and fork-PR
  builds green while still exercising the suite anywhere the secret is
  available (workflow-level env var).
- Reinstate `integration_tests` as a compat alias for `hypersync_health`
  so the base-branch workflow (still on main until this PR lands)
  continues to find the feature it asks for. Drop after main picks up
  the renamed step.
- Replace the flaky "page from genesis" test with a deterministic
  filter (`block 18_000_000..=19_000_000`, USDT logs) that always
  exceeds one hypersync batch and therefore always hits the
  `MorePages` branch.
- Tighten the digit-replacing template regex to `\b\d+\b` so digits
  embedded in hex addresses keep their literal characters while
  standalone integers (block numbers, chain id) become `<N>`.
- Echo back the user's `--chain=` input in the pagination hint by
  storing the normalized user string in `Chain.display` instead of the
  resolved chain id.

https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
@DZakh DZakh enabled auto-merge (squash) June 2, 2026 14:51
@DZakh DZakh disabled auto-merge June 2, 2026 14:53
)

* feat(cli): filter `envio data` by any field

Extend the `envio data` `--where` filter to accept any block, transaction,
or log field. Set-membership filters on fields Hypersync can filter (log
address/topics, transaction from/to/sighash/hash/contractAddress) are
pushed to the server. Everything else — other fields, and all
`_gt`/`_gte`/`_lt`/`_lte` comparisons (numeric only; rejected on hex
fields) — is evaluated client-side over the Arrow response. Client filters
apply per-section, so related rows in other sections may remain.

* feat(cli): push transaction status/type and block hash/miner server-side

Extend the server-filterable set in `envio data --where` to the remaining
fields with a Hypersync builder: transaction `status` (single value) and
`type`, and block `hash`/`miner` (via `where_blocks`). Multi-value
`status` falls back to client-side since the server takes a single value.

`TypedField::server_filterable` stays the single source of truth for which
fields route server-side; each filter type's builder dispatch enforces that
invariant.

* docs(cli): compact --where help text

* refactor(cli): drive --where field handling from a FieldSpec registry

Replace the scattered `server_filterable` predicate, alias lookup, and
per-section builder matches with a single per-field config: each field
resolves to a `FieldSpec { aliases, value_kind, server }`.

- `value_kind` (Numeric/Hex/Bool) drives client parse, compare, and render,
  and makes comparison support explicit (numeric only).
- `server: Option<ServerFilter>` is the single source of truth for
  server-side routing; one tag-driven apply per filter type dispatches it.
- aliases move into the spec; lookup matches name or any alias.

Collapses the three section-specific server-filter vectors into one
`server_filters` list. Behavior-preserving.

* test(cli): end-to-end client-side --where filtering; tighten help + skill

- Add an integration test driving the full pipeline (parse --where →
  classify → compute_masks → render): numeric range, `_in`, and a
  big-endian binary numeric comparison across two sections.
- Make the --where help text terser.
- Update the envio-data skill: any field is filterable, with numeric
  comparison ops; refresh examples.

---------

Co-authored-by: Claude <noreply@anthropic.com>
* Fix envio data returning empty for filter-less block/log/transaction selections

HyperSync only returns rows that match a selection, so a query like
`envio data block.hash --chain=base` produced an empty response: no
log/transaction/block selection meant nothing to return.

Add an unfiltered selection for every entity the user requests fields
for, and set include_all_blocks when block fields are wanted but no
filter scopes the blocks. Bare queries now stream from block zero.

* Support _eq/_in and shorthand for block.number in envio data

block.number now accepts the same forms as other fields: a scalar or
`_eq` pins a single block, and an array or `_in` scans [min, max] then
drops the leftover blocks client-side. Comparison operators keep their
existing range semantics. The pagination hint folds a carried-forward
set back into the number range so reruns keep filtering the same blocks.

* Use block.number shorthand in block-only integration test

---------

Co-authored-by: Claude <noreply@anthropic.com>
…ts, auto-paginate sparse results (#1280)

- TOON headers now echo the field name exactly as typed (block.NUMBER -> NUMBER)
- next-page hint for a block.number set carries only the unfetched values as _in
- automatically fetch following pages while fewer than 100 rows are available

Co-authored-by: Claude <noreply@anthropic.com>
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