Skip to content

1670: [TUI] Show executor's details in a popup#27

Open
martin-augment wants to merge 3 commits intomainfrom
pr-1670-2026-05-08-12-15-35
Open

1670: [TUI] Show executor's details in a popup#27
martin-augment wants to merge 3 commits intomainfrom
pr-1670-2026-05-08-12-15-35

Conversation

@martin-augment
Copy link
Copy Markdown
Owner

1670: To review by AI

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an executor details popup to the Ballista CLI TUI, allowing users to view detailed information about a selected executor, including OS info and metrics. Key changes include new domain models for executor details, API client support for fetching these details, and the UI implementation for the popup with scrollable content and updated key bindings. Feedback focuses on optimizing performance by reducing unnecessary string allocations and clones, and addressing a missing upper bound check in the popup's scroll logic.

Comment on lines +425 to +426
let executor_id = executor.id.clone();
if let Err(e) = load_executor_details_popup(self, &executor_id).await {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The executor_id is cloned unnecessarily here. Since load_executor_details_popup accepts a &str, you can pass a reference to the ID instead to avoid an allocation.

Suggested change
let executor_id = executor.id.clone();
if let Err(e) = load_executor_details_popup(self, &executor_id).await {
let executor_id = &executor.id;
if let Err(e) = load_executor_details_popup(self, executor_id).await {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:good-to-have; category:bug; feedback: The Gemini AI reviewer is correct! There is no need to clone the String. Using a reference of it is good enough too. Prevents wasting some stack memory.

Comment on lines +81 to +83
pub fn scroll_down(&mut self) {
self.scroll_position = self.scroll_position.saturating_add(1);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The scroll_down method increments the scroll position without an upper bound. This can lead to the UI rendering an empty popup if the user scrolls past the actual number of lines generated in the view. Consider passing the maximum number of lines or handling the bounds check in the UI layer.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:good-to-have; category:bug; feedback: The Gemini AI reviewer is correct! The scroll_position should not grow more than ~20 lines, otherwise it will scroll down too much and no info will be shown on the popup window. Prevents rendering useless popup content.

]),
Line::from(vec![
Span::styled(" ID ", label_style),
Span::raw(executor.id.clone()),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using .clone() here is unnecessary as Span::raw can accept a reference &str. Since the executor is already borrowed, you can pass a reference to avoid an allocation. This also applies to other fields like os.system_name, os.os_ver, etc., later in this function.

Suggested change
Span::raw(executor.id.clone()),
Span::raw(&executor.id),

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:good-to-have; category:bug; feedback: The Gemini AI reviewer is correct! There is no need to clone the String. Using a reference of it is good enough too. Prevents wasting some stack memory.

Comment on lines +135 to +143
fn metric_name(typ: &str) -> String {
match typ {
"proc_physical_memory" => "Physical Memory".to_string(),
"proc_virtual_memory" => "Virtual Memory".to_string(),
"peak_physical_memory" => "Peak Physical Memory".to_string(),
"peak_virtual_memory" => "Peak Virtual Memory".to_string(),
_ => typ.to_string(),
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The metric_name function can return a &str instead of a String to avoid unnecessary allocations, as all return paths can provide a string slice with the same lifetime as the input or a static lifetime.

Suggested change
fn metric_name(typ: &str) -> String {
match typ {
"proc_physical_memory" => "Physical Memory".to_string(),
"proc_virtual_memory" => "Virtual Memory".to_string(),
"peak_physical_memory" => "Peak Physical Memory".to_string(),
"peak_virtual_memory" => "Peak Virtual Memory".to_string(),
_ => typ.to_string(),
}
}
fn metric_name(typ: &str) -> &str {
match typ {
"proc_physical_memory" => "Physical Memory",
"proc_virtual_memory" => "Virtual Memory",
"peak_physical_memory" => "Peak Physical Memory",
"peak_virtual_memory" => "Peak Virtual Memory",
_ => typ,
}
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:good-to-have; category:bug; feedback: The Gemini AI reviewer is correct! There is no need to return a String instance. The function can return a string slice too. Prevents wasting some stack memory.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack

Walkthrough

This PR introduces two independent changes. First, it adds configuration rules to four agent files (.cursor/rules.md, .gemini/rules.md, AGENTS.md, CLAUDE.md) restricting AI agents from linking to GitHub issues/PRs in code reviews and from reviewing other AI agents' configuration files. Second, it implements a new executor details popup feature in the ballista-cli TUI, including new data models for executor details and OS information, an HTTP client method to fetch executor data, event-driven state management, keyboard interactions (scroll/close), popup rendering with formatted content, and comprehensive test coverage for all new functionality.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr-1670-2026-05-08-12-15-35

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.

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented May 8, 2026

🤖 Augment PR Summary

Summary: This PR enhances the Ballista CLI TUI executors view by adding an “executor details” popup that fetches and displays extended executor information.

Changes:

  • Introduced a new executor details popup UI with scroll support and an Esc close action
  • Added an Enter key binding on the executors view to load and open the details popup for the selected executor
  • Extended executor domain models to include specification, metrics, and OS info (plus a popup state holder)
  • Added a new HTTP client call to fetch executor details from the scheduler API
  • Extended the UI event/data model to carry executor details payloads
  • Updated footer key binding hints to reflect the new popup interactions
  • Added unit tests for selection helpers, popup scrolling, metric name mapping, and size formatting

Technical Notes: The popup renders metrics and OS information and uses DataFusion’s human-readable formatters for durations/sizes.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.


#[derive(Deserialize, Clone, Debug)]
pub struct Specification {
pub task_slots: u16,
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 8, 2026

Choose a reason for hiding this comment

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

ballista-cli/src/tui/domain/executors.rs:47: The scheduler REST API uses wider/optional types for executor fields (e.g., task_slots/physical_cores/num_disks are u32, open_files_limit is u64, and last_seen can be null when no heartbeat exists), but the CLI structs use narrower non-optional integers (u16/u32/i64). This can lead to JSON deserialization failures (or truncation) when values exceed these ranges or when last_seen is missing.

Severity: medium

Other Locations
  • ballista-cli/src/tui/domain/executors.rs:54
  • ballista-cli/src/tui/domain/executors.rs:55
  • ballista-cli/src/tui/domain/executors.rs:58

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:useful; category:bug; feedback: The Augment AI reviewer is correct! The types of the data transferred with REST should match to avoid mismatches and data loss after transfer from the scheduler to the TUI application.

format!(" {:<20} ", metric_name(&metric.typ)),
label_style,
),
Span::raw(app.format_size(metric.value as usize)),
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 8, 2026

Choose a reason for hiding this comment

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

ballista-cli/src/tui/ui/main/executors/executor_details_popup.rs:87: Casting u64 byte counts (metric.value, total_disk_space, total_available_disk_space) to usize can truncate on 32-bit targets and for extremely large values, leading to incorrect sizes being displayed. This is especially relevant since these numbers are naturally u64 in the scheduler API.

Severity: low

Other Locations
  • ballista-cli/src/tui/ui/main/executors/executor_details_popup.rs:121
  • ballista-cli/src/tui/ui/main/executors/executor_details_popup.rs:125

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:good-but-wont-fix; category:bug; feedback: The Augment AI reviewer is correct! The data coming from the Scheduler REST API uses u64 type but the helper methods coming from DataFusion use usize and this leads to the castings. The TUI application is not expected to be used on a 32-bit system, since DataFusion itself does not support it, so there is no need to worry here.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0c506cd. Configure here.

format!(" {:<20} ", metric_name(&metric.typ)),
label_style,
),
Span::raw(app.format_size(metric.value as usize)),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Lossy u64 as usize cast truncates large values

Low Severity

metric.value, os.total_disk_space, and os.total_available_disk_space are u64 but are cast to usize via as usize before passing to format_size. On 32-bit targets, usize is 32 bits, so any value above ~4 GB is silently truncated, producing incorrect display output. Disk space values routinely exceed 4 GB, making this a realistic truncation scenario on those platforms.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0c506cd. Configure here.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:good-but-wont-fix; category:bug; feedback: The Bugbot AI reviewer is correct! The data coming from the Scheduler REST API uses u64 type but the helper methods coming from DataFusion use usize and this leads to the castings. The TUI application is not expected to be used on a 32-bit system, since DataFusion itself does not support it, so there is no need to worry here.

@claude
Copy link
Copy Markdown

claude Bot commented May 8, 2026

Code Review: TUI – Show Executor Details in a Popup

Overview

This PR adds an executor-details popup to the Ballista TUI. Pressing Enter on a selected executor fires an HTTP request, streams the response through the existing event channel, and renders an ExecutorDetailsPopup with OS info, metrics, and specifications. The implementation follows the existing job-stages popup pattern faithfully.

Positives

  • Consistent with established patterns (job stages popup, event channel, etc.)
  • Solid unit-test coverage across domain types, app helpers, and the metric_name mapping
  • saturating_sub/saturating_add correctly prevents scroll-position underflow
  • Proper tracing::trace! / tracing::error! usage
  • Footer key-binding section also gets the missing "Current view key bindings:" prefix fix

Issues and Suggestions

1. No-op serde attribute on OsInfo

#[serde(rename = "os_info")] on the struct type is a no-op for JSON deserialization — only the field name in the parent struct matters. Remove it, or if renaming is the goal, place the attribute on the field inside ExecutorDetails.

2. Narrowing cast u64 to usize in format_size

format_size accepts usize, but disk-space fields and metric.value are u64. On 64-bit targets this works, but it will truncate silently on 32-bit and triggers a clippy warning. Consider changing the signature to accept u64 directly, or at minimum document why 32-bit truncation is acceptable.

3. Unused _popup parameter in build_lines

The function signature carries _popup: &ExecutorDetailsPopup but never uses it (scroll is applied by the caller). Drop the parameter to keep the API honest.

4. No upper bound on scroll position

scroll_down can increment indefinitely past the last line. ratatui renders blank space silently, which is poor UX. Consider capping at lines.len().saturating_sub(visible_height). Nice-to-have, not a blocker.

5. Import split in event.rs

ExecutorDetails is imported with a separate use statement even though Executor from the same module is already imported in the grouped block below. Merge them for consistency.

6. Minor: format!(...).as_str() pattern in http_client.rs

self.url(format!("executor/{}", ...).as_str()) creates a temporary String then takes a reference. self.url(&format!("executor/{}", ...)) is equivalent and more idiomatic.

Test Coverage

Domain logic and app helpers have good coverage. The rendering path (render_executor_details_popup, build_lines) is untested, which is typical for TUI rendering. A smoke test that calls build_lines directly and checks the resulting line count/content for a fixed ExecutorDetails would add value without needing a terminal backend.

Summary

The feature is well-structured and follows established patterns. The three items to address before merging are: the no-op #[serde(rename)] attribute, the u64 to usize narrowing cast in format_size, and the unused _popup parameter. Everything else is minor polish.

Copy link
Copy Markdown

@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

🤖 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 `@ballista-cli/src/tui/domain/executors.rs`:
- Around line 28-29: Update the TUI deserialization types to match the API:
change the executor struct's last_seen field to an optional integer (e.g.,
Option<u64> or Option<i64>) and/or add #[serde(default)] so nulls deserialize
without error, and change Specification::task_slots from u16 to u32 to match the
API; alternatively ensure the API's ExecutorSpecification type used by the TUI
derives Deserialize (add Deserialize to ExecutorSpecification) so the
Specification type used in this file can be deserialized correctly.
🪄 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: 7c3cb993-ef6b-4ac8-9049-efbf47aa3b44

📥 Commits

Reviewing files that changed from the base of the PR and between 1537e05 and 0c506cd.

📒 Files selected for processing (14)
  • .cursor/rules.md
  • .gemini/rules.md
  • AGENTS.md
  • CLAUDE.md
  • ballista-cli/src/tui/app.rs
  • ballista-cli/src/tui/domain/executors.rs
  • ballista-cli/src/tui/event.rs
  • ballista-cli/src/tui/http_client.rs
  • ballista-cli/src/tui/mod.rs
  • ballista-cli/src/tui/ui/footer.rs
  • ballista-cli/src/tui/ui/main/executors/executor_details_popup.rs
  • ballista-cli/src/tui/ui/main/executors/mod.rs
  • ballista-cli/src/tui/ui/main/mod.rs
  • ballista-cli/src/tui/ui/mod.rs

Comment on lines +28 to +29
pub specification: Specification,
pub metrics: Vec<Metric>,
Copy link
Copy Markdown

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
# Description: Check if the API documentation or response types include specification and metrics

# Search for API response struct definitions or documentation
rg -nP --type=rust -C5 'struct.*Executor.*Response|pub.*struct.*Executor[^a-zA-Z]' -g '!**/tui/**'

# Search for any API endpoint handlers that return executor data
rg -nP --type=rust -C5 'executor.*api|get.*executor' -g '**/server/**' -g '**/scheduler/**'

Repository: martin-augment/datafusion-ballista

Length of output: 49775


🏁 Script executed:

#!/bin/bash
# Examine the TUI Executor struct and its deserialization
cat -n ballista-cli/src/tui/domain/executors.rs | head -60

# Search for any deserialization logic or serde attributes
rg -n 'serde|Deserialize|from_' ballista-cli/src/tui/domain/executors.rs | head -20

Repository: martin-augment/datafusion-ballista

Length of output: 2603


🏁 Script executed:

#!/bin/bash
# Find ExecutorSpecification and ExecutorMetricResponse definitions
rg -n 'struct ExecutorSpecification|struct ExecutorMetricResponse' -A 5 ballista/scheduler/src/api/

# Also check for any custom deserializers
rg -n 'impl.*Deserialize|#\[serde' ballista-cli/src/tui/domain/executors.rs

Repository: martin-augment/datafusion-ballista

Length of output: 143


🏁 Script executed:

#!/bin/bash
# Broader search for type definitions
rg -n 'ExecutorSpecification|ExecutorMetricResponse' --type=rust | head -30

# Also check the handlers file more carefully for the full context
sed -n '60,80p' ballista/scheduler/src/api/handlers.rs

Repository: martin-augment/datafusion-ballista

Length of output: 3923


🏁 Script executed:

#!/bin/bash
# Get the full ExecutorMetricResponse and ExecutorSpecification definitions
sed -n '88,110p' ballista/scheduler/src/api/handlers.rs

# Also check for ExecutorSpecification source (likely protobuf generated)
rg -n 'struct ExecutorSpecification|pub struct ExecutorSpecification' ballista-core/src/serde/

# Check imports in handlers.rs
head -35 ballista/scheduler/src/api/handlers.rs | tail -15

Repository: martin-augment/datafusion-ballista

Length of output: 1640


🏁 Script executed:

#!/bin/bash
# Find ExecutorSpecification definition (in ballista_core/src)
fd -t f 'scheduler' ballista-core/src/serde/ 2>/dev/null | head -10

# Search more broadly
rg -n 'pub struct ExecutorSpecification' ballista-core/

# Also check what the API actually serializes
sed -n '254,275p' ballista/scheduler/src/api/handlers.rs

Repository: martin-augment/datafusion-ballista

Length of output: 803


🏁 Script executed:

#!/bin/bash
# Search for ExecutorSpecification in ballista directory
find ballista -name "*.rs" -type f -exec grep -l "pub struct ExecutorSpecification" {} \;

# Also check what type it is
rg -B2 -A5 'pub struct ExecutorSpecification' ballista/

Repository: martin-augment/datafusion-ballista

Length of output: 1457


🏁 Script executed:

#!/bin/bash
# Check the full ExecutorSpecification implementation in scheduler/mod.rs
sed -n '/pub struct ExecutorSpecification/,/^}/p' ballista/core/src/serde/scheduler/mod.rs | head -30

# Check if there are any #[serde] attributes on ExecutorSpecification
rg -B5 -A10 'pub struct ExecutorSpecification' ballista/core/src/serde/scheduler/mod.rs

Repository: martin-augment/datafusion-ballista

Length of output: 643


🏁 Script executed:

#!/bin/bash
# Check if ExecutorSpecification derives Deserialize
rg -B10 'pub struct ExecutorSpecification' ballista/core/src/serde/scheduler/mod.rs | grep -E '#\[derive|Deserialize'

# Check the actual JSON serialization of ExecutorMetricResponse
rg -B5 -A20 'impl.*ExecutorMetricResponse' ballista/scheduler/src/api/handlers.rs | head -40

# Look at what serde does with ExecutorMetricResponse enum
rg -B5 'pub enum ExecutorMetricResponse' ballista/scheduler/src/api/handlers.rs | head -20

Repository: martin-augment/datafusion-ballista

Length of output: 1231


🏁 Script executed:

#!/bin/bash
# Verify how ExecutorMetricResponse serializes to JSON by checking serde tag usage
rg -B3 -A10 '#\[serde.*tag.*type.*content' ballista/scheduler/src/api/handlers.rs

# Check if there are any integration tests showing the actual JSON structure
rg -n 'ExecutorBriefResponse|ExecutorMetricResponse' ballista/scheduler/src/api/handlers.rs | grep -i test

# Search for tests that show the JSON structure
fd -t f '*.rs' ballista/scheduler/src/api | xargs grep -l 'json\|json!'

Repository: martin-augment/datafusion-ballista

Length of output: 745


🏁 Script executed:

#!/bin/bash
# Check the serde tag configuration for ExecutorMetricResponse
sed -n '88,110p' ballista/scheduler/src/api/handlers.rs

# Look for integration tests or examples showing actual API responses
find ballista/scheduler/src -name "*.rs" -type f | xargs grep -l 'ExecutorBriefResponse' | head -5

# Check if there are any test files
ls -la ballista/scheduler/src/api/

Repository: martin-augment/datafusion-ballista

Length of output: 1277


🏁 Script executed:

#!/bin/bash
# Let me understand the exact JSON structure that will be generated
# Check if ExecutorMetricResponse has Deserialize derive
rg -B10 'pub enum ExecutorMetricResponse' ballista/scheduler/src/api/handlers.rs | grep -E 'Serialize|Deserialize'

# Create a simple Python script to show what the JSON will look like
python3 << 'EOF'
# Show what the serde enum serialization produces
enum_config = {
    'tag': 'type',
    'content': 'value',
    'rename_all': 'snake_case'
}

variants = [
    'AvailableMemory(64)',
    'TotalMemory(256)',
    'UsedMemory(128)'
]

print("With #[serde(tag=\"type\", content=\"value\", rename_all=\"snake_case\")]:")
print("AvailableMemory(64) serializes to:")
print('{"type": "available_memory", "value": 64}')
print()
print("TUI Metric struct expects:")
print('{"type": "...", "value": ...}')
print("So deserialization should work!")
EOF

# The real issue is last_seen - check the type mismatch
echo "=== API last_seen type ==="
sed -n '70,77p' ballista/scheduler/src/api/handlers.rs
echo "=== TUI last_seen type ==="
sed -n '22,30p' ballista-cli/src/tui/domain/executors.rs

Repository: martin-augment/datafusion-ballista

Length of output: 875


🏁 Script executed:

#!/bin/bash
# Check if there are any custom serde attributes on the TUI fields
cat -n ballista-cli/src/tui/domain/executors.rs | sed -n '20,35p'

# Check if there are any custom deserializers in the file
rg -n 'deserialize' ballista-cli/src/tui/domain/executors.rs

# Verify the actual type mismatch - check if Specification matches
sed -n '45,48p' ballista-cli/src/tui/domain/executors.rs
echo "=== API Specification ==="
sed -n '500,550p' ballista/core/src/serde/scheduler/mod.rs | grep -A 10 'pub struct ExecutorSpecification'

# Check how the API actually handles null/None values in JSON
rg -B5 -A5 'last_seen.*Option' ballista/scheduler/src/api/handlers.rs

Repository: martin-augment/datafusion-ballista

Length of output: 965


🏁 Script executed:

#!/bin/bash
# Verify the ExecutorSpecification serialization attributes
rg -B5 -A10 'pub struct ExecutorSpecification' ballista/core/src/serde/scheduler/mod.rs

# Check the full serde configuration
sed -n '175,230p' ballista/core/src/serde/scheduler/mod.rs | head -50

# Final verification: does ExecutorSpecification derive Serialize/Deserialize?
rg '#\[derive' ballista/core/src/serde/scheduler/mod.rs | grep -B1 -A1 'ExecutorSpecification'

Repository: martin-augment/datafusion-ballista

Length of output: 2081


🏁 Script executed:

#!/bin/bash
# Critical check: Does ExecutorSpecification derive Deserialize?
rg -B10 'pub struct ExecutorSpecification' ballista/core/src/serde/scheduler/mod.rs | head -15

# And verify if it's used in any deserialization context in the TUI
rg -n 'from_str|deserialize' ballista-cli/src/tui/ | grep -i executor

# Final check: How does the TUI client actually fetch executor data?
rg -n 'get_executors\|ExecutorBriefResponse\|Executor' ballista-cli/src/ | grep -E '\.rs:.*http|\.rs:.*client|\.rs:.*request' | head -10

Repository: martin-augment/datafusion-ballista

Length of output: 520


🏁 Script executed:

#!/bin/bash
# Check exactly what ExecutorSpecification derives - get the full line
sed -n '170,185p' ballista/core/src/serde/scheduler/mod.rs

# Check if there are any serde attributes on ExecutorSpecification
rg -B3 'pub struct ExecutorSpecification' ballista/core/src/serde/scheduler/mod.rs | head -10

# Verify Specification type in TUI - does it have u32 or u16 for task_slots?
sed -n '45,50p' ballista-cli/src/tui/domain/executors.rs

Repository: martin-augment/datafusion-ballista

Length of output: 972


🏁 Script executed:

#!/bin/bash
# Check if ExecutorSpecification has a custom Deserialize implementation
rg -n 'impl.*Deserialize.*ExecutorSpecification|impl.*From.*ExecutorSpecification' ballista/core/src/serde/scheduler/mod.rs

# Check if ExecutorMetricResponse has Deserialize
rg -B20 'pub enum ExecutorMetricResponse' ballista/scheduler/src/api/handlers.rs | grep -E 'Deserialize|derive'

# Check if there's a custom impl for deserializing ExecutorMetricResponse
rg -n 'impl.*Deserialize.*ExecutorMetricResponse' ballista/scheduler/src/api/handlers.rs

# Look for FromStr or From trait implementations
rg -n 'impl.*From.*for.*Executor|impl.*From.*for.*Specification' ballista-cli/src/tui/

Repository: martin-augment/datafusion-ballista

Length of output: 183


Fix type mismatches between API responses and TUI deserialization structs.

The API does provide specification and metrics fields, but deserialization will fail due to type incompatibilities:

  1. last_seen type mismatch: API sends Option<u128> (can be null), but TUI expects i64 (non-nullable). When the API returns null, deserialization will fail.

  2. ExecutorSpecification not deserializable: The API's ExecutorSpecification derives only Serialize, not Deserialize. Additionally, it has task_slots: u32 while the TUI expects task_slots: u16.

Changes needed:

  • Change TUI's last_seen field from i64 to Option<u64> or Option<i64> with #[serde(default)]
  • Change TUI's Specification::task_slots from u16 to u32 to match the API, or ensure ExecutorSpecification implements Deserialize
🤖 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 `@ballista-cli/src/tui/domain/executors.rs` around lines 28 - 29, Update the
TUI deserialization types to match the API: change the executor struct's
last_seen field to an optional integer (e.g., Option<u64> or Option<i64>) and/or
add #[serde(default)] so nulls deserialize without error, and change
Specification::task_slots from u16 to u32 to match the API; alternatively ensure
the API's ExecutorSpecification type used by the TUI derives Deserialize (add
Deserialize to ExecutorSpecification) so the Specification type used in this
file can be deserialized correctly.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

value:useful; category:bug; feedback: The CodeRabbit AI reviewer is correct! The type of last_seen should be an Option of an integer. There is no need to read it as u128 though. No one expects to support dates in the far future and the helper methods to format timestamps as string work with i64. annoying: There is no ExecutorSpecification struct in the application code base

@martin-augment
Copy link
Copy Markdown
Owner Author

1. No-op serde attribute on OsInfo

#[serde(rename = "os_info")] on the struct type is a no-op for JSON deserialization — only the field name in the parent struct matters. Remove it, or if renaming is the goal, place the attribute on the field inside ExecutorDetails.

value:useful; category:bug; feedback: The Claude AI reviewer is correct! Indeed the Serde attribute is misplaced. It should be on a struct field instead of the struct itself, where it is ignored.

@martin-augment
Copy link
Copy Markdown
Owner Author

4. No upper bound on scroll position

scroll_down can increment indefinitely past the last line. ratatui renders blank space silently, which is poor UX. Consider capping at lines.len().saturating_sub(visible_height). Nice-to-have, not a blocker.

value:good-to-have; category:bug; feedback: The CodeRabbit AI reviewer is correct! The scroll_position should not grow more than ~20 lines, otherwise it will scroll down too much and no info will be shown on the popup window. Prevents rendering useless popup content.

@martin-augment
Copy link
Copy Markdown
Owner Author

2. Narrowing cast u64 to usize in format_size

format_size accepts usize, but disk-space fields and metric.value are u64. On 64-bit targets this works, but it will truncate silently on 32-bit and triggers a clippy warning. Consider changing the signature to accept u64 directly, or at minimum document why 32-bit truncation is acceptable.

value:good-but-wont-fix; category:bug; feedback: The Claude AI reviewer is correct! The data coming from the Scheduler REST API uses u64 type but the helper methods coming from DataFusion use usize and this leads to the castings. The TUI application is not expected to be used on a 32-bit system, since DataFusion itself does not support it, so there is no need to worry here.

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