Skip to content

pre_remediation_merge ref_coherence bypass orphans audited worktree #4228

Description

@Trecek

Summary

remediation.yaml routes pre_remediation_merge failures with failed_step == "ref_coherence" directly to remediate. That route immediately plans and eventually creates a new implementation worktree even though the audited worktree was never merged. When the local feature branch is merely ahead of its remote, this deterministically bypasses the anti-orphan merge added for #3288 and strands the completed remediation commits.

The normal merge path already has the bounded check_ref_push_loop -> ref_push -> commit_guard -> merge recovery delivered for #3261. pre_remediation_merge does not use it.

Production occurrence: #4150

The second audit-remediation cycle for #4150 reached this state on 2026-07-10:

  • Clone feature branch: false-positive-path-contamination-from-global-output-path-to/4150
  • Local feature SHA: f172e18778559367285045eeec5d45cbc6b37dc8
  • Remote feature SHA: 6bc93bc2aa12efb8451a066c5d264d48a1fd3f3f
  • Feature status: local is one commit ahead of upstream, not behind
  • Audited implementation worktree: /home/talon/projects/autoskillit-runs/worktrees/impl-4150-20260710-131655
  • Worktree status: eight commits ahead of upstream, seven commits ahead of the local feature branch, clean
  • Independent test gate before audit: 12,938 passed, 188 skipped, 16 xfailed, zero failed
  • Audit round 2: genuine NO GO with 14/16 round-2 requirements satisfied

pre_remediation_merge returned:

failed_step: ref_coherence
state: worktree_intact_ref_diverged
local_sha: f172e18778559367285045eeec5d45cbc6b37dc8
remote_sha: 6bc93bc2aa12efb8451a066c5d264d48a1fd3f3f

No merge test or cleanup ran. The recipe then routed directly to remediate. The resulting final remediation plan is intentionally test-only because it assumes the 14 satisfied requirements remain in the implementation history. However, create_impl_worktree.sh branches from the clone's current feature branch, which does not contain the seven round-2 worktree commits. Continuing literally would therefore create a new test-only worktree on an incomplete base and orphan the audited implementation.

Root cause

Two prior fixes are individually present but not composed:

  1. remediation.yaml: worktree orphaned when audit_impl NO GO triggers remediation cycle #3288 added pre_remediation_merge so an audit-NO-GO worktree is merged before a new remediation worktree overwrites context.implementation_ref.
  2. ref_coherence merge failure has no recovery route — multi-part issues abort terminally #3261 added bounded ref-coherence push recovery to the normal merge step because each successful worktree merge advances the local feature branch without immediately pushing it.

After one audit-remediation merge, the local feature branch is ahead of remote. On a second audit-remediation merge, the same recoverable state reaches pre_remediation_merge, whose routing is:

- when: result.failed_step == 'ref_coherence'
  route: remediate

This skips both the required merge and the existing bounded recovery.

Expected behavior

When pre_remediation_merge returns ref_coherence with both local_sha and remote_sha present and the remote is an ancestor of local, the recipe must:

  1. Push the local feature branch to the configured remote without rewriting history.
  2. Retry pre_remediation_merge through a bounded, cycle-local counter.
  3. Continue to remediation only after the audited worktree is merged or path_validation proves it was already merged.

Missing or unresolvable refs, non-fast-forward divergence, repeated failure after the bounded retry, and push failure must remain hard failures. The recipe must not force-push genuinely divergent history.

Scope

  • Add push-and-retry recovery for the recoverable pre_remediation_merge ref-coherence case.
  • Reuse or deliberately mirror the ref_coherence merge failure has no recovery route — multi-part issues abort terminally #3261 discrimination and bounded counter semantics.
  • Add a regression covering two consecutive audit-NO-GO cycles: first merge advances local feature, second pre-remediation merge recovers remote lag, and neither implementation worktree is orphaned.
  • Add a negative regression proving non-fast-forward divergence does not force-push.
  • Extend semantic recipe validation so this route cannot silently regress.

Relationships

Deep investigation (2026-07-10)

Claude Code/Fable investigation session 2adc36cd-8fff-4acb-925a-e09884128743 completed successfully in 2,232.3 seconds and wrote /home/talon/projects/autoskillit-runs/remediation-4150-20260710-093024-046178/.autoskillit/temp/investigate/investigation_pre_remediation_merge_ref_coherence_bypass_4228_2026-07-10_145314.md.

The investigation verified the complete #4150 production chain and found that the existing normal-merge recovery is not safe to mirror verbatim: merge_worktree reports strict SHA inequality without ancestry, while ref_push uses --force-with-lease after refreshing the lease. The converged fix is therefore tool-computed remote_is_ancestor, a bounded cycle-local pre_remediation_ref_push_count, a plain non-force push only when the remote is an ancestor, hard failure for missing or non-ancestor refs, and a target-aware semantic rule that prevents any ref_coherence arm from reaching replanning before recovery. The normal merge path's related force-push risk remains a separate follow-up, not part of this issue.

Rectify result (2026-07-10)

The canonical Claude Code rectify step completed successfully:

  • Order: 4228-rectify-1
  • Session: f6efc8c0-fb24-4919-95d1-1110d85bee27
  • Configured model: Sonnet; no provider override
  • Duration: 1,185.01 seconds; exit 0
  • Part A: /home/talon/projects/autoskillit-runs/remediation-4150-20260710-093024-046178/.autoskillit/temp/rectify/4228/rectify_pre_remediation_merge_ref_coherence_bypass_part_a_2026-07-10_153629.md
  • Part B: /home/talon/projects/autoskillit-runs/remediation-4150-20260710-093024-046178/.autoskillit/temp/rectify/4228/rectify_pre_remediation_merge_ref_coherence_bypass_part_b_2026-07-10_153629.md

The proposed immunity is split in recipe order: Part A adds bounded ancestry-aware recovery plus cross-site merge-routing consistency enforcement; Part B hardens barrier-route reachability so anti-orphan analysis inspects the reached merge barrier's own failure routes. Five exploration passes completed. Three final adversarial review subagents encountered sustained service rate limiting and did not return before the parent finalized, so both parts must pass dry-walkthrough before any implementation begins.

Part A dry-walkthrough checkpoint (2026-07-10)

Order 4228-dry-walkthrough-part-a-1, session 9c17cc3b-7740-4f37-9686-30132e3649aa, succeeded on Claude Code/Sonnet in 634.84 seconds and corrected ten concrete plan errors, including nonexistent helper names, stale file paths, incorrect test-coverage claims, TypedDict syntax, and the required repository test command.

This is not yet the final gate. The direct call supplied issue_url as a run_skill field rather than positional argument 2 in the slash command, and the worker explicitly reported that Step 4.6 issue coverage was omitted. After the Claude session limit resets at 17:50 PDT, Part A will be rerun with both the plan path and this issue URL positionally. Part B remains pending and no implementation has begun.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugExisting behavior is brokenrecipe:remediationRoute: investigate/decompose before implementation

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions