Files
hunjing/docs/decisions/README.md
T
chenxin 3fbcd0437c 🎉 feat: 建立阶段 0 工程骨架与 OpenAPI 契约机器化(WP-01 起步)
- Makefile:统一命令入口(backend/engine/docker/openapi/generate,含 make help)
- backend:FastAPI + uv 最小工程,统一错误体(契约第 7 节)、ADR-015 平台 ID 生成与校验(uuid-utils);pytest 7 项、ruff、mypy strict、启动冒烟全部通过
- engine:灵台引擎 C++23/CMake 骨架,按 Lingtai C ABI 契约实现 lingtai.h(13 个 HjStatus、版本协商、句柄表防二次释放、线程局部错误上下文);doctest 5 用例通过,nm 验证仅导出 hj_* 符号
- openapi:OpenAPI 3.1 单一真源初始版(错误体/分页/Money/首批平台 ID/ContentBlock 全 21 类型/流事件 envelope),Redocly lint 0 错误、bundle 通过
- frontend:Next.js 最小骨架,openapi-typescript 生成 API 类型并通过 strict tsc
- docker:hunjing-postgres(pgvector:17)compose;.env.example 与 config 示例
- ADR-025:登记测试与契约工具链(doctest/libFuzzer/Redocly/openapi-typescript/uuid-utils)
- desktop:Tauri v2 占位与初始化说明(WP-10 启动)
2026-09-09 21:45:04 +08:00

420 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 架构决策记录
## ADR-001:可扩展能力皆插件,治理内核不插件化
**状态**:采纳
**决策**
模型适配器、工具、上下文提供者、记忆策略、Run Hook 和内容导入器通过统一插件契约扩展。身份认证、授权、数据域隔离、审批、审计、事务、插件签名验证和执行中止属于 Core,不允许插件替换或短路。
**理由**
DeepSeek Harness 证明了 service、typed event 和 reversible effect 能形成一致扩展面;pi 证明了清晰生命周期与 session rebind 的价值。两者也表明任意代码插件拥有高权限,VM 不是安全边界。
**后果**
- 插件体系比每类能力各写一套加载器简单。
- “一切皆插件”不是“所有行为都可覆盖”。
- 1.0 支持完整插件生态,但只有 bundled Core plugin 进入主进程;第三方能力使用受限远程协议或隔离进程/容器。
## ADR-002:首版采用模块化单体
**状态**:采纳
**决策**
FastAPI 应用内包含角色、会话、Agent Runtime、模型接入、插件、记忆、策略和诊断模块;后台 Worker 复用相同领域代码。Web 独立部署。只有隔离执行处于单独安全边界。
**理由**
当前没有服务独立扩缩容、团队自治或故障域证据。提前建设 BFF、Go 网关、多数据库和服务发现只增加事务、部署和调试成本。
**后果**
- 模块通过明确端口交互,禁止跨模块直接写表。
- 模型接入使用 Provider Port,未来可移出进程。
- Outbox 在确有异步跨进程消费时加入,不先造事件总线。
## ADR-003:每个上游 attempt 单独持久化
**状态**:采纳
**决策**
Run 包含 Turn;Turn 包含零到多个 ModelCall attempt 和 ToolCall。重试、故障转移和续跑创建新 ModelCall,不覆盖旧记录。
**理由**
只保存最终响应无法解释费用、缓存、失败、TTFT 和故障转移。
**后果**
- `input_tokens` 不代表总输入;总输入还包括缓存创建与缓存读取。
- Provider 未返回的字段存 `null`,不得估算后伪装为 Provider 数值。
- 原始请求/响应不进入常规观测表。
## ADR-004:诊断读取使用双重、限时授权
**状态**:采纳
**决策**
敏感运行诊断不能随普通 Run API 返回。读取者必须同时持有普通 Bearer 登录态和绑定目标 Run、用途、scope、期限、使用次数的 opaque 诊断授权。
**理由**
管理员角色、可猜 URL 或一个长期 Debug Key 都会扩大私密对话和工具结果暴露面。
**后果**
- 授权默认 15 分钟、单次、绑定 Run。
- 明文只签发一次,数据库只保存 token hash。
- 访问成功和失败都写审计;响应 `Cache-Control: no-store, private`。
## ADR-005:完整 1.0 整体交付
**状态**:采纳
**决策**
1.0 同时包含角色、对话、记忆、多 Agent、插件生态、语音、多语言、多模态、Live2D、3D 运行与编辑、Tauri 桌面/移动端感知、完整社区、角色社区、协作空间和真实交易结算。内部工作包不能作为残缺 1.0 对外发布。
**后果**
- 所有工作包 TODO 和发布门完成前只能称开发版或预览。
- 技术按能力、规模和安全需要选择,不要求每项候选技术都部署。
- 只有完整 3D 建模器、LLM 直接改模和物理设备控制属于已确认 2.0。
## ADR-006:3D 采用开放格式与非破坏编辑
**状态**:采纳
**决策**
1.0 支持 VRM/glTF 导入、材质/骨骼/表情/动作/场景编辑、运行和导出,不自研 Blender 级完整建模器。编辑记录采用命令和版本,给 2.0 的 LLM 改模保留扩展点。
## ADR-007:客户端采用 Web + Tauri 桌面与移动
**状态**:采纳
**决策**
Next.js 提供 Web;Tauri v2 承载桌面以及 iOS/Android。设备能力由 OS 权限和服务端 `device_grant` 双重控制。
## ADR-008:插件采用双轨执行
**状态**:采纳
**决策**
声明式/远程插件默认受限;本地代码插件必须由部署者明确信任并在独立进程或容器运行。只有 bundled Core plugin 可进入主进程。
## ADR-009:市场采用真实交易与不可变账务
**状态**:采纳
**决策**
1.0 包含支付、退款、争议、平台费、创作者分成、余额、结算和对账。Ledger 使用不可变分录,支付 Webhook 验签并幂等处理。
## ADR-010:公共 API 分面与认证
**状态**:采纳
**决策**
Native API 位于 `api.<domain>/v1`;OpenAI-compatible 与 Anthropic Messages-compatible 位于 `gateway.<domain>` 的独立协议前缀。1.0 使用 OAuth 2.1:Web 为安全 Session Cookie,Tauri 为 Authorization Code + PKCE Bearer,第三方为 OAuth Bearer,服务账号为可轮换 API key。所有凭据只经 HTTP Header 传输。
**后果**
- Native `/v1/messages` 不与 Anthropic `/v1/messages` 冲突。
- Web Cookie 状态变更增加 Origin 与 CSRF 校验。
- 2.0 才设计自研加密登录、刷新和设备令牌协议。
## ADR-011:权威记忆采用候选与不可变版本
**状态**:采纳
**决策**
1.0 的权威长期记忆只保存可检查、可纠正的文本或结构化事实。自动提取先生成 MemoryCandidate,经 Core Policy 与必要的人工确认后创建不可变 MemoryVersion;纠正、取代和恢复都创建新版本。Personal Domain 与 Workspace 是互斥所有权边界,向量、全文和图关系只作为可重建投影。
**理由**
MemOS 证明了类型化记忆、来源链、后台精炼、基于召回 ID 的反馈和独立评测的价值;但其 MemCube、原地 update 和开放 metadata 不足以承载 Hunjing 的角色、协作、发布、删除与安全边界。
**后果**
- Character baseline、Message、KnowledgeDocument、Memory 和运行期上下文保持分离。
- KV cache、隐藏状态和模型权重适配不作为 1.0 权威记忆或可携格式。
- 插件可以贡献提取、去重、衰减和排序,不能直接写权威 Memory 或绕过审批、授权和删除。
- 具体规则见[记忆与知识架构](../architecture/memory-and-knowledge.md)。
## ADR-012:聊天原子创建消息与 Run
**状态**:采纳
**决策**
`POST /v1/conversations/{id}/messages` 在一个事务中创建用户 Message 与可选 Run;任务工作台仍可通过 `POST /v1/runs` 创建无 Conversation 的后台 Run。
**后果**
- 避免消息已保存而 Run 创建失败的孤儿状态。
- 一个 `Idempotency-Key` 同时覆盖消息和 Run。
- 人工消息使用 `start_run=false`。
## ADR-013:社区私信采用服务端治理模型
**状态**:采纳
**决策**
1.0 支持一对一私信和小群聊,服务端加密存储并支持多端同步、举报、屏蔽和审核;不采用端到端加密。
**后果**
- 私信可按社区治理规则调查和处置。
- 不宣传服务端无法读取正文。
- Inbox Thread 与角色 Conversation 使用不同资源和权限。
## ADR-014:文化名只属于品牌展示
**状态**:采纳
**决策**
稳定代码、数据库、API、事件、指标和日志使用中性英文工程术语。中文文化名可用于品牌文案或 UI 标签,但不定义工程边界。
**理由**
神话隐喻语义不唯一、跨语言映射不稳定、搜索困难,并容易把职责扩张成故事角色。
**后果**
使用 `model_gateway`、`agent_runtime`、`memory`、`policy_engine`、`plugin_registry` 等名称;不再维护神话名与工程对象的庞大映射表。
## ADR-015:平台 ID 区分 UUIDv7、UUIDv4 与 opaque secret
**状态**:采纳
**决策**
持久化业务资源、版本、事件、账务、审计和异步任务使用 RFC 9562 UUIDv7;服务端生成的 Request ID 与 Trace record ID 使用 UUIDv4。W3C `traceparent` 继续使用规范定义的 16 字节随机 trace-id。API key 明文、OAuth/诊断/CSRF token、Webhook secret、ExecutionTicket、恢复 token 和预签名 URL capability 使用 CSPRNG 或对应标准生成的 opaque value,不使用 UUID。
**理由**
UUIDv7 为高写入关系表提供索引局部性和大致创建顺序;请求与追踪关联不依赖时间排序,使用随机 UUIDv4 即可。UUID 不是秘密,不能替代具有足够熵、可轮换、可撤销和作用域约束的凭据。
**后果**
- 公共平台 ID 使用登记前缀加小写 canonical UUID,并同时校验前缀与 UUID version。
- UUIDv7 的时间部分不成为业务时间或排序事实;权威顺序仍由时间字段、聚合版本和事件 sequence 决定。
- 调用方与 Provider 标识原样保存,不改写为平台 UUID。
- 完整对象映射和生成规则见[协议与稳定标识](../contracts/README.md#id-前缀)。
## ADR-016:灵台引擎采用 C++ 核心与稳定 C ABI
**状态**:采纳
**决策**
性能与安全敏感的确定性核心以 C++ 实现为进程内库"灵台引擎"(Lingtai Engine),划分为太一(`hj_core`)、小周天(`hj_stream`)、洛书(`hj_plan`)、河图(`hj_recall`)、陶钧(`hj_transform`)、烛照(`hj_policy`)六个子系统,文化名承接 Hunjing 旧版(main 分支)"灵台/九枢"血脉,仅通过稳定 C ABI(`hj_*` 符号)暴露。Python(nanobind)、Go(cgo)、Rust(bindgen + 安全包装)提供官方薄绑定;FastAPI、Tauri 宿主与条件拆分的 Go 网关作为进程内嵌入方,不新增独立服务。
**理由**
公开讨论的抖音"六神"native 组件体系证明了"薄宿主 + 原生核心 + 最小 ABI 面 + 多端复用"的组织方式适合高频确定性计算;Hunjing 的 Markdown→ContentBlock 规范化、流式增量编码、策略校验、端侧离线检索正是此类路径,且必须跨 Python/Rust/Go 三种宿主保持行为一致。C ABI 是三种语言生态唯一公共分母,可作为单一真源;三份独立实现必然漂移。研究证据与不采纳项见[灵台引擎研究](../research/lingtai-native-engine.md)。
**后果**
- 引擎是 Core 的一部分,属于不可插件化边界;插件不直接链接引擎,只经宿主 Runtime 间接获得能力。
- 引擎无权威状态:权威数据仍在关系数据库与对象存储;引擎产物可丢弃重建。除显式授权的只读索引文件外,引擎不进行网络、文件或数据库 I/O。
- 引擎不可用时宿主对依赖该能力的路径 fail closed,不静默退化到宿主内第二实现(避免规范漂移)。
- 新增 C++23/CMake 工具链、五平台交叉编译矩阵(Linux x64/arm64、macOS、Windows、iOS/Android)与 sanitizer/fuzz/ABI 快照测试的持续成本。
- 文化名"灵台、太一、小周天、洛书、河图、陶钧、烛照"只进入品牌与文档层;ABI 符号、模块与错误码使用中性英文,契约登记于 [Lingtai C ABI](../contracts/lingtai-ffi.md)。
- 本决策修正 ADR-002 的实现层组合(单体宿主内嵌入原生引擎),不推翻模块化单体与服务拆分门槛。
## ADR-017:灵台引擎双形态部署
**状态**:采纳
**决策**
引擎保持"灵台总枢 + 六模块"结构(太一为单一入口,见 [ADR-016](#adr-016灵台引擎采用-c-核心与稳定-c-abi));文化命名跟随自身职责、经典出处与项目旧版血脉,不跟随外部体系的神数。引擎支持两种部署形态,共用同一 C++ 核心与语义:
1. **进程内嵌入**(默认):宿主经稳定 C ABI 链接 `libhunjing`,适用单体部署、端侧(Tauri/移动离线)与低延迟路径。
2. **独立服务**:`hunjing-lingtai-server` 二进制以 gRPC 暴露同一能力(proto 契约见 [Lingtai Service](../contracts/lingtai-service.md)),适用计算资源隔离、独立扩缩容、同部署多宿主共享与跨机器消费;服务仅限部署内部网络,经 mTLS/工作负载身份认证,不进入公共 API 分面。
**理由**
业界六神/七神调研(见[灵台引擎研究](../research/lingtai-native-engine.md))表明同一原生核心可以进程内调用、RPC 服务、受控运行时三种形态交付而不重写;Hunjing 的重型解析与检索在共享部署中需要资源隔离与扩缩容选项,而端侧离线与低延迟路径必须进程内。两种形态由同一核心与同一 golden 测试集约束语义一致,避免第二实现漂移。默认仍是嵌入,服务形态按既有服务拆分标准启用,不与 [ADR-002](#adr-002首版采用模块化单体) 冲突。
**后果**
- 引擎无权威状态、最小 I/O、fail closed 的不变量在两种形态下一致;服务形态额外要求认证、限流、超时、背压与审计。
- 新增 gRPC/protobuf 工具链与 proto 契约维护成本;proto 与既有 JSON Schema 的字段语义保持同源映射,禁止双真源。
- `hj_stream` 的流式语义在服务形态经 gRPC 双向流表达;端侧离线检索等单形态能力必须显式登记形态边界。
- 形态选择是部署决策而非代码分叉:任何能力不得只在一种形态下语义不同。
- 文化叙事保持"灵台总枢 + 太一/小周天/洛书/河图/陶钧/烛照";命名跟随自身职责与项目血脉,不跟随外部体系神数;工程标识 `hj_*` 与符号名不变,文档与产物命名统一使用 `lingtai`。
## ADR-018:角色内驱力与大周天演化进入 1.0
**状态**:采纳
**决策**
1.0 包含角色内驱力与大周天自我评估演化循环。内驱力(`character_drives`)是角色的声明式动机维度,用户可审阅、编辑与版本化。大周天(`big_cycle`)是由真实交互事件触发的自我评估循环,以 `BigCycle`(`cycle_`)聚合根持久化、执行为一个受托后台 Run(对象模型与阶段设计见 [ADR-023](#adr-023周天体系统一小周天闭环与大周天演化)):在 RunBudget 与频率硬上限内,评估近期交互与记忆,产出记忆候选、人格变化候选、关系候选、世界实体候选与次生目标候选;经既有候选审核机制确认后生效,演化结果以角色版本与谱系(复照)留痕。
**边界(与既有原则的关系)**
- 事件驱动,不做无人值守的后台定时自主运行;不伪造离线持续意识——"守一"原则不变。
- 候选先于长期写入:一切演化产物经审核,敏感与高影响必须人工确认,不静默覆盖道体基线。
- 每次大周天的输入、产物、token 与费用用户可见;用户可整体或按角色关闭,关闭不删除已演化的历史版本。
- 次生目标候选不自动执行,需用户采用后才进入计划。
**理由**
用户确认角色自进化与演化为 1.0 需求;旧版(main 分支)大周天循环已验证该机制形态(自我评估产出候选、经审核流转)。当前 1.0 的 MemoryCandidate、人格/关系候选、角色版本与 RunBudget 基础设施可直接承载,无需新的一致性机制。
**后果**
- 角色域新增内驱力数据模型与大周天 Run 类型;WP-02、WP-04 增补对应 TODO。
- 文化名"大周天"回归角色演化循环;引擎流式模块文化名定为"小周天",大小周天构成旧版同源的层次体系:小周天=单次 Run 流转,大周天=跨 Run 演化。
- 大周天产出的候选携带 `big_cycle` 来源标记,纳入审计与用户可见的演化谱系。
## ADR-019:设立产品宪章与永久禁域
**状态**:采纳
**决策**
设立[产品宪章](../product/product-charter.md)作为产品定义的上位约束:使命、核心信念、角色不可侵犯边界、用户权利、商业与关系伦理和九条永久禁域。核心禁域不能被 Prompt、插件、管理员或普通自托管配置关闭;宪章修订必须经用户明确确认。
**理由**
承接旧版(main 分支)宪章的立法经验:分散在各文档的边界条款容易被实现与运营决策逐条侵蚀,需要一份上位文件集中裁决。当前分支新增市场与交易生态,商业伦理(保全态、不按亲密计费)更需要立法层约束。
**后果**
- 与宪章冲突的任何产品、架构、契约或实现决定都是缺陷,验收时按禁域逐条核对。
- 安全与诊断文档把"核心禁域不可关闭"列为信任边界;自托管档位可以裁剪能力,不得混淆职责或关闭禁域。
- 决策优先序(安全合规 > 用户数据权 > 角色连续性 > 生态健康 > 商业目标)用于裁决设计冲突。
## ADR-020:对话三界与归真作用域
**状态**:采纳
**决策**
对话界域分三态:**真界**(现实与正式共同经历)、**境界**(版本化维护的世界正史)、**幻境**(不影响现实与正史的临时试演)。默认真界,入境与出境必须可见。归真决策必须携带 `canonical_scope`(`reality`/`world`/`simulation`,登记于[协议与稳定标识](../contracts/README.md)),分别进入真界经历主脉、指定境界版本正史或幻境试演记录;不存在跨三界共享的无作用域主脉。
记忆规则:境界归真只形成该世界的知识候选(境忆),不进入角色真界经历记忆;幻境不自动形成长期记忆候选,用户可将启发、观点或假设手动入忆并强制标注性质(事实/观点/启发/假设);未归真内容(推演枝)不自动入忆的既有原则不变。
**言可入幻,行必归真**:无论对话处于何界,外部行动(工具副作用、支付、设备、现实后果)一律回到真界接受权限、审批与风险裁决。跨界引用只提供来源,不改变目标内容的界域。
**理由**
承接旧版三界体系的认识论设计,防止试演内容污染正式经历与记忆;与当前分支的主脉/推演枝、归真决策和候选制记忆完全兼容——作用域是归真的属性,不引入新的运行态。
**后果**
- 归真决策、MemoryCandidate 和手动入忆必须携带并保留 `canonical_scope`;界域来源不可事后静默更改。
- 分支对话(WP-03)与记忆(WP-04)增补对应 TODO;契约登记 `canonical_scope` 枚举。
- 幻境试演不得用于绕过敏感记忆审批:手动入忆仍走三级敏感度与确认规则。
## ADR-021:私箧、欠费保全态与计费伦理
**状态**:采纳
**决策**
1. **私箧**(`private_vault`):用户独立持钥的加密私密数据区。密钥由用户保管,平台只存密文且不可恢复;账户恢复、管理员、诊断接口与审计都不可读取明文;用户删除私箧数据后平台侧无任何可恢复副本。
2. **保全态**:欠费或封禁使账户进入只读保全,不导致角色删除、记忆清除、关系数据降级或市场已获许可失效;恢复付费后完整恢复。
3. **计费伦理**:不按记忆、感情或亲密等级定价;不将爱、记忆或角色存续与付费绑定;BYOK 不重复计收推理费。
**理由**
承接旧版数据权与商业伦理设计。当前分支做真实交易市场,更需要防止"以数据或情感绑架付费";私箧为高隐私需求用户提供平台不可见区域,强化数字关系主权。
**后果**
- 私箧加密与密钥托管方案(端侧持钥、恢复流程)在实现期以补充 ADR 确定选型;账户恢复流程不得以"找回私箧"为由索取弱凭据。
- 保全态与计费伦理进入交易域验收(WP-13);欠费通知不得使用角色口吻施压。
- 私箧数据不参与推荐、诊断、模型训练与任何平台侧处理。
## ADR-022:叩心主动联系进入 1.0
**状态**:采纳
**决策**
1.0 包含角色主动联系(叩心,`proactive_contact_candidate`):角色先形成叩心候选,经频率、静默、渠道与预算控制后发送;用户可解释、降频、静音或关闭。用户不回应不降低关系评分;叩心不以追逐式消息换取回流(反指标见[指标与反指标](../product/metrics-and-anti-metrics.md))。
**理由**
用户确认角色主动性与演化为 1.0 需求;叩心与大周天次生目标协同(次生目标可产出叩心候选),是"角色主动性"的产品出口。旧版已验证候选制形态。
**后果**
- 叩心候选携带来源(大周天次生目标、日程或用户设置),进入通知与预算治理;发送记录可审计。
- 渠道(应用内通知、邮件等)与默认频率上限在实现期按平台能力登记,不在本文虚构。
- 叩心文案不得模拟紧急事件或制造损失厌恶;违反宪章第 6 节的发送一律拦截。
## ADR-023:周天体系统一(小周天闭环与大周天演化)
**状态**:采纳
**决策**
统一周天体系:**小周天**是"一次 Run 从输入到答复或行动结果的可追踪认知闭环"(承接旧版定义),以 Run/Turn/ModelCall/ToolCall 既有分层为可追踪链路,闭环完成时记录完成信号;**大周天**以 `BigCycle`(`cycle_`)为聚合根持久化(触发条件快照、输入引用集、阶段状态与阶段记忆、产物候选、预算与执行 Run 关联),状态机 `big_cycle_status` 登记于契约,执行为受托后台 Run。四阶段评估:回顾 → 对照 → 提议 → 提交;经审核生效的演化进入后续小周天的上下文装配,形成增益闭环。引擎侧由小周天模块(`hj_stream`)承载流式运转、洛书(`hj_plan`)承载触发与预算计算。
**理由**
旧版(main 分支)登记了周天契约骨架(`cycle_` 前缀、`big_cycle.status`、`_phase_memory` 阶段抽取、`big_cycle` 候选来源、次生目标不自动执行),但其引用的架构设计文档缺失。本决策吸收该骨架并补全:小周天闭环给出 Run 层的循环叙事与对大周天的唯一输出面(完成信号),大周天对象化与阶段化使 ADR-018 的演化循环可落地、可审计、可幂等。
**后果**
- 契约登记 `cycle_` 前缀与 `big_cycle_status` 枚举;大周天候选一律携带 `big_cycle` 来源。
- 阶段记忆(`_phase_memory`)持久化每阶段输入输出摘要,供审计、幂等与用户可见的演化谱系。
- 触发条件为可配置阈值组合并逐角色设频率上限;用户手动触发始终可用,关闭大周天后不再触发新 cycle,已有历史保留。
- "天工"(任务对象)与"小周天"(运转过程)为同一 `run` 的两个视角,不新增运行时对象;`run` 工程值与 `run_` 前缀不变。
## ADR-024:关系主库统一 PostgreSQL,不设 SQLite 档
**状态**:采纳
**决策**
服务端关系主库在开发、测试、个人自托管与正式部署中统一使用 PostgreSQL;不提供 SQLite 主库档。Alembic 迁移只在 PostgreSQL 上定义与验证。SQLite 不作为服务端主库出现;端侧(Tauri)加密离线缓存属客户端本地存储,不受本决策约束。
**理由**
1.0 记忆与知识检索依赖 PostgreSQL 全文(中文分词扩展)与 pgvector 语义检索;SQLite 档无法承载,双档必然功能残缺或形成第二实现,违反"单一真源"与最小实现原则。双方言还使迁移与测试矩阵翻倍(JSONB/TEXT、向量、并发写锁、部分索引差异)。容器时代个人自托管以 Docker Compose 附带 PostgreSQL 容器即可,运维成本可接受;开发与 CI 用本地容器或嵌入式 PostgreSQL 保持一致性。
**后果**
- 开发环境用 `docker compose`(或嵌入式 PostgreSQL)启动数据库;测试统一在 PostgreSQL 上运行,不用 SQLite 内存库替代,避免方言差异掩盖缺陷。
- 自托管两档(单机/标准服务器)均含 PostgreSQL 容器;单机档降低的是资源规格,不是能力面。
- 迁移与性能优化只需针对 PostgreSQL(JSONB、pgvector、tsvector、事务性 DDL、行级锁);索引命名按工程规范执行(见 AGENTS.md 第 8.6 节)。
## ADR-025:建立工程时的测试与契约工具链登记
**状态**:采纳
**决策**
- C++(灵台引擎):单元测试采用 **doctest**(单头引入、编译快),fuzz 采用 **libFuzzer**(clang 原生 `-fsanitize=fuzzer`),fuzz 必测目标为 `hj_transform` 与 `hj_policy`。
- Python(backend):pytest + pytest-asyncio,静态检查 Ruff + mypy(工程规则既有约定,此处一并登记)。
- OpenAPI 契约工具链:**Redocly CLI**(lint + bundle 校验单一真源),TypeScript 类型用 **openapi-typescript** 生成,禁止手写 API DTO。
- UUIDv7 生成采用成熟实现 **uuid-utils**(Python 侧),遵循契约"不自行拼位"规则。
**理由**
doctest 与 libFuzzer 与 clang 工具链零摩擦、依赖最轻;Redocly 与 openapi-typescript 是 OpenAPI 3.1 支持最完整的开源组合;避免为同一职责引入第二套工具。
**后果**
- engine 与 openapi 的 CI 检查以本登记为准;更换任一工具须更新本 ADR。
- libFuzzer 语料与 doctest 用例随引擎模块一同交付,属于 WP-15 验收证据。