# ShipGate：产品与技术设计

## 状态与范围

本文定义 ShipGate v0.1 的产品和技术契约。v0.1 已实现为面向 Git 仓库的本地 CLI：评估变更路径、Git 变更类型、声明式规则和调用方提供的验证证据；不解释源码语义、不执行验证命令、不调用模型，也不进行网络请求。

客户验证仍是试点、GitHub 集成和付费规则包的前置条件，详见 [PROJECT.md](./PROJECT.md)。

## 产品边界

ShipGate 是本地优先的合并前 evaluator：观察预期改动和所提供的验证证据，不执行部署，也不向 Agent 授权。

```text
Git comparison ----> normalized change set ----> deterministic rules
                                                   |
task intent --------> unverified context           |
                                                   v
check evidence -----> normalized verification --> outcome policy
                                                   |
                                                   v
                                  JSON receipt + Markdown summary
```

evaluator 负责规范化、确定性 finding、结果计算和渲染。Git、GitHub Action 与 Agent runtime 都是外围 adapter。

## 术语

| 术语 | 含义 |
| --- | --- |
| Comparison | 待评估的一组 base revision 与 head revision。 |
| Change set | 从 Git 得到并规范化的仓库、提交和文件变更元数据。 |
| Check evidence | 调用方记录的命令或检查及其观察结果；v0.1 不执行它。 |
| Finding | 一次确定性规则命中，包含严重度、证据和人工问题。 |
| Human decision | 必须处理或显式接受的 finding 或遗漏必需检查。 |
| Receipt | 一次评估的不可变 JSON 记录及其派生 Markdown 视图。 |
| Outcome | 活跃策略下的 `pass`、`review` 或 `fail`，绝不代表正确性保证。 |

## 用户流程

1. 开发者完成一项 Agent 辅助的改动。
2. 开发者或 CI 使用明确的 Git base 与 head 调用 ShipGate。
3. Git adapter 解析仓库、完整 head SHA、变更路径和 Git 状态。
4. 调用方可选地提供任务意图和 JSON 检查证据。
5. ShipGate 在评估前验证配置与输入。
6. 规则引擎从规范化 change set 产生 finding。
7. 策略引擎将 finding 和验证结果组合为 outcome 与人工决定。
8. ShipGate 写入 JSON Receipt，并渲染简洁 Markdown 摘要。
9. 开发者处理 finding、在外部记录接受决定，或将收据附到 PR。

“未发现 finding”只表示已配置的确定性检查未命中，不表示改动安全或正确；Markdown 必须明确这一点。

## CLI 契约

```text
shipgate inspect --base <git-ref> [--head <git-ref>]
                 [--checks <path>] [--intent <text>]
                 [--config <path>] [--output <directory>]
                 [--format json|markdown|both] [--ci]
```

- `--head` 默认 `HEAD`；v0.1 强制 `--base`，避免猜测比较范围。
- `--config` 默认 `.shipgate.yml`；文件缺失时使用内置通用规则。
- `--output` 默认 `.shipgate/receipts/<full-head-sha>/`。
- `--format` 默认 `both`，文件名为 `receipt.json` 与 `summary.md`。
- `--checks` 接收下文定义的版本化 JSON；标准输入后续再考虑。
- `--intent` 作为调用方提供、未经验证的上下文保存和渲染，不影响规则严重度或 outcome。
- `--ci` 应用配置的失败阈值；任一模式均不联网。

| 退出码 | 含义 |
| --- | --- |
| `0` | 评估完成，outcome 为 `pass` 或建议性的 `review`。 |
| `1` | CI 策略下评估完成且 outcome 为 `fail`。 |
| `2` | 参数、配置、Git、输入校验或工件写入失败；未生成有效 Receipt。 |

本地模式默认建议性：即使 finding 触发策略，也把 `fail` 降为 `review` 并返回 `0`。`--ci` 下，`policy.failOn` 决定 `review`、`high_risk` finding 或必需检查失败是否返回 `1`。

## 输入

### Git Change Set

Git adapter 产生如下内部数据：

```json
{
  "repository": "https://github.com/example/project",
  "baseCommit": "<40-character-sha>",
  "headCommit": "<40-character-sha>",
  "files": [
    { "path": "db/migrations/001_add_user.sql", "status": "added" }
  ]
}
```

支持 `added`、`modified`、`deleted`、`renamed`、`copied`；重命名和复制另记录 `previousPath`。评估前按规范化的仓库相对路径排序，路径不可逃离仓库根目录。

仓库标识解析顺序为：规范化的 `origin` URL、其他被配置的规范 remote，最后才是调用方显式给出的稳定本地标识。remote URL 中的用户名和凭据必须移除。分离 HEAD 只要能解析为完整 SHA 即有效。

v0.1 等价于读取 `git diff --name-status -z <base>...<head>` 的名称和状态，不读文件内容。三点比较用于 PR 语义；只有验证证明有需求时才添加两点比较标志。

### Check Evidence

检查文件是数据而非可执行清单：

```json
{
  "schemaVersion": "1.0",
  "checks": [
    {
      "id": "unit-tests",
      "label": "Unit tests",
      "status": "passed",
      "command": "pnpm test",
      "exitCode": 0,
      "completedAt": "2026-08-26T08:00:00Z"
    }
  ]
}
```

`status` 只能是 `passed`、`failed`、`skipped` 或 `not_run`。`passed` / `failed` 必须有整数 `exitCode`，且其值与状态一致。ShipGate 不记录 stdout/stderr。可选 `command` 仅用于展示，会拒绝明显包含环境变量赋值、密钥或 token 的内容。非法证据直接失败，不静默修正。

### 任务意图

意图为可选纯文本，序列化后不超过 2 KiB；以“未验证意图”标签渲染，绝不参与确定性规则，默认不进入未来的托管同步。

### 项目配置

`.shipgate.yml` 是版本化的声明式配置：

```yaml
schemaVersion: "1.0"

rules:
  presets: [generic]
  disable: []
  overrides: {}

verification:
  required: [unit-tests, build]

policy:
  failOn: [failed_required_check]

privacy:
  redactPaths: []
```

未知顶层键和非法规则 ID 是错误。配置不可包含命令、脚本、hook 或可执行表达式。glob 规则固定为仓库相对路径，使用 `/` 分隔；除非模式自身包含，不能隐式匹配 dot segment。

规则 override 可调整内置规则的严重度；自定义路径规则是 Pro 候选能力，不属于免费 v0.1 核心。

## 确定性规则引擎

每项规则定义包含：

```text
id, version, description, severity, match(changeSet), message, question
```

每个 finding 记录规则 ID/版本、严重度、命中的路径或状态、消息与整改问题。按 `high_risk`、`review`、`info`，再按规则 ID 和路径排序。除非规则另有约定，每条规则每次 comparison 聚合为一项 finding。

| Rule ID | 默认严重度 | 命中证据 | 人工问题 |
| --- | --- | --- | --- |
| `SG001_DATABASE_MIGRATION` | `high_risk` | 常见迁移目录或迁移后缀下的新增、修改、重命名、删除路径。 | 是否审阅了正向迁移、回滚和兼容性？ |
| `SG002_ENV_CONFIG` | `review` | 环境模板、部署配置或已识别配置路径变更；密钥值文件只以脱敏类别报告。 | 是否在不暴露值的前提下记录了环境与部署改动？ |
| `SG003_AUTH_SURFACE` | `high_risk` | 已识别 auth、permission、policy、middleware、access-control 目录路径。 | 是否测试了允许与拒绝两类认证/授权路径？ |
| `SG004_PUBLIC_API` | `review` | 公开 route、controller、RPC schema、GraphQL schema 或 OpenAPI 路径。 | 公共契约是否向后兼容或已明确版本化？ |
| `SG005_DEPENDENCY_MANIFEST` | `review` | 已识别依赖 manifest 或 lockfile。 | 是否审阅依赖意图、lockfile、许可证与已知公告？ |
| `SG006_FILE_DELETION` | `review` | Git 状态为 `deleted` 的路径。 | 删除是否有意为之，且 import、数据和调用方是否已处理？ |

内置 glob 清单与规则代码一同维护，并用 fixture 覆盖。设计上宁可漏报，也不采用过宽的关键字匹配。Next.js、Supabase 等技术栈路径必须以显式 preset 形式引入并经验证后启用。

路径规则不得声称环境文件包含密钥、API 已发生语义变化，或存在鉴权缺陷；消息只能描述已命中的路径证据。

## 验证与结果策略

配置的必需检查 ID 与提供的证据进行核对：

- 缺少的必需 ID 会以 `not_run` 补入 `verification`，并形成一项人工决定；
- 必需检查为 `failed` 时形成 `failed_required_check`；
- `skipped` 与 `not_run` 保持可见且未解决；
- 多余检查保留，但不满足其他必需 ID；
- 重复 check ID 是非法输入。

| 最高未解决严重度 | Receipt `risk.level` |
| --- | --- |
| 无或 `info` | `low` |
| `review` | `medium` |
| `high_risk` | `high` |

outcome 与风险等级不同：没有未解决 `review`/`high_risk` finding、缺失必需检查或失败必需检查时为 `pass`；存在人工决定但未触发配置失败条件时为 `review`；仅在 CI 中命中 `policy.failOn` 才为 `fail`。

首版不提供交互式接受命令。Receipt schema 可表示 acceptance，但长期存储位置应在验证后决定：本地文件、PR metadata、PR check 或 comment。未接受的 Receipt 仍是一次真实评估快照。

## Release Receipt

JSON 工件符合 [共享 Release Receipt 设计](../docs/shared-release-receipt.md) 所需的 v1 字段，并扩展本地评估详情：

```json
{
  "schemaVersion": "1.0",
  "receiptId": "sg_<content-hash>",
  "createdAt": "2026-08-26T08:01:00Z",
  "source": {
    "repository": "https://github.com/example/project",
    "baseCommit": "<sha>",
    "commit": "<sha>"
  },
  "change": {
    "files": [{ "path": "package.json", "status": "modified" }],
    "summary": "1 file changed"
  },
  "verification": [],
  "risk": { "level": "medium", "findings": [] },
  "outcome": { "status": "review", "decisions": [] },
  "acceptedRisks": [],
  "evaluation": { "ruleSetVersion": "1.0.0", "configDigest": "sha256:<digest>" }
}
```

`receiptId` 基于仓库标识、比较提交、规范化文件、验证证据、规则版本、配置摘要及已接受风险的规范化序列化生成；不包含 `createdAt`、渲染格式或本地路径。因此等价证据具有稳定 ID，实质不同的证据具有不同 Receipt。

JSON Receipt 不可变：重新评估或之后接受风险必须产生新 Receipt，不得编辑旧工件。写入前应进行 JSON Schema 验证，使用原子写入，避免进程中断留下看似有效的半成品。

Markdown 必须从已验证的 Receipt 单向派生，依次包含：outcome、风险、提交和时间；未决人工决定；验证表；按严重度分组的 finding；脱敏后的文件摘要；可选未验证意图；以及“收据是证据而非审批/正确性证明”的固定声明。v0.1 不使用 HTML 或 provider 特有扩展。

## 隐私与脱敏

- 本地模式不联网，默认不发送 telemetry；
- Receipt 不包含文件内容、diff hunk、环境原始值、检查输出、异常 payload 或凭据；
- Git remote URL 规范化并删除用户信息和 token；
- 命中 `privacy.redactPaths` 的路径在序列化和渲染前替换为稳定类别占位符，原路径不写入 Receipt；
- 类似 `.env` 的文件即使没有用户配置也以脱敏环境文件类别报告；
- intent 与净化后的命令标签，除非单独 opt-in，否则不进入未来的托管同步；
- 项目规则是数据，不具备执行命令能力。

测试必须覆盖带凭据的 Git URL、恶意文件名、控制字符、超长意图、符号链接与路径穿越尝试。

## 架构与模块边界

推荐实现为 Node.js 20+ 上的 TypeScript：

```text
CLI / future adapters
        |
        v
application: inspect use case
   |        |         |          |
   v        v         v          v
git port  config   evaluator   artifact writer
adapter   loader    + policy    + Markdown renderer
                      |
                      v
              receipt schema/domain
```

| 模块 | 职责 | 不得依赖 |
| --- | --- | --- |
| `domain` | 规范化类型、不变量、risk/outcome 计算。 | Git、文件系统、CLI、GitHub。 |
| `rules` | 内置声明式规则与 evaluator。 | CLI、文件写入、网络。 |
| `adapters/git` | 仓库标识、提交和 name-status 数据。 | renderer、policy。 |
| `config` | YAML 解析、schema 校验、配置规范化。 | GitHub 或 Agent runtime。 |
| `receipt` | 规范化序列化、ID 生成、Receipt 校验。 | CLI 表现层。 |
| `renderers/markdown` | 将有效 Receipt 转为可携带 Markdown。 | Git 或规则匹配。 |
| `cli` | 参数解析、依赖组装、退出码和诊断。 | 规则内部实现。 |

时间、ID hash、文件系统与 Git 行为需能在 application 边界注入，使 golden test 可重现。evaluator 只接收普通规范化数据并返回普通数据，不产生副作用。

## 错误处理

操作错误与 finding 分离。非法 ref、浅克隆缺少 merge base、配置错误、检查证据错误、不支持 schema 版本、写入失败都返回 `2`，并在 stderr 输出简洁诊断；不得产生 `pass` Receipt。

诊断包含错误码、面向人的消息和一个修复建议，且不能打印凭据、环境原始值或检查输出。普通模式下意外错误应使用稳定的通用消息；仅显式 debug 标志可输出堆栈，且仍要脱敏已知密钥。

## 集成顺序

1. Git 仓库的独立 CLI；
2. 调用 CLI 并发布 artifact 或 PR check 摘要的 GitHub Action；
3. 使用 `apply(ctx)` bundle 和显式 `shipgate` tool 的 DSH adapter；
4. 核心 Receipt 语义稳定后，再开发 Claude Code 和 Codex adapter。

GitHub Action 初期完全运行在用户 workflow 中，不向 ShipGate 服务上传源码或 Receipt。PR comment 更新、check-run 权限、fork PR、非受信 workflow 输入必须在 M2 前单独完成威胁建模。

核心 evaluator 绝不依赖 Agent runtime；adapter 可以收集 intent 和 check evidence，但必须调用同一 `inspect` use case。

## 测试策略

### 单元测试

- Git 状态与路径规范化，包含 rename/copy 与非 ASCII 路径；
- 每条内置规则的命中、非命中、边界和禁用场景；
- 验证对账以及全部 outcome；
- 配置默认值、override、未知键和不支持版本；
- 规范化序列化及稳定 Receipt ID；
- 脱敏与凭据移除。

### 契约与 Golden Test

- 所有 JSON 工件均通过 Receipt v1 JSON Schema；
- 对低、中、高风险 Receipt 生成并固化 Markdown snapshot；
- 对 fixture 断言 finding 顺序、risk 和 Receipt ID 的确定性；
- 共享契约 fixture 必须可由 Release Sentinel 使用，而不导入 ShipGate 代码。

### 集成与验收测试

临时 Git 仓库需要覆盖干净历史、merge-base 比较、分离 HEAD、重命名/删除、带空格或控制字符的路径、缺失 remote、浅历史失败、非法 ref 和原子替换。测试不得依赖全局 Git 配置、网络、时钟、locale 或文件系统排序。

| 场景 | 预期 |
| --- | --- |
| 依赖 manifest 改动，必需测试通过 | `medium` risk、`review` outcome、本地退出 `0`。 |
| migration 改动，必需 build 缺失 | `high` risk，并出现 migration 与缺失 build 决定。 |
| CI 中必需检查失败且命中 `failOn` | 有效 Receipt、`fail` outcome、退出 `1`。 |
| 无规则命中且所有必需检查通过 | `low` risk、`pass` outcome，仍有免责声明。 |
| config 或 checks JSON 畸形 | 退出 `2`，无有效 Receipt。 |
| 同一规范化证据评估两次 | 除 `createdAt` 外语义 JSON 与 Receipt ID 相同。 |
| 路径被脱敏 | JSON 与 Markdown 均不含原路径。 |

## 开发计划

### M0：验证与契约冻结

交付 12 份访谈、5 份真实 PR 人工收据及规则忽略数据；5 名开发者的一周礼宾式原型结果；选定首个规则包与 CLI runtime/distribution；冻结的 Receipt v1 JSON Schema 与共享 fixture；以及对 `PROJECT.md` 门槛的 go/no-go 决定。未通过就修订或停止，不创建生产代码库。

### M1.1：仓库与领域基础

初始化 runtime、format、lint、test、build/release 布局；定义变更、验证、finding、decision、policy、receipt 类型；实现 config/check/Receipt schema；实现规范序列化、内容 ID 和固定时钟测试辅助；建立 fixture 与 golden test 约定。

退出条件：schema 拒绝非法样例，规范 Receipt 在重复运行及支持平台上保持确定性。

### M1.2：Git 与配置输入

实现 base/head 解析和 merge-base 比较，解析 NUL 分隔 name-status（含 rename/copy），净化仓库标识，严格加载 `.shipgate.yml`，校验 checks 与 intent 限制。

退出条件：Git 测试矩阵覆盖，非法输入永远不进入 evaluator。

### M1.3：规则与策略

实现六条通用规则及 glob fixture，确定性聚合/排序，对账必需检查，推导 risk/outcome/人工决定；规则级 metrics hook 保持本地 no-op，直到明确开启。

退出条件：验收场景精确产生预期 finding、outcome 和退出分类，evaluator 无网络或文件副作用。

### M1.4：CLI 与工件

实现 `shipgate inspect`、参数校验、帮助、稳定退出码；原子生成 JSON/Markdown；序列化前脱敏；提供可行动且脱敏的诊断；面向 macOS/Linux 打包 CLI。

退出条件：全新 fixture 仓库能在典型开发机两秒内安装和生成工件，输出通过 schema 且不含禁止数据。

### M1.5：试点加固

在五个 design-partner 仓库运行 CLI；排查崩溃并按版本跟踪规则忽略；编写安装、证据创建、配置、隐私和限制文档；验证 Node.js、macOS、Linux 与常见 CI；产出 M1 release candidate 和 schema 迁移说明。

退出条件：所有 fixture 重复输出一致，试点生成成功率至少 90%，无未解决的高严重度隐私问题，任一默认规则均未超过 30% 忽略上限。

### M2：GitHub Action

仅当 M1 试点后本地 Receipt/outcome 契约保持稳定时开始。实现 pin 版本 Action wrapper、artifact 上传、job summary 和可选 check-run renderer；先定义最小权限、fork 安全、comment 更新、并发和失败行为。

退出条件：PR 可看到 Receipt，且不向 ShipGate 服务发送源码或 Receipt；重复运行不产生 comment spam；分支保护行为与显式配置一致。

### M3：付费技术栈规则包

仅实现验证中选定的规则包。公开其规则、证据边界、fixture 语料和误报率；与核心 CLI 独立版本化。

退出条件：两名用户为具名规则包或抢先体验付费，并在真实改动中使用超过一次。

## 依赖顺序

```text
Validation gate
      |
      v
Receipt/schema freeze
      |
      v
domain foundation
   |             |
   v             v
Git/config     rules/policy
   |             |
   +------> CLI/artifacts
                  |
                  v
             pilot hardening
                  |
          +-------+-------+
          v               v
     GitHub Action    paid stack pack
```

schema 冻结必须先于 adapter，避免集成固化易变契约。领域类型稳定后，Git/config 与 rules/policy 可以并行。M1 试点证据具备后，GitHub Action 与规则包相互独立。

## v0.1 完成定义

- CLI 在无网络条件下评估明确的 Git comparison；
- 六类通用风险具备确定性、可解释性和版本；
- 提供的验证证据经过校验但绝不被执行；
- JSON 与 Markdown 一致并通过冻结 schema；
- 本地模式建议性，CI 失败必须显式配置；
- 等价输入的 Receipt ID 和 finding 顺序稳定；
- 脱敏与仓库 URL 净化通过安全 fixture；
- macOS/Linux 安装和端到端测试通过；
- 文档说明限制，不暗示审批或正确性。

## 延后决策

| 决策 | 最晚解决时间 | 所需证据 |
| --- | --- | --- |
| 首个规则包：Next.js、Supabase 或 Stripe | M0 退出 | 按人群统计频率、可行动性和付费意愿。 |
| Node.js/TypeScript 分发 | M0 退出 | 目标仓库、安装摩擦、二进制大小预期。 |
| 共享 Receipt v1 扩展和同步投影 | M1.1 前 | Release Sentinel 契约审阅与隐私访谈。 |
| 精确通用 glob 清单 | M1.3 前 | 5 个 PR 回放与误报审阅。 |
| 默认 CI `failOn` | M1.4 前 | 试点预期；本地默认始终建议性。 |
| acceptance 持久化模型 | M2 前 | 用户是在 CLI、config、PR check 还是 comment 接受。 |
| telemetry | M1 试点后 | 明确的同意设计和所需最小指标。 |

模型辅助建议、diff 内容分析、自动命令执行、托管 Receipt 存储、团队审批工作流和部署授权均不属于 v0.1。
