docs(pi): record parity and pinned behavior evidence

This commit is contained in:
SaladDay
2026-08-02 22:52:40 +00:00
parent a88a58b516
commit 816a8b3928
3 changed files with 585 additions and 4 deletions
+85
View File
@@ -0,0 +1,85 @@
# Pi Extensions 一等支持设计附录
> 状态:仅设计,不含实现。主工程不实现 extensions;themes 明确不在范围内。
> authority:任何上游路径、加载顺序、启用规则或 tool 组合语义,在实施前都必须
> 由 pin `ab366ebe94cacd419d986be454f12b1b9913aaca` 的 oracle 或
> `scripts/pi-transport-capture.mjs` 实际执行确认,本文不以源码阅读代替证据。
## 目标
未来让用户在 cc-switch 中观察、导入、启用和停用 Pi extensions,同时满足:
1. 原生文件/目录是真相,`exists = active`,不制造与 Pi 分叉的 enabled 影子状态;
2. 只接管 cc-switch 明确拥有或用户显式、可验证采用的内容;
3. extension 提供的 tools 与 pinned core tools 分开展示,不伪装为 MCP server;
4. 所有写操作可并发检测、可补偿,portable import 不覆盖目标设备的未知资产;
5. 复用前置 C inspection 与当前 Skill/Prompt 的共享文件、fingerprint、ownership
和协调器原语。
## 模块边界
```text
PiExtensionInspector (只读、oracle 驱动)
├── NativeExtensionObservation
│ path / fingerprint / manifest / contributed tools
│ validity / reasons / ownership
└── PiExtensionCoordinator (唯一写入口)
├── exact-content adoption
├── CAS + atomic replace
├── ownership ledger transaction
├── catalog epoch / UI invalidation
└── compensation on partial failure
```
- `PiExtensionInspector` 只负责原生观察和结构化诊断;不得写数据库或文件。
- `PiExtensionCoordinator` 是唯一写入口;命令、deeplink、portable reconcile 与
UI mutation 都调用它,禁止各自复制目录。
- 通用 `shared_file`、Skill tree fingerprint 与 ownership ledger 可复用;
extension-specific manifest/加载规则必须先新增捕获向量,不能借 Skill 规则猜测。
- gateway 只消费 coordinator 发布后的 immutable runtime snapshotextension
不能在请求中途直接改 candidate/header 计划。
## 状态模型
建议公开三个正交维度:
- `discovery`: `absent | active | invalid | unknown`,只来自 native observation
- `ownership`: `external | adoptable_exact | managed | conflict`
- `capability`: `inspectable | manageable | unsupported | unknown`
不得增加独立 `enabled` 布尔值。用户点击“停用”时,语义是对受管原生资产执行可逆
移除;外部资产只能显式采用后再管理。内容变化导致 fingerprint 不匹配时进入
`conflict`,不得覆盖。
## Tools 与 MCP
- capture 已确认 pinned core tool inventory 为
`bash/edit/find/grep/ls/read/write`;未来 capture 应分别记录每个 extension
注入前后的 tool inventory 与来源。
- UI 将 tools 按 `core` / `extension:<id>` 分组,并展示冲突与覆盖次序的实测结果。
- MCP 页面仍不为 Pi 建虚假 registry。即使某个 extension 通过自身机制连接外部
tool,也属于 extension capability,除非未来 pinned Pi 真正提供 MCP registry
且由新证据和契约明确升级。
## Portable 与冲突策略
- 备份只携带 cc-switch 拥有的 extension 描述、内容 hash 和期望状态,不携带绝对
目录、设备 token 或未知外部目录。
- 导入先观察目标设备;missing 可部署,exact 可采用,different 必须 conflict
绝不“最后写入者获胜”。
- 多 extension 贡献同名 tool、command 或资源时 fail-closed;只有 oracle/capture
证明 Pi 的确定 precedence 且产品明确展示该覆盖时,才允许自动解析。
## 实施前验收
1. 扩展 transport capture:发现路径、空/损坏 manifest、启停、重复 ID、资源覆盖、
tool inventory、相对路径和 symlink 负例。
2. 冻结 schema/oracle provenance,建立 lossless raw observation;未知形状为
`unknown`,不得整目录连坐隐藏合法兄弟。
3. 服务级测试覆盖显式采用、并发 CAS loser、写后补偿、portable reconcile、
外部冲突、目录越界与 UI 的 `exists = active`
4. 中英文 UI 与可访问性完成后,再进入独立实现与盲审。
Themes 不与 extensions 共用该项目:其资源语义、预览与安全面另行立项。
+96
View File
@@ -46,3 +46,99 @@
不必对齐红绿账本,不必按固定轮次做盲审,偏离不必硬停上报。
遇到本文与既有契约冲突、或需要用户拍板的产品取舍(功能取舍、范围增删),
才上报;其余自行裁量,完成后报终态 SHA。
## 实现 authority 与可复现实证
- 唯一 Pi implementation pin:
`ab366ebe94cacd419d986be454f12b1b9913aaca`。主工程没有沿用历史文档中的
旧 pin,也没有从远端观察值推导行为。
- `scripts/generate-pi-native-oracle.mjs` 负责 schema/composer 的冻结 oracle
`scripts/pi-transport-capture.mjs` 负责需要真实执行 Pi 才能确认的 transport、
compat、原生资源与 CLI 行为。两者都先校验上述 commit,pin 不符即拒绝运行。
- 主工程捕获命令:
`PI_CHECKOUT=<pinned-Pi-checkout> node scripts/pi-transport-capture.mjs`
捕获直接执行 Pi,而非阅读上游源码推断。
- 捕获的发行元数据来自 `packages/coding-agent/package.json`,该文件在 pin 上的
SHA-256 为
`e02deae1cec07035807436c1864c88342e2f7d49050d03b858a3719f0c7aedbf`
包名 `@earendil-works/pi-coding-agent`、可执行文件 `pi`、配置目录 `.pi`
`parseArgs(["--version"])` 与带空格绝对路径的
`parseArgs(["--session", path])` 均由捕获实际执行。
- 同一捕获实际发出了四族请求并记录最终 URL/headers。Anthropic OAuth 凭证
(`sk-ant-oat` 子串)最终为 `Authorization: Bearer <credential>`
`anthropic-beta``claude-code-20250219,oauth-2025-04-20`,且主工程策略
强制不并发 `x-api-key`。OpenAI Responses/Completions、Google 与普通
Anthropic key 的头部矩阵也在同一输出中。
## Hermes 先例逐项对照账本
| 通路 | Pi 终态 | Hermes 差异或不适用理由 |
|---|---|---|
| App 注册、切换器、图标、可见性 | `AppType::Pi` 贯穿 Rust/IPC/TS,旧设置缺字段时默认可见,可独立隐藏 | 无差异 |
| 供应商与模型 | 独立 Pi 表单无损保留 provider/model 的未知 JSON;支持 provider/model 级 `api``baseUrl`、headers、`authHeader`、credential、cost/compat 等 pinned 字段;原生 catalog 使用已认证 inspection 导入 | Hermes 的 Web UI overlay/只读 provider 是 Hermes 自身所有权模型,Pi 使用共享 `models.json`,不套用 overlay |
| 新用户首用 | 创建第一位 Pi provider 时,在数据库、完整初始 endpoints 与原生 catalog 同一协调边界内发布,并把其第一模型设为 native default;随后可直接切换/代理 | 无需先手工导入或另开 native 文件 |
| 原生 catalog 与当前状态 | 复用前置 C 的三层 inspection;展示 raw/managed/composer/gateway 状态;可用 fingerprint CAS 导入;当前 provider/model 直接读 native defaults | 不以数据库 current 字段制造第二份“当前”状态 |
| 端点 | provider 主端点与多个 typed custom endpoints 均可增删、测速;membership 与 provider hydration 一致;网关按主端点及有序候选展开 | Hermes 的 additive provider 不具备该网关数据面 |
| 切换、代理与故障转移 | Pi 有独立 loopback route/token、catalog epoch、健康状态、重试/熔断和 failover 队列;候选必须保持 wire family 与协议身份兼容;不可预测协议表达式只允许单次 direct attempt,不重放 | Hermes 当前没有 cc-switch gateway handlerPi 对照的是已有完整代理 app 的安全边界 |
| OAuth 数据面 | 完整实现 Anthropic OAuth 的 Bearer + oauth beta,强制删除 `x-api-key`deferred credential 在物化后分类 | 由 request-capture 实证;不再停留在前置 C 的 DirectOnly |
| Skills | Pi 进入统一 Skills UI;期望状态、原生发现、受管 ownership 分离;显式 native import 只在内容完全相同时接管;部署、删除、导入及 portable sync 有锁、CAS、事务补偿 | Pi 的原生目录是部署目标,不能复用其他 app 的“复制后即视为拥有”假设 |
| Prompts | Prompt 库投影 `AGENTS.md`;同时原生管理 `SYSTEM.md``APPEND_SYSTEM.md``prompts/*.md`;文件存在即 active,直接编辑空白值会拒绝并要求显式删除 | Hermes 的 prompt 通路仍可复用;Pi 额外公开 pinned 原生资源,不制造 enabled 影子字段 |
| Sessions | 扫描 pinned v1v3 JSONL tree、只显示 active branch,支持详情、删除、终端恢复;遵守环境/设置/default sessionDir;相对 sessionDir 明示需要项目 cwd,不伪装为空列表 | Pi 的 tree/branch 与 Hermes session 格式不同,使用独立 parser 但复用统一 Session UI/安全入口 |
| MCP | **不适用**pinned Pi core 没有原生 MCP registryUI 不展示虚假 MCP 状态,服务入口结构化拒绝;capture 的 core tool inventory 为 `bash/edit/find/grep/ls/read/write` | Hermes 有原生 MCP registryPi extensions 可贡献 tools,但不等同 MCP。未来方案见 `docs/pi-extensions-design-appendix-zh.md` |
| 深链 | provider 深链支持 Pi provider key、模型、api、端点及 credential,走真实 `ProviderService::add`;prompt 深链走统一库与 Pi 文件所有权链 | 未识别 Pi API 保持 opaque,不用名称猜协议 |
| 设置与目录 | 设置页可发现/选择 Pi 配置目录,支持 `PI_CODING_AGENT_DIR`、WSL 路径展示、安装检测、网关/故障转移参数与凭证轮换;本地 gateway token 不下发前端 | 配置目录和 token 是 device-local,不写进 portable DB |
| 使用统计 | 四族 response/SSE 使用量进入统一日志、价格、筛选与 dashboard;每请求携带 input-token semantics,不能用 `app_type` 猜;Pi 混合协议的 cache-write 总数标为“部分可得” | Hermes 无 gateway usagePi 的单一 app 桶可能混合四族,不能显示误导性的确定 0 |
| 导入导出与远端同步 | DB provider/prompt/skill 期望状态可 portable;恢复后通过 catalog/prompt/skill reconciliation 与本机原生状态对齐;设备目录、native defaults、token、session 不跨机复制 | 原生资产属于设备/外部事实,不能塞进 SQL/binary 备份制造影子副本 |
| Profile 切换器 | **不适用**:现有项目 Profile 仅定义 Claude 组与 Codex 组,Hermes 本身也不属于任何 Profile scope;Pi 页面同样不展示 | 若未来产品定义新的跨 app Profile scope,应单独设计原生文件事务,不能暗自归入 Claude/Codex |
| Hermes Memory/Web UI | **不适用**:这是 Hermes 独有 daemon/APIPi 的长期上下文入口是 `AGENTS.md` 与原生 instruction files,已在 Prompts 面公开 | 不伪造不存在的 Pi daemon 或 Web UI |
| 原生“一键导入”按钮 | Pi 不调用 generic `import_default`;改为 certified native catalog 中逐 entry inspection + fingerprint CAS 导入 | 这是更严格的等价通路,不是功能缺失 |
| Extensions / Themes | extensions 本工程只交设计附录;themes 明确排除 | 用户已裁定范围 |
## 原生状态与 portable 状态边界
1. `models.json` 的读取、composition 与 gateway capability 只走前置 C 已认证链。
写入统一经 Pi catalog coordinator,协调 DB aggregate、typed endpoints、
native document、default provider/model、epoch 与失败补偿;legacy live-sync
不得旁路写它。
2. `AGENTS.md``SYSTEM.md``APPEND_SYSTEM.md`、prompt templates、Skills
与 Sessions 直接观察真实文件;所有 UI active 判断均来自 `exists` 或实际发现。
revision/fingerprint 只用于并发保护,不是第二套 enabled 状态。
3. portable import 恢复的是 cc-switch 拥有的 provider、prompt 与 Skill 期望状态,
随后与本机 native 事实 reconcile;不会跨设备覆盖目录、凭证 token、native
defaults 或会话。
4. Pi provider card 的“切换”选择该 provider 的第一模型;多模型的明确选择在
native catalog panel 完成,并写回同一 native default,不维护每 provider 的
隐藏 last-model 状态。
## 完成审查约束
- 主工程盲审最多七轮;每轮冻结精确 SHA/range,两位 fresh、互相独立、只读
reviewer。已审 clean SHA 作为下一轮增量基线;契约新增条款的作用域另做定向
全域调用点扫描。
- P0/P1 finding 必须修复;P2 由主审按可达性、影响面、数据/安全后果与发生概率
独立裁决,只有低影响且极少触发的边界才可保留,并在最终报告列出理由。
- 完成前做一次完整组件通读;零 validated P0/P1、相关验证全绿后才可交付。
## Scope audit(主工程预审检查点)
以主工程基线 `26a95aeb059235612c665d6b6bcd92fde9c3572e` 计,预审工作树为
137 个文件、约 +13.7k 净行,触发历史 90 文件/12k 净行审计线。审计结论为
**范围大但未越界**
- Rust 70 文件:Pi catalog/typed endpoints、共享文件与 ownership、gateway/runtime/
usage、prompts/skills/sessions,以及把 `AppType::Pi` 接进现有 command/service/
startup/sync 通路;其中新增的大文件按 catalog、transport、runtime、session、
deployment 分开,避免一个全知模块。
- 前端 52 文件:3 个 Pi 专用 panel/form、typed IPC/query、既有导航/设置/代理/
使用统计接线和中英文 i18n;没有复制第二套 app shell。
- 前端测试 12 文件:专用表单/prompt/usage 测试及既有跨 app matrix 增量。
- 证据与文档 3 文件:transport capture、本文账本、extensions 设计附录。
- `schema.rs``migration.rs``backup.rs`、三份认证套件及七个 pinned fixtures
均零改动;restore、themes 与 extensions 实现零文件。
压缩方案也做过评估:把 Pi 强塞进 legacy live-sync、通用 additive provider、
固定 app-type usage 语义或无 ledger Skill 复制可以减少文件,却会重新引入已经
认证过的 ownership/原生真实/协议分类错误;把 UI 与领域代码揉成少数巨型文件只
会减少文件数而增加审查风险。当前拆分复用了 provider write、proxy server、
Prompt/Skill/Session UI、同步锁和统计基础设施,新增代码只承载 Pi 不同的原生语义。
因此不为满足计数机械缩并,也不扩展到契约外功能。