Skip to content

fix(quota): unify scoped gate fallback under typed dependency rules - #4253

Merged
huangruiteng merged 3 commits into
mainfrom
codex/typed-scoped-gate-fallback
Sep 12, 2026
Merged

huangruiteng merged 3 commits into
mainfrom
codex/typed-scoped-gate-fallback

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Close the scoped User-gate fallback slice of TS RFC T3 in the existing decision-scope owner: eligibility, ordering, deduplication and dependency selection. Python retains source adaptation and compact presentation.
  • Remove the Python token-overlap gate matcher and selection loop. Explicit links/scopes and global gates take precedence; equal legacy action keys remain conservative blockers. Different or missing labels do not prove independence.
  • Address both P1 review findings: migrate the two shared behavior fixtures to explicit first-screen scope without weakening their execute oracles, and reuse the existing schema-aware nullable projection decoder rather than leaking an unvalidated runtime result.
  • Add real CLI unknown-relation hold coverage across Markdown, File and SQLite, plus malformed/null runtime-response tests. Preserve the bilingual RFC execution cards and remaining migration boundaries.

Behavior and architecture

This intentionally changes legacy heuristic-only fallback: an unscoped gate can now withhold work previously offered on the basis of different words. It does not remove, retarget or expand a User gate, grant permission, promote a provider, or change notification policy. Explicitly independent work still proceeds; unknown relations fail closed even when labels differ.

The existing typed decision-scope owner is sufficient. The future-facing pass removes duplicate business knowledge and reuses the established decoder; no new module, provider or recovery framework. Prose tokenization used for unrelated lesson warnings remains outside gate authority. This closes one T3 consumer, not all T3, T1/T2 or D1–D3 qualification.

Review refinement and validation

Tested head: 48e5a8168abab5cd017a21de37870d47cd8ba673. Rebased after #4252; all source edits below were validated before the final signed commit, with no later source edits.

Check Result
Strict configured mypy Passed, 22 source files; no cast or ignore added.
Ruff / TypeScript typecheck / diff hygiene Passed for changed Python paths / entire control-plane project / final diff.
CLI, decoder, tool behavior and portfolio 71 passed, including the two shared fixtures responsible for the original four CI shard failures.
Adjacent gate, consistency and replan 40 passed.
Full TypeScript control-plane suite 1,195 passed, zero failed; one environment-gated PostgreSQL placeholder skipped.
Actual PostgreSQL integration 46 passed, zero failed/skipped, on disposable isolated PostgreSQL 16.15; independently covers the skipped backend.
Real quota entrypoint Nine Markdown/File/SQLite cases: explicit target precedence, structural independence and unknown-relation hold; canonical state unchanged and missing display not recreated. Included in the 71 tests above.
Public/private scan Clean across all 15 changed files. Unrelated registry-state warnings do not concern the public diff.

Run state: finished for the checks above. Current qualification inputs: synthetic and public fixtures. The earlier PR revision also used an authorized read-only snapshot: baseline/head compared ten lanes on legacy and File sources, finding one intentionally more conservative hold in each arm and nine unchanged. That historical rehearsal was not rerun for this refinement; it is not exact-head private three-arm parity. PostgreSQL evidence here is independent synthetic conformance. No active Goal was promoted or mutated, and no paid model qualification or live automation soak was performed.

Premerge executed all 18 catalog/risk/boundary checks and four direct checks successfully. Its initial overall result was rejected only because an unrelated dashboard merge advanced the base during execution and made the receipt stale. The PR diff is byte-identical against the new base; it was re-reviewed and requalified without repeating unchanged tests.

Refreshed exact-scope receipt: cqr_8294625ee9761bb66446 for 15 files. Fingerprint: 8294625ee9761bb6644658d447b1a714733135ab69d3bdb75d2e7911b21cf337. One bounded safe-fix pass; zero unresolved quality blockers. Final readback and merge decision are recorded in the review response.

Compatibility and boundary checklist

  • Breaking semantic correction is disclosed: missing structural dependency is not permission for fallback.
  • Shared production-scale fixture schema is unchanged. Two durable scenario instances now state their intended scope explicitly; execute assertions are retained. Unknown scope has a separate hold oracle.
  • Real provider checks do not assert default promotion or production migration readiness.
  • No credentials, private snapshots, raw logs, internal links or local machine paths are included.
  • All commits are signed off. Target branch is main; no unrelated main history is included.

@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:1ff5ede19e7fe283aadeb40d73ddbfc0c7f143cc。结论:REQUEST_CHANGES。

动机

这个 PR 修的是一个重要的 authority 缺陷:旧 fallback 会根据 action_kind 的英文 token 是否重叠来猜两个 Todo 是否独立。不同语言、同义词或宽泛标签都会让这种猜测产生 false positive/negative,而“看起来不相关”不能成为绕过 user gate 的机器证据。

改成 exact dependency、decision_scope 与 global_gate 等结构化关系优先是正确方向;equal legacy action key 可以继续作为保守 blocker,但不同或缺失 label 在没有结构证据时应该 fail closed。这个 breaking behavior 也已经在 PR body 中披露。

改动思路

decision_scope.ts 现在拥有 relation 与 fallback selection,agent_scope.py 不再维护 prose overlap authority,只把 legacy Todo facts 交给 typed owner 并解码结果。selection 仍只在 already-eligible Todos 中选择,不会创建权限、改写 gate 或 author dependency。

问题在于这次规则迁移没有覆盖仓库中已有的 durable behavior scenarios。新 helper tests 证明新规则本身,但原来的真实 quota/tool fixture 只有不同的 action_kind,没有 unblocks_todo_id 或非覆盖的 decision_scope,却仍断言 successor 会执行。按新语义它现在必然 hold,所以必须逐条决定这些场景究竟是“真实独立、补结构关系”,还是“关系未知、把 oracle 改成 hold”。

具体改动

真实 base fa57253a7888a33eb98b3b6d49d69726f54e5034 到 head 为 12 个文件、+369/-108。核心是 decision_scope.ts 的 typed selection、缩薄后的 Python adapter、focused tests 和 breaking-change disclosure。

我在 exact head 上运行了 21 个 focused Python tests 与 6 个 focused TypeScript tests,共 27 passed。exact base/head 对照运行 test_gate_notice_plus_executed_successor_proves_non_blocking_semantics:base 通过,head 以 qualification_passed=false 失败。该 fixture 的 gate 是 approve_product_first_screen,successor 是 quality_hardening,但二者没有结构 dependency/scope;这正是新规则不再允许仅凭文案判定独立的兼容迁移点。

此外,base mypy 有 7 个既有错误,head 有 8 个;新增的是 loopx/control_plane/todos/decision_scope.py:240 的 no-any-return:声明返回 dict[str, Any] | None 的函数直接返回 _evaluate() 的 Any。因此这不是可以归到 baseline 的静态错误。

对主干的风险

  1. [P1] durable scoped-gate scenarios 尚未迁移。 当前四个 required Python shards、aggregate 和 merge gate 都是红的。请逐个分类失败场景:如果 successor 确实独立,就补明确的 unblocks_todo_id 或非覆盖 decision_scope 并保留 execute oracle;如果关系未知,就把场景改成期望 hold。不要为了让旧测试变绿而恢复 label/token heuristic。

  2. [P1] 新 adapter 引入 mypy regression。 decision_scope.py:240 需要在返回前把 effect runtime 的结果收窄为 mapping/None,或复用现有 typed decoder;不能把 Any 直接从 typed API 漏出去。

Future-facing pass:typed decision_scope 是正确且足够的 owner。后续重点应该是让 Todo authoring/fixtures 能明确地产生结构关系,并保留一对真实 public-entrypoint regression:显式独立必须 execute,关系未知即使文案不同也必须 hold。

我的整体评价

我支持删除 lexical authority,也认可 conservative hold 的新默认;但 breaking migration 必须把现有行为组合和静态契约一起收敛。当前 focused helper tests 不能覆盖全部真实 caller,required matrix 的系统性失败说明 exact head 尚未达到可合并状态。

English verdict: REQUEST_CHANGES on exact head 1ff5ede19e7fe283aadeb40d73ddbfc0c7f143cc. Moving gate fallback to typed structural relations is the right authority model, and 27 focused tests pass. But the exact head leaves durable quota/tool scenarios on legacy label-only facts, causing all four required test shards and the merge gate to fail, and it adds a new mypy no-any-return error at decision_scope.py:240. Migrate each real scenario to explicit structural independence or an intentional hold oracle, narrow the adapter result, and rerun the full required matrix.

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/typed-scoped-gate-fallback branch from 1ff5ede to 48e5a81 Compare September 12, 2026 04:20
@huangruiteng

Copy link
Copy Markdown
Collaborator Author

Review follow-up — both P1 findings addressed

Reviewed head: 48e5a8168abab5cd017a21de37870d47cd8ba673.

  1. Durable behavior scenarios: the first-screen approval gate in both shared fixture builders now explicitly declares write_scope:action:first-screen. Their independent quality-hardening successor still must execute; the existing execute/notice/anti-bypass oracles were not weakened. Real quota should-run tests separately prove that unknown scope holds even when action labels differ, across Markdown, File and SQLite. No lexical independence heuristic was restored.
  2. Typed adapter: the fallback result now uses the existing schema-aware _projection decoder, accepting its own versioned mapping or explicit null and rejecting malformed or wrong-schema results. _evaluate remains object; no cast or type: ignore. Strict configured mypy passes for 22 source files.

No remaining actionable blocker found in this review. The motivation and placement remain sound: dependency authority cannot be inferred from prose, and the existing typed decision-scope owner is sufficient. Python handles source facts and presentation, not a second selector. The future-facing pass was applied through deletion/reuse rather than adding a framework. Unknown legacy relations intentionally become conservative holds; this compatibility change remains documented in the protocol, bilingual RFCs and PR body. It grants no permission, changes no default provider and does not promote an active Goal.

Exact-head evidence

  • 71 Python tests passed across real CLI, runtime decoder, tool behavior and portfolio scenarios, including both previously failing shared-fixture consumers.
  • 40 adjacent gate/consistency/replan tests passed.
  • Full TS suite: 1,195 passed, zero failures, one environment-gated PostgreSQL placeholder skipped. Independent disposable PostgreSQL 16.15 suite: 46 passed, zero failures/skips.
  • Ruff, TS typecheck, strict mypy and diff hygiene passed. Public-boundary scan is clean across all 15 changed files; unrelated local registry warnings are not source-diff failures.
  • Refreshed exact-scope quality receipt cqr_8294625ee9761bb66446. Fingerprint 8294625ee9761bb6644658d447b1a714733135ab69d3bdb75d2e7911b21cf337; 15 files; safe fix allowed/applied once; zero unresolved blockers/warnings/advisories in the quality review.

The historical private snapshot rehearsal in the body is explicitly identified as prior-revision evidence, not an exact-head rerun or private PostgreSQL three-arm claim. No live automation soak or paid-model qualification was run. This bounded read-policy refinement is covered by public production-entrypoint tests, complete TS tests and isolated real backend checks; it does not alter provider transactions or migrations.

Premerge executed 18/18 catalog, risk and boundary checks plus 4/4 direct checks successfully, including the previously failing hot-path budget check. The initial overall gate rejected a stale receipt when an unrelated dashboard PR advanced main during execution. The PR diff was checked byte-identical against the updated base and re-reviewed; the receipt was refreshed rather than rerunning unchanged tests. This is not a claim that the initial overall gate passed.

Final receipt verification returned valid; a non-executing premerge recheck also accepted the refreshed quality receipt (preview_only, not another test execution). Merge decision: owner-authorized self-merge after this refinement and risk-based validation; do not wait for the entire new hosted CI run. No manual product/authority hold remains. Hosted CI status is separate from the passing local checks above.

@huangruiteng
huangruiteng merged commit 72e5575 into main Sep 12, 2026
21 checks passed
@huangruiteng
huangruiteng deleted the codex/typed-scoped-gate-fallback branch September 12, 2026 04:25
huangruiteng added a commit that referenced this pull request Sep 16, 2026
…rotation fixture

The showcase fixture gave its Gate and agent Todos no structural scope, so the
typed fallback owner could only compare legacy action_kind labels. Since #4253,
distinct labels no longer prove independence and a missing scope is
projection_repair_required, so the fixture stopped exercising the scoped
user-gate safe bypass it documents.

Give the Todos stable todo_ids and let the Gate target the ALE lane explicitly,
then assert the same fixture stays unproven when that link is removed so the
rule cannot be relaxed back to label matching.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng added a commit that referenced this pull request Sep 16, 2026
…rotation fixture (#4491)

The showcase fixture gave its Gate and agent Todos no structural scope, so the
typed fallback owner could only compare legacy action_kind labels. Since #4253,
distinct labels no longer prove independence and a missing scope is
projection_repair_required, so the fixture stopped exercising the scoped
user-gate safe bypass it documents.

Give the Todos stable todo_ids and let the Gate target the ALE lane explicitly,
then assert the same fixture stays unproven when that link is removed so the
rule cannot be relaxed back to label matching.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Co-authored-by: huangruiteng <14976749+huangruiteng@users.noreply.github.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.

1 participant