abhigyanpatwari/GitNexus · critical · RuntimeError

post-apply parity check failed: {replacement['target']}

Error message

post-apply parity check failed: {replacement['target']}

What it means

Thrown in the post-apply loop after every individual exchange passed its own parity check. The full re-validation across all replacements found at least one whose destination/candidate slot identity or state drifted, meaning something changed the entries between their individual swaps and the final global check.

Source

Thrown at eval/workflow_bench/promotion_apply.py:810

            )
            if (
                observed_destination == replacement["candidate_state"]
                and observed_previous == replacement["base_state"]
                and destination_identity == replacement["candidate_identity"]
                and displaced_identity == previous_identity
            ):
                continue
            raise RuntimeError(f"atomic overlay exchange parity check failed: {replacement['target']}")
        for replacement in replacements:
            if (
                current_state(replacement) != replacement["candidate_state"]
                or entry_state(replacement, replacement["candidate"]) != replacement["base_state"]
                or _entry_identity_at(replacement["parent_descriptor"], replacement["name"])
                != replacement["candidate_identity"]
                or _entry_identity_at(replacement["parent_descriptor"], replacement["candidate"])
                != replacement["publication_previous_identity"]
            ):
                raise RuntimeError(f"post-apply parity check failed: {replacement['target']}")
        _validate_prepared_paths(
            repo_root,
            root_descriptor,
            replacements,
            phase="post-apply validation",
        )
        published_all = True
    except BaseException as exc:
        rollback_failures: list[str] = []
        for replacement in reversed(completed):
            try:
                destination_identity = _entry_identity_at(
                    replacement["parent_descriptor"],
                    replacement["name"],
                )
                temporary_identity = _entry_identity_at(
                    replacement["parent_descriptor"],
                    replacement["candidate"],

View on GitHub (pinned to d540b00184)

Solutions

  1. Serialize the entire apply (capture + publish + verify) under an exclusive lock so no writer can interleave.
  2. Run promotion in a clean, isolated checkout that no IDE/build touches.
  3. After a clean rollback (see error 414) re-capture evidence and retry.
  4. Investigate the specific target named in the message for a process that writes it post-swap.

Example fix

# before: post-apply global check found drift
apply_promoted_overlay(overlay, expected_target_bases=bases)  # -> RuntimeError
# after: isolate + lock so no writer can land between swap and final check
with promote_lock(repo_root):  # see error 410 example
    apply_promoted_overlay(
        overlay,
        expected_target_bases=destination_base_digests(overlay),
    )
Defensive patterns

Strategy: validation

Validate before calling

# post-apply drift means a writer landed during the apply — same lock as 409/410.
import fcntl, contextlib

@contextlib.contextmanager
def promote_lock(repo_root):
    with open(repo_root / ".wfbench-promote.lock", "w") as f:
        fcntl.flock(f, fcntl.LOCK_EX); yield

with promote_lock(repo_root):
    apply_promoted_overlay(overlay, expected_target_bases=bases)

Type guard

null

Try / catch

try:
    apply_promoted_overlay(overlay, expected_target_bases=bases)
except RuntimeError as exc:
    if "post-apply parity check failed" in str(exc):
        # rollback should have run; verify tree then re-capture+retry under lock
        import subprocess; subprocess.run(["git", "-C", str(repo_root), "status"], check=False)
    raise

Prevention

When it happens

Trigger: All swaps succeeded individually, but a concurrent writer (or filesystem behavior) altered one or more slots before the global post-apply verification at promotion_apply.py:801-810. Triggers rollback of completed replacements.

Common situations: Concurrent editor/formatter touched a target after its swap but before the final loop; background indexer; an IDE 'restore' that overwrote a just-promoted file; same root causes as 409/410 but landing late.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/0cd08cebf6dbde8b. Report an issue: GitHub.