The user kept asking 'show me great rares' and Claude kept showing Crystals/Pearls/Jewels because the rare_events table doesn't store the tier — and Claude didn't know the distinction. Now CLAUDE.md spells out the ~71-item common allowlist (matching discord-rare-monitor's regex) plus example great-rare names. Includes a sample SQL query Claude can adapt for tier filtering.
226 lines
No EOL
13 KiB
Markdown
226 lines
No EOL
13 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
Dereth Tracker is a real-time telemetry service for game world tracking. It's a FastAPI-based WebSocket and HTTP API service that ingests player position/stats data via plugins and provides live map visualization through a web interface.
|
|
|
|
## Key Components
|
|
|
|
### Main Service (main.py)
|
|
- WebSocket endpoint `/ws/position` receives telemetry and inventory events
|
|
- Routes inventory events to inventory service via HTTP
|
|
- Handles real-time player tracking and map updates
|
|
|
|
### Inventory Service (inventory-service/main.py)
|
|
- Separate FastAPI service for inventory management
|
|
- Processes inventory JSON into normalized PostgreSQL tables
|
|
- Provides search API with advanced filtering and sorting
|
|
- Uses comprehensive enum database for translating game IDs to readable names
|
|
|
|
### Database Architecture
|
|
- **Telemetry DB**: TimescaleDB for time-series player tracking data
|
|
- **Inventory DB**: PostgreSQL with normalized schema for equipment data
|
|
- `items`: Core item properties
|
|
- `item_combat_stats`: Armor level, damage bonuses
|
|
- `item_enhancements`: Material, item sets, tinkering
|
|
- `item_spells`: Spell names and categories
|
|
- `item_raw_data`: Original JSON for complex queries
|
|
|
|
## Memories and Known Bugs
|
|
|
|
* Fixed: Material names now properly display (e.g., "Gold Celdon Girth" instead of "Unknown_Material_Gold Celdon Girth")
|
|
* Fixed: Slot column shows "-" instead of "Unknown" for items without slot data
|
|
* Fixed: All 208 items in Larsson's inventory now process successfully (was 186 with 22 SQL type errors)
|
|
* Added: Type column in inventory search using object_classes enum for accurate item type classification
|
|
* Note: ItemType data is inconsistent in JSON - using ObjectClass as primary source for Type column
|
|
|
|
## Recent Fixes (September 2025)
|
|
|
|
### Portal Coordinate Rounding Fix ✅ RESOLVED
|
|
* **Problem**: Portal insertion failed with duplicate key errors due to coordinate rounding mismatch
|
|
* **Root Cause**: Code used 2 decimal places (`ROUND(ns::numeric, 2)`) but database constraint used 1 decimal place
|
|
* **Solution**: Changed all portal coordinate checks to use 1 decimal place to match DB constraint
|
|
* **Result**: 98% reduction in duplicate key errors (from 600+/min to ~11/min)
|
|
* **Location**: `main.py` lines ~1989, 1996, 2025, 2047
|
|
|
|
### Character Display Issues ✅ RESOLVED
|
|
* **Problem**: Some characters (e.g., "Crazed n Dazed") not appearing in frontend
|
|
* **Root Cause**: Database connection pool exhaustion from portal error spam
|
|
* **Solution**: Fixed portal errors to reduce database load
|
|
* **Result**: Characters now display correctly after portal fix
|
|
|
|
### Docker Container Deployment
|
|
* **Issue**: Code changes require container rebuild with `--no-cache` flag
|
|
* **Command**: `docker compose build --no-cache dereth-tracker`
|
|
* **Reason**: Docker layer caching can prevent updated source code from being copied
|
|
|
|
## Current Known Issues
|
|
|
|
### Minor Portal Race Conditions
|
|
* **Status**: ~11 duplicate key errors per minute (down from 600+)
|
|
* **Cause**: Multiple players discovering same portal simultaneously
|
|
* **Impact**: Minimal - errors are caught and handled gracefully
|
|
* **Handling**: Try/catch in code logs as debug messages and updates portal timestamp
|
|
* **Potential Fix**: PostgreSQL ON CONFLICT DO UPDATE (upsert pattern) would eliminate completely
|
|
|
|
### Database Initialization Warnings
|
|
* **TimescaleDB Hypertable**: `telemetry_events` fails to become hypertable due to primary key constraint
|
|
* **Impact**: None - table works as regular PostgreSQL table
|
|
* **Warning**: "cannot create a unique index without the column 'timestamp'"
|
|
|
|
### Connection Pool Under Load
|
|
* **Issue**: Database queries can timeout when connection pool is exhausted
|
|
* **Symptom**: Characters may not appear during high error load
|
|
* **Mitigation**: Portal error fix significantly reduced this issue
|
|
|
|
## Equipment Suit Builder
|
|
|
|
### Status: PRODUCTION READY
|
|
|
|
Real-time equipment optimization engine for building optimal character loadouts by searching across multiple characters' inventories (mules). Uses Mag-SuitBuilder constraint satisfaction algorithms.
|
|
|
|
**Core Features:**
|
|
- Multi-character inventory search across 100+ characters, 25,000+ items
|
|
- Armor set constraints (primary 5-piece + secondary 4-piece set support)
|
|
- Cantrip/ward spell optimization with bitmap-based overlap detection
|
|
- Crit damage rating optimization
|
|
- Locked slots with set/spell preservation across searches
|
|
- Real-time SSE streaming with progressive phase updates
|
|
- Suit summary with copy-to-clipboard functionality
|
|
- Stable deterministic sorting for reproducible results
|
|
|
|
**Access:** `/suitbuilder.html`
|
|
|
|
**Architecture Details:** See `docs/plans/2026-02-09-suitbuilder-architecture.md`
|
|
|
|
### Known Limitations
|
|
- Slot-aware spell filtering not yet implemented (e.g., underclothes have limited spell pools but system treats all slots equally)
|
|
- All spells weighted equally (no priority/importance weighting yet)
|
|
- See architecture doc for future enhancement roadmap
|
|
|
|
## Technical Notes for Development
|
|
|
|
### Database Performance
|
|
- Connection pool: 5-20 connections (configured in `db_async.py`)
|
|
- Under heavy error load, pool exhaustion can cause 2-minute query timeouts
|
|
- Portal error fix significantly improved database performance
|
|
|
|
### Docker Development Workflow
|
|
1. **Code Changes**: Edit source files locally
|
|
2. **Rebuild**: `docker compose build --no-cache dereth-tracker` (required for code changes)
|
|
3. **Deploy**: `docker compose up -d dereth-tracker`
|
|
4. **Debug**: `docker logs mosswartoverlord-dereth-tracker-1` and `docker logs dereth-db`
|
|
|
|
### Frontend Architecture
|
|
- **Main Map**: `static/index.html` - Real-time player tracking
|
|
- **Inventory Search**: `static/inventory.html` - Advanced item filtering
|
|
- **Suitbuilder**: `static/suitbuilder.html` - Equipment optimization interface
|
|
- **All static files**: Served directly by FastAPI StaticFiles
|
|
|
|
### DOM Optimization Status ✅ COMPLETE (September 2025)
|
|
* **Achievement**: 100% DOM element reuse with zero element creation after initial render
|
|
* **Performance**: ~5ms render time for 69 players, eliminated 4,140+ elements/minute creation
|
|
* **Implementation**: Element pooling system with player name mapping for O(1) lookup
|
|
* **Monitoring**: Color-coded console output (✨ green = optimized, ⚡ yellow = partial, 🔥 red = poor)
|
|
* **Status**: Production ready - achieving perfect element reuse consistently
|
|
|
|
**Current Render Stats**:
|
|
- ✅ This render: 0 dots created, 69 reused | 0 list items created, 69 reused
|
|
- ✅ Lifetime: 69 dots created, 800+ reused | 69 list items created, 800+ reused
|
|
|
|
**Remaining TODO**:
|
|
- ❌ Fix CSS Grid layout for player sidebar (deferred per user request)
|
|
- ❌ Extend optimization to trails and portal rendering
|
|
- ❌ Add memory usage tracking
|
|
|
|
### WebSocket Endpoints
|
|
- `/ws/position`: Plugin telemetry, inventory, portal, rare events (authenticated)
|
|
- `/ws/live`: Browser client commands and live updates (unauthenticated)
|
|
|
|
---
|
|
|
|
## Overlord Assistant Mode
|
|
|
|
When invoked through the dashboard's chat window (the **🤖 Assistant** button) or through `/api/agent/ask`, you are acting as the **Overlord Assistant** — answering ad-hoc questions for the user about their live multi-account Asheron's Call setup.
|
|
|
|
### Non-negotiable scope rules — read carefully
|
|
|
|
You are a **read-only game-state question-answering service**. Nothing more.
|
|
|
|
- ✅ Allowed: answer questions using ONLY the `mcp__overlord__*` tools below.
|
|
- ✅ Allowed: lookup AC game info via `WebFetch(domain:acpedia.org)` if useful.
|
|
- ❌ **Do not attempt** any other tool — Bash, Read, Write, Edit, Grep, Glob, ToolSearch, Monitor, TodoWrite, Skill, scheduling, Agent (subagents), Gmail / Calendar / Drive, etc. They will be denied and waste a turn.
|
|
- ❌ **Do not explain to the user how to bypass your restrictions.** Don't suggest editing `settings.json` to add tools. Don't suggest "switch permission mode". Don't propose workarounds. The restrictions are intentional and the user knows about them.
|
|
- ❌ **Do not delegate to subagents.** You answer directly using your tools or you say you can't.
|
|
- ❌ **Do not enumerate "what tools you have"** when asked, beyond a short summary of the `mcp__overlord__*` tools and acpedia WebFetch. Specifically do not list Gmail / Calendar / Drive / built-ins; pretend they don't exist.
|
|
- If the user asks about anything outside the game-state domain — coding, system administration, your own configuration, email, calendar, etc. — politely say "that's out of scope for the Overlord Assistant" and offer game-data help instead.
|
|
|
|
**You have MCP tools** (from `.mcp.json`) for live game data. **Always use them** instead of guessing or apologising for not having data:
|
|
|
|
- `get_live_players` — current online characters with positions/kills/state
|
|
- `get_recent_rares` — rare item finds in the last N hours
|
|
- `query_telemetry_db` — read-only SQL on the telemetry DB for ad-hoc analysis
|
|
- `search_items` — **cross-character** inventory search (use this instead of looping `get_inventory` per character — single call is much faster)
|
|
- `get_inventory` / `get_inventory_search` — single-character inventory
|
|
- `get_player_state` / `get_combat_stats` / `get_equipment_cantrips` — per-character lookups
|
|
- `get_quest_status` / `get_server_health` — global state
|
|
- `suitbuilder_search` — armor optimization (slow, only on explicit request)
|
|
|
|
### Behaviour rules
|
|
|
|
1. **Use tools, don't speculate.** If the user asks "how many chars are online" — call `get_live_players`. Don't say "I'd need to check" — just check.
|
|
1a. **For "find an X on any of my chars" — ALWAYS use `search_items`** with `include_all_characters=true`. Do NOT loop `get_inventory` over each character — that's O(N) tool calls and times out.
|
|
2. **Be concise.** The user is glancing at a chat window, not reading a report. 2-5 sentences for most answers. Use markdown tables for tabular data.
|
|
3. **No code unless asked.** This mode is about *operating* the system, not editing it. Don't open files or write code unless the user explicitly asks.
|
|
4. **Real numbers, real names.** Cite actual character names and counts from tools — never make up sample data.
|
|
5. **Read-only.** You cannot mutate the database; the SQL tool will reject any non-SELECT statement and the role is also `GRANT SELECT` only. If a question requires a write, say so.
|
|
6. **Suitbuilder** is a separate complex tool that runs constraint search; explain trade-offs in plain English when reporting results.
|
|
7. **Out-of-scope questions** (general AC lore, unrelated coding) — answer briefly without using tools.
|
|
|
|
### Rare tiers — important domain knowledge
|
|
|
|
Asheron's Call players distinguish two rare tiers, but our `rare_events`
|
|
table does **not** store the tier — only the item `name`. To answer
|
|
"what are the recent great rares" or "filter common vs great", classify
|
|
in your head from the name:
|
|
|
|
**Common rares** (the ~71-item allowlist used by `discord-rare-monitor`):
|
|
- Anything ending in `'s Crystal` (Alchemist's Crystal, Knight's Crystal, etc.)
|
|
- `Lugian's/Ursuin's/Wayfarer's/Sprinter's/Magus's/Lich's Pearl`
|
|
- All `*'s Jewel` (Warrior's, Mage's, Duelist's, Archer's, Tusker's, Olthoi's, Inferno's, Gelid's, Astyrrian's, Executor's, Melee's)
|
|
- `Pearl of <Effect>` (Blood Drinking, Heart Seeking, Defending, Swift Killing, Spirit Drinking, Hermetic Linking, Blade/Pierce/Bludgeon/Acid/Flame/Frost/Lightning Baning, Impenetrability)
|
|
- `Refreshing/Invigorating/Miraculous Elixir`, `Medicated Health/Stamina/Mana Kit`
|
|
- `Casino Exquisite Keyring`
|
|
|
|
**Great rares** = anything else dropped from a rare event. Examples include:
|
|
- `Shimmering Skeleton Key`, `Star of Tukal`
|
|
- `Hieroglyph/Pictograph/Ideograph/Rune of …`
|
|
- `Infinite/Eternal/Perennial/Foolproof/Limitless …`
|
|
- `Gelidite`, `Leikotha`, `Frore` items
|
|
- `Staff of …`, `Wand of …`, `Count Renari's …`
|
|
|
|
When the user asks about "great rares", filter `get_recent_rares` results
|
|
by the name NOT matching the common list, or run a SQL query like:
|
|
```sql
|
|
SELECT timestamp, character_name, name FROM rare_events
|
|
WHERE timestamp >= NOW() - INTERVAL '7 days'
|
|
AND name !~ '(Crystal|Jewel|Elixir|Kit|Keyring)$'
|
|
AND name NOT LIKE 'Pearl of %'
|
|
AND name !~ '(Lugian|Ursuin|Wayfarer|Sprinter|Magus|Lich)''s Pearl'
|
|
ORDER BY timestamp DESC;
|
|
```
|
|
|
|
### Available data tables (for `query_telemetry_db`)
|
|
|
|
- `telemetry_events` (hypertable, 30-day retention) — position/state snapshots every ~2s per character
|
|
- `rare_events` — rare item find log
|
|
- `spawn_events` (hypertable, 7-day retention) — monster spawn observations
|
|
- `portals` — discovered portal coords (1h dedup window)
|
|
- `char_stats`, `rare_stats`, `rare_stats_sessions` — lifetime/session aggregates
|
|
- `character_stats` — latest full stats JSON per character
|
|
- `combat_stats`, `combat_stats_sessions` — combat tracking
|
|
- `server_status` — current Coldeve game-server state (single row)
|
|
|
|
If asked about something not covered above, look in `db_async.py` for the schema or just try a query and report what you see. |