mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-15 04:18:05 +00:00
Use the existing snapshot capture ceiling for buffered materialization so valid graphs remain usable on filesystems without reflinks. Preflight both release runtimes before paid sessions and exercise the real copy boundary with a 513 MiB regression and the native release smoke.
73 lines
3.4 KiB
Python
73 lines
3.4 KiB
Python
"""Build and materialize release graphs before any paid agent sessions."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import tempfile
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
|
|
from .process_control import ManagedProcessError, cancellation_scope
|
|
from .proposer_sandbox import SandboxError, preflight_bubblewrap, require_claude_sandbox_helpers
|
|
from .runner_tasks import resolve_task_bindings, select_tasks
|
|
from .runtime_mounts import trusted_gitnexus_runtime_mounts
|
|
from .sanitized_graph import prepare_sanitized_graph, validate_no_prebuilt_graph_assets
|
|
from .task_assets import TaskAssetCache, stage_task_assets
|
|
|
|
|
|
def preflight_release(tasks: list[dict[str, Any]], *, gitnexus_root: Path, claude_bin: Path) -> None:
|
|
"""Exercise the real snapshot/copy path on the same temp filesystem as the runner.
|
|
|
|
No provider or session code is involved. Graphs are rebuilt by the paid
|
|
runner afterwards, preserving its existing provenance and cache lifecycle.
|
|
"""
|
|
bwrap_bin = preflight_bubblewrap()
|
|
require_claude_sandbox_helpers()
|
|
mounts = trusted_gitnexus_runtime_mounts(root=gitnexus_root)
|
|
with (
|
|
tempfile.TemporaryDirectory(prefix="wfbench-preflight-") as directory,
|
|
TaskAssetCache(Path(directory) / ".task-assets") as cache,
|
|
):
|
|
bindings = resolve_task_bindings(tasks, task_asset_cache=cache)
|
|
graphs = {}
|
|
for task, binding in zip(tasks, bindings, strict=True):
|
|
validate_no_prebuilt_graph_assets(task)
|
|
repo = Path(binding["repo_identity"])
|
|
sha = binding["resolved_sha"]
|
|
key = (str(repo), sha)
|
|
if key not in graphs:
|
|
graphs[key] = prepare_sanitized_graph(
|
|
task, repo=repo, resolved_sha=sha, parent=Path(directory), cache=cache,
|
|
claude_bin=claude_bin, bwrap_bin=bwrap_bin, runtime_mounts=mounts,
|
|
)
|
|
graph = graphs[key]
|
|
assets = cache.prepare(task, repo=repo, resolved_sha=sha, expected_dependency_binding=binding)
|
|
print(f"Preflight {task['id']}: graph snapshot {graph.assets.total_bytes} bytes", flush=True)
|
|
with tempfile.TemporaryDirectory(prefix="probe-", dir=directory) as probe:
|
|
clone = Path(probe)
|
|
graph.materialize(clone, sanitized_head=graph.sanitized_head)
|
|
stage_task_assets(task, repo=repo, clone=clone, snapshot=assets)
|
|
print(f"Preflight {task['id']}: materialization passed", flush=True)
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--tasks", required=True, type=Path)
|
|
parser.add_argument("--gitnexus-root", required=True, type=Path)
|
|
parser.add_argument("--claude-bin", required=True, type=Path)
|
|
args = parser.parse_args()
|
|
try:
|
|
document = yaml.safe_load(args.tasks.read_text())
|
|
if not isinstance(document, dict) or not isinstance(document.get("tasks"), list):
|
|
raise ValueError("task file must contain a tasks list")
|
|
tasks, _ = select_tasks(document["tasks"], include_expensive=True)
|
|
with cancellation_scope(handle_signals=True):
|
|
preflight_release(tasks, gitnexus_root=args.gitnexus_root, claude_bin=args.claude_bin)
|
|
except (ManagedProcessError, OSError, SandboxError, RuntimeError, ValueError, yaml.YAMLError) as exc:
|
|
parser.error(str(exc))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|