Skip to content

[Bug]: shipped-runtime UTF-8 guard fails on main - the stride schema asset is read with the host locale codec #6352

Closed

Description

@JasonBuildAI

Preflight

  • I searched existing issues and discussions for this behavior.

  • This report is not an unpatched security vulnerability.

  • The report and attachments contain no credentials or private/internal material.

  • Issue origin: Observed or reproduced in a real environment

  • LoopX version or commit: 64bfb8343 (current main; offender introduced by 7a315eff2, PR feat(replan): add versioned structured stride policy and decision feedback #6298)

  • Host or runtime surface: Not host-specific (reproduced on native Windows; the guard is platform-independent)

  • LoopX area: Control plane (goals, todos, quota, scheduler, registry, runtime)

Impact

tests/test_loopx_text_io_utf8.py::test_shipped_runtime_pins_utf8_for_every_text_file_read_and_write fails on current main, deterministically on every OS. That guard pins the class from #4338 / #4941 / #4942 / #4997: every shipped-runtime text read or write must pin UTF-8 instead of the host locale codec, so a non-UTF-8 host (for example zh-CN Windows, cp936) cannot mis-decode structured LoopX data.

The site it now reports is on the CLI configuration read path. stride_strategy_options() / normalize_stride_strategy() are called from loopx/capabilities/configuration_ui.py, loopx/cli_commands/registry_admin_configure.py, loopx/execution_profile.py, and loopx/capabilities/todo_replan_cadence/machine_defaults.py, so the packaged schema is decoded with the host locale codec on such hosts. The asset is ASCII-only today, so the mis-decode is currently silent; as soon as any non-ASCII character enters that shared schema, those hosts either raise UnicodeDecodeError or silently mis-decode, and the guard that exists to prevent exactly this is failing on main instead of protecting it.

Minimal reproduction

Check out main at 64bfb8343 and run:

uv run --extra test python -m pytest -q tests/test_loopx_text_io_utf8.py

Raw result:

F.
================================== FAILURES ===================================
______ test_shipped_runtime_pins_utf8_for_every_text_file_read_and_write ______

    def test_shipped_runtime_pins_utf8_for_every_text_file_read_and_write() -> None:
        """A text read or write without an explicit codec reopens the #4941 failure."""

>       assert _text_io_calls_without_utf8_encoding() == []
E       AssertionError: assert ['loopx\\cont..._codec.py:16'] == []
E         Left contains one more item: 'loopx\\control_plane\\work_items\\stride_policy_codec.py:16'
E         Use -v to get more diff

tests\test_loopx_text_io_utf8.py:130: AssertionError
=========================== short test summary info ============================
FAILED tests/test_loopx_text_io_utf8.py::test_shipped_runtime_pins_utf8_for_every_text_file_read_and_write
1 failed, 1 passed in 23.60s

The offending call (loopx/control_plane/work_items/stride_policy_codec.py:16):

contract = json.loads(files("loopx.control_plane").joinpath("stride_strategy_schema.json").read_text())

Why this class matters (same host, cp936)

locale.getpreferredencoding(False) = cp936
raw_utf8_bytes_ascii = b'{"title": "\xe7\xad\x96\xe7\x95\xa5 \xf0\x9f\x98\x80"}'
read_text() no encoding roundtrip_equal = False        # host locale codec, silent mojibake
read_text_utf8_roundtrip_equal = True

Expected behavior

The guard passes: the shipped-runtime read pins encoding="utf-8".

Actual behavior

The guard fails and reports the stride schema read, which decodes with the host locale codec.

Additional context

Activity

  1. JasonBuildAI commented on Oct 13, 2026

    @JasonBuildAI
    ContributorAuthor

    Resolved on main by 156eee4c9 ("fix(control-plane): reuse frontier counters and pin resource UTF-8", landed with the #6318 merge ca01854f4), which pins encoding="utf-8" on the same read_text() call.

    Verified against b0b2acffb: uv run --extra test python -m pytest -q tests/test_loopx_text_io_utf8.py -> 2 passed. Closing as fixed; the PR I had prepared for this (#6353) is closed as redundant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions