Skip to content

docs(catalog): add IP-035 install ownership is not an update permission - #4657

Merged
huangruiteng merged 1 commit into
loopx-project:mainfrom
Chumaniac:docs/ip-035-catalog
Sep 17, 2026
Merged

huangruiteng merged 1 commit into
loopx-project:mainfrom
Chumaniac:docs/ip-035-catalog

Conversation

@Chumaniac

Copy link
Copy Markdown

Goal And Delivered Outcome

  • Goal/source and gap: GH-C37 asks for one new public-safe good/bad case in the
    interaction pattern catalog. The catalog had entries for missing write-scope
    projection (IP-006), revision-guarded configuration apply (IP-030), connector
    runtime boundaries (IP-028), and manager-context retention (IP-031), but no
    entry for the case where the write target itself has a different owner than
    the caller
    : an install LoopX does not own. loopx/self_update.py already
    classifies install_kind / owner / loopx_apply_supported and fails closed
    with next_action.kind=use_installation_owner, and
    tests/test_self_update_runtime_activation.py already pins the mutation
    cases, but no concept told a controller or agent that requires_upgrade=true
    is not permission to pick an installer.
  • Observable before → after, with the validation row that proves it: before, the
    catalog has no IP whose agent channel says "classify the install, then hand
    back the owner-owned command"; after, IP-035 Install Ownership Is Not An Update Permission states the classify-then-mutate rule, the fail-closed
    unsupported_install_owner behavior, and the mirror-image smell of reporting
    success without writing. The static and real_entrypoint rows below prove
    the entry is structurally complete (row, detail heading, single-family
    listing) while leaving production behavior untouched.
  • Issue/task and intended base: Closes #4656 (GH-C37), base main.

Scope And Continuation

Validation

  • Tested revision: e179c61b9 (branch docs/ip-035-catalog)
  • Run state: finished
  • Input classes: none
Check kind Result Public-safe evidence / limitation
static passed python3 examples/interaction-pattern-catalog-smoke.py → interaction-pattern-catalog-smoke: ok. Structural check asserts one table row per IP-\d{3}, a matching #### IP-035 detail heading, no orphan detail, and no id listed under two families.
real_entrypoint passed loopx check --scan-path docs/concepts/interaction-pattern-catalog.md → ok: True, errors=0, checks=3, public boundary scan clean: 1 files.
unit not_run Not required: no code or test changed. The five referenced tests in tests/test_self_update_runtime_activation.py are cited as the independent oracle for the entry's claims and were not modified.
  • Coverage and gaps: the changed path is a single documentation file, so the
    structural smoke plus the repository contract check cover it end to end. The
    two warnings in the loopx check output (registry file does not exist)
    are environmental, come from a checkout without .loopx/registry.json, and
    are unrelated to this change. Untested path: the mermaid diagram is rendered
    by the docs pipeline and was verified only as text, not visually. Follow-up
    gap identified above: no CLI-level assertion yet exists for an install whose
    owner command is None.

Frontend / Visual Evidence

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

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring (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 (providers, adapters, skills)
  • Public docs or presentation surface (README, protocols, dashboard)
  • Build, packaging, installer, or CI
  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference, when applicable: Architecture and research
    incubator; GH-C37 interaction-model catalog curation.

Shared-authority RFC fixture impact

  • Production-scale fixture schema: N/A
  • Semantic dimensions changed, or reviewed no-impact rationale: no semantic dimension changed; no fixture or production code touched
  • Provider conformance arms run: N/A
  • Read-only legacy/file/PostgreSQL three-arm rehearsal: N/A

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths (including .loopx/, .codex/goals/, and live ACTIVE_GOAL_STATE.md).
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

Add a State And Boundary entry for the case where the write target has a
different owner than the caller: an install LoopX does not own.

- name the classify-then-mutate rule over install_kind, owner,
  loopx_apply_supported, and owner_upgrade_command
- pin the fail-closed unsupported_install_owner behavior: no pip guess,
  no git pull on a live checkout, no archive snapshot replacing a checkout
- record the mirror-image smell of reporting success without writing
- reference loopx/self_update.py::_install_lifecycle and the four existing
  mutation tests in tests/test_self_update_runtime_activation.py

Refs GH-C37

Signed-off-by: Chumaniac <121109854+Chumaniac@users.noreply.github.com>

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

Reviewed exact head: e179c61b90b3c1f4545f834297783ffeba60bb63 (docs/ip-035-catalog, docs only).

动机

Catalog 已经有「写作用域没被投影出来」(IP-006)、「按 revision 保护配置 apply」(IP-030)、「connector 运行时边界」(IP-028)、「manager context 不等于 turn 授权」(IP-031) 这几条,但缺一条最常见的边界:写入目标本身的 owner 不是调用方——也就是 LoopX 并不拥有的那份安装。缺少这条概念时,agent 看到 requires_upgrade=true 会直接挑一个自己最熟的安装器去改(pip install --upgrade loopx、pipx upgrade、git pull),结果是在另一个环境里装了第二份 LoopX、或者把 source checkout 静默换成了 archive snapshot。这个动机成立:填的是 catalog 里一个真实空缺,且与 #4656(GH-C37) 的既有验收描述一致。

改动思路

只加一条公开安全的 catalog 条目,复用已有的三段式结构,而不是新建文档或新 smoke:family 表新增一行、Pattern-To-Canary matrix 的 State And Boundary 行补上 IP-035、正文新增 #### IP-035 详情段(Trigger / Expected behavior 三条规则 / 与 IP-006、IP-030 的 sibling 边界说明 / mermaid 视觉模型 / Bad smell / Validation)。编号选择也说明清楚了:IP-034 属 #4641,尚未合并,所以本条取 IP-035,谁先落谁负责重编号。这个粒度是对的——issue 只要一个 good/bad case,PR 就只给一个 case,没有顺手改生产代码。

具体改动

1 个文件、+95/-1:

  • matrix 行(第 91 行):State And Boundary 家族补 IP-035,并把 signal 列表加上 install ownership。
  • family 表行(第 346 行):P1 | IP-035 | Install Ownership Is Not An Update Permission,user channel 写「不静默变更,报出所属安装器及其命令」,agent channel 写「先分类再变更;LoopX 不拥有时交还 owner 自己的命令,不切换安装通道」。
  • 详情段(第 2423 行起):三条规则分别对应 install_lifecycle 分类、loopx_apply_supported=false 时的 fail-closed(ok=false、commands.apply=None、changes_applied=false、next_action.kind=use_installation_owner),以及交还 owner_upgrade_command 后停止;bad smell 里额外写了镜像错误——把 apply=None 渲染成「更新完成」。

我复核的关键点:

  • 条目引用的生产标识确实存在:loopx/self_update.py:706 的 next_action.kind=use_installation_owner、:967 的 execution.status=unsupported_install_owner,以及 _install_lifecycle 里的 install_kind / owner / loopx_apply_supported / execution_driver 分类。
  • python examples/interaction-pattern-catalog-smoke.py → ok;python examples/docs-governance-smoke.py → ok。
  • pytest tests/test_self_update_runtime_activation.py -q → 20 passed, 1 skipped,fail-closed 的负例(commands.apply is None、commands.owner_upgrade is None、next_action.command is None、无 pip install 猜测、无 git pull、changes_applied is False)都在。
  • 结构检查确实覆盖了这条目:一个 IP-\d{3} 一行、一个对应 #### IP-035 详情标题、无孤儿详情、无 id 跨家族重复。

遗留问题(非阻塞,P3)

条目正文点了两个机器可见标识符(next_action.kind=use_installation_owner、状态 unsupported_install_owner),但没有任何测试断言它们。我在这个 head 上全仓搜索这两个字符串,命中只有生产实现本身和这条 catalog 条目:tests/test_self_update_runtime_activation.py 断言的是 fail-closed 的 payload(apply、owner_upgrade、next_action.command 为 None,改动未生效),Windows 分支断言的是 execution.status == "unsupported_platform",都不是 unsupported_install_owner。也就是说,行为有护栏,但条目点名的两个字段名一旦被改名或写错,不会有测试失败。

最小修法(任选其一):在条目里直接写出生产行号(loopx/self_update.py:706 / :967),或给 tests/test_self_update_runtime_activation.py 加一条对 next_action.kind 与 unsupported_install_owner 状态的断言。这不阻塞合并:catalog 是散文,结构 smoke 本来就不校验每条断言的真假,而缺口已在 PR body 里如实披露。

对主干的风险

纯文档,无运行时行为、无权限边界、无持久化契约改动,回退成本就是一个 commit。catalog 是 agent 读的机器可读概念面,所以唯一实质风险是「条目说了不成立的话」,而我核对的两处标识符与失败关闭路径都成立。另两个已披露的残余:mermaid 只做了文本校验、未做视觉校验;「没有 owner 命令时应当……」(next_action.command=None)的 CLI 级断言被明确记为 gap 而非在本 PR 里补。编号依赖 #4641 的 IP-034,PR body 已写明谁先落谁负责对齐。

我的整体评价

结论 APPROVE。这是一个粒度正确、可独立评审、公开安全的文档增量:填了 State And Boundary 家族里一个真实空缺,完整接进了 family 表与 matrix,引用的生产事实我逐条复现(含两个标识符与 fail-closed payload),两个相关 smoke 在该 head 上通过,测试未改动。唯一发现是上面那条 P3——条目点名的两个标识符没有测试护栏——修法很小,且不构成合并阻塞。

English verdict: APPROVE - exact head e179c61; docs-only IP-035 catalog entry, docs-governance-smoke and interaction-pattern-catalog-smoke ok, and the entry's cited production facts reproduce (self_update.py:706 use_installation_owner, :967 unsupported_install_owner, plus the fail-closed payload pinned by 20 passing tests in tests/test_self_update_runtime_activation.py). One non-blocking P3 finding: the two machine-visible identifiers the entry names are asserted by no test, so the minimal repair is to cite the production lines in the entry or add one assertion.

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