Skip to content

Commit 2cfb0b6

Browse files
committed
Stop telling the user to rewrite the specification when a fix loop gives up
Both client-side fix loops ended with "Please review and rewrite the specification.", which asserts a cause nothing in the render establishes: a conformance loop has been observed patching thirteen times against a failure it was not moving, which tells us we did not converge, not that the input was wrong. The server said the same and no longer does. Each reason now names the loop, the functionality and the attempt count, and points at the log that holds the detail. The conformance loop also gains the error type its unit-test counterpart already had.
1 parent fa34ff5 commit 2cfb0b6

4 files changed

Lines changed: 69 additions & 8 deletions

File tree

‎render_machine/actions/fix_conformance_test.py‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from render_machine.actions.base_action import BaseAction
1010
from render_machine.implementation_code_helpers import ImplementationCodeHelpers
1111
from render_machine.render_context import RenderContext
12-
from render_machine.render_types import RenderError, TestExecutionPhase
12+
from render_machine.render_types import FIX_LOOP_EXHAUSTED_HINT, RenderError, TestExecutionPhase
1313

1414
MAX_CONFORMANCE_TEST_FIX_ATTEMPTS = 20
1515
MAX_CONFORMANCE_TEST_RERENDER_ATTEMPTS = 1
@@ -32,11 +32,20 @@ def execute(self, render_context: RenderContext, previous_action_payload: Any |
3232

3333
if ctx.fix_attempts >= MAX_CONFORMANCE_TEST_FIX_ATTEMPTS:
3434
if ctx.conformance_tests_render_attempts >= MAX_CONFORMANCE_TEST_RERENDER_ATTEMPTS:
35-
error_msg = f"The renderer was unable to produce an implementation that passes conformance tests for functionality '{render_context.frid_context.frid}' after many attempts. Please review and rewrite the specification. (Render ID: {render_context.run_state.render_id})"
35+
error_msg = (
36+
f"Rendering stopped: the conformance tests for functionality "
37+
f"'{render_context.frid_context.frid}' still failed after "
38+
f"{MAX_CONFORMANCE_TEST_FIX_ATTEMPTS} attempts at fixing them. {FIX_LOOP_EXHAUSTED_HINT} "
39+
f"(Render ID: {render_context.run_state.render_id})"
40+
)
3641
render_context.last_error_message = error_msg
3742
return (
3843
self.LIMIT_EXCEEDED_OUTCOME,
39-
RenderError.encode(message=error_msg).to_payload(),
44+
RenderError.encode(
45+
message=error_msg,
46+
error_type="CONFORMANCE_TESTS_FIX_EXHAUSTED",
47+
frid=render_context.frid_context.frid,
48+
).to_payload(),
4049
)
4150
else:
4251
ctx.regenerating_conformance_tests = True

‎render_machine/actions/render_functional_requirement.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from render_machine.actions.base_action import BaseAction
99
from render_machine.implementation_code_helpers import ImplementationCodeHelpers
1010
from render_machine.render_context import RenderContext
11-
from render_machine.render_types import RenderError
11+
from render_machine.render_types import FIX_LOOP_EXHAUSTED_HINT, RenderError
1212

1313
MAX_CODE_GENERATION_RETRIES = 2
1414

@@ -21,9 +21,9 @@ class RenderFunctionalRequirement(BaseAction):
2121
def execute(self, render_context: RenderContext, _previous_action_payload: Any | None):
2222
if render_context.frid_context.functional_requirement_render_attempts >= MAX_CODE_GENERATION_RETRIES:
2323
error_msg = (
24-
f"The renderer was unable to produce an implementation whose unit tests pass for functionality "
25-
f"'{render_context.frid_context.frid}' after rendering it from scratch {MAX_CODE_GENERATION_RETRIES} "
26-
f"times. Please review and rewrite the specification."
24+
f"Rendering stopped: the unit tests for functionality '{render_context.frid_context.frid}' still "
25+
f"failed after rendering it from scratch {MAX_CODE_GENERATION_RETRIES} times. "
26+
f"{FIX_LOOP_EXHAUSTED_HINT}"
2727
)
2828
render_context.last_error_message = error_msg
2929
return (

‎render_machine/render_types.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ class ScriptExecutionHistory:
148148
should_update_script_outputs: bool = False
149149

150150

151+
# Both fix loops end the same way when they run out of attempts, and neither ending tells us
152+
# the specification is at fault - only that we did not converge. The reason points at the
153+
# evidence instead of assigning blame.
154+
FIX_LOOP_EXHAUSTED_HINT = (
155+
"The render log records what each attempt failed on. " "If this repeats, send the log to support@codeplain.ai."
156+
)
157+
158+
151159
@dataclass
152160
class RenderError:
153161
"""Standardized error format for all render failures."""

‎tests/test_render_failure_payloads.py‎

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@
99

1010
from unittest.mock import MagicMock
1111

12+
from render_machine.actions.fix_conformance_test import (
13+
MAX_CONFORMANCE_TEST_FIX_ATTEMPTS,
14+
MAX_CONFORMANCE_TEST_RERENDER_ATTEMPTS,
15+
FixConformanceTest,
16+
)
1217
from render_machine.actions.refactor_code import MAX_REFACTORING_ITERATIONS, RefactorCode
1318
from render_machine.actions.render_functional_requirement import (
1419
MAX_CODE_GENERATION_RETRIES,
1520
RenderFunctionalRequirement,
1621
)
22+
from render_machine.render_types import FIX_LOOP_EXHAUSTED_HINT
1723

1824

1925
def exhausted_context(**frid_attributes):
@@ -25,6 +31,15 @@ def exhausted_context(**frid_attributes):
2531
return context
2632

2733

34+
def exhausted_conformance_context():
35+
"""A conformance loop that has spent its fix attempts and its one regeneration."""
36+
context = exhausted_context()
37+
ctx = context.conformance_tests_running_context
38+
ctx.fix_attempts = MAX_CONFORMANCE_TEST_FIX_ATTEMPTS - 1
39+
ctx.conformance_tests_render_attempts = MAX_CONFORMANCE_TEST_RERENDER_ATTEMPTS
40+
return context
41+
42+
2843
def test_unit_test_exhaustion_reports_a_typed_reason():
2944
context = exhausted_context(functional_requirement_render_attempts=MAX_CODE_GENERATION_RETRIES)
3045

@@ -43,7 +58,36 @@ def test_unit_test_exhaustion_names_the_functionality_and_what_to_do():
4358

4459
assert "'1'" in message
4560
assert "unit tests" in message
46-
assert "specification" in message
61+
assert FIX_LOOP_EXHAUSTED_HINT in message
62+
63+
64+
def test_no_fix_loop_blames_the_specification_for_giving_up():
65+
"""Exhaustion tells us we did not converge, not that the input was wrong. Both loops used
66+
to end with `Please review and rewrite the specification.`, which asserts a cause nothing
67+
in the render establishes - a conformance loop has been observed patching thirteen times
68+
against a failure it was not moving."""
69+
unit = exhausted_context(functional_requirement_render_attempts=MAX_CODE_GENERATION_RETRIES)
70+
_, unit_payload = RenderFunctionalRequirement().execute(unit, None)
71+
72+
conformance = exhausted_conformance_context()
73+
_, conformance_payload = FixConformanceTest().execute(conformance, None)
74+
75+
for payload in (unit_payload, conformance_payload):
76+
assert "rewrite the specification" not in payload["error"]["message"]
77+
78+
79+
def test_conformance_exhaustion_names_the_functionality_and_what_to_do():
80+
context = exhausted_conformance_context()
81+
82+
outcome, payload = FixConformanceTest().execute(context, None)
83+
message = payload["error"]["message"]
84+
85+
assert outcome == FixConformanceTest.LIMIT_EXCEEDED_OUTCOME
86+
assert payload["error"]["type"] == "CONFORMANCE_TESTS_FIX_EXHAUSTED"
87+
assert "'1'" in message
88+
assert "conformance tests" in message
89+
assert str(MAX_CONFORMANCE_TEST_FIX_ATTEMPTS) in message
90+
assert FIX_LOOP_EXHAUSTED_HINT in message
4791

4892

4993
def test_unit_test_exhaustion_logs_the_same_reason_it_returns():

0 commit comments

Comments
 (0)