mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 11:43:57 +08:00
943 lines
43 KiB
Markdown
943 lines
43 KiB
Markdown
# 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 pin;schema、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_semantics`:wire family 对输入与缓存 token 的计数语义。
|
||
- `managed aggregate`:SQLite 中由 CC Switch 管理的 Provider 主行及全部持久化子行。
|
||
- `native entry`:当前 Pi `models.json` 中的一个原生 provider key。
|
||
- `projection claim`:CC Switch 对 `models.json` 中一个精确 key 的设备本地所有权证据。
|
||
- `desired_enabled`:用户希望 CC Switch 为 Pi 部署某 Skill。
|
||
- `owned_deployment`:设备本地 ledger 证明目标由 CC Switch 部署。
|
||
- `effectively_discovered`:Pi 按当前 discovery 规则实际发现该 Skill。
|
||
- `gateway token`:设备安装级 loopback bearer 凭据。
|
||
- `server_generation`:当前进程 listener 实例代次。
|
||
- `catalog_epoch`:catalog mutation 与请求/writeback fence。
|
||
|
||
上述概念均为独立状态;不得通过 `app_type`、文件存在、内容相同或路径相同互相推导。
|
||
|
||
## 1. 功能范围
|
||
|
||
### 1.1 必须交付
|
||
|
||
- Pi 应用注册、显示/隐藏和切换;
|
||
- Provider/Model CRUD、复制、排序、预设、拉取模型、默认 Provider/Model;
|
||
- Pi 原生全局 Skills;
|
||
- 全局 `AGENTS.md`;
|
||
- 全局 `SYSTEM.md` 与 `APPEND_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.json`(Pi) | 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 两级模型
|
||
|
||
控制面必须表达:
|
||
|
||
```text
|
||
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
|
||
```
|
||
|
||
唯一继承规则:
|
||
|
||
```text
|
||
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 validity:`valid | invalid | unknown`;
|
||
- managed assessment:`manageable | unsupported`;
|
||
- composition status:`composed | failed | unknown`;
|
||
- management status:`importable | managed | unsupported`;
|
||
- gateway status:`proxyable | direct_only | unknown`。
|
||
|
||
```text
|
||
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` 不蕴含
|
||
`manageable`;`manageable` 不蕴含 `proxyable`;direct-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 narrowing:model 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 catalog:raw valid + composed + importable +
|
||
direct-only(`api_family_not_gateway_supported`);
|
||
- built-in/extension 因缺 catalog/default-model context:raw 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 真实语法中禁止符号为零;
|
||
- `Provider`、`ProviderAggregate` 与 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_current`、
|
||
`in_failover_queue`、`sort_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 使用精确行 mutation;touch 影响零行返回 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
|
||
|
||
表的规范形态:
|
||
|
||
```sql
|
||
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` 必须落为实际 `symlink` 或 `copy`;
|
||
- 不加 cascade FK;
|
||
- portable/sync skip 且 restore 保留 live device rows;
|
||
- 同一 skill 可在 root relocation 期间短暂拥有新旧两条记录。
|
||
|
||
## 6. Catalog mutation 状态机
|
||
|
||
Provider mutation 集合:
|
||
|
||
```text
|
||
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,锁序固定为:
|
||
|
||
```text
|
||
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 reconcile;`authoritative_state=mutated_database_authoritative` |
|
||
| DB 已恢复、文件恢复失败 | 旧 DB 为 authority;Pi 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 必须独立返回:
|
||
|
||
```text
|
||
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 三种文件
|
||
|
||
```text
|
||
GlobalContext -> <agent-root>/AGENTS.md
|
||
SystemOverride -> <agent-root>/SYSTEM.md
|
||
SystemAppend -> <agent-root>/APPEND_SYSTEM.md
|
||
```
|
||
|
||
只有 `SystemOverride` 与 `SystemAppend` 暴露 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_DIR` 与 `settings.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 顺序:
|
||
|
||
```text
|
||
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
|
||
|
||
```text
|
||
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 family:`input_tokens` 已是 fresh,使用 `FreshExcludesCache`;
|
||
- OpenAI Completions、OpenAI Responses、Google family:input total 包含 cached bucket,fresh 为 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
|
||
|
||
```text
|
||
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 shaping:`compat`、`reasoning`、`thinkingLevelMap`、`input`、`contextWindow`、`maxTokens` 等;
|
||
- 除明确 transport/auth/display denylist 之外的未知字段;
|
||
- 已知 protocol header 的最终有效值。
|
||
|
||
JSON object key 顺序不敏感;array 顺序敏感;数字与字符串不宽松等价。
|
||
|
||
### 13.2 Header 分类
|
||
|
||
| 类别 | 行为 |
|
||
|---|---|
|
||
| Gateway/HTTP owned:Host、framing、hop-by-hop、proxy trace、gateway bearer | 剥离或重建,不进 equality |
|
||
| Protocol:`anthropic-version`、`anthropic-beta`、`openai-beta`、`openai-version` | 最终有效值进 equality |
|
||
| Candidate auth:Authorization、`x-api-key`、`x-goog-api-key` | 每次 attempt 延迟解析 |
|
||
| Candidate tenant:organization/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 的承重
|
||
invariant;`tests/fixtures/pi/canonical-schema-manifest-v1.json` 是由这些代码 spec
|
||
产生并由测试锁定的审查快照。其余 current user table 由下述穷举
|
||
`RestoreTableSpec` 锁定恢复策略与固定列。Fixture 不是运行时 authority,也不能
|
||
认证 imported schema;外部 schema 无论通过多少结构比较都不得获得 publish 资格。
|
||
|
||
类型屏障固定为:
|
||
|
||
```rust
|
||
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 管线
|
||
|
||
两入口统一执行:
|
||
|
||
```text
|
||
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 IGNORE`、`INSERT OR REPLACE`、
|
||
`REPLACE`、目标端 `ON CONFLICT DO UPDATE` 与复制 `sqlite_sequence`;
|
||
- duplicate canonical key、弱 source UNIQUE 产生的重复行、FK orphan、storage
|
||
class 或 decoder 错误必须整体 abort;
|
||
- Provider 行写 stage 前使用生产 hydration 的同一 decoder 验证
|
||
`settings_config`、`meta`、数字与 NULL;未知 JSON 字段必须保留,不得通过
|
||
重序列化丢失;
|
||
- `pi_provider_projections`、`skill_deployments` 只从 live DB 固定列复制,永不从
|
||
source;复制与 publish 持既定 live/switch boundary,失败保持 live 逐行不变;
|
||
- AUTOINCREMENT 表可复制显式 ID,但不复制 `sqlite_sequence`,并验证下一 INSERT
|
||
的 ID 大于现有最大值;
|
||
- WAL/SHM 永不复制、替换或重命名;binary source 只经 SQLite Backup API 克隆到
|
||
private scratch,publish 同样只用 Backup API。
|
||
|
||
Scratch 必须在不可信执行前关闭 trigger、关闭 `trusted_schema`、开启 defensive、
|
||
设 attached DB limit 为 0,并设置 SQL/value/page-count limits、有限 VM-step
|
||
budget 与取消检查。不注册应用函数、不启用 load-extension;authorizer 至少拒绝
|
||
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=256MiB`、
|
||
`MAX_BINARY_RESTORE_BYTES=2GiB`、`MAX_SCRATCH_BYTES=2GiB`。
|
||
|
||
Publish 前必须执行 `integrity_check`、`foreign_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 sentinel,current、上一版与
|
||
最老支持版同时覆盖 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 两级 `api` 与 `baseUrl`;
|
||
- 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 四 family:`1000 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 验证命令
|
||
|
||
```bash
|
||
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`
|
||
|
||
累积检查点:
|
||
|
||
- A:base..commit 4;
|
||
- B:base..commit 10;
|
||
- C:base..commit 16。
|
||
|
||
B 必须零 validated blocker/high 才可进入数据面。B 通过后记录 `CONTROL_FREEZE_SHA=commit 10`,commit 11–16 每次必须通过:
|
||
|
||
```bash
|
||
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 时停止,不进行第八轮。
|