-
Notifications
You must be signed in to change notification settings - Fork 53
Description
Summary
When the agentic e2e fix workflow exits early (at Step 2 with ALL_TESTS_PASS), commits created by the LLM agent in Step 1 are not pushed to the remote repository, despite the workflow reporting success.
Steps to Reproduce
- Run
pdd fix https://github.com/promptdriven/pdd/issues/409(or any issue where tests pass immediately after Step 1 fix) - Observe workflow exits early at Step 2:
ALL_TESTS_PASS detected in Step 2. Exiting loop. - Check local commits:
git logshows commit exists - Check remote:
git log origin/fix/issue-409shows commit is NOT pushed - Observe git status:
Your branch is ahead of 'origin/fix/issue-409' by 1 commit
Expected Behavior
When the workflow completes successfully (success=True), ALL commits created during the workflow should be pushed to the remote, regardless of whether the workflow exits early or runs all 9 steps.
Actual Behavior
Scenario 1: Full workflow (all 9 steps, like issue #411)
- ✅ Commits are created
- ✅ Commits are pushed
- ✅ Output:
Committed and pushed 7 file(s)
Scenario 2: Early exit (Step 2, like issue #409)
- ✅ Commit is created in Step 1
- ❌ Commit is NOT pushed
- ❌ Output:
No changes to commit
Root Cause
File: pdd/agentic_e2e_fix_orchestrator.py
Function: _commit_and_push() (lines 198-273)
The bug occurs at lines 237-238:
def _commit_and_push(...):
# Get current file hashes
current_hashes = _get_file_hashes(cwd) # Only detects uncommitted files
# Find files that changed during workflow
files_to_commit: List[str] = []
for filepath, current_hash in current_hashes.items():
if filepath not in initial_file_hashes:
files_to_commit.append(filepath)
elif initial_file_hashes[filepath] != current_hash:
files_to_commit.append(filepath)
if not files_to_commit:
return True, "No changes to commit" # ❌ BUG: Exits without pushing!
# ... stage files ...
# ... create commit ...
# ... git push ... ← Never reached!Why it fails:
- Line 346 (before workflow):
initial_file_hashes = _get_file_hashes(cwd)returns{}(no uncommitted files) - Step 1 (LLM agent): Modifies
pdd/commands/generate.pyand creates commit94f3bab5 - Step 2: Detects
ALL_TESTS_PASS, exits early - Line 521 (after workflow): Calls
_commit_and_push() - Inside
_commit_and_push:current_hashes = _get_file_hashes(cwd)callsgit diff --name-only HEAD- Returns
{}because working tree is clean (changes already committed) files_to_commitis empty- Returns "No changes to commit" without executing
git push
The issue: _get_file_hashes() only detects uncommitted changes, but the LLM agent already committed the fix.
Evidence
Issue #409 example:
# Local commits
$ git log --oneline -2
94f3bab5 Fix issue #409: Remove os.environ.update() causing environment variable pollution
0d61f1a8 Add failing tests for issue #409: Environment Variable Pollution
# Remote commits
$ git log origin/fix/issue-409 --oneline -2
0d61f1a8 Add failing tests for issue #409: Environment Variable Pollution
88a37d5d Bump version
# Status
$ git status
Your branch is ahead of 'origin/fix/issue-409' by 1 commit.
(use "git push" to publish your local commits)Workflow output:
E2E fix complete
Total cost: $0.9906
Cycles used: 1/5
Files changed:
Dev units fixed:
No changes to commit ← Should say "Pushed 1 commit" or similar
Suggested Fix
Option 1: Always push at the end
def _commit_and_push(...):
# ... detect files changed ...
if not files_to_commit:
# No new changes to commit, but push any unpushed commits
push_result = subprocess.run(["git", "push"], cwd=cwd, ...)
if push_result.returncode == 0:
return True, "Pushed existing commits"
else:
return True, "No changes to push (up to date)"
# ... stage, commit, and push new changes ...Option 2: Separate commit and push logic
# In run_agentic_e2e_fix_orchestrator() after success:
if success:
# Commit any uncommitted changes
if has_uncommitted_changes():
commit_changes()
# Always push (whether we made a new commit or not)
push_result = subprocess.run(["git", "push"], cwd=cwd, ...)Test Case
Create a test that:
- Runs agentic fix on an issue where tests pass immediately
- Verifies that the local commit exists
- Verifies that the commit was pushed to remote ✅