approaches/ntuple-rl/ntuple-scale/scripts/artifact_refs.pyPython146 lines · 6.1 KB
#!/usr/bin/env python3
"""Resolve the public archive reference a finalized result record must cite.

A finalized result record cites its per-game artifact by the immutable public
reference ``https://data.drop7.dev/runs/<run-id>/<key>#sha256=<digest>``
(AGENTS.md, "Remote research artifacts"), never by a path into the ignored
``runs/`` directory.  This module finds that reference for a local run
artifact from what the run record and the publisher already know, and refuses
to invent one: a reference is returned only when its digest equals the digest
of the local file.

Sources, in order: an explicit reference from the command line, the run
record's ``artifactRefs`` (``research/runs/<run-id>.json``), then the
publisher's manifest (``runs/<run-id>/published.jsonl`` or
``runs/<run-id>/ntuple-scale/published.jsonl``; only lines whose status is
``uploaded`` or ``already-published`` count, a dry-run preview is never a
publication).
"""
from __future__ import annotations

import hashlib
import json
import os
import re
from urllib.parse import urlsplit

PUBLIC_ORIGIN = "https://data.drop7.dev"
PUBLISHED_STATUSES = frozenset({"uploaded", "already-published"})


class UnresolvedArtifact(Exception):
    """No verified public reference exists for the local artifact."""


def sha256_file(path):
    h = hashlib.sha256()
    with open(path, "rb") as handle:
        for chunk in iter(lambda: handle.read(1 << 20), b""):
            h.update(chunk)
    return h.hexdigest()


def parse_public_ref(ref, run_id):
    """Return (object key, digest) for a well-formed public reference below run_id, else None."""
    if not isinstance(ref, str):
        return None
    parsed = urlsplit(ref)
    if parsed.scheme != "https" or parsed.netloc != "data.drop7.dev" or parsed.query:
        return None
    prefix = f"/runs/{run_id}/"
    if not parsed.path.startswith(prefix) or parsed.path == prefix:
        return None
    match = re.fullmatch(r"sha256=([a-f0-9]{64})", parsed.fragment)
    if match is None:
        return None
    return parsed.path[1:], match.group(1)


def published_refs(root, run_id):
    """Yield every public reference recorded for run_id, from the run record and the publisher manifest."""
    run_record = os.path.join(root, "research", "runs", f"{run_id}.json")
    if os.path.isfile(run_record):
        with open(run_record, encoding="utf-8") as handle:
            record = json.load(handle)
        for ref in record.get("artifactRefs", []):
            if isinstance(ref, str) and ref.startswith(PUBLIC_ORIGIN):
                yield ref
    for manifest in (
        os.path.join(root, "runs", run_id, "published.jsonl"),
        os.path.join(root, "runs", run_id, "ntuple-scale", "published.jsonl"),
    ):
        if not os.path.isfile(manifest):
            continue
        with open(manifest, encoding="utf-8") as handle:
            for line in handle:
                line = line.strip()
                if not line:
                    continue
                try:
                    entry = json.loads(line)
                except ValueError:
                    continue
                if entry.get("status") in PUBLISHED_STATUSES and isinstance(entry.get("ref"), str):
                    yield entry["ref"]


def resolve_public_ref(root, run_id, local_path, digest, explicit=None):
    """Return the public reference of the run artifact at local_path (relative to root).

    ``digest`` is the SHA-256 of the local file; every returned reference carries
    it in its fragment.  ``explicit`` is a reference named on the command line
    and is checked, not trusted.  A reference whose object key equals
    local_path is preferred; otherwise a single digest match is accepted.
    """
    if explicit is not None:
        parsed = parse_public_ref(explicit, run_id)
        if parsed is None:
            raise UnresolvedArtifact(
                f"{explicit} is not a public reference of {run_id} "
                f"({PUBLIC_ORIGIN}/runs/{run_id}/<key>#sha256=<digest>)"
            )
        if parsed[1] != digest:
            raise UnresolvedArtifact(f"{explicit} carries digest {parsed[1]} but {local_path} hashes to {digest}")
        return explicit
    by_key, by_digest, seen = [], [], set()
    for ref in published_refs(root, run_id):
        parsed = parse_public_ref(ref, run_id)
        if parsed is None or parsed[1] != digest or ref in seen:
            continue
        seen.add(ref)
        (by_key if parsed[0] == local_path else by_digest).append(ref)
    if by_key:
        return by_key[0]
    if len(by_digest) == 1:
        return by_digest[0]
    if by_digest:
        raise UnresolvedArtifact(
            f"{len(by_digest)} published objects of {run_id} carry the digest of {local_path} under other keys; "
            "pass --per-game-ref to choose one: " + ", ".join(by_digest)
        )
    raise UnresolvedArtifact(
        f"no published object of {run_id} carries the digest of {local_path} ({digest}); publish it first "
        f"(npm run artifact:publish -- --run-id {run_id} --file {local_path} --public), cite the printed "
        f"reference in research/runs/{run_id}.json, or pass it as --per-game-ref"
    )


def citation_limitation(per_game_path, local_path):
    """The limitation sentence a record carries about how its per-game artifact is cited."""
    if per_game_path == local_path:
        return (
            f"DRAFT: the per-game artifact is cited by its local path {local_path}, which exists only on the "
            "workstation; the record is not finalized until the artifact is published and the citation is "
            "its public archive reference."
        )
    return (
        "The per-game artifact is cited by its public archive reference (data.drop7.dev, immutable run-scoped "
        f"key, digest in the fragment); a byte-identical copy remains under {local_path} on the workstation "
        "and a promoted copy under artifacts/results/."
    )


def artifact_manifest_ref(root, experiment_id, run_id):
    """Return the repository path of the promoted-artifact manifest when it exists, else None."""
    relative = os.path.join("artifacts", "results", experiment_id, run_id, "manifest.json")
    return relative if os.path.isfile(os.path.join(root, relative)) else None