Skip to content

fix(replan): return current facts for same-obligation recovery - #7426

Open
loopx-agent wants to merge 1 commit into
mainfrom
codex/controller-stale-review
Open

loopx-agent wants to merge 1 commit into
mainfrom
codex/controller-stale-review

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

A stride review can become stale after delivery but before its same-obligation writeback. The rejection previously offered a generic refresh-state command without the original Turn binding or the current review facts, inviting an unchanged retry or another admission just to recover context.

The TypeScript semantic owner now returns the complete current review context and stride controls on this specific mismatch. The rejection projects read_current_replan_context, asks the consumer to read and reassess those facts, and preserves the original Goal/Agent/Turn/obligation and settlement identity for retry. It does not auto-adopt the reference, accept a stale decision, admit work, or spend quota. Other rejection routes remain unchanged.

共享 Goal 的验收变化仍然会使评审依据过期;不能仅因 outcome 属于另一 Agent 就忽略它。本变更提供完整当前依据供重新判断,保留原结算身份与所有现有拒绝条件,不降低新鲜度要求。它是 controller 统一契约迁移中的恢复切片,未完成共享 writer、差分上下文或全部执行路径迁移,也未证明已安装宿主采用或模型效果改善。

Validation:

  • Real source-checkout CLI against disposable File and SQLite authorities: 4 cases cover both an invalid reference and an actual objective revision after delivery, returned facts, revised validation decision, same-identity writeback, and idempotent single spend without another guard. All 4 new recovery expectations fail against immutable baseline 99921829f2c5fa2ad35a024c72abb88717003ef3.
  • Broader Python selection: 143 passed, 6 failed. All 6 failures reproduce against that same baseline: four existing canonical-authority failures in refresh-state fixtures and two staged-read fixtures rejected for missing finding status. They remain unresolved and are not reported as passes.
  • TypeScript context/stride/semantic suites: 91 passed; shared acceptance invalidation and recovery payload non-aliasing included. Type checking, Ruff and whitespace checks passed.
  • Risk-based premerge: passed, 19 selected checks, no failures or manual holds. The final host-action projection was additionally covered by the final four real CLI cases.

Boundary: 3 runtime source files, focused existing test suites, and bilingual protocol guidance. The new host-action token extends the existing rejection contract; transient recovery data uses existing context/control owners. No new state owner, migration, permission, provider implementation, model run or benchmark job. No install or merge qualification claimed. The controller RFC records the same freshness/relevance/settlement distinction in #7416.

Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>

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

Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; reasoning_effort=max; declaration_source=runtime_reported.

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

动机

Problem and result. An agent completing a required review of its ongoing work can encounter a changed Goal objective or shared acceptance before its original writeback. The old rejection supplies neither the current review facts nor the original Turn binding in its suggested retry command, inviting a repeated stale write or another admission just to recover facts; the new rejection returns current facts and asks for reassessment before retrying the same obligation. Real File and SQLite CLI runs recover the changed basis, accept a revised decision under the original identity, and debit once despite replay; a second basis change still rejects before append or spend. This patch does not weaken freshness, auto-adopt a reference, authorize new work, unify controller contracts or establish installed-host/model benefit. Natural agent adoption of the returned instructions and wider unified-writer/App migration remain unqualified; this patch delivers the source CLI recovery path.

原来的拒绝并未给出重新判断所需的当前依据,却建议再次写入,容易形成无效重试。本次让同一义务的恢复闭环可执行:先读新事实,再修订决定,最后沿原身份回写和结算。

改动思路

Architecture and smaller alternatives. The existing TS semantic owner can return its already-derived current facts; Python only projects the recovery instruction. This repairs the real failure without another admission API, persisted state owner or provider policy. The current PR boundary is same-obligation stale-basis recovery through refresh-state; all existing eligibility, obligation identity, evidence and once-only settlement rules remain authoritative. An ID-only response would encourage blind rebinding; running another guard merely to fetch facts changes the admission context. The chosen payload preserves the complete existing context and current controls, rather than inventing a parallel recovery record.

Source-derived flow at 27125481b0c3d5e7c8e2585799cd672a8fc6f68a (plain table; Mermaid rendering not inspected):

Trigger Baseline Reviewed head
Same obligation, stale review basis Reject; generic unbound write suggestion Reject; current context/control and read/reassess instruction
Basis changes again Still must reject Reject again before append/spend; return newest basis
Reassessed current decision Existing guarded writeback Same original Goal/Agent/Turn/obligation and settlement; one debit
Missing path, foreign obligation or strategy off Existing rules Existing rules; no recovery-based bypass

语义判断留在 TypeScript,Python 只投影错误和恢复动作。共享 Goal 的验收仍影响当前依据,即使修改来自另一位 outcome owner;不能靠忽略他人的变化减少过期拒绝。

具体改动

关键代码讲解

  • projectReplanSemantics: derives reviewContextChanged from exact IDs. Only the otherwise well-formed same-obligation mismatch returns a cloned current replan_context, controls from strideControlContract, received reference and ordered instruction. Existing required-decision/path, foreign-obligation, evidence and terminal checks retain precedence. The returned clone cannot mutate the input context.
  • project_replan_writeback_rejection: recognizes the typed recovery payload, selects read_current_replan_context and removes the generic unbound next_cli_actions. Lifecycle, capability and ordinary rejection routes remain intact when this payload is absent. No recovery operation is executed here.
  • handle_refresh_state_command: retains the typed rejection and only appends a textual Required transition when commands exist. The real subprocess CLI demonstrates refusal before run append/spend and later accepted original-identity persistence.

The complete diff is7files,136additions/12deletions:3runtime sources,3existing test suites and bilingual protocol guidance. The tests also ensure another owner's shared acceptance still changes the review basis and recovery output does not alias the source. No schema migration, storage adapter, new CLI option or settings capability is added.

Independent specification: docs/reference/protocols/quota-replan-planning-selection-v0.md at 99921829f2c5fa2ad35a024c72abb88717003ef3, read before the diff. The newly added section is disclosure of this extension, not its own pre-change oracle.

Criterion Disposition
original-settlement-identity implemented: actual persisted original receipt identity after recovered writeback; wrong obligation stays rejected
writeback-before-single-debit implemented: no rejection effects; repeated spend after accepted original writeback debits once
shared-typed-owner implemented: existing TS qualifier/context/control and Python transport reused
source-versus-installed-qualification deferred: installed/natural host adoption remains with existing host/controller qualification

关键变化是错误返回的可操作性,而不是新工作授权。当前 context 的完整性沿用其既有来源与 coverage 边界;不能把有限展示中没有出现的材料视为不存在。

对主干的风险

Changed invariant and falsification. The real effective-Turn/replan suite passes20tests, including4File/SQLite cases covering invalid references and an objective revision after delivery. Independent baseline runs expose the old generic command without current facts. Two additional reviewer cases change the objective again after recovery: both reject before append/spend, then accept a freshly reassessed decision under the original identity and retain one debit. No new guard is used for those recoveries. The existing test continues through later canonical history/followthrough, beyond the first success.

The3TypeScript suites pass91tests. A paired40-case production-owner comparison covers5review triggers, both strategies and fresh/missing/foreign-obligation/foreign-context inputs:35full JSON outputs are identical; only5enabled stale-context outputs add the intended recovery. All20off-mode outputs match the immutable base exactly. This establishes output isolation, not model comprehension.

Current red checks, independently attributed. The same adjacent command on the immutable baseline and reviewed head yields54passed/6failed. The entire normalized failure output matches, including every node, assertion, error and stack; normalization removes only temporary root counters, process metadata, addresses and duration. Four failures in test_refresh_state_replan_gate.py encounter canonical-authority-required fixtures before semantic qualification (repair-delta-only, atomic blocker, legacy cadence, and rotated Vision cases). Both test_pure_replan_does_not_advertise_unavailable_explore_attachment provider cases fail explore.result.normalize because finding status is missing, before replan rendering. These branches do not enter the3changed production locations. They remain pre_existing_unrelated, with fixture maintenance owned separately; they are not reported as passes or repaired by this PR.

语义与 CI 对齐

This extends existing rejection vocabulary with a read-current-context host action and a transient derived projection. No persisted authority or new protocol lifecycle is created. The ordered instruction retains actor, source provenance, reassessment-before-retry, original identity, no auto-spend and repeated freshness checks. Reading/reassessment is a consumer instruction; merely changing an ID is not proof of model adoption. Generic error text remains domain-neutral.

Risk-based premerge passed6direct and19selected checks, including compile, output budget, semantic advisory, public boundary and existing scheduler/replan checks. No GitHub CI was fetched, polled or used. Initial reviewer command-path/import/key mistakes are retained privately and corrected; they are not attributed to this patch. PostgreSQL storage behavior was not changed and no PostgreSQL qualification is claimed.

最强反例是“第一次恢复有效,但重试前又变化”。该反例已在两个真实隔离后端验证。六个相邻失败保留为红色,已有同命令、同失败细节的基线归因;这支持本次评审结论,不代表整个仓库测试全绿。

我的整体评价

APPROVE — justified recovery increment at 27125481b0c3d5e7c8e2585799cd672a8fc6f68a. Long-horizon behavior is improved by restoring same-identity progress after stale-basis refusal, while later drift and replay still remain guarded. User experience is improved through actionable current facts in the existing CLI; no new setup, required human navigation/re-entry or confirmation round is added. No rendered presentation changes: the touched journey is JSON CLI rejection/recovery and protocol text; No App/Lark view or settings implementation changed; this extends the existing CLI recovery journey. Unverified scope: installed model adoption and host-specific presentation; no rendered UI claim.

The mechanism is proportionate:3small existing source locations reuse the current facts and control owners, avoid duplicate stored state, and remove a misleading retry command. Additional complete-context bytes occur on this refusal path; no token-efficiency gain is claimed. Six unchanged adjacent fixture failures and installed/unified-contract qualification remain separate limits. Existing PR discussion arrays were empty when read. COMMENTED publication records the conclusion because the shared GitHub account is also the author; it grants neither formal GitHub self-approval nor merge authority.

我认可这次范围明确的恢复修复。它完成了原义务在来源变化后的真实 CLI 闭环,同时保留新鲜度、证据和一次结算边界;尚未证明自然模型会遵守返回指令,也未完成统一 controller 契约迁移。

English verdict: APPROVE — 27125481b0c3d5e7c8e2585799cd672a8fc6f68a; real File/SQLite recovery, repeated drift, original identity and single-debit replay verified. Local premerge passes; six independently matched pre-existing adjacent fixture failures remain disclosed, with installed adoption and merge qualification separate.

This branch has not been deployed

No deployments
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