Repository navigation
Conversation
The run index is written with ensure_ascii=False, so an interrupted append
can end in a partial UTF-8 sequence. load_index_snapshot decoded every line
with a strict bytes.decode("utf-8"), so one such row raised UnicodeDecodeError
from every reader of that index: history/status collection, the Todo and
refresh-state readers, and the append-side readback of
write_compact_runtime_projection. The append helpers already repair a missing
row delimiter after a torn tail, so new records kept being written behind the
damaged row while nothing could read the index again.
Count an undecodable row as an invalid row (raw_count and invalid_count), the
same way an unparseable JSON row is already handled, and keep reading the
rest of the index. The digest still covers the original bytes.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: duang777 <duangjl007@gmail.com>
Duang777
requested review from
huangruiteng,
loopx-agent and
songoow
as code owners
November 13, 2026 09:45
This branch has not been deployed
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.
Goal And Delivered Outcome
load_index_snapshotinloopx/history.pydecoded each run-index line with a strictbytes.decode("utf-8"), but the index is written withensure_ascii=False, so an interrupted append can end inside a multibyte character. The append helpers already repair the missing newline after a torn tail, so later rows keep landing behind the damaged one.UnicodeDecodeErrorfrom every reader of that index: history and status collection, the Todo and refresh-state readers and the readback inwrite_compact_runtime_projection. After: the row is counted inraw_count/invalid_countlike an unparseable JSON row and the intact rows are returned; the digest still covers the original bytes. Rows:regression_parity,unit.mainat7bb1b01.Author Declaration
Implemented against
load_index_snapshotinloopx/history.pytests/control_plane/test_run_index_jsonl_framing.py::test_history_read_skips_a_row_torn_inside_a_multibyte_characterslot_accounting._load_goal_run_index_recordsand dropped it: the real settlement readback already fails closed there.Scope And Continuation
Validation
e2202a3eef43004fc8aeb2cf06bdfe5d61c5f77ffor the diff; local runs used a working tree whose touched files were blob-identical tomain7bb1b01before the change (the touchedhistory.pyhunk was re-applied to the currentmainfile; the replaced line is unchanged upstream).regression_paritypassedUnicodeDecodeErrorand passes with the fix;write_compact_runtime_projectionalso stops crashing.unitpassedtest_run_index_jsonl_framing.py18/18;ruff checkclean on both touched files.unitfailedloopx.chat_event_cache); not re-run onmain.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
N/A
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).none.Signed-off-bytrailer (git commit -s).🤖 Generated with Claude Code