# CLAUDE.md — Phase 11: Tracker Rule Corpus

## Scope of This File

This file instructs you (Claude Code) to implement **Phase 11 only** of the Seedbox Command Center.

**Do not implement phases 12 through 15.** Stay in scope.

## Authoritative Specification

`PROJECT.md` §8.8 (Tracker Rule Corpus) and Appendix E (the YAML schema) are authoritative. Read both. Also read:
- `PROGRESS.md` and `DECISIONS.md`.
- The Phase 1 `internal/integrations/trackers` adapter — the corpus feeds tracker-specific behavior into the scraper.
- The Phase 7 `internal/intelligence/hr_risk` predictor — it benefits substantially from corpus-sourced seed-time requirements.

## Phase 11 Mission

Capture the unwritten rules of each tracker (seed-time requirements by size, hit-and-run policies, trump rules, group blacklists, freeleech detection) in a structured YAML schema. The Command Center loads the corpus at boot and on hot-reload, caches it in SQLite for query, and uses it to produce operator warnings before actions ("this torrent is a P2P release and Tracker X auto-removes non-internal duplicates within 24h of an internal release; consider waiting").

After Phase 11, several earlier phases get smarter: HR risk prediction uses precise per-size requirements, recommendations reference tracker-specific policies, the dashboard's per-tracker view surfaces the operator's accumulated knowledge.

## Deliverables Checklist

Phase 11 is complete when every item below is true:

- [ ] SQLite migration `011_phase11_tracker_rules.sql` adds the `tracker_rules` table per Appendix A.
- [ ] Corpus loader (`internal/corpus`):
    - Watches `config/trackers/` directory; each `.yaml` file is one tracker.
    - Validates against the Appendix E schema with detailed error reporting.
    - On valid load, upserts entries into `tracker_rules` table (keyed by `tracker_id + rule_key`), then publishes a `corpus.reloaded` event on the bus.
    - On validation failure, retains previous corpus and logs the structured error.
- [ ] Corpus query API (`internal/corpus/query.go`):
    - `Get(trackerID, ruleKey) (Rule, error)` — fast in-memory lookup.
    - `GetAll(trackerID) (CorpusEntry, error)` — full per-tracker corpus.
    - `SeedTimeRequirement(trackerID, sizeBytes) (time.Duration, error)` — applies the `seed_time_requirements.by_size` ladder.
    - All reads are served from an in-memory cache, refreshed on `corpus.reloaded`. The `tracker_rules` SQL table is the durable copy for cold-start consistency.
- [ ] Warning system (`internal/corpus/warnings`):
    - Before any destructive action via the API (delete torrent, etc.), the action handler calls `warnings.Check(action)` which consults the corpus and returns a structured list of warnings to surface to the operator.
    - Warnings include the rule that fired, the tracker, and a one-line operator-facing explanation.
    - The API does not refuse on warning; the UI requires confirmation when warnings are present.
- [ ] API endpoints (auth required):
    - `GET /api/trackers/:id/rules` — full corpus for one tracker.
    - `POST /api/trackers/:id/check-action` — given a proposed action, return warnings without performing it.
- [ ] Phase 1's `torrent_trackers.seed_time_required_seconds` is populated from the corpus where known (size-aware), falling back to the per-tracker default.
- [ ] Phase 7's `hr_risk` predictor uses corpus values when available; document how it handles ambiguity (e.g., corpus says "120 hours default" but the tracker reported a different requirement once observed).
- [ ] Frontend:
    - `/trackers/:id` (existing from Phase 1) gains a "Rules" tab showing the operator's recorded corpus for the tracker, formatted from the YAML.
    - Destructive actions (delete torrent, change filter that would over-grab) show a warnings modal that lists corpus-derived concerns and requires explicit confirmation.
    - A "Community Corpus" link in Settings explains how to contribute corpus entries back upstream (community contribution doc deferred to Phase 15).
- [ ] Tests: schema validation rejects malformed YAML with helpful errors; warning checker fires on the correct conditions across a synthetic action set; hot-reload preserves the previous corpus on validation failure.
- [ ] `config/trackers.example.yaml` ships a representative example matching Appendix E.
- [ ] `PROGRESS.md` and `DECISIONS.md` updated. `DECISIONS.md` records: the schema versioning strategy (Phase 11 is v1; how future fields are added without breaking existing files), how the warning system interacts with operator override (a "skip warnings this once" mode? Default: no).

## Phase 11 Database Scope

Migration `011_phase11_tracker_rules.sql` creates:
- `tracker_rules`

## Repository Layout

```
internal/
  corpus/
    schema.go                # Appendix E typed schema
    loader.go                # YAML → typed → SQLite + in-memory cache
    query.go                 # operator-facing query API
    warnings/
      warnings.go            # ActionWarning type, Check(action) entry point
      rules/                 # one file per warning rule
        hr_risk.go
        trump_rules.go
        group_blacklist.go
        seed_time.go
        ...
      *_test.go
    *_test.go
config/
  trackers/
    example.yaml             # Appendix E sample, shipped
```

Files modified in existing packages:
- `internal/integrations/trackers/<chosen>.go` — consults corpus for seed-time defaults.
- `internal/intelligence/hr_risk.go` — consults corpus for precise per-size requirements.
- `internal/server/routes_trackers.go` — adds `/rules` and `/check-action` handlers.
- `internal/server/routes_torrents.go` — destructive routes now call `warnings.Check` and return warnings in the response body for client confirmation.

Frontend additions:
- `web/src/pages/TrackerDetail.tsx` — Rules tab.
- `web/src/components/WarningsModal.tsx`
- `web/src/components/CorpusViewer.tsx`

## Working Rules

**Corpus is operator-owned.** The system ships an empty corpus (only the example). Operators populate their own. Community contribution is a Phase 15 polish task.

**Schema is versioned.** Each YAML file carries a top-level `schema_version: 1`. Phase 11 supports v1 only; v2 happens when fields evolve. The loader rejects unknown major versions; minor additions are non-breaking.

**Warnings are advisory.** They surface to the operator; they don't block actions by default. Operators may opt in to "block on warning" mode per warning type.

**Don't ship a community corpus in this phase.** Operators may share entries informally; building a community contribution system is Phase 15. Phase 11's job is the schema and the loading machinery.

**Corpus precedence over observation.** When the corpus declares a rule (e.g., "120h seed time default") and observation suggests different (e.g., one torrent reported as requiring 96h), trust the corpus and log the observation as a `corpus_observation_mismatch` event for the operator's attention. The corpus is the operator's stated truth; observations are inputs to refine it.

## What "Phase 11 Complete" Looks Like

After Phase 11 ships, the operator can:

1. Create `config/trackers/mytracker.yaml` with the Appendix E structure populated for one of their trackers.
2. Open the tracker's detail page; see the corpus surfaced under the Rules tab.
3. Try to delete a torrent that hasn't met its tracker's seed-time requirement; see a warnings modal: "Tracker X requires 96 hours minimum seed time for torrents under 5 GB; current seed time is 47 hours. Deletion now would create a hit-and-run."
4. Decide to wait. The torrent stays.
5. Tomorrow, a P2P release of an internal-eligible release is in the operator's autobrr feed. The Phase 7 recommendation engine, consulting the corpus's `trump_rules`, surfaces "Tracker X removes P2P duplicates within 48h of internal release; consider holding the grab."
6. Edit `config/trackers/mytracker.yaml` to update a rule. Save. The change is reflected in the dashboard's rules tab without restart.

## Begin

Read Appendix E carefully — the schema is rich. Implement the typed schema and validator first; then the loader; then the warning system. Wire the warning checks into the existing destructive routes from Phase 3. UI last. Stop at the end of Phase 11.
