Skip to content

fix(heartbeat): share automation-first Goal execution contract - #4201

Merged
huangruiteng merged 30 commits into
mainfrom
codex/native-goal-prompt-contract
Sep 11, 2026
Merged

huangruiteng merged 30 commits into
mainfrom
codex/native-goal-prompt-contract

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Share automation-aligned live dispatch across Goal hosts without freezing a second refresh/spend recipe. Preserve static authority/privacy and conditional repair routing; remove ambiguous project-branch bans and executor-facing prompt-maintenance advice.
  • Bind unbound native work through the current TS interaction/settlement contract. Todo acceptance is distinct from Turn settlement; an empty Todo list does not prove terminal vision closure.
  • New supported Goal activations store a stable CLI bootstrap; Claude loads its bound inner rules through MCP host_prompt. Explicit caller policy is retained, registry-derived state is refreshed, and loaders cannot recursively load themselves or pin one persistent Turn id.
  • loopx update --apply captures old-template evidence and invokes prompt reconciliation in the new runtime. Exact managed prompts can migrate automatically; custom/ambiguous/foreign-home or canary bindings remain review-only. Qualified macOS heartbeat stores support prompt-only SQLite/TOML migration while the App remains running, with revision checks, a writer lock, private journals and readback.
  • Add opt-in release Goal runners and deterministic host, upgrade and recovery regressions. Live model invocation is not part of ordinary tests or PR CI.

Deliberate behavior changes and boundaries

The default remains thin. Static safety and the executable standalone Turn assignment justify explicit thin/compact ceilings of 2,500/6,500 characters; the output differential has a bounded one-time safety transition, not a permanent growth allowance. Selection, claim, vision replan and settlement authority remain in current contracts, not the saved prompt.

Brief now shares the fully qualified notification/execution rule with thin and follows current settlement steps rather than an independent static refresh/spend recipe. Its 3,500-character ceiling is unchanged; real App preflight and registry-derived scopes are retained.

The running-App writer is a qualified local compatibility adapter, not an official Codex storage API. SQLite and TOML are not one atomic transaction: detected external edits or crashes retain a recovery journal, and pending tasks are reported separately from binary installation success. Scheduler kind, thread, status, schedule, model, notifications and history are not rewritten. Unverified cron/heartbeat mappings remain rejected. Existing native Goal objectives are not imported or rewritten between homes. TraeX retains its separate capability projection. Existing MCP processes must restart after a runtime upgrade.

Validation

  • Tested revision: 1beb54ef04fa0a8dbb3168901312d2e8b3281eaf. Final follow-up: 252 Python tests passed without skips, full heartbeat-prompt smoke, real long-path absolute budget and base/head differential passed; local DCO checks all 30 PR-range commits. Updated main is integrated without dropping contributor ancestry. Earlier broader evidence below retains its original scope.
  • Run state: running (hosted checks); local runs below finished.
  • Input classes: synthetic, public_fixture, authorized_private_read_only (aggregate App budget checks only). All 12 registered local profiles fit the brief App budget, maximum 3,472/3,500 characters. The separately authorized earlier prompt-migration canary was a bounded host-store mutation, not a read-only fixture run.
Check kind Result Public-safe evidence / limitation
real_entrypoint passed CLI bootstrap reload, bound stdio MCP, upgrade reconciliation and install smoke; deterministic, no model call.
real_backend passed Isolated SQLite/TOML, independent connection, lock/race/failure/recovery coverage.
manual passed One running macOS App heartbeat: direct prompt migration and delayed dual-store readback; not universal cache or model compliance evidence.
regression_parity passed CLI base/head output differential, negative changed-safety control; quota budgets unchanged.
integration running Hosted final-head checks; no pass inferred from earlier revisions.
integration passed Doubao evolving: 16/16 independent thin/brief decision probes; synthetic work/wait/replan scenarios, not host execution or full-Goal evidence. Release-only opt-in; no default CI calls.
integration failed Prior Claude/Doubao full-Goal closeout timed out; separate from passing decision probes, follow-up #4208.
  • Executed: 195 focused Python tests passed, one native-Windows update test skipped on macOS; 50 additional MCP completion/settlement, terminal and host-runtime regressions passed.
  • Executed: 38 TypeScript interaction/Turn/host completion/replan settlement tests passed.
  • Executed: real saved-loader CLI and stdio MCP paths, SQLite secondary-reader and writer-contention tests, crash/mirror-recovery injection, stale/custom/foreign-input rejection, and new-runtime CLI reconciliation. Package replacement is substituted in the focused lifecycle test; no model is invoked there.
  • Executed: one owner-authorized running-App canary migrated through the real CLI store adapter. Immediate readback changed only the prompt in both stores; delayed readback across a scheduler interval retained the new prompt and preserved metadata. Scheduler advancement was observed separately. No active Goal/Todo/lease data or unrelated automation was mutated; raw evidence remains private.
  • Passed: heartbeat prompt/error, Claude lifecycle/hook-policy and installation smokes; rebased CLI output budget regression, 66 focused loader/migration/runner tests, 40 output differential tests, focused Ruff and diff hygiene. Hosted final-head results are tracked in the follow-up comment rather than assumed passed.
  • Not claimed: full-Goal live-model release qualification, universal scheduler/cache compatibility, or a fully qualified native /loop timer. The prior Claude/Doubao whole-Goal timeout remains a failure; vision recovery is tracked separately in fix(host): recover vision settlement and preserve scoped replanning #4208. New prompt-decision probes do not replace it.

Contributor follow-up

Refined #4216 on @Green-hats' original fork branch and merged it into this PR, retaining original contributor commits and the merged PR record. Its child-environment isolation and install-smoke corrections remain, with an additional one-bootstrap-load assertion. The integration merge now carries DCO sign-off without dropping contributor ancestry. No blanket cron-to-heartbeat conversion or everyday credential import was adopted.

Review judgment

The owner is the existing heartbeat/host-update boundary, not a new capability. The companion refactor consolidates stable bootstrap rendering and update-time adoption evidence while leaving scheduling and typed work/settlement ownership intact. Public fixtures use synthetic identities; private automation plans, journals, prompts, sessions and model credentials are excluded.

Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng
huangruiteng marked this pull request as draft September 10, 2026 15:40
Signed-off-by: huangruiteng <huangrt01@163.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.

Request changes conclusion (author-owned PR; GitHub blocks formal self-review)

复审绑定 exact head:5605159a76f79dac455fcf9bf1f4cc77afe0610a。

动机

这组改动要解决的核心问题是真实的:native Goal 不应在持久 prompt 里复制一份会过期的 refresh/spend 配方,而应先取得稳定的 Turn identity,再消费当前 interaction_contract 和 typed settlement plan。Todo acceptance 与 Turn settlement 分离、失败后按同一 identity 恢复,也都是正确方向。

关于这次暴露出的 turn-instance-id 摩擦,需要把两件事分开:当前 Codex App heartbeat prompt 已经明确写了 LOOPX_TURN=<current_time_iso>; reuse,quota guard 也已经带 --turn-instance-id。我此前第一次执行仍漏传,是代理遵循 prompt 的失误,不是 #4201 缺少这条说明。#4201 真正修复的是另一条路径:codex_cli / managed native Goal 没有 App 外部注入的 Turn id;base 会直接暴露未绑定的 refresh/spend,head 会先投影带稳定占位符的 quota re-entry。这个 exact-head 行为我用真实 CLI fixture 验证通过。

改动思路

整体架构方向成立:quota 继续拥有 selection、Turn re-entry 和 settlement 顺序;host prompt 只负责长期不变量;MCP 负责 validate/complete/writeback/spend 的同一事务,并用 receipt readback 做 lost-response recovery。successor_todo_ids 复用现有 Todo 语义,没有引入第二套状态机。

不过,“移走会变化的命令”不能连同静态安全边界一起移走;“新增 v2 wrapper”也必须在真实 Codex automation 存储形态上可采用;release-only live runner 则必须把模型子进程限制在最小环境授权内。当前 head 在这三处还没有闭环。

具体改动

确认有效的部分:

  • native Goal 首次 quota read 在缺少 Turn identity 时,只返回一次 re-entry;重入后 identity 绑定为当前 Goal/agent/Todo/Turn,并投影 validation -> durable_writeback -> quota_spend -> terminal_closeout。
  • Goal Mode MCP 先验证并接受 Todo,再完成 writeback/spend;丢失 lifecycle、writeback 或 spend 响应后,同一意图重试不会重复扣 quota。
  • release runner 默认不开模型;独立 ledger oracle、成功 transaction 校验和 timeout 清理均有覆盖。

需要修复的阻塞项:

  1. [P1] native Goal prompt 丢失静态安全与修复路由。 loopx/control_plane/heartbeat/task_body.py:550-576 把动态 settlement 配方移出后,也移除了 credential、destructive git、unauthorized production、repo rules,以及 lifecycle/registry 与 projection drift 的 owner 路由。相同输入下,base 有这些约束,head 没有;我又读取了 head 的真实 quota packet,动态 contract 也没有补回。Continue allowed work within authority 不是这些具体边界的语义等价替代。请只把 volatile selection/settlement 移到 interaction_contract,保留静态 safety/routing,并增加 base/head semantic-ledger + live quota packet 回归。

  2. [P1] v2 prompt upgrade 无法作用于当前受支持的 Codex heartbeat。 loopx/control_plane/heartbeat/automation_upgrade.py:158-179 要求 manifest 与 SQLite backing row 的 kind 都逐字等于 heartbeat。真实 Codex App heartbeat 的逻辑 manifest 是 heartbeat,底层 scheduler row 是 cron;只读 automation-prompts plan 因而直接返回 only existing heartbeat automations are supported,连 desired_prompt 都生成不了。也就是说,这个 PR 虽提供了 v2 wrapper,当前 thin-trial automation 仍无法 preview/adopt,用户感知到的摩擦仍在。请把“逻辑 heartbeat -> backing cron”建模为经过验证的 host mapping,同时继续拒绝真正的 standalone cron;用真实 schema 形状补回归。

  3. [P1] release-live runner 把无关宿主凭据与过宽能力带进模型子进程。 scripts/qualify-claude-goal-release.py:65-80 复制几乎全部 os.environ,映射 provider key 后仍保留原始 ARK_API_KEY 和任意无关 token;随后又给 Claude Bash。scripts/qualify-native-goal-release.py:164-168 还显式使用 shell_environment_policy.inherit="all"、完整环境和 network。使用纯合成 sentinel 的安全探针已确认原始 source key 与无关 secret 都会进入 child;未读取或输出真实凭据。请改成严格 allowlist,映射后删除 raw source key,隔离 HOME/config/runtime,去掉 inherit="all",并用 negative sentinel tests 证明无关 TOKEN/AUTH/SOCK 不会下传。

对主干的风险

这三个问题都会在“单元测试全绿”的情况下穿过:prompt 测试当前甚至显式断言旧修复路由不存在;upgrade 测试只构造 heartbeat/heartbeat,而非真实 heartbeat/cron;runner 测试只排除了 Anthropic/Claude 前缀,没有排除任意宿主秘密。前两项会让实际 automation 仍然摩擦或以更弱边界运行,第三项涉及 live model child 的 credential/authority 扩散。

此外,GitHub 上 21 项检查成功,但 SonarCloud Code Analysis 仍失败(new-code coverage 6.9%,security rating C)。我的三个阻塞项都由独立本地反例复现,不依赖 Sonar 推断。

我的整体评价

结论是 REQUEST CHANGES。我完整阅读了 31 个文件、+1287/-215 的 patch,并在该 exact head 上跑过 prompt、quota、MCP、host、release-runner 相关测试:231 passed;Ruff 与 git diff --check 通过。没有运行付费/真实模型调用。

这不是要推翻该 PR 的架构:Turn-id re-entry 和 typed settlement owner 复用是正确且已验证的。范围虽然大,但四个 commit 仍围绕同一 host-contract/release-qualification 原因,修复上述三个相邻边界即可在当前 PR 内保持可审阅;不需要再引入新的通用框架。修复后请用新 exact head 重新跑:静态 prompt/动态 packet 语义对照、真实 automation plan、child-env negative sentinel,以及现有 231 项回归。

English verdict: REQUEST_CHANGES — the native Turn re-entry and typed settlement design are sound, but static safety semantics, real Codex heartbeat adoption, and live-runner credential isolation must be fixed on a new exact head.

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

Request changes conclusion (author-owned PR; GitHub blocks formal self-review)

复审绑定 exact head:5605159a76f79dac455fcf9bf1f4cc77afe0610a。

动机

这个 PR 解决的主问题成立:native Goal 不应长期保存一份会随控制面演进而过期的 refresh/spend 配方,而应进入当前 interaction_contract,让 quota 继续拥有 selection、Turn re-entry、settlement 顺序和 receipt recovery。Todo acceptance 与 Turn settlement 分离、MCP 复用既有 successor,以及 release-only 真实 host 回归,方向也都合理。

但我需要更正上一次评审里对 Turn ID 摩擦的判断。我之前说“prompt 已明确给出 LOOPX_TURN=<current_time_iso>,第一次漏传主要是 agent 执行失误”,这不够准确。信息虽然存在,却没有形成可直接执行且被真实 shell 回归约束的 bootstrap;这正是 capability/host contract 应该吸收、而不是继续交给模型临场拼装的摩擦。

改动思路

整体架构仍应保留:heartbeat envelope 提供本次 current_time_iso,quota 把它绑定成 exact Turn identity,并在成功 re-entry 后投影完整的 settlement_plan.ordered_steps;host prompt 只保留一条可靠入口和不会随控制面漂移的安全边界。Codex App heartbeat、native Goal 与 Claude /loop 可以共享这套 decision owner,但不能混同 scheduler ownership、host completion 或 child-process authority。

当前 exact head 已正确修复 native Codex CLI/Ark 的 unbound settlement:先返回一个 --turn-instance-id re-entry,绑定后才暴露 validation → writeback → spend → terminal closeout。问题是当前 Codex App thin path仍停在“给模型一段半结构化 shell recipe”,同时另三个已确认的边界问题也仍存在。

具体改动

关键代码讲解

  1. visible_goal_turn_reentry_action 把 native Goal 的无 Turn 状态从“错误地暴露 refresh/spend”改成一次 typed re-entry;真实 CLI fixture 证明绑定后 Goal/Agent/Todo/Turn 与 settlement 顺序正确,这是本 PR 的核心正向价值。
  2. GoalModeMCPControlPlane.complete_task 新增 successor_todo_ids,复用现有 Todo 关系;普通 Todo 可先被验证/接受,MCP 再按同一 identity 完成 writeback/spend,lost response 走 receipt readback,而不是重复记账。
  3. _render_goal_task_body 删除静态 refresh/spend 是正确的,但同时删掉了 credentials、destructive git、unauthorized production、repo rules,以及 loopx-project / loopx-self-repair 路由;这些不是动态 quota contract 的重复知识。
  4. automation_upgrade._read 能识别 v1/v2 wrapper 文本,但仍要求 manifest 和 backing row 的 kind 都等于 heartbeat;当前受支持的 Codex 形态是逻辑 manifest=heartbeat、scheduler row=cron,所以 v2 连 preview 都进不去。
  5. host_environment 与 native release runner 的 inherit="all" 把真实 host 环境带给 Bash/network-capable model child;合成 sentinel 已证明 raw source key 和无关 token 都会下传。

新增的 Turn ID 阻塞项是:render_thin_heartbeat_task_body 在 base 与 head 都输出 LOOPX_TURN=<current_time_iso>; reuse.,下一行 guard 再读取 ${LOOPX_TURN:?}。如果 agent 很自然地合并成 LOOPX_TURN=<iso> loopx ... "${LOOPX_TURN:?}",zsh 会在 command-prefix assignment 生效前展开参数,稳定退出 LOOPX_TURN: parameter not set。先独立赋值再执行才成功。现有测试只断言两个字符串存在,因此 81 个 focused tests 全绿也捕获不了这个真实失败。

对主干的风险

当前有四个 P1 阻塞:

  1. thin heartbeat 的 Turn bootstrap 仍不可直接执行。 首次 quota guard 可能在 LoopX 收到请求前失败,无 guard receipt、无 typed recovery,心跳会白跑。最小修复是生成明确的两步赋值/导出,或直接把 trigger ISO 作为 literal 绑定;测试必须替换固定 ISO 后在支持的 shell 中真正执行,并用 command-prefix mutation 证明会失败。
  2. native Goal 丢失静态安全/修复路由。 只迁移 volatile selection/settlement,不应迁移或删除 repo/user authority 与 credential/destructive-operation 边界;需要 base/head semantic ledger 加真实 quota packet 对照。
  3. v2 upgrade 不支持真实 heartbeat→cron backing mapping。 应显式建模这一 host mapping,同时继续拒绝真正 standalone cron;fixture 不能再只造 heartbeat/heartbeat。
  4. release-live child 环境授权过宽。 改为严格 allowlist,映射 provider key 后删除 raw source key,隔离 HOME/config/runtime,移除 inherit="all";用 TOKEN/AUTH/SOCK 合成负例验证。

此外 exact head 当前落后于 main;GitHub 21 项检查成功,但 SonarCloud Code Analysis 仍失败。我的验证包括:81 个 prompt/upgrade/native-release/Claude/MCP focused tests 通过,Ruff 与 git diff --check 通过;base/head prompt 对照、真实 zsh 反例、真实 supported automation kind mapping 和合成 child-env sentinel 均复现上述问题。没有运行付费模型。

我的整体评价

结论仍是 REQUEST CHANGES,并新增 Turn bootstrap 这一独立阻塞。我不是否定 automation-first / typed settlement 的架构;相反,native Goal re-entry 与 acceptance/settlement 分离已经证明有价值。问题在于当前 PR 宣称共享 thin automation dispatch,却仍把最先发生、最容易阻断整个 contract 的 Turn 绑定留给模型自行正确拼 shell。

这四项都属于本 PR 已触及的最近 owner:task body、automation adapter、release runner;可在现有范围内修复,不需要再加新框架。修复后请用新 exact head 重新跑四类 mutation-sensitive 证据:Turn recipe 真执行、静态 safety ledger、heartbeat/cron upgrade、child env allowlist,然后再复审整个 PR。

English verdict: REQUEST_CHANGES — exact head 5605159a76f79dac455fcf9bf1f4cc77afe0610a has a sound typed re-entry/settlement direction, but the thin App Turn bootstrap is still shell-fragile, and static safety, real heartbeat adoption, and release-child credential isolation remain blocking.

@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Re-evaluated the findings against both the automation baseline and the native Goal path. A local refinement is prepared; it has not been pushed yet, so this is not a resolution claim for the current head.

  1. Static safety and repair routing: agree. The automation path already retained these semantics. Native Goal thinning should remove stale command recipes, not repository rules, privacy/credential boundaries or conditional lifecycle/projection repair routes. The refinement shares the static rule across the relevant hosts; Claude retains MCP execution rather than acquiring a second CLI accounting path. A blocked operation gates only its affected path, not independent authorized work or the whole Goal. Selection, claims, vision replan and ordered settlement remain owned by the current interaction contract.

  2. Project-branch wording: remove, not paraphrase. No project branches can be read as prohibiting Git branches and PR delivery. Prompt-author maintenance advice also does not belong in every executor iteration. Neither is restored. Actual Git/worktree/PR requirements remain user/repository policy.

  3. Turn shell bootstrap: agree. Render assignment and guard as separate statements in one shell. Real Bash and zsh tests execute the emitted block against the isolated CLI; the command-prefix mutation fails before entering LoopX, as reported. The complete guard is retained rather than abbreviated. Thin/compact ceilings are explicitly adjusted to 2,500/6,500 characters to accommodate the boundary and executable bootstrap.

  4. Heartbeat/cron storage mapping: do not broaden offline authority on this evidence. The observed legacy shape also lacks the SQLite thread binding; it is not merely a differently spelled kind. Without a verified host mapping, accepting it would infer ownership from one store. The refinement supplies an actionable App-reconciliation error and tests that this shape cannot offer or apply an offline replacement. Consistently bound heartbeats retain update/recovery/rollback coverage. Native API reconciliation is required before adopting inconsistent stores; no scheduler kind or thread is rewritten by this adapter.

  5. Release-runner environment: agree. Use allowlisted child environments and isolated HOME/config/cache. Claude maps only the selected provider credential instead of forwarding the original ARK key and unrelated secrets. Codex uses an explicit isolated API profile, imports no everyday auth/config/session files, and supplies tool shells a non-secret environment with inheritance disabled. This intentionally changes the live-runner setup requirement. It is not a claim that Claude Bash is an OS-level credential sandbox.

Validation of the local follow-up: 274 focused Python tests passed; final overlapping prompt/host and runner-isolation reruns passed 138 and 23 tests respectively; 60 TypeScript interaction/settlement tests passed; full heartbeat-prompt smoke and diff hygiene passed. Coverage includes real CLI guards, real SQLite migration/recovery, real stdio MCP, Bash/zsh mutation controls, subprocess environment sentinels and a no-model real Codex configuration/features probe. No live-model qualification was claimed or performed for this refinement. No active Goal, automation or installed runtime was changed.

Product/architecture judgment: preserve static authority while keeping changing execution decisions in the live contract. The related refactor consolidates safety/repair text and removes duplicated or ambiguous instructions; it adds no new capability, provider or permission. The separate vision-closeout qualification remains necessary before claiming release readiness.

Signed-off-by: Green hats <183933879+Green-hats@users.noreply.github.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng
huangruiteng force-pushed the codex/native-goal-prompt-contract branch from 5605159 to 258d380 Compare September 11, 2026 03:12
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

The refinement described above is now pushed as 258d380f59501453a87cd722bb904ad3eac54c29, rebased onto main 3b12a1a7524f47d8e9d02f1044bd33741c9238a5.

The static-semantics review exposed a real regression: native Goal still needs authority/privacy safeguards and conditional lifecycle/repair routing. These now share the automation rules, without restoring ambiguous project-branch bans, executor-facing prompt-maintenance advice, or duplicate static refresh/spend recipes. Independent work must remain admitted by the current contract; this does not authorize bypassing a global gate.

The shell bootstrap now uses separate assignment and guarded-command statements with stable retry identity. Release runners isolate configuration and allowlist child environments. I did not accept blanket heartbeat/cron equivalence: inconsistent stores still require App reconciliation rather than inferred thread binding or scheduler conversion.

Validation on the rebased head: 274 Python tests passed, 60 TS tests passed without skips, full heartbeat-prompt smoke, focused Ruff and diff hygiene. Coverage includes real CLI re-entry/settlement, SQLite adoption/recovery, stdio MCP, Bash/zsh guard execution, response-loss handling and child-environment sentinels. Every commit has DCO sign-off. No active Goal, automation, installed runtime or credentials were modified.

Architecture judgment: consolidate invariant safety and current-contract dispatch, while preserving host-specific scheduling and settlement ownership. Todo acceptance and Turn settlement remain distinct; neither an empty Todo list nor a successful spend proves terminal vision closure.

Ready for renewed review, not merged or release-qualified. Hosted checks must rerun on this head. No new live-model run was performed; the prior Claude/Doubao whole-Goal timeout remains a failure, with vision recovery tracked separately in #4208. The updated PR body retains these limitations.

Signed-off-by: Green hats <183933879+Green-hats@users.noreply.github.com>
Signed-off-by: Green hats <183933879+Green-hats@users.noreply.github.com>
huangruiteng and others added 7 commits September 11, 2026 11:52
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Co-authored-by: Green hats <183933879+Green-hats@users.noreply.github.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
…rades

Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@BigDataDZ

Copy link
Copy Markdown
Contributor

The blocking Qualify agent-facing CLI output failure is reproducible: thin/brief/compact heartbeat prompt variants exceed the base/head output-growth budgets by up to 501 characters.

I opened #4219 as a stacked fix against this branch. It compresses duplicate static prompt wording without raising the global allowances, while retaining the complete quota guard, separate LOOPX_TURN assignment, exact scheduler action, notification/execution distinction, safety boundary, and repair routes.

Validation on #4201 head 258d380f5 plus #4219:

  • CLI output budget regression smoke: passed
  • heartbeat/Goal prompt suites: 96 passed
  • standard risk-based premerge: 12/12 selected checks passed, no manual holds
  • changed-file contract/public-boundary check: clean

Once #4219 is merged into this branch, the previously failed Python workflow should be rerun. This branch is also behind current main, so update it before final review.

@huangruiteng
huangruiteng force-pushed the codex/native-goal-prompt-contract branch from 258d380 to 55c0e0e Compare September 11, 2026 03:52
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Update pushed: 08f597a39 (based on main 60b77406f).

The update command now captures old-generator evidence before installation and invokes reconciliation through the upgraded runtime afterward (including the owning pip/pipx interpreter, not an unrelated PATH executable). Exact managed prompts may migrate automatically. Custom policy, mismatched bindings, unverified cron rows and unsupported hosts remain explicit per-task follow-up items.

The qualified macOS adapter was exercised on one owner-authorized heartbeat with the App running, through the real CLI sync path. Immediate SQLite/TOML readback changed only the prompt; delayed readback across a scheduler interval retained the new prompt. Scheduling progress was independently visible and configuration/binding remained unchanged. This validates the selected host/version, not every App cache implementation or the agent's eventual compliance. No raw host records, identities, prompts or backups are published.

Ordinary regression evidence: 195 focused Python tests passed (one native-Windows test skipped on macOS), 50 additional completion/settlement/host regressions passed, 38 TS interaction/settlement tests passed. After rebase, 66 loader/migration/runner tests passed; the final pip/pipx follow-up has 35 migration tests passing. The safety-transition differential has 40 passing tests and the actual base/head CLI budget smoke passes. Heartbeat prompt/error, Claude lifecycle/hook-policy, onboarding activation and installation smokes pass. Ruff and diff hygiene pass. All commits are signed off; #4216's remaining tests retain contributor attribution.

Failure coverage includes SQLite writer contention through mirror delivery, rollback after mirror failure, explicit journal recovery, concurrent manifest changes, changed snapshots, custom prompts and foreign homes. SQLite and TOML are not one atomic transaction; detected conflicts retain recovery evidence rather than reporting success. Recovery remains an explicit operation with the App closed.

Hosted checks are still running/queued on this final head; this is not a merge or all-green claim. Sonar's advisory report is not being represented as resolved, and the prior live Claude/Doubao full-Goal timeout remains a release-qualification failure tracked in #4208. This iteration adds no default paid model calls and does not waive vision replan or settlement authority.

…rap loading

Signed-off-by: huangruiteng <huangrt01@163.com>
huangruiteng added a commit that referenced this pull request Sep 11, 2026
test(hosts): align qualification regressions with updated #4201

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

Request changes conclusion (author-owned PR; GitHub blocks formal self-review)

复审绑定 exact head:e8a5867ae1f0f25642c9954ff5509d344d8f9d10。

动机

这个 PR 解决的是我在 thin automation 上真实遇到的摩擦:第一次执行 quota guard 时,我并不是不知道需要一个 Turn identity,而是不知道应该怎样把 prompt 里的 LOOPX_TURN=<current_time_iso>; reuse 可靠地变成可执行 shell。若自然地写成命令前缀赋值再在同一命令中展开 ${LOOPX_TURN:?},zsh 会在赋值生效前展开参数并直接失败,LoopX 根本收不到请求。

因此,这不是一句“记得传 Turn id”就足够的问题。host contract 应直接给出可执行、可测试的两步 bootstrap,并明确同一 Turn 在 guard、writeback 和 spend 中复用。当前 head 已经把这个摩擦吸收到 capability,而不是继续要求模型临场拼装。

改动思路

架构方向正确:heartbeat envelope 提供当前 ISO;prompt 先独立赋值/导出 LOOPX_TURN,再执行带参数守卫的 quota guard;quota 与 TypeScript effect runtime 继续拥有 selection、Turn 绑定、settlement 顺序和 receipt recovery。静态 authority/privacy/repair 规则留在 host prompt,易变的执行步骤由最新 interaction_contract 投影。

我也更正了此前的一个判断:我一度用旧的 .codex 存储形态推断当前 App heartbeat 是 heartbeat→cron。当前会话实际归属 .codex-gpt,是 thread-bound heartbeat/heartbeat;PR 对缺 thread 的 legacy cron 形态 fail closed 是合理的。现有 v1 automation 不会被静默改写,仍需显式采用 v2。

具体改动

关键代码讲解

  • render_thin_heartbeat_task_body 现在输出真正的两条 shell 语句。Bash/zsh 正向执行通过,命令前缀 mutation 稳定失败,直接覆盖了我最初的 Turn-id 摩擦。
  • native Goal 在缺 Turn 时先投影一次 re-entry,绑定后才暴露 validation → durable writeback → quota spend → terminal closeout;Todo acceptance 与 Turn settlement 不再互相循环依赖。
  • v2 wrapper 只对完整、绑定一致的 store 提供 adoption;unsupported legacy shape 交回 App reconciliation,不猜 scheduler/thread authority。
  • release runner 使用隔离 profile 和 allowlist child environment;pip 与 pipx 更新后通过实际升级的 interpreter 执行 prompt reconciliation,不再回落到旧 PATH binary。
  • 原先约 500 字符的 base/head output differential 已用精确的 none -> host_prompt_static_safety_v1 一次性语义迁移处理:仅限 heartbeat thin/brief/compact 对应行,受 512 chars、640 bytes、5 lines 和 512 compact payload 约束;v1 -> v1、marker mutation 与非 heartbeat 行仍拒绝,绝对上限继续独立生效。

当前 exact head 仍有一个需要修复的合并阻塞:

  1. [P1] 绝对 brief-output 门禁仍会失败,并且当前 merge commit 缺 DCO。 在同一 Python 3.11 环境中,tests/control_plane/test_cli_output_budget.py::test_explicit_compact_and_detail_modes_are_characterized 在该 head 连续两次输出 10634 字符,超过 heartbeat_prompt_brief/json 的 10500 上限;切到当前 origin/main 后同一测试通过。这说明一次性 differential allowance 是有边界的,但最终 exact head 仍未满足另一条独立的绝对预算。GitHub DCO 同时明确指出 merge commit e8a5867... 缺少 Signed-off-by。请在新 exact head 上恢复 DCO,并让长临时路径下的 absolute variant characterization 与 differential 同时通过,不要用更宽的全局豁免掩盖。

对主干的风险

Turn bootstrap、静态安全、真实 wrapper adoption、child-env 隔离和 pipx reconciliation 的核心语义已经闭环;我没有发现需要推翻现有 ownership 的新架构问题。剩余风险很具体:当前 head 仍能在正常本机测试路径触发 recurring prompt 的绝对预算失败,而且提交历史不满足仓库 DCO。Release Artifacts 的 403 发生在 artifact finalize,我把它视为独立基础设施问题,没有借此扩大代码结论。

验证证据包括:此前完整 exact head 上 286 个 focused Python、61 个 TypeScript settlement/effect 测试通过;当前 head 新增 qualification assertion 后,fresh output/qualification 批次为 73 passed、1 failed,失败可重复且 main 对照通过;changed file Ruff 与 git diff --check 通过。没有运行付费/真实模型,whole-Goal live qualification 仍是发布 hold。

我的整体评价

结论是 REQUEST CHANGES,但这次结论与最初四个语义问题不同:两步 Turn bootstrap 已经准确修复了“我一开始不知道怎样传 Turn id”的 capability 摩擦;automation-first / typed settlement 设计也成立。现在只需在最近 owner 内修正 absolute brief-output qualification 和 DCO,不需要再引入新框架。修复后请用新 exact head 重跑长路径 absolute variant、base/head differential、DCO 与最终 merge gate。

未来向前看,我认为当前的一次性语义迁移归因已经把预算例外限制在最小边界;不应再抽象出通用 exception framework。v1→v2 adoption 继续保持显式,且未授权任何 scheduler、permission 或 paid-model 行为。

English verdict: REQUEST_CHANGES — exact head e8a5867ae1f0f25642c9954ff5509d344d8f9d10 correctly fixes the executable Turn-ID bootstrap and the earlier host-contract friction, but it still fails the absolute brief-output ceiling on a reproducible path and contains an unsigned merge commit.

test(hosts): align qualification regressions with updated #4201

Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng
huangruiteng force-pushed the codex/native-goal-prompt-contract branch from e8a5867 to b572baf Compare September 11, 2026 04:47
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Addressed the latest exact-head review in b572baf3817c005edde04e507168d0c73c2ece74.

  1. Absolute brief budget: fixed without widening a ceiling or differential exception. Brief explanatory wording is compressed and default policy text reuses the existing compact policy renderer; custom policy is retained. Complete commands, the standalone Turn assignment/guard, static safety, repair routing, notification/execution distinction and recovery obligations remain. The normal variant matrix now uses the same stable fixture-root convention as the other budget cases; a separate real 128-character absolute-root regression exercises JSON and Markdown without shortening rendered paths. The old renderer fails that same fixture at 10,810 characters against the unchanged 10,500 JSON ceiling; the new renderer passes. The long-path regression also runs in the budget canary.

  2. DCO: fixed. Amended only the unsigned integration merge to add the maintainer's sign-off, preserving both parents and all original contributor commits. The guarded force-with-lease used the previously reviewed head; no contributor history was squashed. All 27 PR-range commits pass the local DCO check.

  3. Additional hosted failure: fixed. The Ark host test still assumed the profile argument ended the command. It now parses arguments and checks the correct profile plus exactly one --bootstrap, preserving the one-Goal/no-automation assertions.

  4. Correction to the review's v1-adoption statement: update-time migration is automatic for exact owned managed v1 wrappers; it does not require per-task v2 approval. automation-prompts plan is intentionally read-only, whereas loopx update --apply snapshots old-template evidence and invokes reconciliation through the upgraded runtime. These must not be conflated. Renamed the misleading read-only test and clarified the product documentation. Expanded the actual new-CLI/real SQLite-TOML upgrade test across pip and pipx: managed v1 becomes v2, custom prompt remains untouched, and every non-prompt row/manifest field plus session history is preserved. Package replacement is substituted in this deterministic test; reconciliation is not mocked. Existing running-App, race, failure, recovery and foreign-binding tests also pass. The earlier owner-authorized running-App canary remains bounded evidence, not universal host compatibility.

Validation on the final diff: 158 Python tests passed, no skips, full heartbeat-prompt smoke passed, real CLI absolute-budget and base/head differential smoke passed, changed-file Ruff and diff hygiene passed. The old-renderer negative control fails as expected. No model calls, active host-store writes or runtime installation were performed for this follow-up.

Architecture judgment: a bounded renderer/qualification correction, not new execution authority. The automatic migration contract was already implemented; this follow-up makes its end-to-end evidence and documentation unambiguous. No scheduler/thread/permission migration is inferred for customized or inconsistent stores. Hosted checks must rerun on this head; prior artifact-finalization failure is not claimed resolved, and full-Goal live release qualification remains tracked separately in #4208. Ready for renewed review, not an all-green or merge claim.

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

Request changes conclusion (author-owned PR; GitHub blocks formal self-review)

动机

这个 PR 想把 heartbeat 从“安装时冻结的一段提示词”改成由当前运行时动态生成,并让 Codex App、原生 Goal、CLI/SSH 等宿主各自拿到与其生命周期匹配的启动与结算协议。这个方向是对的,也直接触及了真实摩擦:旧版 thin 提示把 LOOPX_TURN=<current_time_iso> 和 quota 命令拆成两个行内片段,代理容易不知道应当先绑定 Turn id、在同一 shell 中复用它。

当前 exact head 已经实质修复了这点:thin/brief 都给出可执行的同一 shell 代码块,先赋值 LOOPX_TURN,再通过 ${LOOPX_TURN:?} 调用 quota;Bash、zsh 的回归也从未预置该变量的环境执行生成结果。持久 Goal 同时明确拒绝 --turn-instance-id,避免把 heartbeat Turn 生命周期带进长驻运行。

改动思路

整体设计把职责拆得比较合理:TypeScript quota/settlement 继续掌握状态机与 effect 权威,Python prompt renderer 只负责宿主适配;goal_bootstrap 每次加载当前 registry/runtime contract,而不是复用安装时快照;原生 Goal 通过 typed re-entry action 续跑,SSH 仍走 --begin-turn;安装更新只自动替换 exact-managed prompt,自定义、canary、foreign 或发生竞态的 prompt 进入 review-only。

此外,Todo 的“接受当前工作”与 Turn 的“结算当前工作”被区分开来,方向上能避免未绑定 settlement。更新期先记录旧 prompt 的 exact-managed 身份,再在新 runtime 下协调 adoption,也比把 prompt 迁移混进二进制安装成功状态更清晰。

具体改动

这次改动覆盖动态 prompt 生成、host-loop activation、安装期 prompt adoption、registry-derived agent scope、quota/spend re-entry、CLI 文档与较完整的回归集。

关键代码讲解

  • loopx/control_plane/heartbeat/task_body.py::render_thin_heartbeat_task_body 现在生成同一 fenced shell block,Turn id 的生成与消费不再靠读者自行拼接。
  • loopx/control_plane/heartbeat/bootstrap_prompt.py::goal_bootstrap 保留显式 caller policy,但重新读取 registry-derived runtime state,并拒绝持久化 Turn id/递归 bootstrap。
  • loopx/control_plane/heartbeat/installed_prompt_update.py::update_with_prompts 把 exact-managed prompt 的判定与新运行时下的 adoption 分开处理。
  • loopx/control_plane/quota/spend_sources.py::visible_goal_turn_reentry_action 给原生 Goal 一个带唯一 iteration identity 的 typed 续跑入口。

不过 brief 变体还有两个会阻断合并的语义问题:

  1. render_brief_heartbeat_task_body 插入的是 HEARTBEAT_NOTIFICATION_RULE_THIN。它只写裸字段 agent_must_attempt / must_attempt_work,没有保留权威对象路径 heartbeat_recommendation.agent_must_attempt 与 execution_obligation.must_attempt_work。这会让低上下文代理重新混淆“是否通知用户”和“是否必须执行工作”,而仓库已有的 durable invariant 正是为了防止这种回归;当前 hosted test-shard (1)、fallback pytest 和 merge-gate 都因此失败。
  2. 用当前 exact head、真实 loopx-meta registry scope 与 --brief --codex-app 生成提示时,budget_char_count=3792,超过 brief 声明的 max_chars=3500,within_budget=false。现有 long-path 测试使用较短的合成 agent scope,且没有覆盖 Codex App 的真实 preflight/scope 增量,所以没有验证 PR 描述中声称的生产长路径预算。

最低修复是:brief 输出恢复两个 fully qualified authority locator;同时压缩或正确约束真实 App brief,使 representative registry-derived scope/preflight 下 within_budget=true,并新增 heartbeat-prompt --brief --codex-app 的生产形态预算回归。这里不需要再造新框架,复用 shared exact notification rule,并把预算 fixture 调整到真实宿主形态即可。

对主干的风险

本地在当前 head 上跑 tests/test_host_loop_activation.py tests/control_plane/test_heartbeat_notification_rule.py 得到 84 passed、1 failed,失败就是 brief 丢失 execution_obligation.must_attempt_work 的语义门禁;定向复跑同样稳定复现。Ruff 和 git diff --check 通过。远端 test shard 报 3851 passed、19 skipped、1 failed,随后 fallback 与 merge gate 失败,与本地证据一致。

当前分支相对最新 origin/main 落后 8 个提交;合成 merge tree 无冲突,但 main 已触及 3 个同路径文件,因此修复后复审前仍需重新确认 exact head、merge tree 和真实 App 预算。PR 没有声称新增 live-model qualification,这个非目标本身可以接受;当前 blocker 是已声明接口在真实 prompt 上没有满足,而不是缺少额外模型实验。

我的整体评价

核心架构方向和默认 thin 路径的 Turn-id 修复值得保留,尤其是把 ${LOOPX_TURN:?} 放进可执行同 shell block,确实修到了这次观察到的真实摩擦。但 brief 是低上下文 fallback,恰恰不能丢失执行权威路径,也不能在真实 Codex App 配置下超出自己的接口预算。请在新 head 上补齐上述两点;届时我会按 exact head 重新验证并复审。

English verdict: REQUEST_CHANGES at exact head b572baf3817c005edde04e507168d0c73c2ece74; the default thin path now binds LOOPX_TURN correctly in an executable same-shell block, but brief mode drops the fully qualified execution-obligation locator, fails the required hosted test/merge gate, and renders 3792 budget chars against its 3500 limit for the active Codex App profile.

…mpt-contract

Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Addressed the latest review at 1beb54ef04fa0a8dbb3168901312d2e8b3281eaf (integrated the updated main without rewriting contributor ancestry).

Both findings were valid:

  1. Brief execution authority: thin and brief now share the complete notification rule, including heartbeat_recommendation.agent_must_attempt and execution_obligation.must_attempt_work. The unused weaker rule was removed so another renderer cannot accidentally select it. Output silence does not authorize an execution no-op; missing user-action projection still requires internal repair.
  2. Real App budget: brief no longer embeds an independent static refresh/spend recipe. Validated delivery follows the current interaction_contract.cli_channel.settlement_plan.ordered_steps, including its exact identities/effects, or current next_cli_actions when no plan exists. This is an intentional brief behavior improvement, not merely text shortening. Safety, repair routing, full preflight/guard, registry-derived scope, delivery/history constraints and vision replan remain. Todo acceptance is not Turn settlement or Goal completion. No budget ceiling or differential allowance was widened.

The regression now calls the real heartbeat-prompt --brief --codex-app entrypoint with a multi-scope registry profile and real preflight, and asserts both the unchanged 3,500-character interface ceiling and current settlement ownership. Read-only validation across 12 locally registered profiles passed for all 12; the largest brief was 3,472 characters. Only aggregate evidence is reported here; no private prompts, registry contents or Goal state were committed or modified.

Model regression: added scripts/qualify-host-prompt-release.py --release-live, reusing the existing Doubao evolving client. Current thin/brief prompts are checked against four independent synthetic scenarios: quiet work, notifying wait, quiet wait and required vision replan. Expected decisions are not sent to the model. Two independent repetitions per scenario/mode produced 16/16 passing model responses; there is no answer correction or retry-until-pass. Ordinary pytest uses scripted clients and negative oracles, including a failed first attempt followed by successes. Default execution makes no provider calls, missing credentials are a skip rather than a model pass, and attempted transport failures fail the run.

This is decision-level evidence only, not actual host tool execution, scheduler/cache behavior, migration delivery or whole-Goal qualification. It does not erase the earlier Claude/Doubao whole-Goal closeout failure tracked in #4208. No live automation migration or installation was performed in this follow-up.

Validation: 252 Python tests passed without skips on the final head; full heartbeat prompt smoke, real CLI absolute-budget plus base/head differential smoke, changed-file Ruff and diff hygiene passed. All 30 PR-range commits have DCO sign-off. Hosted checks must complete on this head; prior CI results are not reused as current passes.

Architecture/refactor judgment: retain one current TS execution/settlement authority and one shared notification rule; remove duplicated static instructions rather than adding a new framework. Default remains thin; full/compact behavior and automatic exact-managed v1 adoption are unchanged by this correction. Ready for renewed review, not an all-green/merge claim.

@huangruiteng
huangruiteng merged commit b57c615 into main Sep 11, 2026
21 of 22 checks passed
@huangruiteng
huangruiteng deleted the codex/native-goal-prompt-contract branch September 11, 2026 07:27
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Post-merge audit(绑定 exact head 1beb54ef04fa0a8dbb3168901312d2e8b3281eaf)

动机

这个 PR 解决的是一组真实且会按每次唤醒累积的 host-contract 摩擦:保存的 heartbeat/Goal 提示会冻结旧执行步骤;旧 thin 文本虽然提到 LOOPX_TURN=<current_time_iso>,却没有给出可直接执行的同一 shell 两步程序,代理很容易把赋值写成命令前缀,导致 Bash/zsh 在赋值生效前展开 ${LOOPX_TURN:?};native Goal 又可能在未绑定迭代 identity 时暴露结算动作。PR 还要让 exact-managed automation 在升级后采用动态 bootstrap,同时保持 custom/canary prompt、scheduler、跨 home 会话和 provider 权限不被静默改写。

我重新检查了最终合并 head。此前关于 Turn id、brief authority locator、真实 App budget、DCO 和 prompt adoption 的 blocker 均已修复;但合并时失败的外部 Sonar 门禁包含一个此前评审遗漏、且可独立复现的凭据边界问题,仍需要 post-merge 修复。

改动思路

整体架构仍然成立:heartbeat-prompt 每次生成当前 task body,thin/brief 在一个 fenced shell block 中先独立赋值 LOOPX_TURN,再运行带 --turn-instance-id 的 quota guard;selection、work obligation、settlement identity 和 effect 顺序继续由当前 interaction_contract/typed settlement owner 决定。native/Claude host 只保留稳定 bootstrap,通过 CLI 或 MCP 重新加载当前规则;loopx update --apply 仅对 byte-exact managed prompt 做带 CAS、journal 和双存储回读的 adoption,custom/冲突输入保持 review-required。

release-only qualification 也被设计为显式 --release-live、默认不调用模型,并从 allowlist 环境启动 Codex/Claude。问题出在“哪个程序有资格接收 allowlist 中唯一保留的 provider key”没有被同样绑定:公开 --codex-bin / --claude-bin 参数仍允许调用者把真实 host principal 换成任意本地可执行文件。

具体改动

关键代码讲解

  • loopx/control_plane/heartbeat/task_body.py::render_thin_heartbeat_task_body:最终输出明确写出“assignment 与 guard 是同一 shell 中的两个 statement”,并生成 LOOPX_TURN=<current_time_iso> 后再执行 guard。以当前真实 registry/profile 生成时为 1932/2500 字符,旧 base 是模糊的 inline hint;这正面修复了“一开始不知道如何传 Turn id”的问题。
  • loopx/control_plane/heartbeat/task_body.py::render_brief_heartbeat_task_body:保留 heartbeat_recommendation.agent_must_attempt 与 execution_obligation.must_attempt_work 两个完整 authority locator,并依赖当前 settlement plan 而非冻结的 refresh/spend 配方;当前输出 3316/3500。
  • loopx/control_plane/heartbeat/bootstrap_prompt.py::goal_bootstrap 与 installed_prompt_update.py::update_with_prompts:持久入口不固定单个 Turn;更新前识别 exact-managed bytes,更新后用新 runtime reconcile。一个真实 exact-managed heartbeat 已在升级后回读为 bootstrap v2、status=current、automatic_eligible=true;不公开本地 automation 身份或原始 prompt。
  • loopx/control_plane/quota/spend_sources.py::visible_goal_turn_reentry_action 和 loopx/cli_commands/todo.py::_completion_settlement_error:native iteration 先取得 identity;Todo 验收与 Turn accounting 分离,只有 terminal no-follow-up 在缺完整 receipt chain 时阻止 closeout。
  • scripts/qualify-native-goal-release.py::prerequisite_failure / qualify 与 scripts/qualify-claude-goal-release.py::run_host:这里存在新的 P1。--codex-bin / --claude-bin 直接进入 subprocess.run/Popen;在 spawn 前没有可信 executable identity/allowlist 判定,但环境已经含有选定的 qualification provider key。

复现使用的只是 synthetic key:把一个本地假程序传给 --codex-bin,它读取到 LOOPX_CODEX_QUALIFICATION_API_KEY、输出 goals stable,而 prerequisite_failure() 返回 None。也就是说,availability/self-reported feature output 被当成了 executable trust,任意程序可以先拿到 key 再伪造 probe。Claude 路径同样把 ANTHROPIC_API_KEY 交给 caller-selected executable。Sonar 对这两个 sink 报出 S8701,质量门禁的 new security rating 为 C;这个告警不是无法解释的误报。

对主干的风险

heartbeat 主路径的语义风险已经明显下降:base/head 真实输出对比确认旧 inline Turn hint 被可执行两步 bootstrap 替代;Bash/zsh mutation regression、当前安装回读和预算回读均通过。304 个 focused Python 行为测试通过;control-plane typecheck 通过,TypeScript 全套为 1096 passed、1 intentional skip。GitHub 的 DCO、dependency、build、Python、Node compatibility 和 merge gate 均通过。

剩余风险只在显式 live release qualification 开启时出现,但影响是 provider credential exposure,不应因为 default-off 就忽略。最低修复是:从 credential-bearing public live path 移除任意 binary override,改由 owner-controlled trusted configuration/allowlist 解析 executable;测试需要替换 binary 时使用内部 dependency injection。新增两个负向回归:分别给 Codex/Claude 传假 executable 与 synthetic key,必须在 spawn 前拒绝,且假程序不能观察到 key。修复后让外部 security gate 变绿;new-code coverage 当前为 43.7%,也应补齐或对真正不可执行的 release-only 分支做经过评审的精确排除,而不是继续整体 bypass。

我的整体评价

Turn-id 摩擦已经被准确修到:现在不是“提醒代理记得传 id”,而是给出可执行、可回归、同一 wake 重试复用的 shell contract;brief 的 notification/work authority、动态 prompt adoption、native settlement re-entry 和 host 边界也形成了一个可解释的整体。这个结论不会因为 post-merge finding 被推翻。

但最终 head 不应被视为完全审净:release qualifier 新增的 arbitrary executable override 把“允许一次 live qualification”扩大成了“任意 caller-selected program 可接收 provider key”。请拆一个最小 follow-up 修复 trusted-executable boundary 和对应回归;不需要重新设计 heartbeat 或 settlement。

English verdict: POST-MERGE ACTION REQUIRED at exact head 1beb54ef04fa0a8dbb3168901312d2e8b3281eaf — the executable two-statement Turn-ID bootstrap, brief authority semantics, budgets, dynamic prompt adoption, and settlement flow are verified, but the release-only --codex-bin/--claude-bin overrides can hand the selected provider credential to an arbitrary local executable; remove or owner-bind that override and add negative credential-boundary tests.

huangruiteng pushed a commit that referenced this pull request Sep 12, 2026
* fix(cli): restore module size and manpage classification budgets

Two required public smokes fail on current `main`.

`cli-command-module-size-ownership-command-modularization-smoke.py` reports
`project_lifecycle.py has 1007 lines, above budget 1000`. The file crossed the
budget when #4169 added the mutually exclusive external-sink delivery flags.
Extract the three typed inline input codecs into
`project_lifecycle_inputs.py`, which returns the owner to 925 lines without
changing any public invocation.

`cli-help-manpage-smoke.py` reports `unclassified: ['agent-context']`. The
command shipped in #4244 without a manpage class. Add it to the existing
`MANPAGE_COMMAND_HELP_ONLY` set, which is where comparable read-only
lifecycle helpers already live.

Extraction keeps the existing ownership contract: the registration and
dispatch markers asserted by
`cli-project-lifecycle-command-modularization-smoke.py` stay in the module,
and `PROJECT_LIFECYCLE_COMMANDS` still covers all four commands.

Validation:
- `python3 examples/cli-command-module-size-ownership-command-modularization-smoke.py` -> ok
- `python3 examples/cli-help-manpage-smoke.py` -> ok
- `python3 examples/cli-project-lifecycle-command-modularization-smoke.py` -> ok
- `python3 regression/cli-command-module-contract.py` -> ok
- `python -m pytest tests/cli_commands/ tests/control_plane/test_cli_output_budget.py` -> 94 passed

Signed-off-by: song <liusongstep@gmail.com>

* test(smokes): realign stale contracts with shipped behavior

Four required public smokes assert contracts that have since moved. Each is
reproducible on a clean `main@fa57253`, so this aligns the checks with the
shipped behavior rather than changing any product path.

- `blocker-push-runtime-smoke.py` asserted the retired per-shell phrasing
  `` `LOOPX_TURN=<current_time_iso>`; reuse. ``. #4201 moved the bootstrap rule
  into the shared `HEARTBEAT_TURN_BOOTSTRAP_RULE`, whose current sentence ends
  with `reuse the value on retries`. Assert that sentence.
- `install-local-smoke.py` required the accountable refresh and spend commands
  inside the `--brief` prompt, but brief mode renders exactly one bounded guard
  block by design; those commands belong to the full and compact modes. #4201
  already realigned the adjacent thin-mode assertions and missed this one.
  Assert the brief contract, including that the pair stays out.
- `github-actions-runtime-smoke.py` rejected the `22.14` SQLite runtime and the
  Node 26 forward job, and required the pre-#4241 `merge-gate` needs order.
  Record `SQLITE_NODE_VERSION` with its finalization rationale, extend the
  `python-tests.yml` expectation, and match the current needs list.
- `repository-hygiene-smoke.py` fails because the `v1.0.3` tag exists without a
  timeline entry. Add the entry, following the existing format.

Validation (each command exits 0):
- `python3 examples/blocker-push-runtime-smoke.py`
- `python3 examples/install-local-smoke.py`
- `python3 examples/github-actions-runtime-smoke.py`
- `python3 examples/repository-hygiene-smoke.py`
- `python3 examples/release/release-readiness-doc-smoke.py`
- `python -m pytest tests/control_plane/test_heartbeat_notification_rule.py tests/control_plane/test_heartbeat_prompt_support.py tests/control_plane/test_heartbeat_receipt.py tests/control_plane/test_heartbeat_recommendation_rules.py` -> 48 passed

Signed-off-by: song <liusongstep@gmail.com>

* test(ci): qualify runtime pins per workflow lane

Signed-off-by: song <liusongstep@gmail.com>

* test(ci): ignore comments when checking qualified runtime pins

Signed-off-by: song <liusongstep@gmail.com>

---------

Signed-off-by: song <liusongstep@gmail.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.

3 participants