Files
knowledge-governance/docs/DOMAIN_MODEL.md
zheromiku dcdc8d1ddd feat: 知识治理平台(含已验证发布/回滚契约)
全栈知识治理平台首次入库(P1-P10 + 发布链路模拟验证闭环):

- 治理核心:源目录/变更集/人工审核/发布批次/发布执行(fail-closed 闸口)
- 测试通道:WeKnora 测试 KB 上传/轮询/验收;poll 完成时写入
  parser_generation/index_generation,修复 manual/seed 路径发布闸口永久拦截
- 发布适配器 v071(本地 source=测试角色 / 云端 target=生产角色 模拟验证通过):
  * ES 导出/导入 mapping 自适应(.keyword 子字段、可选 tenant_id)
  * OSS locator 支持嵌套 scheme;chunks.seq_id 由目标序列分配
  * bundle 归档同身份重试原子替换;verifier 按 bundle chunk_type 计数
  * 回滚 job payload 支持 prior_execution_id(strict 解码)
- 三通道发布+回滚演练实测:publish 4/4 verified,检索命中,
  rollback 4/4 rolled_back,目标端 PG is_enabled=false、ES is_enabled=false
- 前端 A·Data-console 风格全站统一,120 用例通过
- 门禁:go vet / go test 全包通过,gofmt 干净
2026-09-30 10:54:06 +08:00

294 lines
10 KiB
Markdown
Raw Permalink 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.
# 知识治理平台领域对象契约
## 目的
本文件是知识治理平台当前实现的唯一领域对象映射。它将产品术语映射到现有Go模型、PostgreSQL表和外部边界;后续模块不得另造一套身份、时间或状态语义。
本文件不把“代码存在”“容器健康”写成已完成能力。尚未存在的对象或关联明确列在 [Current implementation gaps](#current-implementation-gaps)。
## 统一主链
```text
SourceConnection → SourceItem → SourceItemVersion → ContentObject
SourceConnection → SourceCatalogSnapshot → SourceCatalogNode
SourceCatalogChangeSet → SourceCatalogChangeItem
SourceItemVersion → TestPublication → AcceptanceResult
ReleaseBatch → ReleaseExecution → ReleaseItemExecution
```
完整目标主链将在后续工作包补齐为:
```text
SourceConnection
→ SourceItem / SourceItemVersion / ContentObject
→ SourceCatalogSnapshot
→ SourceCatalogChangeSet
→ ProcessingExecution / Job
→ TestPublication / AcceptanceResult
→ ReleaseChangeSet
→ ProductionSnapshot
→ ReleaseBatch / ReleaseExecution
```
## 全局身份与时间规则
| 规则 | 契约 |
| --- | --- |
| ID | 所有主对象使用服务端生成的不透明ID;页面和Job Payload只能传递ID,不能传递受保护来源URL、Token或Cookie。 |
| 时间 | `created_at`表示治理对象创建;`updated_at`表示本对象最后治理状态变化;来源侧时间必须单独使用`updated_at_source`或`source_updated_at`。 |
| 内容Hash | 只有`content_objects.sha256`是文件内容SHA-256。`canonical_uri_hash`、`source_locator_hash`和`snapshot_sha256`绝不能作为内容Hash展示或用于内容去重。 |
| 删除 | 来源不可用不等于来源删除。只有权威来源删除事件或经人工确认的删除ChangeSet才可进入目标移除流程。 |
| 目标写入 | 普通治理层不直接写WeKnora数据库;测试写入通过官方API/受控适配器;生产发布由独立Release Worker和门禁处理。 |
## Source
**产品含义:**一个独立配置、独立健康状态、独立刷新策略的资料来源。
**当前实现:**
| 项目 | 当前映射 |
| --- | --- |
| Go模型 | `governance.SourceConnection` |
| 数据表 | `source_connections` |
| 主键 | `source_connections.id` |
| 类型 | `source_type`:当前为`pp`、`alist`、`dingtalk`;`manual`是Go层支持的扩展类型。 |
| 时间 | `created_at`、`updated_at` |
| 可变配置 | `enabled`、`schedule`、`last_health` |
| 敏感字段 | `base_url`、`secret_ref`;不得返回前端或日志。 |
**不可变/关系约束:**
```text
一个SourceConnection可以有多个SourceItem。
一个SourceConnection可以有多个SourceCatalogSnapshot。
SourceItem、Snapshot、ChangeSet不得跨SourceConnection关联。
```
## SourceFile
**产品含义:**来源中的一份可治理资料,以及该资料的每个来源版本和内容对象。
SourceFile不是一个单表对象,当前由三个对象组成:
| 逻辑层 | Go模型 | 数据表 | 稳定身份 |
| --- | --- | --- | --- |
| 文件身份 | `governance.SourceItem` | `source_items` | `(source_connection_id, stable_external_id)` |
| 文件版本 | `governance.SourceItemVersion` | `source_item_versions` | `(source_item_id, revision)` |
| 内容对象 | `governance.ContentObject` | `content_objects` | 全局`sha256` |
**关键字段:**
```text
SourceItem:
- source_connection_id
- stable_external_id
- canonical_uri_hash
- normalized_path
- revision
- updated_at_source
- source_change
SourceItemVersion:
- source_item_id
- revision
- content_object_id(内容尚未下载或验证前允许为空)
- content_state
- source_updated_at
ContentObject:
- sha256
- size_bytes
- mime
- validated_format
- local_spool_ref
- content_state
```
**关系规则:**
```text
路径变化不必然产生新SourceItem。
内容Hash变化产生新的SourceItemVersion或新的内容关联。
同一内容Hash可以被多个SourceItemVersion复用,但每个版本仍保留自己的来源身份和来源时间。
TestPublication必须引用一个SourceItemVersion,不能直接引用路径或ContentObject。
```
## Snapshot
**产品含义:**一次来源目录扫描获得的不可变目录事实;它记录当时看到的文件/目录,而不是文件正文副本。
**当前实现:**
| 项目 | 当前映射 |
| --- | --- |
| 快照表 | `source_catalog_snapshots` |
| 节点表 | `source_catalog_nodes` |
| 当前指针 | `source_catalog_heads` |
| 快照主键 | `source_catalog_snapshots.id` |
| 来源约束 | `(source_connection_id, snapshot_sha256)`唯一 |
| 时间 | `observed_at`、`created_at`;Head使用`activated_at` |
| 目录节点 | `node_type=folder` |
| 文件节点 | `node_type=file` |
**Snapshot规则:**
```text
SourceConnection → SourceCatalogSnapshot → SourceCatalogNode
Head只指向一个当前快照;切换Head不得修改旧快照。
节点的source_locator_hash是来源定位摘要,不是内容Hash。
节点可选关联source_item_id;未关联节点仍可作为目录事实展示。
```
**操作记录补充:**`source_scans`和`source_scan_changes`是旧扫描运行记录,不能替代当前不可变目录快照。
## ChangeSet
**产品含义:**两个不可变来源Snapshot之间的可审查差异计划。
**当前实现:**
| 项目 | 当前映射 |
| --- | --- |
| 主表 | `source_catalog_change_sets` |
| 条目表 | `source_catalog_change_items` |
| Go投影 | `governance.CatalogChangeSet`、`CatalogChangeItem` |
| 主键 | `source_catalog_change_sets.id` |
| 快照关系 | `from_snapshot_id`、`to_snapshot_id` |
| 动作 | `add`、`update`、`move_scope`、`delete`、`no_change` |
| 时间 | `created_at`、`confirmed_at`、`applied_at` |
| 当前状态字段 | `planned`、`confirmed`、`applied`、`cancelled` |
**ChangeSet规则:**
```text
一个ChangeSet只能属于一个SourceConnection。
from_snapshot_id和to_snapshot_id必须属于同一SourceConnection。
to_snapshot_id当前唯一,因此一份激活快照最多对应一份目录ChangeSet。
ChangeItem当前使用(change_set_id, source_locator_hash)唯一。
ChangeSet只表达比较结果;它本身不等于已经上传、解析或删除。
```
**后续目标:**S8/P3/P5会补充SourceItemVersion、内容Hash、旧新范围、确认执行和Job关联。
## Job
**产品含义:**可租约、可重试、可恢复的异步工作项;Job只保存安全业务ID和进度,不保存敏感连接数据。
**当前实现:**
| 项目 | 当前映射 |
| --- | --- |
| Go模型 | `jobs.Job`(`internal/jobs`) |
| 数据表 | `jobs` |
| 主键 | `jobs.id` |
| 幂等 | `idempotency_key`唯一 |
| 调度 | `priority`、`available_at` |
| 租约 | `lease_owner`、`lease_until` |
| 尝试 | `attempt`、`max_attempts` |
| 时间 | `created_at`、`updated_at`、`started_at`、`completed_at` |
**当前Job类型示例:**
```text
source.catalog.refresh
test.upload
test.poll
test.validate
test.remove
release.publish
release.rollback
```
**Job规则:**
```text
Job完成只表示本地处理器完成;对于WeKnora解析,必须继续由test.poll确认远端终态。
Job payload不允许保存Token、Cookie、签名URL、原始文件内容或生产凭据。
ReleaseExecution通过job_id外键绑定发布Job。
```
## Release
**产品含义:**把经过测试验收的知识,以可追溯、可验证、可回滚方式发布到生产。
当前Release由批次、执行和执行项组成:
| 逻辑层 | Go模型 | 数据表 | 主键 |
| --- | --- | --- | --- |
| 发布批次 | `governance.ReleaseBatch` | `release_batches` | `id` |
| 批次条目 | `ReleaseBatchItemView`投影 | `release_batch_items` | `(release_batch_id, publication_id)` |
| 发布执行 | `governance.ReleaseExecution` | `release_executions` | `id` |
| 执行条目 | `ReleaseItemExecutionView`投影 | `release_item_executions` | `id` |
**Release关系:**
```text
ReleaseBatch → ReleaseExecution → ReleaseItemExecution
ReleaseExecution → Job(通过job_id)
ReleaseItemExecution → TestPublication(通过publication_id)
Rollback ReleaseExecution → prior publish ReleaseExecution
```
**Release规则:**
```text
ReleaseBatch sealed后内容不可变。
一个批次最多有一个publish execution。
一个publish execution最多有一个rollback execution。
ReleaseItemExecution记录生产前后revision和安全错误码。
只有独立生产门禁、备份恢复验证和Release Worker均满足时才可以请求生产执行。
```
## TestPublication和验收(辅助对象)
TestPublication不是原始SourceFile,也不是生产Release;它表示某个SourceItemVersion在指定测试知识库中的处理实例。
```text
SourceItemVersion → TestPublication → AcceptanceResult
```
| 项目 | 当前映射 |
| --- | --- |
| 测试发布 | `governance.Publication` / API投影`TestPublication` / 表`test_publications` |
| 验收结果 | `governance.AcceptanceResult` / 表`acceptance_results` |
| 身份 | `(source_item_version_id, test_kb_id)`唯一 |
| 处理维度 | ingest_state、processing_state、retrieval_state |
| 版本维度 | parser_generation、index_generation |
## 当前实现缺口
### Current implementation gaps
以下缺口是已知事实,不能在任何页面、报告或测试中标为“已完成”:
1. `SourceCatalogNode`尚不能为所有来源绑定`SourceItem`和`SourceItemVersion`。
2. 目录Snapshot节点尚未持久保存文件内容SHA-256;`snapshot_sha256`不是文件内容Hash。
3. `SourceCatalogChangeItem`尚未保存旧新内容Hash、旧新范围和SourceItemVersion关联。
4. ChangeSet确认尚未直接创建Processing Job;当前Processing Confirmation仅绑定TestPublication。
5. Job尚未通过统一外键绑定ChangeSet、文件版本、目标和动作;该工作属于P3/P5。
6. `ReleaseChangeSet`和`ProductionSnapshot`尚未实现;当前Release Plan是实时计算,不能冒充不可变发布ChangeSet。
7. 当前ReleaseExecution没有来源Snapshot、来源ChangeSet、发布ChangeSet和生产Snapshot的完整外键链;该工作属于R1、R2、R6。
8. Source配置、SourceFile身份和内容Hash的运行时证据仍需后续S2、P1、P2补齐。
## C1验收边界
C1只完成以下内容:
```text
冻结当前对象术语和真实映射
明确身份、时间和关系规则
标出当前不存在的对象和关联
用测试防止领域契约文档丢失关键对象
```
C1不完成:
```text
统一状态机(C2)
OpenAPI(C3)
写操作幂等(C4)
内容Hash闭环(P1)
ChangeSet执行(P3)
发布ChangeSet或Production Snapshot(R1/R2)
```