Files

69 lines
4.0 KiB
SQL
Raw Permalink Normal View History

-- Migration: 0014_stuck_objective
-- Date: 2026-06-16
-- Purpose: Persistent, fleet-aggregated STUCK-OBJECTIVE LEDGER (#7 follow-up).
-- The WedgeWatchdog self-remediation layer abandons a bot's current
-- objective when it has been wedged (GoalUnreachable / CombatLoop) past
-- RemediationMs. That abandon is a 5-minute in-memory blacklist (the
-- bot RETRIES automatically once it expires) and, until now, the only
-- record of WHICH content stranded bots was the ephemeral
-- [wedge_remediate] log line (Playerbot.log is truncated every boot).
--
-- This table turns the fleet into a self-documenting content-QA system:
-- every remediation upserts a row keyed by (quest_id, obj_id), so an
-- operator can later run e.g.
-- SELECT quest_id, obj_id, category, hit_count, sample_map,
-- sample_zone, sample_x, sample_y, sample_bot, last_seen
-- FROM playerbot_v2_stuck_objective ORDER BY hit_count DESC LIMIT 50;
-- to find the quests/objectives that strand the most bots and root-cause
-- them (navmesh gap, off-mesh bridge, bad POI data, friendly-only kill
-- target, permanent blacklist, ...). It is the durable, queryable
-- successor to the manual log-forensics + character_queststatus queries
-- used in the 2026-06-15 cross-region investigation (4494 / 876 / 55660).
--
-- Columns:
-- quest_id / obj_id The stranded objective (obj_id 0 = quest-level /
-- no specific sub-objective). Composite PK so each
-- distinct objective is one accumulating row.
-- category Last WedgeCategory that remediated it
-- (GoalUnreachable / CombatLoop).
-- hit_count Cumulative remediation events across the whole
-- fleet AND across restarts (the writer flushes a
-- per-interval delta via hit_count = hit_count +
-- VALUES(hit_count)). A high count = chronically
-- stuck content worth investigating.
-- first_seen When this objective first stranded a bot (set on
-- insert, never overwritten).
-- last_seen Most recent remediation (updated every flush). A
-- stale last_seen ~ the issue resolved itself.
-- sample_* A representative stuck location + bot for the
-- objective, so an investigator can fly there /
-- reproduce without grepping logs.
--
-- Reverts: yes (DROP TABLE).
--
-- Retention: the writer does NOT prune — rows are small, bounded by the number
-- of DISTINCT stuck objectives (hundreds–low thousands), and the long
-- history is the point. Operators may DELETE on last_seen if desired.
CREATE TABLE IF NOT EXISTS playerbot_v2_stuck_objective (
quest_id INT UNSIGNED NOT NULL,
obj_id INT UNSIGNED NOT NULL DEFAULT 0,
category VARCHAR(24) NOT NULL DEFAULT '',
hit_count BIGINT UNSIGNED NOT NULL DEFAULT 0,
first_seen DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_seen DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
sample_map INT UNSIGNED NOT NULL DEFAULT 0,
sample_zone INT UNSIGNED NOT NULL DEFAULT 0,
sample_x FLOAT NOT NULL DEFAULT 0,
sample_y FLOAT NOT NULL DEFAULT 0,
sample_bot VARCHAR(48) NOT NULL DEFAULT '',
PRIMARY KEY (quest_id, obj_id),
KEY idx_hit_count (hit_count),
KEY idx_last_seen (last_seen)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- Record this migration as applied (mirrors the 0011/0012/0013 pattern).
INSERT INTO playerbot_v2_schema_version (version, sha256) VALUES
(14, REPEAT('0', 64))
ON DUPLICATE KEY UPDATE applied_at = CURRENT_TIMESTAMP;