{"record":{"id":"dc5fa8a9a35e1e3c","repo":"abhigyanpatwari/GitNexus","slug":"overlay-destination-drifted-before-apply-replace","errorCode":null,"errorMessage":"overlay destination drifted before apply: {replacement['target']}","messagePattern":"overlay destination drifted before apply: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/promotion_apply.py","lineNumber":738,"sourceCode":"                replacement[\"backup\"] = _stage_replacement_at(\n                    item[\"parent_descriptor\"],\n                    item[\"original\"],\n                    item[\"mode\"],\n                )\n            except _StagingCleanupError as stage_exc:\n                replacement[\"backup\"] = stage_exc.name\n                raise\n        # Recheck the entire compare set after staging and before the first\n        # replacement, then check each member immediately before its swap.\n        _validate_prepared_paths(\n            repo_root,\n            root_descriptor,\n            replacements,\n            phase=\"pre-publication\",\n        )\n        for replacement in replacements:\n            if current_state(replacement) != replacement[\"base_state\"]:\n                raise ValueError(f\"overlay destination drifted before apply: {replacement['target']}\")\n        for replacement in replacements:\n            _validate_prepared_paths(\n                repo_root,\n                root_descriptor,\n                [replacement],\n                phase=\"publication\",\n            )\n            if current_state(replacement) != replacement[\"base_state\"]:\n                raise ValueError(f\"overlay destination drifted during apply: {replacement['target']}\")\n            previous_identity = _entry_identity_at(\n                replacement[\"parent_descriptor\"],\n                replacement[\"name\"],\n            )\n            replacement[\"publication_previous_identity\"] = previous_identity\n            try:\n                _exchange_at(\n                    replacement[\"parent_descriptor\"],\n                    replacement[\"candidate\"],","sourceCodeStart":720,"sourceCodeEnd":756,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/promotion_apply.py#L720-L756","documentation":"Thrown in the pre-publication loop of `apply_promoted_overlay` when, after staging candidate and backup files but before any exchange, a target's current on-disk state no longer equals its `base_state` captured during preparation. This detects concurrent edits that landed in the window between prepare and publish.","triggerScenarios":"A concurrent process (IDE formatter, build tool, another git operation, an editor autosave) modified one of the destination files between `_prepare_targets` and the `current_state(replacement) != base_state` check at promotion_apply.py:737. The promote operation aborts before doing any exchange.","commonSituations":"An IDE autosaves a file mid-promotion; a `pre-commit` hook or formatter runs in parallel; a developer edits a target while CI is promoting; background indexing rewrites a file; another `apply_promoted_overlay` call raced on the same repo.","solutions":["Re-capture `expected_target_bases` and `expected_digest`, then retry the apply — the new capture will include the concurrent edit.","Serialize promotion: ensure no other writer (formatter, IDE, build) runs against the repo during apply.","Take a working-tree lock (e.g. `.git/index.lock` convention or a harness-level mutex) around capture+apply.","If a specific tool is the culprit (ruff/black/prettier), disable it for the repo or run promotion in a clean checkout."],"exampleFix":"# before: apply raced with an editor autosave\napply_promoted_overlay(overlay, expected_target_bases=bases)  # -> ValueError drifted\n# after: serialize promotion and re-capture after any concurrent edit\nimport fcntl\nwith open(repo_root / '.wfbench-promote.lock', 'w') as lock:\n    fcntl.flock(lock, fcntl.LOCK_EX)\n    bases = destination_base_digests(overlay)\n    apply_promoted_overlay(overlay, expected_target_bases=bases)","handlingStrategy":"validation","validationCode":"import fcntl, contextlib\nfrom workflow_bench.promotion_apply import destination_base_digests\n\n@contextlib.contextmanager\ndef promote_lock(repo_root):\n    with open(repo_root / \".wfbench-promote.lock\", \"w\") as f:\n        fcntl.flock(f, fcntl.LOCK_EX)\n        yield\n\n# hold the lock across capture+apply so no writer can drift a target\nwith promote_lock(repo_root):\n    bases = destination_base_digests(overlay)\n    apply_promoted_overlay(overlay, expected_target_bases=bases)","typeGuard":"null","tryCatchPattern":"try:\n    apply_promoted_overlay(overlay, expected_target_bases=bases)\nexcept ValueError as exc:\n    if \"drifted before apply\" in str(exc):\n        # a concurrent writer landed: re-capture and retry under a lock\n        with promote_lock(repo_root):\n            bases = destination_base_digests(overlay)\n            apply_promoted_overlay(overlay, expected_target_bases=bases)\n    raise","preventionTips":["Serialize promotion with a file lock so no editor/formatter can interleave.","Run promotion in a clean checkout that no IDE touches.","Disable autosave/format-on-save for the repo during CI."],"tags":["concurrency","drift","integrity","overlay"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}