Skip to content

feat(steward): record the intent basis a materialized team plan advances - #4538

Merged
huangruiteng merged 1 commit into
mainfrom
codex/team-plan-intent-basis
Sep 16, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/team-plan-intent-basis

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

Problem

A confirmed team plan creates work-graph edits, and nothing tied those edits to the canonical revision
they were meant to advance — the traceability the shared-goal alignment contract asks for. The receipt
named what was created, not what it advanced.

What changed

  • The settlement now reads the Goal's own shared_goal_alignment_v0 source basis before it writes
    and publishes it in the receipt as a bounded intent_basis.
  • It reads the basis for one of the plan's Agents: the source basis is a Goal-level fact, so any lane's
    Agent reads the same one, and a ready lane is preferred because that is where the work now lives. A
    Goal whose basis cannot be read omits the field rather than inventing one.
  • The read happens before the lanes are created on purpose. Computing it afterwards would let the
    edit describe itself instead of the revision it advanced; the test pins this by comparing the
    receipt against a fresh pre-apply projection read and against a post-apply read.
  • intent_basis joins lane_todo_ids as an explicitly bounded additive field in the otherwise closed,
    persisted receipt field set, so a receipt written before it still validates and a malformed digest is
    refused.
  • The Chat action's own receipt carries the same basis, so the owner's readback can name what the new
    lanes advance. No new field is added to the Todo row; the receipt is the traceability record.
  • The RFC notes this in both editions.

Validation

  • tests/test_steward_team_plan_apply.py, tests/test_chat_team_plan_action.py,
    tests/extensions/test_governed_capability_execution.py, tests/test_chat_operation_actions.py:
    35 passed. The new coverage asserts the recorded basis equals a fresh pre-apply projection read,
    differs from a post-apply read, still validates as a receipt, and rejects sha256:short, a bare hex
    string and an uppercase digest.
  • examples/docs-governance-smoke.py: ok.
  • loopx canary premerge --from-git-diff: merge_gate_passed=true, self_merge_allowed=true,
    failures 0.

Boundaries

Traceability only: no authority, no new write path, no Todo schema change. The basis is read from the
canonical projection rather than derived from the proposal, and an unreadable basis is reported as
absent instead of being fabricated.

A team plan creates work-graph edits, and nothing tied those edits to the
canonical revision they were meant to advance. The settlement now reads that
basis before it writes and publishes it in the receipt.

The basis is the Goal's own `shared_goal_alignment_v0` source basis, read for one
of the plan's Agents (the source basis is a Goal-level fact, so any lane's Agent
reads the same one, and a ready lane is preferred because that is where the work
now lives). A Goal whose basis cannot be read omits the field rather than
inventing one, and the value is validated as a bounded digest shape.

The read happens before the lanes are created on purpose: computing it afterwards
would let the edit describe itself instead of describing the revision it advanced.
The receipt is the traceability record, so the Todo row itself needs no new field.

The Chat action's own receipt carries the same basis, so the owner's readback can
name what the new lanes advance.

Verified: tests/test_steward_team_plan_apply.py, tests/test_chat_team_plan_action.py,
tests/extensions/test_governed_capability_execution.py and
tests/test_chat_operation_actions.py 35 passed, including a receipt basis that
equals a fresh pre-apply projection read, differs from a post-apply read, still
validates, and rejects a malformed digest. examples/docs-governance-smoke.py ok.

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.

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

一、变更内容

  • 结算在写入之前读取该 Goal 的 shared_goal_alignment_v0 source basis,并把它作为有界字段 intent_basis 写进回执;Chat action 自己的回执也带上同一 basis,业主回读即可看到"新建的 lane 在推进哪个修订"。
  • basis 用计划中某个 Agent 读取(source basis 是 Goal 级事实,任意 lane 的 Agent 读到同一个值;优先取 ready lane,因为工作现在落在那里)。读不到就省略字段,不编造。
  • intent_basis 与 lane_todo_ids 一样,是那个封闭且持久化回执字段集的显式有界加性例外:旧回执仍通过校验,畸形 digest(sha256:short、裸 hex、大写)被拒绝。
  • 不给 Todo 行加新字段:回执就是可追溯性记录;RFC 双语说明这一点。

二、依据与一致性

  • 依据是共享目标对齐契约(§3.2)的要求:"work-graph edits must remain traceable to the canonical intent revision they are intended to advance";此前 #4535 只记录"建了什么",没有记录"推进哪个修订"。
  • 与"不要发明权威/事实"一致:basis 来自 canonical projection,而不是从提案推导;读不到就缺省,而不是造一个 digest。
  • 与"回执是持久化状态"的兼容约束一致:加性字段 + 有界形状 + 旧回执仍有效;TS 侧把 transition_receipts 当不透明数组透传,所以这是 Python 侧有界变更。
  • 顺序是刻意的:最初我把 basis 读在 lane 创建之后,测试立刻暴露了两个问题——它会包含这次编辑自己创建的 Todo(等于让编辑自我描述),并且同一测试内两次结算因此得到相同 digest。现在读在写入之前,并用"等于 apply 前的新鲜读取、不等于 apply 后的读取"把语义钉住。

三、验证

  • tests/test_steward_team_plan_apply.py、tests/test_chat_team_plan_action.py、tests/extensions/test_governed_capability_execution.py、tests/test_chat_operation_actions.py:35 passed。新增断言:回执 basis == apply 前的新鲜投影读取;apply 后的读取与之不同;回执仍通过校验;三种畸形 digest 被拒。
  • examples/docs-governance-smoke.py:ok。
  • loopx canary premerge --from-git-diff:merge_gate_passed=true、self_merge_allowed=true、failures 0。

四、风险与残余缺口

  • basis 的粒度是"Goal 级修订事实"(状态时间戳、status、注册 Agent、Todo basis),不是"逐行文本";这一点已写进测试注释与 RFC,避免读者把它误解成内容哈希。
  • 仍未做:前端确认面(最大剩余项);peer directory 的实现接线。另外 Todo 行本身仍不带 basis——如果未来需要在没有回执的路径上读它,那是一次显式的 Todo 契约扩展,本次没有偷偷加。
  • 一处实现细节:basis 读取失败被吞成"缺省"。我选择缺省而非失败,因为可追溯性不是写入的授权条件;但它也意味着"回执没有 intent_basis"有多种可能原因,读者应把它读作"未知"而不是"没有修订"。

五、结论

批准以 admin squash 合并(self_merge_allowed=true)。单一目的、可回滚、无权限变化:把团队计划的落地从"记录了建了什么"推进到"记录了推进哪个修订",并保持回执契约的封闭性与向后兼容。

English verdict: Approved for an admin squash merge. The settlement now reads the Goal's canonical source basis before it writes and records it as a bounded intent_basis in the receipt (and in the Chat action's readback), so a materialized lane Todo is traceable to the intent revision it advances without changing the Todo schema. 35 focused tests pass, including the ordering property that the recorded basis equals a pre-apply read and differs from a post-apply one, and the canary premerge gate is green.

@huangruiteng
huangruiteng merged commit 86530b3 into main Sep 16, 2026
6 checks passed
@huangruiteng
huangruiteng deleted the codex/team-plan-intent-basis branch September 16, 2026 11:18

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

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

动机

缺口是真的:确认后的团队计划会创建 work-graph 编辑,但回执只说"现在有什么"(lane_todo_ids),没有说这次编辑是在哪个 basis 上应用的,所以后来的人只能靠时间推断一条 lane 属于哪次 Goal 级变化。补上一条"写入前读取、随回执记录"的 basis 事实,方向正确。

改动思路

两个实现选择我认为是对的:

  • 复用既有只读投影,而不是自己算摘要。 _intent_basis_for 调 project_shared_goal_alignment,取 source_basis.source_basis_digest;读取失败时返回 None,回执省略字段而不是编造。这与"不要发明 canonical 事实"的要求一致。
  • 读取顺序在写入之前。 basis 在 lane 创建之前读,所以它描述的是编辑前的基础,而不是编辑自身产生的结果。新测试恰好把这一点钉住了:记录值等于结算前读到的值,且结算后 basis 已经变化。

字段的可选性处理也与 lane_todo_ids 一致:加入 _OPTIONAL_RECEIPT_FIELDS,形状用 ^sha256:[0-9a-f]{64}$ 严格校验,老回执仍然有效,非法值被拒。

具体改动

governed_transition_proposal.py 新增 _intent_basis_for(约 40 行)、可选回执字段与其形状校验、_apply_team_plan 的写入前读取;chat_actions.py 把该值复制到业主可见的 Chat action 回执;测试 +44 行;RFC 中英两版记录。六文件 +128/-13,无新模块、无新状态存储。

验证:pytest tests/test_steward_team_plan_apply.py tests/test_chat_team_plan_action.py tests/test_steward_team_plan_preview.py tests/extensions/test_governed_capability_execution.py → 42 passed,其中新用例断言:记录值匹配 ^sha256:[0-9a-f]{64}$、等于结算前读取的 basis、结算后 basis 已不同、且四种畸形值被拒;Chat action 回执也带该字段。

P2(非阻塞,但建议修):字段名 intent_basis 与它实际承载的值不符。它承载的是对齐投影的 source_basis_digest,而该模块自己的 docstring 明确写着:source_basis_digest 是"typed source-facts basis summary ... not a canonical intent-envelope digest —— RFC §3.1 的 envelope(objective、non-goals、acceptance、permission scope、terminal conditions)目前没有类型化存储,因此这里不声称 canonical intent identity",并且 state_event_basis_sequence "is NOT a canonical goal/intent revision"。新测试还从另一个角度印证了这一点:字段值在 lane 创建后就变了——它是 state basis,不是稳定的修订身份。

风险具体有两个:后续消费者可能把 intent_basis 当作 canonical intent 修订去比较(或与未来 shared_goal_intent_v0 的值比较),从而对"这条 lane 推进什么"得出错误结论;同时这个已持久化的字段会以仓库自己否定的名义成为兼容性义务。最小修法二选一:把字段改成名副其实的名字(如 source_basis_digest / alignment_basis_digest,形状校验保留),或保留名字但在回执契约与两版 RFC 里写明它记录的是该 Goal 的 source-facts basis、是写入前读取的、且 §3.1 的类型化意图 envelope 尚不存在。

P3(非阻塞):RFC 里"仍缺什么"那句被改成了 What is still missing is the surface that sends that confirmation and the per-Goal coverage behind it: a multi-lane preview has no frontend confirmation surface yet.——冒号后面只有一项,"the per-Goal coverage behind it" 没有可操作的指代;而原本那句具体缺口("lane Todo 不携带它本应推进的意图修订")被删掉后,读者再也看不到真正的原因:§3.1 的意图 envelope 没有类型化存储。把这点写明白(中英两版),既能修好句子,也正好支撑上面的字段命名说明。

对主干的风险

写入路径本身没有变化:只是多读一次只读投影、多一个可选回执字段(缺失即省略),lane 创建、gap 处理、陈旧与幂等行为都不受影响;共享回执校验器的既有规则(lane_todo_ids 可选、未知字段拒绝、monitor key 分型)仍然通过原有测试。

风险集中在语义而非行为:intent_basis 这个名字比它承载的值更"强"。今天没有任何逻辑依赖它,所以是 P2 而非阻塞;但如果等到有消费者按名字使用它再改名,代价会高得多——这也是我建议现在处理的原因。

我的整体评价

方向与实现都对:复用既有只读投影、写入前读取、可选字段 + 严格形状、缺失即省略而不编造,并用测试把"记录的是编辑前的 basis"这一关键性质固定下来(42 passed)。它确实补上了每个团队计划都缺的那条可追溯事实。

需要跟进的是一处命名的语义(P2:intent_basis 实际是 source basis,而 owning 模块明确否认它是 canonical intent revision)与一处文档澄清(P3:把"仍缺 §3.1 类型化意图 envelope"写回两版 RFC)。两者都不构成合并阻塞。

English verdict: APPROVE (exact head 04cf5c4)

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