- 新增 ADR-024:服务端关系主库统一 PostgreSQL,不设 SQLite 档(pgvector 与中文全文无法在 SQLite 承载,双档必然残缺或第二实现);端侧离线缓存不受约束 - AGENTS.md:权威事实源与部署句更新;8.6 固化 pk_/uk_/idx_/fk_ 索引命名约定 - system-architecture、data-architecture、memory-and-knowledge、roadmap WP-01、handoff(决策 29)同步清理 SQLite 引用
19 KiB
19 KiB
Hunjing 工程规则
目标:交付可维护、可验证、可长期负责的完整 1.0。 语言:用户可见输出、文档、注释和 Git Commit 使用简体中文;代码标识符和稳定协议值使用英文。
1. 事实源与工作方式
1.1 开发前阅读
按任务读取对应文档,不凭旧设计或记忆实现:
docs/product/product-charter.md:产品宪章、不可侵犯边界与永久禁域(上位约束);docs/product/product-definition.md:产品定义与 1.0/2.0 边界;docs/product/complete-1.0-scope.md:完整 1.0 范围与发布门;docs/product/cultural-language.md:文化名、直白解释与工程映射;docs/architecture/:系统、Agent、插件、数据、媒体、社区市场和前端渲染架构;docs/contracts/:API、ContentBlock、事件、ID、枚举、请求头和错误;docs/security/security-and-diagnostics.md:安全和受保护诊断;docs/delivery/implementation-roadmap.md:1.0 TODO 与验收证据。
事实层级:产品范围 → ADR → 架构 → 契约/OpenAPI → 实现 → 测试与运行证据。下游不得静默覆盖上游;运行事实与文档不符时先记录偏差,再修正事实源或实现。
1.2 需求处理
- 需求明确:完整实现;需求有多种会显著改变产品/API/数据/安全的解释:先列选项并询问。
- 普通命名、格式和等价技术细节由 AI 按既有规则直接决定,不把常规判断推给用户。
- 多步骤任务先列编号流程和验证方式;只有需要用户决策时暂停。
- 不总结或附和错误前提;先指出问题,再给修正方案并继续可执行部分。
- 未请求不做;发现无关问题只报告,不顺手重构。
1.3 实施原则
- 最小实现:在满足完整当前需求和安全边界前提下采用最少代码、依赖和服务。
- 能力必达,技术按需:1.0 产品能力是硬范围;数据库、语言、服务拆分和库按 ADR、官方资料、实测规模和维护成本选择,不为堆技术栈而部署。
- 优先复用:标准库 → 平台能力 → 已安装依赖 → 成熟依赖 → 最小自研。新增依赖前查官方文档、版本兼容、许可、维护状态和现有能力。
- 删除废弃路径:不为未发布实现保留兼容层;正式公共契约按弃用策略演进。
- 模块化单体优先:服务拆分须有独立扩缩容、故障域、数据/密钥边界、团队节奏或量化瓶颈证据。
- 安全边界不简化:认证、授权、租户隔离、审批、交易账、幂等、审计、秘密管理、文件/URL 校验和 Sandbox fail-closed 不得省略。
2. 完整 1.0 约束
docs/delivery/implementation-roadmap.md中全部 1.0 TODO 和发布门完成前,不得称为正式 1.0。- 产品宪章的永久禁域不可被实现、插件、管理员或自托管配置关闭;与宪章冲突的实现决定都是缺陷。
- 内部工作包可以并行开发和验收,但不是独立公开版本。
- 1.0 包含:角色与记忆、分支多模态对话、多 Agent、插件生态、实时语音、多语言、图像、Live2D、3D 运行编辑、Web/Tauri 桌面与移动、设备感知、完整社区、角色社区、协作空间、真实支付退款分成结算、运营和自托管。
- 已确认 2.0:Blender 级完整建模器、LLM 直接修改完整 3D 几何/绑定、IoT/机器人/物理动作控制。不得把其他已列能力静默移出 1.0。
- 文档 TODO 是真实待办;实现中的
TODO、pass、省略代码、假数据和无调用点定义不算完成。
3. 文化语言与工程标识
- 产品使用完整双层文化体系:文化名 + 直白中文解释;首次出现和高风险界面必须显示直白解释。
- API、OpenAPI、数据库、代码目录、事件、错误码、权限 scope、指标和日志只使用
docs/contracts/登记的中性英文稳定值。 - 后端返回
status: "running",前端本地化为“运转 · 运行中”;不得把文化名作为唯一协议值。 - 权限、金额、退款、删除、支付、结算、审核和现实后果不得用文化叙事掩盖。
- 新文化名先更新
docs/product/cultural-language.md;新稳定值先更新契约/OpenAPI。
4. API 与数据契约
4.1 API 分面
- Native:
api.<domain>/v1; - OpenAI-compatible:
gateway.<domain>/openai/v1; - Anthropic-compatible:
gateway.<domain>/anthropic/v1; - Provider Webhook:
api.<domain>/webhooks/v1; - Lingtai C ABI:进程内
hj_*稳定符号,契约见docs/contracts/lingtai-ffi.md;Lingtai gRPC Service:独立服务形态,仅限部署内部网络,契约见docs/contracts/lingtai-service.md;两者为同一灵台引擎核心; - 内部模块优先用类型化 Port/Command/Query/Event,不为每个模块增加 HTTP。
4.2 通用格式
- OpenAPI 3.1 是公共 HTTP 契约单一真源;生成 TypeScript/Rust 客户端,不手写重复 DTO。
- JSON/SQL/path 参数使用
snake_case;事件使用domain.action;逻辑模型使用kebab-case。 - 时间为 UTC RFC 3339;时长为
_ms非负整数;金额使用最小货币单位或 Decimal,禁止浮点。 - 列表使用 opaque cursor;更新使用 ETag/
If-Match;客户端忽略未知响应字段和枚举。 - 创建 Run、支付、退款、结算和外部副作用必须使用
Idempotency-Key。 Hunjing-Request-ID用于业务关联,traceparent用于分布式追踪,两者不能互相替代。- 1.0 认证采用 OAuth 2.1:Web 使用安全 Session Cookie,Tauri 使用 Authorization Code + PKCE,公共客户端使用短期 Bearer,自动化使用限 scope Service Account API key。
- 凭据只经 Header 传递,不进入 URL、query、业务 body、SSE data 或 WebSocket URL。
- Provider Header deny-by-default,仅 Adapter 白名单透传;用户登录凭据、Cookie 和诊断令牌永不转发上游。
4.3 消息与 Run
- 聊天通过
POST /v1/conversations/{id}/messages在同一事务创建 Message 和可选 Run;一个幂等键覆盖两者。 - 后台任务通过
POST /v1/runs显式创建。 - Run → Turn → ModelCall/ToolCall 分层;每个上游 attempt 单独记录,不覆盖失败或重试。
- 首个用户可见流事件前可以安全重试/故障转移;之后不得切换 Provider 重新生成另一份内容。
4.4 数据
- PostgreSQL 关系数据是权威事实源(ADR-024,不设 SQLite 主库档);对象存储保存媒体;全文、向量、图投影、推荐特征和缓存均可重建。
- 角色、消息、记忆、知识、社区发布、许可、订单、支付和 Ledger 分离建模。
- Ledger 不可变,修正写反向分录;支付 Provider Adapter 不直接写账。
- 删除传播到主存储、索引、缓存和派生数据;墓碑不保存被删原文。
- 权威状态、AuditEvent 和 OutboxEvent 在同一事务提交。
5. 统一 ContentBlock 与流式输出
5.1 ContentBlock
Native API 和持久化消息统一使用 docs/contracts/content-blocks-and-streaming.md 定义的类型化 Block:
text、markdown、code、quote、table、callout;math、mermaid;image、video、audio、file、gallery、avatar;tool_call、tool_result、agent_status、approval_request、artifact、citation、error。
用户输入可使用 Markdown 内嵌 Mermaid、代码和数学定界符;服务端必须使用确定性 parser 规范化为 canonical ContentBlock,记录 parser version,不把原始 HTML 当可信内容。
5.2 流式事件
统一事件:
content.block.started
content.block.delta
content.block.progress
content.block.completed
content.block.failed
content.block.cancelled
message.completed
- Event 在 Run 内有单调
sequence;Block delta 有单调delta_index。 - 客户端按 event ID 和
(block_id, delta_index)去重;缺口通过重放或最终 Message 对账,不猜顺序。 - Completed Block/Message 是权威快照,临时累积状态必须可丢弃重建。
- SSE 用于 Run/通知;WebSocket 用于实时语音、协同和设备双向会话。
5.3 分级实时渲染
- Markdown/text 增量显示并节流解析;未闭合结构保持源码态。
- Code 按行/时间片高亮,不逐 token 执行 Shiki。
- Math 仅在定界符闭合或 Block 完成后渲染;必须有源码/fallback text。
- Mermaid 仅在 Block 完成后以 strict mode 隔离渲染;失败显示源码和错误摘要。
- 图片、视频、音频和文件先显示结构化进度,资源 ready 后加载。
- Tool/Agent/Approval 使用状态替换,不拼接自由文本模拟状态。
5.4 前端安全与可访问性
- 禁用 Markdown 原始 HTML;URL/协议/目标域校验;外链
noopener noreferrer。 - Mermaid 禁止 click、HTML label、外部脚本和危险初始化;SVG 二次净化。
- KaTeX/MathJax 禁止 trust/宏注入并限制展开;Shiki 只高亮不执行。
- 图片必须有 alt;音视频有字幕/转写;公式有 MathML/fallback;图表有标题、说明和源码替代。
- 流增量不持续抢焦点;错误、审批和费用不能只靠颜色表达。
6. 插件、Agent 与安全
- 所有可扩展能力皆插件;认证、授权、数据隔离、审批、交易 Ledger、审计和 Sandbox 内核不可插件化。
- 只有 bundled Core plugin 可进主进程;声明式/远程插件默认受限;可信本地代码插件也进入独立进程或容器。
- Python import、Node
vm和 WebView 不是安全隔离。 - 插件 Manifest 声明版本、依赖、数据、网络、设备、费用、外部目的地与现实后果和配置 Schema;升级新增权限必须重新确认。
- Run 固定 PluginSnapshot;活动 Run 不热替换。安全撤架可以阻断新调用,但保留历史审计。
- 子 Agent 的工具、数据、网络、预算和权限是父 Run 的交集子集;不继承审批令牌,默认不能写长期记忆。
- Tool input 是不可信模型输出,必须 Schema 校验、Policy、审批、路径/URL 约束、资源限制和幂等。
- 无符合策略的 Sandbox 时拒绝执行,不静默退化到宿主。
7. 社区、协作、设备与交易
- PersonalDomain、Workspace、Community、Marketplace、Finance 和 Diagnostics 使用不同授权策略。
- 社区私信采用服务端治理的一对一/小群聊,不宣传 E2EE;支持举报、屏蔽、审核和多端同步。
- 公开角色 Release 不包含私密记忆、关系、对话、设备授权或密钥。
- Tauri v2 Desktop/iOS/Android 的文件、相机、麦克风、屏幕、位置和通知同时受 OS 权限与
device_grant约束;采集有持续指示并可即时撤回。 - 购买不等于安装插件,安装不等于启用,启用不等于授予新增权限。
- 支付 Webhook 验签、按事件 ID 幂等、允许乱序;客户端金额不可信;退款、分成和结算可对账。
8. 语言与框架规范
8.1 TypeScript / Next.js
- TypeScript 开启
strict;禁止无理由any、非空断言和重复定义 API 类型。 - 使用生成的 OpenAPI 类型;表单边界使用 Zod/React Hook Form;服务端状态使用 TanStack Query。
- React Server Component 默认;只有需要浏览器 API、交互状态或第三方客户端库时使用
"use client"。 - 不在 render 中产生副作用;Effect 必须清理订阅、Timer、Worker 和 WebSocket。
- ContentBlock renderer 采用穷尽判别联合;未知类型走兼容占位,不能崩溃。
- 长列表使用虚拟滚动;Markdown/Math/Mermaid/Shiki 高成本处理放 Worker 并按 content hash 缓存。
- 图标统一 Lucide;界面禁止表情符号代替图标、状态或操作。
- 测试:Vitest + Testing Library;核心旅程和跨端行为使用 Playwright。
8.2 Python / FastAPI
- Python 3.12+,使用 uv;格式/Lint 用 Ruff,类型检查用 mypy,测试用 pytest/pytest-asyncio。
- FastAPI 边界使用 Pydantic v2;领域对象不依赖 HTTP Request/Response 或 Provider SDK 类型。
- SQLAlchemy 2.0 typed mapping;迁移只用 Alembic;禁止运行时隐式建表修改生产 Schema。
- I/O 使用 async;不得在事件循环执行阻塞模型、文件、媒体或数据库操作。
- Provider、Tool、Storage、Payment 通过明确 Port;异常映射为稳定领域错误,不匹配错误字符串。
- Decimal/整数处理金额;时间统一 aware UTC datetime。
- 模型/工具流必须可取消,资源使用
async with/try-finally释放。
8.3 Rust / Tauri
- 使用 Tauri v2 和 stable Rust;
cargo fmt、cargo clippy -- -D warnings、cargo test。 - Tauri command 输入使用 serde/specta 类型并校验;不暴露通用 Shell 或任意路径命令。
- Capability/permission 最小化,桌面与移动平台分别声明;敏感命令验证用户、设备和 DeviceGrant。
- 路径 canonicalize 后限制在授权根目录;秘密使用系统 Keychain/Keystore,不写普通配置或日志。
unsafe仅在无安全替代时使用,封装最小并写明不变量和测试。- Tokio 任务支持取消和超时;不要持锁跨
await。 - 共享 TypeScript 类型由 specta/OpenAPI 生成,不手工漂移。
8.4 C++(灵台引擎)
- C++23 与 CMake;
clang-format、clang-tidy,编译警告全开并视为错误;测试与 fuzz 框架在建立工程时按 ADR 登记。 - 对外只导出
extern "C"的hj_*符号与不透明句柄;异常、STL 类型、RTTI 和 C++ 类不得跨越 ABI 边界;入口函数捕获一切异常并转换为HjStatus。 - 同一核心支持进程内嵌入与 gRPC 独立服务(
hunjing-lingtai-server)双形态;任何能力在两种形态语义必须一致,服务仅限部署内网并经 mTLS 认证。 - 内存全部 RAII,禁止裸
new/delete;引擎分配的缓冲只经hj_buffer_free释放;字符串一律 UTF-8。 HjEngine线程安全,会话句柄单线程亲和;回调在调用线程同步执行且回调内禁止再入引擎;不持锁跨回调。- 全部引擎输入(Markdown、模型输出、工具参数、查询、Webhook 字节)按不可信输入处理,长度/深度/节点数有硬上限;
hj_transform与hj_policy为 fuzz 必测目标。 - 每次提交跑 ASan/UBSan,线程路径跑 TSan,并维护 ABI 快照与双形态 golden 一致性测试。
- 引擎无权威状态、不做网络/文件/数据库 I/O(显式只读索引除外);引擎缺失或服务不可达时宿主 fail closed,禁止宿主内第二实现降级。
- 第三方库进入前按官方文档、许可与维护状态评估,gRPC/ANN/分词等选型以补充 ADR 登记。
8.5 Go(仅在 ADR 决定拆出高并发服务时)
- 版本以
go.mod为准;gofmt/gofumpt、go vet、golangci-lint、go test ./...。 - 所有外部 I/O 接受
context.Context,传播取消和 deadline;不把 Context 存入 struct。 - 错误使用
%w包装并以errors.Is/As分类;不匹配错误字符串。 - Goroutine 必须有 owner、退出路径和测试;channel 由发送方关闭;禁止无界队列。
- HTTP/Header/流式协议由共享契约生成或验证,不单独发明模型协议。
8.6 SQL 与存储
- 表/列/index 使用
snake_case;索引命名使用pk_/uk_/idx_/fk_前缀加表名与字段;外键、唯一约束、检查约束和租户条件在数据库层落实。 - 所有 Query 明确 PersonalDomain/Workspace/Finance scope;禁止先全表读后应用层过滤。
- N+1、无界列表和
%keyword%全表扫描必须在实现前处理或有量化例外。 - 向量、图、搜索和缓存只保存可重建投影,删除和权限变化必须传播。
9. 复杂度与变更规范
- 只改目标所需文件;匹配既有命名、注释密度和风格;保护用户已有改动。
- 删除自己引入的无用代码、导入、配置和孤儿注释。
- 函数有效逻辑超过 40 行、圈复杂度 >10、认知复杂度 >15、参数 >5 时应拆;确需保留须说明原因和风险。
- 不为一个实现创建接口/工厂/配置层;但稳定跨模块/插件/Provider 边界需要 Port 时不受此限制。
- 不重写或删除已有注释,除非需求明确要求或注释已失真。
10. 验证纪律
- 中大型或安全/状态/边界/并发/外部依赖变更先写失败测试,再实现通过。
- 逻辑变更优先覆盖公共行为;核心逻辑自动化覆盖目标 80%+。
- 每条需求交付前核对:需求 → 实现位置 → 调用点 → 测试 → 运行证据。
- 新函数、类、配置、事件和 ContentBlock 类型必须有真实调用/消费点。
- 新依赖、资源、Header、事件、ID 和配置名称必须验证真实存在且与契约一致。
- 纯文档变更可不跑代码测试,但必须验证内部链接、Mermaid、Markdown 和契约引用。
- 不报告虚假完成;测试失败、步骤跳过和未实现项必须明确说明。
11. 文档与图表
- 正式文档统一在
docs/;新增入口同步docs/README.md。 - 稳定 API/字段/ID/事件/错误只在
docs/contracts/和生成 Schema 定义;下游引用,不复制可漂移值集。 - 架构、流程、时序、状态和 ER 图统一使用 Mermaid,提交前必须实际渲染验证。
- 产品文化名更新
docs/product/cultural-language.md;工程值更新契约;两层保持一对一映射。 - 每次功能/API/状态变化同步相关产品、架构、契约、TODO 和测试文档。
12. 目录与配置
docs/:文档;logs/:本地日志;db/:本地数据库;config/:应用配置;docker/:Docker 文件。.env.example位于根目录,列出环境变量和中文说明;只提交.env.example和其他不含秘密的*.example.*配置,不提交真实.env、密钥、数据库、日志和用户数据。- 代码导入使用语言包/alias 的项目根路径;运行时文件路径通过统一项目根解析器或配置解析,不依赖进程当前目录。
- Docker 容器名以
hunjing-开头;Compose 不使用顶部version;开发、测试与自托管统一 PostgreSQL(ADR-024),正式环境按完整 1.0 能力启用 Redis、对象存储和 Worker。 - 本地启动、测试、迁移、生成和检查统一通过根
Makefile;新增命令同步make help。
13. Git 与交付
- 不覆盖、重置或删除用户未授权的现有改动。
- 不执行
git reset --hard、强制推送、清理未跟踪文件等破坏性操作,除非用户明确要求并确认目标。 - 只有用户要求时提交或推送;Commit 使用简体中文的 Conventional Commits/Gitmoji 规范。
- 提交前运行适用的 format、lint、typecheck、test、OpenAPI drift、Markdown/Mermaid 和安全检查。