Replaces the UtilityBelt over-retail float with the user's actual in-game OD:
per-weapon-type MaxDamage/elemVsMon thresholds from Loot.utl. Bows/thrown
deferred (null) pending a computed-stat calibration. (L) Dagger MS bucket
folded into (L) Dagger (indistinguishable by captured fields).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
nginx's X-Forwarded-For is $proxy_add_x_forwarded_for, which only appends
to whatever the client sends — a forged leftmost hop passed straight
through, letting an attacker rotate spoofed values to dodge the 5s login
cooldown. X-Real-IP is set by nginx to $remote_addr on every proxied
location and can't be forged by the client, so key on that instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Go cutover omitted get_character_inventory; the React InventoryWindow
fetches GET /inventory/{name} and got 404 -> empty. Port the endpoint:
per-character items with placement (current_wielded_location/container_id/
items_capacity), mana (current_mana/max_mana from original_json IntValues),
icon overlays, and join-table combat/req/enh/rating stats; material-prefixed
name. Returns {character_name,item_count,items}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per-search filter selecting which crit-damage tiers are allowed on armor.
Default (all allowed) is byte-identical to current behavior; "prefer highest
allowed tier" falls out of existing scoring. Go-only (live solver); Python
copy left frozen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README: Go-backend architecture, build/run via the compose override stack,
WS/payload/auth/DB contracts, the branch layout (master = Go, python-legacy).
- CLAUDE.md: Project Overview + Components reflect the Go services; a "Go services
— build, deploy, gotchas" section (string coercion, typeless telemetry, the
trinket dedup, rollback); Deploying + Suitbuilder point at the Go paths. The
behavioral contracts (WS/auth/DB/routes) are kept — Go honors them; file refs to
main.py/inventory-service mark the legacy source.
- .gitignore: ignore .env / .env.bak-* (public repo; .env.example stays tracked).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes the Go backend so it can fully replace Python in production:
tracker-go website layer (serves the unchanged frontend):
- static file serving + SPA fallback + /icons (website.go)
- login/logout with itsdangerous cookie ISSUING (bcrypt, Python-interop) and the
/me handler (auth.go issueSessionCookie + website.go)
- admin user CRUD (website_admin.go) and the issue-board write side (website_issues.go)
- request-scoped user context + requireAdmin (auth.go)
cutover ingest (gated off during the parallel run, required for a clean cutover):
- inventory forwarding: full_inventory -> /process-inventory, inventory_delta ->
item POST/DELETE, per-character serialized, fire-and-forget (inventory_forward.go)
- death/idle Discord alerts via DISCORD_ACLOG_WEBHOOK (aclog.go)
- SKIP_SCHEMA_INIT so write mode against the prod DBs runs no DDL (tracker-go + inventory-go)
two bugs found live and fixed:
- coerceNum: the plugin sends kills_per_hour/deaths/total_deaths/prismatic_taper_count
as STRINGS; pydantic coerced them, Go's number helpers wrote null/0 (reads.go/ingest.go)
- telemetry is broadcast TYPELESS so the browser ignores it and uses the /live poll;
broadcasting it typed flapped the per-player counters 0<->value (ingest.go stripType)
docker-compose.cutover.yml: reversible override flipping the Go services to write
mode against the production DBs and repointing the Discord bot at the Go /ws/live.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The /go/ read stack is now fully Go end-to-end: browser -> nginx /go/ -> Go
tracker (dereth-tracker-go) -> Go inventory (inventory-go) -> read-only prod
DBs. Previously the Go tracker proxied inventory calls to the Python service;
inventory-go is validated byte-identical (search, sets, suitbuilder) so the
whole parallel stack is now Go. Production is untouched (additive override).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>