# 为 K2F 做贡献

感谢你的帮助。我们关注**确定性布局**、**如实报告完整性**，并保持**规范、schema 与引擎**一致。

**仓库：** [github.com/suzheng/k2f](https://github.com/suzheng/k2f) · **社区中心：** [k2f.dev/community](https://k2f.dev/community) · **一致性（golden 运行器）：** [k2f.dev/conformance](https://k2f.dev/conformance)

## 参与贡献的方式

| 领域 | 在哪里工作 | 有什么帮助 |
| --- | --- | --- |
| **缺陷与想法** | [GitHub Issues](https://github.com/suzheng/k2f/issues)（使用模板） | 最小 `.K2F`、复现步骤、格式变更对规范的影响 |
| **编写文档与规范** | 本仓库中的 [`docs/`](docs/README.md) | 指南、规范（`docs/spec/`）、面向贡献者的架构说明 |
| **Agent 技能** | [k2f](https://github.com/suzheng/k2f) — [`skills/core/k2f/`](https://github.com/suzheng/k2f/tree/main/skills/core/k2f) | 工作流、目录（`ex_*.json`）、skill schema、脚本 |
| **引擎、CLI、导出器、查看器** | 本仓库（`engine/`、`cli/`、`export/`、`sdk/`） | 带测试的 Rust/Python/JS 变更 |

安全漏洞：[SECURITY.md](SECURITY.md) — 不要通过公开 issue 报告。

## 前置条件

- **Rust**（最新稳定版）— [rustup.rs](https://rustup.rs/)
- **Python 3.9+** — 测试 Python SDK 时使用 `k2f_py` / maturin
- **Node.js 18+** — 修改 `sdk/js` 或运行 JS 测试时

有关引擎版本匹配和支持的运行时，请参阅 [COMPATIBILITY.md](COMPATIBILITY.md)。

## 开发环境设置

克隆并构建贡献者和 CI 使用的工具链（无需先通过 PyPI 安装）：

```bash
git clone https://github.com/suzheng/k2f.git
cd k2f
bash scripts/dev-install.sh
bash scripts/test-getting-started.sh
```

`dev-install.sh` 会在 `sdk/python/.venv` 下创建 venv，使用 maturin 构建 Python 包，并编译 JS WASM 绑定。冒烟脚本会写入一个包、导出 PDF、检查 `PDF_IS_NOT_A_SOURCE`，并运行 `k2f verify`。

在 Windows 上，请使用 Git Bash 或 WSL 运行 bash 脚本。需要 Rust。

```bash
cargo build
cargo test
```

## 文档（单一事实来源）

| 内容 | 在此编辑 | 发布为 |
| --- | --- | --- |
| 人类可读文档（指南、编写、规范） | [`docs/`](docs/README.md) | 通过符号链接复制到 [`sdk/js/public/`](sdk/js/public/)；随 `@openk2f/k2f` 发布，并显示在 [k2f.dev/docs](https://k2f.dev/docs) |
| Agent 技能（目录、`SKILL.md`、skill `schema/`） | 本仓库中的 [`skills/core/k2f/`](skills/core/k2f/) | `npx skills add suzheng/k2f --skill k2f` · [k2f.dev/skills/k2f](https://k2f.dev/skills/k2f) |
| 安装指引 | [`skills/README.md`](skills/README.md) | 注册表与安装概览 |
| 格式 JSON Schema | 仓库根目录的 [`schema/`](schema/) | Rust 中的验证器；skill schema 应保持同步 |

**不要**手动编辑 `sdk/js/public/` 下的文件——在 git 检出中，它们符号链接到 `docs/`、`schema/`、`skills/README.md` 和 `meta/`；`npm pack` 会将副本实际写入 tarball。

更改 `docs/` 下的 Markdown 或仓库元文件后：

```bash
bash scripts/check-doc-links.sh
```

## 构建与测试

### Golden 测试套件

Lock 比较是**几何 + 渲染计划 + 内容哈希**。引擎提交 SHA 和 `appearance_hash` 不参与 golden 相等比较（它们在 debug `UNKNOWN` 与 release git SHA 之间会不同）。

**本地（快速）：** 每个用例编译一次，不生成 PNG。未设置 `CI` 时的默认行为：

```bash
cargo run -p k2f-test-runner -- run
cargo test -p k2f_sdk -p k2f_package -p k2f
```

**CI：** 每个用例编译五次（确定性），外加一个小型 PNG 外观门禁（`elevation_shadows`、`card_variants`、`running_footer_page_numbers`）。已发布示例（`examples/published/*.K2F`）不参与 PNG golden 比较。

**视觉门禁 PNG**（本地可选）：

```bash
cargo run -p k2f-test-runner -- run --check-png --dataset-runs 1
```

没有提交 `page_*.png` 的用例会跳过像素检查。要刷新门禁 PNG：`--update --check-png`。

默认的 `cargo test -p k2f_paint` 仍会渲染这些场景并检查 PNG 魔数字节，但不会逐字节比较 golden（macOS 与 Linux 的光栅字节可能不同）。Linux CI 通过 `CHECK_PAINT_GOLDENS=1` 和 `--check-png` 作业进行比较。使用 `UPDATE_PAINT_GOLDENS=1` 刷新 paint crate 的 golden。

**Nightly：** 相同的确定性 + PNG 门禁；请参阅 [`.github/workflows/golden-nightly.yml`](.github/workflows/golden-nightly.yml)。

### JS / WASM（查看器变更）

```bash
bash scripts/build-sdk-js.sh
cd sdk/js && npm test
```

### 文档与规范检查

```bash
bash scripts/check-spec-paths.sh
bash scripts/check-doc-links.sh
```

## 官方像素

切勿对文档正文使用浏览器 `fillText` 或 CSS 流式布局。Web 查看器仅通过 WASM lock 执行器绘制。回归测试：`sdk/js/test/no-fill-text.mjs`。

## 格式 schema 变更

仓库根目录的 [`schema/`](schema/) 是**格式**契约（manifest、nodes、styles、visual_primitives、signatures）。Agent 方言位于 `engine/k2f_sdk/profiles/` 下；MCP 目录位于 `engine/k2f_mcp/mcp_tools.json`。

更改格式 `schema/*.json` 时：

1. 在同一个 PR 中更新 Rust 验证器
2. 更新 [`docs/spec/k2f-v0.3.md`](docs/spec/k2f-v0.3.md)
3. 如有需要，重新生成已提交的示例（`bash scripts/build-published-examples.sh`）
4. 格式契约变更时，保持 [k2f](https://github.com/suzheng/k2f) skill 的 `schema/` 同步

## Pull request 检查清单

- [ ] 测试在本地通过（`cargo run -p k2f-test-runner -- run` 加上上述 crate 测试）
- [ ] 如果格式或 verify 代码有变更，规范已更新
- [ ] 如果改动了 `docs/` 或元 Markdown，文档链接检查已通过
- [ ] 未提交机密、密钥或 `.env` 文件
- [ ] 查看器中无 `fillText` / CSS 流式布局回归

## 发布（维护者）

**不要**使用 `scripts/archive/local-publish/` 从笔记本电脑发布。

**请**通过 GitHub Actions 发布（[`.github/workflows/publish.yml`](.github/workflows/publish.yml)）：

1. 在功能分支上工作；**squash-merge** 到 **`main`**，然后在提升版本或打标签前执行 `git checkout main && git pull`。
2. 提升版本并更新 `CHANGELOG.md`。
3. `bash scripts/publish-preflight.sh`
4. 可选：`bash scripts/trigger-publish-dry-run.sh`（仅 wheels，不上传注册表）
5. `git tag vX.Y.Z && git push origin vX.Y.Z` — 发布到 crates.io、npm 和 PyPI
6. `gh release create vX.Y.Z`，说明来自 `CHANGELOG.md`（推送标签不会创建 GitHub Release）
7. **网站：** 在 **k2f-site** 中提升 `dependencies.k2f`（`npm:@openk2f/k2f@^…`），执行 `npm install`、测试并部署——标签工作流不会更新 [k2f.dev](https://k2f.dev)

完整维护者检查清单（包括 Linux 冒烟和站点步骤）：`bash scripts/publish-all.sh`。背景：[scripts/archive/local-publish/README.md](scripts/archive/local-publish/README.md)。

## 行为准则

请参阅 [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)。
