from __future__ import annotations import json import os import tempfile from datetime import UTC, datetime from pathlib import Path from typing import Any def utc_now_iso() -> str: """Return a stable UTC timestamp for manifests and capture artifacts.""" return datetime.now(UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z") def write_json_atomic(path: Path, payload: Any) -> None: """Write JSON without exposing a partially written artifact.""" path = path.expanduser() path.parent.mkdir(parents=True, exist_ok=True) serialized = json.dumps(payload, ensure_ascii=False, indent=2) + "\n" temp_name: str | None = None try: with tempfile.NamedTemporaryFile( mode="w", encoding="utf-8", dir=path.parent, prefix=f".{path.name}.", suffix=".tmp", delete=False, ) as stream: temp_name = stream.name stream.write(serialized) stream.flush() os.fsync(stream.fileno()) Path(temp_name).replace(path) finally: if temp_name is not None: Path(temp_name).unlink(missing_ok=True)