# SPEC-ARTIFACT-001: アーティファクト参照システム実装仕様

## メタデータ

| 項目 | 内容 |
|------|------|
| 仕様ID | SPEC-ARTIFACT-001 |
| 仕様名 | アーティファクト参照システム実装仕様 |
| バージョン | 1.0.0 |
| 作成日 | 2025-01-09 |
| 最終更新 | 2025-01-09 |
| 作成者 | Claude Code |
| レビュー担当 | システム設計者 |
| 承認者 | プロジェクト責任者 |

## 概要

### 目的

`/noveler write`コマンド実行時にエピソードプロットが原稿生成プロンプトに含まれない問題を解決し、プロンプトサイズの大幅削減を実現する**Pass-by-Reference（参照渡し）システム**を実装する。

### 背景

#### 問題の詳細
1. **原稿生成プロンプトにプロットが含まれない問題**
   - `prepare_plot_data`でプロットコンテンツを読み込んでいるが、`write_manuscript_draft`では使用されていない
   - 結果として、プロット情報なしで原稿が生成され、一貫性のない内容になる

2. **プロンプトサイズとトークン消費の問題**
   - 長大なプロットコンテンツをプロンプトに直接埋め込むとトークン制限に抵触する
   - コンテキストサイズ制限により、複雑な物語の詳細情報を含められない

3. **スケーラビリティの問題**
   - エピソード数や詳細度が増すにつれてプロンプトサイズが指数的に増加
   - 複数ファイル（設定、キャラクター、世界観等）の統合が困難

### 解決策

**SHA256ベースのコンテンツアドレス管理**による参照渡しシステムを実装し、以下を実現する：

- プロンプトには短い参照ID（`artifact:abc123`形式）のみを含める
- LLMは必要に応じて`fetch_artifact`ツールでコンテンツをオンデマンド取得
- **87.4%以上のプロンプト削減**を達成（テスト実績）

## 機能要件

### FR-001: アーティファクトストレージ機能

#### FR-001-001: コンテンツアドレス管理
- **要件**: SHA256ハッシュベースのコンテンツ識別
- **形式**: `artifact:{12文字のハッシュ}`（例: `artifact:abc123def456`）
- **一意性**: 同一コンテンツは同じアーティファクトIDを生成
- **衝突回避**: SHA256の最初の12文字使用により実質的な衝突回避

#### FR-001-002: ハイブリッドストレージ
- **メモリキャッシュ**: 高速アクセス用の一時ストレージ
- **永続化ストレージ**: `.noveler/artifacts/`ディレクトリにJSON形式で保存
- **自動フォールバック**: メモリにない場合は永続化ストレージから読み込み
- **ディレクトリ構造**:
  ```
  .noveler/
  └── artifacts/
      ├── abc123def456.json
      ├── def456789abc.json
      └── ...
  ```

#### FR-001-003: メタデータ管理
- **必須フィールド**:
  - `artifact_id`: アーティファクトID
  - `content_type`: コンテンツタイプ（text, json, yaml等）
  - `created_at`: 作成日時（ISO形式）
  - `size_bytes`: バイト数
- **オプションフィールド**:
  - `source_file`: 元ファイルパス
  - `description`: 人間可読な説明
  - `tags`: 分類用タグ（Dict[str, str]）

### FR-002: MCPツール機能

#### FR-002-001: fetch_artifact ツール
- **機能**: アーティファクト参照IDからコンテンツを取得
- **引数**:
  - `artifact_id` (必須): `artifact:abc123`形式の参照ID
  - `section` (オプション): 部分取得セクション名
  - `format_type` (オプション): 出力フォーマット（text, json, yaml）
  - `project_root` (オプション): プロジェクトルートパス
- **戻り値**: JSON形式
  ```json
  {
    "success": true,
    "artifact_id": "artifact:abc123def456",
    "content": "実際のコンテンツ",
    "section": null,
    "format": "text",
    "metadata": {
      "size_bytes": 1024,
      "created_at": "2025-01-09T10:30:00",
      "content_type": "text",
      "source_file": "/path/to/file.md"
    },
    "instructions": "アーティファクト 'artifact:abc123def456' の全コンテンツを取得しました"
  }
  ```

#### FR-002-002: list_artifacts ツール
- **機能**: 利用可能なアーティファクト一覧を表示
- **引数**:
  - `project_root` (オプション): プロジェクトルートパス
- **戻り値**: JSON形式
  ```json
  {
    "success": true,
    "total_artifacts": 3,
    "artifacts": [
      {
        "artifact_id": "artifact:abc123def456",
        "content_type": "text",
        "size_bytes": 1024,
        "created_at": "2025-01-09T10:30:00",
        "source_file": "/path/to/plot.md",
        "description": "第001話プロット"
      }
    ],
    "instructions": "fetch_artifact ツールで個別のアーティファクトを取得できます"
  }
  ```

### FR-003: プロンプト統合機能

#### FR-003-001: prepare_plot_data 修正
- **機能**: プロットコンテンツをアーティファクト化し、参照プロンプトを生成
- **変更内容**:
  - プロットファイル読み込み後、`ArtifactStoreService.store()`でアーティファクト化
  - プロンプトには参照IDと取得指示のみを含める
  - セッションデータにアーティファクトIDを保存
- **出力プロンプト形式**:
  ```markdown
  # 第001話 データ準備段階（参照渡し版）
  ## アーティファクト参照情報
  - **プロット**: artifact:abc123def456

  ## 実行手順
  1. **プロット確認**: `fetch_artifact artifact:abc123def456` でプロット全文を取得し、内容を理解してください
  2. **分析実行**: 取得したプロットを分析し、以下の要素を抽出してください
     - 主要登場人物とその関係性
     - 物語の核となるテーマ
     - 重要な転換点やクライマックス
  ```

#### FR-003-002: write_manuscript_draft 修正
- **機能**: アーティファクト参照を使用した執筆プロンプトを生成
- **変更内容**:
  - セッションデータまたはファイルからプロット取得時にアーティファクト化
  - 執筆プロンプトに参照ID含めた取得指示を埋め込み
  - セッションデータにアーティファクトIDを保存
- **出力プロンプト形式**:
  ```markdown
  # 第001話 原稿執筆段階（参照渡し版）

  ## アーティファクト参照情報
  - **プロット**: artifact:abc123def456

  ## 実行手順
  1. まず `fetch_artifact artifact:abc123def456` でプロットを取得してください
  2. プロットの内容を理解し、上記の要件に基づいて原稿を生成してください

  ## 執筆要件
  - 目標文字数: 4000文字
  - ジャンル: ファンタジー
  - 視点: 三人称単元視点
  ```

### FR-004: セクション指定部分取得機能

#### FR-004-001: JSONセクション抽出
- **機能**: JSON形式コンテンツから指定キーの値を抽出
- **例**: `fetch_artifact artifact:abc123 --section="characters"`
- **対応形式**: 標準JSON

#### FR-004-002: テキストセクション抽出
- **機能**: Markdownヘッダーベースのセクション抽出
- **抽出ルール**: `# セクション名`または`## セクション名`で開始し、次のヘッダーまで
- **例**: `## キャラクター`セクションを抽出

#### FR-004-003: YAMLセクション抽出
- **機能**: YAML形式コンテンツから指定キーの値を抽出
- **対応形式**: 標準YAML（yaml.safe_load使用）

## 非機能要件

### NFR-001: パフォーマンス要件

#### NFR-001-001: プロンプト削減率
- **要件**: 80%以上のプロンプト削減率を達成
- **測定方法**: `(1 - 参照ID長 / 元コンテンツ長) * 100`
- **目標値**: 87.4%（実績値）
- **検証**: E2Eテストで継続監視

#### NFR-001-002: 応答時間要件
- **アーティファクト取得**: 2秒以内（1MB以下のコンテンツ）
- **アーティファクト一覧**: 1秒以内（100個以下）
- **アーティファクト保存**: 3秒以内（大容量コンテンツ）

#### NFR-001-003: メモリ使用量
- **メモリキャッシュ上限**: 50MBまで
- **自動クリーンアップ**: メモリ不足時は古いアーティファクトから削除
- **永続化保証**: クリーンアップされたアーティファクトも永続化ストレージから復元可能

### NFR-002: 可用性要件

#### NFR-002-001: エラー復旧
- **破損ファイル対応**: 永続化ファイルが破損した場合はnullを返し、ログに記録
- **ストレージ不足**: 一時的な書き込みエラーでもメモリキャッシュで動作継続
- **権限エラー**: 適切なエラーメッセージと代替手段の提示

#### NFR-002-002: 下位互換性
- **既存セッション**: アーティファクトIDがないセッションでも従来通り動作
- **段階的移行**: 既存のプロット直接埋め込み方式と並行動作
- **設定切り替え**: 環境変数による参照システムの有効/無効切り替え

### NFR-003: セキュリティ要件

#### NFR-003-001: アクセス制御
- **プロジェクト境界**: 異なるプロジェクトのアーティファクトへの不正アクセス防止
- **パス検証**: `project_root`パラメータの検証とサニタイズ
- **ファイル書き込み**: プロジェクト外への書き込み防止

#### NFR-003-002: データ整合性
- **ハッシュ検証**: ロード時にSHA256ハッシュの検証（オプション）
- **原子性**: アーティファクト保存の原子性保証（一時ファイル経由）
- **リトライ**: 一時的なI/Oエラーに対する自動リトライ

## 設計仕様

### DS-001: アーキテクチャ設計

#### DS-001-001: レイヤー構成
```
Application Layer
├── JSONConversionServer (MCP Tools)
│   ├── fetch_artifact
│   ├── list_artifacts
│   ├── prepare_plot_data (modified)
│   └── write_manuscript_draft (modified)
│
Domain Layer
├── ArtifactStoreService (Core Logic)
│   ├── store()
│   ├── fetch()
│   ├── get_metadata()
│   └── list_artifacts()
│
Infrastructure Layer
├── Memory Cache (Dict[str, StoredArtifact])
└── File Storage (.noveler/artifacts/*.json)
```

#### DS-001-002: データフロー
```
1. プロット読み込み (prepare_plot_data)
   File System → ArtifactStoreService.store() → artifact_id

2. プロンプト生成
   artifact_id → 参照プロンプト生成 → Session Storage

3. LLMによるアーティファクト取得
   fetch_artifact(artifact_id) → ArtifactStoreService.fetch() → content

4. 原稿執筆プロンプト生成 (write_manuscript_draft)
   Session Data → artifact_id → 参照プロンプト生成
```

### DS-002: データモデル設計

#### DS-002-001: ArtifactMetadata
```python
@dataclass
class ArtifactMetadata:
    artifact_id: str          # artifact:abc123def456
    content_type: str         # text, json, yaml
    created_at: str           # ISO format datetime
    size_bytes: int           # コンテンツサイズ
    source_file: Optional[str] = None     # 元ファイルパス
    description: Optional[str] = None     # 人間可読説明
    tags: Optional[Dict[str, str]] = None # 分類タグ
```

#### DS-002-002: StoredArtifact
```python
@dataclass
class StoredArtifact:
    content: str              # 実際のコンテンツ
    metadata: ArtifactMetadata # メタデータ
```

#### DS-002-003: 永続化形式 (JSON)
```json
{
  "content": "実際のコンテンツ文字列",
  "metadata": {
    "artifact_id": "artifact:abc123def456",
    "content_type": "text",
    "created_at": "2025-01-09T10:30:00.000Z",
    "size_bytes": 1024,
    "source_file": "/path/to/plot.md",
    "description": "第001話プロット",
    "tags": {"episode": "001", "type": "plot"}
  }
}
```

### DS-003: API設計

#### DS-003-001: ArtifactStoreService API
```python
class ArtifactStoreService:
    def store(
        self,
        content: str,
        content_type: str = "text",
        source_file: Optional[str] = None,
        description: Optional[str] = None,
        tags: Optional[Dict[str, str]] = None
    ) -> str:
        """コンテンツをストアしてアーティファクトIDを返す"""

    def fetch(
        self,
        artifact_id: str,
        section: Optional[str] = None
    ) -> Optional[str]:
        """アーティファクトIDからコンテンツを取得"""

    def get_metadata(self, artifact_id: str) -> Optional[ArtifactMetadata]:
        """メタデータ取得"""

    def list_artifacts(self) -> Dict[str, ArtifactMetadata]:
        """全アーティファクト一覧"""

    def delete_artifact(self, artifact_id: str) -> bool:
        """アーティファクト削除"""
```

#### DS-003-002: MCP Tool API
```python
# fetch_artifact ツール
async def fetch_artifact(
    artifact_id: str,
    section: str = None,
    format_type: str = "text",
    project_root: str = None
) -> str:
    """JSON形式でアーティファクトコンテンツを返す"""

# list_artifacts ツール
async def list_artifacts(project_root: str = None) -> str:
    """JSON形式でアーティファクト一覧を返す"""
```

## テスト要件

### TR-001: ユニットテスト

#### TR-001-001: ArtifactStoreService テスト
- **ファイル**: `tests/unit/domain/services/test_artifact_store_service.py`
- **カバレッジ**: 95%以上
- **テスト項目**:
  - 基本的な store/fetch 動作
  - メタデータ管理
  - セクション指定取得
  - エラーハンドリング
  - Unicode文字対応
  - 大容量ファイル処理
  - 永続化機能

#### TR-001-002: ファクトリ関数テスト
- **対象**: `create_artifact_store()`
- **テスト項目**:
  - デフォルト引数での初期化
  - カスタムパラメータでの初期化
  - 引数検証

### TR-002: 統合テスト

#### TR-002-001: MCP Tools 統合テスト
- **ファイル**: `tests/integration/mcp/test_artifact_mcp_tools.py`
- **テスト項目**:
  - fetch_artifact ツールの基本動作
  - list_artifacts ツールの基本動作
  - セクション指定機能
  - フォーマット指定機能
  - エラーハンドリング
  - パフォーマンス要件

#### TR-002-002: JSONConversionServer 統合
- **対象**: MCPツールとJSONConversionServerの統合
- **テスト項目**:
  - ツール登録の確認
  - 非同期実行の検証
  - エラー時の適切なレスポンス

### TR-003: E2Eテスト

#### TR-003-001: ワークフローE2Eテスト
- **ファイル**: `tests/e2e/test_artifact_reference_workflow.py`
- **テスト項目**:
  - prepare_plot_data → write_manuscript_draft 完全ワークフロー
  - 複数エピソードでのアーティファクト管理
  - インスタンス間でのアーティファクト永続化
  - パフォーマンス要件（大容量プロット）
  - エラー復旧シナリオ

#### TR-003-002: プロンプト削減効果検証
- **測定項目**:
  - 削減率の計算と検証
  - 様々なコンテンツサイズでの削減効果
  - メモリ使用量の監視

### TR-004: パフォーマンステスト

#### TR-004-001: 負荷テスト
- **シナリオ**:
  - 100個のアーティファクト同時管理
  - 1MBサイズのアーティファクト処理
  - 連続100回のfetch操作
- **要件**:
  - 応答時間要件の遵守
  - メモリリーク無し
  - ファイルハンドルリーク無し

#### TR-004-002: ストレステスト
- **シナリオ**:
  - ディスク容量不足時の動作
  - 権限エラー時の動作
  - 破損ファイルからの復旧

## 実装ガイドライン

### IG-001: コーディング規約

#### IG-001-001: B20準拠開発
- **インポート方針**: `scripts.` プレフィックス強制、相対インポート禁止
- **共有コンポーネント**: 既存の共有コンポーネントを使用
- **Path Service**: PathService経由でのパス管理必須
- **ロガーサービス**: ILoggerService実装を使用

#### IG-001-002: DDD準拠設計
- **ドメイン層**: ビジネスロジックの純粋性維持
- **依存方向**: ドメイン→アプリ→インフラの方向を厳守
- **ユースケース経由**: アプリケーション層はユースケース経由でサービス呼び出し

#### IG-001-003: エラーハンドリング
- **例外設計**: 適切な例外クラスの使用
- **ログ出力**: エラー発生時の詳細ログ
- **ユーザー体験**: ユーザー向けエラーメッセージの適切な表示

### IG-002: 実装順序

#### IG-002-001: フェーズ1: コア実装
1. ArtifactStoreService 実装
2. ユニットテスト作成・実行
3. ファクトリ関数実装

#### IG-002-002: フェーズ2: MCP統合
1. fetch_artifact ツール実装
2. list_artifacts ツール実装
3. 統合テスト作成・実行

#### IG-002-003: フェーズ3: ワークフロー統合
1. prepare_plot_data 修正
2. write_manuscript_draft 修正
3. E2Eテスト作成・実行

#### IG-002-004: フェーズ4: 最適化・監視
1. パフォーマンステスト実行
2. メモリ使用量最適化
3. 監視機能追加

## 受入基準

### AC-001: 機能要件受入基準

#### AC-001-001: プロンプト削減効果
- [ ] テストケースで87.4%以上の削減率を達成
- [ ] 様々なサイズのコンテンツで80%以上の削減率を維持
- [ ] 大容量コンテンツ（1MB以上）で95%以上の削減率を達成

#### AC-001-002: ワークフロー統合
- [ ] prepare_plot_data でアーティファクト参照プロンプトが生成される
- [ ] write_manuscript_draft でアーティファクト参照プロンプトが生成される
- [ ] fetch_artifact でプロットコンテンツが正確に取得できる
- [ ] 18ステップシステムとの統合が正常に動作する

#### AC-001-003: データ整合性
- [ ] アーティファクト保存後、同一内容を正確に取得可能
- [ ] 複数インスタンス間でのアーティファクト永続化
- [ ] セクション指定でのコンテンツ部分取得が正確

### AC-002: 非機能要件受入基準

#### AC-002-001: パフォーマンス
- [ ] 1MBコンテンツの取得が2秒以内
- [ ] 100個アーティファクトの一覧取得が1秒以内
- [ ] 大容量プロットでの prepare_plot_data が3秒以内

#### AC-002-002: エラーハンドリング
- [ ] 存在しないアーティファクトID指定時の適切なエラー
- [ ] 破損ファイルからのグレースフル復旧
- [ ] ディスク容量不足時の適切なエラーハンドリング

#### AC-002-003: セキュリティ
- [ ] プロジェクト境界を越えたアクセスの防止
- [ ] パス操作の適切な検証とサニタイズ
- [ ] 不正な artifact_id に対する適切な拒否

### AC-003: テスト要件受入基準

#### AC-003-001: テストカバレッジ
- [ ] ユニットテストのコードカバレッジ95%以上
- [ ] 統合テスト・E2Eテストの実装完了
- [ ] パフォーマンステストの実装完了

#### AC-003-002: 継続的テスト
- [ ] CIパイプラインでの自動テスト実行
- [ ] 回帰テストの自動化
- [ ] パフォーマンス監視の自動化

## リスクと対策

### RS-001: 技術リスク

#### RS-001-001: ファイルシステム依存
- **リスク**: ファイルシステムの制限によるスケーラビリティ問題
- **対策**: 将来的なデータベース移行への準備、抽象化層の実装
- **監視**: アーティファクト数とパフォーマンスの継続監視

#### RS-001-002: メモリ使用量
- **リスク**: 大量のアーティファクトによるメモリ不足
- **対策**: メモリキャッシュサイズ制限、LRUによる自動削除
- **監視**: メモリ使用量の継続的な監視

### RS-002: 運用リスク

#### RS-002-001: データ消失
- **リスク**: .novelerディレクトリの誤削除
- **対策**: バックアップツールとの統合、重要データのレプリケーション
- **予防**: ユーザー教育、削除前警告の実装

#### RS-002-002: 移行時の互換性
- **リスク**: 既存プロジェクトでの動作不良
- **対策**: 段階的移行機能、フィーチャーフラグによる制御
- **検証**: 既存プロジェクトでの広範囲な検証テスト

### RS-003: パフォーマンスリスク

#### RS-003-001: ディスクI/O負荷
- **リスク**: 大量のアーティファクトによるI/O性能劣化
- **対策**: 非同期I/O、バッチ処理、インデックス化
- **監視**: ディスクI/O使用量の監視

#### RS-003-002: ネットワーク遅延
- **リスク**: MCPツール経由での通信遅延
- **対策**: 接続プール、タイムアウト設定、リトライ機構
- **監視**: レスポンス時間の継続監視

## 今後の拡張計画

### EP-001: 短期拡張 (3ヶ月以内)

#### EP-001-001: アーティファクトタイプ拡張
- **対象**: 画像、音声、バイナリファイルのサポート
- **実装**: Base64エンコーディング、MIMEタイプ判定
- **用途**: 挿絵、BGM、リソースファイルの管理

#### EP-001-002: バージョニング機能
- **機能**: アーティファクトの履歴管理
- **実装**: `artifact:abc123#v1`, `artifact:abc123#v2` 形式
- **用途**: プロット変更履歴、原稿修正履歴

### EP-002: 中期拡張 (6ヶ月以内)

#### EP-002-001: 分散ストレージ対応
- **技術**: S3、GCS等のクラウドストレージ連携
- **利点**: チーム開発での共有、容量制限の解消
- **移行**: 既存ローカルストレージからの段階的移行

#### EP-002-002: 検索・インデックス機能
- **機能**: コンテンツ全文検索、メタデータ検索
- **実装**: Elasticsearch、SQLiteベースの検索エンジン
- **UI**: 検索インターフェースの提供

### EP-003: 長期拡張 (1年以内)

#### EP-003-001: AIベース自動分類
- **機能**: アーティファクトの自動タグ付け、分類
- **技術**: 自然言語処理、機械学習
- **効果**: 大量アーティファクトの効率的な管理

#### EP-003-002: コラボレーション機能
- **機能**: 複数ユーザーでのアーティファクト共有
- **実装**: 権限管理、変更履歴、競合解決
- **用途**: チーム執筆、査読、共同編集

## 関連仕様

### 関連SPEC
- SPEC-PROMPT-001: 外部テンプレート読み込み機能実装仕様
- SPEC-901: 段階実行システム実装仕様
- SPEC-WRITE-STAGE-001: 執筆段階品質基準

### 依存システム
- B20_Claude_Code開発作業指示書: 開発プロセス準拠
- 18ステップ執筆システム: ワークフロー統合
- PathService: パス管理統一
- MCPサーバー: ツール実行基盤

### 影響を受けるコンポーネント
- JSONConversionServer: MCPツール追加
- prepare_plot_data: アーティファクト化対応
- write_manuscript_draft: 参照プロンプト対応
- WritingSessionManager: セッションデータ拡張

---

## 更新履歴

| バージョン | 日付 | 変更内容 | 担当者 |
|-----------|------|----------|--------|
| 1.0.0 | 2025-01-09 | 初版作成、要件定義・設計・テスト要件策定 | Claude Code |
### 2.3 MCPサーバー（noveler）でのツール提供（更新）
本実装では、noveler MCPサーバー（`src/mcp_servers/noveler/main.py`）にて以下を提供する。

- `fetch_artifact(artifact_id, section?, project_root?, format=raw|json)`
- `list_artifacts(project_root?)`

これにより、LLMは参照IDから内容をオンデマンドで取得し、プロンプトに必要なコンテキストを効率的に取り込める。

### 2.4 ProgressiveWriteManager による自動参照化（更新）
以下の入力は存在時に自動でartifact化され、ステップ実行時の参照一覧に提示される。

- 30_設定集/キャラクター.yaml・世界観.yaml・用語集.yaml・文体/スタイル系yaml
- 20_プロット/話別プロット/第{episode}話_*.yaml
- 40_原稿/第{episode-1}話_*.md（前話原稿）

また、要約アーティファクト（`summary: true`タグ）を自動生成して先頭優先で提示する。
