/**
 * Validation logic for SF preferences.
 *
 * Pure validation -- no filesystem access, no loading, no merging.
 * Accepts a raw SFPreferences object and returns a sanitized copy
 * together with any errors and warnings.
 */
import { normalizeStringArray } from "@singularity-forge/coding-agent";
import { VALID_BRANCH_NAME } from "./git-constants.js";
import {
	CURRENT_PREFERENCES_SCHEMA_VERSION,
	checkPreferencesDrift,
	migrateForward,
} from "./preferences-migrations.js";
import {
	KNOWN_PREFERENCE_KEYS,
	KNOWN_UNIT_TYPES,
	SKILL_ACTIONS,
} from "./preferences-types.js";
import { VALID_SEARCH_PROVIDER_PREFS } from "./setup-catalog.js";

const VALID_TOKEN_PROFILES = new Set([
	"budget",
	"balanced",
	"quality",
	"burn-max",
]);
const VALID_UOK_TURN_ACTIONS = new Set(["commit", "snapshot", "status-only"]);
export function validatePreferences(preferences) {
	const errors = [];
	const warnings = [];
	const validated = {};
	// Schema version: report drift, then migrate forward. Errors from a
	// malformed migration chain bubble up so the caller can surface "your
	// prefs need attention" instead of silently dropping fields. Field
	// checks below run against the migrated copy.
	for (const w of checkPreferencesDrift(preferences).warnings) warnings.push(w);
	let migrated = preferences;
	try {
		const outcome = migrateForward(preferences);
		migrated = outcome.preferences;
		if (outcome.applied.length > 0) {
			warnings.push(
				`migrated prefs forward: ${outcome.applied
					.map((m) => `v${m.from}→v${m.to} (${m.description})`)
					.join("; ")}`,
			);
		}
	} catch (err) {
		errors.push(
			err instanceof Error
				? `prefs migration failed: ${err.message}`
				: `prefs migration failed: ${String(err)}`,
		);
	}
	preferences = migrated;
	// ─── Unknown Key Detection ──────────────────────────────────────────
	// Common key migration hints for pi-level settings that don't map to SF prefs
	const KEY_MIGRATION_HINTS = {
		taskIsolation:
			'use "git.isolation" instead (values: worktree, branch, none)',
		task_isolation:
			'use "git.isolation" instead (values: worktree, branch, none)',
		isolation: 'use "git.isolation" instead (values: worktree, branch, none)',
		manage_gitignore: 'use "git.manage_gitignore" instead',
		auto_push: 'use "git.auto_push" instead',
		main_branch: 'use "git.main_branch" instead',
	};
	for (const key of Object.keys(preferences)) {
		if (!KNOWN_PREFERENCE_KEYS.has(key)) {
			const hint = KEY_MIGRATION_HINTS[key];
			if (hint) {
				warnings.push(`unknown preference key "${key}" — ${hint}`);
			} else {
				warnings.push(`unknown preference key "${key}" — ignored`);
			}
		}
	}
	if (preferences.version !== undefined) {
		if (preferences.version === CURRENT_PREFERENCES_SCHEMA_VERSION) {
			validated.version = CURRENT_PREFERENCES_SCHEMA_VERSION;
		} else if (preferences.version > CURRENT_PREFERENCES_SCHEMA_VERSION) {
			// Already warned via checkPreferencesDrift; preserve so a later
			// sf upgrade reads correctly without rewriting the file.
			validated.version = preferences.version;
		} else {
			// Should be unreachable: migrateForward stamps the current version
			// or throws. Defend against a future bug instead of silently dropping.
			errors.push(
				`unsupported version ${preferences.version} (migration chain ` +
					`should have produced v${CURRENT_PREFERENCES_SCHEMA_VERSION})`,
			);
		}
	}
	// ─── Workflow Mode ──────────────────────────────────────────────────
	if (preferences.mode !== undefined) {
		const validModes = new Set(["solo", "team"]);
		if (
			typeof preferences.mode === "string" &&
			validModes.has(preferences.mode)
		) {
			validated.mode = preferences.mode;
		} else {
			errors.push(
				`invalid mode "${preferences.mode}" — must be one of: solo, team`,
			);
		}
	}
	const validDiscoveryModes = new Set(["auto", "suggest", "off"]);
	if (preferences.skill_discovery) {
		if (validDiscoveryModes.has(preferences.skill_discovery)) {
			validated.skill_discovery = preferences.skill_discovery;
		} else {
			errors.push(
				`invalid skill_discovery value: ${preferences.skill_discovery}`,
			);
		}
	}
	if (preferences.skill_staleness_days !== undefined) {
		const days = Number(preferences.skill_staleness_days);
		if (Number.isFinite(days) && days >= 0) {
			validated.skill_staleness_days = Math.floor(days);
		} else {
			errors.push(
				`invalid skill_staleness_days: must be a non-negative number`,
			);
		}
	}
	validated.always_use_skills = normalizeStringArray(
		preferences.always_use_skills,
	);
	validated.prefer_skills = normalizeStringArray(preferences.prefer_skills);
	validated.avoid_skills = normalizeStringArray(preferences.avoid_skills);
	validated.custom_instructions = normalizeStringArray(
		preferences.custom_instructions,
	);
	if (preferences.skill_rules) {
		const validRules = [];
		for (const rule of preferences.skill_rules) {
			if (!rule || typeof rule !== "object") {
				errors.push("invalid skill_rules entry");
				continue;
			}
			const when = typeof rule.when === "string" ? rule.when.trim() : "";
			if (!when) {
				errors.push("skill_rules entry missing when");
				continue;
			}
			const validatedRule = { when };
			for (const action of SKILL_ACTIONS) {
				const values = normalizeStringArray(rule[action]);
				if (values.length > 0) {
					validatedRule[action] = values;
				}
			}
			if (!validatedRule.use && !validatedRule.prefer && !validatedRule.avoid) {
				errors.push(`skill rule has no actions: ${when}`);
				continue;
			}
			validRules.push(validatedRule);
		}
		if (validRules.length > 0) {
			validated.skill_rules = validRules;
		}
	}
	for (const key of [
		"always_use_skills",
		"prefer_skills",
		"avoid_skills",
		"custom_instructions",
	]) {
		if (validated[key] && validated[key].length === 0) {
			delete validated[key];
		}
	}
	if (preferences.uat_dispatch !== undefined) {
		validated.uat_dispatch = !!preferences.uat_dispatch;
	}
	if (preferences.unique_milestone_ids !== undefined) {
		validated.unique_milestone_ids = !!preferences.unique_milestone_ids;
	}
	if (preferences.persist_model_changes !== undefined) {
		if (typeof preferences.persist_model_changes === "boolean") {
			validated.persist_model_changes = preferences.persist_model_changes;
		} else {
			errors.push("persist_model_changes must be a boolean");
		}
	}
	if (preferences.budget_ceiling !== undefined) {
		const raw = preferences.budget_ceiling;
		if (typeof raw === "number" && Number.isFinite(raw)) {
			validated.budget_ceiling = raw;
		} else if (typeof raw === "string" && Number.isFinite(Number(raw))) {
			validated.budget_ceiling = Number(raw);
		} else {
			errors.push("budget_ceiling must be a finite number");
		}
	}
	// ─── Budget Enforcement ──────────────────────────────────────────────
	if (preferences.budget_enforcement !== undefined) {
		const validModes = new Set(["warn", "pause", "halt"]);
		if (
			typeof preferences.budget_enforcement === "string" &&
			validModes.has(preferences.budget_enforcement)
		) {
			validated.budget_enforcement = preferences.budget_enforcement;
		} else {
			errors.push(`budget_enforcement must be one of: warn, pause, halt`);
		}
	}
	// ─── UOK Flags ──────────────────────────────────────────────────────
	if (preferences.uok !== undefined) {
		if (typeof preferences.uok === "object" && preferences.uok !== null) {
			const raw = preferences.uok;
			const valid = {};
			if (raw.enabled !== undefined) {
				if (typeof raw.enabled === "boolean") valid.enabled = raw.enabled;
				else errors.push("uok.enabled must be a boolean");
			}
			const parseEnabledBlock = (key, targetKey) => {
				const normalizedTargetKey =
					targetKey ?? (key === "plan_v2" ? "planning_flow" : key);
				const value = raw[key];
				if (value === undefined) return;
				if (typeof value !== "object" || value === null) {
					errors.push(`uok.${key} must be an object`);
					return;
				}
				const block = value;
				const parsed = {};
				if (block.enabled !== undefined) {
					if (typeof block.enabled === "boolean")
						parsed.enabled = block.enabled;
					else errors.push(`uok.${key}.enabled must be a boolean`);
				}
				const unknown = Object.keys(block).filter((k) => k !== "enabled");
				for (const unk of unknown) {
					warnings.push(`unknown uok.${key} key "${unk}" — ignored`);
				}
				if (Object.keys(parsed).length > 0) {
					valid[normalizedTargetKey] = parsed;
				}
			};
			parseEnabledBlock("gates");
			parseEnabledBlock("model_policy");
			parseEnabledBlock("execution_graph");
			parseEnabledBlock("audit_envelope");
			if (raw.audit_unified !== undefined && raw.audit_envelope === undefined) {
				warnings.push(
					"uok.audit_unified is deprecated; use uok.audit_envelope",
				);
				parseEnabledBlock("audit_unified", "audit_envelope");
			}
			parseEnabledBlock("planning_flow");
			if (raw.plan_v2 !== undefined && raw.planning_flow === undefined) {
				warnings.push("uok.plan_v2 is deprecated; use uok.planning_flow");
				parseEnabledBlock("plan_v2", "planning_flow");
			}
			if (raw.gitops !== undefined) {
				if (typeof raw.gitops !== "object" || raw.gitops === null) {
					errors.push("uok.gitops must be an object");
				} else {
					const gitops = raw.gitops;
					const parsed = {};
					if (gitops.enabled !== undefined) {
						if (typeof gitops.enabled === "boolean")
							parsed.enabled = gitops.enabled;
						else errors.push("uok.gitops.enabled must be a boolean");
					}
					if (gitops.turn_action !== undefined) {
						if (
							typeof gitops.turn_action === "string" &&
							VALID_UOK_TURN_ACTIONS.has(gitops.turn_action)
						) {
							parsed.turn_action = gitops.turn_action;
						} else {
							errors.push(
								"uok.gitops.turn_action must be one of: commit, snapshot, status-only",
							);
						}
					}
					if (gitops.turn_push !== undefined) {
						if (typeof gitops.turn_push === "boolean")
							parsed.turn_push = gitops.turn_push;
						else errors.push("uok.gitops.turn_push must be a boolean");
					}
					const unknown = Object.keys(gitops).filter(
						(k) => !["enabled", "turn_action", "turn_push"].includes(k),
					);
					for (const unk of unknown) {
						warnings.push(`unknown uok.gitops key "${unk}" — ignored`);
					}
					if (Object.keys(parsed).length > 0) {
						valid.gitops = parsed;
					}
				}
			}
			const knownUokKeys = new Set([
				"enabled",
				"gates",
				"model_policy",
				"execution_graph",
				"gitops",
				"audit_envelope",
				"audit_unified",
				"planning_flow",
				"plan_v2",
			]);
			for (const key of Object.keys(raw)) {
				if (!knownUokKeys.has(key)) {
					warnings.push(`unknown uok key "${key}" — ignored`);
				}
			}
			if (Object.keys(valid).length > 0) {
				validated.uok = valid;
			}
		} else {
			errors.push("uok must be an object");
		}
	}
	// ─── Token Profile ─────────────────────────────────────────────────
	if (preferences.token_profile !== undefined) {
		if (
			typeof preferences.token_profile === "string" &&
			VALID_TOKEN_PROFILES.has(preferences.token_profile)
		) {
			validated.token_profile = preferences.token_profile;
		} else {
			errors.push(
				`token_profile must be one of: budget, balanced, quality, burn-max`,
			);
		}
	}
	// ─── Service Tier ───────────────────────────────────────────────────
	// OpenAI service tier for gpt-5.4 models. "off" explicitly disables the
	// whole feature (hooks, footer, command refuse enable). Undefined = not
	// configured. Historical gap: this field wasn't wired through validation
	// so even "priority" / "flex" were being silently dropped.
	if (preferences.service_tier !== undefined) {
		const validTiers = new Set(["priority", "flex", "off"]);
		if (
			typeof preferences.service_tier === "string" &&
			validTiers.has(preferences.service_tier)
		) {
			validated.service_tier = preferences.service_tier;
		} else {
			errors.push(`service_tier must be one of: priority, flex, off`);
		}
	}
	// ─── forensics_dedup ────────────────────────────────────────────────
	if (preferences.forensics_dedup !== undefined) {
		validated.forensics_dedup = !!preferences.forensics_dedup;
	}
	// ─── stale_commit_threshold_minutes ─────────────────────────────────
	if (preferences.stale_commit_threshold_minutes !== undefined) {
		const raw = Number(preferences.stale_commit_threshold_minutes);
		if (Number.isFinite(raw) && raw >= 0) {
			validated.stale_commit_threshold_minutes = Math.floor(raw);
		} else {
			errors.push(
				"stale_commit_threshold_minutes must be a non-negative number (minutes; 0 = disabled)",
			);
		}
	}
	// ─── widget_mode ────────────────────────────────────────────────────
	if (preferences.widget_mode !== undefined) {
		const valid = new Set(["full", "small", "min", "off"]);
		if (
			typeof preferences.widget_mode === "string" &&
			valid.has(preferences.widget_mode)
		) {
			validated.widget_mode = preferences.widget_mode;
		} else {
			errors.push("widget_mode must be one of: full, small, min, off");
		}
	}
	// ─── slice_parallel ─────────────────────────────────────────────────
	// Shallow validation: object-shape check + primitive field coercion.
	// Deeper structural checks can come later; the goal here is to stop
	// silently dropping the preference.
	if (preferences.slice_parallel !== undefined) {
		const sp = preferences.slice_parallel;
		if (typeof sp === "object" && sp !== null && !Array.isArray(sp)) {
			const v = {};
			const anySp = sp;
			if (anySp.enabled !== undefined) v.enabled = !!anySp.enabled;
			if (anySp.max_workers !== undefined) {
				const n = Number(anySp.max_workers);
				if (Number.isFinite(n) && n >= 1) {
					v.max_workers = Math.floor(n);
				} else {
					errors.push("slice_parallel.max_workers must be a positive integer");
				}
			}
			validated.slice_parallel = v;
		} else {
			errors.push("slice_parallel must be an object");
		}
	}
	// ─── modelOverrides ─────────────────────────────────────────────────
	// Per-model capability overrides. Deep-merged into built-in profiles at
	// consumer sites — here we just confirm the shape and pass through.
	if (preferences.modelOverrides !== undefined) {
		const mo = preferences.modelOverrides;
		if (typeof mo === "object" && mo !== null && !Array.isArray(mo)) {
			validated.modelOverrides = mo;
		} else {
			errors.push("modelOverrides must be an object keyed by model ID");
		}
	}
	// ─── safety_harness ─────────────────────────────────────────────────
	// Rich nested config. Pass-through with an object-shape guard; field-level
	// validation can land alongside the features that consume them.
	if (preferences.safety_harness !== undefined) {
		const sh = preferences.safety_harness;
		if (typeof sh === "object" && sh !== null && !Array.isArray(sh)) {
			validated.safety_harness = sh;
		} else {
			errors.push("safety_harness must be an object");
		}
	}
	// ─── Search Provider ─────────────────────────────────────────────
	if (preferences.search_provider !== undefined) {
		if (
			typeof preferences.search_provider === "string" &&
			VALID_SEARCH_PROVIDER_PREFS.has(preferences.search_provider)
		) {
			validated.search_provider = preferences.search_provider;
		} else {
			errors.push(
				`search_provider must be one of: ${[...VALID_SEARCH_PROVIDER_PREFS].join(", ")}`,
			);
		}
	}
	// ─── Provider Preference (benchmark tie-break order) ────────────────
	if (preferences.provider_preference !== undefined) {
		if (
			Array.isArray(preferences.provider_preference) &&
			preferences.provider_preference.every((s) => typeof s === "string")
		) {
			const cleaned = preferences.provider_preference
				.map((s) => s.trim().toLowerCase())
				.filter((s) => s.length > 0);
			if (cleaned.length > 0) validated.provider_preference = cleaned;
		} else {
			errors.push(
				"provider_preference must be an array of provider-ID strings",
			);
		}
	}
	// ─── Allowed Providers (hard allowlist) ─────────────────────────────
	// When set, model selection is gated to these providers only — any
	// model from any other provider is filtered out of the candidate set
	// before models.* resolution and dynamic routing. Case-insensitive.
	if (preferences.allowed_providers !== undefined) {
		if (Array.isArray(preferences.allowed_providers)) {
			const allStrings = preferences.allowed_providers.every(
				(s) => typeof s === "string",
			);
			if (allStrings) {
				const cleaned = preferences.allowed_providers
					.map((s) => s.trim().toLowerCase())
					.filter((s) => s.length > 0);
				if (cleaned.length > 0) validated.allowed_providers = cleaned;
			} else {
				errors.push(
					"allowed_providers must be an array of strings (provider IDs)",
				);
			}
		} else {
			errors.push("allowed_providers must be an array of strings");
		}
	}
	// ─── Blocked Providers (hard denylist) ──────────────────────────────
	// Applied after allowed_providers; deny wins when both are configured.
	if (preferences.blocked_providers !== undefined) {
		if (Array.isArray(preferences.blocked_providers)) {
			const allStrings = preferences.blocked_providers.every(
				(s) => typeof s === "string",
			);
			if (allStrings) {
				const cleaned = preferences.blocked_providers
					.map((s) => s.trim().toLowerCase())
					.filter((s) => s.length > 0);
				if (cleaned.length > 0)
					validated.blocked_providers = Array.from(new Set(cleaned));
			} else {
				errors.push(
					"blocked_providers must be an array of strings (provider IDs)",
				);
			}
		} else {
			errors.push("blocked_providers must be an array of strings");
		}
	}
	// ─── Per-provider model allow-list ──────────────────────────────────
	// When a provider has an entry here, only listed model IDs are usable
	// from that provider. Providers absent from the block are unrestricted.
	if (preferences.provider_model_allow !== undefined) {
		if (
			preferences.provider_model_allow !== null &&
			typeof preferences.provider_model_allow === "object" &&
			!Array.isArray(preferences.provider_model_allow)
		) {
			const cleaned = {};
			for (const [provider, models] of Object.entries(
				preferences.provider_model_allow,
			)) {
				const providerId = provider.trim().toLowerCase();
				if (!providerId) {
					errors.push(
						"provider_model_allow provider IDs must be non-empty strings",
					);
					continue;
				}
				if (
					!Array.isArray(models) ||
					models.some((m) => typeof m !== "string")
				) {
					errors.push(
						`provider_model_allow.${provider} must be an array of model ID strings`,
					);
					continue;
				}
				const list = models.map((s) => s.trim()).filter((s) => s.length > 0);
				cleaned[providerId] = Array.from(new Set(list));
			}
			if (Object.keys(cleaned).length > 0)
				validated.provider_model_allow = cleaned;
		} else {
			errors.push(
				"provider_model_allow must be a map of provider → array of model IDs",
			);
		}
	}
	// ─── Per-provider model block-list ──────────────────────────────────
	// Deny wins after provider_model_allow; matching models are never used.
	if (preferences.provider_model_block !== undefined) {
		if (
			preferences.provider_model_block !== null &&
			typeof preferences.provider_model_block === "object" &&
			!Array.isArray(preferences.provider_model_block)
		) {
			const cleaned = {};
			for (const [provider, models] of Object.entries(
				preferences.provider_model_block,
			)) {
				const providerId = provider.trim().toLowerCase();
				if (!providerId) {
					errors.push(
						"provider_model_block provider IDs must be non-empty strings",
					);
					continue;
				}
				if (
					!Array.isArray(models) ||
					models.some((m) => typeof m !== "string")
				) {
					errors.push(
						`provider_model_block.${provider} must be an array of model ID strings`,
					);
					continue;
				}
				const list = models.map((s) => s.trim()).filter((s) => s.length > 0);
				cleaned[providerId] = Array.from(new Set(list));
			}
			if (Object.keys(cleaned).length > 0)
				validated.provider_model_block = cleaned;
		} else {
			errors.push(
				"provider_model_block must be a map of provider → array of model IDs",
			);
		}
	}
	// ─── Flat-rate Providers ────────────────────────────────────────────
	// User-declared flat-rate providers for dynamic routing suppression.
	// Built-in providers (github-copilot, copilot, claude-code) and any
	// externalCli provider are already auto-detected; this list layers on
	// top for private subscription proxies and custom CLI wrappers.
	if (preferences.flat_rate_providers !== undefined) {
		if (Array.isArray(preferences.flat_rate_providers)) {
			const allStrings = preferences.flat_rate_providers.every(
				(item) => typeof item === "string",
			);
			if (allStrings) {
				// Strip empty/whitespace-only entries to avoid false matches.
				validated.flat_rate_providers = preferences.flat_rate_providers
					.map((s) => s.trim())
					.filter((s) => s.length > 0);
			} else {
				errors.push("flat_rate_providers must be an array of strings");
			}
		} else {
			errors.push("flat_rate_providers must be an array of strings");
		}
	}
	// ─── Shell Wrapper ───────────────────────────────────────────────────
	if (preferences.shell_wrapper !== undefined) {
		if (
			Array.isArray(preferences.shell_wrapper) &&
			preferences.shell_wrapper.every(
				(s) => typeof s === "string" && s.length > 0,
			)
		) {
			validated.shell_wrapper = preferences.shell_wrapper;
		} else {
			errors.push("shell_wrapper must be an array of non-empty strings");
		}
	}
	// ─── Minimum Request Interval ───────────────────────────────────────
	if (preferences.min_request_interval_ms !== undefined) {
		const raw = Number(preferences.min_request_interval_ms);
		if (Number.isFinite(raw) && raw >= 0) {
			validated.min_request_interval_ms = Math.floor(raw);
		} else {
			errors.push(
				"min_request_interval_ms must be a non-negative number (milliseconds; 0 = disabled)",
			);
		}
	}
	// ─── Workspace Lifecycle Hooks ───────────────────────────────────────
	if (preferences.workspace !== undefined) {
		if (
			typeof preferences.workspace === "object" &&
			preferences.workspace !== null
		) {
			const ws = preferences.workspace;
			const validatedWs = {};
			for (const key of ["after_create", "before_run", "after_run"]) {
				if (ws[key] !== undefined) {
					if (typeof ws[key] === "string") {
						validatedWs[key] = ws[key];
					} else {
						errors.push(`workspace.${key} must be a string`);
					}
				}
			}
			validated.workspace = validatedWs;
		} else {
			errors.push("workspace must be an object");
		}
	}
	// ─── Phase Skip Preferences ─────────────────────────────────────────
	if (preferences.phases !== undefined) {
		if (typeof preferences.phases === "object" && preferences.phases !== null) {
			const validatedPhases = {};
			const p = preferences.phases;
			if (p.skip_research !== undefined)
				validatedPhases.skip_research = !!p.skip_research;
			if (p.skip_reassess !== undefined)
				validatedPhases.skip_reassess = !!p.skip_reassess;
			if (p.skip_slice_research !== undefined)
				validatedPhases.skip_slice_research = !!p.skip_slice_research;
			if (p.skip_milestone_validation !== undefined)
				validatedPhases.skip_milestone_validation =
					!!p.skip_milestone_validation;
			if (p.reassess_after_slice !== undefined)
				validatedPhases.reassess_after_slice = !!p.reassess_after_slice;
			if (p.require_slice_discussion !== undefined)
				validatedPhases.require_slice_discussion = !!p.require_slice_discussion;
			if (p.mid_execution_escalation !== undefined)
				validatedPhases.mid_execution_escalation = !!p.mid_execution_escalation;
			if (p.progressive_planning !== undefined)
				validatedPhases.progressive_planning = !!p.progressive_planning;
			if (p.escalation_auto_accept !== undefined)
				validatedPhases.escalation_auto_accept = !!p.escalation_auto_accept;
			// Warn on unknown phase keys
			const knownPhaseKeys = new Set([
				"skip_research",
				"skip_reassess",
				"skip_slice_research",
				"skip_milestone_validation",
				"reassess_after_slice",
				"require_slice_discussion",
				"mid_execution_escalation",
				"progressive_planning",
				"escalation_auto_accept",
			]);
			for (const key of Object.keys(p)) {
				if (!knownPhaseKeys.has(key)) {
					warnings.push(`unknown phases key "${key}" — ignored`);
				}
			}
			validated.phases = validatedPhases;
		} else {
			errors.push(`phases must be an object`);
		}
	}
	// ─── Context Pause Threshold ────────────────────────────────────────
	if (preferences.context_pause_threshold !== undefined) {
		const raw = preferences.context_pause_threshold;
		if (typeof raw === "number" && Number.isFinite(raw)) {
			validated.context_pause_threshold = raw;
		} else if (typeof raw === "string" && Number.isFinite(Number(raw))) {
			validated.context_pause_threshold = Number(raw);
		} else {
			errors.push("context_pause_threshold must be a finite number");
		}
	}
	// ─── Models ─────────────────────────────────────────────────────────
	if (preferences.models !== undefined) {
		if (preferences.models && typeof preferences.models === "object") {
			validated.models = preferences.models;
		} else {
			errors.push("models must be an object");
		}
	}
	// ─── Auto Supervisor ────────────────────────────────────────────────
	if (preferences.auto_supervisor !== undefined) {
		if (
			preferences.auto_supervisor &&
			typeof preferences.auto_supervisor === "object"
		) {
			const as = preferences.auto_supervisor;
			const validatedAs = {};
			if (as.model !== undefined) {
				if (typeof as.model === "string") validatedAs.model = as.model;
				else errors.push("auto_supervisor.model must be a string");
			}
			if (as.supervised_mode !== undefined) {
				if (typeof as.supervised_mode === "boolean")
					validatedAs.supervised_mode = as.supervised_mode;
				else
					errors.push(
						"auto_supervisor.supervised_mode must be a boolean (true/false)",
					);
			}
			if (as.runaway_guard_enabled !== undefined) {
				if (typeof as.runaway_guard_enabled === "boolean") {
					validatedAs.runaway_guard_enabled = as.runaway_guard_enabled;
				} else {
					errors.push(
						"auto_supervisor.runaway_guard_enabled must be a boolean (true/false)",
					);
				}
			}
			if (as.runaway_hard_pause !== undefined) {
				if (typeof as.runaway_hard_pause === "boolean") {
					validatedAs.runaway_hard_pause = as.runaway_hard_pause;
				} else {
					errors.push(
						"auto_supervisor.runaway_hard_pause must be a boolean (true/false)",
					);
				}
			}
			if (as.soft_timeout_minutes !== undefined) {
				const val = Number(as.soft_timeout_minutes);
				if (!Number.isNaN(val) && val >= 0)
					validatedAs.soft_timeout_minutes = val;
				else
					errors.push(
						"auto_supervisor.soft_timeout_minutes must be a non-negative number",
					);
			}
			if (as.idle_timeout_minutes !== undefined) {
				const val = Number(as.idle_timeout_minutes);
				if (!Number.isNaN(val) && val >= 0)
					validatedAs.idle_timeout_minutes = val;
				else
					errors.push(
						"auto_supervisor.idle_timeout_minutes must be a non-negative number",
					);
			}
			if (as.hard_timeout_minutes !== undefined) {
				const val = Number(as.hard_timeout_minutes);
				if (!Number.isNaN(val) && val >= 0)
					validatedAs.hard_timeout_minutes = val;
				else
					errors.push(
						"auto_supervisor.hard_timeout_minutes must be a non-negative number",
					);
			}
			if (as.solver_max_iterations !== undefined) {
				const val = Number(as.solver_max_iterations);
				if (!Number.isNaN(val) && val >= 1 && val <= 100000) {
					validatedAs.solver_max_iterations = Math.floor(val);
				} else {
					errors.push(
						"auto_supervisor.solver_max_iterations must be a number from 1 to 100000",
					);
				}
			}
			if (as.solver_eval_on_autonomous_exit !== undefined) {
				validatedAs.solver_eval_on_autonomous_exit =
					!!as.solver_eval_on_autonomous_exit;
			}
			if (as.phase_timeout_minutes !== undefined) {
				const val = Number(as.phase_timeout_minutes);
				if (!Number.isNaN(val) && val >= 0)
					validatedAs.phase_timeout_minutes = val;
				else
					errors.push(
						"auto_supervisor.phase_timeout_minutes must be a non-negative number",
					);
			}
			if (as.completion_nudge_after !== undefined) {
				const val = Number(as.completion_nudge_after);
				if (!Number.isNaN(val) && val >= 0)
					validatedAs.completion_nudge_after = val;
				else
					errors.push(
						"auto_supervisor.completion_nudge_after must be a non-negative number",
					);
			}
			for (const key of [
				"runaway_tool_call_warning",
				"runaway_token_warning",
				"runaway_elapsed_minutes",
				"runaway_changed_files_warning",
				"runaway_diagnostic_turns",
			]) {
				if (as[key] === undefined) continue;
				const val = Number(as[key]);
				if (!Number.isNaN(val) && val >= 0) {
					validatedAs[key] = val;
				} else {
					errors.push(`auto_supervisor.${key} must be a non-negative number`);
				}
			}
			validated.auto_supervisor = validatedAs;
		} else {
			errors.push("auto_supervisor must be an object");
		}
	}
	// ─── Notifications ──────────────────────────────────────────────────
	if (preferences.notifications !== undefined) {
		if (
			preferences.notifications &&
			typeof preferences.notifications === "object"
		) {
			validated.notifications = preferences.notifications;
		} else {
			errors.push("notifications must be an object");
		}
	}
	// ─── Cmux ───────────────────────────────────────────────────────────────
	if (preferences.cmux !== undefined) {
		if (preferences.cmux && typeof preferences.cmux === "object") {
			const cmux = preferences.cmux;
			const validatedCmux = {};
			if (cmux.enabled !== undefined) validatedCmux.enabled = !!cmux.enabled;
			if (cmux.notifications !== undefined)
				validatedCmux.notifications = !!cmux.notifications;
			if (cmux.sidebar !== undefined) validatedCmux.sidebar = !!cmux.sidebar;
			if (cmux.splits !== undefined) validatedCmux.splits = !!cmux.splits;
			if (cmux.browser !== undefined) validatedCmux.browser = !!cmux.browser;
			const knownCmuxKeys = new Set([
				"enabled",
				"notifications",
				"sidebar",
				"splits",
				"browser",
			]);
			for (const key of Object.keys(cmux)) {
				if (!knownCmuxKeys.has(key)) {
					warnings.push(`unknown cmux key "${key}" — ignored`);
				}
			}
			if (Object.keys(validatedCmux).length > 0) {
				validated.cmux = validatedCmux;
			}
		} else {
			errors.push("cmux must be an object");
		}
	}
	// ─── Remote Questions ───────────────────────────────────────────────
	if (preferences.remote_questions !== undefined) {
		if (
			preferences.remote_questions &&
			typeof preferences.remote_questions === "object"
		) {
			const rq = preferences.remote_questions;
			const validRq = {
				channel: rq.channel,
				channel_id: rq.channel_id,
			};
			if (rq.timeout_minutes !== undefined) {
				const timeout = Number(rq.timeout_minutes);
				if (Number.isFinite(timeout)) validRq.timeout_minutes = timeout;
				else errors.push("remote_questions.timeout_minutes must be a number");
			}
			if (rq.poll_interval_seconds !== undefined) {
				const poll = Number(rq.poll_interval_seconds);
				if (Number.isFinite(poll)) validRq.poll_interval_seconds = poll;
				else
					errors.push(
						"remote_questions.poll_interval_seconds must be a number",
					);
			}
			if (rq.allowed_user_ids !== undefined) {
				if (Array.isArray(rq.allowed_user_ids)) {
					const allowed = rq.allowed_user_ids
						.map((id) => String(id).trim())
						.filter((id) => /^-?\d{1,20}$/.test(id));
					if (allowed.length === rq.allowed_user_ids.length) {
						validRq.allowed_user_ids = allowed;
					} else {
						errors.push(
							"remote_questions.allowed_user_ids must contain only Telegram numeric user IDs",
						);
					}
				} else {
					errors.push("remote_questions.allowed_user_ids must be an array");
				}
			}
			if (rq.auto_resolve_on_timeout !== undefined) {
				if (typeof rq.auto_resolve_on_timeout === "boolean") {
					validRq.auto_resolve_on_timeout = rq.auto_resolve_on_timeout;
				} else {
					errors.push(
						"remote_questions.auto_resolve_on_timeout must be a boolean",
					);
				}
			}
			if (rq.auto_resolve_strategy !== undefined) {
				if (rq.auto_resolve_strategy === "recommended-option") {
					validRq.auto_resolve_strategy = "recommended-option";
				} else {
					errors.push(
						'remote_questions.auto_resolve_strategy must be "recommended-option"',
					);
				}
			}
			const knownRemoteKeys = new Set([
				"channel",
				"channel_id",
				"allowed_user_ids",
				"timeout_minutes",
				"poll_interval_seconds",
				"auto_resolve_on_timeout",
				"auto_resolve_strategy",
			]);
			for (const key of Object.keys(rq)) {
				if (!knownRemoteKeys.has(key)) {
					warnings.push(`unknown remote_questions key "${key}" — ignored`);
				}
			}
			validated.remote_questions = validRq;
		} else {
			errors.push("remote_questions must be an object");
		}
	}
	// ─── Post-Unit Hooks ─────────────────────────────────────────────────
	if (
		preferences.post_unit_hooks &&
		Array.isArray(preferences.post_unit_hooks)
	) {
		const validHooks = [];
		const seenNames = new Set();
		const knownUnitTypes = new Set(KNOWN_UNIT_TYPES);
		for (const hook of preferences.post_unit_hooks) {
			if (!hook || typeof hook !== "object") {
				errors.push("post_unit_hooks entry must be an object");
				continue;
			}
			const name = typeof hook.name === "string" ? hook.name.trim() : "";
			if (!name) {
				errors.push("post_unit_hooks entry missing name");
				continue;
			}
			if (seenNames.has(name)) {
				errors.push(`duplicate post_unit_hooks name: ${name}`);
				continue;
			}
			const after = normalizeStringArray(hook.after);
			if (after.length === 0) {
				errors.push(`post_unit_hooks "${name}" missing after`);
				continue;
			}
			for (const ut of after) {
				if (!knownUnitTypes.has(ut)) {
					errors.push(
						`post_unit_hooks "${name}" unknown unit type in after: ${ut}`,
					);
				}
			}
			const prompt = typeof hook.prompt === "string" ? hook.prompt.trim() : "";
			if (!prompt) {
				errors.push(`post_unit_hooks "${name}" missing prompt`);
				continue;
			}
			const validHook = { name, after, prompt };
			if (hook.max_cycles !== undefined) {
				const mc =
					typeof hook.max_cycles === "number"
						? hook.max_cycles
						: Number(hook.max_cycles);
				validHook.max_cycles = Number.isFinite(mc)
					? Math.max(1, Math.min(10, Math.round(mc)))
					: 1;
			}
			if (typeof hook.model === "string" && hook.model.trim()) {
				validHook.model = hook.model.trim();
			}
			if (typeof hook.artifact === "string" && hook.artifact.trim()) {
				validHook.artifact = hook.artifact.trim();
			}
			if (typeof hook.retry_on === "string" && hook.retry_on.trim()) {
				validHook.retry_on = hook.retry_on.trim();
			}
			if (typeof hook.agent === "string" && hook.agent.trim()) {
				validHook.agent = hook.agent.trim();
			}
			if (hook.enabled !== undefined) {
				validHook.enabled = !!hook.enabled;
			}
			seenNames.add(name);
			validHooks.push(validHook);
		}
		if (validHooks.length > 0) {
			validated.post_unit_hooks = validHooks;
		}
	}
	// ─── Pre-Dispatch Hooks ─────────────────────────────────────────────────
	if (
		preferences.pre_dispatch_hooks &&
		Array.isArray(preferences.pre_dispatch_hooks)
	) {
		const validPreHooks = [];
		const seenPreNames = new Set();
		const knownUnitTypes = new Set(KNOWN_UNIT_TYPES);
		const validActions = new Set(["modify", "skip", "replace"]);
		for (const hook of preferences.pre_dispatch_hooks) {
			if (!hook || typeof hook !== "object") {
				errors.push("pre_dispatch_hooks entry must be an object");
				continue;
			}
			const name = typeof hook.name === "string" ? hook.name.trim() : "";
			if (!name) {
				errors.push("pre_dispatch_hooks entry missing name");
				continue;
			}
			if (seenPreNames.has(name)) {
				errors.push(`duplicate pre_dispatch_hooks name: ${name}`);
				continue;
			}
			const before = normalizeStringArray(hook.before);
			if (before.length === 0) {
				errors.push(`pre_dispatch_hooks "${name}" missing before`);
				continue;
			}
			for (const ut of before) {
				if (!knownUnitTypes.has(ut)) {
					errors.push(
						`pre_dispatch_hooks "${name}" unknown unit type in before: ${ut}`,
					);
				}
			}
			const action = typeof hook.action === "string" ? hook.action.trim() : "";
			if (!validActions.has(action)) {
				errors.push(
					`pre_dispatch_hooks "${name}" invalid action: ${action} (must be modify, skip, or replace)`,
				);
				continue;
			}
			const validHook = {
				name,
				before,
				action: action,
			};
			if (typeof hook.prepend === "string" && hook.prepend.trim())
				validHook.prepend = hook.prepend.trim();
			if (typeof hook.append === "string" && hook.append.trim())
				validHook.append = hook.append.trim();
			if (typeof hook.prompt === "string" && hook.prompt.trim())
				validHook.prompt = hook.prompt.trim();
			if (typeof hook.unit_type === "string" && hook.unit_type.trim())
				validHook.unit_type = hook.unit_type.trim();
			if (typeof hook.skip_if === "string" && hook.skip_if.trim())
				validHook.skip_if = hook.skip_if.trim();
			if (typeof hook.model === "string" && hook.model.trim())
				validHook.model = hook.model.trim();
			if (hook.enabled !== undefined) validHook.enabled = !!hook.enabled;
			// Validation: action-specific required fields
			if (action === "replace" && !validHook.prompt) {
				errors.push(
					`pre_dispatch_hooks "${name}" action "replace" requires prompt`,
				);
				continue;
			}
			if (action === "modify" && !validHook.prepend && !validHook.append) {
				errors.push(
					`pre_dispatch_hooks "${name}" action "modify" requires prepend or append`,
				);
				continue;
			}
			seenPreNames.add(name);
			validPreHooks.push(validHook);
		}
		if (validPreHooks.length > 0) {
			validated.pre_dispatch_hooks = validPreHooks;
		}
	}
	// ─── Dynamic Routing ─────────────────────────────────────────────────
	if (preferences.dynamic_routing !== undefined) {
		if (
			typeof preferences.dynamic_routing === "object" &&
			preferences.dynamic_routing !== null
		) {
			const dr = preferences.dynamic_routing;
			const validDr = {};
			if (dr.enabled !== undefined) {
				if (typeof dr.enabled === "boolean") validDr.enabled = dr.enabled;
				else errors.push("dynamic_routing.enabled must be a boolean");
			}
			if (dr.escalate_on_failure !== undefined) {
				if (typeof dr.escalate_on_failure === "boolean")
					validDr.escalate_on_failure = dr.escalate_on_failure;
				else
					errors.push("dynamic_routing.escalate_on_failure must be a boolean");
			}
			if (dr.budget_pressure !== undefined) {
				if (typeof dr.budget_pressure === "boolean")
					validDr.budget_pressure = dr.budget_pressure;
				else errors.push("dynamic_routing.budget_pressure must be a boolean");
			}
			if (dr.cross_provider !== undefined) {
				if (typeof dr.cross_provider === "boolean")
					validDr.cross_provider = dr.cross_provider;
				else errors.push("dynamic_routing.cross_provider must be a boolean");
			}
			if (dr.hooks !== undefined) {
				if (typeof dr.hooks === "boolean") validDr.hooks = dr.hooks;
				else errors.push("dynamic_routing.hooks must be a boolean");
			}
			if (dr.capability_routing !== undefined) {
				if (typeof dr.capability_routing === "boolean")
					validDr.capability_routing = dr.capability_routing;
				else
					errors.push("dynamic_routing.capability_routing must be a boolean");
			}
			if (dr.tier_models !== undefined) {
				if (typeof dr.tier_models === "object" && dr.tier_models !== null) {
					const tm = dr.tier_models;
					const validTm = {};
					for (const tier of ["light", "standard", "heavy"]) {
						if (tm[tier] !== undefined) {
							if (typeof tm[tier] === "string") validTm[tier] = tm[tier];
							else
								errors.push(
									`dynamic_routing.tier_models.${tier} must be a string`,
								);
						}
					}
					if (Object.keys(validTm).length > 0) validDr.tier_models = validTm;
				} else {
					errors.push("dynamic_routing.tier_models must be an object");
				}
			}
			if (Object.keys(validDr).length > 0) {
				validated.dynamic_routing = validDr;
			}
		} else {
			errors.push("dynamic_routing must be an object");
		}
	}
	// ─── Context Management ──────────────────────────────────────────────
	if (preferences.context_management !== undefined) {
		if (
			typeof preferences.context_management === "object" &&
			preferences.context_management !== null
		) {
			const cm = preferences.context_management;
			const validCm = {};
			if (cm.observation_masking !== undefined) {
				if (typeof cm.observation_masking === "boolean")
					validCm.observation_masking = cm.observation_masking;
				else
					errors.push(
						"context_management.observation_masking must be a boolean",
					);
			}
			if (cm.observation_mask_turns !== undefined) {
				const turns = cm.observation_mask_turns;
				if (typeof turns === "number" && turns >= 1 && turns <= 50)
					validCm.observation_mask_turns = turns;
				else
					errors.push(
						"context_management.observation_mask_turns must be a number between 1 and 50",
					);
			}
			if (cm.compaction_threshold_percent !== undefined) {
				const pct = cm.compaction_threshold_percent;
				if (typeof pct === "number" && pct >= 0.5 && pct <= 0.95)
					validCm.compaction_threshold_percent = pct;
				else
					errors.push(
						"context_management.compaction_threshold_percent must be a number between 0.5 and 0.95",
					);
			}
			if (cm.tool_result_max_chars !== undefined) {
				const chars = cm.tool_result_max_chars;
				if (typeof chars === "number" && chars >= 200 && chars <= 10000)
					validCm.tool_result_max_chars = chars;
				else
					errors.push(
						"context_management.tool_result_max_chars must be a number between 200 and 10000",
					);
			}
			if (Object.keys(validCm).length > 0) {
				validated.context_management = validCm;
			}
		} else {
			errors.push("context_management must be an object");
		}
	}
	// ─── Parallel Config ────────────────────────────────────────────────────
	if (preferences.parallel && typeof preferences.parallel === "object") {
		const p = preferences.parallel;
		const parallel = {};
		if (p.enabled !== undefined) {
			if (typeof p.enabled === "boolean") parallel.enabled = p.enabled;
			else errors.push("parallel.enabled must be a boolean");
		}
		if (p.max_workers !== undefined) {
			if (
				typeof p.max_workers === "number" &&
				p.max_workers >= 1 &&
				p.max_workers <= 4
			) {
				parallel.max_workers = Math.floor(p.max_workers);
			} else {
				errors.push("parallel.max_workers must be a number between 1 and 4");
			}
		}
		if (p.budget_ceiling !== undefined) {
			if (typeof p.budget_ceiling === "number" && p.budget_ceiling > 0) {
				parallel.budget_ceiling = p.budget_ceiling;
			} else {
				errors.push("parallel.budget_ceiling must be a positive number");
			}
		}
		if (p.merge_strategy !== undefined) {
			const validStrategies = new Set(["per-slice", "per-milestone"]);
			if (
				typeof p.merge_strategy === "string" &&
				validStrategies.has(p.merge_strategy)
			) {
				parallel.merge_strategy = p.merge_strategy;
			} else {
				errors.push(
					"parallel.merge_strategy must be one of: per-slice, per-milestone",
				);
			}
		}
		if (p.auto_merge !== undefined) {
			const validModes = new Set(["auto", "confirm", "manual"]);
			if (typeof p.auto_merge === "string" && validModes.has(p.auto_merge)) {
				parallel.auto_merge = p.auto_merge;
			} else {
				errors.push(
					"parallel.auto_merge must be one of: auto, confirm, manual",
				);
			}
		}
		if (p.worker_model !== undefined) {
			if (typeof p.worker_model === "string" && p.worker_model.length > 0) {
				parallel.worker_model = p.worker_model;
			} else {
				errors.push("parallel.worker_model must be a non-empty string");
			}
		}
		if (Object.keys(parallel).length > 0) {
			validated.parallel = parallel;
		}
	}
	// ─── Reactive Execution ─────────────────────────────────────────────────
	if (preferences.reactive_execution !== undefined) {
		if (
			typeof preferences.reactive_execution === "object" &&
			preferences.reactive_execution !== null
		) {
			const re = preferences.reactive_execution;
			const validRe = {};
			if (re.enabled !== undefined) {
				if (typeof re.enabled === "boolean") validRe.enabled = re.enabled;
				else errors.push("reactive_execution.enabled must be a boolean");
			}
			if (re.max_parallel !== undefined) {
				const mp =
					typeof re.max_parallel === "number"
						? re.max_parallel
						: Number(re.max_parallel);
				if (Number.isFinite(mp) && mp >= 1 && mp <= 8) {
					validRe.max_parallel = Math.floor(mp);
				} else {
					errors.push(
						"reactive_execution.max_parallel must be a number between 1 and 8",
					);
				}
			}
			if (re.isolation_mode !== undefined) {
				if (re.isolation_mode === "same-tree") {
					validRe.isolation_mode = "same-tree";
				} else {
					errors.push('reactive_execution.isolation_mode must be "same-tree"');
				}
			}
			if (re.subagent_model !== undefined) {
				if (
					typeof re.subagent_model === "string" &&
					re.subagent_model.length > 0
				) {
					validRe.subagent_model = re.subagent_model;
				} else {
					errors.push(
						"reactive_execution.subagent_model must be a non-empty string",
					);
				}
			}
			const knownReKeys = new Set([
				"enabled",
				"max_parallel",
				"isolation_mode",
				"subagent_model",
			]);
			for (const key of Object.keys(re)) {
				if (!knownReKeys.has(key)) {
					warnings.push(`unknown reactive_execution key "${key}" — ignored`);
				}
			}
			if (Object.keys(validRe).length > 0) {
				validated.reactive_execution = validRe;
			}
		} else {
			errors.push("reactive_execution must be an object");
		}
	}
	// ─── Gate Evaluation ─────────────────────────────────────────────────────
	if (preferences.gate_evaluation !== undefined) {
		if (
			typeof preferences.gate_evaluation === "object" &&
			preferences.gate_evaluation !== null
		) {
			const ge = preferences.gate_evaluation;
			const validGe = {};
			if (ge.enabled !== undefined) {
				if (typeof ge.enabled === "boolean") validGe.enabled = ge.enabled;
				else errors.push("gate_evaluation.enabled must be a boolean");
			}
			if (ge.slice_gates !== undefined) {
				if (
					Array.isArray(ge.slice_gates) &&
					ge.slice_gates.every((g) => typeof g === "string")
				) {
					validGe.slice_gates = ge.slice_gates;
				} else {
					errors.push(
						"gate_evaluation.slice_gates must be an array of strings",
					);
				}
			}
			if (ge.task_gates !== undefined) {
				if (typeof ge.task_gates === "boolean")
					validGe.task_gates = ge.task_gates;
				else errors.push("gate_evaluation.task_gates must be a boolean");
			}
			const knownGeKeys = new Set(["enabled", "slice_gates", "task_gates"]);
			for (const key of Object.keys(ge)) {
				if (!knownGeKeys.has(key)) {
					warnings.push(`unknown gate_evaluation key "${key}" — ignored`);
				}
			}
			if (Object.keys(validGe).length > 0) {
				validated.gate_evaluation = validGe;
			}
		} else {
			errors.push("gate_evaluation must be an object");
		}
	}
	// ─── Verification Preferences ───────────────────────────────────────────
	if (preferences.verification_commands !== undefined) {
		if (Array.isArray(preferences.verification_commands)) {
			const allStrings = preferences.verification_commands.every(
				(item) => typeof item === "string",
			);
			if (allStrings) {
				validated.verification_commands = preferences.verification_commands;
			} else {
				errors.push("verification_commands must be an array of strings");
			}
		} else {
			errors.push("verification_commands must be an array of strings");
		}
	}
	if (preferences.verification_auto_fix !== undefined) {
		if (typeof preferences.verification_auto_fix === "boolean") {
			validated.verification_auto_fix = preferences.verification_auto_fix;
		} else {
			errors.push("verification_auto_fix must be a boolean");
		}
	}
	if (preferences.verification_max_retries !== undefined) {
		const raw = preferences.verification_max_retries;
		if (typeof raw === "number" && Number.isFinite(raw) && raw >= 0) {
			validated.verification_max_retries = Math.floor(raw);
		} else {
			errors.push("verification_max_retries must be a non-negative number");
		}
	}
	if (preferences.verification_auto_defer_threshold !== undefined) {
		const raw = preferences.verification_auto_defer_threshold;
		if (
			typeof raw === "number" &&
			Number.isFinite(raw) &&
			raw >= 0 &&
			raw <= 1
		) {
			validated.verification_auto_defer_threshold = raw;
		} else {
			errors.push(
				"verification_auto_defer_threshold must be a number between 0 and 1",
			);
		}
	}
	// ─── Git Preferences ───────────────────────────────────────────────────
	if (preferences.git && typeof preferences.git === "object") {
		const git = {};
		const g = preferences.git;
		if (g.auto_push !== undefined) {
			if (typeof g.auto_push === "boolean") git.auto_push = g.auto_push;
			else errors.push("git.auto_push must be a boolean");
		}
		if (g.push_branches !== undefined) {
			if (typeof g.push_branches === "boolean")
				git.push_branches = g.push_branches;
			else errors.push("git.push_branches must be a boolean");
		}
		if (g.remote !== undefined) {
			if (typeof g.remote === "string" && g.remote.trim() !== "")
				git.remote = g.remote.trim();
			else errors.push("git.remote must be a non-empty string");
		}
		if (g.snapshots !== undefined) {
			if (typeof g.snapshots === "boolean") git.snapshots = g.snapshots;
			else errors.push("git.snapshots must be a boolean");
		}
		if (g.pre_merge_check !== undefined) {
			if (typeof g.pre_merge_check === "boolean") {
				git.pre_merge_check = g.pre_merge_check;
			} else if (
				typeof g.pre_merge_check === "string" &&
				g.pre_merge_check.trim() !== ""
			) {
				git.pre_merge_check = g.pre_merge_check.trim();
			} else {
				errors.push(
					"git.pre_merge_check must be a boolean or a non-empty string command",
				);
			}
		}
		if (g.commit_type !== undefined) {
			const validCommitTypes = new Set([
				"feat",
				"fix",
				"refactor",
				"docs",
				"test",
				"chore",
				"perf",
				"ci",
				"build",
				"style",
			]);
			if (
				typeof g.commit_type === "string" &&
				validCommitTypes.has(g.commit_type)
			) {
				git.commit_type = g.commit_type;
			} else {
				errors.push(
					`git.commit_type must be one of: feat, fix, refactor, docs, test, chore, perf, ci, build, style`,
				);
			}
		}
		if (g.merge_strategy !== undefined) {
			const validStrategies = new Set(["squash", "merge"]);
			if (
				typeof g.merge_strategy === "string" &&
				validStrategies.has(g.merge_strategy)
			) {
				git.merge_strategy = g.merge_strategy;
			} else {
				errors.push("git.merge_strategy must be one of: squash, merge");
			}
		}
		if (g.main_branch !== undefined) {
			if (
				typeof g.main_branch === "string" &&
				g.main_branch.trim() !== "" &&
				VALID_BRANCH_NAME.test(g.main_branch)
			) {
				git.main_branch = g.main_branch;
			} else {
				errors.push(
					"git.main_branch must be a valid branch name (alphanumeric, _, -, /, .)",
				);
			}
		}
		if (g.isolation !== undefined) {
			const validIsolation = new Set(["worktree", "branch", "none"]);
			if (typeof g.isolation === "string" && validIsolation.has(g.isolation)) {
				git.isolation = g.isolation;
			} else {
				errors.push("git.isolation must be one of: worktree, branch, none");
			}
		}
		if (g.commit_docs !== undefined) {
			warnings.push(
				"git.commit_docs is deprecated — .sf/ is managed externally and always gitignored. Remove this setting.",
			);
		}
		if (g.manage_gitignore !== undefined) {
			if (typeof g.manage_gitignore === "boolean")
				git.manage_gitignore = g.manage_gitignore;
			else errors.push("git.manage_gitignore must be a boolean");
		}
		if (g.worktree_post_create !== undefined) {
			if (
				typeof g.worktree_post_create === "string" &&
				g.worktree_post_create.trim()
			) {
				git.worktree_post_create = g.worktree_post_create.trim();
			} else {
				errors.push(
					"git.worktree_post_create must be a non-empty string (path to script)",
				);
			}
		}
		if (g.auto_pr !== undefined) {
			if (typeof g.auto_pr === "boolean") git.auto_pr = g.auto_pr;
			else errors.push("git.auto_pr must be a boolean");
		}
		if (g.pr_target_branch !== undefined) {
			if (typeof g.pr_target_branch === "string" && g.pr_target_branch.trim()) {
				git.pr_target_branch = g.pr_target_branch.trim();
			} else {
				errors.push(
					"git.pr_target_branch must be a non-empty string (branch name)",
				);
			}
		}
		// Deprecated: merge_to_main is ignored (branchless architecture).
		if (g.merge_to_main !== undefined) {
			warnings.push(
				"git.merge_to_main is deprecated — milestone-level merge is now always used. Remove this setting.",
			);
		}
		// #4765 — collapse cadence + milestone resquash
		if (g.collapse_cadence !== undefined) {
			const validCadence = new Set(["milestone", "slice"]);
			if (
				typeof g.collapse_cadence === "string" &&
				validCadence.has(g.collapse_cadence)
			) {
				git.collapse_cadence = g.collapse_cadence;
			} else {
				errors.push("git.collapse_cadence must be one of: milestone, slice");
			}
		}
		if (g.milestone_resquash !== undefined) {
			if (typeof g.milestone_resquash === "boolean") {
				git.milestone_resquash = g.milestone_resquash;
				const cadence =
					git.collapse_cadence ??
					(typeof g.collapse_cadence === "string"
						? g.collapse_cadence
						: undefined);
				if (cadence !== "slice") {
					warnings.push(
						'git.milestone_resquash is ignored unless git.collapse_cadence is "slice"',
					);
				}
			} else {
				errors.push("git.milestone_resquash must be a boolean");
			}
		}
		if (Object.keys(git).length > 0) {
			validated.git = git;
		}
	}
	// ─── Auto Visualize ─────────────────────────────────────────────────
	if (preferences.auto_visualize !== undefined) {
		if (typeof preferences.auto_visualize === "boolean") {
			validated.auto_visualize = preferences.auto_visualize;
		} else {
			errors.push("auto_visualize must be a boolean");
		}
	}
	// ─── Auto Report ────────────────────────────────────────────────────
	if (preferences.auto_report !== undefined) {
		if (typeof preferences.auto_report === "boolean") {
			validated.auto_report = preferences.auto_report;
		} else {
			errors.push("auto_report must be a boolean");
		}
	}
	// ─── Context Selection ──────────────────────────────────────────────
	if (preferences.context_selection !== undefined) {
		const validModes = new Set(["full", "smart"]);
		if (
			typeof preferences.context_selection === "string" &&
			validModes.has(preferences.context_selection)
		) {
			validated.context_selection = preferences.context_selection;
		} else {
			errors.push(`context_selection must be one of: full, smart`);
		}
	}
	// ─── GitHub Sync ────────────────────────────────────────────────────────
	if (preferences.github !== undefined) {
		if (typeof preferences.github === "object" && preferences.github !== null) {
			const gh = preferences.github;
			const validGh = {};
			if (gh.enabled !== undefined) {
				if (typeof gh.enabled === "boolean") validGh.enabled = gh.enabled;
				else errors.push("github.enabled must be a boolean");
			}
			if (gh.repo !== undefined) {
				if (typeof gh.repo === "string" && gh.repo.includes("/"))
					validGh.repo = gh.repo;
				else errors.push('github.repo must be a string in "owner/repo" format');
			}
			if (gh.project !== undefined) {
				const p =
					typeof gh.project === "number" ? gh.project : Number(gh.project);
				if (Number.isFinite(p) && p > 0) validGh.project = Math.floor(p);
				else errors.push("github.project must be a positive number");
			}
			if (gh.labels !== undefined) {
				if (
					Array.isArray(gh.labels) &&
					gh.labels.every((l) => typeof l === "string")
				) {
					validGh.labels = gh.labels;
				} else {
					errors.push("github.labels must be an array of strings");
				}
			}
			if (gh.auto_link_commits !== undefined) {
				if (typeof gh.auto_link_commits === "boolean")
					validGh.auto_link_commits = gh.auto_link_commits;
				else errors.push("github.auto_link_commits must be a boolean");
			}
			if (gh.slice_prs !== undefined) {
				if (typeof gh.slice_prs === "boolean") validGh.slice_prs = gh.slice_prs;
				else errors.push("github.slice_prs must be a boolean");
			}
			const knownGhKeys = new Set([
				"enabled",
				"repo",
				"project",
				"labels",
				"auto_link_commits",
				"slice_prs",
			]);
			for (const key of Object.keys(gh)) {
				if (!knownGhKeys.has(key)) {
					warnings.push(`unknown github key "${key}" — ignored`);
				}
			}
			if (Object.keys(validGh).length > 0) {
				validated.github = validGh;
			}
		} else {
			errors.push("github must be an object");
		}
	}
	// ─── Show Token Cost ──────────────────────────────────────────────
	if (preferences.show_token_cost !== undefined) {
		if (typeof preferences.show_token_cost === "boolean") {
			validated.show_token_cost = preferences.show_token_cost;
		} else {
			errors.push("show_token_cost must be a boolean");
		}
	}
	// ─── Experimental Features ────────────────────────────────────────
	if (preferences.experimental !== undefined) {
		if (
			typeof preferences.experimental === "object" &&
			preferences.experimental !== null
		) {
			const exp = preferences.experimental;
			const validExp = {};
			if (exp.rtk !== undefined) {
				if (typeof exp.rtk === "boolean") validExp.rtk = exp.rtk;
				else errors.push("experimental.rtk must be a boolean");
			}
			if (exp.dispatch_rules !== undefined) {
				if (
					typeof exp.dispatch_rules === "object" &&
					exp.dispatch_rules !== null
				) {
					const rawDispatch = exp.dispatch_rules;
					const validDispatch = {};
					if (rawDispatch.order !== undefined) {
						if (
							Array.isArray(rawDispatch.order) &&
							rawDispatch.order.every((item) => typeof item === "string")
						) {
							validDispatch.order = rawDispatch.order
								.map((item) => item.trim())
								.filter((item) => item.length > 0);
						} else {
							errors.push(
								"experimental.dispatch_rules.order must be an array of strings",
							);
						}
					}
					if (rawDispatch.variants !== undefined) {
						if (
							typeof rawDispatch.variants === "object" &&
							rawDispatch.variants !== null &&
							!Array.isArray(rawDispatch.variants)
						) {
							const validVariants = {};
							for (const [variantName, variantOrder] of Object.entries(
								rawDispatch.variants,
							)) {
								if (
									!Array.isArray(variantOrder) ||
									variantOrder.some((item) => typeof item !== "string")
								) {
									errors.push(
										`experimental.dispatch_rules.variants.${variantName} must be an array of strings`,
									);
									continue;
								}
								validVariants[variantName] = variantOrder
									.map((item) => item.trim())
									.filter((item) => item.length > 0);
							}
							validDispatch.variants = validVariants;
						} else {
							errors.push(
								"experimental.dispatch_rules.variants must be an object mapping variant names to string arrays",
							);
						}
					}
					if (rawDispatch.active_variant !== undefined) {
						if (
							typeof rawDispatch.active_variant === "string" &&
							rawDispatch.active_variant.trim().length > 0
						) {
							validDispatch.active_variant = rawDispatch.active_variant.trim();
						} else {
							errors.push(
								"experimental.dispatch_rules.active_variant must be a non-empty string",
							);
						}
					}
					const knownDispatchKeys = new Set([
						"order",
						"variants",
						"active_variant",
					]);
					for (const key of Object.keys(rawDispatch)) {
						if (!knownDispatchKeys.has(key)) {
							warnings.push(
								`unknown experimental.dispatch_rules key "${key}" — ignored`,
							);
						}
					}
					if (Object.keys(validDispatch).length > 0) {
						validExp.dispatch_rules = validDispatch;
					}
				} else {
					errors.push("experimental.dispatch_rules must be an object");
				}
			}
			const knownExpKeys = new Set(["rtk", "dispatch_rules"]);
			for (const key of Object.keys(exp)) {
				if (!knownExpKeys.has(key)) {
					warnings.push(`unknown experimental key "${key}" — ignored`);
				}
			}
			if (Object.keys(validExp).length > 0) {
				validated.experimental = validExp;
			}
		} else {
			errors.push("experimental must be an object");
		}
	}
	// ─── Codebase Map ──────────────────────────────────────────────────
	if (preferences.codebase !== undefined) {
		if (
			typeof preferences.codebase === "object" &&
			preferences.codebase !== null
		) {
			const cb = preferences.codebase;
			const validCb = {};
			if (cb.exclude_patterns !== undefined) {
				if (
					Array.isArray(cb.exclude_patterns) &&
					cb.exclude_patterns.every((p) => typeof p === "string")
				) {
					validCb.exclude_patterns = cb.exclude_patterns;
				} else {
					errors.push("codebase.exclude_patterns must be an array of strings");
				}
			}
			if (cb.max_files !== undefined) {
				const mf =
					typeof cb.max_files === "number"
						? cb.max_files
						: Number(cb.max_files);
				if (Number.isFinite(mf) && mf >= 1) {
					validCb.max_files = Math.floor(mf);
				} else {
					errors.push("codebase.max_files must be a positive integer");
				}
			}
			if (cb.collapse_threshold !== undefined) {
				const ct =
					typeof cb.collapse_threshold === "number"
						? cb.collapse_threshold
						: Number(cb.collapse_threshold);
				if (Number.isFinite(ct) && ct >= 1) {
					validCb.collapse_threshold = Math.floor(ct);
				} else {
					errors.push("codebase.collapse_threshold must be a positive integer");
				}
			}
			if (cb.indexer_backend !== undefined) {
				if (cb.indexer_backend === "sift" || cb.indexer_backend === "none") {
					validCb.indexer_backend = cb.indexer_backend;
				} else {
					errors.push(
						'codebase.indexer_backend must be one of "sift" or "none"',
					);
				}
			}
			const knownCbKeys = new Set([
				"exclude_patterns",
				"max_files",
				"collapse_threshold",
				"indexer_backend",
			]);
			for (const key of Object.keys(cb)) {
				if (!knownCbKeys.has(key)) {
					warnings.push(`unknown codebase key "${key}" — ignored`);
				}
			}
			if (Object.keys(validCb).length > 0) {
				validated.codebase = validCb;
			}
		} else {
			errors.push("codebase must be an object");
		}
	}
	// ─── Enhanced Verification ──────────────────────────────────────────────────
	if (preferences.enhanced_verification !== undefined) {
		if (typeof preferences.enhanced_verification === "boolean") {
			validated.enhanced_verification = preferences.enhanced_verification;
		} else {
			errors.push("enhanced_verification must be a boolean");
		}
	}
	if (preferences.enhanced_verification_pre !== undefined) {
		if (typeof preferences.enhanced_verification_pre === "boolean") {
			validated.enhanced_verification_pre =
				preferences.enhanced_verification_pre;
		} else {
			errors.push("enhanced_verification_pre must be a boolean");
		}
	}
	if (preferences.enhanced_verification_post !== undefined) {
		if (typeof preferences.enhanced_verification_post === "boolean") {
			validated.enhanced_verification_post =
				preferences.enhanced_verification_post;
		} else {
			errors.push("enhanced_verification_post must be a boolean");
		}
	}
	if (preferences.enhanced_verification_strict !== undefined) {
		if (typeof preferences.enhanced_verification_strict === "boolean") {
			validated.enhanced_verification_strict =
				preferences.enhanced_verification_strict;
		} else {
			errors.push("enhanced_verification_strict must be a boolean");
		}
	}
	// ─── Discuss Preparation ────────────────────────────────────────────
	if (preferences.discuss_preparation !== undefined) {
		if (typeof preferences.discuss_preparation === "boolean") {
			validated.discuss_preparation = preferences.discuss_preparation;
		} else {
			errors.push("discuss_preparation must be a boolean");
		}
	}
	// ─── Discuss Web Research ───────────────────────────────────────────
	if (preferences.discuss_web_research !== undefined) {
		if (typeof preferences.discuss_web_research === "boolean") {
			validated.discuss_web_research = preferences.discuss_web_research;
		} else {
			errors.push("discuss_web_research must be a boolean");
		}
	}
	// ─── Discuss Depth ──────────────────────────────────────────────────
	if (preferences.discuss_depth !== undefined) {
		const validDepths = new Set(["quick", "standard", "thorough"]);
		if (
			typeof preferences.discuss_depth === "string" &&
			validDepths.has(preferences.discuss_depth)
		) {
			validated.discuss_depth = preferences.discuss_depth;
		} else {
			errors.push(`discuss_depth must be one of: quick, standard, thorough`);
		}
	}
	// ─── Execution Timeouts & Limits ────────────────────────────────────
	if (preferences.context_compact_at !== undefined) {
		const tokens = Number(preferences.context_compact_at);
		if (Number.isFinite(tokens) && tokens > 0) {
			validated.context_compact_at = Math.floor(tokens);
		} else {
			errors.push("context_compact_at must be a positive number");
		}
	}
	if (preferences.context_hard_limit !== undefined) {
		const tokens = Number(preferences.context_hard_limit);
		if (Number.isFinite(tokens) && tokens > 0) {
			validated.context_hard_limit = Math.floor(tokens);
		} else {
			errors.push("context_hard_limit must be a positive number");
		}
	}
	if (preferences.unit_timeout !== undefined) {
		const seconds = Number(preferences.unit_timeout);
		if (Number.isFinite(seconds) && seconds > 0) {
			validated.unit_timeout = Math.floor(seconds);
		} else {
			errors.push("unit_timeout must be a positive number (seconds)");
		}
	}
	if (preferences.unit_timeout_by_phase !== undefined) {
		if (
			typeof preferences.unit_timeout_by_phase === "object" &&
			preferences.unit_timeout_by_phase !== null
		) {
			const validatedPhaseTimeouts = {};
			for (const [phase, timeout] of Object.entries(
				preferences.unit_timeout_by_phase,
			)) {
				const seconds = Number(timeout);
				if (Number.isFinite(seconds) && seconds > 0) {
					validatedPhaseTimeouts[phase] = Math.floor(seconds);
				} else {
					errors.push(
						`unit_timeout_by_phase.${phase} must be a positive number (seconds)`,
					);
				}
			}
			if (Object.keys(validatedPhaseTimeouts).length > 0) {
				validated.unit_timeout_by_phase = validatedPhaseTimeouts;
			}
		} else {
			errors.push(
				"unit_timeout_by_phase must be an object mapping phases to seconds",
			);
		}
	}
	if (preferences.max_agents_by_phase !== undefined) {
		if (
			typeof preferences.max_agents_by_phase === "object" &&
			preferences.max_agents_by_phase !== null
		) {
			const validatedAgents = {};
			for (const [phase, count] of Object.entries(
				preferences.max_agents_by_phase,
			)) {
				const agents = Number(count);
				if (Number.isFinite(agents) && agents >= 1) {
					validatedAgents[phase] = Math.floor(agents);
				} else {
					errors.push(
						`max_agents_by_phase.${phase} must be a positive integer`,
					);
				}
			}
			if (Object.keys(validatedAgents).length > 0) {
				validated.max_agents_by_phase = validatedAgents;
			}
		} else {
			errors.push(
				"max_agents_by_phase must be an object mapping phases to agent counts",
			);
		}
	}
	if (preferences.turn_input_required !== undefined) {
		validated.turn_input_required = !!preferences.turn_input_required;
	}
	if (preferences.worktree_mode !== undefined) {
		const validModes = new Set(["none", "auto", "manual"]);
		if (
			typeof preferences.worktree_mode === "string" &&
			validModes.has(preferences.worktree_mode)
		) {
			validated.worktree_mode = preferences.worktree_mode;
		} else {
			errors.push(`worktree_mode must be one of: none, auto, manual`);
		}
	}
	if (preferences.tool_abort_grace !== undefined) {
		const ms = Number(preferences.tool_abort_grace);
		if (Number.isFinite(ms) && ms >= 0) {
			validated.tool_abort_grace = Math.floor(ms);
		} else {
			errors.push(
				"tool_abort_grace must be a non-negative number (milliseconds)",
			);
		}
	}
	if (preferences.max_turns_per_attempt !== undefined) {
		const turns = Number(preferences.max_turns_per_attempt);
		if (Number.isFinite(turns) && turns >= 1) {
			validated.max_turns_per_attempt = Math.floor(turns);
		} else {
			errors.push("max_turns_per_attempt must be a positive integer");
		}
	}
	if (preferences.hot_cache_turns !== undefined) {
		const turns = Number(preferences.hot_cache_turns);
		if (Number.isFinite(turns) && turns >= 0) {
			validated.hot_cache_turns = Math.floor(turns);
		} else {
			errors.push("hot_cache_turns must be a non-negative integer");
		}
	}
	return { preferences: validated, errors, warnings };
}
