# 挖掘闭环：变更如何沉淀为组织记忆

Canonical source: https://maguyva.ai/zh-hans/blog/mining-workflow-closing-the-loop

License: text under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/); code samples under [MIT-0](https://opensource.org/license/mit-0); the Maguyva name, logos, brand assets and other code are not covered. Details: [maguyva.ai/license](https://maguyva.ai/license).

Date: 2026-02-03 · Author: Maguyva Team

> Git 提交会变成结构化的变更日志条目和架构决策记录，再反哺回 AI 智能体，成为可查询的组织记忆。

> *本文中的数字反映的是发布时（2026 年 2 月）的系统状态。如需查看最新数据，请参阅我们的 [团队页面](/zh-hans/team)。*

每个工程团队都面临同一个难题：变更每天都在发生，但这些变更背后的*原因*却会渐渐消失。六个月之后，有人会问“我们当初为什么在流水线阶段里采用了 DuckDB?”，而答案往往只存在于当初做出这个决定的人脑子里——前提是那个人还在。

我们搭建了一套挖掘工作流，把这个闭环补上了。变更通过 Git 提交流动，经由我们的挖掘流水线处理，变成结构化的变更日志条目和架构决策记录，再通过 CLI 查询反哺回我们的 AI 智能体。结果就是：一份人类和 AI 都能访问的组织记忆。

## 问题所在：决策会蒸发

设想一个典型场景。某个开发者提交了这样一条记录：

```
feat(canonical): add DuckDB runtime for pipeline stages
```

这次提交代表着一个重大的架构选择。团队评估过多个方案、权衡过各种取舍，最终出于特定原因选定了 DuckDB。但所有这些上下文，都散落在：

- 某个 Slack 讨论串里（大概率已经被删了）
- 某个人的记忆里（必然正在淡去）
- 代码里的某条注释里（如果你运气好的话）

三个月后，一位新加入团队的成员问道：“这个新阶段我应该用 DuckDB 还是 SQLite?”没有组织记忆的情况下，他们要么重新发明一遍轮子，要么做出前后不一致的选择。

## 这个闭环：从提交到上下文

我们的挖掘工作流，把 Git 历史转化为可查询的知识：

```
Git Commits
    │
    ▼
┌─────────────────────┐
│  mine sync          │  ← Build index from git history
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  mine candidates    │  ← Surface commits for review
└─────────────────────┘
    │
    ▼
┌─────────────────────┐
│  Classification     │  ← Human or LLM assessment
│  (changelog or ADR) │
└─────────────────────┘
    │
    ├──────────────────────┐
    ▼                      ▼
┌─────────────┐    ┌───────────────┐
│ Changelog   │    │ Decisions     │
│ Ledger      │    │ Registry      │
│ (JSONL)     │    │ (YAML files)  │
└─────────────┘    └───────────────┘
    │                      │
    ▼                      ▼
┌─────────────┐    ┌───────────────┐
│ CHANGELOG.md│    │ orkestra CLI  │
│ per package │    │ queries       │
└─────────────┘    └───────────────┘
    │                      │
    └──────────────────────┘
              │
              ▼
      ┌───────────────┐
      │ AI Agents     │
      │ (via CLI)     │
      └───────────────┘
```

这里的关键洞见是：变更日志和架构决策，都来自同一份 Git 历史，经由同一套统一的流水线处理。这确保了不会有任何东西从缝隙中漏掉。

## 挖掘是如何进行的

### 第一步：同步索引

```bash
uv run orkestra mine sync
```

这个命令会扫描 Git 历史，为所有提交建立索引。它会从每次提交中提取结构化信号：

- 符合约定式提交（Conventional Commit）规范的类型（`feat`、`fix`、`chore`、`docs`）
- 作用域（涉及哪个包或哪个领域）
- 破坏性变更标记
- 涉及的文件以及复杂度指标

### 第二步：检查覆盖状态

```bash
uv run orkestra mine status
```

我们目前的状态大致是这样的：

```
Mining Status
=============

Decisions
---------
  Coverage:        100.0%
    Processed:     15637  (of 15637)
    Extracted:       476
    Skipped:       15161

Changelog
---------
  Coverage:        100.0%
    Processed:     15637  (of 15637)
    Released:       6799
    Skipped:        8838
```

15,637 次提交已被处理。476 次变成了架构决策。6,799 次变成了变更日志条目。每一次提交都被分类过了。

### 第三步：获取待审查的候选提交

```bash
uv run orkestra mine candidates --limit 50 --full
```

这会找出尚未处理过的提交，并附带用于分类的完整上下文：

```json
{
  "sha": "90571786d99166c0039ca2e80e4d9cd96184bd85",
  "date": "2026-01-26",
  "subject": "feat(canonical): add DuckDB runtime for pipeline stages",
  "signals": {
    "commit_type": "feat",
    "scope": "canonical",
    "breaking": false,
    "is_releasable_type": true,
    "domains_affected": ["pipeline", "data-architecture"]
  },
  "body": "Establishes DuckDB as canonical in-process analytical database...",
  "files_changed": ["packages/canonical/pipelines/stages/duckdb_runtime.py", "..."],
  "stats": {"files": 8, "insertions": 450, "deletions": 120}
}
```

这些信号能帮助指导分类：`is_releasable_type: true` 暗示这应该出现在变更日志中；较大的插入行数以及涉及的基础设施文件，则暗示它可能同时也是一条架构决策。

### 第四步：对提交进行分类

到这一步，会分出两条路径：变更日志条目和架构决策。

**对于变更日志条目：**

```bash
uv run orkestra mine classify abc123 --changelog added
```

这会记录下提交 `abc123` 应该出现在变更日志的“Added”类别下。

**对于架构决策：**

首先，获取一个真实的决策 ID:

```bash
uv run orkestra registry decisions new --domain pipeline --dry-run
# Returns: DEC-PL-143
```

然后用这个决策 ID 进行分类：

```bash
uv run orkestra mine classify abc123 --decision DEC-PL-143
```

这会把这次提交，关联到一条将被创建或更新的决策记录上。

**对于批量处理（我们实际采用的方式）：**

```bash
# Generate classifications file with LLM assistance
uv run orkestra mine commit --input classifications.jsonl
```

JSONL 格式可以在一次处理中同时支持两个领域：

```jsonl
{"sha":"abc123","domain":"changelog","action":"release","category":"added","summary":"Add DuckDB runtime for pipeline stages"}
{"sha":"abc123","domain":"decisions","action":"extract","decision_id":"DEC-PL-142"}
{"sha":"def456","domain":"changelog","action":"skip","reason":"Chore: dependency update"}
```

### 第五步：渲染输出

```bash
uv run orkestra registry changelog render --package <pkg>
```

这会根据台账（Ledger），为每个包生成 `CHANGELOG.md` 文件。变更日志是派生产物——删掉它们，也能从源头台账完美地重新生成。

## 决策记录的结构

提取出的决策，会变成带有丰富元数据的 YAML 文件：

```yaml
id: DEC-PL-142
title: Adopt DuckDB as Canonical Processing Runtime for Pipeline Stages
domain: pipeline
status: active
created: '2026-01-26'
summary: |
  Establishes DuckDB as the canonical in-process analytical database for pipeline
  stage transformations. Provides a shared runtime module that resolves settings
  from pipeline defaults with stage-level overrides.

context: |
  Pipeline stages performing data transformations each independently configured
  DuckDB connections. This led to inconsistent settings, duplicated configuration
  code, and no way to tune DuckDB globally for a pipeline run.

rationale:
  - DuckDB provides efficient in-process OLAP with zero configuration deployment
  - Centralized runtime module eliminates duplicated DuckDB setup across stages
  - Hierarchical settings enable global tuning with stage-level overrides
  - Memory limits and thread counts can be adjusted per-pipeline

impact:
  positive:
    - Consistent DuckDB configuration across all pipeline stages
    - Single point of control for memory/thread tuning
    - Reduced code duplication in conversion and export stages
  negative:
    - Adds dependency on shared runtime module
    - Stages must adopt new configuration pattern

source_commits:
  - sha: 90571786d99166c0039ca2e80e4d9cd96184bd85
    message: 'feat(canonical): add DuckDB runtime for pipeline stages'
    date: '2026-01-26'
    role: primary

files:
  - packages/canonical/pipelines/stages/duckdb_runtime.py
  - packages/canonical/pipelines/runner.py
  - packages/canonical/pipelines/stages/convert_hdx_admin_boundaries_to_geoparquet.py

related:
  - DEC-DA-014  # Data architecture decisions that influenced this
```

每条决策都会关联回其源头提交，每条决策都会指明它影响哪些文件，决策与决策之间的关系也是明确的。

## CLI 集成：查询组织记忆

这正是闭环真正合拢的地方。智能体可以通过 CLI 查询决策：

```bash
# Search by topic
uv run orkestra registry decisions search --query "retry"
```

返回与重试逻辑、错误处理、恢复模式相关的决策。

```bash
# Get full details on a specific decision
uv run orkestra registry decisions info DEC-PL-142
```

返回完整的决策记录，包括上下文、理由和影响。

```bash
# List recent decisions for context
uv run orkestra registry decisions list --limit 15
```

展示最近做出了哪些架构选择。

### 智能体如何使用它

我们编排器的基础指令中包含了这样一条：

```markdown
**Essential CLI commands:**
- `orkestra registry decisions search "X"` — Find architectural decisions
```

当一个智能体被要求实现与 DuckDB 相关的东西时，它可以先检查：

```bash
uv run orkestra registry decisions search --query "DuckDB"
```

然后发现 DEC-PL-142，并从中了解到：
- 我们为什么选择 DuckDB(context)
- 该如何正确使用它（agent_guidance）
- 应该查看哪些文件（files）
- 存在哪些相关决策（related）

智能体不需要重新发明轮子，而是在既有模式的基础上继续构建。

## 三问测试

并非每次提交都值得拥有一条决策记录。我们用“三问测试”来做筛选：

1. **这个决定难做吗？** 是否需要经过大量分析、权衡评估，或者一番争论？
2. **改变它的代价高吗？** 如果要推翻这个决定，是否需要大量返工？
3. **它是否具有系统级的影响？** 是否影响多个包，或者树立了其他人会遵循的模式？

如果一次提交对这三个问题中至少一个的答案是“是”，那它就是决策提取的候选对象。我们通常的比例是：每 100 次提交中有 1 到 4 条决策（大约 1% 到 4%）。

对于变更日志条目，门槛要低一些：任何面向用户的变更（功能、修复、改进）都会被记录下来。内部杂务、文档更新和重构通常会被跳过。我们通常的比例是：每 100 次提交中有 30 到 50 条变更日志条目。

## 数据存储：仅追加式台账

这套挖掘系统使用仅追加式的 JSONL 台账，以实现无冲突的多智能体协作：

```
packages/orchestration/ai_assets/reference/changelog/
├── commits_processed.jsonl  # Classification ledger (both domains)
├── release_notes.jsonl      # Changelog entries
└── commits_index.yaml       # Derived index (gitignored)

packages/orchestration/ai_assets/reference/decisions/
├── registry.yaml            # Decision index
└── records/
    ├── DEC-AD-001.yaml
    ├── DEC-AD-002.yaml
    └── ...
```

这种在 `.gitattributes` 中使用 `merge=union` 的 JSONL 格式，意味着多个智能体可以同时对提交进行分类，而不会产生合并冲突。每一行都是独立的。

## 验证门禁

在任何一次挖掘会话开始之前，我们都会先运行验证：

```bash
uv run orkestra mine validate --quick
```

这会检查：
- SHA 格式是否有效
- 决策 ID 格式是否合规
- 同一个 SHA 是否存在重复条目
- 引用的决策是否真实存在

分类完成之后，我们会在提交改动之前再验证一遍。

## 为什么这很重要

我们搭建的这个反馈闭环，解决了好几个问题：

**对新团队成员而言：** 他们不必再问“我们当初为什么这么做”，而是可以直接搜索决策注册表。上下文被完整保留了下来。

**对 AI 智能体而言：** 它们不再是在真空中运作，而是可以在给出建议之前先查询组织知识。当被要求新增一个流水线阶段时，它们可以发现 DuckDB 这个模式并加以遵循。

**对架构一致性而言：** 决策是明确的、可搜索的。当有人提出一个与既有决策相矛盾的方案时，系统可以把这个冲突暴露出来。

**对变更日志生成而言：** 发布说明不再是临阵磨枪赶出来的东西，而是开发过程中持续分类的一个副产品。

**对新人上手而言：** 新加入的智能体能继承代码库的完整上下文。它们看到的不只是代码本身，还有塑造了这些代码的那些决策。

## 现状

截至目前：
- 已有 **15,637 次提交** 经流水线处理
- 已提取并记录了 **476 条架构决策**
- 已记录了 **6,799 条变更日志条目**
- 两个领域都达到了 **100% 覆盖率**

自我们开始以来的每一次提交，都已经被分类过了。这份组织记忆是完整的，并且可以查询。

## 快速上手

如果你想实现类似的东西：

1. **从约定式提交开始。** 当提交带有结构化前缀（`feat:`、`fix:`、`chore:`）时，这套挖掘流水线的效果最好。

2. **定义你自己的领域。** 我们使用诸如 `pipeline`、`agent-design`、`observability`、`data-modeling` 这样的领域，用它们按区域来组织决策。

3. **养成分类的习惯。** 只有当团队持续、定期地对提交进行分类时，挖掘才会真正有效。借助 LLM 辅助的批量处理，有助于扩大规模。

4. **让决策可以被查询。** 当智能体能够通过 CLI 搜索决策时，这份价值会不断复利累积。请为机器可读性来组织你的输出结构。

5. **让闭环真正闭合。** 决策应该影响未来的工作。请在智能体指令和代码评审清单中，加入对决策的引用。

目标不是追求完美的文档，而是让变更背后的*原因*——无论是今天，还是六个月之后——对人类和 AI 都保持可访问。当变更沉淀为组织记忆，团队就能在既有模式的基础上继续构建，而不必重新发明它们。

---

*这套挖掘工作流，是我们编排引擎的一部分，具体来说，是我们编排包中的上下文引擎（Context Engine）模块。*
