You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Context
`ct record` invokes the Rust-backed `codetracer_python_recorder` CLI
when capturing Python traces. The CLI currently returns the traced
script's process exit code (`codetracer_python_recorder/cli.py:165`).
When the target program exits with a non-zero status—whether via
`SystemExit`, a failed assertion, or an explicit `sys.exit()`—the
recorder propagates that status. The desktop CLI treats any non-zero
exit as a fatal recording failure, so trace uploads and follow-on
automation abort even though the trace artefacts are valid and the
recorder itself completed successfully.
Our recorder already captures the script's exit status in session
metadata (`runtime/tracer/lifecycle.rs:143`) and exposes it through
trace viewers. Downstream consumers that need to assert on the original
program outcome can read that field. However, other integrations (CI
pipelines, `ct record` automations, scripted data collection) rely on
the CLI process exit code to decide whether to continue, and they expect
Codetracer to return `0` when recording succeeded.
We must let callers control whether the recorder propagates the script's
exit status or reports recorder success independently. The default
should favour Codetracer success (exit `0`) to preserve `ct record`
expectations, while still allowing advanced users and direct CLI
invocations to opt back into passthrough semantics.
## Decision
Introduce a recorder exit-code policy with the following behaviour:
1. **Default:** When tracing completes without recorder errors (start,
flush, stop, and write phases succeed and `require_trace` did not
trigger), the CLI exits with status `0` regardless of the traced
script's exit code. The recorder still records the script's status in
trace metadata.
2. **Opt-in passthrough:** Expose a CLI flag `--propagate-script-exit`
and environment override `CODETRACER_PROPAGATE_SCRIPT_EXIT`. When
enabled, the CLI mirrors the traced script's exit code (the current
behaviour). Both configuration surfaces resolve through the recorder
policy layer so other entry points (e.g., embedded integrations) can opt
in.
3. **User feedback:** If passthrough is disabled and the script exits
non-zero, emit a one-line warning on stderr indicating the script's exit
status and how to re-enable propagation.
4. **Recorder failure precedence:** Recorder failures (startup errors,
policy violations such as `--require-trace`, flush/stop exceptions)
continue to exit non-zero irrespective of the propagation setting to
ensure automation can detect recorder malfunction.
This policy applies uniformly to `python -m codetracer_python_recorder`,
`ct record`, and any embedding that drives the same CLI module.
Copy file name to clipboardExpand all lines: README.md
+6-5Lines changed: 6 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,12 +41,13 @@ All subclasses carry the same attributes, so existing handlers can migrate by ca
41
41
42
42
`python -m codetracer_python_recorder` returns:
43
43
44
-
-`0` when tracing and the target script succeed.
45
-
- The script's own exit code when it calls `sys.exit()`.
46
-
-`1` when a `RecorderError` bubbles out of startup or shutdown.
47
-
-`2` when the CLI arguments are incomplete.
44
+
-`0` when the recorder finishes cleanly, even if the traced script exits non-zero. The script's status is still recorded in `trace_metadata.json`, and a warning on stderr highlights the suppressed status.
45
+
-`1` when a `RecorderError` bubbles out of startup or shutdown (policy failures, `require_trace`, flush/stop issues).
46
+
-`2` when the CLI arguments are incomplete or invalid.
48
47
49
-
Pass `--codetracer-json-errors` (or set the policy via `configure_policy(json_errors=True)`) to stream a one-line JSON trailer on stderr. The payload includes `run_id`, `trace_id`, `error_code`, `error_kind`, `message`, and the `context` map so downstream tooling can log failures without scraping text.
48
+
Opt into mirroring the script's exit code with `--propagate-script-exit` (or `CODETRACER_PROPAGATE_SCRIPT_EXIT=true`). Use `--no-propagate-script-exit` to force suppression, even if the environment enables mirroring.
49
+
50
+
Pass `--json-errors` (or set the policy via `configure_policy(json_errors=True)`) to stream a one-line JSON trailer on stderr. The payload includes `run_id`, `trace_id`, `error_code`, `error_kind`, `message`, and the `context` map so downstream tooling can log failures without scraping text.
Copy file name to clipboardExpand all lines: codetracer-python-recorder/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
10
10
11
11
### Changed
12
12
- Module-level call events now prefer the frame's `__name__`, fall back to filter hints, `sys.path`, and package markers, and no longer depend on the legacy resolver/cache. The globals-derived naming flag now defaults to enabled so direct scripts record `<__main__>` while package imports emit `<pkg.mod>`, with CLI and environment overrides available for the legacy resolver.
13
+
- The CLI now exits with `0` when recording succeeds regardless of the traced script’s status, records a warning when suppressing non-zero script exits, and exposes `--propagate-script-exit` / `CODETRACER_PROPAGATE_SCRIPT_EXIT` / `configure_policy(propagate_script_exit=True)` to restore passthrough semantics.
0 commit comments