路径、Hash 与 ID 规则
# 路径、Hash 与 ID 规则
修订记录
| 版本 | 日期 | 修订说明 |
|---|---|---|
| v0.1 | 2026-05-01 | 建立当前设计基线;延续 kunora-wiki 作为 llm-wiki 方案的既有产品封板和工程设计,不推倒重来。 |
1. 文档目标
本文定义 kunora-wiki 自研模块共享的路径规范化、内容 hash、对象 ID、运行 ID、请求 ID、幂等键和去重键规则。
这些规则会被 DocumentRecord、SyncChange、manifest、索引、引用回跳、反馈去重和审计日志共同使用。任何模块不得私自定义第二套路径、hash 或 ID 规则。
2. 总体原则
| 原则 | 约束 |
|---|---|
| 稳定 | 同一逻辑对象在不同运行中应得到相同 ID。 |
| 可重建 | ID 和 hash 应尽量能从已有事实源重新计算。 |
| 可比较 | path、hash、documentId 必须能跨模块比较。 |
| 不泄密 | dedupeKey、idempotencyKey 不包含明文敏感信息。 |
| 不依赖时间 | 内容 hash、documentId 不依赖文件修改时间。 |
| 不依赖外部产品私有 ID | RAGFlow、Meilisearch、GitHub 的内部 ID 不能作为 LLM-WIKI 主 ID。 |
3. 路径类型
| 路径类型 | 示例 | Owner | 说明 |
|---|---|---|---|
repoPath | docs/index.md | SourceReader | 来源仓库内路径。 |
sourcePath | docs/** | SourceConfig | 来源配置声明的读取范围。 |
publishPath | publish/system/components/kunora-kgent/index.md | SourceConfig / WorkspaceStore | LLM-WIKI 工作目录路径。 |
statePath | state/source-lock.json | WorkspaceStore | 状态和 manifest 路径。 |
siteUrl | /system/components/kunora-kgent/ | DisplayBackend Adapter | 展示站 URL。 |
anchor | #配置说明 | DisplayBackend Adapter / Answer API | 页面内锚点。 |
4. 路径规范化规则
所有自研模块内部统一使用 NormalizedPath。
规则:
- 使用 UTF-8 字符串。
- 使用
/作为路径分隔符。 - 不允许 Windows 反斜杠
\\进入契约对象。 - 不允许绝对文件系统路径进入契约对象。
- 不允许
.、..、空 segment。 - 不允许路径末尾
/,除非该字段明确表示 URL 目录。 publishPath必须以publish/开头。statePath必须以state/开头。- 路径比较默认大小写敏感。
- URL path 和 repository path 是不同类型,不能混用。
非法路径示例:
| 输入 | 原因 |
|---|---|
C:\\repo\\publish\\a.md | 绝对文件系统路径。 |
publish/../docs/a.md | 包含 ..。 |
/publish/a.md | repository contract 中不允许前导 /。 |
publish//a.md | 空 segment。 |
publish/a.md/ | 文件路径不允许尾随 /。 |
5. Markdown 内容规范化
内容 hash 计算前必须先规范化 Markdown。
规范化规则:
| 项 | 规则 |
|---|---|
| encoding | UTF-8。 |
| line ending | 统一为 LF。 |
| BOM | 移除 UTF-8 BOM。 |
| trailing whitespace | 默认保留,除非后续格式化策略明确修改。 |
| final newline | 统一确保文件以单个 LF 结尾。 |
| frontmatter order | 不在 hash 阶段重排;重排属于内容变更。 |
| path separators in links | 不在 hash 阶段改写;链接规范化属于内容处理。 |
重要约束:
- hash 规范化只能消除平台差异,不能改变文档语义。
- 不允许在 hash 计算中忽略 frontmatter,除非字段明确标记为 runtime-only 并在数据结构文档中定义。
- 文件修改时间、Git author、提交时间不参与 content hash。
6. Hash 类型
| Hash 类型 | 输入 | 格式 | 用途 |
|---|---|---|---|
contentHash | 规范化后的 Markdown 内容 | sha256:<hex> | 判断文档内容是否变化。 |
sourceHash | 来源文件规范化内容 | sha256:<hex> | SyncEngine 判断上游变化。 |
publishHash | publish 文件规范化内容 | sha256:<hex> | SyncEngine 判断工作目录变化。 |
renderedHash | 展示构建产物规范化内容 | sha256:<hex> | 展示层漂移检测。 |
configHash | 规范化配置文件内容或配置 bundle canonical JSON | sha256:<hex> | 配置影响检测。 |
payloadHash | canonical JSON payload | sha256:<hex> | 幂等、去重和审计。 |
Hash 格式规则:
- 必须使用小写 hex。
- 必须带算法前缀:
sha256:。 - MVP 只允许
sha256。 - 如未来更换算法,必须通过版本化字段或 ADR。
7. Canonical JSON 规则
用于 payloadHash、dedupeKey、idempotencyKey 的 JSON 必须先 canonicalize。
规则:
- object key 按 Unicode code point 升序排序。
- 不输出多余空格和换行。
- 字符串使用 JSON 标准 escaping。
- array 顺序保持原始语义顺序。
- 忽略值为
null的可选字段,仅当该字段在契约中声明为 nullable 且 null 有语义时保留。 - 时间字段必须使用 UTC ISO-8601 格式。
示例:
{"path":"publish/a.md","sourceId":"demo"}
8. documentId
documentId 是索引、引用、manifest 对账的稳定文档 ID。
MVP 规则:
doc:<sha256(normalized publishPath)>
其中 hash 输入为不带前导 / 的 publishPath,例如:
publish/system/components/kunora-kgent/index.md
输出示例:
doc:4f2c...
规则:
documentId不包含 content hash,因此同一路径内容更新时 ID 不变。documentId不依赖 Docusaurus URL,因此展示层 URL 变化不改变文档身份。documentId不依赖 RAGFlow 或 Meilisearch 内部 ID。- rename/move 在 MVP 中视为旧
documentId删除、新documentId新增。 - 如未来需要跨路径保留身份,必须引入显式
stableDocumentId,并通过 ADR 修改规则。
9. chunkId
chunkId 用于引用 RAGFlow 或其他索引中的片段。
MVP 规则:
- LLM-WIKI 不把 chunkId 作为内容事实源。
- 如果 RAGFlow 返回 chunk ID,Answer API 可以保存为
externalChunkId。 - 标准引用必须至少包含
documentId、path、url或anchor中的可回跳信息。 - 如果需要自研 chunk,chunkId 规则另行设计,不能复用 RAGFlow 私有 ID 作为主键。
建议格式:
chunk:<documentId>:<ordinal-or-hash>
但 MVP 不要求自研 chunkId 稳定。
10. runId
runId 表示一次 workflow 或批处理运行。
格式:
run:<kind>:<yyyyMMddTHHmmssZ>:<short-random>
示例:
run:sync:20260429T081530Z:a1b2c3
run:publish:20260429T082000Z:f9e8d7
run:index:20260429T083000Z:012abc
规则:
kind必须来自受控枚举:sync、publish、index、answer、agent、review、config。- 时间使用 UTC。
short-random至少 6 个 base16 或 base36 字符。- runId 用于关联报告、manifest、workflow summary 和日志。
- 失败重试是否复用 runId 由对应 workflow 决定;同一逻辑发布重试应复用
publishRunId。
11. requestId
requestId 表示一次 API 或工具调用。
格式:
req:<yyyyMMddTHHmmssZ>:<random>
示例:
req:20260429T083015Z:8f3a21c4
规则:
- API 入口收到请求时生成,或接受可信上游传入的 requestId。
- requestId 必须进入 response audit 字段和服务日志。
- requestId 不参与业务幂等判断。
12. publishRunId
publishRunId 是一次发布、展示和索引对账的全局 ID。
格式:
pub:<yyyyMMddTHHmmssZ>:<gitShortSha>:<short-random>
示例:
pub:20260429T090000Z:5cad315:a1b2c3
规则:
- 一个 publishRunId 必须贯穿
publish-impact-report、publish-manifest、site-manifest、index-manifest和 workflow summary。 - 同一 publishRunId 的失败步骤可以重试。
- 新 publishRunId 不能复用旧 publishRunId 的半完成状态。
- publishRunId 不等于 Git commit,但必须记录对应 Git commit。