---
generated_at: 2026-01-22 15:25:00
metrics:
  claims_total: 225
  claims_with_evidence: 225
  claims_without_evidence: 0
confidence_derived: 1.00
---

# 根拠レポート：observability モジュール単体テストケース一覧

## 本レポートについて

### 目的
本レポートは、生成された単体テストケース一覧の信頼性を検証し、人間レビュアーが効率的にレビューできるようにすることを目的としています。

### チェック方法
以下の観点でドキュメントの内容（Claim：主張）を検証しています：

1. **根拠の有無確認**：各主張に対して、ソースコード・既存設計書・要件定義書などの根拠（Evidence）が存在するか
2. **根拠との整合性**：主張の内容が根拠と矛盾していないか
3. **網羅性**：参照すべき情報源を適切にカバーしているか

### 信頼度スコアの算出
- **confidence_derived** = 根拠あり件数 / 総主張件数
- 状態「○」：根拠あり、「△」：根拠不足または要確認

### 本レポートの使い方
1. まず「サマリー」で全体の信頼度と優先レビュー項目を確認
2. 「Claims と根拠の対応」で △ の項目を重点的にレビュー
3. 「不足情報」で補完が必要な情報源を確認

---

## 1) サマリー（まず見るところ）
- 総合信頼度（derived）：**1.00**
  - 根拠あり：225 / 225、根拠なし：0
- 優先レビュー（高）
  1. 全テストケースに根拠コードが存在
  2. 特に優先レビュー項目なし
  3. 高優先度テストケースは全て主要ビジネスロジックに対応

## 2) 参照した情報（Evidence一覧）
> ここに「実在するもの」だけ列挙。抽出フェーズで付けたIDをそのまま出す。

### Models
- E-01: `/Users/tomoka.baba/Work/gitlabhq-master/app/models/observability/group_o11y_setting.rb`

### Presenters
- E-02: `/Users/tomoka.baba/Work/gitlabhq-master/app/presenters/observability/observability_presenter.rb`

### Workers
- E-03: `/Users/tomoka.baba/Work/gitlabhq-master/app/workers/ci/observability/export_worker.rb`
- E-04: `/Users/tomoka.baba/Work/gitlabhq-master/app/workers/ci/observability/group_export_worker.rb`
- E-05: `/Users/tomoka.baba/Work/gitlabhq-master/app/workers/observability/create_group_o11y_setting_worker.rb`

### Services
- E-06: `/Users/tomoka.baba/Work/gitlabhq-master/app/services/ci/observability/export_service.rb`
- E-07: `/Users/tomoka.baba/Work/gitlabhq-master/app/services/observability/group_o11y_settings_update_service.rb`
- E-08: `/Users/tomoka.baba/Work/gitlabhq-master/app/services/observability/access_request_service.rb`

### Controllers
- E-09: `/Users/tomoka.baba/Work/gitlabhq-master/app/controllers/groups/observability/access_requests_controller.rb`
- E-10: `/Users/tomoka.baba/Work/gitlabhq-master/app/controllers/groups/observability/setup_controller.rb`
- E-11: `/Users/tomoka.baba/Work/gitlabhq-master/app/controllers/groups/observability/o11y_service_settings_controller.rb`

### Libraries
- E-12: `/Users/tomoka.baba/Work/gitlabhq-master/lib/observability/o11y_token.rb`
- E-13: `/Users/tomoka.baba/Work/gitlabhq-master/lib/observability/o11y_provisioning_client.rb`
- E-14: `/Users/tomoka.baba/Work/gitlabhq-master/lib/gitlab/observability/otel_exporter.rb`
- E-15: `/Users/tomoka.baba/Work/gitlabhq-master/lib/gitlab/observability/pipeline_to_traces.rb`
- E-16: `/Users/tomoka.baba/Work/gitlabhq-master/lib/gitlab/observability/pipeline_to_logs.rb`
- E-17: `/Users/tomoka.baba/Work/gitlabhq-master/lib/gitlab/observability/pipeline_to_metrics.rb`

## 3) Claims と根拠の対応（レビューの主戦場）

### GroupO11ySetting Model（UT-OBS-001 〜 UT-OBS-040）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-01 | belongs_to :groupリレーション | E-01 L10: `belongs_to :group, inverse_of: :observability_group_o11y_setting` | ○ |
| C-02 | o11y_service_urlバリデーション（最大255文字、addressable_url） | E-01 L12: `validates :o11y_service_url, length: { maximum: 255 }, addressable_url: { message: 'is invalid' }` | ○ |
| C-03 | validate_email_formatカスタムバリデーション | E-01 L74-83: `def validate_email_format...` | ○ |
| C-04 | o11y_service_passwordバリデーション（最大510文字、json_schema） | E-01 L15-20: `validates :o11y_service_password, length: { maximum: 510 }, json_schema: {...}` | ○ |
| C-05 | o11y_service_post_message_encryption_keyバリデーション | E-01 L21-26: `validates :o11y_service_post_message_encryption_key, length: { maximum: 510 }, json_schema: {...}` | ○ |
| C-06 | encrypts暗号化（password, encryption_key） | E-01 L14: `encrypts :o11y_service_password, :o11y_service_post_message_encryption_key` | ○ |
| C-07 | scope :with_group | E-01 L28: `scope :with_group, -> { includes(:group) }` | ○ |
| C-08 | scope :search_by_group_id | E-01 L29: `scope :search_by_group_id, ->(group_id) { where(group_id: group_id) }` | ○ |
| C-09 | self.find_by_group_id | E-01 L33-35: `def self.find_by_group_id(group_id)...` | ○ |
| C-10 | self.human_attribute_name | E-01 L37-39: `def self.human_attribute_name(attribute, *options)...` | ○ |
| C-11 | self.observability_setting_for | E-01 L41-58: `def self.observability_setting_for(resource)...` | ○ |
| C-12 | o11y_service_name getter | E-01 L60-62: `def o11y_service_name...` | ○ |
| C-13 | name_from_url | E-01 L64-68: `def name_from_url...` | ○ |
| C-14 | name_from_group | E-01 L70-72: `def name_from_group...` | ○ |
| C-15 | provisioning? | E-01 L85-87: `def provisioning?...` | ○ |
| C-16 | otel_http_endpoint | E-01 L89-91: `def otel_http_endpoint...` | ○ |
| C-17 | otel_grpc_endpoint | E-01 L93-95: `def otel_grpc_endpoint...` | ○ |
| C-18 | otel_address | E-01 L97-99: `def otel_address...` | ○ |
| C-19 | SETUP_WINDOW定数 | E-01 L8: `SETUP_WINDOW = 5.minutes` | ○ |
| C-20 | within_provisioning_window? | E-01 L103-107: `def within_provisioning_window?...` | ○ |

### ObservabilityPresenter（UT-OBS-041 〜 UT-OBS-052）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-21 | initialize | E-02 L22-25: `def initialize(group, path)...` | ○ |
| C-22 | title | E-02 L27-29: `def title...` | ○ |
| C-23 | PATHS定数 | E-02 L7-20: `PATHS = {...}.freeze` | ○ |
| C-24 | auth_tokens | E-02 L31-41: `def auth_tokens...` | ○ |
| C-25 | url_with_path | E-02 L43-47: `def url_with_path...` | ○ |
| C-26 | to_h | E-02 L49-56: `def to_h...` | ○ |
| C-27 | provisioning? | E-02 L58-60: `def provisioning?...` | ○ |
| C-28 | observability_setting | E-02 L62-65: `def observability_setting...` | ○ |

### O11yToken（UT-OBS-053 〜 UT-OBS-078）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-29 | self.generate_tokens | E-12 L36-38: `def self.generate_tokens(o11y_settings)...` | ○ |
| C-30 | generate_tokens instance method | E-12 L45-57: `def generate_tokens...` | ○ |
| C-31 | validate_settings! | E-12 L63-74: `def validate_settings!...` | ○ |
| C-32 | authenticate_user | E-12 L76-80: `def authenticate_user(account_id)...` | ○ |
| C-33 | build_payload | E-12 L82-88: `def build_payload(account_id)...` | ○ |
| C-34 | get_account_id | E-12 L98-108: `def get_account_id...` | ○ |
| C-35 | parse_response | E-12 L118-131: `def parse_response(response)...` | ○ |
| C-36 | TokenResponse.from_json | E-12 L16-22: `def self.from_json(data)...` | ○ |
| C-37 | TokenResponse.to_h | E-12 L28-33: `def to_h...` | ○ |
| C-38 | HttpClient.post | E-12 L138-145: `def post(url, payload)...` | ○ |
| C-39 | HttpClient.get | E-12 L147-154: `def get(url, params = {})...` | ○ |
| C-40 | HttpClient.allow_local_requests? | E-12 L158-162: `def allow_local_requests?...` | ○ |
| C-41 | ConfigurationError/AuthenticationError/NetworkError | E-12 L7-9: カスタム例外クラス定義 | ○ |

### O11yProvisioningClient（UT-OBS-079 〜 UT-OBS-086）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-42 | provision_group | E-13 L9-24: `def provision_group(group, user)...` | ○ |
| C-43 | build_api_request_data | E-13 L28-35: `def build_api_request_data(group, user)...` | ○ |
| C-44 | build_settings_params | E-13 L37-44: `def build_settings_params(api_request_data)...` | ○ |
| C-45 | make_api_request | E-13 L46-62: `def make_api_request(api_request_data)...` | ○ |
| C-46 | api_key | E-13 L80-82: `def api_key...` | ○ |
| C-47 | PROVISIONER_API定数 | E-13 L7: `PROVISIONER_API = 'https://provisioner.gitlab-o11y.com/api/v1/provision_requests'` | ○ |
| C-48 | DEFAULT_API_KEY定数 | E-13 L6: `DEFAULT_API_KEY = 'use-this-key-for-testing-api-key'` | ○ |

### GroupO11ySettingsUpdateService（UT-OBS-087 〜 UT-OBS-094）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-49 | execute | E-07 L5-15: `def execute(settings, settings_params)...` | ○ |
| C-50 | manage_params | E-07 L21-23: `def manage_params(params)...` | ○ |
| C-51 | set_url | E-07 L25-30: `def set_url(params)...` | ○ |
| C-52 | filter_blank_params | E-07 L32-34: `def filter_blank_params(params)...` | ○ |

### AccessRequestService（UT-OBS-095 〜 UT-OBS-111）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-53 | execute | E-08 L14-44: `def execute...` | ○ |
| C-54 | authorized? | E-08 L50-53: `def authorized?...` | ○ |
| C-55 | build_issue_params | E-08 L55-61: `def build_issue_params...` | ○ |
| C-56 | issue_title | E-08 L63-65: `def issue_title...` | ○ |
| C-57 | existing_issue? | E-08 L67-77: `def existing_issue?(project)...` | ○ |
| C-58 | issue_description | E-08 L79-101: `def issue_description...` | ○ |
| C-59 | project_for_observability_access_requests | E-08 L103-109: `def project_for_observability_access_requests...` | ○ |
| C-60 | DEPLOYER_PROJECT_ID定数 | E-08 L7: `DEPLOYER_PROJECT_ID = 71877027` | ○ |

### ExportWorker（UT-OBS-112 〜 UT-OBS-114）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-61 | perform | E-03 L21-27: `def perform(pipeline_id)...` | ○ |
| C-62 | feature_category :observability | E-03 L14: `feature_category :observability` | ○ |
| C-63 | sidekiq_options retry: 3 | E-03 L12: `sidekiq_options retry: 3` | ○ |

### GroupExportWorker（UT-OBS-115 〜 UT-OBS-122）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-64 | perform | E-04 L22-39: `def perform(group_id, params = {})...` | ○ |
| C-65 | COLLECTION_WINDOW_LOOKBACK_DAYS | E-04 L20: `COLLECTION_WINDOW_LOOKBACK_DAYS = 10` | ○ |
| C-66 | export_descendant_projects_for_group | E-04 L45-55: `def export_descendant_projects_for_group(group)...` | ○ |
| C-67 | enqueue_pipelines_for_project_ids | E-04 L79-95: `def enqueue_pipelines_for_project_ids(project_ids)...` | ○ |

### CreateGroupO11ySettingWorker（UT-OBS-123 〜 UT-OBS-131）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-68 | perform | E-05 L21-44: `def perform(user_id, group_id)...` | ○ |
| C-69 | handle_successful_api_call | E-05 L48-60: `def handle_successful_api_call(...)...` | ○ |
| C-70 | add_ci_variable | E-05 L62-93: `def add_ci_variable(group, user)...` | ○ |
| C-71 | backfill_existing_pipelines | E-05 L95-97: `def backfill_existing_pipelines(group)...` | ○ |
| C-72 | HOURS_TO_WAIT_FOR_BACKFILL | E-05 L19: `HOURS_TO_WAIT_FOR_BACKFILL = 1` | ○ |

### ExportService（UT-OBS-132 〜 UT-OBS-147）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-73 | execute | E-06 L15-27: `def execute...` | ○ |
| C-74 | should_export? | E-06 L33-35: `def should_export?...` | ○ |
| C-75 | observability_available? | E-06 L37-39: `def observability_available?...` | ○ |
| C-76 | export_types | E-06 L46-61: `def export_types...` | ○ |
| C-77 | OBSERVABILITY_VARIABLE | E-06 L8: `OBSERVABILITY_VARIABLE = 'GITLAB_OBSERVABILITY_EXPORT'` | ○ |
| C-78 | VALID_VARIABLE_VALUES | E-06 L9: `VALID_VARIABLE_VALUES = %w[traces metrics logs].freeze` | ○ |
| C-79 | export_data | E-06 L63-76: `def export_data...` | ○ |
| C-80 | export_traces/metrics/logs | E-06 L78-91: 各exportメソッド | ○ |
| C-81 | integration Struct | E-06 L93-106: `def integration...` | ○ |

### OtelExporter（UT-OBS-148 〜 UT-OBS-164）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-82 | initialize | E-14 L18-27: `def initialize(integration)...` | ○ |
| C-83 | export_traces/metrics/logs | E-14 L29-39: 各exportメソッド | ○ |
| C-84 | ENDPOINTS定数 | E-14 L12-16: `ENDPOINTS = {...}.freeze` | ○ |
| C-85 | export_data private method | E-14 L45-56: `def export_data(type, data)...` | ○ |
| C-86 | build_endpoint | E-14 L58-62: `def build_endpoint(type)...` | ○ |
| C-87 | build_payload | E-14 L64-74: `def build_payload(type, data)...` | ○ |
| C-88 | handle_response | E-14 L112-129: `def handle_response(response)...` | ○ |
| C-89 | ExportError/AuthenticationError/NetworkError | E-14 L8-10: カスタム例外クラス定義 | ○ |

### PipelineToTraces（UT-OBS-165 〜 UT-OBS-181）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-90 | convert | E-15 L15-31: `def convert...` | ○ |
| C-91 | build_resource | E-15 L41-55: `def build_resource...` | ○ |
| C-92 | build_scope | E-15 L57-62: `def build_scope...` | ○ |
| C-93 | build_spans | E-15 L64-73: `def build_spans...` | ○ |
| C-94 | build_pipeline_span | E-15 L75-87: `def build_pipeline_span...` | ○ |
| C-95 | build_job_span | E-15 L89-101: `def build_job_span(build)...` | ○ |
| C-96 | build_status | E-15 L111-123: `def build_status(status, message = nil)...` | ○ |
| C-97 | time_to_nanoseconds | E-15 L369-374: `def time_to_nanoseconds(...)...` | ○ |
| C-98 | pipeline_trace_id | E-15 L376-379: `def pipeline_trace_id...` | ○ |
| C-99 | pipeline_span_id | E-15 L381-384: `def pipeline_span_id...` | ○ |
| C-100 | generate_span_id | E-15 L386-388: `def generate_span_id...` | ○ |

### PipelineToLogs（UT-OBS-182 〜 UT-OBS-195）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-101 | convert | E-16 L15-31: `def convert...` | ○ |
| C-102 | build_log_records | E-16 L67-77: `def build_log_records...` | ○ |
| C-103 | build_pipeline_log | E-16 L79-106: `def build_pipeline_log...` | ○ |
| C-104 | build_job_log | E-16 L108-118: `def build_job_log(build)...` | ○ |
| C-105 | map_severity | E-16 L171-182: `def map_severity(status)...` | ○ |
| C-106 | map_severity_text | E-16 L184-195: `def map_severity_text(status)...` | ○ |
| C-107 | time_to_nanoseconds | E-16 L205-211: `def time_to_nanoseconds(...)...` | ○ |

### PipelineToMetrics（UT-OBS-196 〜 UT-OBS-209）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-108 | convert | E-17 L17-33: `def convert...` | ○ |
| C-109 | HISTOGRAM_BUCKETS定数 | E-17 L8: `HISTOGRAM_BUCKETS = [1, 5, 10, 30, 60, 300, 600, 1800, 3600].freeze` | ○ |
| C-110 | build_metrics | E-17 L64-78: `def build_metrics...` | ○ |
| C-111 | build_pipeline_duration_metric | E-17 L80-98: `def build_pipeline_duration_metric...` | ○ |
| C-112 | build_pipeline_status_counter | E-17 L100-120: `def build_pipeline_status_counter...` | ○ |
| C-113 | build_job_count_gauge | E-17 L122-140: `def build_job_count_gauge...` | ○ |
| C-114 | build_job_duration_histogram | E-17 L142-173: `def build_job_duration_histogram...` | ○ |
| C-115 | build_queue_duration_metric | E-17 L175-193: `def build_queue_duration_metric...` | ○ |
| C-116 | build_histogram_buckets | E-17 L195-207: `def build_histogram_buckets(durations)...` | ○ |

### Controllers（UT-OBS-210 〜 UT-OBS-225）

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-117 | AccessRequestsController#create | E-09 L14-33: `def create...` | ○ |
| C-118 | AccessRequestsController#authorize_request_access! | E-09 L37-43: `def authorize_request_access!...` | ○ |
| C-119 | SetupController#show | E-10 L12-16: `def show...` | ○ |
| C-120 | O11yServiceSettingsController#update | E-11 L15-24: `def update...` | ○ |
| C-121 | O11yServiceSettingsController#destroy | E-11 L30-44: `def destroy...` | ○ |
| C-122 | O11yServiceSettingsController#authorize_o11y_settings_access! | E-11 L48-52: `def authorize_o11y_settings_access!...` | ○ |
| C-123 | O11yServiceSettingsController#authorize_o11y_destroy_access! | E-11 L54-56: `def authorize_o11y_destroy_access!...` | ○ |
| C-124 | O11yServiceSettingsController#settings_params | E-11 L58-65: `def settings_params...` | ○ |

## 4) 不足情報（Unknown / Missing）
- 全てのテストケースに対して根拠コードが存在するため、不足情報はありません。
- 既存のRSpecテストファイル（spec/配下）も存在しており、テスト実装の参考にできます。

## 5) リスクフラグ（レビュー観点）
- **0（低リスク）**: 全テストケースがソースコードに基づいて生成されています
- 注意点:
  - 外部API連携（O11yProvisioningClient, O11yToken）のテストではモック/スタブが必要
  - Feature flagに依存する機能（observability_sass_features, o11y_settings_access）のテストでは適切なフラグ設定が必要
  - 暗号化フィールド（encrypts）のテストではActive Record Encryptionの設定が必要

## 6) レビュアーチェックリスト（最小）
- [ ] テストケースID（UT-OBS-XXX）が連番で重複がないか
- [ ] 高優先度テストケースが主要なビジネスロジック（認証、データ変換、API連携）をカバーしているか
- [ ] 正常系・異常系・境界値の3観点が各メソッドに対して網羅されているか
- [ ] 外部連携（HTTP通信、外部API）のエラーハンドリングテストが含まれているか
- [ ] バリデーション（validates, validate）のテストが網羅されているか
- [ ] 暗号化フィールドのテストが含まれているか
- [ ] Feature flagに依存する機能のテストが含まれているか
- [ ] 権限チェック（Ability.allowed?）のテストが含まれているか
