"""Campaign-aware continuation leases for an existing Git branch. This module is deliberately transport-neutral. It validates branch lineage and hands ref mutation to an injected compare-and-swap broker; it does not run Git, inspect credentials, or create a branch itself. """ from __future__ import annotations from dataclasses import dataclass, replace from datetime import datetime, timedelta, timezone import re from typing import Protocol OID_RE = re.compile(r"^[0-9a-f]{40}$") TARGET_BRANCH = "agent/autonomous-release-campaign-v1-20260807" LINEAGE_ANCHOR = "69b45e81dcd2c3707c367003b08c55fd361faae8" CAMPAIGN_HEAD = "bba675fab3b7e0c5fba7066720252b3c91b9f20d" class ContinuationError(RuntimeError): """Stable fail-closed error for lease or branch binding violations.""" class BranchProbe(Protocol): def branch_exists(self, branch: str) -> bool: ... def branch_head(self, branch: str) -> str: ... def is_ancestor(self, older: str, newer: str) -> bool: ... class RefCAS(Protocol): def compare_and_swap_branch(self, branch: str, expected: str, new: str) -> str: ... def _oid(value: str, field: str) -> str: if not isinstance(value, str) or not OID_RE.fullmatch(value): raise ContinuationError(f"{field}_invalid") return value @dataclass(frozen=True, slots=True) class WriterLeaseRequestV2: task_id: str repository: str branch_mode: str base_oid: str expected_branch_oid: str target_branch: str generation: int lease_seconds: int = 900 job_id: str = "" schema = "aios.task-writer-lease.v2" accepted_schemas = frozenset({"aios.task-writer-lease.v2", "aios.task-writer-lease-request.v2"}) def validate(self, probe: BranchProbe) -> None: if not self.task_id or self.repository != "aios/aios": raise ContinuationError("request_identity_invalid") if not self.job_id or not self.job_id.startswith("job-"): raise ContinuationError("job_id_invalid") if self.branch_mode not in {"CREATE_NEW", "CONTINUE_EXISTING"}: raise ContinuationError("branch_mode_invalid") _oid(self.base_oid, "base_oid") _oid(self.expected_branch_oid, "expected_branch_oid") if self.target_branch in {"main", "master"} or self.target_branch.startswith(("refs/", "tags/")): raise ContinuationError("protected_branch_rejected") if not isinstance(self.generation, int) or isinstance(self.generation, bool) or self.generation < 1: raise ContinuationError("generation_invalid") if not isinstance(self.lease_seconds, int) or not 1 <= self.lease_seconds <= 86_400: raise ContinuationError("lease_duration_invalid") if self.branch_mode == "CONTINUE_EXISTING": if not probe.branch_exists(self.target_branch): raise ContinuationError("EXISTING_BRANCH_MISSING") actual = _oid(probe.branch_head(self.target_branch), "actual_branch_oid") if actual != self.expected_branch_oid: raise ContinuationError("EXISTING_BRANCH_OID_CONFLICT") if not probe.is_ancestor(self.base_oid, actual): raise ContinuationError("BASE_NOT_ANCESTOR_OF_BRANCH") elif hasattr(probe, "commit_exists") and not probe.commit_exists(self.base_oid): raise ContinuationError("BASE_COMMIT_NOT_FOUND") elif self.branch_mode == "CREATE_NEW" and probe.branch_exists(self.target_branch): raise ContinuationError("TARGET_BRANCH_ALREADY_EXISTS") elif self.branch_mode == "CREATE_NEW" and self.base_oid != self.expected_branch_oid: raise ContinuationError("CREATE_NEW_BASE_EXPECTATION_MISMATCH") @dataclass(frozen=True, slots=True) class CampaignWriterLease: task_id: str repository: str branch: str lineage_anchor_oid: str current_head_oid: str generation: int lease_expires_at: datetime append_only: bool = True renewable: bool = True multi_commit: bool = True recoverable: bool = True state: str = "ACTIVE" branch_bound: bool = True def __post_init__(self) -> None: _oid(self.lineage_anchor_oid, "lineage_anchor_oid") _oid(self.current_head_oid, "current_head_oid") if not all((self.append_only, self.renewable, self.multi_commit, self.recoverable, self.branch_bound)): raise ContinuationError("lease_capability_downgrade") class ContinuationLeaseManager: """State machine for a multi-commit lease with CAS-only ref updates.""" def __init__(self, probe: BranchProbe, refs: RefCAS, *, now=datetime.now) -> None: self.probe = probe self.refs = refs self.now = now def open(self, request: WriterLeaseRequestV2) -> CampaignWriterLease: request.validate(self.probe) if request.branch_mode != "CONTINUE_EXISTING": raise ContinuationError("CREATE_NEW_REQUIRES_SEPARATE_PROVISIONER") return CampaignWriterLease( task_id=request.task_id, repository=request.repository, branch=request.target_branch, lineage_anchor_oid=request.base_oid, current_head_oid=request.expected_branch_oid, generation=request.generation, lease_expires_at=self.now(timezone.utc) + timedelta(seconds=request.lease_seconds), ) def renew(self, lease: CampaignWriterLease, seconds: int) -> CampaignWriterLease: if lease.state != "ACTIVE" or not lease.renewable or seconds < 1: raise ContinuationError("lease_not_renewable") return replace(lease, lease_expires_at=self.now(timezone.utc) + timedelta(seconds=seconds)) def append_commit(self, lease: CampaignWriterLease, new_head_oid: str) -> CampaignWriterLease: if lease.state != "ACTIVE": raise ContinuationError("lease_not_active") _oid(new_head_oid, "new_head_oid") if not self.probe.is_ancestor(lease.current_head_oid, new_head_oid): raise ContinuationError("NON_FAST_FORWARD_COMMIT") try: actual = self.refs.compare_and_swap_branch( lease.branch, lease.current_head_oid, new_head_oid ) except Exception as exc: raise ContinuationError("BRANCH_LEASE_STALE") from exc if actual != new_head_oid: raise ContinuationError("BRANCH_LEASE_STALE") return replace(lease, current_head_oid=new_head_oid) def supersede(self, lease: CampaignWriterLease) -> CampaignWriterLease: if lease.state not in {"ACTIVE", "RECOVERABLE_FAILURE", "RECONCILIATION_REQUIRED"}: raise ContinuationError("lease_not_supersedable") return replace(lease, generation=lease.generation + 1, state="SUPERSEDED")