Skip to content

fix(#832): retry on stale tree SHA in commitFiles and DeleteFiles - #865

Open
fullsend-ai-coder[bot] wants to merge 2 commits into
mainfrom
agent/832-delete-files-stale-sha
Open

fix(#832): retry on stale tree SHA in commitFiles and DeleteFiles#865
fullsend-ai-coder[bot] wants to merge 2 commits into
mainfrom
agent/832-delete-files-stale-sha

Conversation

@fullsend-ai-coder

Copy link
Copy Markdown

Summary

Retry commitFilesTo and DeleteFiles when the GitHub API returns a 422 "Tree SHA does not exist" error, fixing intermittent behaviour test failures during concurrent after-scenario cleanup.

Related Issue

Fixes #832

Changes

  • Add isStaleTreeSHAError helper to detect 422 "Tree SHA does not exist" API errors (case-insensitive, checks both top-level message and error details)
  • Wrap stale tree SHA errors with forge.ErrNonFastForward at both the create-tree and create-commit stages in commitFilesTo, so commitFilesWithRetry retries the full operation from scratch
  • Refactor DeleteFiles to extract deleteFilesOnBranch and add deleteFilesWithRetry wrapper (same retry pattern as commitFilesWithRetry) with stale-SHA handling at both tree creation and commit creation steps
  • Add unit tests for isStaleTreeSHAError covering top-level messages, error details, case insensitivity, and negative cases
  • Add integration tests for both CommitFiles and DeleteFiles stale-tree-SHA retry paths

Testing

  • TestIsStaleTreeSHAError — verifies the new helper detects stale tree SHA errors correctly
  • TestCommitFiles_StaleTreeSHARetry — end-to-end retry for CommitFiles when tree creation returns stale SHA
  • TestDeleteFiles_StaleTreeSHARetry — end-to-end retry for DeleteFiles when tree creation returns stale SHA
  • TestIsNonFastForwardError — existing tests still pass (no regression)
  • TestDeleteFiles_Atomic — existing tests still pass (no regression)
  • TestCommitFiles_NonFastForwardRetry — existing tests still pass (no regression)
  • Full internal/forge/github package tests pass with -race
  • go vet ./internal/forge/github/... passes
  • go build ./... passes

Checklist

  • PR title follows Conventional Commits (correct type, no breaking change)
  • Tests added for new logic

Closes #832

Post-script verification

  • Branch is not main/master (agent/832-delete-files-stale-sha)
  • Secret scan passed (gitleaks — c887fc47c59d8b87b5282ca44044d2933d30df41..HEAD)
  • PR body secret scan passed (gitleaks — no-git)
  • Pre-commit hooks passed (authoritative run on runner)
  • Tests ran inside sandbox

When the GitHub API returns a 422 "Tree SHA does not exist" during
tree or commit creation, the base_tree SHA has gone stale due to
concurrent branch operations (e.g. parallel e2e cleanup). This is
the same class of race as a non-fast-forward ref update.

Add isStaleTreeSHAError helper to detect these 422 responses and
wrap them with forge.ErrNonFastForward so the existing retry loops
re-fetch and retry from scratch.

Changes:
- Add isStaleTreeSHAError helper (case-insensitive, checks both
  top-level message and error details)
- commitFilesTo: wrap stale-tree-SHA 422 at create-tree and
  create-commit steps so commitFilesWithRetry retries
- DeleteFiles: extract deleteFilesOnBranch and add
  deleteFilesWithRetry wrapper (same pattern as
  commitFilesWithRetry) with stale-SHA handling at both steps

Tests:
- TestIsStaleTreeSHAError: helper detection coverage
- TestCommitFiles_StaleTreeSHARetry: end-to-end retry for
  CommitFiles
- TestDeleteFiles_StaleTreeSHARetry: end-to-end retry for
  DeleteFiles

Note: pre-commit could not run (network access unavailable in
sandbox). The post-script runs an authoritative pre-commit on the
runner.

Closes #832
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 2, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:44 AM UTC · Completed 9:59 AM UTC
Commit: b413adf · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 2, 2026

Copy link
Copy Markdown

Looks good to me

Previous run

Review

Findings

Medium

  • [error-handling-gap] internal/forge/github/github.go:1211deleteFilesOnBranch wraps the ref-update PATCH in retryOnRepoRace, which only retries 404 and 409 — not 422. If the PATCH returns a 422 non-fast-forward (concurrent push moved the ref), the error is not wrapped with forge.ErrNonFastForward, so deleteFilesWithRetry will not retry it. By contrast, commitFilesTo handles this case explicitly at its ref-update step by checking isNonFastForwardError and wrapping with forge.ErrNonFastForward. This gap is pre-existing (not introduced by this PR), but the introduction of deleteFilesWithRetry makes the asymmetry actionable as follow-up work.

Low

  • [semantic-error-mapping] internal/forge/github/github.go:1035 — Stale tree SHA errors are mapped to forge.ErrNonFastForward, which represents a different failure mode (ref-update rejection vs. tree-creation staleness). This is a pragmatic reuse of an existing sentinel to leverage the retry infrastructure and works correctly for the retry use case. A dedicated sentinel (e.g., forge.ErrStaleTree) would improve debuggability as a follow-up.

  • [architectural-inconsistency] internal/forge/github/github.go:1118deleteFilesWithRetry and retryOnRepoRace handle different error classes at different abstraction levels (semantic 422 vs. infrastructure 404/409), mirroring the established two-tier pattern used by commitFilesWithRetry. No change needed — noting for visibility.


Labels: PR fixes a bug in the GitHub forge client's error handling during concurrent operations

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment type/bug Confirmed defect in existing behavior labels Aug 2, 2026
@guyoron1

guyoron1 commented Aug 2, 2026

Copy link
Copy Markdown
Owner

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 2, 2026

Copy link
Copy Markdown
Author

🤖 Finished Fix · ✅ Success · Started 10:32 AM UTC · Completed 10:39 AM UTC
Commit: b413adf · View workflow run →

…Branch

Add explicit 422 non-fast-forward detection at the ref-update step in
deleteFilesOnBranch, matching commitFilesTo's pattern. Without this,
a concurrent push that moves the ref between our read and the PATCH
would not be wrapped with forge.ErrNonFastForward, so
deleteFilesWithRetry would not retry the operation.

Add TestDeleteFiles_NonFastForwardRefUpdateRetry integration test.

Addresses review feedback on #865
@fullsend-ai-coder

Copy link
Copy Markdown
Author

🔧 Fix agent — iteration 1 (human-triggered)

Fixed the medium-severity error-handling-gap: added 422 non-fast-forward detection at the ref-update step in deleteFilesOnBranch, matching commitFilesTo's existing pattern, with integration test. Disagreed with 2 low-severity findings that the reviewer explicitly marked as follow-up or visibility-only.

Fixed (1):

  1. error-handling-gap: deleteFilesOnBranch missing 422 non-fast-forward detection at ref-update step (internal/forge/github/github.go): Added explicit 422 non-fast-forward detection after the retryOnRepoRace call for the ref-update PATCH in deleteFilesOnBranch, matching commitFilesTo's pattern. When the PATCH returns a 422 with a non-fast-forward message, the error is now wrapped with forge.ErrNonFastForward so deleteFilesWithRetry retries the full operation from scratch. Added TestDeleteFiles_NonFastForwardRefUpdateRetry integration test.

Disagreed (2):

  1. semantic-error-mapping: stale tree SHA errors mapped to forge.ErrNonFastForward instead of dedicated sentinel: The review itself notes this is 'not a correctness issue' and suggests a dedicated sentinel 'in a follow-up if debugging concurrent failures proves difficult.' This is explicitly flagged as follow-up work, not a fix for this PR.
  2. architectural-inconsistency: two-tier retry pattern (deleteFilesWithRetry + retryOnRepoRace): The review itself states 'No change needed — noting for visibility.' This mirrors the established pattern used by commitFilesWithRetry + retryOnRepoRace.

Tests: passed

Next steps:

  • /fs-review — request a re-review of the changes
  • /fs-fix <your instruction> — run another fix pass with specific guidance
  • Push commits directly — review re-runs automatically on push
    Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 2, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:41 AM UTC · Completed 10:54 AM UTC
Commit: 74b89ac · View workflow run →

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed requires-manual-review Review requires human judgment labels Aug 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had any activity in the last month. It will be closed in 2 weeks if no further activity occurs. Remove the stale label to reset the inactivity timer.

@github-actions github-actions Bot added the stale label Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-merge All reviewers approved — ready to merge stale type/bug Confirmed defect in existing behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

behaviour test flaky: 422 Tree SHA does not exist in after-scenario hook

1 participant