本文へスキップ
cd /blog

ループを掘り起こす:変更はいかにして組織の記憶になるか

[アーキテクチャ][ワークフロー]

> Gitのコミットは構造化された変更履歴とアーキテクチャ上の意思決定記録になり、クエリ可能な組織の記憶としてAIエージェントへフィードバックされます。

この記事の数値は公開時点(2026年2月)のシステムを反映しています。最新の数値はチームページをご覧ください。

どのエンジニアリングチームも同じ課題に直面します。変更は絶えず起こりますが、その変更の背後にある理由は消え去っていきます。半年後、誰かが「なぜパイプラインのステージにDuckDBを採用したのか?」と尋ねたとき、その答えはその判断を下した本人の頭の中にしか存在しません ―― しかもその人がまだ在籍していればの話です。

私たちは、このループを閉じるためのマイニングワークフローを構築しました。変更はgitのコミットとして流れ込み、私たちのマイニングパイプラインで処理され、構造化された変更履歴やアーキテクチャ上の意思決定記録になり、そしてCLIクエリを通じて私たちのAIエージェントへとフィードバックされます。結果として得られるのは、人間とAIの両方がアクセスできる組織の記憶です。

問題:意思決定は蒸発する

典型的なシナリオを考えてみましょう。ある開発者が次のようにコミットします:

feat(canonical): add DuckDB runtime for pipeline stages

このコミットは、重要なアーキテクチャ上の選択を表しています。チームは選択肢を評価し、トレードオフを検討し、特定の理由からDuckDBに落ち着きました。しかしそのコンテキストはすべて、次のような場所に存在しています:

  • Slackのスレッド(おそらく削除済み)
  • 誰かの記憶(確実に薄れつつある)
  • コード中のコメント(運が良ければ、もしかしたら)

3か月後、新しいチームメンバーがこう尋ねます。「この新しいステージには、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履歴から、統一されたパイプラインを通じて流れ出すということです。これにより、何かが見落とされることがなくなります。

マイニングの仕組み

ステップ1:インデックスを同期する

uv run orkestra mine sync

このコマンドはgit履歴をスキャンし、すべてのコミットのインデックスを構築します。各コミットから構造化されたシグナルを抽出します:

  • 標準的なコミットタイプ(featfixchoredocs)
  • スコープ(どのパッケージまたは領域か)
  • 破壊的変更のマーカー
  • 変更されたファイルと複雑度のメトリクス

ステップ2:カバレッジ状況を確認する

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件が変更履歴のエントリになりました。すべてのコミットが分類済みです。

ステップ3:レビュー対象の候補を取得する

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

これにより、まだ処理されていないコミットが、分類に必要な完全なコンテキストとともに表示されます:

on
{
  "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は、これが変更履歴に載るべきものであることを示唆しています。挿入行数の多さとインフラ関連ファイルの存在は、これがアーキテクチャ上の意思決定でもある可能性を示唆しています。

ステップ4:コミットを分類する

ここで2つの経路に分岐します。変更履歴のエントリと、アーキテクチャ上の意思決定です。

変更履歴のエントリの場合:

uv run orkestra mine classify abc123 --changelog added

これにより、コミットabc123が変更履歴の「Added」カテゴリーに載るべきものとして記録されます。

アーキテクチャ上の意思決定の場合:

まず、実際の意思決定IDを取得します:

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

続いて、その意思決定IDを使って分類します:

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

これにより、コミットが、作成または更新されることになる意思決定レコードに紐づけられます。

バッチ処理の場合(私たちが実際に行っている方法):

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

JSONL形式なら、1回のパスで両方のドメインに対応できます:

on
l
{"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"}

ステップ5:出力をレンダリングする

uv run orkestra changelog render --package <pkg>

これにより、台帳からパッケージごとのCHANGELOG.mdファイルが生成されます。変更履歴は派生成果物です ―― 削除しても、元の台帳から完璧に再生成されます。

意思決定レコードの構造

抽出された意思決定は、豊富なメタデータを持つ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を通じて意思決定にクエリを投げられます:

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

リトライロジック、エラーハンドリング、リカバリーパターンに関する意思決定を返します。

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

コンテキスト、根拠、影響を含む完全な意思決定レコードを返します。

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

最近どのようなアーキテクチャ上の選択が行われたかを表示します。

エージェントはこれをどう使うか

私たちのオーケストレーターのベースライン指示には、次のような内容が含まれています:

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

エージェントがDuckDBに関連する何かの実装を依頼されたとき、まず次のように確認できます:

uv run orkestra decisions search --query "DuckDB"

そしてDEC-PL-142を発見し、次のことを学びます:

  • なぜDuckDBを選んだのか(コンテキスト)
  • 正しい使い方(agent_guidance)
  • どのファイルを見ればよいか(files)
  • どんな関連する意思決定が存在するか(related)

エージェントは車輪の再発明をしません。確立されたパターンの上に積み上げていきます。

3つの質問テスト

すべてのコミットが意思決定レコードに値するわけではありません。私たちは3つの質問テストでふるいにかけています:

  1. 判断が難しかったか? 大きな分析、トレードオフの検討、あるいは議論を要したか?
  2. 変更のコストは高いか? この決定を覆すには大幅な作り直しが必要か?
  3. システム全体に影響するか? 複数のパッケージに影響を与えるか、他が従うことになるパターンを確立するか?

これらの質問のうち少なくとも1つに「はい」と答えられるコミットは、意思決定抽出の候補になります。私たちの典型的な割合は、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形式のおかげで、複数のエージェントがマージコンフリクトを起こすことなく同時にコミットを分類できます。各行は独立しています。

バリデーションゲート

マイニングセッションを行う前には、必ずバリデーションを実行します:

uv run orkestra mine validate --quick

これは次を確認します:

  • SHA形式の妥当性
  • 意思決定IDの形式準拠
  • 同一SHAに対する重複エントリがないこと
  • 参照されている意思決定が実際に存在すること

分類後、変更をコミットする前にもう一度バリデーションを行います。

これが重要な理由

私たちが構築したフィードバックループは、いくつかの問題を解決します:

新しいチームメンバーにとって: 「なぜXをしたのか?」と尋ねる代わりに、意思決定レジストリを検索できます。コンテキストは保存されています。

AIエージェントにとって: 真空の中で動作しているわけではありません。提案を行う前に、組織的な知識にクエリを投げられます。新しいパイプラインステージの追加を依頼されたとき、DuckDBのパターンを発見し、それに従うことができます。

アーキテクチャの一貫性にとって: 意思決定は明示的で検索可能です。誰かが既存の意思決定と矛盾するアプローチを提案したとき、システムはその衝突を表面化できます。

変更履歴の生成にとって: リリースノートは土壇場でのドタバタ作業ではなくなります。開発中に継続的に行われる分類の副産物になるのです。

オンボーディングにとって: 新しいエージェントは、コードベースの完全なコンテキストを引き継ぎます。コードを見るだけでなく、それを形作った意思決定も見ることになります。

現在の状態

現時点で:

  • 15,637件のコミットがパイプラインで処理済み
  • 476件のアーキテクチャ上の意思決定が抽出・文書化済み
  • 6,799件の変更履歴エントリが記録済み
  • 両ドメインにわたる100%のカバレッジ

開始以来のすべてのコミットが分類済みです。組織の記憶は完全であり、クエリ可能です。

はじめに

同様の仕組みを実装したい場合:

  1. まずConventional Commitsから始める。 マイニングパイプラインは、コミットに構造化されたプレフィックス(feat:fix:chore:)がある場合に最もよく機能します。

  2. ドメインを定義する。 私たちはpipelineagent-designobservabilitydata-modelingのようなドメインを使っています。これらは意思決定を領域別に整理します。

  3. 分類する習慣を作る。 マイニングは、チームが定期的にコミットを分類することで機能します。LLMの支援によるバッチ処理はスケールを助けます。

  4. 意思決定をクエリ可能にする。 エージェントがCLI経由で意思決定を検索できるようになると、価値は複利的に積み上がります。出力を機械が消費しやすい形に構造化しましょう。

  5. ループを閉じる。 意思決定は今後の作業に影響を与えるべきです。エージェントへの指示やコードレビューのチェックリストに、意思決定への参照を含めましょう。

目標は完璧なドキュメントを作ることではありません。変更の背後にある理由を、今日も半年後も、人間とAIの双方がアクセスできるようにすることです。変更が組織の記憶になるとき、チームは再発明するのではなく、確立されたパターンの上に積み上げていけるようになります。


マイニングワークフローは、私たちのオーケストレーションエンジンの一部であり、具体的にはオーケストレーションパッケージ内のコンテキストエンジンモジュールに含まれています。

関連記事

Maguyva開発ログのその他の記事

コード検索をvoyage-4-largeへアップグレードした理由_

私たちはコード埋め込みをvoyage-4-largeへ移行しました ―― 現在、公開RTEBコード検索リーダーボードのトップに立つモデルです。正直に言うと:私たちが受け入れているトレードオフ、実際に何をインデックス化しているか、そしてなぜプレミアムな埋め込みにお金を払うのか。

[エンベディング][検索][アーキテクチャ]

言語の再帰的自己改善:約280言語にわたるコードインテリジェンスの磨き上げ_

私たちは約280言語のコードインテリジェンスに対応しています。人間の手でそのすべてを監査することはできません。そこで私たちは、言語の再帰的自己改善ループ ―― 抜き取り検査、LLM-as-judge、1点修正、再検証 ―― を構築し、抽出が単に「グリーン」であるだけでなく実際に正しくなるまで、隔離されたエージェント群でこれを回し続けています。

[アーキテクチャ][言語][エージェント]

マルチモーダル・フュージョン検索:あらゆるクエリに最適な検索エンジンを選ぶ_

「parseConfigはどこで定義されているか」のようなクエリと「認証はどう動いているか」のようなクエリでは、求められる検索の種類が異なります。Maguyvaは意図を分類し、それに応じて4つの検索モダリティに重みを付け、重み付き相互順位融合で結果を統合します。

[検索][アーキテクチャ]