Skip to content

feat: add preview-first OPC host adapters#28

Merged
coconilu merged 13 commits into
mainfrom
codex/issue-26-host-adapters
Jul 25, 2026
Merged

feat: add preview-first OPC host adapters#28
coconilu merged 13 commits into
mainfrom
codex/issue-26-host-adapters

Conversation

@coconilu

@coconilu coconilu commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Summary

  • add a stable preview/apply/verify/rollback Adapter core for Codex, Claude Code, and Kimi Code CLI
  • reuse the existing Codex Marketplace lifecycle, use Claude's public plugin CLI, and project documented Kimi user Skills from one common scan root
  • add App-owned ownership manifests, exact logical Diff, drift/conflict protection, recovery entries, capability matrix, ADR, docs, and the OPC App Adapters page
  • harden plans with 120-second expiry, one-time use, restart invalidation, and write-time fingerprints over source, host/discovery, capability contract, ownership, and target state

Safety boundaries

  • File/Git knowledge remains authoritative
  • preview is zero-write and apply requires a one-time explicit confirmation
  • unknown versions, missing hosts, invalid discovery, stale plans, missing ownership, user edits, and links fail closed
  • Claude update/rollback never uses plugin marketplace remove; a stable App-owned marketplace is atomically swapped and refreshed, and uninstall/partial-install cleanup uses --keep-data
  • uninstall preserves OPC knowledge, project .opc, Git history, manager preferences/rules/experience, optional Mem0 data, plugin data where supported, and other hosts
  • real-host acceptance used disposable HOME/config roots only; the user's installed Claude 2.1.204 and real host configuration were not modified

CI cleanup-race repair

  • disable Git automatic/background maintenance only inside the disposable capability-evolution test repository before its first commit
  • retain all privacy/text assertions; cleanup errors are not ignored
  • add a regression test that reads back the four repository-local maintenance settings
  • document an exact privacy-safe Reviewer recipe for isolated three-host lifecycle, sentinel, fresh verification, rollback, and redacted evidence capture

Integration with merged #27

  • merged origin/main normally; merge commit parents are Adapter head 4903612 and feat(app): 独立本地 OPC App 控制平面 #27 squash merge e88118e
  • verified origin/main and the former feat(app): 独立本地 OPC App 控制平面 #27 branch had identical trees before resolving the nine same-content conflicts
  • resolved those conflicts to the Adapter branch versions because they contain that exact App baseline plus the reviewed Adapter additions
  • merge tree 485c05326dafc4bf278d96cd55d06cda0106eab5 exactly equals the pre-merge Adapter tree; no product content was dropped or rewritten

Validation

  • python scripts/validate_repo.py - PASS
  • Windows: python -m unittest discover -s tests -p test_*.py -v - 422 PASS, 6 expected skips at 6bcf6f7
  • Fresh GitHub CI run 30161595116: Ubuntu/Python 3.10+3.12, Windows/Python 3.10+3.12, and both optional-Mem0 jobs PASS at 6bcf6f7
  • failing Ubuntu privacy-range test repeated 20 times - 20/20 PASS
  • Reviewer PowerShell recipe parse and mutation-header coverage - PASS (Origin + CSRF on plan/apply/rollback)
  • Windows real-App background-job isolation smoke - PASS; exact git status unchanged and all 7 environment roots isolated
  • python scripts/privacy_scan.py - PASS
  • official Plugin Validator - PASS
  • all 7 Skill quick validators - PASS
  • Prior GitHub CI run 30154167815 - all 4 core and both optional-Mem0 jobs PASS
  • Fresh installed lifecycle run 30161595066: synthetic Ubuntu/Windows PASS; fixed-ref release job expected SKIP for a PR
  • real-browser recovery QA - PASS at desktop and 390x844 mobile; rollback dialog requires explicit checkbox confirmation, has no horizontal overflow, and emits zero App console errors
  • failure injection - PASS for Claude marketplace add/update, plugin install/update, partial-install cleanup, and rollback steps; plugin-data and unrelated-marketplace sentinels preserved

Disposable real-host implementation evidence

This is Developer evidence, not independent QA:

  • Codex 0.144.1: install, fresh discovery, no-op update, uninstall, rollback, reinstall, and unrelated sentinel preservation - PASS
  • Claude 2.1.212: pinned official npm package SHA-256 2162841dd793d21671eccb7fe76fe9c3da6816adf447ba3890a4871b7e5f4e69; local marketplace install, real update, fresh discovery, uninstall, rollback, reinstall, config/plugin-data sentinels - PASS
  • Kimi 0.29.1: isolated KIMI_CODE_HOME with loopback-only OpenAI-compatible stub; real /v1/chat/completions request contained all seven exact canonical Skill identities; install, discovery, no-op update, uninstall, rollback, reinstall, sentinel preservation - PASS

Independent Reviewer installed-state evidence

Reviewed against exact commit 221fb4205e4e3ed821d9012dd92c42732428931e; Developer self-report was not used as QA evidence:

  • Codex 0.144.1 and isolated Claude 2.1.212 each passed real install, verified fresh discovery, no-change update, uninstall, reinstall, rollback, post-rollback availability, and sentinel preservation.
  • Kimi 0.29.1 passed the same lifecycle; each of the three installed-state fresh-process model requests contained all seven exact canonical Skill names, uninstall removal was verified, rollback returned to available, and the sentinel was preserved.
  • With the documented disposable APPDATA, LOCALAPPDATA, and PSModuleAnalysisCachePath, exact repository status remained clean. No raw paths, prompts, requests, credentials, tokens, or session identifiers are retained here.

Prior independent Reviewer verdict at 221fb42: approve, with no findings. Merge-only head 6bcf6f7 preserves the exact tree of review-fix head 4903612, adds merged #27 as its second parent, and has fresh green CI; the PR remains unmerged pending the responsible owner's decision. The reproducible privacy-safe commands are in docs/host-adapters.md.

Depends on #27.
Closes #26

@coconilu

Copy link
Copy Markdown
Owner Author

Independent QA acceptance

  • Reviewed exact commit: 221fb4205e4e3ed821d9012dd92c42732428931e
  • Reviewer verdict: approve; findings: none
  • Timestamp: 2026-07-25 Asia/Shanghai
  • Codex CLI 0.144.1: disposable install → fresh discovery → update → uninstall → reinstall → rollback/post-probe PASS
  • Claude Code 2.1.212: isolated official package lifecycle and fresh discovery PASS; plugin-data/config sentinels preserved
  • Kimi Code CLI 0.29.1: disposable lifecycle PASS; every installed-state fresh-process request contained all 7 canonical OPC Skills; uninstall removal and rollback availability verified
  • Isolation: unrelated sentinels preserved; repository remained clean with disposable APPDATA, LOCALAPPDATA and PSModuleAnalysisCachePath
  • Exact-head CI: run 30154167815 all core/optional jobs PASS; run 30154167812 synthetic Windows/Linux PASS; fixed-ref job expected SKIP on PR
  • Provenance: independent Reviewer; Developer self-report was not accepted as QA evidence

No raw home paths, credentials, prompts, requests, tokens, or session identifiers are retained in this public evidence.

@coconilu
coconilu marked this pull request as ready for review July 25, 2026 10:44

@coconilu coconilu left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review(Kimi Code CLI 代为审查)

总体评价:架构与 issue #26 契约高度对齐,但有 4 个 major 问题,建议修复后再合并

已核实属实的部分:plan 零写、120s 过期、一次性确认、重启失效、写入时状态指纹(覆盖 source/probe/capability/ownership/target,常量时间比较)均在代码中真实强制且有注入测试;verify 走新进程官方发现机制而非文件存在;Claude 不用 marketplace remove、卸载 --keep-data;所有权 fail-closed 有充分测试;adapter 路由全部经过 Host+Origin+CSRF 防护;manifest 不含绝对路径/凭据,privacy_scan PASS。

本地实测:validate_repo.py PASS;隔离环境下 python -m unittest discover -s tests415 tests, OK (skipped=6),与 PR 声明一致。

Major(建议修复后合并)

  1. Kimi 更新可静默置换用户自有目录 — opc_adapters.py:1143-1146
    守卫条件是 if target.exists() and manifest is None: raise UNKNOWN_TARGET_CONFLICT,只在全新安装时 fail closed。场景:OPC 已装 v1(skills A/B),canonical v2 新增 skill C,而用户自己已有 ~/.kimi-code/skills/C(非 OPC 创建)。更新时 os.replace 直接把用户目录挪进备份并覆盖,plan diff 只显示 replace kimi:skill/C,无任何冲突提示。违反 issue「更新只处理 manifest 能证明由 OPC 创建的内容;未知文件必须保留并转为冲突/人工处理」及 ADR-0018 的 fail-closed 原则。建议:manifest 存在时,对已存在但不在 managed_targets 中的 target 同样抛 UNKNOWN_TARGET_CONFLICT

  2. Kimi update 的回滚不校验当前哈希即 shutil.rmtreeopc_adapters.py:1275-1292
    backup 恢复路径中 if target.exists(): if current is None: raise ROLLBACK_CONFLICT; shutil.rmtree(target) —— 有 manifest 时不校验哈希直接删除,update 之后用户做过的编辑会被 rollback 销毁。同文件 install 回滚路径(1266-1273)恰恰有 _is_link + tree_digest 校验并抛 ROLLBACK_CONFLICT,两条路径自相矛盾,也违反 ADR-0018「manifest 证明所有权且当前哈希仍匹配才可改动/移除」。建议:rmtree 前按 current manifest 校验链接与哈希,不匹配则 ROLLBACK_CONFLICT

  3. 前端没有任何恢复入口 — assets/app/dashboard.js
    apply 返回的 rollback_id 被直接丢弃,UI 无回滚按钮,/api/adapters/rollback 只能从带外脚本调用(前端仅展示 plan 的 rollback 描述文本,adapter-plan-rollback)。issue 明确要求「OPC App 提供每个宿主的…执行进度、验证结果和恢复入口」。建议:apply 成功后展示本次 rollback_id 并提供「回滚本次操作」按钮(配确认对话)。

  4. apply 中途失败不留结构化恢复入口 — opc_adapters.pywrite_operation 仅在成功路径执行)
    失败时遗留的 backup 目录无任何记录指向它。具体地,Claude 部分安装清理失败(ROLLBACK_FAILED)后:插件已装、manifest 不存在 → probe 报 drifted → 任何 plan 都抛 OWNERSHIP_CONFLICT,用户被卡死只能手工修。测试 test_claude_partial_install_cleanup_failure_is_explicit_and_recoverable(名含 "recoverable")实际固定的正是这个无恢复路径的状态。违反 issue「部分失败有结构化结果、恢复入口」。建议:失败时也持久化 operation 记录(含 backup_ref 与错误码),或对 OPC 刚写入的内容允许带指纹的修复计划。

Minor

  1. opc_adapters.py:466-469 vs 529-530CodexAdapter.target_fingerprint 读取的投影目录名是 {version}-{hash16},而 _codex_source 实际创建的是 {version},指纹永远返回 projection_exists=False, hash=None —— 写入前指纹对 Codex 投影状态失明(apply 时 _codex_sourcetree_digest 校验兜底,非安全洞,但属死代码且削弱 PLAN_STATE_CHANGED 覆盖)。建议统一命名。
  2. opc_adapters.py:1137-1158 + 1428-1434:Kimi update 不清理 canonical 包中已删除的 skill,manifest 被重写为当前集合后旧 skill 目录成为孤儿,之后卸载也不再清除,违反卸载完整性。
  3. AdapterManager.apply 只在 pop plan 时持锁(opc_adapters.py:1382-1383),而服务是 ThreadingHTTPServer:同一 host 的两个不同 plan 可并发 apply,状态指纹校验与首次写入之间存在 TOCTOU 窗口。建议 apply/rollback 全程持 per-host 锁。
  4. nit:opc_adapters.py:530-534 Codex 投影缓存仅按 source_version 键控,同版本内容变化会在 apply 时抛 PROJECTION_CONFLICT 阻断合法更新。
  5. nit:opc_adapters.py:722-725 Claude _is_installedname 兜底匹配可能把其他 marketplace 的同名插件误判为已安装(仅影响状态显示,无实际破坏)。

值得确认的疑问

  • /api/adapters/rollback 无独立确认令牌(仅 Origin+CSRF+rollback_id)。rollback 是恢复性写入且有 CSRF/Origin 防护,可辩护,但前端补回滚按钮时应配确认对话,请明确设计意图。
  • Codex/Claude 的漂移检测只覆盖安装态、不回读宿主缓存内容哈希(manifest 的 content_hash 是 canonical 源哈希),与 Kimi 不对称,建议文档写明。

未做的事:三宿主真实安装态验收需要一次性环境与真实 CLI,本次未执行;官方 Plugin Validator 未复跑。

@coconilu
coconilu changed the base branch from codex/issue-25-opc-app to main July 25, 2026 14:10
@coconilu
coconilu merged commit bce8f4e into main Jul 25, 2026
9 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.

feat(adapters): 管理 Codex、Claude 与 Kimi 的本地 OPC 集成生命周期

1 participant