"""Merge debug instrumentation — enabled by MUSE_MERGE_DEBUG=1. When the env var is set, every merge event is appended as a JSON line to /tmp/muse_merge_debug.log. Importing this module is always safe; logging is a no-op unless the env var is set. Usage:: from muse.core.merge_debug import merge_debug_log merge_debug_log("phase", {"key": "value"}) """ from __future__ import annotations import json import os import pathlib import time from muse.core.types import JsonObject, Manifest _ENABLED = os.getenv("MUSE_MERGE_DEBUG", "").strip() not in ("", "0", "false", "no") _LOG_PATH = pathlib.Path(os.getenv("MUSE_MERGE_DEBUG_LOG", "/tmp/muse_merge_debug.log")) def merge_debug_log(event: str, data: JsonObject) -> None: """Append a JSON-line record to the merge debug log. No-op unless MUSE_MERGE_DEBUG=1. Never raises — debug logging must not break the merge path. """ if not _ENABLED: return try: record = {"t": round(time.time(), 4), "event": event, **data} with _LOG_PATH.open("a") as fh: fh.write(json.dumps(record) + "\n") except Exception: # pragma: no cover pass # debug logging must never break the merge path def merge_debug_manifest_summary(manifest: Manifest) -> JsonObject: """Return a compact, loggable summary of a manifest. Full manifest is included — every path and object_id — so we can reconstruct exactly what both sides held at merge time. """ return { "file_count": len(manifest), "files": manifest, }