"""Milestone 3 projection, worker, fragment, and publication benchmark gates.""" from __future__ import annotations import argparse import gc import hashlib import json import math import platform import resource import statistics import subprocess import sys import tempfile import time import tracemalloc from collections.abc import Callable, Mapping, Sequence from dataclasses import dataclass, replace from pathlib import Path from typing import cast from milestone0_baseline import write_synthetic_project from docforge.graph_projection import ( GraphViewRequestV1, build_graph_projection_package, build_graph_view_plan, ) from docforge.graph_rendering import GraphRenderService from docforge.manual_projection import ( build_manual_projection_package, build_manual_render_plan, ) from docforge.models import ProjectSnapshot from docforge.project import Project from docforge.projection_contract import ( MAX_PACKAGE_BYTES, MAX_PLAN_BYTES, MAX_RECEIPT_BYTES, GraphViewPlanV1, ManualRenderPlanV1, ProjectionPackageV1, ProjectionRenderResult, canonical_projection_bytes, projection_hash, ) from docforge.projection_fragments import ( FragmentKey, FragmentRecord, ProjectionFragmentCache, fragment_semantic_hash, ) from docforge.projection_worker import ( MAX_WORKER_ARTIFACT_BYTES, render_projection_in_worker, ) from docforge.render_contract import GenericHtmlRenderer, PreparedRender from docforge.rendering import RenderService from docforge.telemetry import COUNTER_NAMES, request from docforge_renderers.graph import PortableGraphHtmlRenderer from docforge_renderers.manual import ManualHtmlRenderer ROOT = Path(__file__).resolve().parents[1] FULL_NODE_COUNT = 1_000 SMOKE_NODE_COUNT = 25 DEFAULT_FULL_SAMPLES = 3 DEFAULT_SMOKE_SAMPLES = 1 MAX_STATUS_RESPONSE_BYTES = 256_000 MAX_TRACED_PEAK_BYTES = 256 * 1024 * 1024 MAX_CHILD_PEAK_BYTES = 256 * 1024 * 1024 ZERO_WORK_COUNTERS = tuple( counter for counter in COUNTER_NAMES if counter != "source_generation_checks" ) @dataclass(frozen=True) class _ProjectionSample: plan_id: str package_id: str artifact: bytes receipt: Mapping[str, object] plan_bytes: int package_bytes: int child_peak_memory_bytes: int | None @dataclass(frozen=True) class _StatusSample: response: Mapping[str, object] counters: Mapping[str, object] @dataclass(frozen=True) class _FragmentSweep: fragment_count: int aggregate_content_bytes: int ordered_record_hash: str def _parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( description="Gate DocForge2 Milestone 3 projection behavior on a disposable project." ) parser.add_argument("--mode", choices=("smoke", "full"), default="full") parser.add_argument("--nodes", type=int) parser.add_argument("--samples", type=int) parser.add_argument("--output", type=Path) return parser def encode_report(value: object) -> str: """Serialize one report deterministically for files, CI logs, and comparisons.""" return json.dumps(value, sort_keys=True, indent=2, ensure_ascii=False) + "\n" def _git(arguments: list[str]) -> str: return subprocess.run( ["git", *arguments], cwd=ROOT, check=True, capture_output=True, text=True, ).stdout.strip() def _compact_size(value: object) -> int: return len(canonical_projection_bytes(value)) def _sha256(content: bytes) -> str: return hashlib.sha256(content).hexdigest() def _prepare_fixture(root: Path, node_count: int) -> None: write_synthetic_project(root, node_count) descriptor = root / ".docforge" / "project.toml" maximum_edges = node_count - 1 maximum_work = max(100, node_count * 4) original = descriptor.read_text(encoding="utf-8") original = original.replace( "max_render_bytes = 20000000", "max_render_bytes = 4000000", ) descriptor.write_text( original + f""" [graph_render] output_root = ".docforge/portable-graph" [[graph_render.views]] id = "architecture" renderer = "portable_graph_html" output = "architecture.html" title = "Synthetic architecture" query = "synthetic measurement" initial_mode = "web" depth = 1 max_nodes = {node_count} max_edges = {maximum_edges} max_work = {maximum_work} families = ["guide"] relations = ["depends_on"] authorities = [] statuses = ["active"] tags = [] include_logic = false """, encoding="utf-8", ) def _manual_package( snapshot: ProjectSnapshot, ) -> tuple[ManualRenderPlanV1, ProjectionPackageV1, str]: descriptor = snapshot.descriptor render = descriptor.render if render is None: raise RuntimeError("Milestone 3 fixture has no manual render configuration") view = render.views[0] renderer_version = GenericHtmlRenderer(incremental=False).renderer_version plan = build_manual_render_plan(snapshot, view, changeset_hash=None) package = build_manual_projection_package( plan, view.template_path.read_bytes(), renderer_id=ManualHtmlRenderer.renderer_id, renderer_version=renderer_version, max_output_bytes=descriptor.limits.max_render_bytes, ) return plan, package, renderer_version def _graph_package( snapshot: ProjectSnapshot, node_count: int, ) -> tuple[GraphViewPlanV1, ProjectionPackageV1]: descriptor = snapshot.descriptor plan = build_graph_view_plan( snapshot, GraphViewRequestV1( view_id="architecture", title="Synthetic architecture", query="synthetic measurement", initial_mode="web", depth=1, max_nodes=node_count, max_edges=node_count - 1, max_work=max(100, node_count * 4), families=("guide",), relations=("depends_on",), statuses=("active",), ), False, ) package = build_graph_projection_package( plan, renderer_id=PortableGraphHtmlRenderer.renderer_id, renderer_version=PortableGraphHtmlRenderer.renderer_version, max_output_bytes=descriptor.limits.max_render_bytes, ) return plan, package def _projection_sample( plan: ManualRenderPlanV1 | GraphViewPlanV1, package: ProjectionPackageV1, result: ProjectionRenderResult, ) -> _ProjectionSample: if len(result.artifacts) != 1: raise RuntimeError("Projection benchmark expected exactly one artifact") artifact = result.artifacts[0].content peak = result.receipt.document.get("peak_memory_bytes") if peak is not None and (type(peak) is not int or peak < 1): raise RuntimeError("Detached worker did not report valid peak memory") return _ProjectionSample( plan_id=plan.plan_id, package_id=package.package_id, artifact=artifact, receipt=result.receipt.as_dict(), plan_bytes=_compact_size(plan.as_dict()), package_bytes=_compact_size(package.as_dict()), child_peak_memory_bytes=peak, ) def _projection_summary(sample: _ProjectionSample) -> dict[str, object]: return { "plan_id": sample.plan_id, "package_id": sample.package_id, "artifact_sha256": _sha256(sample.artifact), "artifact_bytes": len(sample.artifact), "plan_bytes": sample.plan_bytes, "package_bytes": sample.package_bytes, } def _measure( operation: Callable[[], object], *, samples: int, p95_limit_ms: float, response_limit_bytes: int, summary: Callable[[object], Mapping[str, object]], response_size: Callable[[object], int], warmups: int = 0, ) -> tuple[dict[str, object], object]: for _ in range(warmups): operation() durations: list[float] = [] traced_peaks: list[int] = [] response_sizes: list[int] = [] stable_summary: Mapping[str, object] | None = None last: object = None for _ in range(samples): gc.collect() tracemalloc.start() started = time.perf_counter_ns() try: value = operation() elapsed_ms = (time.perf_counter_ns() - started) / 1_000_000 _, traced_peak = tracemalloc.get_traced_memory() finally: tracemalloc.stop() current_summary = dict(summary(value)) if stable_summary is None: stable_summary = current_summary elif current_summary != stable_summary: raise RuntimeError("Milestone 3 operation changed deterministic result across samples") current_response_size = response_size(value) if current_response_size > response_limit_bytes: raise RuntimeError( "Milestone 3 response exceeded its fixed benchmark boundary: " f"{current_response_size} > {response_limit_bytes}" ) if traced_peak > MAX_TRACED_PEAK_BYTES: raise RuntimeError( "Milestone 3 operation exceeded its traced-memory boundary: " f"{traced_peak} > {MAX_TRACED_PEAK_BYTES}" ) durations.append(elapsed_ms) traced_peaks.append(traced_peak) response_sizes.append(current_response_size) last = value ordered = sorted(durations) p95_index = max(0, math.ceil(len(ordered) * 0.95) - 1) p95 = ordered[p95_index] if p95 > p95_limit_ms: raise RuntimeError(f"Milestone 3 operation p95 {p95:.3f} ms exceeds {p95_limit_ms:.3f} ms") assert stable_summary is not None return ( { "samples": samples, "median_ms": round(statistics.median(ordered), 3), "p95_ms": round(p95, 3), "min_ms": round(ordered[0], 3), "max_ms": round(ordered[-1], 3), "p95_limit_ms": p95_limit_ms, "maximum_response_bytes": max(response_sizes), "response_limit_bytes": response_limit_bytes, "maximum_traced_peak_bytes": max(traced_peaks), "traced_peak_limit_bytes": MAX_TRACED_PEAK_BYTES, "stable_result": dict(stable_summary), }, last, ) def _projection_measurement( operation: Callable[[], _ProjectionSample], *, samples: int, p95_limit_ms: float, ) -> tuple[dict[str, object], _ProjectionSample]: child_peaks: list[int] = [] def observed_operation() -> _ProjectionSample: sample = operation() if sample.child_peak_memory_bytes is not None: if sample.child_peak_memory_bytes > MAX_CHILD_PEAK_BYTES: raise RuntimeError( "Detached worker peak memory " f"{sample.child_peak_memory_bytes} exceeds " f"{MAX_CHILD_PEAK_BYTES} bytes" ) child_peaks.append(sample.child_peak_memory_bytes) return sample measurement, value = _measure( observed_operation, samples=samples, p95_limit_ms=p95_limit_ms, response_limit_bytes=MAX_RECEIPT_BYTES, summary=lambda item: _projection_summary(cast(_ProjectionSample, item)), response_size=lambda item: _compact_size(cast(_ProjectionSample, item).receipt), ) sample = cast(_ProjectionSample, value) if sample.plan_bytes > MAX_PLAN_BYTES or sample.package_bytes > MAX_PACKAGE_BYTES: raise RuntimeError("Projection plan or package exceeded its protocol boundary") if child_peaks: measurement["maximum_child_peak_bytes"] = max(child_peaks) measurement["child_peak_limit_bytes"] = MAX_CHILD_PEAK_BYTES return measurement, sample def _profiled_status(operation: Callable[[], Mapping[str, object]]) -> _StatusSample: with request("benchmark.m3", enabled=True) as collector: response = operation() if collector is None: raise RuntimeError("Milestone 3 telemetry collector was not created") counters = collector.as_dict(outcome="ok")["counters"] typed_counters = cast(Mapping[str, object], counters) for counter in ZERO_WORK_COUNTERS: if typed_counters[counter] != 0: raise RuntimeError(f"Receipt-only status performed forbidden work: {counter}") if typed_counters["source_generation_checks"] != 2: raise RuntimeError("Receipt-only status did not perform its two race-safe source checks") if response.get("status") != "ok" or response.get("state") != "current": raise RuntimeError("Receipt-only status did not report a current publication") return _StatusSample(response=response, counters=typed_counters) def _status_summary(value: object) -> Mapping[str, object]: sample = cast(_StatusSample, value) return { "response": dict(sample.response), "counters": dict(sample.counters), } def _fragment_summary(value: object) -> Mapping[str, object]: sample = cast(_FragmentSweep, value) return { "fragment_count": sample.fragment_count, "aggregate_content_bytes": sample.aggregate_content_bytes, "ordered_record_hash": sample.ordered_record_hash, } def _fragment_sweep(records: Sequence[FragmentRecord]) -> _FragmentSweep: return _FragmentSweep( fragment_count=len(records), aggregate_content_bytes=sum(record.byte_count for record in records), ordered_record_hash=projection_hash([record.record_id for record in records]), ) def _prepared_summary(value: object) -> Mapping[str, object]: prepared = cast(PreparedRender, value) return { "render_identity": prepared.render_identity, "output_sha256": prepared.output_hash, "output_bytes": len(prepared.output), } def _prepared_response_size(value: object) -> int: prepared = cast(PreparedRender, value) return _compact_size(prepared.projection_receipt) def _benchmark(root: Path, node_count: int, samples: int) -> dict[str, object]: project = Project.open(root) snapshot = project.load() if len(snapshot.nodes) != node_count or len(snapshot.edges) != node_count - 1: raise RuntimeError("Milestone 3 fixture does not have full synthetic coverage") operations: dict[str, object] = {} def manual_full() -> _ProjectionSample: plan, package, renderer_version = _manual_package(snapshot) result = ManualHtmlRenderer(renderer_version).render(package) return _projection_sample(plan, package, result) operations["manual_full_render"], manual_result = _projection_measurement( manual_full, samples=samples, p95_limit_ms=15_000, ) def graph_full() -> _ProjectionSample: plan, package = _graph_package(snapshot, node_count) result = PortableGraphHtmlRenderer().render(package) return _projection_sample(plan, package, result) operations["portable_graph_full_render"], graph_result = _projection_measurement( graph_full, samples=samples, p95_limit_ms=10_000, ) manual_plan, manual_package, manual_renderer_version = _manual_package(snapshot) graph_plan, graph_package = _graph_package(snapshot, node_count) graph_diagnostics = cast(Mapping[str, object], graph_plan.document["diagnostics"]) manual_pages = cast(list[dict[str, object]], manual_plan.document["pages"]) if ( len(manual_pages) != node_count or graph_diagnostics["returned_nodes"] != node_count or graph_diagnostics["returned_edges"] != node_count - 1 ): raise RuntimeError("Projection plans did not retain every synthetic node and edge") manual_worker_measurement, manual_worker = _projection_measurement( lambda: _projection_sample( manual_plan, manual_package, render_projection_in_worker(manual_package), ), samples=samples, p95_limit_ms=20_000, ) operations["manual_detached_worker"] = manual_worker_measurement manual_worker_peak = cast( int, manual_worker_measurement["maximum_child_peak_bytes"], ) graph_worker_measurement, graph_worker = _projection_measurement( lambda: _projection_sample( graph_plan, graph_package, render_projection_in_worker(graph_package), ), samples=samples, p95_limit_ms=20_000, ) operations["portable_graph_detached_worker"] = graph_worker_measurement graph_worker_peak = cast( int, graph_worker_measurement["maximum_child_peak_bytes"], ) if ( manual_worker.artifact != manual_result.artifact or graph_worker.artifact != graph_result.artifact ): raise RuntimeError("Detached worker output is not byte-equivalent to in-process output") manual_renderer = ManualHtmlRenderer(manual_renderer_version) fragment_records = [ FragmentRecord.create( FragmentKey.create( projection_kind="manual", renderer_id=ManualHtmlRenderer.renderer_id, renderer_version=manual_renderer_version, component_version=GenericHtmlRenderer.page_component_version, semantic_input_hash=fragment_semantic_hash(page), ), manual_renderer.render_page_fragment(page).encode("utf-8"), ) for page in manual_pages ] fragment_cache = ProjectionFragmentCache( root, root / ".docforge" / "milestone3-fragment-cache", ) def fragment_misses() -> _FragmentSweep: if any(fragment_cache.get(record.key) is not None for record in fragment_records): raise RuntimeError("Cold fragment-cache lookup unexpectedly hit") return _fragment_sweep(fragment_records) operations["fragment_cache_miss_sweep"], _ = _measure( fragment_misses, samples=samples, p95_limit_ms=5_000, response_limit_bytes=32_768, summary=_fragment_summary, response_size=lambda item: _compact_size(_fragment_summary(item)), ) def fragment_puts() -> _FragmentSweep: published: list[FragmentRecord] = [] for record in fragment_records: stored = fragment_cache.put(record.key, record.content) if stored != record: raise RuntimeError("Fragment cache did not publish an exact record") assert stored is not None published.append(stored) return _fragment_sweep(published) operations["fragment_cache_put_sweep"], _ = _measure( fragment_puts, samples=1, p95_limit_ms=10_000, response_limit_bytes=32_768, summary=_fragment_summary, response_size=lambda item: _compact_size(_fragment_summary(item)), ) def fragment_hits() -> _FragmentSweep: loaded: list[FragmentRecord] = [] for expected in fragment_records: record = fragment_cache.get(expected.key) if record != expected: raise RuntimeError("Fragment cache hit was not byte-exact") assert record is not None loaded.append(record) return _fragment_sweep(loaded) operations["fragment_cache_hit_sweep"], _ = _measure( fragment_hits, samples=samples, p95_limit_ms=5_000, response_limit_bytes=32_768, summary=_fragment_summary, response_size=lambda item: _compact_size(_fragment_summary(item)), ) render_config = snapshot.descriptor.render assert render_config is not None incremental_package = build_manual_projection_package( manual_plan, render_config.views[0].template_path.read_bytes(), renderer_id=ManualHtmlRenderer.renderer_id, renderer_version=manual_renderer_version, max_output_bytes=snapshot.descriptor.limits.max_render_bytes, fragment_records=[record.as_dict() for record in fragment_records], ) def fragment_equivalence() -> _ProjectionSample: sample = _projection_sample( manual_plan, incremental_package, ManualHtmlRenderer(manual_renderer_version).render(incremental_package), ) if sample.artifact != manual_result.artifact: raise RuntimeError("Fragment-assisted manual output is not byte-equivalent") return sample operations["fragment_assisted_equivalence"], fragment_result = _projection_measurement( fragment_equivalence, samples=samples, p95_limit_ms=15_000, ) render_config = snapshot.descriptor.render assert render_config is not None manual_view = render_config.views[0] template_bytes = manual_view.template_path.read_bytes() production_renderer = GenericHtmlRenderer() operations["manual_incremental_cold"], cold_prepared = _measure( lambda: production_renderer.prepare( snapshot, manual_view, template_bytes, changeset_hash=None, ), samples=1, p95_limit_ms=20_000, response_limit_bytes=MAX_RECEIPT_BYTES, summary=_prepared_summary, response_size=_prepared_response_size, ) operations["manual_incremental_warm"], warm_prepared = _measure( lambda: production_renderer.prepare( snapshot, manual_view, template_bytes, changeset_hash=None, ), samples=samples, p95_limit_ms=20_000, response_limit_bytes=MAX_RECEIPT_BYTES, summary=_prepared_summary, response_size=_prepared_response_size, ) operations["manual_forced_full"], forced_prepared = _measure( lambda: GenericHtmlRenderer(incremental=False).prepare( snapshot, manual_view, template_bytes, changeset_hash=None, ), samples=samples, p95_limit_ms=20_000, response_limit_bytes=MAX_RECEIPT_BYTES, summary=_prepared_summary, response_size=_prepared_response_size, ) production_values = tuple( cast(PreparedRender, value) for value in (cold_prepared, warm_prepared, forced_prepared) ) if len({value.output for value in production_values}) != 1: raise RuntimeError("Production cold, warm, and forced-full manual output differs") changed_node = replace( snapshot.nodes[0], content=snapshot.nodes[0].content + "\nChanged projection content.\n", content_hash=_sha256( (snapshot.nodes[0].content + "\nChanged projection content.\n").encode() ), ) added_node = replace( snapshot.nodes[-1], node_id="guide.synthetic-added", title="Synthetic added", source_path="docs/content/synthetic-added.md", content_hash=_sha256(b"synthetic-added"), ) variants = { "change": replace( snapshot, nodes=(changed_node, *snapshot.nodes[1:]), source_hash=_sha256(b"manual-change-variant"), ), "add": replace( snapshot, nodes=(*snapshot.nodes, added_node), source_hash=_sha256(b"manual-add-variant"), ), "delete": replace( snapshot, nodes=snapshot.nodes[:-1], edges=tuple( edge for edge in snapshot.edges if edge.source_id != snapshot.nodes[-1].node_id and edge.target_id != snapshot.nodes[-1].node_id ), source_hash=_sha256(b"manual-delete-variant"), ), "reorder": replace( snapshot, nodes=tuple(reversed(snapshot.nodes)), source_hash=_sha256(b"manual-reorder-variant"), ), } variant_equivalence: dict[str, bool] = {} for name, variant in variants.items(): incremental = GenericHtmlRenderer().prepare( variant, manual_view, template_bytes, changeset_hash=None, ) full = GenericHtmlRenderer(incremental=False).prepare( variant, manual_view, template_bytes, changeset_hash=None, ) variant_equivalence[name] = incremental.output == full.output if not all(variant_equivalence.values()): raise RuntimeError("Production incremental mutation output differs from forced full") manual_service = RenderService(project) graph_service = GraphRenderService(project) manual_service.render("manual") graph_service.render("architecture") operations["manual_status_no_work"], manual_status = _measure( lambda: _profiled_status(lambda: manual_service.status("manual")), samples=samples, p95_limit_ms=500, response_limit_bytes=MAX_STATUS_RESPONSE_BYTES, summary=_status_summary, response_size=lambda item: _compact_size(cast(_StatusSample, item).response), ) operations["portable_graph_status_no_work"], graph_status = _measure( lambda: _profiled_status(lambda: graph_service.status("architecture")), samples=samples, p95_limit_ms=500, response_limit_bytes=MAX_STATUS_RESPONSE_BYTES, summary=_status_summary, response_size=lambda item: _compact_size(cast(_StatusSample, item).response), ) return { "fixture": { "kind": "synthetic_generic_projection", "node_count": node_count, "edge_count": node_count - 1, "manual_page_count": len(manual_pages), "portable_graph_node_count": graph_diagnostics["returned_nodes"], "portable_graph_edge_count": graph_diagnostics["returned_edges"], "full_coverage": ( len(manual_pages) == node_count and graph_diagnostics["returned_nodes"] == node_count and graph_diagnostics["returned_edges"] == node_count - 1 ), }, "operations": operations, "equivalence": { "manual_in_process_vs_detached": manual_worker.artifact == manual_result.artifact, "portable_graph_in_process_vs_detached": graph_worker.artifact == graph_result.artifact, "manual_full_vs_fragment_assisted": fragment_result.artifact == manual_result.artifact, "manual_production_cold_warm_full": len({value.output for value in production_values}) == 1, "manual_production_variants": variant_equivalence, }, "sizes": { "manual": { **_projection_summary(manual_result), "receipt_bytes": _compact_size(manual_result.receipt), }, "portable_graph": { **_projection_summary(graph_result), "receipt_bytes": _compact_size(graph_result.receipt), }, "fragment_assisted_manual": { **_projection_summary(fragment_result), "receipt_bytes": _compact_size(fragment_result.receipt), "fragment_count": len(fragment_records), "aggregate_fragment_content_bytes": sum( record.byte_count for record in fragment_records ), }, "manual_status_response_bytes": _compact_size( cast(_StatusSample, manual_status).response ), "portable_graph_status_response_bytes": _compact_size( cast(_StatusSample, graph_status).response ), }, "memory": { "process_peak_rss_kib": int(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss), "manual_worker_peak_bytes": manual_worker_peak, "portable_graph_worker_peak_bytes": graph_worker_peak, }, } def main() -> int: arguments = _parser().parse_args() default_nodes = FULL_NODE_COUNT if arguments.mode == "full" else SMOKE_NODE_COUNT default_samples = DEFAULT_FULL_SAMPLES if arguments.mode == "full" else DEFAULT_SMOKE_SAMPLES node_count = default_nodes if arguments.nodes is None else arguments.nodes samples = default_samples if arguments.samples is None else arguments.samples if not 2 <= node_count <= FULL_NODE_COUNT: raise SystemExit("--nodes must be between 2 and 1000") if arguments.mode == "full" and node_count != FULL_NODE_COUNT: raise SystemExit("--mode full requires exactly 1000 nodes") if samples < 1: raise SystemExit("--samples must be positive") with tempfile.TemporaryDirectory(prefix="docforge-milestone3-") as directory: benchmark_root = Path(directory).resolve() _prepare_fixture(benchmark_root, node_count) measurement = _benchmark(benchmark_root, node_count, samples) status = _git(["status", "--porcelain"]) report: dict[str, object] = { "schema_version": 1, "benchmark": "docforge2_milestone3", "mode": arguments.mode, "source": { "revision": _git(["rev-parse", "HEAD"]), "dirty": bool(status), }, "environment": { "platform": platform.platform(), "machine": platform.machine(), "python": platform.python_version(), "implementation": platform.python_implementation(), }, "method": { "clock": "time.perf_counter_ns", "in_process_peak_memory": "tracemalloc per measured invocation", "detached_peak_memory": "worker receipt resource peak RSS", "process_peak_memory": "resource.getrusage(RUSAGE_SELF).ru_maxrss", "response_size": "UTF-8 bytes of canonical compact sorted JSON", "samples": samples, "full_mode_node_requirement": FULL_NODE_COUNT, "determinism": ( "stable semantic summaries must match across samples; report JSON uses sorted keys" ), "maximum_worker_artifact_bytes": MAX_WORKER_ARTIFACT_BYTES, }, **measurement, } encoded = encode_report(report) if arguments.output is not None: output = arguments.output.resolve() output.parent.mkdir(parents=True, exist_ok=True) output.write_text(encoded, encoding="utf-8") sys.stdout.write(encoded) return 0 if __name__ == "__main__": raise SystemExit(main())