Skip to content

Commit 74958a1

Browse files
fix(provenance): record traced child's Python identity, not roar's host
Friction-journal feedback on #108: after the cross-Python fixes, `roar show @N` reports `Environment: ... Python 3.13.x` for jobs whose command was system `python3` (3.12). The Python identity in job metadata was being captured from `platform.python_version()` in roar's own host process (`runtime_collector.collect`), not from the traced child. Right at the seam roar is selling reproducibility on. Captures `python_version` + `python_implementation` from `platform.{python_version,python_implementation}()` *inside* the traced process in `tracker.write_log`, threads them through the `PythonInjectData` model, and has `runtime_collector` prefer the traced values (falling back to host values when the inject log is missing the fields, e.g. older logs). Also: stderr remediation in `sitecustomize.py` now suggests `uv tool install --python pythonX.Y roar-cli --reinstall` instead of `--force`. Same effect, accurate user-facing semantics, less alarming. Tests: - `test_runtime_tracker_writes_expected_log_payload` asserts `python_version` (with at least 2 dots, e.g. "3.12.3") and a non-empty `python_implementation`. - 968 unit tests passing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 23bf3c4 commit 74958a1

5 files changed

Lines changed: 19 additions & 3 deletions

File tree

roar/core/models/provenance.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class PythonInjectData(RoarBaseModel):
6565
shared_libs: list[str] = Field(default_factory=list)
6666
used_packages: dict[str, str | None] = Field(default_factory=dict)
6767
installed_packages: dict[str, str] = Field(default_factory=dict)
68+
python_version: str = ""
69+
python_implementation: str = ""
6870

6971
@computed_field # type: ignore[prop-decorator]
7072
@property

roar/execution/provenance/runtime_collector.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,14 @@ def collect(
195195
"machine": platform.machine(),
196196
},
197197
python={
198-
"version": platform.python_version(),
199-
"implementation": platform.python_implementation(),
198+
# Prefer the traced child's Python (captured via the inject log)
199+
# over roar-cli's host Python — when they differ (cross-Python
200+
# roar run), the host value would misrepresent which Python
201+
# actually ran the user's code.
202+
"version": python_data.python_version or platform.python_version(),
203+
"implementation": (
204+
python_data.python_implementation or platform.python_implementation()
205+
),
200206
},
201207
env_vars=python_data.env_reads,
202208
container=container_info,

roar/execution/runtime/inject/sitecustomize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def _append_roar_runtime_pythonpath() -> None:
5555
f" - Install roar in this Python: pip install roar-cli\n"
5656
f" - Reinstall roar-cli under matching Python:\n"
5757
f" uv tool install --python python{_running_abi[0]}.{_running_abi[1]} "
58-
f"roar-cli --force\n"
58+
f"roar-cli --reinstall\n"
5959
)
6060
_runtime_import_controller.disable_backend_dispatch()
6161
else:

roar/execution/runtime/inject/tracker.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import contextlib
77
import json
88
import os
9+
import platform
910
import sys
1011
from collections.abc import Mapping, MutableMapping, Sequence
1112
from typing import Any, Protocol, cast
@@ -203,6 +204,8 @@ def write_log(self) -> None:
203204
"argv": sys.argv,
204205
"installed_packages": installed_packages,
205206
"used_packages": used_packages,
207+
"python_version": platform.python_version(),
208+
"python_implementation": platform.python_implementation(),
206209
}
207210
with self._real_open(self._log_file, "w") as handle:
208211
json.dump(data, handle)

tests/execution/runtime/test_runtime_tracker.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ def handle_import(self, module_name: str, module) -> None:
3737
assert str(data_path.resolve()) in payload["opened_files"]
3838
assert payload["env_reads"]["VIRTUAL_ENV"] == "/tmp/venv"
3939
assert payload["virtual_env"] == "/tmp/venv"
40+
# Python identity from the *traced* process — consumed by runtime_collector
41+
# to populate job metadata. Critical when roar's host Python and the traced
42+
# Python differ (cross-Python `roar run`).
43+
assert payload["python_version"].count(".") >= 2 # e.g. "3.12.3"
44+
assert payload["python_implementation"] # e.g. "CPython"
4045

4146

4247
def test_runtime_tracker_excludes_roar_runtime_pythonpath_modules(tmp_path) -> None:

0 commit comments

Comments
 (0)