# Todo 52.9 Atomic Report Bundles and Audit Parity Plan **Status:** in_progress ## Goal Replace the fundamentally non-transactional two-path report publication with one atomic bundle publication boundary, and close the remaining report/CLI audit gaps found after Todo 52.8. ## Root Cause Publishing flat JSON and Markdown paths requires two independent filesystem operations. If the second operation conflicts, rolling back the first requires a check-then-unlink sequence that cannot atomically prove pathname ownership. A competing process can replace the first path between the inode check and `unlink()`, so the writer may delete another process's file or return a mixed pair. ## Scope - Fully write and `fsync` `report.json` and `report.md` inside one private, uniquely named bundle directory. - Publish the complete bundle through one atomic, no-overwrite directory symlink named from the timestamp; a collision chooses the next numeric suffix without deleting or replacing the competitor. - Return the two report paths through the published bundle path and leave no flat two-file rollback path. - Clean only unpublished private bundle state. Never inspect-then-delete a published competitor-controlled pathname. - Treat mutation after successful publication as out of scope: a process with write access to the output directory can replace any published filesystem entry after the command returns. - Render runtime errors and semantic failures together in Markdown when both exist, preserving the facts present in JSON. - Map summary/error stream failures to exit code `2` without exposing secrets or confusing them with benchmark sample failures. ## Files - Modify: `src/agent_lab/infrastructure/benchmark_reporting.py` - Modify: `src/agent_lab/presentation/benchmark_cli.py` - Modify: `tests/test_benchmark_reporting.py` - Modify: `tests/test_benchmark_cli.py` ## Verification - Reproduce the Todo 52.8 inode-check-to-unlink race before implementation. - `uv run pytest tests/test_benchmark_reporting.py tests/test_benchmark_cli.py -q` - concurrent process/thread bundle publication and collision stress tests - `uv run pytest` - `git diff --check`