Skip to content

fix(runtime): discover Python interpreters without fixed minor lists - #4482

Merged
huangruiteng merged 4 commits into
loopx-project:mainfrom
songoow:codex/python-development-entrypoints
Sep 16, 2026
Merged

huangruiteng merged 4 commits into
loopx-project:mainfrom
songoow:codex/python-development-entrypoints

Conversation

@songoow

@songoow songoow commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Installed Python discovery previously depended on hand-maintained minor-version lists. A supported interpreter exposed only under a name outside those lists could be missed. The POSIX launcher and DSH plugin now discover installed python3.<minor> names and retain their existing compatibility probes and explicit-configuration precedence.

Changes

  • POSIX launcher: keep explicit LOOPX_PYTHON, the installer record, and the project environment ahead of discovery; discover versioned names on PATH and in existing user/Homebrew fallback directories, in descending numeric order.
  • DSH plugin: keep explicit PYTHON_BIN authoritative and the implicit python3 first; discover the remaining names on the supplied PATH. Installation still validates Python >=3.11 and pip; reopening still validates the managed LoopX CLI.
  • Reuse the plugin discovery owner in the real integration suite instead of copying another version list.
  • Keep the earlier developer entrypoint changes in this PR: uv-based source instructions, endpoint commands, Dashboard recovery text and generic installer help. Related feat(pr-review): add bounded semantic triage and repair guidance #4459 covers contributor/test guides and semantic RFC/generator repair commands.

The discovery behavior now admits compatible installed names absent from the old list. POSIX selection and DSH installation still reject invalid explicit interpreters. Managed-runtime readback keeps its existing CLI fallback behavior. No Python downloads, automatic installation side effects, global Python mutation, or uv runtime dependency are added. CI versions, supported-version declarations, and concrete compatibility fixtures remain intentional.

Validation

  • Regression-first POSIX tests reproduced the old failure for an unlisted minor name.
  • Focused Python discovery/Dashboard/install tests: 60 passed. After syncing main to edcddc7aa, the expanded Python set including Chat baseline tests passes 126 tests.
  • DSH plugin tests: 187 passed, including the real LoopX admission/closeout integration suite.
  • DSH plugin TypeScript checks and packaged build: passed.
  • Packaged managed-launcher probe: a synthetic unlisted executable name forwards to the real supported Python and invokes this checkout's LoopX successfully. This tests name discovery, not a claim about an unreleased Python version.
  • Semantic inventory check, Ruff and shell syntax checks: passed.
  • Premerge canary before the final main sync: 19 selected checks passed, 0 failures, 0 manual holds, including installer/update and plugin quality/package/runtime phases. After the sync, the 126 Python tests, 187 plugin tests and inventory check were revalidated.

The production entrypoints are the existing installation/development launcher and DSH managed-runtime resolver. No frontend view or settings field changes are needed; the affected command help and both runtime documents are updated. The bounded refactor removes repeated version lists while keeping each distribution's existing selection precedence. No model benchmark or release publication was performed.

Base-sync validation repair

The newly merged test_a_channel_without_a_session_reads_as_unbound assumed the optional DSH runtime was installed. It failed both here and on unmodified main edcddc7aa in the same environment (dsh_runtime_unavailable). A separate test-only commit pins the existing runtime-availability probe to the test's declared ready-endpoint premise; the original assertions and production behavior are unchanged. This makes the unbound-session assertion independent of locally installed optional hosts.

中文摘要

此前的开发命令调整没有覆盖运行时写死的小版本候选列表。本次将 POSIX 启动器和 DSH 插件改为发现已安装的版本化解释器,再执行原有兼容性校验;集成测试复用生产发现逻辑。显式配置优先级、最低 Python 要求及插件安装时的 pip 校验保留,不增加 uv 运行时依赖。60 项定向 Python 测试、187 项插件测试、类型检查、构建及真实打包入口探针通过。同步主干后扩展验证为 126 项 Python 测试通过;其中一个主干测试的环境依赖已用独立测试提交修复,未改生产逻辑。

@songoow songoow changed the title docs(development): finish version-neutral Python entrypoints fix(runtime): discover Python interpreters without fixed minor lists Sep 16, 2026
@songoow

songoow commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator Author

Coordination readback: the current author head is db58562bf8db078504006f02af6f8a10f3863849, which already contains main edcddc7aa and is MERGEABLE.

The maintenance pass observed concurrent author updates and preserved them. A separate local candidate combining the earlier cd4cb4db7 implementation with that main passed 60 Python discovery/Dashboard/install tests, 20 semantic tests and 35 focused DSH discovery/init/admission tests. This is evidence for that candidate, not a claim that the newer author head was revalidated locally. The newer author head supersedes the redundant maintenance push; no force push or edits to the author's working tree were used.

The previous CI failures were in change-window and chat-context tests; both focused cases pass on a clean edcddc7aa baseline locally, and the latest author commit additionally isolates the chat fixture from installed runtime state. New-head CI remains the qualification source.

Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
Signed-off-by: song <liusongstep@gmail.com>
@songoow
songoow force-pushed the codex/python-development-entrypoints branch from db58562 to 2164327 Compare September 16, 2026 03:03
…pment-entrypoints

Signed-off-by: song <liusongstep@gmail.com>
@songoow
songoow force-pushed the codex/python-development-entrypoints branch from 54044df to 5545d17 Compare September 16, 2026 04:27

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

动机

解释器发现以前依赖人工维护的 minor 版本清单:POSIX 启动器里写着 python3.13/3.12/3.11,DSH 插件里冻结了 PYTHON_CANDIDATES = [python3, python3.14, 3.13, 3.12, 3.11]。这带来一种安静但会周期性复发的失败:当某台机器上可用的受支持解释器不是这几个名字(例如只有 python3.15,或者名字被改过),启动器会一路走到最后的 python3,而那个可能是 3.10 甚至更旧,于是表现为"环境明明有 Python 却起不来"。每加一个新 Python 版本都得同时改两处清单,属于典型的会把维护成本滚大的知识复制。

改动思路

作者把"名字清单"换成"发现 + 探测":两个 surface 各自枚举 python3.<minor> 形式的名字,但对每个候选都保留原有的兼容性探测(脚本里是 python_version_ok,插件侧是版本 + pip 探测),并且显式配置的优先级一点没动——LOOPX_PYTHON、.loopx-python 记录、PYTHON_BIN、仓库 .venv 仍然排在发现之前。脚本侧按 minor 数值降序排列(sort -t. -k2,2nr,避免 python3.14 在字典序上输给 python3.9),并用 case 过滤掉非纯数字后缀,python3.12-config、python3.12.1、同名目录都不会被当成解释器。插件侧同样过滤非目录项后按 minor 降序返回,但保留 python3 在最前。另外,之前集成测试里那份"另一份版本清单"被删除,改成直接复用插件自己的发现 owner,这是这次改动里最值得肯定的去重。

具体改动

  • scripts/loopx-python.sh:新增 versioned_python_names(枚举 → 过滤 → 数值降序 → 去重),select_loopx_python 的顺序变成"显式配置/记录/.venv → PATH 上的版本化名字 → python3 → ~/.local/bin、Homebrew、/usr/local/bin 兜底目录",每个候选都要过 python_version_ok。
  • packages/dsh-loopx-plugin/src/managed-runtime.ts:删除 PYTHON_CANDIDATES,pluginPythonCandidates 改为"显式 PYTHON_BIN 优先;否则 python3 打头 + 按 minor 降序的发现结果",读取 PATH 不可用的目录直接跳过。
  • 测试:tests/test_python_discovery.py(新增 7 项)、packages/dsh-loopx-plugin/tests/python-discovery.spec.ts(2 项),并把 admission-closeout.integration.spec.ts 改为复用插件发现 owner。
  • 文档:AGENTS.md 新增 Source-Checkout Python Entry Points(建议 uv run --extra test、检查 sys.executable 与 loopx.__file__),以及 dashboard/personal-workspace 文档、scripts/dashboard-dev.sh 与安装脚本 help 文本的相应措辞。

关键代码讲解

  • scripts/loopx-python.sh:24 versioned_python_names:核心过滤在 case "${minor}" in ''|*[!0-9]*) continue,配合 [ -x ] && [ ! -d ],确保只有可执行的纯 python3.<数字> 参与排序;sort -t. -k2,2nr | uniq 完成数值降序与跨目录去重。
  • scripts/loopx-python.sh:74 起的 select_loopx_python:显式来源之后先扫 PATH 目录(把 PATH 按 : 拆开、空段按 . 处理,与 PATH 语义一致),再退回 python3,最后扫 ~/.local/bin、/opt/homebrew/bin、/usr/local/bin——旧代码里那些路径仍然在,只是从"硬编码名字"变成"发现名字"。
  • packages/dsh-loopx-plugin/src/managed-runtime.ts:28 pluginPythonCandidates:/^python3\.(\d+)(?:\.exe)?$/i 匹配、!entry.isDirectory() 过滤、minorB - minorA || nameA.localeCompare(nameB) 排序,返回 ['python3', ...发现结果];读取失败静默跳过,实际有效性仍由调用方的版本/pip 探测决定。
  • 去重证据:admission-closeout.integration.spec.ts 不再内嵌版本列表,而是调用插件的发现 owner;head 上 grep 只在新的单测期望里还能看到具体 minor。

对主干的风险

我把能跑的都跑了:pytest -q tests/test_python_discovery.py 7 项通过;插件侧 vitest run tests/python-discovery.spec.ts 2 项通过;admission-closeout.integration.spec.ts + init-command.spec.ts 33 项通过(46s)。行为面上,显式配置的优先级、3.11 下限、以及"每个候选必须探测"这三条约束都没被削弱,发现本身是只读的一次 glob/readdir,没有新增状态、协议字段或 CLI 选项,回滚也只是恢复两份清单。

一条非阻塞 P3:两个 surface 的发现顺序不一致。启动器现在是"先版本化名字、后 python3",插件是"先 python3、后版本化名字",PR 描述里也是分开说明的。在 python3 落在较旧(但受支持)minor 的机器上,两个 surface 可能选到不同解释器——都由 3.11 探测兜底,所以不会选出不可用环境,但一旦某个运行期问题只在其中一个解释器上复现,这个差异会让复现路径变模糊。建议在一处文档里写清两个 surface 各自的有意顺序,并在两个套件里补一条共同的顺序期望,而不是各自只断言自己那一侧。另外,我没有在"只暴露非常见受支持 minor 名"的真实机器上做过安装,这一项保持 unverified;集成与单测覆盖了代码路径。

我的整体评价

结论是 APPROVE。这是一次典型的"删掉知识复制而不是延长它"的改动:两处人工 minor 清单换成发现 + 原有探测,且在改动过程中把集成测试里的第三份清单也去掉了,净效果是以后新增 Python 版本不再需要同时改多处。优先级、下限与探测这些真正决定正确性的约束都原样保留,测试覆盖也随改动一起补齐并全部通过。唯一值得跟进的是两个 surface 的排序策略不同——它是有意的(插件要保持 python3 隐式优先以不改变既有安装行为),但目前只散落在 PR 描述与各自实现里,建议集中说明以免将来被当成 bug 修掉。没有发现阻塞项。

English verdict: APPROVE — exact head 5545d1747aa07e1e31b9481a0bd16745600c620a of #4482. The change replaces two hand-maintained minor-version lists with name discovery plus the existing probes, and it removes a third copy of the same knowledge from admission-closeout.integration.spec.ts by reusing the plugin's discovery owner. Explicit precedence is untouched on both surfaces (LOOPX_PYTHON, the .loopx-python record, the repository .venv, and PYTHON_BIN all stay ahead of discovery), the 3.11 floor and per-candidate probing are preserved, and the shell filter rejects python3.12-config/python3.12.1/directories while ordering by numeric minor so python3.14 is not lexically ranked behind python3.9. Validation at this head: tests/test_python_discovery.py 7 passed, packages/dsh-loopx-plugin/tests/python-discovery.spec.ts 2 passed, and admission-closeout.integration.spec.ts plus init-command.spec.ts 33 passed in 46s. One non-blocking P3: the launcher prefers versioned names before python3 while the plugin keeps python3 first, so the two surfaces can pick different (both supported) interpreters on the same machine — document that intended order in one place and add a shared ordering expectation to both suites. Unverified: no install was executed on a machine that exposes only an unusual supported minor name, since this environment has the usual names; the unit and integration suites cover the code paths. No protocol, state, quota or authority surface changes.

@huangruiteng
huangruiteng merged commit dd584fa into loopx-project:main Sep 16, 2026
23 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants