Repository navigation
fix(llc): resolve the run transcript from the adapter state file (#13614) - #14755
Merged
Merged
Conversation
Contributor
✅ SSOT Configuration Compliance: Passing🎉 No hardcoded values detected that have SSOT config equivalents! |
Applied Black, isort, and autoflake to match code-quality checks. Triggered by workflow auto-fix-formatting.yml.
This was referenced Aug 22, 2026
…it (#13614) The fallback recomputed the transcript path from the returned run id `<pid>/<session>`, but an adapter must name that file before spawning the child — it is the child's stdout — so the name always carries the placeholder `0/<session>`. A live process cannot have pid 0, so the fallback named a file no run has ever written and missed every time, in exactly the case it exists to cover: a missing or unreadable state file. The placeholder was being rebuilt by hand in four adapters, which is what let the two derivations drift apart. It now has one definition in subprocess_base and every adapter imports it, with a guard test so it cannot regrow. An ImportError of the path helpers is a wiring fault, not an absent transcript; the caller cannot tell those apart from a None, so it is logged. Copilot adapters use a different filename scheme and stay unresolved; that pre-existing gap is filed as #14760 and referenced from the docstring.
Applied Black, isort, and autoflake to match code-quality checks. Triggered by workflow auto-fix-formatting.yml.
…ites (#13614) test_uses_exact_output_path_from_external_run_id wrote its transcript at the path derived from the returned run id `<pid>/<session>`. No adapter has ever written there — the file is named before the child exists, so it always carries the placeholder `0/<session>`. The test was passing on a shape no producer emits, which is the same derivation #13614 is about. Its guarantee — resolve one file outright, never a glob or an mtime ordering — is worth keeping, so it now builds the path through the adapter's own helpers and keeps the later-mtime decoy.
This was referenced Aug 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #13614.
Thinking Path
A
claude_coderun executed real work end to end — 5 turns, real tool calls,is_error: false— and its 37 KB transcript sat on disk whilellc_run_replay_logs.output_textstayed empty andrecorded_eventsNULL.Two places derive the same path from different inputs:
The placeholder is not an oversight that can simply be corrected: the file is
the child's stdout, so it must be created before
Popen, and the pid doesnot exist until after. Any fix that keeps two derivations has to keep them in
step forever.
The adapter already records the truth. Its state file — written after spawn,
keyed by the id it returns — carries the real
output_file. So the fix is toread it and delete the second derivation entirely.
What Changed
heartbeat_scheduler.pygains_resolve_adapter_output_file, which reads theadapter's state file for the returned run id and takes
output_filefrom it.It falls back to the computed path when the state file is missing or unreadable
— runs predating the state file still resolve as well as they used to, and the
caller already reports a missing transcript rather than silently recording an
empty one.
Verification
Reproduced the defect and the fix against a stand-in that mirrors the adapter
exactly — placeholder-named file, pid-bearing returned id, state file written:
A regression test drives
_record_run_for_replayitself, with the filenamed by the placeholder and a state file keyed by the returned id. It asserts
up front that the computed path does not exist — otherwise the test would
pass through the fallback and prove nothing — then asserts the transcript is
attached and
recorded_eventsis non-empty.The existing H1 test still passes, through the fallback: it creates the file
at the computed path with no state file, which is now the fallback's exact
case. So both paths are covered, and the older behaviour is preserved rather
than replaced.
Not addressed
The
0/placeholder remains in the adapter. Renaming the file post-spawn wouldremove the oddity but adds a failure mode (a rename that half-completes) to a
path that currently cannot lose data. The state file is the contract; this makes
the recorder use it.
Model Used
Claude Opus 5