Skip to content

test(extensions): give the entrypoint smoke the repository import bootstrap - #4615

Merged
huangruiteng merged 2 commits into
mainfrom
codex/extension-entrypoint-smoke-bootstrap-20260917
Sep 17, 2026
Merged

huangruiteng merged 2 commits into
mainfrom
codex/extension-entrypoint-smoke-bootstrap-20260917

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

What changed

examples/extension-entrypoint-surface-smoke.py (added by #4509, commit 78c1124ab) imports loopx.extensions.entrypoint_surface at module scope without putting the repository root on sys.path. 204 of the 320 public smoke scripts do that bootstrap; this one does not.

When the public smoke sweep runs a script with an interpreter that has no installed loopx on sys.path — python examples/foo.py puts examples/ on sys.path[0], not the repository root, and the CI job installs nothing for these checks — the check dies before it tests anything:

ModuleNotFoundError: No module named 'loopx'
  examples/extension-entrypoint-surface-smoke.py, line 16

That is the failure recorded in main's two most recent full public smoke runs (35160630605 at 23:04Z and 35164002565 at 23:50Z), which both fail the same nine checks.

Validation

CI-equivalent run, using an interpreter that hides site-packages so the script must find the repository itself:

$ <venv>/python -S examples/extension-entrypoint-surface-smoke.py     # before
ModuleNotFoundError: No module named 'loopx'

$ <venv>/python -S examples/extension-entrypoint-surface-smoke.py     # after
- manifests: 9
- entrypoints: 11
- unresolved: 0
extension-entrypoint-surface-smoke: ok

$ <venv>/python -m ruff check examples/extension-entrypoint-surface-smoke.py
All checks passed!

The ordinary interpreter run is unchanged (extension-entrypoint-surface-smoke: ok). ruff format --check reports one pre-existing hunk in this file on main as well; this change leaves it alone.

Boundary

One public smoke script, six lines: the guard plus a single ROOT definition moved above the guarded import. No product code, runtime, control-plane, permission or scoring behavior changes, and the resolution the smoke performs (9 manifests, 11 entrypoints, 0 unresolved) is the same work it always intended to do.

…tstrap

`examples/extension-entrypoint-surface-smoke.py` imported `loopx.extensions…`
at module scope without adding the repository root to `sys.path`, which 204 of
the 320 public smokes do. When the public smoke sweep runs a smoke with an
interpreter that has no installed `loopx` on `sys.path`, as the CI job does, the
check dies at import with `ModuleNotFoundError: No module named 'loopx'` and has
failed on every `main` run since it landed in #4509.

Reproduced with an interpreter that hides site-packages: `python -S
examples/extension-entrypoint-surface-smoke.py` fails with the same error before
this change and prints `extension-entrypoint-surface-smoke: ok` (9 manifests, 11
entrypoints, 0 unresolved) after it. The script keeps its single `ROOT`
definition and moves it above the guarded import.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

动机

examples/extension-entrypoint-surface-smoke.py(#4509,commit 78c1124)在模块级直接 import loopx.extensions.entrypoint_surface,却没有像 320 个公开 smoke 里另外 204 个那样把仓库根加入 sys.path。python examples/foo.py 只把 examples/ 放进 sys.path[0],CI 的这个任务也不安装 loopx,所以检查在 import 阶段就死掉(ModuleNotFoundError: No module named 'loopx'),自落地以来每一次 main 的 full public smokes 都失败——最近两次 run 35160630605 与 35164002565 都失败在同一批九项。

改动思路

按仓库既有惯例补上 import 引导:把唯一的 ROOT 定义上移到被守卫的 import 之前,sys.path 已包含时不重复插入,import 行标注 # noqa: E402,与其它 smoke 一致。除此之外不改任何断言或解析逻辑。

具体改动

单文件六行:新增 import sys、ROOT 前移与 sys.path 守卫、import 加 noqa;删除原先重复在文件下方的 ROOT 定义。冒烟脚本要解析的 9 个 manifest / 11 个 entrypoint / 0 unresolved 结果不变。

对主干的风险

只影响该公开 smoke 的导入路径。为复现 CI 条件,用隐藏 site-packages 的解释器做 A/B:改动前 python -S examples/extension-entrypoint-surface-smoke.py 报同一条 No module named 'loopx',改动后输出 extension-entrypoint-surface-smoke: ok;普通解释器运行结果不变;ruff check 通过(ruff format --check 的既有 hunk 与本次无关,未触碰)。

我的整体评价

修的是 main 上可复现的公开 smoke 失败,改动最小且不绕过断言,A/B 证据清楚。建议在该 head 的必过检查转绿后合并。

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Head: $HEAD_OID

English verdict: APPROVE

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

动机

examples/extension-entrypoint-surface-smoke.py(#4509,commit 78c1124)在模块级直接 import loopx.extensions.entrypoint_surface,却没有像 320 个公开 smoke 里另外 204 个那样把仓库根加入 sys.path。python examples/foo.py 只把 examples/ 放进 sys.path[0],CI 的这个任务也不安装 loopx,所以检查在 import 阶段就死掉(ModuleNotFoundError: No module named 'loopx'),自落地以来每一次 main 的 full public smokes 都失败——最近两次 run 35160630605 与 35164002565 都失败在同一批九项。

改动思路

按仓库既有惯例补上 import 引导:把唯一的 ROOT 定义上移到被守卫的 import 之前,sys.path 已包含时不重复插入,import 行标注 # noqa: E402,与其它 smoke 一致。除此之外不改任何断言或解析逻辑。

具体改动

单文件六行:新增 import sys、ROOT 前移与 sys.path 守卫、import 加 noqa;删除原先重复在文件下方的 ROOT 定义。冒烟脚本要解析的 9 个 manifest / 11 个 entrypoint / 0 unresolved 结果不变。

对主干的风险

只影响该公开 smoke 的导入路径。为复现 CI 条件,用隐藏 site-packages 的解释器做 A/B:改动前 python -S examples/extension-entrypoint-surface-smoke.py 报同一条 No module named 'loopx',改动后输出 extension-entrypoint-surface-smoke: ok;普通解释器运行结果不变;ruff check 通过(ruff format --check 的既有 hunk 与本次无关,未触碰)。

我的整体评价

修的是 main 上可复现的公开 smoke 失败,改动最小且不绕过断言,A/B 证据清楚。建议在该 head 的必过检查转绿后合并。(本条取代上一条把 head 占位符写错正文的记录。)

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Head: 405135b

English verdict: APPROVE

…point-smoke-bootstrap-20260917

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

动机

examples/extension-entrypoint-surface-smoke.py 在模块级 import loopx.extensions.entrypoint_surface,却没有把仓库根放进 sys.path——320 个 public smoke 脚本里有 204 个都做了这一步,这个漏了。当 sweep 用一个没有安装 loopx 的解释器跑它时(python examples/foo.py 把 examples/ 而不是仓库根放在 sys.path[0],而 CI 对这些检查不安装任何东西),脚本在断言任何东西之前就死在 ModuleNotFoundError: No module named 'loopx'。main 最近两次 full public smoke 记录的正是这个失败。

改动思路

补上那一步 bootstrap:脚本自己把仓库根放到 sys.path 上,从而能在 CI 那种“什么都没安装”的解释器下先 import 成功再断言。不改任何断言,也不改被检查的入口面契约。

具体改动

  • examples/extension-entrypoint-surface-smoke.py:新增仓库根 sys.path bootstrap(其余断言与输出不变)。

对主干的风险

风险面很窄:只加 import 前的一步路径设置,不改检查内容。关键证据是解释器层面的 A/B——用 python -S(隐藏 site-packages,等价于 CI 那种没有安装 loopx 的解释器)跑同一个脚本:改动前 ModuleNotFoundError: No module named 'loopx',改动后打印 9 manifests / 11 entrypoints / 0 unresolved 并 ok。

本次复审在更新后的 head 上复跑同一 A/B(该 head 只是把 origin/main 合进来,唯一被评审文件在旧 head 与新 head 之间逐字节一致,已用内容哈希核对):

  • uv run --extra test python examples/extension-entrypoint-surface-smoke.py → unresolved: 0, extension-entrypoint-surface-smoke: ok
  • uv run --extra test python -S examples/extension-entrypoint-surface-smoke.py → 同样 ok

我的整体评价

这类“脚本在 CI 解释器下连 import 都过不去”的失败会让整条 public smoke 链看起来在拦别的 PR,补 bootstrap 是把失败收回到它自己该在的位置。建议在该 head 的必过检查全绿的前提下合并。

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Head: b49abe4

English verdict: APPROVE

@huangruiteng
huangruiteng merged commit e66ba69 into main Sep 17, 2026
23 checks passed
@huangruiteng
huangruiteng deleted the codex/extension-entrypoint-smoke-bootstrap-20260917 branch September 17, 2026 06:12
huangruiteng added a commit that referenced this pull request Sep 17, 2026
A confirmed team plan can be applied partially: the settlement staffs the
lanes the host can run and reports the rest as gaps. Nothing could then finish
it. `apply` returned the stored proposal for any applied plan, so a lane that
was missing for a reason the host later resolved stayed missing until the owner
confirmed a whole new plan.

A partial application now records what it still owes -- the digest of the
confirmed plan and the lanes it left unstaffed -- and a re-entrant apply of that
same proposal completes the plan instead of replaying an empty success: the
settlement re-reads the host's staffing facts, every committed lane keeps its
Todo, and only the lanes that are staffable now become work. The outcome
becomes team_plan_applied once no lane is left, and the receipt keeps the lanes
it recovered. The apply entry point, the settlement call and the receipt builder
are shared with the first apply, so one plan cannot have two settlements.

A recovery refuses before writing anything when the host can no longer staff a
lane the plan already committed, records that refusal on the plan, and never
turns an apply that already happened into a failure. What it deliberately does
not gate is Goal-level intent drift: the repository has no typed intent identity
(shared_goal_alignment says so), and both facts that could stand in for one move
on the apply's own writes, so the plan itself -- the commitment the owner
confirmed -- is what a recovery proves it is completing.

The team-plan settlement, its receipt and its recovery live in
loopx/chat_team_plan_actions.py, beside the monitor, Todo and lifecycle action
mixins, so the router module does not grow past its reviewed module metric
ceiling for work that is not routing.

Validation: 46 focused Python tests, including the recovery, a no-progress
replay, the committed-lane refusal and the unchanged behaviour of a fully
applied plan; loopx canary premerge --from-git-diff passes with 0 failures
(maintainability ratchet, vocabulary drift, 4 catalog canaries, public boundary).
Rebase reconciliation (2026-09-17, onto main after #4587 and #4615 landed):
main had added the typed lane-write failure path in `_apply_team_plan` while this
branch moved that method into the team-plan action mixin, so the two changes
collided in one place. The resolution keeps both behaviours: the mixin now
forwards `lane_failure` from the settlement and `_apply_team_plan` records the
retry-safe `team_plan_lane_write_failed` failure with the identities it did
create, while the F4 recovery cursor stays on the partial-application path.
The test file keeps main's two lane-failure cases and this branch's recovery
cases side by side; this branch's second-lane helper is renamed to
`_unstaffed_second_lane_plan` because main already owns the name
`_two_lane_plan` for the both-lanes-staffed plan.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
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.

1 participant