Skip to content

fix(dspy): count only true assignments in ProgramOfThought._parse_code single-line guard - #82

Open
detail-app[bot] wants to merge 1 commit into
mainfrom
detail/bug-fix/fix-dspy-count-only-true-assignments-in-programoft-2e90e0
Open

fix(dspy): count only true assignments in ProgramOfThought._parse_code single-line guard#82
detail-app[bot] wants to merge 1 commit into
mainfrom
detail/bug-fix/fix-dspy-count-only-true-assignments-in-programoft-2e90e0

Conversation

@detail-app

@detail-app detail-app Bot commented Sep 6, 2026

Copy link
Copy Markdown

Warning

GitHub issue creation failed

Detail attempted to publish this bug to GitHub, but the issue could not be created. This fix PR was created without that issue, and missing tracker references are shown as Unknown issue.

You can review and merge this PR normally. Please review your tracker integration settings before the next publish run.

Detail bug report: View on Detail

📝 Changes Description

ProgramOfThought._parse_code rejected valid single-line Python that contains a comparison operator (==, !=, <=, >=). Its single-line guard used code_block.count("=") > 1, which counts every = character including those inside comparison operators, so a perfectly executable one-liner like result = 5 == 3 was rejected with ''"Error: Code format is not correct."'' before the interpreter was ever reached. If the LM regenerated the same shape across retries, forward wasted hops and could raise RuntimeError: Max hops reached.... The bug was reachable on the deprecated single-line "old-style" path (no SUBMIT()), where result = 5 > 3 ran but the semantically identical result = 5 == 3 did not — an inconsistency left in place by the recent single-line echo fix (fe75476c).

  • Fix: Replace the raw character count with one that counts only true assignments. Normalize each augmented-assignment operator (//=, **=, <<=, >>=, +=, -=, *=, /=, %=, &=, |=, ^=, @=) to a single =, strip the comparison operators (==, !=, <=, >=), then count =. Comparisons now contribute zero and augmented assignments contribute one, so a single assignment containing comparisons is accepted, while genuine multi-assignment single-liners are still rejected.
  • Guard value preserved: a = b = 5, a = 1; b = 2, x += 1; y -= 2, x <<= 1; y >>= 2, and invalid=python=code still raise the format error (the existing test_pot_code_parse_error still passes, now for the right reason).
  • Added regression tests covering: single-line comparisons accepted with the correct output-capturing echo; single-line augmented assignments accepted; genuine multi-assignment single-liners still rejected; a Deno-free end-to-end test (via MockInterpreter) confirming the comparison code reaches the interpreter on the first hop; and a @pytest.mark.deno end-to-end test mirroring test_old_style_pot confirming the parsed code evaluates to False under the real Deno/Pyodide interpreter.

Closes Unknown issue

✅ Contributor Checklist

  • Pre-Commit checks are passing (locally and remotely) — ruff check --fix-only --exit-non-zero-on-fix and ruff format --check both clean on the changed files.
  • Title of your PR / MR corresponds to the required format — fix(dspy): ... matches (label)(dspy): message.
  • Commit message follows required format {label}(dspy): {message}fix(dspy): count only true assignments in ProgramOfThought._parse_code single-line guard.

⚠️ Warnings

  • AI assistance disclosure (per CONTRIBUTING.md): This change was prepared with the assistance of Detail (Detail: Automatic Fixes). The bug was reproduced directly against _parse_code, the fix was reviewed and understood line-by-line, and all verification was run locally. The human author reviewed and is submitting this PR.
  • ProgramOfThought is deprecated (emits DeprecationWarning, will be removed in 3.5 in favor of RLM), so this fix targets a legacy path; it keeps that path consistent with the single-line support rehabilitated in fe75476c.
  • Testing performed: Non-deno tests/predict/test_program_of_thought.py (29 passed, 7 deno deselected); the broader tests/predict/ suite (264 passed, 6 skipped, 0 failed — no regressions); ruff lint and format clean. The new @pytest.mark.deno end-to-end test was executed against a real Deno/Pyodide interpreter (deno 2.9.5) and passed (7 passed under -m deno --deno), confirming the parsed comparison code evaluates to False and flows through generate_output.

Automatic Fixes PRs can be configured here.

@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adjusts ProgramOfThought._parse_code so comparison operators do not count as assignments and adds regression coverage for comparisons, augmented assignments, retry behavior, and real-interpreter execution. The revised guard handles ordinary result = lhs == rhs expressions, but it also admits comparison-first statement sequences for which the output-capturing echo selects the wrong identifier.

Confidence Score: 4/5

The PR should not merge until newly accepted comparison-first single-line programs capture the actual assigned result rather than the comparison’s left operand.

The comparison stripping fixes the reported ordinary assignment form, but it broadens accepted input to a realistic valid statement sequence that can silently return the wrong value.

Files Needing Attention: dspy/predict/program_of_thought.py

Important Files Changed

Filename Overview
dspy/predict/program_of_thought.py Reworks single-line assignment counting, but newly accepted comparison-first statement sequences can produce the wrong captured output.
tests/predict/test_program_of_thought.py Adds broad regression coverage for standard comparison and augmented-assignment forms, but omits comparison-before-assignment sequences.

Reviews (1): Last reviewed commit: "fix(dspy): count only true assignments i..." | Re-trigger Greptile

Comment on lines +173 to +174
true_assigns = re.sub(r"==|!=|<=|>=", "", true_assigns)
if true_assigns.count("=") > 1:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Comparison selects wrong output

Stripping comparisons before counting assignments newly allows a comparison-first statement such as True == False; result = 2. The existing echo regex then mistakes the first = in == for an assignment and appends True, so the interpreter returns True instead of the intended result value. Restrict the accepted single-line forms or identify the actual assignment before appending its output variable.

Knowledge Base Used: Prediction programs and agent workflows

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