Skip to content

fix(quota): fence settlement by exact GoalRef - #5340

Open
Duang777 wants to merge 4 commits into
loopx-project:mainfrom
Duang777:codex/quota-goalref-owner-fence
Open

Duang777 wants to merge 4 commits into
loopx-project:mainfrom
Duang777:codex/quota-goalref-owner-fence

Conversation

@Duang777

@Duang777 Duang777 commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Goal and delivered outcome

Scope and continuation

  • This change covers spend, exact-effect replay, prepared receipt repair, void target ownership, settlement identity inference, checkpoint commits, monitor and prior-Turn recovery, native-child receipts, and rolling-window accounting for source_session_v1.
  • Readback now filters events and runs by the typed alias | exact_source owner before identity inference. Alias requests cannot consume exact rows. Exact requests verify the current source GoalRef under the same two-lock admission used by writes.
  • Non-source requests retain legacy behavior and omit GoalRef fields.
  • This qualifies only the quota_settlement inventory row. Unsupported providers and every other unqualified M3 owner remain blocked. The RFC activation hold and execution_authority: false remain unchanged.

Validation

  • Tested revision: a23624c967785ffb7b3cee39c2052db08c0399ef
  • Run state: finished
  • Input classes: synthetic
Check kind Result Evidence or limitation
unit passed npm run test:control-plane: 3,587 tests, 3,557 passed, 30 optional PostgreSQL tests skipped, 0 failed.
integration passed quota_settlement_readback.test.ts: 88 passed. Durable cases cover alias plus exact A, B inference with only A, delayed A after B publication using a distinct Turn ID, and legacy alias plus legacy rows.
integration passed Combined Python target suite: 279 passed. This includes 199 settlement compatibility cases, 34 exact checkpoint/native-child/external-delivery cases, 36 spend/void/rolling-window cases, and 10 inventory/census cases.
static passed TypeScript control-plane typecheck, Ruff on all changed Python files, docs governance, git diff --check, and the 260-site project-registry I/O manifest check passed.
premerge passed Diff-driven standard premerge ran 5 direct checks and all 19 selected risk, smoke, and public-boundary checks.
repository_hygiene baseline failure The existing tests/test_contract_scan_missing_roots.py:46 private-IP fixture fails unchanged on clean origin/main@0644abaaa. This PR does not modify that file.

The PR remains dependent on #5344 for unrelated test-shard baseline repairs. This change does not qualify PostgreSQL quota storage or any external provider path.

See validation disclosure guidance.

Frontend / visual evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring with no functional changes
  • Documentation update
  • Test update

LoopX area

  • Control plane: goals, todos, quota, scheduler, registry, runtime
  • Benchmark boundary: adapters, runners, verifiers, scoring, evidence
  • Capability or extension: native-child receipt projection
  • Public docs or presentation surface: RFC and inventory
  • Build, packaging, installer, or CI
  • Host or runtime integration

Technical direction

  • Acceptance reference: Shared Goal Authority and cross-host coordination, M3 quota_settlement owner qualification.

Shared-authority RFC fixture impact

  • Source-session quota records, events, index rows, receipts, and response payloads carry the exact GoalRef. Lock witnesses remain transport-only and never persist.
  • Covered dimensions include same-alias Goal A to Goal B recreation, delayed stale reads and writes, exact replay and repair, exact void ownership, pre-inference readback isolation, checkpoint integration, and legacy parity.
  • Provider coverage includes the source-session file profile and the non-source legacy path. PostgreSQL quota storage is outside this owner and remains unqualified.

Boundary checklist

  • The diff, PR body, comments, and attachments contain no private state, credentials, raw traces, verifier output, internal links, or local machine paths.
  • I did not duplicate maintainer-owned benchmark work.
  • I kept the change scoped to [Task][RFC]: Complete Goal lifetime fencing and governed orphan recovery #5206.
  • UI impact is none.
  • Every authored commit includes a DCO Signed-off-by trailer.

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Collaborator Author

CI attribution update for head 377952efe:

  • The direct, TypeScript, Windows, Stage 2C, PostgreSQL, DCO, and packaging checks passed.
  • Shard 3 failed test_new_independent_twin_cannot_hide_behind_generated_pair plus one test_live_decision_adds_only_existing_required_read_channel parameter.
  • Shard 4 failed the other parameter of test_live_decision_adds_only_existing_required_read_channel.
  • pytest and merge-gate only propagate those shard failures.

I replayed all three tests in an isolated worktree at current origin/main@996bcc027; the same three assertions fail there. The two commits added after this PR opened do not touch these tests or their owners. I am keeping the quota branch unchanged while checking for an existing baseline repair, so unrelated baseline work does not enter this PR.

@Duang777

Copy link
Copy Markdown
Collaborator Author

Baseline dependency follow-up:

  • Existing draft PR perf(authority): copy journal JSON without repeated primitive allocation #5251 contains signed test-only commit 106b923a57c60d411dba9276c37d1f927e0023bc, which updates the two stale CI guards behind this PR's three failures.
  • I applied only that commit to an isolated origin/main@996bcc027 worktree and ran the affected tests. Result: 3 passed in 6.74s.
  • The quota branch remains unchanged. I will sync it once the baseline repair reaches main, avoiding unrelated test changes in this PR.

Reference: #5251

@Duang777

Copy link
Copy Markdown
Collaborator Author

The verified baseline repair is now isolated in #5344. It preserves the original author, contains only the two test files from 106b923a5, and passes the full affected files (38 passed) plus Ruff. I will sync this quota branch after #5344 reaches main.

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

评审提交:377952efe6311b5eefecf32a80316e17f773e2fe。这是 policy-11 whole-PR、exact-head 评审。我检查了全部 26 个文件,沿着 CLI/Turn → Python admission → TypeScript owner → spend/void transaction → receipt/index → settlement readback/rolling window 走完正负路径,并独立运行了 focused tests、静态检查、base/head 失败归因和两个 readback 反例。写侧设计明显正向,但 readback 仍有可复现的跨实例缺口,因此不能 approve。

动机

这个改动解决的是明确且高价值的问题:同一个 goal_id 被重建后,旧 Goal A 的延迟 quota spend、replay、repair、void 或 settlement 证据不能落到新 Goal B。PR 给出的 before/after 可观察收益是成立的——写侧现在会在当前 GoalRef 和双锁 witness 不匹配时先拒绝,再把 B 的 GoalRef 写入 record、quota event、index row、transaction receipt 和响应;rolling-window 也按实例隔离。这里不是“为了抽象而抽象”,而是修复 append-only accounting 可能跨生命周期归属的 correctness boundary。

不过当前实现只完整关闭了 mutation/replay/void,未关闭 readback 和 inferred recovery。PR 正文与 RFC 宣称 quota_settlement 已 exact-owned/M3-qualified,比可执行行为更强;这个差距本身就是 blocker。另请把 Related to #4447 改为真正承载 Goal-instance/quota-owner 验收的 issue,或明确解释依赖关系:#4447 是 semantic vocabulary convergence tracker,不能单独作为这 1,981 行机制与 M3 qualification 的收益/验收来源。

改动思路

入口层在 quota spend-slot、void-slot 和 turn run-once 捕获 source-session 当前 GoalRef。quota_accounting_admission 按 run-index → source guard 顺序持锁并生成两个 cross-runtime witness;parseQuotaAccountingOwner 校验 GoalRef、profile、路径和 witness,withQuotaAccountingOwner claim 两把锁并调用既有 decideFirstPartyHostRuntime(require_current)。因此 stale A 在写入前失败,B 的 transaction owner 能覆盖 replay、prepared repair、void target 和最终 artifact commit。

accounting_artifact_transaction 把 GoalRef 纳入 request digest、receipt 校验、effect identity 冲突和所有持久 projection;goal_quota_with_spend_ledger 则让 current exact instance 只累计自己的行。这个方向复用了现有 first-party host 和 artifact transaction owner,机制成本虽大但与高严重度一致。问题出在 settlement_readback:它没有复用上述 owner,只接受一个 nullable goal_ref,且直到 identity 已解析后才在 findSpend 上做可选比较。

具体改动

阻塞问题

  1. [P1] 请在 identity inference 之前把 settlement readback 纳入 current exact-owner fence。 findSpend 的 goalRef === null || ... 让 alias-only/未更新 caller 把任意 exact-source row 当作自己的;传入 GoalRef 时,也只比较持久行与请求值,不读取 registry、不 claim source guard、也不验证该 GoalRef 仍是 current。更早的 resolveIdentity/inferPersistedIdentity 完全看不到 GoalRef,会先从同 alias 的所有 run 中选 Turn。独立 exact-head 反例得到两个错误结果:一是无 GoalRef 请求直接返回 A 的 exact spend_run;二是当前 B 的 infer_turn_instance_id 请求在只有 A 记录时仍返回 found=true,并选中 A 的 Turn 后报告 spend_required。后者可让下游把 A 的 settlement tuple 带进一个由 B admission 合法通过、最终却 stamp 为 B 的新 spend。

最小修复应让 readback 使用与 spend/replay/void 相同的 typed alias/exact owner:source 请求在 guard 下验证 current GoalRef;alias 请求不能消费带 GoalRef 的记录;并在 resolveIdentity/inferPersistedIdentity 选择候选前应用 owner,而不是只过滤最终 spend row。请审计所有生产 read_heartbeat_settlement caller——当前 refresh-state、Todo completion、live decision、checkpoint、reward-memory、native-child 等多条路径仍未传 GoalRef。补四个 durable case:无 GoalRef + exact A、B inference + 仅 A、B 发布后 delayed A read、legacy alias + legacy row;前三者 fail closed/not found,最后一个保持原行为。完成前不要把 inventory 标为 m3_qualified。

关键代码讲解

  • quota_accounting_admission 是 Python 锁顺序与 witness 生产者;source 必须有 exact GoalRef,legacy 保留原 index-lock 行为。
  • withQuotaAccountingOwner 是 TypeScript 写侧 authority owner;它校验并 claim 两个 witness,在 require_current 通过后才执行 transaction,finally 中按逆序释放。
  • commitQuotaAccountingArtifactTransaction 把 GoalRef 纳入 existing receipt、effect row、prepared repair 和四类 projection 的一致性检查,避免同 effect id 跨实例重放。
  • evaluateQuotaSpendCommit/evaluateQuotaVoidCommit 在同一 owner 下完成 lookup、target validation 和 commit;legacy wire-shape tests 证明未携带 GoalRef 的记录不新增字段。
  • readQuotaSettlementFromRequest 目前仅把 request.goal_ref 传给 findSpend;它没有 current authority,也没有在 identity/event 候选阶段做 owner 隔离,这是 whole-PR 中唯一但关键的断口。

对主干的风险

独立验证结果:提交内 130 个 TypeScript quota tests、36 个 Python spend/void/rolling-window tests、10 个 owner-inventory/registry-census tests全部通过;TypeScript typecheck、Ruff 和 git diff --check 通过。GitHub 红项是 test-shard (3)、test-shard (4),聚合 pytest 和 merge-gate 随之失败;我在 immutable base 3ec049e138917a8cce4f84197ba196d26445b2b0 与 exact head 上重跑同三个 assertion,均为相同失败,因此不把它们归因于本 PR,也不把这点当作功能正确性的替代证据。

真正的主干风险是 silent scope escape:readback 不报 conflict,而是给出看似正常的 found/settled/spend_required。这会影响 quota 自身,也会影响消费 readback 的恢复、Todo、checkpoint 与 live-decision 路径。现有 submitted readback test 只覆盖“显式 A 匹配、显式 B 不匹配”,所以 130/130 仍无法捕捉 null-owner 和 pre-inference 两个反例。

代码量方面,26 文件共 +1,981/-176,其中约 980 行 production、946 行 tests;对高风险跨语言持久化 race 来说,测试占比和机制总体可接受。最高价值的收敛不是再加新层,而是让 readback 复用已经引入的 QuotaAccountingOwner,避免写侧 typed union、读侧 nullable wildcard 两套权威。domain wording 保持 Goal/Turn/quota 中性;没有把 advisory 当 obligation,但 RFC/inventory 的“qualified”是机器与 rollout 声明,必须等负路径真实通过。

语义与 CI 对齐

写侧的 alias | exact_source union、goal_instance_conflict 与 require_current 一致;readback 的 JsonObject | null 则把“legacy owner”与“未提供过滤条件”混为一类。CI 和 inventory tests 只验证声明结构与现有 positive cases,无法证明 scope 完整。应先把 readback 的状态规则对齐,再保留 exact_goal_ref_enforced/m3_qualified 声明。

我的整体评价

结论是 REQUEST_CHANGES。这项需求本身有清晰收益,写侧实现和大部分验证也值得保留;若只看 stale write、replay、repair、void 与 rolling-window,我会认为方向明显正向。当前不能 approve 的原因不是泛泛要求更多测试,而是核心承诺中的 readback/inference 有两个可复现反例,并且 inventory 已提前宣称 whole owner qualified。

请先让 readback 共享 current exact-owner 边界,补齐上述四个正反例,并修正或解释实际 task anchor。修复后重跑 130 TS quota、36 Python quota、owner inventory/census、typecheck、Ruff,以及这两个 reviewer counterexample;若 exact head 不再跨实例且 legacy parity 保持,我愿意重新审查。本次 review 不修改 PR,也不授权 merge。

English verdict: REQUEST_CHANGES on exact head 377952efe6311b5eefecf32a80316e17f773e2fe. The exact GoalRef write/replay/repair/void fence is a valuable and mostly well-tested improvement, and the current CI shard failures reproduce unchanged on the exact base. However, settlement readback still treats a missing GoalRef as a wildcard and applies GoalRef only after identity inference, so an unscoped caller can consume an exact A row and Goal B can infer Goal A's persisted Turn. Reuse the typed current-owner boundary for readback, add the negative cases, and keep quota_settlement unqualified until they pass.

optionalString(run.goal_id) === identity.goal_id &&
normalizeAgentId(run.agent_id) === identity.agent_id &&
(
goalRef === null

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.

[P1] goalRef === null currently matches every spend row, including exact-source rows. Because resolveIdentity / inferPersistedIdentity run before this filter and the request carries no source-authority proof, an alias-only caller can consume Goal A state and current Goal B can select Goal A’s persisted Turn identity. Please reuse a typed alias/exact quota owner for readback, validate current source authority before inference, filter every identity/event candidate by that owner, and audit production callers that still omit GoalRef. Add durable cases for alias + exact A, B inference + only A, delayed A after B publication, and legacy alias + legacy row before retaining the m3_qualified claim.

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.

Addressed in ec7f51aaf on top of origin/main@0644abaaa.

  • settlement_readback now decodes the same typed alias | exact_source owner used by spend, replay, repair, and void.
  • It filters every event and run candidate before resolveIdentity and inferPersistedIdentity. Alias requests accept only legacy rows with no GoalRef.
  • Exact reads claim both admission witnesses and verify require_current; nested checkpoint, refresh-state, native-child, monitor, and prior-Turn recovery paths use borrowed or already-adopted admission without releasing the enclosing transaction.
  • I audited all 19 production read_heartbeat_settlement calls. Every source-aware call now carries both registry_path and goal_ref; already-locked callers also carry source_admission.
  • The durable counterexamples now prove: alias plus exact A fails closed with receipt_missing and no spend row; current B plus only A returns found=false; delayed A with a distinct Turn ID cannot replace current B inference; legacy alias plus legacy rows still settles.
  • The exact checkpoint test replaces A with B after context capture and confirms that A cannot append a checkpoint.

Validation at this head: full TypeScript 3,587 total, 3,557 passed, 30 optional PostgreSQL skipped; focused readback 88 passed; Python settlement compatibility 199 passed; exact checkpoint/native-child/external-delivery 34 passed; spend/void/rolling-window 36 passed; inventory/census 10 passed; typecheck, Ruff, docs governance, and the 260-site manifest check passed.

The PR body now uses #5206 as the task anchor. The only selected premerge failure reproduces unchanged on clean origin/main@0644abaaa (interaction-contract-state-machine-smoke.py), as does the separate repository-hygiene fixture finding.

@Duang777

Copy link
Copy Markdown
Collaborator Author

#5344 also picked up the separate signed test-only fix e4e754982 after its first CI run reproduced the existing Host marker partial-write race. The Host process test passes on Node 22 and passed 10 consecutive reruns locally. The quota branch remains unchanged.

@Duang777
Duang777 requested a review from cocolord September 30, 2026 11:16
@mergify

mergify Bot commented Sep 30, 2026

Copy link
Copy Markdown

Hi @Duang777, the DCO Sign-off check did not pass. Please inspect
its details first: checkout, fetch, timeout or infrastructure errors
need their own recovery, not a rewrite of otherwise signed commits.

If the log confirms a missing Signed-off-by trailer, amend the
affected commit with git commit --amend -s; for multiple commits,
use an interactive rebase against the current base from the correct
base-repository remote and sign off each affected commit. Push the
rewritten PR branch with git push --force-with-lease origin HEAD.

@Duang777

Copy link
Copy Markdown
Collaborator Author

Exact-head update: merged origin/main@21f89e4ad into the branch. The main update included the required-read smoke correction and the auxiliary-monitor replan guard. Both compose cleanly with this PR's GoalRef CLI propagation. Current head is a23624c96.

Exact-head validation now passes: full TypeScript 3,587 total, 3,557 passed, and 30 optional PostgreSQL skipped; combined Python target suite 279 passed; TypeScript typecheck; Ruff; docs governance; 260-site manifest check; and diff-driven standard premerge with 5 direct checks plus 19 of 19 selected checks.

The separate repository-hygiene private_ip fixture remains an unchanged main baseline finding. #5344 remains the dependency for the unrelated shard assertions identified earlier. Re-review is requested from cocolord and huangruiteng.

@mergify

mergify Bot commented Sep 30, 2026

Copy link
Copy Markdown

Hi @Duang777, the DCO Sign-off check did not pass. Please inspect
its details first: checkout, fetch, timeout or infrastructure errors
need their own recovery, not a rewrite of otherwise signed commits.

If the log confirms a missing Signed-off-by trailer, amend the
affected commit with git commit --amend -s; for multiple commits,
use an interactive rebase against the current base from the correct
base-repository remote and sign off each affected commit. Push the
rewritten PR branch with git push --force-with-lease origin HEAD.

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.

2 participants