Skip to content

fix: display full error messages instead of truncated table output#72

Open
jordanpartridge wants to merge 1 commit intomasterfrom
fix/table-truncation-issue-63
Open

fix: display full error messages instead of truncated table output#72
jordanpartridge wants to merge 1 commit intomasterfrom
fix/table-truncation-issue-63

Conversation

@jordanpartridge
Copy link
Copy Markdown
Contributor

@jordanpartridge jordanpartridge commented Mar 13, 2026

Problem

Laravel Prompts table() function truncates long error messages at column width limits (~140 characters), making it impossible for users to debug test failures.

Root Cause

File: app/Commands/CertifyCommand.php:149-152

The table() function formats output in fixed-width columns, causing truncation like:

│ Tests & Coverage │ bifrost:withings:auth → it shows auth URL when no code provided: ! bifrost:withings:auth → it fails when client_id is missing → file_g… 0.02s │

Solution

  • Removed table() import and call
  • Replaced with line-by-line output using $this->line()
  • Format: ✗ CheckName: full error message
  • No character limits or truncation

Testing

Added regression test with 260+ character error message to verify full display without truncation.

Impact

  • ✅ Users can now see complete error messages for debugging
  • ✅ Maintains visual formatting with colored output
  • ✅ Backward compatible - no breaking changes
  • ✅ Fixes critical issue blocking multiple repositories

Closes #63

Summary by CodeRabbit

Release Notes

  • Improvements
    • Updated failure message display format for better readability and clarity
    • Long error messages from failing checks are now displayed in full without truncation

Replace Laravel Prompts table() with line-by-line output so long error
messages are no longer truncated. Closes #63.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 13, 2026

📝 Walkthrough

Walkthrough

The CertifyCommand failure display was refactored from a table format to individual formatted lines to eliminate truncation of long error messages. Two new tests validate that complete error messages from multiple checks display without truncation.

Changes

Cohort / File(s) Summary
Failure Output Refactoring
app/Commands/CertifyCommand.php
Changed failure presentation from table format with headers to plain formatted lines with red cross and bolded check names, preventing message truncation.
Long Message Test Coverage
tests/Unit/Commands/CertifyCommandTest.php
Added two tests validating full error message display without truncation: one for single check with long detail and one for multiple checks with simultaneous long details.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 The table grew too tight, my friend,
With truncated lines that wouldn't end!
Now error messages flow complete and clear,
No more mystery ... need we fear! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 clearly and specifically describes the main change: replacing truncated table output with full error messages.
Linked Issues check ✅ Passed The PR implements all coding requirements from issue #63: removes table() truncation, replaces with line-by-line output with colored formatting, and adds regression tests for messages >140 characters.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the truncation issue: modifications to failure display logic in CertifyCommand and new test coverage for long error messages.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/table-truncation-issue-63
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@github-actions
Copy link
Copy Markdown

📊 Coverage Report

Metric Coverage Threshold Status
Lines 68.2% 100%

Files Below Threshold

File Coverage Uncovered Lines
app/Commands/AnalyzeCommand.php 0% 22, 23, 25, 26, 28... (+51 more)
app/Commands/CheckCommand.php 0% 30, 31, 33, 34, 37... (+91 more)
app/Transformers/PhpStanPromptTransformer.php 3.6% 49, 51, 52, 53, 54... (+76 more)
app/Transformers/TestFailurePromptTransformer.php 11.7% 47, 68, 69, 71, 72... (+101 more)
app/Services/PromptAssembler.php 88.9% 55, 56, 57, 58, 120
app/GitHub/ChecksClient.php 89.1% 218, 219, 222, 223, 226... (+8 more)

🏆 Synapse Sentinel Gate

@github-actions
Copy link
Copy Markdown

🔧 Synapse Sentinel: 2 checks need attention

The following issues must be resolved before this PR can be merged:


All tests passed.---

Security Audit


Review the output and fix any issues.

Quick Reference:

  • PHPStan errors → Fix type mismatches first, then missing types
  • Test failures → Read the assertion message, trace expected vs actual
  • Style issues → Run composer format to auto-fix

🤖 Generated by Synapse Sentinel - View Run

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 the current code and only fix it if needed.

Inline comments:
In `@app/Commands/CertifyCommand.php`:
- Around line 148-152: The console output is injecting unescaped dynamic values
from failureRows ($row[0], $row[1]) into a formatted string, which lets any
"<...>" sequences be interpreted as Symfony formatting tags; fix it by escaping
both values with Symfony\Component\Console\Formatter\OutputFormatter::escape()
(or equivalent escape helper available in CertifyCommand) before interpolating
them into the styled $this->line call so the red/white styling remains but the
content is printed verbatim.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 981724e8-9643-425b-905c-6329cbceac58

📥 Commits

Reviewing files that changed from the base of the PR and between 5691a60 and fa97dcd.

📒 Files selected for processing (2)
  • app/Commands/CertifyCommand.php
  • tests/Unit/Commands/CertifyCommandTest.php

Comment on lines +148 to +152
$this->newLine();
foreach ($failureRows as $row) {
$this->line(" <fg=red>✗</> <fg=white;options=bold>{$row[0]}</>: {$row[1]}");
}
$this->newLine();
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

🧩 Analysis chain

🏁 Script executed:

# First, find and read the CertifyCommand.php file
find . -name "CertifyCommand.php" -type f

Repository: synapse-sentinel/gate

Length of output: 98


🏁 Script executed:

# Read the CertifyCommand.php file, focusing on the area around lines 148-152
wc -l ./app/Commands/CertifyCommand.php

Repository: synapse-sentinel/gate

Length of output: 102


🏁 Script executed:

cat -n ./app/Commands/CertifyCommand.php | sed -n '130,170p'

Repository: synapse-sentinel/gate

Length of output: 1875


🏁 Script executed:

# Now let me find where $failureRows is populated
cat -n ./app/Commands/CertifyCommand.php | head -150 | tail -50

Repository: synapse-sentinel/gate

Length of output: 2321


🏁 Script executed:

# Search for failureRows initialization/population
grep -n "failureRows" ./app/Commands/CertifyCommand.php

Repository: synapse-sentinel/gate

Length of output: 259


🏁 Script executed:

# Let me see the full context around lines 71 and 94 where failureRows is created/populated
cat -n ./app/Commands/CertifyCommand.php | sed -n '65,100p'

Repository: synapse-sentinel/gate

Length of output: 1567


🏁 Script executed:

# Let me find where CheckResult or similar is defined to understand what $result->details contains
find . -name "*.php" -type f | xargs grep -l "class.*Check\|interface.*Check" | head -10

Repository: synapse-sentinel/gate

Length of output: 375


🏁 Script executed:

# Also, let me look at the runCheck method to understand the result structure
cat -n ./app/Commands/CertifyCommand.php | sed -n '170,234p'

Repository: synapse-sentinel/gate

Length of output: 2297


🏁 Script executed:

# Let me examine the CheckResult class to understand what $details contains
cat -n ./app/Checks/CheckResult.php

Repository: synapse-sentinel/gate

Length of output: 796


🏁 Script executed:

# Let me check the various Check implementations to see what data goes into details
cat -n ./app/Checks/SecurityScanner.php | head -100

Repository: synapse-sentinel/gate

Length of output: 2330


🏁 Script executed:

# Also check TestRunner
cat -n ./app/Checks/TestRunner.php | head -100

Repository: synapse-sentinel/gate

Length of output: 4064


🏁 Script executed:

# Continue reading TestRunner to see parseFailureDetails implementation
cat -n ./app/Checks/TestRunner.php | sed -n '100,180p'

Repository: synapse-sentinel/gate

Length of output: 2103


🏁 Script executed:

# Let me check if OutputFormatter is already used in the codebase
grep -r "OutputFormatter" ./app --include="*.php"

Repository: synapse-sentinel/gate

Length of output: 47


🏁 Script executed:

# Also check what PestOutputParser returns for parseFailures to understand the content better
cat -n ./app/Services/PestOutputParser.php | head -80

Repository: synapse-sentinel/gate

Length of output: 3304


🏁 Script executed:

# Let me check what dependencies are available, particularly Symfony
cat composer.json | grep -A 20 '"require"'

Repository: synapse-sentinel/gate

Length of output: 555


🏁 Script executed:

# Also check if there are any console-related imports in CertifyCommand
head -30 ./app/Commands/CertifyCommand.php

Repository: synapse-sentinel/gate

Length of output: 926


🏁 Script executed:

# Check if symfony/console is available as a transitive dependency
cat composer.lock | grep -A 5 '"name": "symfony/console"'

Repository: synapse-sentinel/gate

Length of output: 328


🏁 Script executed:

# Also verify what base class CertifyCommand extends and where line() comes from
grep -r "class Command" ./app --include="*.php" -A 5

Repository: synapse-sentinel/gate

Length of output: 47


🏁 Script executed:

# Search for escape or sanitize patterns in the codebase
grep -r "escape\|sanitize\|htmlspecialchars" ./app --include="*.php"

Repository: synapse-sentinel/gate

Length of output: 47


Escape dynamic failure text before writing styled console output.

At line 150, $row[0] and $row[1] are injected directly into a formatted console string. These values originate from external sources: check names, package names from composer audit JSON, test failure messages from Pest output, and file paths. If any contain <...> patterns, Symfony's OutputFormatter will parse them as formatting tags, potentially stripping or altering content and breaking error visibility.

Proposed fix
+use Symfony\Component\Console\Formatter\OutputFormatter;
...
                 $this->newLine();
                 foreach ($failureRows as $row) {
-                    $this->line("  <fg=red>✗</> <fg=white;options=bold>{$row[0]}</>: {$row[1]}");
+                    $checkName = OutputFormatter::escape((string) $row[0]);
+                    $detail = OutputFormatter::escape((string) $row[1]);
+                    $this->line("  <fg=red>✗</> <fg=white;options=bold>{$checkName}</>: {$detail}");
                 }
                 $this->newLine();
📝 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
$this->newLine();
foreach ($failureRows as $row) {
$this->line(" <fg=red>✗</> <fg=white;options=bold>{$row[0]}</>: {$row[1]}");
}
$this->newLine();
$this->newLine();
foreach ($failureRows as $row) {
$checkName = OutputFormatter::escape((string) $row[0]);
$detail = OutputFormatter::escape((string) $row[1]);
$this->line(" <fg=red>✗</> <fg=white;options=bold>{$checkName}</>: {$detail}");
}
$this->newLine();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/Commands/CertifyCommand.php` around lines 148 - 152, The console output
is injecting unescaped dynamic values from failureRows ($row[0], $row[1]) into a
formatted string, which lets any "<...>" sequences be interpreted as Symfony
formatting tags; fix it by escaping both values with
Symfony\Component\Console\Formatter\OutputFormatter::escape() (or equivalent
escape helper available in CertifyCommand) before interpolating them into the
styled $this->line call so the red/white styling remains but the content is
printed verbatim.

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.

🐛 Table output truncates long error messages

1 participant