Skip to content

refactor(work-items): retire Python primary-action instruction selection - #7462

Merged
huangruiteng merged 1 commit into
mainfrom
codex/ts-bridge-retire-20261027
Oct 27, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/ts-bridge-retire-20261027

Conversation

@hhyykk

@hhyykk hhyykk commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Move primary-action instruction selection into the existing typed interaction owner: selectPrimaryActionInstruction in loopx/control_plane/work_items/interaction_contract.ts, composed by projectInteractionExecution inside the existing work_item.interaction_execution.project request. It selects candidate-source precedence (agent lane, due monitors, schedule-metadata repair, capability-runnable count, scoped fallback, advancement Todos, backlog, advancement reason, work-lane text), the exact per-mode instructions, replan-packet fallbacks and child/peer lane counts, and runs actionSelectionNeedsRecovery in process before reading instruction facts so rejected/deferred selections never build an executable instruction.
  • Retire the three Python decision owners in work_items/primary_action.py (protocol_first_candidate_action, protocol_replan_action_packet_instruction, resolve_canonical_primary_action; 347 → 152 lines). Python keeps only protocol_action_text / protocol_action_label as compatibility codecs (Python str/repr, whitespace, ... truncation), protocol_monitor_action, the resolution trace and final JSON serialization, plus the facts/views carrier primary_action_instruction_facts. The carrier transports at most the first selectable coerced row per list source, so the request size no longer depends on backlog/Todo list length; the typed owner applies the same predicates and precedence to whatever arrives.
  • interaction_contract.py::_project_interaction_execution sends primary_action_facts plus the existing action_selection_context packet only when the final contract builder asks for them (include_primary_action=True); mode-only preflight requests and the unadmitted_action_selection result shape are byte-identical to before. No new RPC operation, handler registration, runtime, provider, store or persisted-format change.
  • Vocabulary budget: the moved repair instruction carries the standalone goal_boundary prose token. The retirement-ledger lexical budgets move 30/2 → 29/3 (Python tightened to its measured count; TypeScript increased with evidence: byte-identical relocated prose, cross-language total unchanged at 32, migration surfaces unchanged at 16/1 — no new field reader). Recorded in the bilingual ledger per the budget-failure decision guide.
  • Tests: 182 pre-change cases pinned in tests/control_plane_ts/fixtures/primary_action_instruction_selection.json (all modes, precedence, fallbacks, lane counts, empty/invalid shapes, Unicode/non-BMP, truncation), checked through the bounded codec and the real typed owner against independently pinned instructions; the 22,000-row oversized-backlog lane and rejected-selection recovery cases are pinned against the base outputs with a <16 KiB facts bound; existing CLI/Host adapter assertions retained.
  • Docs: bilingual ledger pair docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.md + .zh-CN.md and both migration RFC checkpoints. Deletion conditions: remove the trace/monitor facade when their consumers adopt a complete typed action/trace projection; remove the scalar/label codecs and facts carrier only after the last Python text/label consumer exits and a typed codec proves coercion/Unicode/truncation/trace parity.
  • Rollback: code-only revert of this single commit; no data migration.

Measured results

Local bench harness, runs interleaved base → head → base → head; 25 timed runs / 3 warm-ups per command, N=1 and N=3 synthetic SQLite fixtures. Each median below is the minimum of that side's two interleaved medians. Crossings are Python→Node logical requests on the real CLI path; latency remains sensitive to host/launcher noise.

Command Fixture Crossings before → after Median ms base → head (min-pair) Stdout bytes before → after
agent-context --phase before_plan N=1 1 → 1 148.52 → 150.33 1885 → 1885
agent-context --phase after_delegate_result N=1 3 → 3 174.47 → 178.64 1612 → 1612
same phase with --turn-instance-id N=1 3 → 3 172.98 → 177.37 2594 → 2594
quota should-run N=1 75 → 75 877.61 → 840.89 25520 → 25520
agent-context --phase before_plan N=3 1 → 1 148.75 → 150.33 2247 → 2247
agent-context --phase after_delegate_result N=3 3 → 3 174.80 → 177.04 1612 → 1612
same phase with --turn-instance-id N=3 3 → 3 174.42 → 176.85 2594 → 2594
quota should-run N=3 75 → 75 883.94 → 852.11 25904 → 25904

Latency deltas stay within the base-1 vs base-2 noise floor (agent-context ≤ +2.6%; quota −4.2% / −3.6%; launcher floor 38.45 → 39.16 ms).

  • Output parity: stdout byte counts are identical on all eight commands in every run; normalized JSON (excluding *_at timestamps, context_id, event_id, staleness_seconds) is equal base vs head. Every emitted instruction literal is byte-equal to the retired Python string. Token consumption (bytes/4 estimate) is unchanged; crossings are unchanged (this slice removes a decision owner, not a request).
  • Production LOC (git diff --numstat origin/main -- loopx/): Python −185 net, TypeScript +109 net, production total −76. git show --stat HEAD: 13 files, 914 insertions / 278 deletions.

Validation

  • npm run typecheck:control-plane: pass. npm run test:control-plane: 5,528 passed / 0 failed / 75 PostgreSQL-isolated skipped (independent validator; Node 26.12.0, i.e. CI's forward-compatibility lane). Focused native tests re-verified on the final head: 37 passed.
  • Python adapters + arbitration + CLI output differential: 309 passed on the fixed head. A 44-module attribution sweep of every referencing/importing module (1,984 tests) on the final head vs base: 84 failed on both sides with byte-identical failing test IDs — zero head-only failures.
  • Independent validator's full pytest -m "not stage2c_e2e" (head, 2:04:46): 908 failed / 27,169 passed / 234 skipped / 8 errors; 916 distinct failing IDs. Base replay of all 147 failing files: 913/916 also fail on base (inherited: canonical-authority fixtures Control-plane tests fail on main when scenario Goals lack canonical authority #7433, scheduler launcher Scheduler native launcher readback tests fail on main with "value must be strict JSON" #7434, quota-bound wait Quota-bound wait recovery test fails on main #7435, project registry Project registry pending-registration tests raise CanonicalAuthorityRequired on main #7436, plus guard-induced local artifacts). The 3 head-only IDs were: the two architecture checks this commit initially failed (goal_boundary lexical budget 3>2 and its downstream retrodiction signal 13/15) — resolved by the registry budget move recorded above, both tests now pass on the final head — and one frontend lifecycle test that only ran because dashboard dependencies were installed into the worktree during validation (skips on base; environment-induced, not a code regression).
  • Premerge canary on the final head (loopx canary premerge --from-git-diff --git-diff-base origin/main): status: passed, ok: true, merge_gate_passed: true, 0 failures, 0 manual holds. Bilingual RFC gate (scripts/check_rfc_bilingual.py --base origin/main --head HEAD): passed.
  • Changed-file ruff, configured mypy, git diff --check, public-boundary scan: clean. Semantic advisory: no new supported vocabulary carriers.
  • CI-only lanes not reproducible locally: PostgreSQL authority (real server), Node 22.22.3 minimum, Windows, browser/chat-bundle jobs. origin/main at the base be1dc37a0 already shows red Python test-shards 3 and 6, browser timeouts and Windows failures (tracked by Control-plane tests fail on main when scenario Goals lack canonical authority #7433–Project registry pending-registration tests raise CanonicalAuthorityRequired on main #7436 and CI: chat-bundle-browser and dashboard-browser shards time out on main #7389); those will appear on this PR as inherited and are not caused by this diff.
  • Residuals (recorded in the ledger): scalar/label codecs, monitor text and resolution trace remain in Python until the deletion conditions above are met; admission, monitor and trace migration are outside this slice. No broader retirement or installed-delivery qualification is claimed.

Select candidate precedence, exact mode instructions, replan fallbacks and
orchestration lane counts in the existing typed interaction execution owner.
Keep Python scalar/label compatibility views, resolution trace and final JSON
serialization; preserve mode-only preflight and lazy selection recovery.

Pin pre-change behavior, retain CLI/Host adapter coverage and record the
bilingual retirement ledger, measured output/crossing parity and validation
holds. No new RPC operation or persisted-format change.

Bound primary-action list facts to the first selectable coerced row per source;
TypeScript retains instruction predicates and source precedence.
Pin 22,000-row backlog lane/recovery parity and all 182 bounded-codec instructions.

Move goal_boundary budgets 30/2 -> 29/3 with RETIREMENT_ANCHOR in the same diff, per the anchor design.
Same-source recount: 32 tokens total, migration surfaces 16/1, byte-identical prose, no new reader, writer or binder.
Both architecture gates green again: 128 passed; retrodiction restored to unchanged baseline 12/15.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Signed-off-by: hhyykk <4408344+hhyykk@users.noreply.github.com>

@loopx-agent loopx-agent 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.

Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max

动机 / Motivation

通过 quota、heartbeat 和既有上下文入口读取下一步工作的 Agent,以及维护这些指令规则的开发者。
原来同一次工作契约先由 TypeScript 选执行模式,再由 Python 选具体指令;本提案在原 typed 请求内同时选择模式和指令,减少后续规则修改时的双处维护。

194组完整production interaction contract在不可变base与精确head逐项相同;wheel/sdist各194组及File/SQLite真实CLI回读通过,原拒绝恢复和只读状态保留。这证明当前切片有真实调用方和功能增量;代码行数减少本身不证明持续运行更便宜。

本切片不完成整个T3/T4、controller统一、实际Host或模型长程采用,不改provider、权限、持久格式或执行费用授权。

改动思路 / Approach

审查完整 head 0331874 的 13 个文件。既有 interaction execution 请求足够承接指令选择,Python 兼容编码与后续恢复保留,没有新增 RPC 或状态 owner。本 PR 只收敛三项指令决定及必要传输;monitor、trace 和更广 T3/T4 留原 owner,当前切换的性能资格仍须补齐。

Python 把原 str/repr、真值、空白、按码点截断和标签视图送入既有 work_item.interaction_execution.project。TypeScript 先选模式并检查原 selection recovery,再产生 primary instruction;Python 原恢复命令、selection/capability gate、blocked-wait 覆盖和 resolution trace 保留。列表只传同语义下首个可选视图,避免把整份 backlog 搬入请求。当前不新增 provider IO、持久 store、配置或用户准备轮次。

具体改动 / Changes

先读的验收依据为 既有迁移 RFC,路径 docs/architecture/rfcs/typescript-control-plane-migration-v0.md,spec revision:be1dc37a008be7017b64b622f653b6707df5c544。

  • Payoff-phase PR contract:确实删除三个 Python choice 函数,复用原 RPC,保留 codec/trace 的实际 caller 和退出条件,是有用且可回滚的迁移切片。
  • Caller-observable semantic parity is a promotion gate:同脚本/同输入的 194 组完整 contract 全等,未归一化任何字段;源输入未变。另有实际 File/SQLite CLI、物理包读回及单条义务 mutation 的独立检错。
  • Correctness:相关原生与 Python 检查、两种实际本地后端、wheel/sdist 深层执行已有正证;20 项旧 fixture 失败完整归因如下,不提升为通过。
  • Performance:本次完整 quota CLI 样本未见物质回退,但原 §6 要求的 cold-start、warm typed request、代表性 transaction/full CLI p50/p95 和 idle/burst daemon memory 尚未完整资格化,判定 not_met。

关键代码讲解

  • primary_action_instruction_facts 保留 Python coercion,按既有 Todo eligibility 生成首个可选视图,不再返回最终指令。182 个 fixture 已逐项读取,并补测有/无当前 lane、22,000 行 foreign/blocked 前缀、末尾合法项及 admitted/rejected/deferred。
  • selectPrimaryActionInstruction 收敛原来源优先序和完整文案,包括当前 lane、到期 monitor、修调度、capability 候选、scoped fallback、Todo、backlog 和最后回退;空 child list 仍优先于 peer lanes。
  • projectInteractionExecution 仅在 final facts 存在且原 selection 不需恢复时选择指令,mode-only preflight 不增字段。拒绝恢复保留原命令及 false 执行/交付标志。
  • _build_interaction_contract_projection 是生产采用点,final 请求开启 primary action,再走原恢复或 agent channel;后续覆盖没有被此次迁移绕过。

生产 Python −185 行、TS +109 行,净 −76;总 diff +948/−278 包含双语 docs、测试和 fixture。保留 Python codec/monitor/trace 有具名消费者,是兼容编码和显示边界。沿原 action_selection_context 收敛而非新建 admission encoder 是合适的伴随整理;更广删除按原退出条件处理。

对主干的风险 / Risks

[P2] 补齐本切换的 §6 性能资格,再声明验证完成。 当前双语 RFC 新增 Validation is complete for this slice,依据是 canary、字节/crossing 和 25 次样本的 median。原有 §6 要求 cold/warm/完整 caller 的 p50/p95 及 idle/burst RSS;median 不能排除尾部或常驻内存问题。该事实 carrier 进入默认 final contract,功能等价和 RPC 数不变仍不能证明完整成本不退化。

本次独立固定 32 对、交错 AB/BA、相同物理 source/interpreter/单行 SQLite fixture 的完整 quota should-run:p50 278.89→277.99 ms,p95 325.09→317.33 ms。该样本未见物质回退;不把 −2.39% 认定为因果提速,也不将 3 次 warmup 当 cold-start 分布。当前仍缺原门中的 cold/warm/RSS 及其余代表 caller 尾延迟资格。最小修复是在同一切片补可重放回执、保留失败和未知,并同步双语完成边界;若测出回退,再在现有 owner 内修复。无需完成无关 parent roadmap 或新增模型实验。

语义与 CI 对齐

goal_boundary 原指令文字逐字迁移造成词法预算 Python/TS 30/2→29/3,总量仍 32,真正 reader/writer surface 16/1 未增。Registry 和 retirement anchor 同步、原义务未缩短,相关 smoke 与双语检查通过;这项有证据的预算调整本身不阻断。当前阻断来自已接受的 Performance 验收缺口,新的 complete 声明不能改写原标准。

独立检查 结果
4 个 TS 模块 PASS:88,零 skip
10 个 Python 模块 177 PASS / 20 FAIL;失败单独归因
Base/head 完整 interaction contract PASS:194,全字段相同,输入未改
Wheel 与 sdist 各 1,767 个产品文件与 source/安装字节一致;各 194 contract 通过,两后端各 5 条 CLI 均 exit 0,记录与 revision 不变
隔离 wheel 的单句语义 mutation 原独立全契约 oracle 正确失败;随后恢复原字节
Typecheck、Ruff、标准 premerge PASS;6 直接 + 19 选中,零 manual hold

20 项失败均在第一个 todo list 因 fixture 未初始化 canonical authority 拒绝;不可变 base 与 head 的 nodeid、exit code、完整诊断及恢复 payload 逐项相同,未进入迁移后的下游,不归为本 PR 新回归。首次 package build 因本地换头后 Chat bundle 陈旧被拒;沿原 build:chat 重建后两种物理包均通过,无 tracked source 改动。历史完整 Python 失败和未运行下游不标绿。本次不查询或等待远端 CI,未把其他 PR 的 PostgreSQL 结果冒作本头资格。

我的整体评价 / Verdict

REQUEST_CHANGES,原因是本切换既有性能资格尚未齐备。功能迁移、真实调用方采用、完整指令/恢复语义和打包均有独立正证,未发现当前语料内的功能差异;保留它们供后续复审复用。长期成本与收益仍未资格化,不能从行数、单次投影或一个 CLI 样本推断。

用户侧现有 CLI 指令和恢复路径保持,没有新增配置或确认轮次。13 文件无渲染组件、页面布局或按钮改动,因此视觉观察不适用;正式 App/Host、Windows、最低 Node、模型理解与持续收益未验。当前变更复用已注册 mode 与原 owner,无新共享持久词汇。补齐当前门后可复审,不以这次结论扩大 merge、安装或执行权限。

English verdict: REQUEST_CHANGES at 0331874. Full-contract parity, real File/SQLite callers and independently installed wheel/sdist pass. The default cutover still lacks the accepted cold/warm/p95 and daemon-memory qualification; median/crossing parity and the passing local canary do not establish completion.

CLI outputs retain equal byte counts and normalized content; crossings remain
1/3/3/75 for both binding counts. No latency improvement is claimed.
The slice moves one `goal_boundary` prose token Python → TypeScript; lexical budgets move 30/2 → 29/3 with migration surfaces unchanged at 16/1, as recorded in the ledger; registry and anchor move together.
Validation is complete for this slice: the final canary reports status:

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.

[P2] 当前完成声明超出了本切换的已验边界。变更前同一RFC §6 Performance明确要求cold-start、warm typed request、transaction/full CLI的p50/p95及idle/burst daemon memory;ledger/PR当前只给25次median、字节和crossing parity。本次独立194完整contract、实际File/SQLite及物理wheel/sdist均通过,32对同条件完整quota CLI p95也未见回退(325.09→317.33ms),但它们仍不回答cold/warm/RSS与其余代表caller尾延迟。请沿原切片补可重放默认SQLite资格回执,保留原失败/未知,并同步中英文完成声明;若测出回退再有界修复,无需扩大到整个parent roadmap或模型实验。

@huangruiteng
huangruiteng merged commit a704725 into main Oct 27, 2026
27 of 40 checks passed
@huangruiteng
huangruiteng deleted the codex/ts-bridge-retire-20261027 branch October 27, 2026 11:29
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.

3 participants