fix(response_analyzer): guard against zero last_output_length (division by zero) - #333
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
Walkthrough
ChangesOutput Length Guard Fix
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 `@tests/unit/test_exit_detection.bats`:
- Around line 1465-1489: The regression test for analyze_response only covers an
empty .last_output_length file, so it does not actually exercise the non-numeric
path. Update the test in test_exit_detection.bats to include a separate real
non-numeric value for .last_output_length in addition to the empty-file case, so
the [[ "$last_length" =~ ^[0-9]+$ ]] guard is validated for both branches. Keep
the coverage centered on analyze_response and the .last_output_length setup.
🪄 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: b22e8c0a-47b6-4fba-8c4d-28471e94abb7
📒 Files selected for processing (1)
tests/unit/test_exit_detection.bats
Code Review — requesting-code-reviewReview of the division-by-zero guard fix + regression tests (head abe93b6). Strengths
Findings
Rejected (pushback)
AssessmentCritical 0 · Important 0 · Minor 1 (valid, quick-win) · Rejected 1. The fix is correct; no merge blocker. |
AI Review Summary — receiving-code-review
Verdict✅ Critical 0 · Important 0 · Minor 1 (deferred, valid) · Rejected 1. The guard covers zero / empty / non-numeric |
…sion
Split the empty/non-numeric regression test into two cases. The empty
case only exercised the guard via an empty value; add a sibling test that
writes real non-numeric content ('not-a-number') so the ^[0-9]+$ guard's
false branch is covered with a non-empty value too.
Addresses the CodeRabbit review comment on PR frankbria#333.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d division by zero When .last_output_length contains 0 (e.g. a prior loop recorded an empty/zero-length response), the output-length trend check did output_length*100/last_length, which aborts response_analyzer.sh with a division-by-zero and kills the loop mid-output. Skip the ratio computation unless last_length is a positive integer.
…_length guard Cover the division-by-zero guard added in this PR: assert analyze_response does not abort when .last_output_length is 0, empty, or non-numeric, and still produces .response_analysis. Both fail on the pre-fix code with "division by 0 (error token is last_length)" and pass with the guard.
…sion
Split the empty/non-numeric regression test into two cases. The empty
case only exercised the guard via an empty value; add a sibling test that
writes real non-numeric content ('not-a-number') so the ^[0-9]+$ guard's
false branch is covered with a non-empty value too.
Addresses the CodeRabbit review comment on PR frankbria#333.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e8b2147 to
1b595df
Compare
Cross-family review — opencode (zai/glm-5.2)Adversarial Review — PR #333Guard logic analysisThe condition
The two-layer guard is correctly redundant: FindingsSuggestion — lib/response_analyzer.sh:804 (criterion 2 test coverage): Acceptance criterion 2 ("positive last length still adds +10") is preserved by the code but not asserted by any test in this diff; the three new tests only cover the no-crash cases. A fourth test with a prior Nitpick — lib/response_analyzer.sh:806 ( Edge cases verified safe
SecurityNo new external input surface, no Test qualityThe three regression tests are well-constructed: they VerdictAPPROVE |
…(review feedback) Cross-family GLM review noted criterion 2 (normal-path behavior unchanged) had no test. Differential assertion: same output analyzed with last length 1000 (ratio <50% -> +10) vs 1 (no bonus); score delta must be 10. Mutation-verified (disabling the +=10 fails the test). Reads .analysis.confidence_score from .ralph/.response_analysis.
Final Triage Summary (PR #333)Cutoff: 2026-07-10T18:59:38Z — no new findings since cutoff. Applied
Skipped (with justification)
CI note
Demo
|
Problem
lib/response_analyzer.shaborts with a division-by-zero when$RALPH_DIR/.last_output_lengthcontains0:This happens whenever a prior loop wrote a zero/empty output length into
.last_output_length(e.g. an interrupted or crashed agent call that produced no output). On the next loop,analyze_response()dies mid-execution and takes the whole loop down — the loop crashes while streaming output:Fix
Compute
length_ratioonly whenlast_lengthis a positive integer. This also guards against an empty or non-numeric file.if [[ -f "$RALPH_DIR/.last_output_length" ]]; then local last_length=$(cat "$RALPH_DIR/.last_output_length") - local length_ratio=$((output_length * 100 / last_length)) - - if [[ $length_ratio -lt 50 ]]; then - # Output is less than 50% of previous - possible completion - ((confidence_score+=10)) + # Guard against missing/zero previous length (avoids division by zero) + if [[ "$last_length" =~ ^[0-9]+$ ]] && (( last_length > 0 )); then + local length_ratio=$((output_length * 100 / last_length)) + + if [[ $length_ratio -lt 50 ]]; then + # Output is less than 50% of previous - possible completion + ((confidence_score+=10)) + fi fi fiBehavior
last_length > 0.0/ empty / non-numeric, the "declining engagement" heuristic is skipped for that loop (no false completion signal) instead of crashing the loop.Summary by CodeRabbit