Skip to content

FRO-211 / ROB-3946 Truncate over-wide summary table cells instead of wrapping#2123

Open
alonelish wants to merge 3 commits into
masterfrom
claude/summary-table-truncation-fix-4627ca
Open

FRO-211 / ROB-3946 Truncate over-wide summary table cells instead of wrapping#2123
alonelish wants to merge 3 commits into
masterfrom
claude/summary-table-truncation-fix-4627ca

Conversation

@alonelish

Copy link
Copy Markdown
Collaborator

What & why

Jira ROB-3946 / Linear FRO-211

The Slack "Alerts Summary - N Notifications" grouping digest rendered a corrupted ASCII table. When the label:site column held long Java class names (e.g. ats.betting.betcatcher.settlement.settler.AbstractBetSettler), each value was word-wrapped across multiple physical lines instead of being truncated — mangling every row (ServiceImpl / erviceImpl spilling onto the next line).

Root cause

TableBlock.to_table_string() passed maxcolwidths=col_max_width to tabulate, and tabulate wraps over-wide cells onto extra physical lines rather than truncating them. The digest is built in send_or_update_summary_message()TableBlock(...)to_markdown()to_table_string(). The bug title says "trimmed" but the code wrapped.

The fix (src/robusta/core/reporting/blocks.py)

  • Truncate, don't wrap. to_table_string() now truncates over-wide cells itself with a single-char ellipsis and no longer passes maxcolwidths to tabulate, so every row stays on one physical line.
  • Left-trim dotted class names. For space-free dotted qualified names (Java FQCNs), truncation keeps the distinctive suffix (…settler.AbstractBetSettler), since the class name is at the end; plain text (with spaces) is trimmed from the right. (1 char) is used over ... (3 chars) so width accounting stays exact.
  • Never shrink numeric columns. __calc_max_width now detects columns whose non-empty cells are all numeric (the Fired / Resolved counters) and leaves them at full width; the overflow is water-filled across the widest text columns (fair distribution + a minimum-width floor) instead of gutting a single column.

Tables that already fit render byte-identical to before.

Before / after (real prod-az2 screenshot data)

Before — wrapped:

 ats.betting.betcatcher.service.BetcatcherS | az  |   0 |   1
 erviceImpl                                 |     |     |

After — single line, suffix preserved:

 ….betcatcher.service.BetcatcherServiceImpl | az                |       0 |          1
 …ation.impl.AccountRestrictionBetValidator | az                |       0 |          1
 ats.wallet.DefaultFundsAdjuster            | az                |       0 |          1

Tests

  • Adds regression tests in tests/test_blocks.py proving rows stay single-line and over-wide cells are truncated (not wrapped): line-count invariant, truncation, dotted-name suffix retention, numeric columns never truncated, and trailing-cut for plain text.
  • Existing test_transformer.py table/HTML tests still pass (the HTML path uses tabulate directly and is unaffected).
pytest tests/test_blocks.py tests/test_transformer.py -k "to_table_string or to_markdown_wide or to_html"
21 passed

Manual verification in Slack

The change is centralized in to_table_string, so it affects every sink that renders a TableBlock (Slack, Discord, Google Chat, Zulip, PagerDuty, incident.io, …). To exercise the exact digest path end-to-end, run the manual repro (not part of this PR unless requested):

SLACK_TOKEN=xoxb-... SLACK_CHANNEL=test-robusta python tests/manual_tests/summary_table_slack_repro.py

🤖 Generated with Claude Code

The Slack "Alerts Summary" digest rendered a corrupted ASCII table: long
values in text columns (e.g. Java class names in `label:site`) were passed
to tabulate via `maxcolwidths`, which *wraps* cells onto extra physical
lines rather than truncating them, mangling every following row.

TableBlock.to_table_string now truncates over-wide cells itself (with a
single-char "…" ellipsis) so each row stays on one line, and no longer
passes maxcolwidths to tabulate. Dotted, space-free qualified names are
trimmed from the left to keep the distinctive class-name suffix (e.g.
`…settler.AbstractBetSettler`); other text is trimmed from the right.

__calc_max_width now water-fills the reduction across the widest text
columns (fair distribution, with a minimum width floor) and never shrinks
numeric columns, so the Fired/Resolved counters are always shown in full.

Adds regression tests proving rows stay single-line and are truncated
(not wrapped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Docker image ready for 476f656 (built in 1m 30s)

⚠️ Warning: does not support ARM (ARM images are built on release only - not on every PR)

Use this tag to pull the image for testing.

📋 Copy commands

⚠️ Temporary images are deleted after 30 days. Copy to a permanent registry before using them:

gcloud auth configure-docker us-central1-docker.pkg.dev
docker pull us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:476f656
docker tag us-central1-docker.pkg.dev/robusta-development/temporary-builds/robusta-runner:476f656 me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:476f656
docker push me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:476f656

Patch Helm values in one line:

helm upgrade --install robusta robusta/robusta \
  --reuse-values \
  --set runner.image=me-west1-docker.pkg.dev/robusta-development/development/robusta-runner-dev:476f656

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4d6a5a57-692c-4c04-804d-a4fa1c609c11

📥 Commits

Reviewing files that changed from the base of the PR and between aeac173 and 82fb6a2.

📒 Files selected for processing (1)
  • src/robusta/core/reporting/blocks.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/robusta/core/reporting/blocks.py

Walkthrough

TableBlock now calculates numeric-aware column widths and truncates headers and cells before rendering. Tests cover single-line output, dotted identifiers, numeric values, plain text, ragged rows, and Markdown rendering.

Changes

Table truncation

Layer / File(s) Summary
Width calculation and cell truncation
src/robusta/core/reporting/blocks.py
Adds truncation constants, numeric-column detection, water-fill width reduction, minimum text widths, and ellipsis-based truncation with dotted-name suffix preservation.
Rendering integration and regression coverage
src/robusta/core/reporting/blocks.py, tests/test_blocks.py
Pre-truncates headers and rows before tabulate, with tests for single-line rows, numeric columns, dotted names, plain text, ragged rows, and Markdown output.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TableBlock
  participant WidthCalculation
  participant CellTruncation
  participant tabulate
  TableBlock->>WidthCalculation: calculate bounded numeric-aware widths
  WidthCalculation->>CellTruncation: apply per-column limits
  CellTruncation-->>TableBlock: return truncated headers and cells
  TableBlock->>tabulate: render pre-truncated table
  tabulate-->>TableBlock: return aligned table output
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: truncating over-wide summary table cells instead of wrapping them.
Description check ✅ Passed The description directly explains the table truncation fix, root cause, and accompanying tests, matching the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 claude/summary-table-truncation-fix-4627ca

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@src/robusta/core/reporting/blocks.py`:
- Around line 410-413: Update the shrinkable-column selection around
__numeric_column_indices so an all-numeric table does not fall back to
list(range(num_columns)). Preserve numeric columns at full width when no
non-numeric column exists, while retaining the existing behavior of shrinking
non-numeric columns when available.
- Around line 399-403: Update the table width calculation around num_columns and
columns_max_widths so it expands to cover every column in rendered_rows,
including when headers is empty or rows contain more values than headers.
Preserve header widths and use the resulting column widths for subsequent
rendering without indexing beyond the list.
🪄 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: 7dc50a4d-7ee1-45bf-9126-dc189ce565f8

📥 Commits

Reviewing files that changed from the base of the PR and between eb350a4 and bdd71c6.

📒 Files selected for processing (2)
  • src/robusta/core/reporting/blocks.py
  • tests/test_blocks.py

Comment thread src/robusta/core/reporting/blocks.py Outdated
Comment thread src/robusta/core/reporting/blocks.py Outdated
- __calc_max_width now sizes columns to the widest row, not just the
  headers, so headerless or ragged tables no longer raise IndexError.
- An all-numeric over-width table is left at full width instead of
  ellipsizing the numbers.
- Shorten code/test comments; add regression tests for both cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/test_blocks.py (1)

159-162: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove redundant and ineffective wrap-spillover assertion.

The assertion not any(line.strip() in ("ServiceImpl", "erviceImpl") for line in lines) is technically ineffective. Because the presto table format includes column dividers (e.g., |), a wrapped line would look something like erviceImpl | |, meaning line.strip() would never exactly match the literal strings in the tuple.

Furthermore, the explicit line-count assertion earlier (len(lines) == 2 + len(rows)) already perfectly guarantees that no extra physical lines were generated. You can safely remove this check.

♻️ Proposed fix
-    # The class name is truncated, not present in full, and no wrap-spillover fragment.
+    # The class name is truncated, not present in full.
     assert LONG_CLASS_NAME not in output
     assert "…" in output
-    assert not any(line.strip() in ("ServiceImpl", "erviceImpl") for line in lines)
🤖 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 `@tests/test_blocks.py` around lines 159 - 162, Remove the ineffective
any-based wrap-spillover assertion from the test around LONG_CLASS_NAME. Keep
the existing LONG_CLASS_NAME, ellipsis, and line-count assertions unchanged,
since the line-count check already verifies that no extra physical lines are
produced.
🤖 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.

Nitpick comments:
In `@tests/test_blocks.py`:
- Around line 159-162: Remove the ineffective any-based wrap-spillover assertion
from the test around LONG_CLASS_NAME. Keep the existing LONG_CLASS_NAME,
ellipsis, and line-count assertions unchanged, since the line-count check
already verifies that no extra physical lines are produced.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 80dc6ee8-bc69-449e-8dbe-2737c81ce6ae

📥 Commits

Reviewing files that changed from the base of the PR and between bdd71c6 and aeac173.

📒 Files selected for processing (2)
  • src/robusta/core/reporting/blocks.py
  • tests/test_blocks.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/robusta/core/reporting/blocks.py

@alonelish alonelish changed the title ROB-3946 Truncate over-wide summary table cells instead of wrapping FRO-211 / ROB-3946 Truncate over-wide summary table cells instead of wrapping Jul 15, 2026
Drop the Slack-digest-specific "Fired/Resolved" example, since blocks.py
is core code shared across all sinks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alonelish alonelish requested a review from Avi-Robusta July 15, 2026 14:27
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.

1 participant