Files
CC-Switch/docs/pi-support-review-contract-zh.md
T

43 KiB
Raw Blame History

Pi 一等支持:盲审规范契约

状态:规范性(normative

用途:本文件是 Pi 一等支持累积盲审的唯一产品与行为契约。审查只使用本文件列明的 authority、artifacts 与验证命令。

优先级:本文件若与 pi-support-contracts-zh.md 冲突,以后者为准;Pi 原生格式与加载行为以本节固定的官方源码提交为准。

0. 固定来源与术语

0.1 源码固定点

Pi 实现 authority 与 2026-07-31 UTC Phase 0 远端观察值必须分开记录:

来源 提交 规范用途
earendil-works/pi ab366ebe94cacd419d986be454f12b1b9913aaca 唯一 Pi implementation pinschema、composer、transport 与源码注释 authority
earendil-works/pi remote HEAD 977ec833bbb86e245057e9162dbc1443c7b6e707 Phase 0 观察值;不是第二个 implementation pin
CallmeLins/pi-switch 5cfa2e8d3f6657b0508ee66ea63acdedfb53388d 产品层 gateway/failover 参考,不定义 Pi 原生契约
Ginkgoooo/pi-cc-switch-provider 740c06692b15ad891e6d3ac3ee24c053d2626a9a 互操作边界参考,不定义主架构
Wing900/Pi-switch e2cc7f7837136277d317b742b650f402048ca80d Provider/Model 桌面交互参考,不定义数据契约

实现与测试中的 Pi schema、文件加载顺序和行为注释只能标明 implementation pin。 社区项目和远端观察值不得覆盖该 authority。

0.2 术语

  • logical_app_type:产品归属、UI 与筛选;Pi 的值为 pi
  • wire_api_family:请求实际使用的协议 family。
  • input_token_semanticswire family 对输入与缓存 token 的计数语义。
  • managed aggregateSQLite 中由 CC Switch 管理的 Provider 主行及全部持久化子行。
  • native entry:当前 Pi models.json 中的一个原生 provider key。
  • projection claimCC Switch 对 models.json 中一个精确 key 的设备本地所有权证据。
  • desired_enabled:用户希望 CC Switch 为 Pi 部署某 Skill。
  • owned_deployment:设备本地 ledger 证明目标由 CC Switch 部署。
  • effectively_discoveredPi 按当前 discovery 规则实际发现该 Skill。
  • gateway token:设备安装级 loopback bearer 凭据。
  • server_generation:当前进程 listener 实例代次。
  • catalog_epochcatalog mutation 与请求/writeback fence。

上述概念均为独立状态;不得通过 app_type、文件存在、内容相同或路径相同互相推导。

1. 功能范围

1.1 必须交付

  • Pi 应用注册、显示/隐藏和切换;
  • Provider/Model CRUD、复制、排序、预设、拉取模型、默认 Provider/Model
  • Pi 原生全局 Skills
  • 全局 AGENTS.md
  • 全局 SYSTEM.mdAPPEND_SYSTEM.md
  • 全局 prompt templates
  • Pi sessions 的发现、树形 active branch 展示、恢复和显式删除;
  • loopback gateway、同 family 请求级 failover、circuit breaker 与 SSE
  • usage 明细、聚合、费用、Pi 筛选;
  • portable backup、同步、restore 与运行态 reconcile
  • en、zh、zh-TW、ja 四语 UI。

1.2 明确排除

  • 跨 API family 转换;
  • User-Agent 伪装;
  • Pi auth.json 或 OAuth 生命周期管理;
  • MCP
  • themes、keybindings
  • project-local resources、packages 与 trust
  • extensions/package 的 inventory、安装、启停、升级或删除;
  • agent 内自动模型切换。

extensions 仅允许保留本文件第 16 节的设计契约;不得出现 Rust、SQL、TS、UI、IPC、capability flag 或空占位实现。

2. 数据所有权

数据或资源 权威来源 允许操作 禁止操作
Pi managed Provider aggregate SQLite aggregate CRUD、默认与 route state 把它视作 Pi 全部 provider universe
pi_provider_projections 当前设备 SQLite 记录精确 provider key claim 以前缀、内容或命名猜所有权
models.json Pi、用户与第三方共享 原子 patch 已 claim 的精确 key 整体覆盖或删除 unowned key
settings.jsonPi Pi 与用户共享 原子 patch 明确的默认字段 重写未知字段
auth.json Pi 只判断凭据能力是否可用 读取、复制、导出、覆盖凭据
skill_deployments 当前设备 SQLite 证明 CC Switch 的 Pi deployment portable/sync 搬运或由内容猜记录
Pi Skill 目录 Pi、用户与 CC Switch 共享 仅操作 identity/digest 匹配的 owned target 覆盖或删除 unowned target
AGENTS.md 用户与 CC Switch 共享 revision-safe library 投影 以 DB enabled 状态覆盖外部修改
SYSTEM.md / APPEND_SYSTEM.md 当前设备用户共享文件 revision-safe 直接 CRUD 建 DB enabled mirror 或进 portable sync
prompt templates 当前设备用户共享目录 用户指定的单文件 CRUD 递归扫描或删除未知文件
Pi sessions Pi 只读解析、用户显式恢复/删除 修改 transcript
gateway token 设备 settings 文件 本地生成、持久化、显式旋转 进入 DB authority、URL、日志、export/sync
runtime snapshot 当前成功发布的 generation immutable request lease 请求中回读可变 DB/global Provider

所有 ~/.pi/agent 路径必须经一个统一的 get_pi_agent_dir() 解析并尊重 PI_CODING_AGENT_DIR。Session 另按第 9 节解析 session root。

3. Managed Provider 与 capability

3.1 API family

本范围只代理下列四个 Pi 原生 family:

  • anthropic-messages
  • openai-completions
  • openai-responses
  • google-generative-ai

其他合法 Pi native family 可显示为 unsupported/direct-only 诊断,但不得被误路由。

3.2 两级模型

控制面必须表达:

PiManagedProviderConfig
  provider baseUrl?: string
  provider api?: PiManagedApiId
  apiKey?: unresolved expression
  headers
  models[]
  modelOverrides
  compat

PiManagedModel
  id
  name?
  model baseUrl?: string
  model api?: PiManagedApiId
  contextWindow?: PiNumber
  maxTokens?: PiNumber
  remaining native shaping fields

唯一继承规则:

effective api family = model.api ?? provider.api
effective endpoint   = model.baseUrl ?? provider.baseUrl

每个 managed model 必须解析出 family 与 endpoint。Provider 默认字段可以为空,只要每个 model 自身完整。一个 Provider 可以包含多个不同 family 的 model;路由单位是 (provider_id, model_id, effective_api_family)

effective_pi_model() 是投影、诊断、runtime、routing 与 failover 的共同解析入口。不得在调用点复制继承规则。

PiNumber 保持 Pi/JavaScript JSON number 语义;整数与小数都可无损经过 raw→managed→projection round-trip,不得以 u64 DTO 收窄。Managed 额外的正值 要求属于 managed-layer narrowing,不改变 raw validity。

Managed API ID 是 opaque non-empty string,必须无损 round-trip。四 family enum 只能存在于 gateway 层;新的 Pi-valid API ID 本身不构成 managed rejection。

3.3 capability 独立性

每个 native entry 必须独立表达分层结果:

  • raw native validityvalid | invalid | unknown
  • managed assessmentmanageable | unsupported
  • composition statuscomposed | failed | unknown
  • management statusimportable | managed | unsupported
  • gateway statusproxyable | direct_only | unknown
importable = raw validity == valid AND managed assessment == manageable
proxyable  = raw validity == valid
             AND composition status == composed
             AND API family、credential 与 headers 均受 gateway 支持

后层不得把 raw invalid/unknown 提升为 importable/proxyable。valid 不蕴含 manageablemanageable 不蕴含 proxyabledirect-only managed entry 不得进入 failover 候选。

Reason 必须是 {layer, code, json_pointer?}。raw schema failure、managed narrowing、composition failure 与 gateway limitation 使用不同 layer 和稳定 code。

4. Native catalog diagnostics 与 import

4.1 只读检查

检查必须每次读取当前 models.json,不得写文件、数据库、claim、默认值或 runtime。每个原生 key 都必须产生诊断,包括:

  • built-in overlay
  • modelOverrides-only
  • 完整 custom catalog
  • extension overlay
  • malformed/unknown shape。

每项至少返回 provider key、可选显示名、确定性 fingerprint、entry kind、四层判定、 management/gateway capability 和结构化 reason。

Layer 1 只运行 vendored pinned TypeBox schema 的 JSON evaluator

  • 直接消费 raw JSON,不先反序列化为 managed 类型;
  • 支持 provenance allowlist 中的 required/optional、absent/null、object/record/array、 union/literal/enum、string/boolean/Number、additionalProperties,以及完整递归 compat
  • 遇到未支持 operator、custom validator/transform、pin/hash 漂移或适用 schema 不确定时返回 unknown
  • 不解释 built-in/extension registry、OAuth、env、!command、文件、网络、 credential、composer fallback 或 gateway。

Layer 2 独立评估 managed narrowingmodel id 唯一非空、override key 闭合、present URL 为非空绝对 HTTP(S)。API ID 以 opaque string 保留。Pi Number 保持 number 语义,小数不得因整数 DTO 而变成 raw invalid。

Layer 3 只组合显式 custom catalog、显式 models 与 matching overrides。默认值与 precedence 来自实际执行 pinned Pi 的 vendored composer oracle。Composer 直接消费 raw-valid value,不先转换为 managed DTO;未知 provider/model/override shaping 字段、thinking map 与 compat 必须以 JSON value 无损保留。它是 credential-blind 纯函数:OAuth/env/!command/文件/网络表达式只作为 deferred material 保留,不能 执行或令 composition 变为 unknown。只有必须依赖但无法执行的 built-in/extension catalog/default-model 语义才 fail-closed 为 unknown,并返回 精确 catalog-required reason。

Layer 4 才把 composed API ID 缩窄到四个 gateway family,并在 capability 阶段构造 完整 CandidateHeaderPlan。非法/protected/hop-by-hop header 使候选不可代理; request 阶段必须在任何网络 I/O 前逐候选物化 deferred auth、tenant、自定义与 protocol header,失败只淘汰当前候选,不得复用前一候选的 URL、Host、auth 或 header。Gateway 不支持已知 opaque API ID 时为 direct-only,不得把 composition 降为 unknown。

固定状态矩阵:

  • 未知 API 的显式 custom catalograw valid + composed + importable + direct-only(api_family_not_gateway_supported)
  • built-in/extension 因缺 catalog/default-model contextraw valid + unknown composition + unknown gateway。

未知或不支持的 entry 必须可见,不得只记录日志。

4.2 显式 import

只有 importable entry 可导入。Import 必须在 Pi switch boundary 内:

  1. 重读精确 key
  2. 重算并比较 caller 提供的 fingerprint
  3. 原子插入完整 aggregate 与精确 claim
  4. 不写 models.json
  5. 不改默认 Provider/Model
  6. 不解析 env、!command 或 OAuth 凭据;
  7. 不自动加入 failover queue。

fingerprint 变化、claim collision、unsupported shape 或 DB failure必须零副作用。成功重试不得生成重复 Provider 或 claim。

5. Provider aggregate 与数据库 ledger

5.1 Aggregate hydration

Provider DAO 必须提供完整 aggregate 的单项与全量读取。旧的 Provider 单行读取只能 从 aggregate API 转换。Aggregate 只用于 read、rollback snapshot 与 restore,不是 通用 mutation DTO。

  • 单项与全量读取对同一 Provider 必须逐字段一致;
  • 删除 save_provider()save_provider_row_on_tx()、全部 upsert_provider*、通用 aggregate save 与同签名兼容壳;结构扫描必须证明生产 与 integration test 真实语法中禁止符号为零;
  • ProviderProviderAggregate 与 hydration 后的 ProviderMeta.custom_endpoints 都不是主行 write DTO;不得提供从 read DTO 到 write DTO 的隐式 From/Into
  • write surface 只暴露 create_provider(NewProviderAggregate)update_provider(&ProviderKey,&ProviderRowUpdate)rename_db_only_additive_provider(RenameProvider)add/remove/touch_provider_endpoint 六类类型化操作;
  • ProviderRowUpdate 不得含 id、endpoint 集合、is_currentin_failover_queuesort_index;update 恰好命中一行,零行返回 NotFound, 永不转为 create
  • create 在同一事务 strict INSERT 主行与全部 initial endpoints;重复 Provider、 endpoint 或任一约束失败时主行、endpoint、current/failover 状态均零副作用;
  • existing-provider 表单与 update IPC 不携带 endpoints;后端收到非空 custom_endpoints 必须显式拒绝,create IPC 在 service boundary 拆为 initial_endpoints
  • CustomEndpoint.added_at 在 Rust、IPC 与 TS 全链路 nullable;不得使用 epoch 0、 COALESCE 或 unwrap default 代替 NULL
  • add/remove/touch endpoint 使用精确行 mutationtouch 影响零行返回 NotFound
  • rename 只允许 OpenCode/OpenClaw 的 DB-only、非 live、非 OMO additive Provider;单事务 strict INSERT 新主行、复制全部 endpoint 的 url/added_at/last_used(含 NULL)、删除旧主行;目标冲突或不允许的来源均整体 失败。provider_health 可丢弃,usage/history 保留旧 provider id
  • live import、seed、universal sync 等 reconcile 必须先读取,再显式 strict create 或 strict update;并发 create 冲突不得退化为 overwrite
  • exact endpoint replacement 只允许 switch-lock 串行的 compensation coordinator 调用 pub(super)/sealed restore_provider_aggregate_on_tx()
  • delete/restore snapshot 必须包含 Provider 主行、endpoints、projection claims 与 Pi route state
  • provider_health 可重建,不属于 rollback snapshot。

针对 providers / provider_endpoints 的 production DML 只允许存在于 provider row/state DAO、endpoint DAO、schema migration 与 canonical data copier。结构扫描 必须区分 DML/DDL/SELECT/普通字符串、忽略 #[cfg(test)],并以禁止符号、越权 DML 的负向 fixture 证明规则会失败。

认证测试必须经过真实 ProviderService

  1. create 多个 initial endpoints 后完整 hydration 集合完全一致,duplicate create 零副作用;
  2. stale update 前后的公开 endpoint add/remove/touch 全部存活,非空 endpoint update payload 显式拒绝;
  3. rename 成功保留 endpoint 与 NULL 时间戳;target conflict、live、OMO、非 additive rename 均零副作用。

5.2 Projection ledger

projection claim 是设备本地状态:

  • 精确绑定 provider key
  • 不进入 portable export/sync
  • restore 时保留 live device 的 ledger
  • stale claim 清理失败必须显式失败;
  • claim collision 不得覆盖原生 entry。

5.3 Skill ledger

表的规范形态:

CREATE TABLE skill_deployments (
    app_type TEXT NOT NULL CHECK (app_type = 'pi'),
    skill_id TEXT NOT NULL,
    destination TEXT NOT NULL,
    destination_key TEXT NOT NULL,
    method TEXT NOT NULL CHECK (method IN ('symlink', 'copy')),
    source_identity TEXT NOT NULL,
    deployed_digest TEXT,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    PRIMARY KEY (app_type, skill_id, destination_key),
    UNIQUE (app_type, destination_key)
);
  • destination 是部署时词法规范化的绝对路径;
  • destination_key 按目标卷大小写语义生成,不使用 SQLite NOCASE
  • Auto 必须落为实际 symlinkcopy
  • 不加 cascade FK
  • portable/sync skip 且 restore 保留 live device rows
  • 同一 skill 可在 root relocation 期间短暂拥有新旧两条记录。

6. Catalog mutation 状态机

Provider mutation 集合:

CreateProvider(provider, initial_endpoints)
UpdateProvider(provider)
AddEndpoint(provider_id, endpoint)
RemoveEndpoint(provider_id, url)
DeleteProvider(provider_id)
ImportNative(provider_key, expected_fingerprint)
SetDefault(provider_id, model_id)

Provider form 的 update submit 不得携带 endpoint 集合;endpoint 控件只调用专用 mutation。last_used 当前不影响 routing,使用精确单行 touch 且不进入 catalog epoch;若将来参与 routing,必须升级进入 switch boundary。

所有 Pi Provider CRUD、endpoint CRUD、default、import、route/failover queue、takeover start/stop 与 database restore 必须共享一个 switch boundary,锁序固定为:

Pi switch lock
  -> listener lock
  -> begin odd catalog epoch / close Pi admission
  -> load complete PiCatalogSnapshot
  -> short DB transaction
  -> atomic exact-key projection
  -> build runtime from the same hydrated catalog
  -> publish even epoch
  -> activate listener generation

不得跨文件 I/O 持 SQLite connection mutex。Projection helper 不得自行开始 epoch。

纯排序只取得 Pi switch lock、执行单个 DB 事务并原子发布下一份 even-epoch runtime;不得取得 listener lock、进入 odd epoch或修改 models.json

6.1 成功

DB、精确 projection、runtime 与 listener 必须指向同一 catalog generation。旧 request lease 可以完成响应,但 epoch 不匹配时不得写 usage/health。

6.2 失败

失败点 必须结果
DB mutation 前 DB/文件不变,旧 runtime 以新 even epoch republish
DB 后、projection/runtime 失败,完整恢复成功 aggregate、claims、route state 与精确文件集合恢复;返回原错误;authoritative_state=previous_restored
DB restore 事务失败 restore 事务自身回滚;mutated DB 为 authority;按实际 DB reconcileauthoritative_state=mutated_database_authoritative
DB 已恢复、文件恢复失败 旧 DB 为 authorityPi admission 保持关闭;authoritative_state=projection_pending

任何分支都不得返回假成功,不得将旧 runtime 发布到 mutated DB 之上。

6.3 故障注入

必须覆盖:

  • 带多个 endpoint 的 Provider 删除后 projection replace 失败;
  • rollback-reject trigger 与 projection failure 同时发生;
  • projection 阻塞时并发 edit、default、restore 与请求;
  • restore staging 与 live device ledger 的 commit-boundary race
  • stale epoch usage/health writeback。

7. Skill 三态与安全部署

API 必须独立返回:

desired_enabled
owned_deployment
effectively_discovered
ownership
discovery
issue

UI toggle 只绑定 desired_enabled。原生发现但未 owned 的 Skill 显示“原生 Skill 活跃”,toggle 不得点亮。

7.1 Enable

在共享 deployment mutex 内:

  1. 解析 source identity 与目标;
  2. 对同名目录、同内容 copy、指向 SSOT 的 symlink 一律视为 unowned collision
  3. 使用同目录临时路径部署并 atomic rename
  4. 在一个 DB 事务中写 ledger 与 desired_enabled=true

collision 必须拒绝且不改目标、ledger 或 desired。

7.2 Disable

  1. 先持久化 desired_enabled=false
  2. 只有 ledger 存在且当前 identity/digest 匹配时删除目标;
  3. 成功删除后删 ledger。

owned copy 漂移或 symlink retarget 后必须拒删、保留 ledger并显示冲突。

7.3 Crash 与 relocation

  • 部署完成但 ledger 写入前崩溃:目标为 unowned orphan;不得自动删除或收养;
  • agent root 变化:旧记录显示 stale_destination
  • reconcile 先部署并登记新目标,再只在旧 identity/digest 匹配时清理旧目标;
  • toggle、sync-all、uninstall、Skill 更新和 storage migration 共用同一 mutex 与判断。

Discovery 必须遵循 frontmatter name、必填 description、root file/递归规则、ignore 文件、位置优先级与 effective-name first-wins shadow。

8. 原生指令文件与模板

8.1 三种文件

GlobalContext  -> <agent-root>/AGENTS.md
SystemOverride -> <agent-root>/SYSTEM.md
SystemAppend   -> <agent-root>/APPEND_SYSTEM.md

只有 SystemOverrideSystemAppend 暴露 direct IPC replace/delete。GlobalContext 只能由现有 Prompt library service 投影。

官方固定提交的拼装契约:

  • SYSTEM.md 存在时替换 Pi 默认 system prompt
  • APPEND_SYSTEM.md 的内容追加在所选 default/SYSTEM prompt 之后;
  • context files 再作为 project context 追加;
  • 已运行进程只在其资源 reload/rebuild 边界观察变化,UI 不得承诺即时影响现有会话。

8.2 文件状态与并发

  • 文件存在即 active,不存在即 inactive
  • 不提供 Switch,不建 DB enabled 字段,不使用空内容、改名或 .disabled 表达停用;
  • whitespace-only replace 必须拒绝;
  • replace/delete 必须带 exists + sha256 expected revision
  • 外部修改后旧 revision 必须 conflict
  • 三文件操作共用一个进程内 mutex
  • 只接受 UTF-8 regular file,最大 1 MiB
  • symlink、目录、设备文件 fail closed
  • 写入使用同目录临时文件、flush/fsync 与 atomic rename,并保留既有权限;
  • agent root 变化时不迁移或清理旧 root;
  • 隐藏 Pi、关闭 gateway、切 Provider 或恢复数据库均不得删除这些文件。

8.3 Library 与 templates

  • Prompt library 只投影 AGENTS.md
  • live AGENTS.md revision 偏离最后投影内容时,disable/switch/clear 必须 conflict并保留文件;
  • SYSTEM.md/APPEND_SYSTEM.md 不进 prompts 表、Profile、portable backup 或自动同步;
  • templates 只位于 <agent-root>/prompts/*.md,非递归;
  • slug 必须是 Pi 可调用的单 token 安全文件名,拒绝空白、路径遍历、separator、控制字符、保留名及与 agent-root 指令文件混淆的名字;
  • template 名为 SYSTEM.md 时仍是模板目录资源,UI 必须显示完整路径以区分。

9. Sessions

  • Pi JSONL 按 entry id/parentId 形成树;
  • UI 展示 header 指定/current leaf 的 active branch,不混入 abandoned branch
  • session id、cycle、entry 数、文件大小、UTF-8、symlink 与路径均有 fail-closed guard
  • 恢复使用 pi --session <path-or-id>,并使用完整进程树的 timeout/cancel
  • 删除只在用户显式确认后删除精确 session regular file
  • root 优先级必须明确处理 PI_CODING_AGENT_SESSION_DIRsettings.json.sessionDir
  • relative sessionDir 无法从全局 UI 确定启动 cwd 时返回“不可枚举/project-relative”状态,不得回退扫描默认 root。

10. Device settings 与 gateway token

10.1 Settings 文件

CC Switch device settings 必须使用同目录临时文件:

  1. 创建/校验 regular file
  2. Unix 权限收紧为 0600
  3. 写入完整内容;
  4. flush/fsync
  5. atomic rename
  6. 必要时同步父目录。

不得使用 .truncate(true) 直接写 authority 文件。

10.2 Token 生命周期

  • gateway token 存于 device settings 文件;
  • 首次生成后跨进程重启稳定;
  • 只有显式“重置网关凭据”操作旋转;
  • reset UI 必须提示运行中的 Pi 会话需要重启;
  • GatewayToken 的 Debug/Display 脱敏;
  • bearer 比较采用常量时间;
  • frontend settings DTO 清空 token
  • save merge 无条件保留 existing token
  • TS settings 类型不得包含 token。

10.3 Legacy 与 export

  • SQLite settings.pi_gateway_token 仅可在 live DB 启动迁移时读取;
  • device 文件已有 token 时 device 胜出,并删除 DB key
  • staged import/portable restore 直接删除远端 key,不得 adopt;
  • export_sql_string()export_sql_string_for_sync() 分别断言产物不含 token key和实际 value
  • token migration 在文件 durable write 后、DB delete 前崩溃时必须幂等。

11. Listener、runtime 与 takeover

Bind/reconcile 顺序:

bind exact loopback host/port
  -> 持久化首次动态端口
  -> 读取稳定 token
  -> close Pi admission
  -> compare exact owned projection
  -> mismatch 时以同 token atomic reconcile
  -> publish immutable runtime(origin + token + catalog)
  -> activate listener generation
  • 重启必须恢复同 host/port/token
  • 已占用的固定旧端口必须显式失败,不得暗换端口;
  • bind、settings durable write 或 projection reconcile 失败时 token 不旋转、Pi admission 不打开;
  • listener 可以继续服务其他 app
  • desired takeover 保留并显示 degraded/pending
  • 停止 takeover 先关闭 admission,再恢复 direct projection
  • database restore、proxy start/stop、端口更新与 catalog mutation 使用同一锁序。

每个请求取得 immutable runtime lease,包含 origin、token、catalog、server generation 与 even catalog epoch。旧 generation 不得 admission;旧 epoch 不得 writeback。

12. Usage semantics

12.1 类型与 authority

InputTokenSemantics
  1 TotalIncludesCacheBuckets
  2 FreshExcludesCache

StoredInputTokenSemantics
  Live(1|2)
  3 LegacyTotalIncludesCacheRead
  4 UnknownLegacy
  • 新请求由 wire adapter/parser 在 request context 创建时提供 live semantics
  • 落库 authority 是 proxy_request_logs.input_token_semantics
  • logical app_type 不参与语义选择;
  • request-id collision equality 与 dedup hash 包含 semantics
  • spawn 后移动到 logger 的值来自 admission lease,不受后续 catalog 变化影响;
  • live writer 缺 semantics 必须拒绝落库。

12.2 Fresh input

  • Anthropic familyinput_tokens 已是 fresh,使用 FreshExcludesCache
  • OpenAI Completions、OpenAI Responses、Google familyinput total 包含 cached bucketfresh 为 total 减 cached,使用 TotalIncludesCacheBuckets

费用、明细、dedup、backfill、rollup 与前端 fresh 展示必须消费同一 stored semantics。

12.3 Migration

schema migration 是唯一允许从旧 app_type 推断的路径:

  • 旧值 0 且 app 为 codex/gemini/grokbuild -> 3
  • 其他已发布 app -> 2
  • 意外旧 Pi row -> 4,不得猜 family或自动回填费用;
  • rollup 旧 0 -> 2
  • migration 后所有相关表不得残留 0
  • typed DAO、runtime decoder 与 import 拒绝 0
  • 所有 session import raw SQL 显式写 semantics。

前端 KNOWN_APP_TYPES 包含 pi,但该列表只用于筛选。

13. Routing、candidate materialization 与 failover

13.1 Eligibility

eligible(primary, candidate, route) :=
  candidate exposes route.model_id
  AND effective_api_family(primary) == route.api_family
  AND effective_api_family(candidate) == route.api_family
  AND canonical_request_wire_profile(primary)
      == canonical_request_wire_profile(candidate)
  AND canonical_protocol_header_profile(primary)
      == canonical_protocol_header_profile(candidate)

不进入 equality

  • scheme、host、port、base path
  • provider/model baseUrl
  • API key 与认证 header
  • tenant 与普通自定义 headers
  • display、pricing、排序、默认值。

进入 wire equality

  • 已知 request shapingcompatreasoningthinkingLevelMapinputcontextWindowmaxTokens 等;
  • 除明确 transport/auth/display denylist 之外的未知字段;
  • 已知 protocol header 的最终有效值。

JSON object key 顺序不敏感;array 顺序敏感;数字与字符串不宽松等价。

13.2 Header 分类

类别 行为
Gateway/HTTP ownedHost、framing、hop-by-hop、proxy trace、gateway bearer 剥离或重建,不进 equality
Protocolanthropic-versionanthropic-betaopenai-betaopenai-version 最终有效值进 equality
Candidate authAuthorization、x-api-keyx-goog-api-key 每次 attempt 延迟解析
Candidate tenantorganization/project headers 每次 attempt 解析
Provider custom headers 每次 attempt 解析
Incoming request-local 统一过滤后复制到每个候选,不进 equality

未知配置 header 视为 candidate-local。已知 protocol header 使用不可预测 !command 时,该候选 failover-ineligible。protected 与 hop-by-hop header 不得由配置覆盖。

13.3 Candidate materialization

  • 每个候选先经 effective_pi_model()
  • 复用对应 family adapter 的 URL builder
  • 最终 Host 从该候选最终 URL 重建;
  • auth、tenant、custom header 均来自当前候选,不得从 primary 串值;
  • 同一序列化请求 body 字节等价地 clone 给每个候选;
  • 不得做候选级 body/model 改写;
  • command-valued secret 需要 process-group/job-object tree kill、整体 timeout、有界 stdout/stderr,且日志不得包含 resolved secret。

13.4 Retry 与 SSE fence

允许切换:网络错误、timeout、401、403、404、408、409、429、非结构性其他 4xx 与 5xx。

禁止切换:400、405、406、413、414、415、422、501。

SSE 只有在首个语义事件提交给 Pi 前可切换;comment/keep-alive 不算语义提交。语义事件后失败不得 replay。

Failover 只影响当前请求,不改全局 current Provider、默认值、live config 或 UI current state。

13.5 必须存在的矩阵测试

  1. pi_route_identity_matrix
  2. pi_cross_origin_materialization_matrix
  3. pi_wire_profile_canonical_matrix
  4. pi_protocol_header_profile_matrix
  5. pi_four_family_candidate_materialization
  6. pi_failover_error_policy_matrix
  7. pi_sse_commit_boundary_matrix
  8. pi_snapshot_epoch_race

14. Shared-file 与 restore 安全

  • JSONC/CST patch 保留 comments、unknown fields 与 unowned entries
  • 只修改 manifest-owned exact keys
  • 文件写入均为同目录 temp + durable atomic replace
  • path traversal、symlink、目录、设备文件和超限内容 fail closed
  • 删除前后重新执行 symlink_metadata/identity check
  • portable export/sync 不包含 projection ledger、skill ledger、gateway token、SYSTEM/APPEND
  • restore 完成后在 Pi switch boundary reconcile DB、projection、runtime 与 listener
  • 任何 reconcile 失败都必须返回明确 authority/admission 状态。

14.1 Canonical schema authority

src-tauri/src/database/schema.rs 的 current-schema factory、current DDL 与 migration chain 是完整 canonical schema authority。CanonicalTableSpec / SchemaInvariantSpec 机械描述 Provider/endpoint/device-local ledger 的承重 invarianttests/fixtures/pi/canonical-schema-manifest-v1.json 是由这些代码 spec 产生并由测试锁定的审查快照。其余 current user table 由下述穷举 RestoreTableSpec 锁定恢复策略与固定列。Fixture 不是运行时 authority,也不能 认证 imported schema;外部 schema 无论通过多少结构比较都不得获得 publish 资格。

类型屏障固定为:

struct UntrustedScratch(Connection);
struct CanonicalStage(Connection); // 私有字段,仅 schema.rs current factory 构造

Publish 只消费 CanonicalStage;不得接收裸 Connection,也不得存在 UntrustedScratch 到 publish 参数类型的转换。Canonical stage 是全新磁盘临时库, 由 schema.rs 从空库建立当前全部 tables/indexes/collations、PK conflict policy、 CHECK、FK action、canonical trigger/view、PRAGMA 与 user_version,不得复制 source sqlite_schema 中的任何对象。Restore 生产代码不得包含 CREATE TABLE/INDEX/TRIGGER/VIEW 字符串。

RestoreTableSpec 必须对每张 current user table 恰好指定一种策略:

  • PortableIncoming:从 input 固定列逐行 decode 与复制;
  • PreserveLive:设备本地 rows 只从 live DB 复制;
  • RebuildRuntime:运行态不从 input 恢复;
  • SeedCanonical:由 current schema/seeding authority 重建。

结构测试必须证明 canonical user-table 集合与 policy 集合完全相等;新增表没有策略 必须失败。每个 spec 固定列名、复制顺序、NULL/storage type、row validator 与父子 拓扑;不得读取 source PRAGMA table_info 决定搬运列。

14.2 SQL 与 binary 共用 publish 管线

两入口统一执行:

untrusted input
  → UntrustedScratch
  → scratch 中 current migrations
  → RestoreTableSpec 固定列逐行 decode
  → schema.rs 从空库创建 CanonicalStage
  → live device-local copy
  → canonical validation
  → SQLite Backup API publish
  • Data transfer 在 foreign_keys=ON 的单个 canonical-stage transaction 中使用 plain INSERT;禁止 SELECT *INSERT OR IGNOREINSERT OR REPLACEREPLACE、目标端 ON CONFLICT DO UPDATE 与复制 sqlite_sequence
  • duplicate canonical key、弱 source UNIQUE 产生的重复行、FK orphan、storage class 或 decoder 错误必须整体 abort
  • Provider 行写 stage 前使用生产 hydration 的同一 decoder 验证 settings_configmeta、数字与 NULL;未知 JSON 字段必须保留,不得通过 重序列化丢失;
  • pi_provider_projectionsskill_deployments 只从 live DB 固定列复制,永不从 source;复制与 publish 持既定 live/switch boundary,失败保持 live 逐行不变;
  • AUTOINCREMENT 表可复制显式 ID,但不复制 sqlite_sequence,并验证下一 INSERT 的 ID 大于现有最大值;
  • WAL/SHM 永不复制、替换或重命名;binary source 只经 SQLite Backup API 克隆到 private scratchpublish 同样只用 Backup API。

Scratch 必须在不可信执行前关闭 trigger、关闭 trusted_schema、开启 defensive、 设 attached DB limit 为 0,并设置 SQL/value/page-count limits、有限 VM-step budget 与取消检查。不注册应用函数、不启用 load-extensionauthorizer 至少拒绝 ATTACH/DETACH、vtable、load-extension、writable-schema、非白名单 PRAGMA 与 unknown action。外部 batch 后删除 source trigger/view/显式 index,再执行可信 migration。未来 user_version 立即拒绝;0..=SCHEMA_VERSION 全部走现有 migration chain,缺固定列或 row decode 失败即 abort。

SQL 文件入口使用 symlink metadata、regular file、nofollow open、opened/current identity 与有限读取;binary 使用 READ_ONLY | NOFOLLOW | PRIVATE_CACHE 与同样 检查。边界为 MAX_SQL_IMPORT_BYTES=256MiBMAX_BINARY_RESTORE_BYTES=2GiBMAX_SCRATCH_BYTES=2GiB

Publish 前必须执行 integrity_checkforeign_key_check、全表 decoder sweep 与 行为断言,至少证明 providers PK collation 为 BINARY、精确 duplicate 为 ABORT、 duplicate 不会 REPLACE/级联删 endpoint。

SQL import_sql_string* 与 binary restore_from_backup 两个公开入口必须参数化覆盖:

  1. NOCASE/REPLACE PK、弱 endpoint UNIQUE/FK、trigger/view/index injection 后只发布 canonical schema
  2. 不可解码 Provider JSON、错误 storage class、duplicate canonical key、FK orphan abort 且 live/device-local rows 不变;
  3. NULL added_at 等 nullable 值与显式 AUTOINCREMENT ID 无损往返;
  4. symlink、目录、FIFO、N+1、VM/page budget、ATTACH/VACUUM INTO 在 publish 前 失败;
  5. 每个 user_version=0..SCHEMA_VERSION 有 migration sentinelcurrent、上一版与 最老支持版同时覆盖 SQL 与 binary。

14.3 Native oracle provenance

盲审与 CI 消费以下 vendored artifacts,不运行 Node、不联网:

  • tests/fixtures/pi/native-oracle/provider-schema.snapshot.json
  • tests/fixtures/pi/native-oracle/raw-oracle-v1.json
  • tests/fixtures/pi/native-oracle/composer-oracle-v1.json
  • tests/fixtures/pi/native-oracle/transport-oracle-v1.json
  • tests/fixtures/pi/native-oracle/field-coverage-v1.json
  • tests/fixtures/pi/native-oracle/provenance-v1.json

provenance 必须记录 Pi repo/commit、TypeBox version、schema/composer 源文件路径与 SHA-256、实际调用的 composer/transport entry functions、全部 artifact SHA-256、 generator 与 evaluator operator allowlist。Composer/transport expected output 只能 来自 implementation pin 的实际执行,不能由本仓库 mirror 生成。

field-coverage-v1.json 必须枚举 schema 的每个 canonical field path。每个字段都 必须同时引用:

  1. 输入确实含该字段且 TypeBox 1.3.7 实际执行成功的 raw case
  2. 输入确实含该字段、在其所属 provider/model/override 层实际执行成功且有 expected output 的 pinned Pi composer case。

缺字段、重复/陈旧字段、虚构 case、只在错误层出现或无法由 Pi 实际执行时 bundle 认证失败;无法执行的语义在 Rust 中 fail-closed 为 unknown。任一 hash/pin 不一致 时 raw evaluator 返回 unknown。更新 pin 必须显式重生成并审查。

15. UI、IPC、fixtures 与验收

15.1 UI/IPC

  • Pi Provider 表单支持 provider/model 两级 apibaseUrl
  • native catalog 使用独立只读面板,不使用 managed ProviderCard 操作;
  • 只有 importable entry 显示导入操作;
  • direct-only 在 managed 卡片上显式显示且无 failover 操作;
  • 多模型 Provider 不显示必然失败的无 model-id 通用 Enable
  • Skill UI 独立展示 desired、owned、discovered/shadow
  • Prompt 顶层名称为 Instruction Files | Prompt Templates,不得将 AGENTS.md 称为 system prompt
  • SYSTEM 页面有替换默认 prompt 的危险警告;APPEND 页面有追加说明;
  • Sessions 显示不可枚举的 relative root 状态;
  • 所有异步入口有 loading、error、empty 与 disabled 状态;
  • en、zh、zh-TW、ja key parity,且不得依赖 fallback。

15.2 控制面 fixture

tests/fixtures/pi/control-contract-v1.json 必须稳定覆盖:

  • 四 API family
  • provider-level 与 model-level api/baseUrl 继承;
  • provider 默认为空、models 自包含;
  • built-in overlay、modelOverrides-only、custom、extension overlay、malformed
  • raw validity / managed assessment / composition / management / gateway 分层分类与 {layer,code,json_pointer?} reasons
  • aggregate 主行 + 多 endpoint
  • projection claim
  • Skill desired/owned/discovered 的组合及 stale/collision/drift
  • prompt file kinds、路径与 revision
  • session tree、active branch 与 relative-root diagnostic
  • 四语 UI/IPC 枚举与字段名。

fixture 只含无凭据的确定性示例。Commit 10 后其语义与字段冻结。

检查点 A 还必须锁定:

  • canonical schema manifest 与 schema.rs code spec 等价;
  • raw oracle 的 valid/invalid 结果与 vendored TypeBox 1.3.7 期望逐项一致;
  • composer oracle 的默认值、provider/model/override headers/compat precedence、 unmatched override、空 URL、built-in/extension unknown 结果逐项一致;
  • schema 每个 canonical field 均有实际成功的 TypeBox 与所属层 pinned Pi composer 执行证据;transport resolver 的 deferred value/header 结果逐项来自 pinned Pi 实际执行;
  • raw unknown/invalid inspection 对文件、DB、claim、projection、default 与 gateway 均零副作用。

15.3 故障 fixture

至少覆盖:

  • cache-heavy 四 family1000 input / 800 cached
  • native import fingerprint TOCTOU
  • exact claim collision
  • aggregate delete + projection failure
  • DB rollback failure
  • Skill 三种 unowned collision
  • deploy 后 ledger 前 crash
  • owned copy drift 与 symlink retarget
  • external prompt revision conflict 与 symlink
  • relative session root
  • stable token restart、migration crash 与 unwritable projection
  • concurrent mutation/restore/request
  • cross-origin URL/header/auth materialization
  • SSE pre/post semantic-commit failure。

15.4 验证命令

cd src-tauri
cargo fmt --all -- --check
cargo clippy --lib -- -D warnings
cargo test --lib

cd ..
pnpm typecheck
pnpm test:unit -- --run
pnpm format:check
pnpm build:renderer
git diff --check

renderer build 后必须删除 dist/dist-web/。仓库不得提交生成物。

16. Extensions 设计边界(仅设计)

未来只有在固定官方源码确认下列原生能力后,才可另行实现:

  • 不执行 extension 代码的 machine-readable inventory
  • 原生持久 enable/disable 位或官方 passthrough
  • scope 明确、结果可判定的官方 install/remove CLI
  • 一个固定 owned key 的窄集成。

任何未来实现都必须以 Pi 原生配置/CLI 为 authority,不建 DB enabled mirror;不得自建 registry、依赖解析、semver、lockfile、下载器、trust 流程或 project-local 管理;不得执行 extension 取 metadata;不得复制凭据;不得自动 claim provider overlay或 Skill;不得把 extension MCP 表示为 Pi 原生 MCP。

本次实现不得包含以上能力的代码或 UI。

17. Commit 与盲审边界

实现必须保持 16 个独立 green commits

  1. docs(pi): freeze support contracts and extension design
  2. domain(pi): add managed model and capability contracts
  3. db(pi): add aggregate hydration and device-local ledgers
  4. config(pi): add read-only native catalog inspection
  5. provider(pi): add catalog mutation coordinator
  6. skill(pi): add ownership-safe deployment reconciliation
  7. ui(pi): expose provider native and skill control plane
  8. prompt(pi): support native instruction files and templates
  9. session(pi): add tree-aware session management
  10. test(pi): close and freeze control-plane contracts
  11. settings(pi): harden local settings and persist gateway credential
  12. gateway(pi): add listener admission and immutable runtime
  13. usage(pi): make input token semantics explicit
  14. routing(pi): materialize four native API families
  15. failover(pi): add cross-host failover and SSE commit fence
  16. test(pi): close recovery concurrency and end-to-end boundaries

累积检查点:

  • Abase..commit 4
  • Bbase..commit 10
  • Cbase..commit 16。

B 必须零 validated blocker/high 才可进入数据面。B 通过后记录 CONTROL_FREEZE_SHA=commit 10commit 1116 每次必须通过:

git diff --exit-code "$CONTROL_FREEZE_SHA"..HEAD -- \
  src-tauri/src/pi_config/model.rs \
  src/components/providers/forms/PiProviderForm.tsx \
  tests/fixtures/pi/control-contract-v1.json

schema.rs 由 schema snapshot/contract tests 守护 managed aggregate 与 ledger 形态。数据面若需要改变冻结文件、Provider IPC/form 字段、managed/native/direct-only 分类或 aggregate/ledger schema,必须停止并使 B 失效,不得在数据面提交顺手修改。

每个检查点的 reviewer 必须检查完整累积 range,并按 correctness、regression、data integrity、concurrency、security、compatibility、UI state、i18n 与 tests 维度报告。每条 finding 必须包含 severity、confidence、精确文件与行、具体故障场景、推理与建议方向;无 finding 时明确写出。

检查点 A 的 reviewer 材料必须包含:精确 base/checkpoint SHA、中立仓库地图与 authority 表、本文件、canonical schema manifest、native provenance manifest、 schema snapshot、带期望结果的 raw/composer/transport oracle fixtures、field coverage、provider-write/restore-policy/module-boundary 机器快照、完整验证命令与 通用审查维度。不得附带实现摘要、设计辩护、疑似文件/行号、既有审查输出或定向检查 提示。

审查总预算最多七轮。同一 invariant 连续两轮失败时停止局部修补并回到契约/状态模型;第七轮后仍有 blocker/high/data-integrity finding 时停止,不进行第八轮。