同一个问题,代码、Jira 和 Confluence 各能回答到哪里

跨来源检索真正难的不是找到更多文本,而是判断需求、设计和当前代码分别能证明什么。

本页目录 · 9 节

「订单查询为什么没有返回这个字段?」

Jira 可能写着需求已经完成,Confluence 可能描述过设计,仓库里可能存在同名 Resolver,线上结果却仍然为空。四条材料可以同时为真,因为它们回答的是四个不同问题:团队想做什么、当时怎样设计、某个 Commit 实现了什么、某个环境实际运行了什么。

企业 RAG 最先要解决的不是召回率,而是来源权威边界。如果进入索引后只剩下一段匿名文本,系统越擅长总结,越容易把不同时间和证明能力的材料合成一段错误故事。

本篇知识地图

flowchart LR
  Q["工程问题"] --> I["Intent<br/>Jira"]
  Q --> D["Design<br/>Confluence"]
  Q --> C["Implementation<br/>Pinned Git Commit"]
  Q --> B["Business Config<br/>Read-only DDB Scope"]
  I --> E["SourceRecord + Evidence Locator"]
  D --> E
  C --> E
  B --> E
  E --> V["按问题类型选择最终验证来源"]

这一章涉及五个核心知识点:Source Authority、Stable Identity、Metadata-only 与 Body-loaded 的区别、Temporal Semantics,以及最小权限采集。

当前接入的来源,不是四堆等价文本

mt_rag 当前本地数据范围有明确边界:

来源 当前采集范围 最适合证明 不能单独证明
Jira 受控项目范围内的 Issue、描述、评论、Changelog、Worklog、Remote Link、附件元数据与可读附件 需求、接受范围、状态变化和讨论 当前代码、部署版本、线上行为
Confluence 受控入口页及其 Descendants、多种 Body Format 与附件 设计背景、业务规则、术语和历史决定 当前调用链、某分支已实现
Git/Bitbucket 本机递归发现到的 Repository Inventory,逐仓更新到 main/master 后 Pin Commit,再解析代码 被 Pin Commit 中的静态实现、Symbol、Call Evidence Bitbucket Workspace 全量覆盖、生产部署、运行时动态分派
Business Config 仅经单独确认的、非用户态只读配置范围 某次授权读取到的配置结构 用户态、交易与支付数据、实时生产行为

高成本或当前不支持的附件只保留 Metadata,不下载、不重试、不抽取文本。Business Config 明确排除任何用户态、交易态、支付态或可识别个人的数据;它仍然属于持久数据读取,必须经过单独的风险说明和显式确认,不能因为「RAG 需要更多数据」就自动执行。

PR 在目标合同中有独立 Source Type,但当前没有独立 PR Collector。图中的 PullRequest 主要来自 Jira/Confluence 文本中的 URL,是 link-derived entity;它不包含完整 Diff、Comments、Approvals 或 Revision。现有直接证据以 Pinned Code、Jira/Confluence Raw 和已采集 Remote Link 为准。合同允许一种来源,不等于当前 Corpus 已完整覆盖它。

SourceRecord:目标合同与现有采集产物之间仍有距离

SourceRecordV1 定义了希望所有来源最终遵守的严格合同。它不只保存正文,而是把一条来源记录拆成几个互不替代的域:

record_id / source_type / native_id
record_payload_hash
content_status
original_blob + original_content_hash
created_at / updated_at / observed_at
source_url / attachment_urls
freshness / metadata / provenance

这里最重要的是 content_status 的 Fail-closed 语义:

  • available 必须同时拥有 Original Blob 与 Original Content Hash;
  • metadata_onlyunavailable 不允许假装自己有正文;
  • 下游看到一个页面标题和 URL,只能说「找到了这个页面」,不能总结页面内容。

但不能把目标合同写成已经完成的迁移。当前生产 Collector 主要仍输出 Legacy Raw JSON 和 SourceManifestEntryV1SourceRecordV1 的直接构造更多出现在 Legacy Adapter 与测试中。查询侧已经执行同方向的 Fail-closed 约束:Confluence Result 只有 document_read_status=body_loaded 才能进入业务 Summary;metadata_onlybody_missing 只能作为定位线索。这里的真实状态是「下游合同已经收紧,上游格式仍在迁移」。

稳定身份不能用标题

页面会改名,Issue 状态会变,代码行号会移动。稳定 ID 必须由来源的 Native Identity 构造,而不是由显示文本构造:

对象 稳定身份
Confluence Page con_<content_id>
Jira Issue jira_<ISSUE_KEY>
Repository Workspace + Repo Slug
Attachment Parent Source Record + Native Attachment ID
Code Symbol(目标 Helper) Repo、Language、Relative Path、Kind、Qualified Name

目标 code_symbol_id() 不包含 Commit 和 Line Range。原因是它表达「逻辑上的同一个 Symbol」;Commit、Line 和内容 Hash 属于这一版证据的 Revision/Locator。反过来,如果把 Commit 塞进实体 ID,每次代码更新都会制造一个全新实体,图上就无法表达同一个 Symbol 的版本变化。

这里还有一个尚未收敛的实现缺口:实际 CPG _node_id() 目前把 Line 编入 Hash,Symbol 仅移动行号就会改变 Node ID。现有 Stable-ID 测试覆盖的是 Helper,并不能证明真实 CPG Node Identity 已跨行移动稳定。文章保留这一差异,因为它正是 Canonical Migration 需要继续解决的问题。

同一个字段问题,正确阅读顺序是什么

假设要判断一个 GraphQL Field 是否已经贯通:

  1. 从 Jira 确认字段是否在接受范围内,而不是只在评论中被提过;
  2. 从 Confluence 理解字段的业务语义和当时的方案,但记录页面版本与更新时间;
  3. 从目标仓库的 Pinned Commit 定位 Operation、Selected Field、Resolver 和 Provider;
  4. 只有出现 USES_OPERATION -> SELECTS_FIELD -> RESOLVES_FIELD 等带 Evidence 的 Graph Edge,才把关系写成已验证调用链;
  5. 如果问题问「生产是否生效」,还要另查 Deployment/Runtime Readback。当前静态 Corpus 到这里必须停下。

这不是固定的「Jira 优先级低于代码」。优先级取决于问题:问需求就以 Jira/设计为主,问实现就以当前 Commit 为主,问生产状态则这些静态来源都不够。

Code Source 为什么要先 Pin

代码采集的核心不是「扫描某个目录」,而是建立可重复读取的 Revision。

当前 Source Gate 会先递归发现代码仓库,并通过显式 Denylist 排除历史工作区副本;更新前对所有仓库做 tracked-change Preflight,发现冲突就全局阻断,不 Reset、Clean 或 Stash 用户改动。然后逐仓执行 fetch --prune、解析 origin/HEAD 或唯一可用的 main/masterpull --ff-only,验证 HEAD == origin/<branch> 后记录 Commit Pin。

解析阶段会再次验证 Pin,再从已验证 Working Tree 路径读取字节并把 Commit 写进 Locator;它不是逐文件执行 git show <commit>:<path>。因此正常情况下 Working Tree 与 Pin 对齐,但验证和实际读取之间仍存在较小的 TOCTOU 窗口。网络失败时,显式 Degraded Mode 只允许 Pin 一个干净且恰好等于缓存 Remote Ref 的分支,并标成 stale_remote_unreachable,不会声称 Fresh。

失败模式与取舍

失败模式 保护策略 取舍
页面只有标题,没有正文 metadata_only,禁止正文总结 少给一个答案,也不根据标题猜业务规则
Jira 状态为 Done 只证明工单状态,不能映射成部署成功 需要额外 CI/部署/运行时证据
仓库 Dirty 或无法 Fast-forward 本轮 Code Extraction Fail Closed Freshness 让位于不覆盖开发者工作和可重复性
Remote 不可达 可用缓存 Pin 只能标 Stale 能定位旧入口,但不能宣称当前
增量采集里没看到某对象 不把「缺席」当删除 真删除要等权威 Full Inventory/Reconciliation
DDB 范围不清楚 默认不执行;仅允许固定 Read-only Business Config Scope 少收数据以换取隐私、成本与生产安全
Scheduled Jira Handoff 当前定时命令先完整 Collect,再只 Enrich Placeholder;可能没有 Jira Issue Source Event Raw 已更新不等于 V3 Journal 已闭环,需要补事件验收
旧 Full Refresh 入口读取 DDB 兼容路径不自动继承 Weekly Gate 仍需外部安全确认,不能把 --read-only 当零风险

可复核的项目证据

  • Source Policy 配置:受控文档入口、Issue 范围、Code Source Gate 和 Business Config Include/Exclude Scope;
  • src/mt_rag/core/system_contracts.pySourceRecordV1EvidenceRefV1content_status 不变量;
  • src/mt_rag/operations/cli.py:Jira/Confluence Collector、附件、Raw 写入与当前 Source Event Handoff;
  • src/mt_rag/code/repositories.py:Repo Discovery、Inventory Comparison、Dirty Preflight、Branch Resolution 与 Pin;
  • src/mt_rag/documents/jira.py:Description、Comments、Changelog、Worklog、Remote Link 转成可定位 Block;
  • src/mt_rag/documents/batch.py:Confluence Raw 到 DocumentIR 与 CAS;
  • README.md 的「当前数据范围」与「可重入策略」:实际 Corpus、附件与 DDB 边界。

参考资料

跨来源 RAG 的第一条原则不是「接得越多越好」,而是每条材料进入系统后仍然知道自己是谁、来自哪一版,以及它最多能证明到哪里。

相关文章

在做类似的事情?

很乐意就分布式系统、交付流程和应用 AI 交换意见。

[email protected]