#!/usr/bin/env python3 """ Diagnose why data appears in API but not in costs.json. """ import json from pathlib import Path def main(): target_email = 'ratoui@sonymusic-pde.com' target_date = '2025-10-18' print(f'=== Diagnosing missing data for {target_email} on {target_date} ===\n') # Step 1: Load users and find ratoui's user ID print('Step 1: Loading user metadata...') with open('output/usage/raw/users.json') as f: users_data = json.load(f) target_user = None for user in users_data['data']: if user['email'] == target_email: target_user = user break if not target_user: print(f'ERROR: User {target_email} not found!') return target_user_id = target_user['id'] print(f' User ID: {target_user_id}') print(f' Name: {target_user["name"]}') # Step 2: Load API keys and find ratoui's keys print('\nStep 2: Loading API keys...') with open('output/usage/raw/api_keys.json') as f: api_keys_data = json.load(f) user_api_keys = [] for key in api_keys_data['data']: if key.get('created_by', {}).get('id') == target_user_id: user_api_keys.append(key) user_key_ids = {key['id'] for key in user_api_keys} print(f' Found {len(user_api_keys)} API keys') for key in user_api_keys: print(f' - {key["name"]} ({key["id"]}) - {key["status"]}') # Step 3: Check raw usage file for target date print(f'\nStep 3: Checking raw usage file for {target_date}...') raw_file = Path(f'output/usage/raw/messages_{target_date}.json') if not raw_file.exists(): print(f' ERROR: Raw file {raw_file} does not exist!') print(' This means the date was never fetched. Run: make fetch-costs-update') return with open(raw_file) as f: raw_usage = json.load(f) # Parse the raw file structure usage_records = [] data_array = raw_usage.get('data', []) if data_array and len(data_array) > 0: usage_records = data_array[0].get('results', []) print(f' Raw file has {len(usage_records)} total usage records') # Find ratoui's records ratoui_records = [r for r in usage_records if r.get('api_key_id') in user_key_ids] print(f' Found {len(ratoui_records)} records for ratoui') if ratoui_records: for record in ratoui_records: key_id = record['api_key_id'] key_name = 'Unknown' for key in user_api_keys: if key['id'] == key_id: key_name = key['name'] break cache_creation = record.get('cache_creation', {}) cache_tokens = cache_creation.get('ephemeral_1h_input_tokens', 0) + cache_creation.get('ephemeral_5m_input_tokens', 0) print(f'\n Record for key: {key_name}') print(f' Model: {record["model"]}') print(f' Uncached input: {record.get("uncached_input_tokens", 0):,}') print(f' Cache creation: {cache_tokens:,}') print(f' Cache read: {record.get("cache_read_input_tokens", 0):,}') print(f' Output: {record.get("output_tokens", 0):,}') else: print(' ❌ No records found for ratoui in raw file!') return # Step 4: Check costs.json print('\nStep 4: Checking costs.json...') costs_file = Path('output/usage/costs.json') if not costs_file.exists(): print(f' ERROR: {costs_file} does not exist!') print(' Run: make regenerate-costs') return with open(costs_file) as f: costs_data = json.load(f) # Find ratoui's API keys in costs.json print(f' Checking {len(costs_data["api_keys"])} API keys in costs.json...') found_in_costs = False for api_key_data in costs_data['api_keys']: if api_key_data['api_key_id'] in user_key_ids: found_in_costs = True print(f'\n ✓ Found key in costs.json: {api_key_data["name"]}') print(f' API Key ID: {api_key_data["api_key_id"]}') print(f' Total cost: ${api_key_data.get("total_cost", 0):.2f}') print(f' Created by: {api_key_data.get("created_by_name")} ({api_key_data.get("created_by_email")})') # Check time periods time_periods = api_key_data.get('time_periods', []) print(f' Time periods: {len(time_periods)}') # Look for target date target_period = None for period in time_periods: if period['time_period'] == target_date: target_period = period break if target_period: print(f'\n ✓ Found data for {target_date}:') print(f' Cost: ${target_period["period_cost"]:.2f}') print(f' Models: {len(target_period["models"])}') for model_data in target_period['models']: print(f' - {model_data["model"]}: ${model_data["cost"]["total"]:.2f}') else: print(f'\n ❌ NO data for {target_date} in time_periods!') print(' Available periods:') for period in time_periods[:5]: # Show first 5 print(f' - {period["time_period"]}: ${period["period_cost"]:.2f}') if not found_in_costs: print(' ❌ No keys found for ratoui in costs.json!') print(' This means the rebuild process is filtering out the data.') # Step 5: Summary print('\n=== Summary ===') print(f'Raw file exists: {raw_file.exists()}') print(f'Records in raw file: {len(ratoui_records)}') print(f'Keys in costs.json: {found_in_costs}') if len(ratoui_records) > 0 and not found_in_costs: print('\n⚠️ DATA LOSS DETECTED!') print('Data exists in raw file but missing from costs.json.') print('Possible causes:') print(' 1. The rebuild script is not processing the raw file correctly') print(' 2. The API key ID is not matching between raw data and metadata') print(' 3. The date/time grouping is incorrect') print('\nTo debug further:') print(' 1. Run: make regenerate-costs') print(' 2. Check the console output for warnings') print(' 3. Verify API key IDs match between raw files') if __name__ == '__main__': main()