evalstone/bash/fingerprint/tools/llm-verify/.github/copilot-instructions.md
ruoxi_sun 58657935fc bundle fingerprint tool repos into evalstone for self-containment
Vendor LLMmap / llm-verify / llm-fingerprint-detector under
bash/fingerprint/tools so the three fingerprint benchmarks run with only
/data1/eval mounted (no /data1/xii dependency):
- run.py DEFAULT_TOOLS_ROOT prefers builtin tools/, falls back to /data1/xii
- exclude .git / node_modules / template backups
- detector dist/ (pre-built) retained; node_modules not needed at runtime
2026-09-03 06:45:46 +00:00

272 lines
12 KiB
Markdown

# 🤖 COPILOT AUTO-UPDATE RULE
**Copilot MUST update this file automatically when ANY of the following happens:**
1. **User defines or changes** project domain, stack, database, or scale → Update 🎯 PROJECT IDENTITY
2. **User starts a new task** or completes one → Update 🚧 CURRENT FOCUS and ✅ COMPLETED WORK
3. **User makes architectural decisions** → Update 📋 IMPORTANT CONTEXT and 🏗 PATTERNS TO USE
4. **User adds explicit instructions** (e.g., "always do X", "use Y for Z") → Add to 📜 USER INSTRUCTIONS LOG
5. **User provides credentials or config names** → Add NAME ONLY to 🔐 CREDENTIALS & CONFIG (⚠️ NEVER store values!)
6. **User says "don't do X"** or prohibits something → Add to 🚫 USER SAID "DON'T DO THIS"
7. **User shares important context** (business rules, constraints, domain knowledge) → Add to 📋 IMPORTANT CONTEXT
**After updating, briefly confirm what was changed at the end of the response.**
---
## 🎯 PROJECT IDENTITY
| Field | Value |
| ------------ | ------------------------------------------------------------------------------------------------------ |
| **Name** | LLM Verify |
| **Domain** | AI model verification & benchmarking — detect model fraud (e.g., resold APIs misrepresenting identity) |
| **Stack** | Python 3.12+ · FastAPI · Pydantic v2 · httpx (async) · SQLAlchemy 2.0 (async) · Alembic |
| **Database** | SQLite (dev & prod — file-based, zero-config) |
| **Scale** | Single-node CLI + web dashboard · benchmarks run locally or via CI |
| **Repo** | `benchmark/` |
---
## 📜 USER INSTRUCTIONS LOG
| # | Date | Instruction |
| --- | ---------- | ------------------------------------------------ |
| 1 | 2026-02-17 | Project bootstrapped with Copilot context system |
| | | |
---
## ✅ COMPLETED WORK
| # | Date | Task |
| --- | ---------- | ----------------------------------------------------------------------- |
| 1 | 2026-02-17 | Project bootstrap — copilot context, settings, gitignore |
| 2 | 2026-02-17 | Full project scaffolding — 30+ files, all layers, 32 prompts |
| 3 | 2026-02-17 | All 9 unit tests passing |
| 4 | 2026-02-17 | Renamed to LLM Verify, pushed to GitHub |
| 5 | 2026-02-17 | Fixed factory: suspect provider now uses Anthropic protocol by default |
| 6 | 2026-02-17 | First live benchmark — identity probes vs suspect API (opuscode.pro) |
| 7 | 2026-02-17 | Confirmed fraud: suspect serves Claude 3.5 Sonnet as Claude Sonnet 4 |
| 8 | 2026-02-17 | Updated README with no-API-key usage guide and red flags doc |
| 9 | 2026-02-17 | Added deep analysis feature — service, schemas, handler, README section |
---
## 🚧 CURRENT FOCUS
| Item | Detail |
| -------------- | ------------------------------------------------------------------- |
| **Working on** | Deep analysis feature complete — ready for live testing |
| **Blockers** | None |
| **Next up** | Live test deep analysis endpoint, web dashboard, more prompt suites |
---
## 🔐 CREDENTIALS & CONFIG
> ⚠️ **NEVER store actual values here — names/keys only!**
| # | Name | Service | Notes |
| --- | -------------------- | ------------ | ------------------------------------ |
| 1 | SUSPECT_API_KEY | opuscode.pro | Suspect API key — Anthropic protocol |
| 2 | SUSPECT_API_BASE_URL | opuscode.pro | https://opuscode.pro/api |
---
## 🚫 USER SAID "DON'T DO THIS"
| # | Date | Prohibition |
| --- | ---- | ----------- |
| | | |
---
## 📋 IMPORTANT CONTEXT
- **Core Problem:** Users are being sold API access to models misrepresented as premium models (e.g., Kimi sold as Claude). The system prompt says "Claude" but the underlying model is actually Kimi.
- **Goal:** Build a benchmark suite that can fingerprint AI model behavior to verify true model identity, comparing response patterns, capabilities, and quirks across models.
- **Suspect API (opuscode.pro):** Uses **Anthropic Messages protocol**, NOT OpenAI. Endpoint: `https://opuscode.pro/api/v1/messages`. Auth header: `x-api-key`. Available models: `Opus 4.6`, `Sonnet 4.5`, `Haiku 4.5` (their naming). Default model: `Opus 4.6`.
- **First test result:** Suspect claims to be Claude Sonnet 4 but self-identifies as **claude-3-5-sonnet-20241022** (Claude 3.5 Sonnet). Gave 3 different knowledge cutoffs, mentions "custom proxy server", avg latency 14s.
- **Factory mapping:** `suspect` provider defaults to `anthropic` protocol. Can be overridden via `protocol` field in ModelConfig.
- **Key Features Planned:**
- Run standardized prompt suites against multiple API endpoints
- Collect and store structured benchmark results (latency, token usage, response quality)
- Statistical comparison & fingerprinting to detect model identity
- Web dashboard to visualize results
- CLI for running benchmarks in CI/CD
---
## 🚨 HARD RULES
### Security
-**NEVER** commit secrets, API keys, or tokens to code or config files
- ✅ Use `.env` files (gitignored) and `pydantic-settings` for all secrets
- ✅ Parameterized queries only — no string interpolation in SQL
- ✅ Validate all external input with Pydantic models
### Performance
- ✅ Use `async/await` for all I/O (HTTP calls, DB queries, file ops)
- ✅ Use `httpx.AsyncClient` with connection pooling for API calls
- ✅ Use SQLAlchemy async sessions with proper context managers
- ✅ Batch concurrent API calls with `asyncio.gather()` where appropriate
### Architecture
- ✅ Dependency injection via FastAPI `Depends()`
- ✅ Strict separation: handlers → services → repositories → models
- ✅ Each layer has a single responsibility
- ✅ Config is centralized in one place (`src/config.py`)
---
## 📐 CODE STYLE
- **Type hints** on ALL function signatures and return types
- **Docstrings** on all public functions (Google style)
- **Descriptive names** — no single-letter variables except `i`, `_` in comprehensions
- **Early returns** to reduce nesting
- **Max 30 lines** per function — extract helpers if longer
- **Pydantic models** for all data structures crossing boundaries
- **f-strings** for string formatting
- **`pathlib.Path`** over `os.path`
---
## 🏗 PATTERNS TO USE
| Pattern | Usage |
| ---------------------- | ---------------------------------------------------------------- |
| **Result pattern** | Return `Result[T, Error]` for operations that can fail |
| **Service pattern** | Business logic lives in service classes, not in handlers |
| **Repository pattern** | DB access abstracted behind repository interfaces |
| **Adapter pattern** | Each AI provider gets an adapter implementing a common interface |
| **Factory pattern** | Create model adapters dynamically from config |
| **Strategy pattern** | Benchmark suites are pluggable strategies |
---
## 🚫 PATTERNS TO AVOID
| Anti-pattern | Why |
| ------------------------- | --------------------------------------------------- |
| **God objects** | Split into focused, single-responsibility classes |
| **Magic numbers/strings** | Use enums and constants |
| **Mutable global state** | Use DI and explicit passing |
| **Generic `utils.py`** | Create specific modules (`string_helpers.py`, etc.) |
| **Bare `except:`** | Always catch specific exceptions |
| **Print debugging** | Use `structlog` or `logging` |
| **Nested callbacks** | Use async/await |
---
## 📁 PROJECT STRUCTURE
```
benchmark/
├── src/
│ ├── __init__.py
│ ├── main.py # FastAPI app entry point
│ ├── config.py # Pydantic Settings configuration
│ ├── database.py # SQLAlchemy engine & session setup
│ ├── handlers/ # API route handlers (thin layer)
│ │ ├── __init__.py
│ │ ├── benchmarks.py
│ │ └── results.py
│ ├── services/ # Business logic
│ │ ├── __init__.py
│ │ ├── benchmark_runner.py
│ │ ├── model_comparator.py
│ │ └── fingerprint.py
│ ├── repositories/ # Database access
│ │ ├── __init__.py
│ │ ├── benchmark_repo.py
│ │ └── result_repo.py
│ ├── models/ # SQLAlchemy ORM models
│ │ ├── __init__.py
│ │ ├── benchmark.py
│ │ └── result.py
│ ├── schemas/ # Pydantic request/response schemas
│ │ ├── __init__.py
│ │ ├── benchmark.py
│ │ └── result.py
│ ├── adapters/ # AI provider adapters
│ │ ├── __init__.py
│ │ ├── base.py # Abstract base adapter
│ │ ├── openai_adapter.py
│ │ ├── anthropic_adapter.py
│ │ └── generic_adapter.py # For OpenAI-compatible APIs
│ └── prompts/ # Benchmark prompt suites
│ ├── __init__.py
│ ├── identity.py # "Who are you?" probes
│ ├── capability.py # Capability-specific tests
│ └── fingerprint.py # Behavioral fingerprinting prompts
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Shared fixtures
│ ├── test_benchmark_runner.py
│ ├── test_model_comparator.py
│ └── test_adapters/
│ └── test_generic_adapter.py
├── alembic/ # Database migrations
│ └── versions/
├── alembic.ini
├── .env.example
├── .gitignore
├── pyproject.toml
└── README.md
```
---
## 🔑 ENVIRONMENT VARIABLES
```env
# === REQUIRED ===
DATABASE_URL=sqlite+aiosqlite:///./benchmarker.db
# === AI PROVIDER API KEYS (add as needed) ===
# OPENAI_API_KEY=
# ANTHROPIC_API_KEY=
# SUSPECT_API_KEY= # The API you're testing/verifying
# SUSPECT_API_BASE_URL= # Base URL of the suspect API
# === OPTIONAL ===
# LOG_LEVEL=INFO
# BENCHMARK_TIMEOUT=30 # Seconds per API call
# MAX_CONCURRENT_CALLS=5 # Limit parallel API requests
```
---
## 📚 GLOSSARY
| Abbreviation | Meaning |
| ---------------- | ------------------------------ |
| `ctx` | Context |
| `repo` | Repository |
| `svc` | Service |
| `dto` | Data Transfer Object |
| `handler` | API route handler (controller) |
| `adapter` | AI provider adapter |
| `cfg` / `config` | Configuration |
| `db` | Database |
| `req` / `res` | Request / Response |
| `bench` | Benchmark |
| `fp` | Fingerprint |
---
## ✅ TESTING
- **Test alongside code** — tests mirror `src/` structure
- **Mock all externals** — API calls, database, file system
- **Cover edge cases** — empty inputs, timeouts, malformed responses
- **Target 80% coverage** minimum
- **Use `pytest`** with `pytest-asyncio` for async tests
- **Fixtures in `conftest.py`** — shared test data and mocks
- **Test naming:** `test_<function>_<scenario>_<expected>` (e.g., `test_run_benchmark_timeout_raises_error`)
- **Use `httpx.AsyncClient`** for integration testing FastAPI endpoints