Add guarded same-job execution re-anchor repair script

This commit is contained in:
AIOS Governed Continuation
2026-08-25 12:04:48 +08:00
parent 5855d4b53e
commit e7c094782a
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import ast
from datetime import datetime, timezone
import pathlib
import shutil
import sys
UTC = timezone.utc
def die(msg: str) -> None:
print(f"ERROR: {msg}", file=sys.stderr)
raise SystemExit(2)
def backup(path: pathlib.Path) -> pathlib.Path:
stamp = datetime.now(UTC).strftime("%Y%m%dT%H%M%SZ")
out = path.with_name(path.name + f".bak.{stamp}")
shutil.copy2(path, out)
return out
def ensure_import(path: pathlib.Path, import_line: str) -> None:
text = path.read_text(encoding="utf-8")
if import_line + "\n" in text:
return
lines = text.splitlines(keepends=True)
at = 0
if lines and lines[0].startswith("#!"):
at = 1
if at < len(lines) and lines[at].startswith("from __future__ import"):
at += 1
lines.insert(at, import_line + "\n")
path.write_text("".join(lines), encoding="utf-8")
def replace_once(path: pathlib.Path, old: str, new: str, label: str) -> None:
text = path.read_text(encoding="utf-8")
if new in text:
print(f"OK already patched: {label}")
return
count = text.count(old)
if count != 1:
die(f"{label}: expected exactly one match, found {count}")
b = backup(path)
path.write_text(text.replace(old, new, 1), encoding="utf-8")
print(f"PATCHED {label}; backup={b}")
def syntax_check(path: pathlib.Path) -> None:
ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
print(f"OK syntax: {path}")
def main() -> int:
ap = argparse.ArgumentParser(description="Add guarded same-job execution re-anchor support.")
ap.add_argument("--rebind", required=True)
args = ap.parse_args()
path = pathlib.Path(args.rebind).resolve()
if not path.is_file():
die(f"missing rebind source: {path}")
ensure_import(path, "import subprocess")
old = ''' binding = GovernedExecutionBinding.from_mapping(old_execution)
resolved = dict(self.resolver(task_id, capabilities))
new_execution = validate_execution_envelope(resolved, binding=binding)
if new_execution.get("action") != "deterministic":
raise ExecutionRebindError("EXECUTION_REBIND_DETERMINISTIC_PLAN_REQUIRED", 409)
if new_execution["execution_digest"] != request.expected_new_execution_digest:
raise ExecutionRebindError("EXECUTION_REBIND_NEW_DIGEST_DRIFT", 409)
if new_execution["execution_digest"] == old_execution["execution_digest"]:
raise ExecutionRebindError("EXECUTION_REBIND_DIGEST_UNCHANGED", 409)
'''
new = ''' binding = GovernedExecutionBinding.from_mapping(old_execution)
resolved = dict(self.resolver(task_id, capabilities))
candidate_binding = GovernedExecutionBinding.from_mapping(resolved)
# Same-job continuation may advance only the branch head (and may
# transition CREATE_NEW -> CONTINUE_EXISTING after the branch exists).
immutable_fields = (
"task_id",
"job_id",
"repository",
"base_oid",
"target_branch",
"generation",
"idempotency_key",
)
for field in immutable_fields:
if getattr(candidate_binding, field) != getattr(binding, field):
raise ExecutionRebindError("EXECUTION_REBIND_BINDING_CONFLICT", 409)
head_advanced = candidate_binding.expected_branch_oid != binding.expected_branch_oid
if head_advanced:
allowed_modes = {
(binding.branch_mode, binding.branch_mode),
("CREATE_NEW", "CONTINUE_EXISTING"),
}
if (binding.branch_mode, candidate_binding.branch_mode) not in allowed_modes:
raise ExecutionRebindError("EXECUTION_REBIND_BRANCH_MODE_CONFLICT", 409)
authority_git_dir = "/data/aios-gitops/repo.git"
authority_ref = f"refs/heads/{binding.target_branch}"
try:
authority_head = subprocess.check_output(
[
"/usr/bin/git",
f"--git-dir={authority_git_dir}",
"rev-parse",
authority_ref,
],
text=True,
timeout=5,
).strip()
ancestry = subprocess.run(
[
"/usr/bin/git",
f"--git-dir={authority_git_dir}",
"merge-base",
"--is-ancestor",
binding.expected_branch_oid,
candidate_binding.expected_branch_oid,
],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=5,
check=False,
)
except (OSError, subprocess.SubprocessError) as exc:
raise ExecutionRebindError("EXECUTION_REBIND_AUTHORITY_GIT_UNAVAILABLE", 503) from exc
if authority_head != candidate_binding.expected_branch_oid:
raise ExecutionRebindError("EXECUTION_REBIND_CURRENT_HEAD_MISMATCH", 409)
if ancestry.returncode != 0:
raise ExecutionRebindError("EXECUTION_REBIND_NON_FAST_FORWARD_DENY", 409)
elif candidate_binding.branch_mode != binding.branch_mode:
raise ExecutionRebindError("EXECUTION_REBIND_BRANCH_MODE_CONFLICT", 409)
# Validate the canonical envelope on its own after the continuation
# binding proof above. Worker-side strict equality remains unchanged.
new_execution = validate_execution_envelope(resolved)
# Re-anchor may legitimately remain source_capture when no deterministic
# plan is registered yet. A non-head-changing rebind must still advance
# source_capture -> deterministic.
if new_execution.get("action") not in {"source_capture", "deterministic"}:
raise ExecutionRebindError("EXECUTION_REBIND_ACTION_INVALID", 409)
if not head_advanced and new_execution.get("action") != "deterministic":
raise ExecutionRebindError("EXECUTION_REBIND_DETERMINISTIC_PLAN_REQUIRED", 409)
if new_execution["execution_digest"] != request.expected_new_execution_digest:
raise ExecutionRebindError("EXECUTION_REBIND_NEW_DIGEST_DRIFT", 409)
if new_execution["execution_digest"] == old_execution["execution_digest"]:
raise ExecutionRebindError("EXECUTION_REBIND_DIGEST_UNCHANGED", 409)
'''
replace_once(path, old, new, "same-job fast-forward execution re-anchor")
old_event = ''' "old_action": old_execution.get("action"),
"new_action": new_execution.get("action"),
"previous_revision": request.expected_revision,
'''
new_event = ''' "old_action": old_execution.get("action"),
"new_action": new_execution.get("action"),
"old_expected_branch_oid": binding.expected_branch_oid,
"new_expected_branch_oid": candidate_binding.expected_branch_oid,
"head_advanced": head_advanced,
"previous_revision": request.expected_revision,
'''
replace_once(path, old_event, new_event, "re-anchor audit evidence")
syntax_check(path)
print("RESULT: PATCH_OK")
return 0
if __name__ == "__main__":
raise SystemExit(main())