← 全体レポートに戻る

局所トレーサビリティビュー グループ: MAINT

生成日時: 2026-03-13 23:59:51

対象アイテム

12

REQ

1

ARCH

1

SPEC

1

TST

1

IMPL

1

ADR

7

レビュー済

12/12

Suspect

0

グループ

MAINT
アイテム: REQ010 ARCH010 SPEC020 TST020 IMPL020 ADR016 ADR018 ADR020 ADR021 ADR023 ADR029 ADR041

トレーサビリティマトリクス

✓=レビュー済 ○=未レビュー ⚠=Suspect(複数同時表示あり。IDクリックで詳細へ)

グループREQARCHSPECTSTIMPLADR
MAINTREQ010
期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。
ARCH010
## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase...
SPEC020
## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra...
TST020
## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用...
IMPL020
## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...
ADR016
# Interactive Deletion and Cleanup Policy ## Context and Problem Statement / コン...
MAINTREQ010
期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。
ARCH010
## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase...
SPEC020
## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra...
TST020
## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用...
IMPL020
## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...
ADR018
# Expansion of Testing Strategy: Introduction of High-Level Integration Tests #...
MAINTREQ010
期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。
ARCH010
## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase...
SPEC020
## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra...
TST020
## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用...
IMPL020
## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...
ADR020
# Tolerant Deletion Policy for Task Cleanup ## Context and Problem Statement / ...
MAINTREQ010
期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。
ARCH010
## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase...
SPEC020
## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra...
TST020
## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用...
IMPL020
## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...
ADR021
# Code Visualization and Quality Metrics Strategy ## Context and Problem Statem...
MAINTREQ010
期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。
ARCH010
## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase...
SPEC020
## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra...
TST020
## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用...
IMPL020
## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...
ADR023
# Service Layer for Maintenance Operations ## Context and Problem Statement / コ...
MAINTREQ010
期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。
ARCH010
## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase...
SPEC020
## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra...
TST020
## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用...
IMPL020
## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...
ADR029
# Recursive Storage Cleanup and Zombie Project Collection ## Context and Proble...
MAINTREQ010
期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。
ARCH010
## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase...
SPEC020
## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra...
TST020
## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用...
IMPL020
## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...
ADR041
# Garbage Collection Strategy for Abandoned Temporary Files ## Context and Prob...

カバレッジ(局所)

リンク方向カバー数カバー率未カバー
ARCH → REQ 1 / 1 100.0%
SPEC → ARCH 1 / 1 100.0%
TST → SPEC 1 / 1 100.0%
IMPL → SPEC 1 / 1 100.0%
ADR → REQ 1 / 1 100.0%

アイテム詳細

REQ010 REQ {h(g)} ✓ レビュー済

期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除(prune)等のメンテナンス操作ができること。

親:

子: ADR016, ADR018, ADR020, ADR021, ADR023, ADR029, ADR041, ARCH010

ARCH010 ARCH {h(g)} ✓ レビュー済

コンポーネント構成

graph TD
  A[MaintenanceService] -->|操作集約| B[TaskDBBase]
  A -->|操作集約| C[BlobStorageBase]
  A -->|自動実行| D[Probabilistic Eviction]

コンポーネント責務

コンポーネント 責務 インターフェース
MaintenanceService DBとストレージを跨ぐクリーンアップ操作のファサード clean_garbage(), prune()
TaskDBBase 参照カウントや期限切れレコードの提供 get_blob_refs(), delete_expired()
BlobStorageBase 物理ファイルの列挙と削除 list_keys(), delete()

データフロー (GCプロセス)

sequenceDiagram
  participant Service as MaintenanceService
  participant DB as TaskDB
  participant Storage as BlobStorage

  Service->>DB: get_blob_refs()
  DB-->>Service: 有効な参照リスト (Whitelist)
  Service->>Storage: list_keys()
  Storage-->>Service: 全ファイルリスト
  Service->>Service: 差分抽出 (孤立ファイルの特定)
  Service->>Storage: delete(orphan_keys)
  Note over Service: 猶予期間 (grace_period) を考慮して削除

技術選定

技術領域 選定 理由
削除ポリシー ホワイトリスト方式 DBに記録がないBlobを削除対象とすることで、データの整合性を担保
競合防止 更新時刻確認 (mtime) 保存中のファイルを誤って消さないよう、一定時間経過した孤立のみ削除
実行頻度 確率的オートエビクション 書き込み時に低確率でGCをキックし、手動メンテなしでの健康度を維持

非機能要件方針

親: REQ010

子: SPEC020

SPEC020 SPEC {h(g)} ✓ レビュー済

インターフェース

class MaintenanceService:
    def clean_garbage(self, grace_period: int = 3600) -> GarbageStats: ...
    def prune(self, days: int, func_name: str | None = None) -> int: ...
    def clear(self, func_name: str | None = None) -> int: ...

振る舞い

ガベージコレクション (clean_garbage)

  1. DB Flush: 保存中のタスクをDBへ反映させる
  2. 期限切れ削除: delete_expired() でDBから古いタスクを除去
  3. 孤立Blobスキャン: DB内の全 blob_key とストレージ内の全ファイルを比較
  4. 物理削除: 参照のないBlobのうち、作成から grace_period 以上経過したものを削除
  5. 構造清掃: ストレージ内の空ディレクトリを削除

パラメータ詳細

パラメータ デフォルト 説明
grace_period 3600 孤立Blobを削除するまでの猶予期間(秒)。並行実行中の保存を保護する
days なし prune で削除対象とする経過日数

エラーハンドリング

エッジケース

親: ARCH010

子: IMPL020, TST020

TST020 TST {h(g)} ✓ レビュー済

目的

MaintenanceService は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用者の誤判断を招き、メンテナンス操作の不備はデータの意図しない削除に繋がる。

検証観点

references: tests/unit/test_maintenance.py

親: SPEC020

子:

IMPL020 IMPL {h(g)} ✓ レビュー済

実装概要

MaintenanceService クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出といったガベージコレクション(GC)を担当。 主にCLIの beautyspot gc コマンドから呼び出される。 対象となる DB (TaskDBMaintenable) とストレージ (BlobStorageMaintenable) を受け取り、 複数のフェーズに分けてクリーンアップを実行する。

設計判断

5フェーズのクリーンアッププロセス

clean_garbage() は以下の順序で安全にGCを実行する: 1. 期限切れDBレコードの削除 2. Blobストレージの一時ファイル(.spot_tmp)のクリーンアップ 3. 孤立したBlobファイル(DBに存在しないファイル)の特定 4. 孤立ファイルの削除 5. 空ディレクトリの剪定

Grace Period (猶予期間) の導入

実行中のタスクがBlobを書き込んだ直後で、まだDBにメタデータが保存されていない タイミングでGCが走ると、必要なファイルが孤立と誤認されるリスクがある。 これを防ぐため、orphan_grace_seconds(デフォルト60秒)より新しいファイルは 孤立判定から除外する設計とした。

実装メモ

references: src/beautyspot/maintenance.py

親: SPEC020

子:

ADR016 ADR {h(g)} ✓ レビュー済

Interactive Deletion and Cleanup Policy

Context and Problem Statement / コンテキスト

beautyspot は「試行錯誤の高速化」を掲げていますが、ユーザーが失敗した実験結果(キャッシュ)を即座に破棄する手段が Dashboard 上に存在しませんでした。 また、キャッシュ削除のロジックが cli.py に直接実装されており、Core API (Spot クラス) として提供されていないため、プログラムからの制御やテストが困難な状態でした。

加えて、削除機能を実現するには BlobStorageBase (Storage backend) に物理ファイルを削除するインターフェースが必要ですが、これまでの定義には saveload しか存在しませんでした。

Decision Drivers / 要求

Considered Options / 検討

Decision Outcome / 決定

Chosen option: Option 2.

  1. Core API への delete メソッドの追加 Spot.delete(cache_key) を正式な API として追加します。このメソッドは、「DBレコードの削除」と「Blobファイルの削除」をアトミック(ベストエフォート)に行う責任を持ちます。

  2. Storage Interface への拡張 BlobStorageBase 抽象基底クラスに delete(location) メソッドを追加します。

  3. Breaking Change: ユーザーが独自の Storage Backend を実装している場合、delete メソッドの実装が必要となります。
  4. Idempotency: ファイルが既に存在しない場合でもエラーを送出せず、静かに終了する(冪等な挙動)ことを推奨実装とします。

  5. Dashboard への削除機能の露出 Dashboard に削除ボタンを配置します。誤操作を防ぐため、確認ダイアログを経由する UI とし、Spot.delete を呼び出します。

Consequences / 決定

親: REQ010

子:

ADR018 ADR {h(g)} ✓ レビュー済

Expansion of Testing Strategy: Introduction of High-Level Integration Tests

Context and Problem Statement / コンテキスト

現在、beautyspot のテストスイート(tests/)は、主にユニットテストや特定の機能(シリアライザー、リミッターなど)に焦点を当てたテストで構成されている。これらは個々のコンポーネントの正確性を保証する上では有効だが、以下の課題がある:

  1. 連携の検証不足: 複数のタスクが依存関係を持つパイプライン(Load -> Process -> Train)において、バージョニングやキャッシュの伝播が正しく行われるかどうかの検証が不十分である。
  2. 実環境との乖離: 多くの場合、CliRunner やモックオブジェクトを使用しているため、実際のファイルシステムや SQLite データベースに対する副作用(ファイルの生成、削除、ロック競合など)を検証できていない。
  3. ユーザー体験の保証: CLI コマンド(stats, clean など)と Python API による実行結果の整合性を、ユーザーの一連の操作フローとして検証する仕組みがない。

「個々の部品は正しいが、組み合わせると意図した通りに動かない」という統合レベルのバグを防ぐため、テスト戦略を見直す必要がある。

Decision Drivers / 要求

Considered Options / 検討

Decision Outcome / 決定

Chosen option: Option 3.

テストピラミッドの上層として、以下の戦略でインテグレーションテストを導入する:

  1. ディレクトリ構成: tests/integration/ を新設し、ユニットテストとは明確に分離する。
  2. テスト範囲 (Scope):
    • Pipeline E2E: データのロードから学習までの一連のタスクフローを定義し、初回の実行、キャッシュヒット、バージョニングによる部分再計算(依存関係の解決)を検証する。
    • CLI Integration: Python コードで生成された DB ファイルに対し、beautyspot CLI コマンド(stats, list 等)を実行し、出力が正しいことを検証する。
  3. 技術的制約:
    • モックの使用は最小限に留め、原則として実ファイル(SQLite DB, Blobファイル)を使用する(tmp_path フィクスチャを活用)。
    • beautyspot.Spot クラスを実際にインスタンス化し、ユーザーコードと同じインターフェース経由で操作を行う。

Example Scenario / 想定シナリオ

def test_ml_pipeline_lifecycle(spot_env):
    # 1. Pipeline Definition (Load -> Process -> Train)
    # 2. Initial Run (Assert all executed)
    # 3. Cache Hit Run (Assert none executed)
    # 4. Version Upgrade of Middle Task (Assert downstream re-executed)
    # 5. CLI "stats" command check (Assert DB integrity)

Consequences / 決定

親: REQ010

子:

ADR020 ADR {h(g)} ✓ レビュー済

Tolerant Deletion Policy for Task Cleanup

Context and Problem Statement / コンテキスト

spot.delete(key) 機能は、特定のタスクに関連する「キャッシュレコード(DB)」と「実データ(Blob/File)」の両方を削除することを目的としています。

ローカルファイルシステムやS3などの外部ストレージにおいて、Blobの削除操作は様々な理由(ネットワーク障害、一時的な権限エラー、ファイルが既に手動で削除されている等)で失敗する可能性があります。

このとき、厳密な整合性を求めて「Blob削除に失敗したらDBレコードの削除もロールバック(中断)する」という実装にすると、以下の問題が発生します:

  1. ゾンビレコード: 物理ファイルが見つからないだけなのに、DBからレコードを消せず、ユーザーは永遠にそのタスクを「無効化」できない。
  2. 再計算の阻害: 破損したキャッシュエントリが残り続けることで、新しい計算結果での上書きや、クリーンな状態からの再実行が妨げられる。

Decision Drivers / 要求

Considered Options / 検討

Decision Outcome / 決定

Chosen option: Option 2.

削除操作において 「メタデータの削除を優先する」 ポリシーを採用します。

  1. まず、Blob(実データ)の削除を試みる。
  2. Blobの削除中に例外が発生した場合、処理を中断せずWARNING レベルのログを出力してエラーを捕捉する。
  3. Blob削除の成否に関わらず、DB上のタスクレコードの削除を必ず実行する。

Consequences / 決定

親: REQ010

子:

ADR021 ADR {h(g)} ✓ レビュー済

Code Visualization and Quality Metrics Strategy

Context and Problem Statement / コンテキスト

プロジェクトの規模拡大に伴い、以下の課題が発生しています:

  1. 構造の把握困難: モジュール間の依存関係が複雑化し、全体像を掴みにくい。
  2. 品質の定量化: コードの複雑さが主観で語られており、客観的なリファクタリング基準がない。
  3. アーキテクチャの健全性: 「安定依存の原則(SDP)」が守られているか(不安定なモジュールが安定したモジュールに依存していないか)を確認する手段がない。

Decision Drivers / 要求

Considered Options / 検討

Decision Outcome / 決定

Chosen option: Option 2.

以下のツールを導入し、開発フローに統合します。

  1. Radon:
    • 循環的複雑度 (Cyclomatic Complexity) と保守性指数 (Maintainability Index) を計測する。
  2. Pydeps:
    • モジュール間のインポート依存関係を可視化するグラフ(SVG)を生成する。
  3. Custom Stability Analyzer:
    • 不安定度 ($I$) を算出する独自スクリプトを tools/ に配置する。
    • Graphviz を用いて、安定度に基づいた色分け(青=安定、赤=不安定)を行ったアーキテクチャ図を生成する。

Consequences / 決定

親: REQ010

子:

ADR023 ADR {h(g)} ✓ レビュー済

Service Layer for Maintenance Operations

Context and Problem Statement / コンテキスト

現在、src/beautyspot/cli.py には以下のビジネスロジックが直接記述されています: 1. Pruning: タイムスタンプに基づく古いタスクの削除。 2. Cleaning: 孤立した Blob ファイルの特定と削除(ガベージコレクション)。

これらのロジックは sqlite3 ドライバに直接アクセスしたり、ファイルパスを操作したりしており、TaskDBBlobStorageBase の抽象化をバイパスしています。これにより、CLI が SQLite やローカルファイルストレージの詳細に密結合し、他のインターフェース(スクリプトや Web UI)から同じロジックを再利用できないという問題が発生しています。また、S3 などの外部ストレージに対する「掃除」機能の実装も困難になっています。

Decision Drivers / 要求

Considered Options / 検討

Decision Outcome / 決定

Chosen option: Option 3.

メンテナンスロジックを cli.py から抽出し、専用の MaintenanceService (src/beautyspot/maintenance.py) に移動します。

Spot クラスはアプリケーションの実行コンテキストとキャッシュ制御に集中させ、メンテナンス(行政的タスク)は別の関心事として分離します。

Consequences / 決定

親: REQ010

子:

ADR029 ADR {h(g)} ✓ レビュー済

Recursive Storage Cleanup and Zombie Project Collection

Context and Problem Statement / コンテキスト

これまでの beautyspot clean コマンドの実装には、以下の課題がありました。

  1. ディレクトリの残留: clean コマンドは個別のファイル削除のみを行い、空になったディレクトリを削除していませんでした。
  2. 隠しファイルの阻害: macOS の .DS_Store などのシステムファイルが存在する場合、ディレクトリが空とみなされず、削除できないケースがありました。
  3. ゾンビプロジェクト: ユーザーが手動で DB ファイル (.db) のみを削除した場合、対応する Blob ディレクトリが管理外のゴミ(ゾンビプロジェクト)として残り続け、削除する手段がありませんでした。

Decision Drivers / 要求

Considered Options / 検討

Decision Outcome / 決定

Chosen option: Option 2.

ストレージのクリーンアップ戦略を以下のように刷新します。

1. Two-Phase Cleanup Strategy (clean command)

clean コマンドを2段階に分割します。 * Phase 1 (File Deletion): DB参照のない孤立ファイルを削除。 * Phase 2 (Directory Pruning): LocalStorageprune_empty_dirs() メソッドを追加し、再帰的に空ディレクトリを一括削除。

2. Robust Directory Pruning

システム生成ファイル(.DS_Store, Thumbs.db, desktop.ini)のみが存在する場合、それらを「実質的な空」とみなし、強制的に削除した上で親ディレクトリを削除します。

3. Zombie Project Garbage Collection (gc command)

DBファイルが失われたプロジェクトを回収するための gc コマンドを実装します。対応する .db ファイルが存在しないディレクトリを「ゾンビプロジェクト」と判定し、shutil.rmtree で強制的に一括削除します。

Consequences / 決定

親: REQ010

子:

ADR041 ADR {h(g)} ✓ レビュー済

Garbage Collection Strategy for Abandoned Temporary Files

Context and Problem Statement / コンテキスト

Blob データの保存時、アトミックな書き込みを実現するために一時ファイルを作成し、完了後にリネームする設計を採用しています。しかし、アンチウイルスソフトやバックアッププロセスの介入によりリネームが失敗するエッジケースが存在します。この際、一時ファイルの削除もロックにより失敗すると、一時ファイルがストレージ上に永久に残留し続ける(ストレージリーク)という問題がありました。

Decision Drivers / 要求

Considered Options / 検討

Decision Outcome / 決定

Chosen option: Option 3.

アトミック書き込みのフェイルセーフとして、以下の機構を導入します。

  1. 専用サフィックスの導入: 一時ファイルの生成時に .spot_tmp という専用のサフィックスを付与し、追跡を容易にします。
  2. 遅延ガベージコレクション (GC): MaintenanceService.clean_garbage に、一時ファイルの削除処理を統合します。
  3. Grace Period (猶予期間) の設定: 更新時刻が指定時間(デフォルト24時間)を経過しているもののみを削除対象とし、並行プロセスへの影響を回避します。

Consequences / 決定

親: REQ010

子: