Skip to content

Say why a render stopped when its unit tests keep failing - #332

Open
gorandodig wants to merge 1 commit into
mainfrom
fix/eng-325-name-the-render-stop-cause
Open

gorandodig wants to merge 1 commit into
mainfrom
fix/eng-325-name-the-render-stop-cause

Conversation

@gorandodig

@gorandodig gorandodig commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

When a functionality's unit tests still fail after its last render attempt, the render now prints why it stopped and where the last test output is, instead of logging None.

What happens now

The log and the TUI show the same stop reason:

[00:32:30] INFO codeplain: ↻ The Unit Tests script has failed. Initiating the patching mode to automatically correct the discrepancies.
[00:32:30] ERROR codeplain: Functionality 1: unit tests still fail after 2 render attempts, 20 fix rounds each. Last unit tests output: /tmp/tmpk3x9q2_1.script_output
[00:32:31] INFO codeplain: To continue rendering from the last successfully rendered functionality, provide the --render-from 1 flag.

The path is the file the client already writes for every unit tests run, the same one the TUI lists as "Unit tests output". The client doesn't keep a total fix-round count per functionality. A render attempt is only restarted after its unit tests use up all 20 fix rounds, though, so "20 fix rounds each" is exact.

The other stop paths change too, because they go through the same code:

  • Every other stop (conformance tests failing after their last attempt, environment errors, a functionality that is too complex): the log line shows the message. Before, it showed the raw payload, e.g. {'error': {'message': ..., 'type': ..., 'details': ...}}.
  • Unit tests failing a second time while conformance tests are being fixed: the TUI shows "Failed to adjust the unit tests ... for functionality 1 ..." instead of Unexpected error format: dict, and the log has that line once. Before, it was followed by a dump of the last unit tests output.

Why it happened

When the last render attempt ran out, RenderFunctionalRequirement stored its message in last_error_message but returned no error payload. ExitWithError logged whatever payload it was handed, which here was None. After that, CodeRenderer overwrote last_error_message with ExitWithError's payload dict, and ModuleRenderer passed that dict to the TUI. The TUI's error display can't handle a dict: it raised AttributeError: 'dict' object has no attribute 'translate'.

Now ExitWithError works out the stop reason once. It uses the failed action's error payload if there is one, otherwise the stored message. It logs that reason, and ModuleRenderer sends the same string to the TUI. RenderError.from_payload treats a payload that isn't in the error format as "no error" instead of producing Unexpected error format: dict. dispatch_error stopped logging, since ExitWithError now logs the message.

Verification

  • I added tests/test_render_stop_reason.py before changing anything. Its two main tests run the real render state machine through the last failing unit tests run of functionality 1, using a unit tests script that exits 1 and a fake API:
    • after the last implementation attempt: the ERROR log line is exactly the new message, the named output file exists, and the TUI text is the same string.
    • after the last allowed failure while conformance tests are being fixed: one ERROR line naming the cause, and the TUI text is the same string.
    • Three more tests check what ExitWithError logs for an error payload, a non-error payload, and no payload.
  • Before the fix, all 5 failed, and the first logged exactly ['None']. A scratch probe of the same path showed the TUI receiving a dict that the error display rejected with the AttributeError above. After the fix the probe gets the message string and it renders.

Summary by CodeRabbit

  • Bug Fixes
    • Rendering failures now show the most relevant available error message, including the cause of repeated unit-test failures.
    • Error messages are preserved for the TUI, and missing messages are no longer displayed as “None.”
    • Reaching the render-attempt limit now reports the configured number of fix rounds and, when available, the latest unit-test output path.

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2540f009-68f6-4e27-8781-83b5fbe1bf6f
📥 Commits

Reviewing files that changed from the base of the PR and between 2f721a4 and 432702b.

📒 Files selected for processing: 7
  • module_renderer.py
  • render_machine/actions/exit_with_error.py
  • render_machine/actions/render_functional_requirement.py
  • render_machine/code_renderer.py
  • render_machine/render_context.py
  • render_machine/render_types.py
  • tests/test_render_stop_reason.py
💤 Files with no reviewable changes: 1
  • render_machine/code_renderer.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

📝 Walkthrough

Render errors now carry iteration-limit details and flow through the render failure path. Error handling stores and logs resolved messages, while render failure display uses the stored message with a default fallback.

Changes: Render Error Handling

Layer / File(s) Summary
Create and decode render errors
render_machine/actions/render_functional_requirement.py, render_machine/render_types.py, tests/test_render_stop_reason.py
Iteration-limit outcomes include an encoded error message with fix-round details and, when available, the latest unit-test output path. RenderError.from_payload returns None for non-error payloads. Tests cover unit-test failures at the configured limits.
Resolve and display failure messages
render_machine/actions/exit_with_error.py, render_machine/code_renderer.py, render_machine/render_context.py, module_renderer.py, tests/test_render_stop_reason.py
ExitWithError resolves the message from the action payload or stored context, then stores and logs it. Error dispatch no longer logs directly, and module rendering uses the stored error message with a default fallback. Tests cover payload, stored-message, and missing-message cases.

Priority: ⬇️ Low

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

Change: Bug fix

Suggested reviewers: pedjaradenkovic

Merge Risk: ⚪ Minimal · up to 43270

The inspected render-failure path preserves the stop reason for display. No merge-blocking issue was established.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 15.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
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.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly describes the main change: reporting why rendering stops when unit tests continue to fail.
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

When a functionality's unit tests still failed after its last render
attempt, the render stopped with "ERROR codeplain: None" in the log, and
the TUI got a dict it could not display.

The stop now reads "Functionality 1: unit tests still fail after 2 render
attempts, 20 fix rounds each. Last unit tests output: <path>" in both the
log and the TUI. ExitWithError resolves the stop reason once, and every
other stop path logs its message instead of a raw payload.
@gorandodig
gorandodig force-pushed the fix/eng-325-name-the-render-stop-cause branch from ba39e55 to 432702b Compare October 14, 2026 10:29
@gorandodig
gorandodig marked this pull request as ready for review October 14, 2026 13:48
@gorandodig
gorandodig requested a review from hisenb3rg October 15, 2026 12:43

@hisenb3rg hisenb3rg left a comment •

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.

Looks good, nice work 👍

This branch has not been deployed

No deployments
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