Skip to content

issue_fix: borrow MAINTAINER_ASSOCIATIONS from github_public - #8613

Merged
huangruiteng merged 2 commits into
loopx-project:mainfrom
psychologister:codex/issue-fix-maintainer-association-owner
Nov 13, 2026
Merged

huangruiteng merged 2 commits into
loopx-project:mainfrom
psychologister:codex/issue-fix-maintainer-association-owner

Conversation

@psychologister

Copy link
Copy Markdown
Contributor

What

issue_fix/candidate_evidence.py kept a private _MAINTAINER_ASSOCIATIONS = {"COLLABORATOR", "MEMBER", "OWNER"}. It now borrows MAINTAINER_ASSOCIATIONS from github_public.py, which pr_lifecycle.py already imports. github_public is a leaf module (stdlib only), so this introduces no import cycle.

Guard

New tests/architecture/test_issue_fix_maintainer_association_owner.py:

  • whole-tree member-set census (folds set/frozenset/list/tuple literals, so a renamed restatement is caught, not just the original name);
  • identity for both consumers + retirement of the private name;
  • an AST reader check (loads the borrowed name, binds neither);
  • a behavioral truth table through _normalise_comment_signal with timing held fixed, so association membership — not the clock — is what flips the signal.

The four-member TypeScript reviewer set (adds CONTRIBUTOR) is a different question and is left alone.

Tests

Guard + issue_fix focused tests + turn-executor integration pass locally; the census is poison-proven.

candidate_evidence drops its private restatement; a new architecture guard pins the single owner.

Signed-off-by: psychologister <230141834+psychologister@users.noreply.github.com>

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

Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max

本次评审对应提交 0932a4151ded8393175196436ca46c3783fde554。

[P2] 把 maintainer association 检查对准候选入口。 全包 AST 检查会拒绝无关的有序展示标签。隔离候选分支额外接受 CONTRIBUTOR 后,新增检查全部通过,真实候选构建器却收录了该评论修订。

动机 / Motivation

执行 issue-fix 候选预检的用户和维护相关权限判断的贡献者。候选预检和 PR lifecycle 持有相同三成员规则,候选端另有本地副本。基线与当前头对六类 association 的候选证据完全一致。三个成员产生当前评论修订证据,缺少 updatedAt 时拒绝。其他三类均不进入证据。基线与当前头对六类 association 的候选证据完全一致。三个成员产生当前评论修订证据,缺少 updatedAt 时拒绝。其他三类均不进入证据。证据来自隔离本地构建器与合成 provider 评论。未查询远端 CI,也未执行 live GitHub 候选采集。全包 AST 检查会拒绝无关的有序展示标签。隔离候选分支额外接受 CONTRIBUTOR 后,新增检查全部通过,真实候选构建器却收录了该评论修订。

改动思路 / Approach

两个调用方共享现有 owner 是直接的复用方式。当前生产改动的归一化、修订与结果 shape 保持原行为。新增检查的作用域需收回到该 owner 的实际契约。 候选预检引用 github_public 已有的 MAINTAINER_ASSOCIATIONS,PR lifecycle 也引用同一个集合。修订读取仍在实际构建器里,适合在那里验证过滤和失败语义。

具体改动 / Changes

关键代码讲解

  • 候选构建器按原规则归一化 authorAssociation,再用共享集合筛选评论。合格评论仍必须提供当前 updatedAt。 候选入口
  • 新测试确认对象身份和 AST Load,另遍历 loopx 下的 Python 文件,匹配三标签字面量集合。这里缺少标签用途和实际调用范围。 全包扫描
  • 精确基线与当前头的完整预检结果相同。OWNER、MEMBER、COLLABORATOR 提供当前评论修订,其他三类均过滤。缺失修订的成员仍走同一拒绝。 候选证据契约

采用 docs/development/README.md @ ea67e68 的 Scope-Fit Review。single_issue_fix_owner 与 current_comment_revision_parity 已满足,behavior_sensitive_guard 由两项反例判定未满足。 Scope-Fit Review

对主干的风险 / Risks

全包约束会把无关的有序显示标签变成新的测试失败。隔离 mutation 保留共享常量的引用,同时额外放行 CONTRIBUTOR,新增检查均通过,实际候选构建器已把该评论修订收进证据。这一扩权只发生在故意修改的测试模块。精确头的构建器保持六类输入的原有判断。

语义与 CI 对齐

133 项候选、GitHub 编码、PR lifecycle 与执行器相关测试及 20 项新增架构测试通过。另在隔离测试中复现两个 guard 反例。Ruff、DCO 和 git diff --check 通过。未查询远端 CI 或执行 live GitHub 候选采集。

我的整体评价 / Verdict

保留生产代码的共享 owner。请收窄新测试的静态作用域,并让实际候选入口的测试拒绝扩大的成员集合且保留当前修订校验。完成后可复审该测试边界。本次评审覆盖现有宿主与 CLI 行为。证据来自隔离本地构建器与合成 provider 评论。未查询远端 CI,也未执行 live GitHub 候选采集。

English verdict: REQUEST_CHANGES. Keep the shared constant. The package-wide guard rejects unrelated display labels and misses a deliberate expansion of the candidate predicate.


def test_only_the_owner_states_the_maintainer_association_set() -> None:
offenders: dict[str, list[int]] = {}
for path in sorted(PACKAGE_ROOT.rglob("*.py")):

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.

[P2] 把 maintainer association 检查对准候选入口。 这个全包扫描按三个字符串的集合匹配。隔离 fixture 中,普通的有序展示标签 ('OWNER', 'MEMBER', 'COLLABORATOR') 会使该测试失败。反过来,在候选构建器加上 or association == 'CONTRIBUTOR' 后,新增静态检查和 owner 真值表全部通过,构建器却将该评论及修订纳入 maintainer evidence。请把检查约束到 issue-fix 的实际消费点,并经候选构建器断言非成员与缺失修订的行为。

Addresses the CHANGES_REQUESTED review on the maintainer-association single-owner
guard. The production single-sourcing is kept exactly as reviewed: candidate_evidence
and pr_lifecycle still borrow github_public.MAINTAINER_ASSOCIATIONS, unchanged.

Two test-only fixes:

The static census was package-wide, so any unrelated ordered display label elsewhere
in loopx that lists ("OWNER", "MEMBER", "COLLABORATOR") would be swept as a false
offender. Its scope is narrowed to loopx/capabilities/issue_fix -- the capability that
owns the contract (the owner plus its two consumers) -- so a renamed restatement inside
the capability is still caught while unrelated tuples outside it are out of scope.

The behavioural evidence only exercised github_public._normalise_comment_signal, not
the candidate gate, so a deliberate `or association == "CONTRIBUTOR"` expansion at
candidate_evidence.py's maintainer filter passed every static check and the owner truth
table. A new truth table drives the real builder
build_public_github_candidate_preflight_input with synthetic provider comments: the
three members produce maintainer evidence at their current updatedAt revision, a
non-member (notably CONTRIBUTOR) produces none, and a member comment with a missing or
empty updatedAt is rejected. Mutating the gate to admit CONTRIBUTOR fails exactly the
non-member case while the census stays green, confirming the guard is now
behaviour-sensitive at the real consumption point. The signal-normalizer table,
identity, AST-reader and poison controls are retained.

Refs loopx-project#4447.

Signed-off-by: psychologister <230141834+psychologister@users.noreply.github.com>

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

Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max

复审提交 cbb8a257c7436f2a58bcbf3d4297d6a771f51516。上轮两项发现均已验证解决。本轮无阻塞发现。

动机 / Motivation

运行 issue-fix 候选预检的贡献者,需要知道哪条维护者评论会要求先核验,再继续补丁。 旧版在候选预检和评论采集各维护一份成员集合。当前提交共用已有集合,成员的当前修订、非成员过滤及缺字段错误保持一致。 我对照主干与当前提交的 11 组候选输入和 18 组评论时序,两边完整输出一致。把 CONTRIBUTOR 故意放进候选条件后,新测试抓住了这次扩张。 证据来自源码预检、合成 GitHub 评论及主干试合并。实时 GitHub 采集、整仓和托管 CI 未执行。

改动思路 / Approach

生产改动限候选预检借用现有常量,测试覆盖 issue-fix 域内的共享规则与两个实际读取入口。 把集合留在 GitHub 输入 owner,两个入口保留各自的时序和修订校验。 原来两份集合遇到策略调整需要同步。候选预检只换引用,公开回复仍以发帖时间和锚点为准,PR lifecycle 仍按已验证评论和修订处理。新增测试直接跑真实候选构建器,也约束共享规则只在所属能力内定义。

具体改动 / Changes

关键代码讲解

  • current-comment-revision。候选构建器先规整 association,再通过共享成员集合筛选。OWNER、MEMBER、COLLABORATOR 以及带空白的 owner 都输出当前评论 URL 和修订。 CONTRIBUTOR 与未知身份不进入证据。成员缺 updatedAt、缺 association、重复 URL 或缺 URL 保持原拒绝。 候选预检分支
  • shared-owner-parity。公开评论归一化和 PR 生命周期继续读取同一对象。在公开回复入口,三个维护者身份只有晚于锚点的其他评论才产生信号,正文未进入投影。 公开回复投影 生命周期读入
  • regression-sensitive-guard。在独立副本加入同标签的域外显示元组,静态检查通过。扩张候选条件后 CONTRIBUTOR 用例失败,两个普通非成员用例依旧通过。保护条件在候选构建器上生效。扫描范围 候选反例

契约依据为 loopx/capabilities/issue_fix/README.md,版本 167b0a1。按相同提交的 Scope-Fit Review 核对了验证作用域、现有调用方和可证伪性。候选证据契约 Scope-Fit Review

对主干的风险 / Risks

运行时仍只把具备当前修订的维护者评论作为候选证据,审批关闭路径的另一组成员规则保持其独立用途。最直接的风险是普通评论被当作维护者输入,或测试误拦同名展示标签。两项针对上轮发现的反例均已覆盖。精确头 56 项、最新主干 33 项、试合并 65 项相关测试通过。源码与 GitHub 的改动路径一致,Ruff、DCO、diff 检查和 RFC 双语门通过。 架构测试的 fixture 仍有合并空间,现有反例已足以保护变更。

我的整体评价 / Verdict

批准当前提交。共享规则归属明确,候选证据和回复时序的原有语义得以保留。未来若调整评论来源字段,应继续在现有预检验证修订和失败回执。证据来自源码预检、合成 GitHub 评论及主干试合并。实时 GitHub 采集、整仓和托管 CI 未执行。 本次评审只判定代码和当前行为。

English verdict: APPROVE. The scoped guard now leaves unrelated display labels alone and catches an expanded maintainer predicate at the real candidate builder. The exact head preserves comment-revision and reply-timing behavior against main.

@huangruiteng
huangruiteng merged commit 55ca4e4 into loopx-project:main Nov 13, 2026
33 of 38 checks passed
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