File size: 5,094 Bytes
d61821a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bf40baf
d61821a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"""Build a deterministic compact publication package without raw trajectories."""

from __future__ import annotations

import gzip
import hashlib
import io
import json
import subprocess
import tarfile
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
PACKAGE_NAME = "agent-harness-publication-package"
ROOT_FILES = (
    ".zenodo.json",
    "CITATION.cff",
    "LICENSE",
    "LICENSE-DATA",
    ".gitignore",
    "README.md",
    "README_ZENODO.md",
    "REPRODUCING.md",
    "THIRD_PARTY_NOTICES.md",
    "pyproject.toml",
    "requirements-analysis.txt",
    "requirements.lock",
)
SOURCE_DIRS = (
    "configs",
    "docs",
    "paper",
    "scripts",
    "src",
    "tasks",
    "tests",
    "output/pdf",
    "results/derived/confirmatory_analysis_174ce71bcbce",
    "results/derived/e07",
    "results/derived/study2",
    "results/derived/study3",
    "results/derived/study4",
    "results/derived/study4_ancillary",
    "results/derived/study5",
)
EXTRA_FILES = (
    "results/reports/study2_preflight.json",
    "results/reports/study3_preflight.json",
    "results/reports/study4_preflight.json",
    "results/reports/study4_ancillary_preflight.json",
    "results/reports/study5_preflight.json",
)


def sha256(data: bytes) -> str:
    return hashlib.sha256(data).hexdigest()


def collect_files(root: Path) -> list[Path]:
    candidates = [root / path for path in ROOT_FILES + EXTRA_FILES]
    for directory in SOURCE_DIRS:
        candidates.extend((root / directory).rglob("*"))
    files = sorted({path for path in candidates if path.is_file() and
                    "__pycache__" not in path.parts and path.suffix != ".pyc"})
    missing = [str(root / path) for path in ROOT_FILES + EXTRA_FILES
               if not (root / path).is_file()]
    if missing:
        raise FileNotFoundError(f"required publication files are missing: {missing}")
    return files


def tar_info(name: str, size: int) -> tarfile.TarInfo:
    info = tarfile.TarInfo(name=name)
    info.size = size
    info.mode = 0o644
    info.mtime = 0
    info.uid = info.gid = 0
    info.uname = info.gname = ""
    return info


def build(root: Path = ROOT) -> dict[str, object]:
    files = collect_files(root)
    revision = subprocess.run(
        ["git", "rev-parse", "HEAD"], cwd=root, check=True,
        capture_output=True, text=True,
    ).stdout.strip()
    entries = []
    payloads: list[tuple[str, bytes]] = []
    for path in files:
        relative = path.relative_to(root).as_posix()
        data = path.read_bytes()
        entries.append({"path": relative, "bytes": len(data), "sha256": sha256(data)})
        payloads.append((relative, data))

    package_metadata = {
        "schema_version": 1,
        "title": "Dissecting Repository-Scale Code-Agent Harnesses",
        "author": "Mandeep Sidhu",
        "version": "1.0.0-preprint",
        "doi": "10.5281/zenodo.21781711",
        "licenses": {"software": "MIT", "paper_and_derived_data": "CC-BY-4.0"},
        "source_revision": revision,
        "reported_cells": 5453,
        "reported_generative_tokens": 368125497,
        "study2_cells": 912,
        "study3_cells": 540,
        "study4_cells": 210,
        "study5_cells": 2826,
        "file_count": len(entries),
        "contents": "compact source, derived evidence, paper, and preflight",
        "excluded": ["raw trajectories", "repository checkouts", "index caches", "model weights"],
    }
    manifest = {
        "package": package_metadata,
        "files": entries,
    }
    metadata_bytes = json.dumps(package_metadata, indent=2, sort_keys=True).encode() + b"\n"
    manifest_bytes = json.dumps(manifest, indent=2, sort_keys=True).encode() + b"\n"

    output_dir = root / "output" / "releases"
    output_dir.mkdir(parents=True, exist_ok=True)
    archive = output_dir / f"{PACKAGE_NAME}.tar.gz"
    with archive.open("wb") as raw:
        with gzip.GzipFile(filename="", mode="wb", fileobj=raw, mtime=0) as compressed:
            with tarfile.open(fileobj=compressed, mode="w", format=tarfile.PAX_FORMAT) as tar:
                prefix = PACKAGE_NAME
                for name, data in payloads:
                    info = tar_info(f"{prefix}/{name}", len(data))
                    tar.addfile(info, io.BytesIO(data))
                for name, data in (
                    ("PUBLICATION_PACKAGE.json", metadata_bytes),
                    ("MANIFEST.sha256.json", manifest_bytes),
                ):
                    info = tar_info(f"{prefix}/{name}", len(data))
                    tar.addfile(info, io.BytesIO(data))

    archive_digest = sha256(archive.read_bytes())
    checksum = output_dir / f"{archive.name}.sha256"
    checksum.write_text(f"{archive_digest}  {archive.name}\n", encoding="utf-8")
    return {
        **package_metadata,
        "archive": str(archive),
        "archive_bytes": archive.stat().st_size,
        "archive_sha256": archive_digest,
        "checksum": str(checksum),
    }


def main() -> None:
    print(json.dumps(build(), indent=2, sort_keys=True))


if __name__ == "__main__":
    main()