Skip to content

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

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

Duang777 wants to merge 10 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

  • Behavior-suite revision: a23624c967785ffb7b3cee39c2052db08c0399ef
  • Final DCO and merge-gate revision: 70c74576b38cd85bccff6418aae5169c1c57ca5e
  • 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 behavior 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. The three former shard failures also pass on current main.
static passed At final head 70c74576b, TypeScript control-plane typecheck, the 260-site project-registry I/O manifest check, and 10 inventory/census tests passed. Ruff, docs governance, and git diff --check also passed for the feature diff.
premerge passed At final head 70c74576b, 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 the main baseline. This PR does not modify that file.

The three previously failing shard assertions pass on current main. 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.

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

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@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
Duang777 force-pushed the codex/quota-goalref-owner-fence branch from a23624c to 2d82f93 Compare September 30, 2026 12:45
@Duang777

Copy link
Copy Markdown
Collaborator Author

DCO history correction completed with the approved --force-with-lease update.

The PR now contains one authored contribution commit, 2d82f938e, with a valid Signed-off-by trailer. GitHub then updated the branch to current main with verified merge commit 70c74576b; its committer is web-flow, verification is valid, and its parents are the signed contribution plus origin/main@a7e6b826a.

Final-head local gates pass: TypeScript typecheck, the 260-site manifest check, 10 inventory/census tests, and standard premerge with 5 direct checks plus 19 of 19 selected checks. The three previous shard assertions now pass on current main, so #5344 is no longer a dependency for this PR.

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

Copy link
Copy Markdown
Collaborator Author

CI follow-up for head 7026e4638:

  • kernel-static-checks exposed a real dependency-boundary regression from this PR. loopx/control_plane/quota/effect_program.py is one of the 19 strict mypy roots; importing source_session_registry_state from it expanded the checked import graph and surfaced 4,248 unrelated baseline errors.
  • The fix moves the pure GoalRef validation into goal_instance_identity.py. source_session_registry_state keeps its existing exports, while the settlement-plan root imports only the lightweight identity module.
  • Local verification now passes with mypy (Success: no issues found in 19 source files), Ruff, git diff --check, and 124 focused Python tests.
  • The prior Windows failure was a one-off runtime-termination race in an unchanged test. The exact parent a7e6b826a passed the same Windows job, including that lifecycle step. This push will rerun it on the new head.

The commit is signed off and was pushed without rewriting history.

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

Copy link
Copy Markdown
Collaborator Author

CI follow-up for head b8fb1069c:

  • Shard 3 exposed two PR-owned regressions. The lightweight Python GoalRef helper had the same basename as the existing TypeScript owner, raising the independently maintained twin count from 43 to 44. It is now named goal_ref_validation.py, which preserves the strict-mypy dependency boundary without creating a new cross-runtime twin.
  • The legacy monitor effect-id test now passes goal_ref=None explicitly, so it continues to exercise the alias-only compatibility path under the new required helper argument.
  • Both failing tests now pass. Broader local verification passes 99 affected Python tests, strict mypy over all 19 configured roots, Ruff, and git diff --check.

The commit is signed off and was pushed normally without rewriting history. uv.lock remains unchanged and untracked.

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

Copy link
Copy Markdown
Collaborator Author

Final-head CI update for 8189e5a25:

  • Synced with origin/main@0538bf163; the merge commit carries Signed-off-by.
  • All required checks pass, including DCO, kernel-static-checks, Windows PowerShell, all four Python shards, pytest, TypeScript, Stage 2C, PostgreSQL, release artifacts, Frontstage, and merge-gate.
  • The prior shard 3 failures are closed on CI: the independent Python/TypeScript twin count remains within the frozen budget, and the legacy monitor effect-id case passes with an explicit alias owner.

The branch is current with main, mergeable, and unchanged outside the reviewed fix plus the main sync. Re-review requests for cocolord and huangruiteng remain active.

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

Copy link
Copy Markdown
Collaborator Author

Exact-head required CI is green on 34ca5528c178d8fa49b4ec5ca7f8a8aaa9ac8ef9: 31 checks passed with no failures, including DCO, all Python and TypeScript shards, Windows PowerShell, Stage 2C, browser/dashboard acceptance, coverage, pytest, and merge-gate. The only remaining job is non-blocking SonarCloud analysis, currently queued.

The branch is mergeable. The visible CHANGES_REQUESTED decision is still tied to 377952efe; the settlement readback blocker was addressed in the later commits. @cocolord @huangruiteng please re-review this exact head when available. No merge action was taken.

Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
…wner-fence

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

Copy link
Copy Markdown
Collaborator Author

Synced the branch with main@3b73108e32acfe6657204b902a037171797e3e5c, including the merged #5344 baseline repair. The signed merge commit is bd4c4652f6d4129590d72ed5d44fb2428a8f2b71; the merge was conflict-free.

Post-sync validation passes: 62 focused Python tests, 175 focused TypeScript tests, strict mypy over 19 source files, control-plane TypeScript typecheck, Ruff, and git diff --check. The local untracked uv.lock remains unmodified and was not staged. Exact-head CI is running.

@cocolord @huangruiteng please re-review this exact head when available. No merge action was taken.

@Duang777

Copy link
Copy Markdown
Collaborator Author

CI attribution for exact head bd4c4652f:

  • test-shard (1) failed test_runtime_request_source_churn_raises_a_stable_startup_diagnostic: the observed diagnostic was runtime_exited_before_ready instead of packaged_runtime_source_unstable.
  • test-shard (4) failed test_runtime_fingerprint_rescans_when_a_snapshotted_file_disappears_while_reading: the runtime read first.ts and later.ts, then returned without the expected retry read of first.ts.

These are the same concurrent runtime-source fingerprint failures reproduced on current main and do not involve this PR's quota GoalRef changes. The dedicated baseline repair is #5367 at exact head f5995f102; it validates the post-read source snapshot, retries once, and preserves the fail-closed churn diagnostic. This branch remains unchanged pending that baseline fix. No merge action was taken.

@Duang777

Copy link
Copy Markdown
Collaborator Author

CI dependency update for exact head bd4c4652f:

  • Shards 1 and 4 failed only the two runtime fingerprint/readiness tests already reproduced on origin/main@67930ab6a.
  • I cancelled the queued pytest aggregator after those failures were established; it could only propagate the same failed result and was waiting for a runner.
  • The dedicated baseline repair is now fix(runtime): reject stale batched source fingerprints #5367 at signed commit f5995f102. Its focused runtime readiness and concurrent file-read suite passes locally (35 passed), and CI is running.

This quota branch remains unchanged. I will sync it only after #5367 reaches main; no merge action was taken.

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

详细中文评审

审查 head:bd4c4652f6d4129590d72ed5d44fb2428a8f2b71
比较基线:3b73108e32acfe6657204b902a037171797e3e5c
结论:REQUEST_CHANGES

动机

以 #5206 和 Goal Instance RFC 的 quota owner 隔离为验收框架,不以 #4447 的整体 carrier convergence 为本 PR 的完成条件。要解决的是同名 Goal 删除重建后,A 的迟到扣费、回放或交付依据影响 B;不是仅给记录补一个字段。

这一需求有明确收益。独立 base/head 探针中,base 接受过期 A 的请求并写入一笔账;head 对 A 连续两次返回 stale_goal_instance、不写账,而当前 B 首次写入、重试回放,最终仍只有一行。普通 alias 的首次写入/重试也保持一行。因此我认可这一 bounded owner 改造,不要求本 PR 完成整个 M3。但当前不能认定 quota owner 已完整 qualified。

改动思路

本轮重新阅读了完整 base-to-head 的 76 个文件,+3999/-370,没有把旧 head 377952efe 的结论直接迁移过来。相比上轮,QuotaAccountingOwner = alias | exact_source、在 identity inference 前过滤 runs/events、readback 的 current-owner admission,确实修复了之前的主要问题。

主链路是:CLI/Host 捕获 source GoalRef → Python 按 run-index、source guard 顺序持锁并交接 witness → TypeScript 验证 exact owner → 账本、receipt、readback 消费同一身份。既有 artifact transaction 继续负责 CAS、三种产物与 prepared repair;没有必要另起一个 quota provider 框架。alias persisted shape 需要保留,但“省略 GoalRef”必须表示 alias 分区,而不是任意实例的通配符。

具体改动

  • 入口传播:quota/monitor/action-selection/reward-memory/scheduler、Todo/event、Turn、agent context、refresh-state、MCP/host completion 传递 GoalRef 或 --goal-instance-id;settlement plan、interaction/recovery 命令继续携带原身份。
  • owning boundary:accounting_admission.py、source_admission.ts 复用 source lifetime owner;goal_ref_validation.py 抽出轻量输入验证,避免 strict-mypy 根引入整个 registry graph。Python 仍是传输/文件适配,current-owner 决策在 TypeScript。
  • 持久化和读取:spend/replay/void/artifact transaction 给 record、event、index、receipt、payload 一致盖章;settlement readback 和 prior-Turn recovery 在选择身份前筛选;rolling-window、heartbeat/native-child、checkpoint/external-delivery 也传递所属实例。
  • 配套:双语 RFC 更新 quota candidate,inventory 将 quota_settlement 标为 qualified,registry I/O census 随调用位置更新;新增/扩展的是上述真实边界的测试。无 UI 或安装面改动。

还有以下必须修复的具体缺口:

R1 · [P1] legacy fallback 仍把 exact 历史当成 alias 的记账依据。
位置:slot_accounting.py:403。

_latest_unspent_turn_settlement_run 只在 goal_ref is not None 时过滤;alias 调用会读取 exact A 的行。使用真实 preview → spend commit,固定合法 operator-gate safe-bypass decision,得到四组对照:空账本拒绝;legacy 交付允许;仅 exact A 交付也允许,并实际追加一条没有 GoalRef 的 alias 扣费;legacy 交付后追加 exact A 的 spend 又会让 alias 拒绝。后者由 foreign quota_slot_spent 提前 return None 引起。当前 38 项 slot-accounting 测试仍全绿,说明缺少 mixed-owner 反例。

请在任何分类、提前返回和交付选择之前执行与 typed owner 一致的双向分区:exact 只看相同 GoalRef,alias 排除所有 exact 行;覆盖上述两种相反方向,并把 durable commit/readback 纳入测试。不能只修主 readback 后保留这个 fallback 通配符。该项对应 #5206 的“历史不能授权/结算新身份”及本 PR 声明的 alias/exact 独立读取契约。

R2 · [P2] 辅助 monitor 将内部 admission 对象当成 wire request 重新解码。
位置:monitor_poll_commit.ts:580。

readAuxiliarySettlement 传入 source_admission: request.owner.admission;后者已经是内部的 registryPath/plannedGoalRef 对象,不再含 decoder 要求的 schema_version/profile_id/registry_path/planned_goal_ref。我用真实 Python 双锁 witness、source registry 和持久化 heartbeat receipt 调用 native monitor 边界:独立 settlement readback 先确认身份有效、状态为 writeback_required;alias auxiliary preflight 返回 provider_required,相同合法 exact-owner auxiliary preflight 却返回 quota_source_admission_invalid: quota source admission is malformed。这不是缺失结算身份造成的失败。

请复用已解析 owner 的内部 readback 接口,或保留/正确编码原始 wire projection(prior-Turn recovery 已有相邻模式),不要把两种结构混用;增加 exact auxiliary preflight、提交和 replay 回归。

R3 · [P2] monitor 的多阶段事务过早消费了 source admission。
位置:monitor_poll_commit.ts:2444,调用方:monitor_poll.py:826。

Python 的一次 admission 内按 preflight → provider → commit 复用同一组 witness;native 每个 phase 却使用会释放底层锁的 withQuotaAccountingOwner。真实 exact-owner preflight 返回 provider_required 时,两把 .ts-effect.lock 已不存在;仍在同一 Python context 中重用该 witness 立即得到 quota_source_admission_expired。这与 enclosing transaction 的持锁契约不一致。

请明确多阶段 owner,复用已经存在的 borrowed-admission 方式或等效的完整生命周期设计;验证 preflight 后 witness 仍有效、最终 commit/rejection/exception 后释放,并覆盖 retry。**边界说明:**保留所有生产门禁的完整 Python monitor 调用目前在 generic-registry 的 source-profile gate 停止,没有发生 provider 写入;我没有绕过门禁据此宣称线上 stale-write。这里是本 PR 新接入的 native quota 多阶段契约缺陷,应在 qualification 前修正,不是要求提前启用未 qualified provider。

对主干的风险

独立运行结果:

  • 83 项 focused Python 加 38 项 slot-accounting:121 passed。
  • 原五组 TypeScript 175 项,加 monitor/auxiliary 45 项:220 passed;control-plane typecheck 通过。
  • diff-driven standard premerge:direct checks、19 项选中的 canary/risk/public-boundary 检查通过。
  • 独立 base/head spend/replay 对照、mixed-owner durable accounting、真实 source admission/auxiliary readback 探针,得到上述明确结果。决策/receipt 输入为 synthetic;native quota、锁、registry、账本和回放没有 mock。完整 source provider journey 仍受既有 activation gate 限制,不能把内层验证说成已启用 CLI 全链路。

当前 CI 的两个 runtime fingerprint/readiness 失败,已在固定 base 和本 head 用同一命令独立复现:一项少了 first.ts 重读,另一项得到 runtime_exited_before_ready 而非 packaged_runtime_source_unstable;生产 owner 和相关测试均无 PR diff。它们属于 pre-existing unrelated,由 #5367 单独修复,pytest aggregator 的 cancellation 也不计作新 quota 缺陷。它们继续影响 merge readiness,但不是 R1–R3 的依据。

检查了 typed-state、domain-neutrality、default-change disclosure、guidance-vs-obligation 四个 lens:typed owner 是正确方向,没有新增 substring denylist 或业务领域专用义务;source identity 仍是强制条件,不是文字 guidance。默认 source activation hold 和 execution_authority: false 保留。风险集中在所有消费者是否真的遵守同一分区和锁契约,而非字段数量。

我的整体评价

REQUEST_CHANGES。 目标正向,主要 spend/readback 修复成立;当前阻塞不是需求收益不清,也不是“代码多所以不通过”,而是三个可重复的 owner-contract 缺口。修复 R1–R3 并增加 mixed-owner / multi-phase 回归后,再按新 exact head 复审。请同步校准 RFC/inventory 的 qualification 表述,不要把未完成的 monitor 契约包装成已验证完整覆盖;无须在此 PR 开启其他 M3 owner。

Future-facing pass:本 PR 已应用共享 source-admission owner 和轻量 GoalRef 验证抽取;剩余最有价值的 bounded 改进,是统一 fallback 的 owner 分区及复用现有 borrowed/raw-projection 接口。它们与本次修复同域、可局部测试和回滚,不需要新框架。更广泛的 Python/TypeScript owner 迁移留在既有边界之外。

English verdict: REQUEST_CHANGES - head bd4c465. The core stale-spend fence works, but alias fallback still consumes or is blocked by exact-owner history; exact auxiliary monitor re-encodes a decoded admission incorrectly; monitor preflight consumes locks needed by its next phase. Verified with real quota/lock/receipt boundaries, 121 Python tests, 220 TypeScript tests, typecheck and premerge. Source provider activation remains gated; no live stale provider write is claimed. The two red runtime CI cases reproduce unchanged at the immutable base and are separate merge holds.

@mergify

mergify Bot commented Sep 30, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @Duang777.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Sep 30, 2026
…wner-fence

# Conflicts:
#	loopx/semantics/project_registry_io_manifest_v1.json
Signed-off-by: duanjialing.777 <duanjialing.777@bytedance.com>
@Duang777

Copy link
Copy Markdown
Collaborator Author

Exact-head follow-up for 71d009d8ff1c03197752b7dacbcf3fce3a666319:

  • R1: alias settlement fallback now excludes exact-owner history before classification, with durable mixed-owner commit/readback regressions.
  • R2: auxiliary monitor readback reuses the parsed QuotaAccountingOwner instead of re-encoding an internal admission object as a wire request.
  • R3: the monitor preflight/provider/commit sequence now borrows one source admission across phases and releases it only after commit, rejection, exception, or replay.
  • RFC/inventory wording now distinguishes single-phase witness adoption from multi-phase borrowing and preserves the provider activation hold.
  • The quota CLI helper was tightened without changing the capture-before-hook boundary; the maintainability smoke passes.

Local verification passes: 118 focused Python CLI tests, 43 slot-accounting/inventory tests, 134 auxiliary-monitor/readback TypeScript tests, TypeScript typecheck, configured mypy over 19 roots, CI-scope Ruff, git diff --check, and standard premerge with 19/19 selected checks. The commit is signed off and was pushed normally; the untracked uv.lock was not modified or staged.

@cocolord @huangruiteng please re-review this exact head when available. No merge action was taken.

@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

DCO follow-up: the new fix commit 71d009d8f has a valid Signed-off-by trailer, but the check correctly found an older manual main-sync merge, cf8218d5f, without one. Because that commit is already in the published ancestry, resolving this requires either an approved history rewrite or a clean replacement branch/PR. I am not rewriting or force-pushing this branch. Functional CI continues on the exact head.

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

REQUEST_CHANGES — exact head 71d009d; immutable base f49b4a0. 全量复审;本次阻塞是 PR 自身的 DCO 提交缺口,不是无关红 CI。

动机

本 PR 交付 Goal-instance RFC 的 quota_settlement 候选闭环:同名 Goal 被替换后,旧实例的 delivery、spend、void 或历史 receipt 不能被新实例消费成额度效果。这个边界会在重试、恢复和后续轮次反复触发,不能只靠给单个 receipt 加字段解决。当前切片是有用的额度归属增量,不代表整个 source_session_v1 或父级 M3 已可激活。

改动思路

复用既有 GoalRef、first-party host 的 require_current 和文件 mutation-lock 所有者,TypeScript 持有判定与效果边界,Python 只传递规范身份及锁见证、执行 IO。legacy 的 alias 与 exact_source 是同一个额度 owner 的显式变体,不是两个平行决策框架。写入需要当前实例准入,历史回读则保持原实例身份且不产生新效果;candidate inventory 的 qualified 行不授予执行权限。没有新增用户设置、前端入口或 Lark 配置,现有 CLI、MCP 与 host 回读负责携带可选实例归属。

具体改动

本次按不可变 base 到当前 head 读取全部 78 个文件,并另外检查上次评审 head 后的修复,没有把 R1/R2/R3 消失直接当成整 PR 批准。变化包括额度写入事务和读模型、checkpoint/monitor/recovery、CLI/host/MCP 参数传递、status/native-child 历史过滤,以及双语 RFC、绑定 inventory 和耐久负例。

关键代码讲解

  1. loopx/control_plane/quota/source_admission.ts:268 的 withQuotaAccountingOwner 将已持有的 source/run-index 见证接入原有 require_current,再进入事务;GoalRef、路径、角色、PID/token 不一致不能获得额度效果。
  2. 同文件 :349 的 withBorrowedQuotaAccountingOwner 只释放临时 native claim,不提前释放 Python 的外层锁。monitor 的 preflight、provider、commit、replay 因而仍处于同一归属边界,这是上次 R3 的关键修复。
  3. loopx/control_plane/quota/settlement_readback.ts:1210 的 readQuotaSettlementForAdmittedOwnerFromSnapshot 接收已经解析的 owner,避免 auxiliary monitor 把内部 camel-case 对象当 wire admission 重新解码。规范历史先按 owner 过滤,再推断 settlement。
  4. loopx/control_plane/quota/slot_accounting.py:384 的 _latest_unspent_turn_settlement_run 在 classification 和提前返回前排除其他实例,关闭 R1 的 Python fallback;alias 仅接受没有 GoalRef 的 legacy 行,不能吞掉 exact 历史。

对主干的风险

[P2] 修复 PR-only 手工合并提交的 DCO。 cf8218d5f 仍位于当前 origin/main..71d009d8ff1c03197752b7dacbcf3fce3a666319,没有有效 Signed-off-by,也不是 GitHub 生成的集成合并。按 .github/workflows/dco.yml 当前规则逐条独立检查后,仅此提交失败。另一条无 trailer 的 70c7457 经 API 验证为签名有效的 web-flow 两父集成合并,满足明确豁免,不作为问题。最小修复是作者按获授权的历史修复或干净签署替代流程认证该手工提交,再运行贡献范围 DCO 检查、提交新精确 head;追加一个带签名的无关提交不能认证旧 merge。本评审不改写或 force-push 作者分支。

亲测当前 head 的 116 项 Python、221 项 native TypeScript、TS typecheck、配置内 19 个 source 的 Mypy、57 个变更 Python 文件的 Ruff、diff check 通过。同输入公共 CLI 的 base/head 对照也通过:未验证前拒绝、写回结果后只扣一次、重复结算不追加、legacy 不输出 GoalRef。过期锁分支的历史原实例回读未形成新实例写入证据,不列为缺陷。测试用隔离 synthetic registry、物理锁和真实 native/CLI,未操作活跃 Goal;不宣称完整 PostgreSQL、外部子进程 drain 或 source profile 部署已验证。

语义与 CI 对齐

这里复用既有 GoalRef,额度 owner union 是局部显式分类,不引入泛化 actor 生命周期或 prose 判定。development advisory 在 58 个变更 source 路径上没有检测到支持的 vocabulary carrier,但它不覆盖所有 TS union 或动态构造;另跑完整语义与 registry IO 漂移 smoke 通过。source_session_v1 的 execution_authority=false 与 activation hold 保留。未查询、轮询或等待远端 CI;DCO 结论来自当前 PR 精确提交范围的本地检查和集成合并来源验证,不是根据 CI 颜色推测。

我的整体评价

当前配额切片对长期重试与替换归属有正向价值,普通 legacy 用户结算路径在同输入对照中保持一致;不增加重复填写或额外人工确认。未来向简化检查认可既有 typed owner、borrowed-lock seam 和轻量 IO 验证,未发现需要另加框架的理由。但一条真实的 PR-owned DCO 缺口尚未满足仓库贡献义务,因此保持 REQUEST_CHANGES,修复后对新 head 重审。以上是额度候选的阶段判断,不关闭父级验收、不激活 source profile,也不自合并运行时改动。

English verdict: REQUEST_CHANGES — The runtime fixes are supported by current local validation; certify the PR-only manual merge cf8218d under the repository's DCO rule and return a repaired exact head. No unrelated red CI is used as a blocker.

@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 1, 2026
@Duang777

Duang777 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Clean DCO replacement: #5389 at f2b154547671d0cb9230cb371ab99b49846a30eb is based directly on main@f49b4a00870604d39fa4318da24d6dd35e72bb6e and contains one signed commit. Its tree, a451f7a95aad8b29a918b8de56f607ee12ac60ff, is identical to this PR's reviewed exact head 71d009d8ff1c03197752b7dacbcf3fce3a666319. No force push, merge, or close action was taken here; this PR remains open as the review record.

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.

3 participants