Repository navigation
fix(extensions): transport the isolated presentation view validator payload as UTF-8 bytes - #6230
Open
JasonBuildAI wants to merge 1 commit into
Open
JasonBuildAI wants to merge 1 commit into
JasonBuildAI wants to merge 1 commit into
Conversation
…-8 bytes `load_presentation_view_validator` launches the extension-declared helper as `python -I -c <helper>` inside the extension's runtime interpreter. `-I` ignores `PYTHONIOENCODING`/`PYTHONUTF8`, so the helper's `sys.stdin` and `sys.stdout` fall back to the host locale codec while the transport owner writes the request as UTF-8 bytes and decodes the response as UTF-8. On a zh-CN Windows host (cp936) a view with non-ASCII text decodes into mojibake with lone surrogates; the parent then raises `UnicodeDecodeError` when the surrogates are re-encoded, or `UnicodeEncodeError` in the envelope hash and persisted projection when the response survives. Decode and encode the JSON payload explicitly as UTF-8 bytes in the generated helper and document the isolation contract. Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
JasonBuildAI
requested review from
huangruiteng and
loopx-agent
as code owners
October 11, 2026 10:50
JasonBuildAI
added a commit
to JasonBuildAI/loopx
that referenced
this pull request
Oct 11, 2026
JasonBuildAI
commented
Oct 11, 2026
JasonBuildAI
left a comment
Contributor
Author
There was a problem hiding this comment.
Independent review record (commissioned by the author)
An independent reviewing agent re-verified this PR from the issue, the diff and its own reproduction on a genuinely affected cp936 host, without relying on the author's summary. Reviewed head: 7535bcef8 (unchanged since).
Six-question verdict:
- Value — real, reproducible. The pre-fix failure is deterministic and has no user-side workaround (
-IdropsPYTHONIOENCODING/PYTHONUTF8). The affected path is shipped production code (validate_provider_presentation_projection->_runtime_presentation_view_validator, used by publish, status readback and doctor/readiness), so any extension view with non-ASCII text fails on any non-UTF-8-locale host (Windows cp936/cp932/cp949/cp125x). Circumscribed to non-UTF-8 hosts; UTF-8 hosts are unaffected before and after. - Single problem — yes. 3 files, +118/-2: the generated helper transport, one documentation paragraph, one test file. No drive-bys; the semantic-vocabulary probe reports no new vocabulary carriers.
- Logic and edge cases — no defect found.
-Iis the actual launch flag; the byte contract is symmetric (request encoded UTF-8 by the parent, response encoded UTF-8 by the helper, decoded UTF-8 by the parent). Empty stdin, non-UTF-8 stdin and lone-surrogate responses behave as before or better; no missing flush (verified end-to-end). - Over-abstraction — none. Two lines in the generated script plus a comment; the in-process stdio pin cannot be used inside the isolated interpreter (no
PYTHONPATH), so local byte handling is the right scope. - Tests — genuine. Test 1 executes the real helper source against forced cp936 streams; it fails on the unmodified base even under
-X utf8, so it is a portable guard, not a host artifact. Test 2 runs the realpython -Ichild through the production transport and failed on base with the reported error. The limitation that test 2 alone would pass pre-fix on UTF-8 hosts is disclosed in the PR body. - Local checks — reproduced on both heads. New file: 2 passed on head / 2 failed on unmodified base.
tests/test_cli_stdio_utf8.py+tests/extensions/test_extension_provider_stdio_utf8.py: 6 passed. CI lint scope ruff: clean. Fulltests/extensionshead vs base: failure node-id sets identical (350F/1018P/63S/80E vs 350F/1016P/63S/80E; the +2 passes are the new tests). Validator-adjacent files: 69F/82P/5S on both, failure ids identical (Windowsentrypoint_missingenvironment issues).
Must fix: none. Non-blocking notes: the new test file has no trailing newline (ruff/CI do not flag it); the simulated stdout uses errors="strict" where a real cp936 child uses surrogateescape (immaterial, because the fixed helper bypasses the text layer entirely). Out-of-scope observation for future contract work: a validator that itself prints to sys.stdout corrupts the JSON response both before and after this change, unchanged in kind.
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
loopx/extensions/presentation.py::_ISOLATED_VIEW_VALIDATOR...-IignoresPYTHONIOENCODING, so their fix has to live inside the script").load_presentation_view_validator({"view_validator": "builtins:str"})({"headline": "中文标题,带标点。"})raisesValueError: ... returned invalid output(UnicodeDecodeErroron the parent decode); after, the same call returns the view string and the new regression tests pass (rowregression_parity+unit).main@adb247e5f.Author Declaration
Implemented against
docs/reference/extensions.mdupdated by this PR at head7535bcef8.python -Ihelper must read its request as UTF-8 bytes regardless of host locale (#6228 expected)loopx/extensions/presentation.py::_ISOLATED_VIEW_VALIDATORtests/extensions/test_isolated_view_validator_utf8.py::test_generated_helper_transports_utf8_bytes_behind_locale_streamsinvoke_runtime_validatormust be UTF-8, with no mojibake or lone surrogates (#6228 actual)tests/extensions/test_isolated_view_validator_utf8.py::test_isolated_validator_round_trips_non_ascii_view_in_runtimepython -IignoresPYTHONIOENCODING/PYTHONUTF8; payload crosses stdio as UTF-8 bytes)docs/reference/extensions.md(extension runtime boundary section)_RESOLVE_DECLARED_MODULE_ORIGIN, the other successor named by #6168, is unaffectedloopx/extensions/readiness.pyjson.dumpdefault (ensure_ascii=True), so its output is ASCII-only and locale-safetests/extensionssuite on base and head and compared failure identities; ran the canary premerge catalog on the diff and re-ran every failing check on the clean base; read the transport owner (run_capped_processcall, request encode, response decode) and the readiness helper before writing the issue. Left out: non-Windows non-UTF-8 locales (e.g.LANG=Con Linux) and the CI-only workflows.Scope And Continuation
Validation
unitpassedtests/extensions/test_isolated_view_validator_utf8.py(2 tests). Before, on unmodified baseadb247e5f: 2 failed (UnicodeDecodeError: 'utf-8' codec can't decode bytes ... invalid continuation byte;ValueError: presentation surface view_validatorbuiltins:strreturned invalid output). After: 2 passed.regression_paritypassedtests/extensionshead vs unmodified baseadb247e5f: identical failure/error identity sets (268 unique), head350 failed, 1018 passed, 63 skipped, 80 errorsvs base350 failed, 1016 passed, 63 skipped, 80 errors; the +2 passed are the new tests. The pre-existing failures are Windows-environment issues (shebang fixtures, missing npm dev dependencies) that fail identically on the base.staticpassedruff check tests loopx/canary loopx/control_plane loopx/domain_packs loopx/presentation(CI lint scope) and the canary directgit diff --checkchecks.real_entrypointpassedloopx canary premerge --from-git-diff --git-diff-base upstream/mainon head: 11 checks selected, public boundary passed; the 7 failing checks (semantic-vocabulary-drift,cli-project-lifecycle-command-modularization, 5content-ops-*smokes) fail identically when re-run on the unmodified base worktree for environment reasons (repository npm dev dependencies not installed; host Node 22.2.0 < required 22.22.3).integrationpassedtests/test_cli_stdio_utf8.py(3 tests) still passes, exercising the adjacent stdio-pinning contract.python -Ichild throughload_presentation_view_validator, so it fails on a cp936 host without the fix and passes with it. Not exercised locally: non-Windows non-UTF-8 locales and CI-only workflows. The envelope-hash/projection write path is covered indirectly (the response equality assertion catches surrogate-corrupted views).Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).none.Signed-off-bytrailer (git commit -s).