#include <bits/stdc++.h>
#define UPLINK_TARGET_BASE_MILLI 6000
#define UPLINK_TARGET_STRENGTH_MILLI 4750
#define P21_CHUNK_CAP 16
#define P21_ENABLE_CHUNK 1
#define P21_ENABLE_PRIOR 1
#define P21_PRIOR_STRENGTH_MILLI 1000
#define T5_COHORT_SCALE_NUM 1
#define T5_COHORT_SCALE_DEN 4
#define T6_COHORT_MULT 8
using i64 = long long;

namespace {
    enum class state : unsigned char {
        none,
        p_pre_ready,
        p_pre_run,
        p_up_wait,
        p_proc_ready,
        p_proc_run,
        p_down_wait,
        p_post_ready,
        p_post_run,
        d_pre_ready,
        d_pre_run,
        d_up_wait,
        d_proc_ready,
        d_proc_run,
        d_down_wait,
        d_post_ready,
        d_post_run,
        done
    };

    struct request {
        state st = state::none;
        int version = 0;
        int len = 0;
        int c = -1;
        int tokens = 0;
        int wave = -1;
        int next_layer = 0;
        int chunk_end = 0;
        int prefill_pieces = 0;
        bool counted = false;
        bool admitted = false;
        double arrival = 0;
        double ready_since = 0;
        double last_token = 0;
    };

    struct queue_item {
        int id = -1;
        int version = -1;
    };

    struct decode_wave {
        int remaining = 0;
        int ready = 0;
    };

    struct predicted_transfer {
        double due = 0;
        int cloud = -1;
        int units = 0;
        bool decode = false;
    };

    struct task_table {
        std::array<std::vector<std::pair<int, double>>, 6> col;

        void add(int size, const std::array<double, 6>& value) {
            for (int j = 0; j < 6; ++j) {
                if (value[j] >= 0)
                    col[j].push_back({size, value[j]});
            }
        }

        void prepare() {
            for (auto& v : col)
                std::sort(v.begin(), v.end());
        }

        double get(int kind, int size) const {
            const auto& v = col[kind];
            const auto it =
                std::lower_bound(v.begin(), v.end(), std::pair<int, double>{size, -1e100});
            if (it == v.begin())
                return it->second;
            if (it == v.end())
                return v.back().second;
            if (it->first == size)
                return it->second;
            const auto lo = std::prev(it);
            const double ratio = static_cast<double>(size - lo->first) / (it->first - lo->first);
            return lo->second + ratio * (it->second - lo->second);
        }

        int best_d_proc_batch(double schedule_cost) const {
            std::vector<int> candidate{1};
            for (const auto& [size, value] : col[4]) {
                (void)value;
                candidate.push_back(std::min(size, 2000));
            }
            std::sort(candidate.begin(), candidate.end());
            candidate.erase(std::unique(candidate.begin(), candidate.end()), candidate.end());
            int best = 1;
            double best_unit = (schedule_cost + get(4, 1));
            for (int size : candidate) {
                const double unit = (schedule_cost + get(4, size)) / size;
                if (unit + 1e-12 < best_unit) {
                    best_unit = unit;
                    best = size;
                }
            }
            return best;
        }
    };

    bool parse_cloud(const std::string& s, int& c) {
        if (s.size() < 2 || s[0] != 'C')
            return false;
        i64 value = 0;
        for (std::size_t i = 1; i < s.size(); ++i) {
            if (!std::isdigit(static_cast<unsigned char>(s[i])))
                return false;
            value = value * 10 + s[i] - '0';
            if (value > INT_MAX)
                return false;
        }
        c = static_cast<int>(value);
        return true;
    }
    enum class edge_kind : unsigned char { p_pre, p_post, d_pre, d_post };

    struct edge_choice {
        bool valid = false;
        edge_kind kind = edge_kind::p_pre;
        double key = 0;
        int tie = 0;
        int id = -1;
        int c = -1;
        std::vector<int> ids;
    };

    struct solver {
        static constexpr int max_batch = 4096;
        int k;
        int layers;
        int bytes_per_token;
        double schedule_cost;
        double latency;
        double bandwidth;
        double slo1;
        double slo2;
        double tp_upper;
        double tp_base;
        double dist_base;
        double w_tp;
        double w_c;
        task_table table;
        double minimum_prefill_path = 0;
        double now = 0;
        bool e_busy = false;
        std::vector<bool> c_busy;
        std::array<double, 2> link_tail{0.0, 0.0};
        std::array<std::deque<predicted_transfer>, 2> transfer_queue;
        std::array<std::vector<std::deque<std::pair<double, int>>>, 2> decode_transfer_queue;
        std::array<bool, 2> prediction_ok{true, true};
        std::vector<int> c_load;
        std::vector<int> c_decode_load;
        std::vector<int> c_hot_load;
        std::vector<double> c_prefill_work;
        std::vector<double> last_starved_time;
        int next_c = 0;
        int latency_decode_edge_cur = 0;
        int active_decode = 0;
        bool dal = false;
        int d_proc_batch = 1;
        int base_decode_window = 1;
        int decode_window = 1;
        int controller_step = 1;
        int controller_max = 1;
        int unrd = 0;
        bool sdc = false;
        bool ssrp = false;
        i64 ptok = 0;
        double first_arrival = -1;
        double last_arrival = -1;
        int epoch_opportunities = 0;
        int epoch_blocked = 0;
        int epoch_launches = 0;
        int epoch_starved = 0;
        double epoch_util_sum = 0;
        int good_epochs = 0;
        int low_epochs = 0;
        int cooldown = 0;
        int completed_epochs = 0;
        bool probe_pending = false;
        double probe_deficit = 0;
        double probe_saturation = 0;
        double probe_g1 = 0;
        double probe_g2 = 0;
        double probe_norm_tp = 0;
        std::array<std::vector<int>, 3> best_size;
        std::array<std::vector<int>, 3> latency_size;
        std::vector<double> ccy;
        std::vector<int> crb;
        std::vector<int> cbq;
        bool syde = false;
        int spc = 0;
        double syr = 0;
        int bc = 1;
        int sypp = 64;
        int mep = 64;
        int arrived_count = 0;
        int ptdr = 0;
        int last_fallback_arrivals = -1;
        double pending_arrival_sum = 0;
        double completed_tdr_sum = 0;
        bool rtf = false;
        int finished_count = 0;
        int one_token_finished = 0;
        i64 finished_token_count = 0;
        std::vector<int> ftcf;
        int fto = 0;
        int fto_at_last_arrival = 0;
        int multi_token_outcomes = 0;
        bool arrival_seen_in_frame = false;
        int p_post_skip = 0;
        int p_pre_skip = 0;
        std::vector<int> p_proc_skip;
        std::vector<int> fallback_decode_streak;
        std::array<int, 18> ready_count{};
        std::vector<int> d_proc_ready_count;
        std::vector<request> req;
        std::vector<decode_wave> waves;
        std::deque<queue_item> p_pre_q;
        std::deque<queue_item> p_post_q;
        std::deque<queue_item> d_pre_new_q;
        std::deque<queue_item> d_pre_open_q;
        std::deque<queue_item> d_post_q;
        std::vector<std::deque<queue_item>> p_proc_q;
        std::vector<std::deque<queue_item>> d_proc_q;

        solver(int k_,
               int layers_,
               int bytes_per_token_,
               double schedule_cost_,
               double latency_,
               double bandwidth_,
               double slo1_,
               double slo2_,
               double tp_upper_,
               double tp_base_,
               double dist_base_,
               double w_tp_,
               double w_c_,
               task_table table_)
            : k(k_),
              layers(layers_),
              bytes_per_token(bytes_per_token_),
              schedule_cost(schedule_cost_),
              latency(latency_),
              bandwidth(bandwidth_),
              slo1(slo1_),
              slo2(slo2_),
              tp_upper(tp_upper_),
              tp_base(tp_base_),
              dist_base(dist_base_),
              w_tp(w_tp_),
              w_c(w_c_),
              table(std::move(table_)),
              c_busy(k),
              c_load(k),
              c_decode_load(k),
              c_hot_load(k),
              c_prefill_work(k),
              last_starved_time(k, -1e100),
              p_proc_skip(k),
              fallback_decode_streak(k),
              d_proc_ready_count(k),
              p_proc_q(k),
              d_proc_q(k) {
            decode_transfer_queue[0].resize(k);
            decode_transfer_queue[1].resize(k);
            for (int step = 0; step < 3; ++step) {
                best_size[step].resize(max_batch + 1);
                latency_size[step].resize(max_batch + 1);
                int best = 1;
                double best_unit = std::numeric_limits<double>::infinity();
                for (int size = 1; size <= max_batch; ++size) {
                    const double unit = task_cost(3 + step, size) / size;
                    const double eps =
                        std::isfinite(best_unit) ? 1e-12 * std::max(1.0, std::abs(best_unit)) : 0;
                    if (!std::isfinite(best_unit) || unit < best_unit - eps ||
                        (std::abs(unit - best_unit) <= eps && size > best)) {
                        best = size;
                        best_unit = unit;
                    }
                    best_size[step][size] = best;
                    if (w_tp <= 1e-12 && w_c > 1e-12) {
                        int latency_best = 1;
                        double latency_area = std::numeric_limits<double>::infinity();
                        for (int batch = 1; batch <= size; ++batch) {
                            const int full = size / batch;
                            const int rem = size % batch;
                            const double full_cost = task_cost(3 + step, batch);
                            double area =
                                static_cast<double>(batch) * full_cost * full * (full + 1) / 2.0;
                            if (rem > 0) {
                                area += static_cast<double>(rem) *
                                        (full * full_cost + task_cost(3 + step, rem));
                            }
                            if (area < latency_area - 1e-12 ||
                                (std::abs(area - latency_area) <= 1e-12 && batch > latency_best)) {
                                latency_area = area;
                                latency_best = batch;
                            }
                        }
                        latency_size[step][size] = latency_best;
                    } else {
                        latency_size[step][size] = best_size[step][size];
                    }
                }
            }
            d_proc_batch = table.best_d_proc_batch(schedule_cost);
            const int cohort_limit = 2000;
            ccy.assign(cohort_limit + 1, std::numeric_limits<double>::infinity());
            crb.assign(cohort_limit + 1, 1);
            cbq.assign(cohort_limit + 1, 1);
            double best_cohort_rate = 0;
            double best_pipeline_rate = 0;
            int best_rate_size = 1;
            std::vector<double> pipeline_capacity(cohort_limit + 1);
            for (int m = 1; m <= cohort_limit; ++m) {
                double best_cycle = std::numeric_limits<double>::infinity();
                int best_q = 1;
                for (int q = 1; q <= std::min(k, m); ++q) {
                    std::vector<int> part(q, m / q);
                    for (int i = 0; i < m % q; ++i)
                        ++part[i];
                    double up = task_cost(3, m);
                    std::vector<std::pair<double, int>> proc_done;
                    proc_done.reserve(q);
                    double cloud_capacity = 0;
                    for (int b : part) {
                        up += transfer_cost(b);
                        proc_done.push_back({up + task_cost(4, b), b});
                        cloud_capacity += static_cast<double>(b) / task_cost(4, b);
                    }
                    std::sort(proc_done.begin(), proc_done.end());
                    double down = 0;
                    for (const auto& [finish, b] : proc_done) {
                        down = std::max(down, finish) + transfer_cost(b);
                    }
                    const double cycle = down + task_cost(5, m);
                    if (cycle < best_cycle - 1e-12) {
                        best_cycle = cycle;
                        best_q = q;
                    }
                    const double edge_capacity =
                        static_cast<double>(m) / (task_cost(3, m) + task_cost(5, m));
                    const double link_capacity =
                        static_cast<double>(m) /
                        (q * latency +
                         8.0 * static_cast<double>(bytes_per_token) * m / (bandwidth * 1e6));
                    best_pipeline_rate =
                        std::max(best_pipeline_rate,
                                 std::min({edge_capacity, cloud_capacity, link_capacity}));
                }
                pipeline_capacity[m] = best_pipeline_rate;
                ccy[m] = best_cycle;
                cbq[m] = best_q;
                const double rate = static_cast<double>(m) / best_cycle;
                if (rate > best_cohort_rate + 1e-12) {
                    best_cohort_rate = rate;
                    best_rate_size = m;
                }
                crb[m] = (m == 1 ? 1 : crb[m - 1]);
                const int old = crb[m];
                if (rate > static_cast<double>(old) / ccy[old] + 1e-12) {
                    crb[m] = m;
                }
            }
            syr = best_pipeline_rate > 1e-15 ? best_cohort_rate / best_pipeline_rate : 0;
            const double single_rate = 1.0 / ccy[1];
            const double beco = best_cohort_rate / std::max(1e-15, single_rate);
            const double distance_tolerance = dist_base / (dist_base + 32.0);
            const double tppr = w_tp + w_c * distance_tolerance;
            minimum_prefill_path = std::numeric_limits<double>::infinity();
            double maximum_prefill_path = 0;
            std::vector<int> visible_sizes{1};
            for (const auto& column : table.col) {
                for (const auto& [size, value] : column) {
                    (void)value;
                    visible_sizes.push_back(size);
                }
            }
            std::sort(visible_sizes.begin(), visible_sizes.end());
            visible_sizes.erase(std::unique(visible_sizes.begin(), visible_sizes.end()),
                                visible_sizes.end());
            for (int size : visible_sizes) {
                const double path = task_cost(0, size) + 2.0 * transfer_cost(size) +
                                    task_cost(1, size) + task_cost(2, size);
                minimum_prefill_path = std::min(minimum_prefill_path, path);
                maximum_prefill_path = std::max(maximum_prefill_path, path);
            }
            const double modeled_norm_tp = std::clamp(
                (best_cohort_rate - tp_base) / std::max(1e-15, tp_upper - tp_base), 0.0, 1.0);
            const bool generous_waiting =
                minimum_prefill_path <= 0.65 * slo1 + 1e-12 && ccy[1] <= 0.65 * slo2 + 1e-12;
            ssrp = tp_base > 1e-15 && w_tp >= 0.35 - 1e-12 && w_c + 1e-12 >= w_tp &&
                   dist_base >= 256.0 && dist_base < 10000.0 && tppr >= 0.95 - 1e-12 &&
                   modeled_norm_tp >= 0.75 - 1e-12 &&
                   maximum_prefill_path >= 1.20 * minimum_prefill_path - 1e-12 && generous_waiting;
            const bool cohort_objective =
                w_tp >= 0.72 - 1e-12 || (dist_base >= 10000.0 && tp_upper > 1.0);
            const bool medium_weight_tolerant = w_tp >= 0.72 - 1e-12 && w_tp <= 0.86 + 1e-12 &&
                                                dist_base >= 256.0 && tppr >= 0.97 - 1e-12;
            const bool very_tolerant_balanced = w_tp >= 0.30 - 1e-12 && w_tp <= 0.70 + 1e-12 &&
                                                dist_base >= 10000.0 && tp_upper > 1.0 &&
                                                tppr >= 0.97 - 1e-12;
            const bool strict_model_support = syr >= 0.72 - 1e-12 && beco >= 1.18 - 1e-12;
            const bool tolerant_model_support = syr >= 0.52 - 1e-12 && beco >= 1.05 - 1e-12;
            const bool baseline_syde =
                k >= 2 && w_c > 0.02 && cohort_objective && tppr >= 0.90 - 1e-12 &&
                best_rate_size >= 2 &&
                (strict_model_support ||
                 ((medium_weight_tolerant || very_tolerant_balanced) && tolerant_model_support));
            const double score_weight_sum = w_tp + w_c;
            const double tps = score_weight_sum > 1e-15 ? w_tp / score_weight_sum : 0.0;
            const double ultra_weight_gate = std::clamp((tps - 0.95) / 0.03, 0.0, 1.0);
            const double stream_cohort_support = syr * std::sqrt(std::max(1.0, beco));
            const double ss = std::clamp((tps - 0.82) / 0.08, 0.0, 1.0);
            if (k >= 2 && dist_base >= 64.0 && tppr >= 0.90 - 1e-12 && ss > 1e-12) {
                spc = std::clamp(static_cast<int>(std::lround(ss * T6_COHORT_MULT * k)), 2, 8 * k);
            }
            const bool ultra_syde =
                k >= 2 && cohort_objective && best_rate_size >= 2 && beco >= 1.02 - 1e-12 &&
                ultra_weight_gate * stream_cohort_support >= 0.45 + 0.25 * w_c - 1e-12;
            syde = baseline_syde || ultra_syde;
            int ust = static_cast<int>(std::lround(
                ultra_weight_gate *
                std::min(8 * k, std::max(2, best_size[0][std::min(max_batch, 8 * k)]))));
            if (spc == 0 && cohort_objective)
                spc = ust;
            bc = crb[std::min(cohort_limit, std::max(8, k * std::clamp(d_proc_batch, 2, 64)))];
            sypp = std::max(24, std::min(192, bc));
            mep = sypp;
            const int bootstrap_index = std::min(cohort_limit, std::max(1, bc));
            const bool dominant_decode_batching =
                beco >= static_cast<double>(sypp) - 1e-12 &&
                maximum_prefill_path <= ccy[bootstrap_index] + 1e-12;
            const bool baseline_entry_support = dominant_decode_batching && syr >= .74 - 1e-12;
            const bool ultra_entry_support = ultra_syde && syr >= 0.45 - 1e-12;
            if (syde && (baseline_entry_support || ultra_entry_support)) {
                int entry_population = sypp;
                const auto score_proxy = [&](int population) {
                    const int cohort = crb[std::clamp(population, 1, cohort_limit)];
                    const double cycle = ccy[cohort];
                    const double rate = static_cast<double>(cohort) / cycle;
                    const double norm_tp = std::clamp(
                        (rate - tp_base) / std::max(1e-15, tp_upper - tp_base), 0.0, 1.0);
                    const double e1 = std::max(0.0, cycle / std::max(1e-9, slo1) - 1.0);
                    const double e2 = std::max(0.0, cycle / std::max(1e-9, slo2) - 1.0);
                    const double distance = std::hypot(e1, e2);
                    const double norm_wait = dist_base > 1e-15
                                                 ? std::clamp(1.0 - distance / dist_base, 0.0, 1.0)
                                                 : static_cast<double>(distance <= 1e-12);
                    return w_tp * norm_tp + w_c * norm_wait;
                };
                const double singleton_score = score_proxy(1);
                for (int population = 2; population <= sypp; ++population) {
                    const int cohort = crb[population];
                    if (cohort >= 2 && score_proxy(population) > singleton_score + 1e-12) {
                        entry_population = population;
                        break;
                    }
                }
                mep = entry_population;
            }
            if (w_tp >= 0.72 - 1e-12) {
                decode_window = 2000;
            } else {
                const double weight_sum = w_tp + w_c;
                const double tp_share = weight_sum > 0 ? w_tp / weight_sum : 0.5;
                int admission_waves = 4;
                if (tp_share < 0.34)
                    admission_waves = 1;
                if (tp_share > 0.67)
                    admission_waves = 3;
                const int practical_batch = std::min(d_proc_batch, 64);
                const int window_cap = tp_share > 0.67 ? 768 : 512;
                decode_window = std::clamp(k * practical_batch * admission_waves, 1, window_cap);
            }
            if (dist_base >= 10000.0)
                decode_window = 2000;
            if (dist_base >= 100.0 && dist_base < 10000.0 && w_tp > 1e-12 && w_tp < 0.25 - 1e-12) {
                decode_window = std::min(1024, 8 * k * std::min(d_proc_batch, 64));
            }
            if (w_tp >= 0.55 - 1e-12 && w_tp < 0.72 - 1e-12 && w_c > 0.05 && dist_base >= 256.0 &&
                dist_base < 10000.0 && tppr >= 0.90 - 1e-12) {
                const auto model = [&](int population) {
                    const int cohort = crb[population];
                    const double cohort_rate = cohort / ccy[cohort];
                    const double finite_pipeline =
                        std::min(pipeline_capacity[population], population / ccy[1]);
                    const double rate = std::max(cohort_rate, finite_pipeline);
                    const double robust_rate = 0.85 * rate;
                    const double norm_tp = std::clamp(
                        (robust_rate - tp_base) / std::max(1e-15, tp_upper - tp_base), 0.0, 1.0);
                    const double excess = std::max(
                        0.0, population / std::max(1e-15, rate) / std::max(1e-9, slo2) - 1.0);
                    const double norm_wait = dist_base > 1e-15
                                                 ? std::max(0.0, 1.0 - excess / dist_base)
                                                 : static_cast<double>(excess <= 1e-12);
                    return std::pair<double, double>{w_tp * norm_tp + w_c * norm_wait, norm_tp};
                };
                const int old_window = std::clamp(decode_window, 1, cohort_limit);
                const auto old_model = model(old_window);
                int candidate = old_window;
                auto best_model = old_model;
                for (int population = 1; population < old_window; ++population) {
                    const auto value = model(population);
                    if (value.first > best_model.first + 1e-12) {
                        candidate = population;
                        best_model = value;
                    }
                }
                if (candidate < old_window && best_model.first >= old_model.first + 0.001 &&
                    best_model.second + 0.005 >= old_model.second) {
                    double fw = std::clamp((tppr - 0.985) / 0.010, 0., 1.);
                    decode_window = std::max(
                        k,
                        static_cast<int>(std::lround(old_window + fw * (candidate - old_window))));
                }
            }
            if (w_tp <= 1e-12 && w_c >= 0.95 - 1e-12 && dist_base < 2.0) {
                decode_window = std::max(1, decode_window * 15 / 16);
            }
            const double proactive_policy_strength =
                w_tp > 1e-12 ? std::clamp((0.30 - w_tp) / 0.12, 0.0, 1.0) : 0.0;
            decode_window =
                std::max(decode_window,
                         static_cast<int>(std::lround(decode_window + proactive_policy_strength *
                                                                          (2000 - decode_window))));
            base_decode_window = decode_window;
            controller_step = k * std::clamp(d_proc_batch, 1, 64);
            controller_max = base_decode_window;
            if (dist_base >= 100.0 && dist_base < 10000.0 && w_tp >= 0.1 - 1e-12 &&
                base_decode_window < 2000) {
                if (w_tp < 0.25 - 1e-12) {
                    controller_max = std::min(1024, base_decode_window + 3 * controller_step);
                } else if (w_tp < 0.7 - 1e-12) {
                    controller_max = 2000;
                } else if (w_tp < 0.8 - 1e-12) {
                    controller_max = std::min(1536, base_decode_window + 2 * controller_step);
                }
            }
            if (dist_base >= 100.0 && dist_base < 10000.0 && w_tp > 1e-12 && w_tp < 0.25 - 1e-12) {
                controller_max = base_decode_window;
            }
        }

        bool valid(int id) const {
            return id >= 0 && id < static_cast<int>(req.size());
        }

        bool cpr() const {
            return rtf;
        }

        request& get(int id) {
            if (id >= static_cast<int>(req.size()))
                req.resize(static_cast<std::size_t>(id) + 1);
            return req[id];
        }

        bool is_ready_state(state st) const {
            return st == state::p_pre_ready || st == state::p_proc_ready ||
                   st == state::p_post_ready || st == state::d_pre_ready ||
                   st == state::d_proc_ready || st == state::d_post_ready;
        }

        void account_ready(state st, int c, int delta) {
            if (!is_ready_state(st))
                return;
            ready_count[static_cast<std::size_t>(st)] += delta;
            if (st == state::d_proc_ready && c >= 0 && c < k) {
                d_proc_ready_count[c] += delta;
            }
        }

        void push_ready(int id) {
            const queue_item item{id, req[id].version};
            switch (req[id].st) {
                case state::p_pre_ready:
                    p_pre_q.push_back(item);
                    break;
                case state::p_proc_ready:
                    p_proc_q[req[id].c].push_back(item);
                    break;
                case state::p_post_ready:
                    p_post_q.push_back(item);
                    break;
                case state::d_pre_ready:
                    if (req[id].tokens == 0)
                        d_pre_new_q.push_back(item);
                    else
                        d_pre_open_q.push_back(item);
                    break;
                case state::d_proc_ready:
                    d_proc_q[req[id].c].push_back(item);
                    break;
                case state::d_post_ready:
                    d_post_q.push_back(item);
                    break;
                default:
                    break;
            }
        }

        void set_state(int id, state to) {
            request& r = req[id];
            account_ready(r.st, r.c, -1);
            r.st = to;
            ++r.version;
            if (is_ready_state(to))
                r.ready_since = now;
            account_ready(r.st, r.c, 1);
            push_ready(id);
        }

        bool advance(int id, state from, state to) {
            if (!valid(id) || req[id].st != from)
                return false;
            set_state(id, to);
            return true;
        }

        bool release(const std::string& server) {
            if (server == "E") {
                if (!e_busy)
                    return false;
                e_busy = false;
                return true;
            }
            int c = -1;
            if (!parse_cloud(server, c) || c < 0 || c >= k || !c_busy[c])
                return false;
            c_busy[c] = false;
            return true;
        }

        void predict_transfer(int dir, int cloud, bool decode, int units) {
            if (dir < 0 || dir > 1 || cloud < 0 || cloud >= k || units <= 0 || !prediction_ok[dir])
                return;
            const double due = std::max(now, link_tail[dir]) + transfer_cost(units);
            link_tail[dir] = due;
            transfer_queue[dir].push_back({due, cloud, units, decode});
            if (decode)
                decode_transfer_queue[dir][cloud].push_back({due, units});
        }

        void disable_prediction(int dir) {
            prediction_ok[dir] = false;
            transfer_queue[dir].clear();
            for (auto& q : decode_transfer_queue[dir])
                q.clear();
            link_tail[dir] = now;
        }

        void consume_transfer(int dir, int cloud, bool decode, i64 bytes, int members) {
            if (dir < 0 || dir > 1 || !prediction_ok[dir])
                return;
            auto& q = transfer_queue[dir];
            if (q.empty()) {
                disable_prediction(dir);
                return;
            }
            const predicted_transfer p = q.front();
            const i64 modeled_bytes = static_cast<i64>(bytes_per_token) * p.units;
            const double eps = 1e-7 * std::max(1.0, std::abs(now));
            if (p.cloud != cloud || p.decode != decode || modeled_bytes != bytes ||
                (decode && p.units != members) || std::abs(p.due - now) > eps ||
                (!decode && members != 1)) {
                disable_prediction(dir);
                return;
            }
            q.pop_front();
            if (decode) {
                auto& dq = decode_transfer_queue[dir][cloud];
                if (dq.empty() || std::abs(dq.front().first - p.due) > eps ||
                    dq.front().second != p.units) {
                    disable_prediction(dir);
                    return;
                }
                dq.pop_front();
            }
            if (q.empty())
                link_tail[dir] = now;
        }

        std::pair<double, int> next_decode_transfer(int dir, int cloud = -1) const {
            if (dir < 0 || dir > 1 || !prediction_ok[dir]) {
                return {std::numeric_limits<double>::infinity(), 0};
            }
            std::pair<double, int> best{std::numeric_limits<double>::infinity(), 0};
            const int first = cloud < 0 ? 0 : cloud;
            const int last = cloud < 0 ? k : cloud + 1;
            for (int c = first; c < last; ++c) {
                const auto& q = decode_transfer_queue[dir][c];
                if (!q.empty() && q.front().first > now + 1e-9 && q.front().first < best.first) {
                    best = q.front();
                }
            }
            return best;
        }

        bool hdp() const {
            return std::any_of(
                c_hot_load.begin(), c_hot_load.end(), [](int count) { return count > 0; });
        }

        bool contains_hot_decode(const std::vector<int>& ids) const {
            return std::any_of(
                ids.begin(), ids.end(), [&](int id) { return valid(id) && req[id].tokens > 0; });
        }

        bool score_srpt_active() const {
            return ssrp && !sdc && !hdp();
        }

        bool uplink_is_prefill_bottleneck(int len) const {
            const double xfer = transfer_cost(len);
            const double remote = schedule_cost + task_cost(1, len);
            const double edge = schedule_cost + task_cost(0, len);
            return xfer >= 2.0 * remote - 1e-12 && xfer >= 1.25 * edge - 1e-12;
        }

        bool kpub() const {
            if (!prediction_ok[0] || arrived_count < 64)
                return false;
            return std::any_of(transfer_queue[0].begin(),
                               transfer_queue[0].end(),
                               [&](const predicted_transfer& transfer) {
                                   return !transfer.decode &&
                                          uplink_is_prefill_bottleneck(transfer.units);
                               });
        }

        int queued_prefill_up() const {
            return static_cast<int>(
                std::count_if(transfer_queue[0].begin(),
                              transfer_queue[0].end(),
                              [](const predicted_transfer& transfer) { return !transfer.decode; }));
        }

        double visible_prefill_path(int id) const {
            const int len = req[id].len;
            return task_cost(0, len) + 2.0 * transfer_cost(len) + task_cost(1, len) +
                   task_cost(2, len);
        }

        double curst(int id) const {
            if (!valid(id) || !prediction_ok[0] || transfer_queue[0].empty() || hdp() ||
                w_c <= w_tp + 1e-12)
                return 0;
            const int len = req[id].len;
            const double xfer = transfer_cost(len);
            const double edge = task_cost(0, len);
            const double remote = task_cost(1, len);
            const double weight_sum = std::max(1e-12, w_tp + w_c);
            const double weight_strength = std::clamp((w_c - w_tp) / (0.10 * weight_sum), 0.0, 1.0);
            const double link_ratio =
                std::min(xfer / std::max(1e-12, edge), k * xfer / std::max(1e-12, 2.0 * remote));
            const double cost_strength = std::clamp((link_ratio - 0.80) / 0.20, 0.0, 1.0);
            double model_strength = weight_strength * cost_strength;
            if (model_strength <= 1e-12 ||
                visible_prefill_path(id) <= minimum_prefill_path + edge + 1e-12) {
                return 0;
            }
            const double queue_per_cloud =
                static_cast<double>(queued_prefill_up()) / std::max(1, k);
            const double target = UPLINK_TARGET_BASE_MILLI * 0.001 -
                                  UPLINK_TARGET_STRENGTH_MILLI * 0.001 * model_strength;
            const double depth_strength = std::clamp(queue_per_cloud - (target - 1.0), 0.0, 1.0);
            model_strength *= depth_strength;
            if (sdc) {
                model_strength *= 0.75 + 0.15 * weight_strength;
            }
            return model_strength;
        }

        bool should_hold_prefill_up(int id) const {
            if (id < 0 || hdp() || !prediction_ok[0] || transfer_queue[0].empty())
                return false;
            const bool legacy_hold = !sdc && kpub();
            if (!legacy_hold && curst(id) < 0.85 - 1e-12) {
                return false;
            }
            if (w_c > w_tp + 1e-12 && dist_base >= 100.0 - 1e-12 && last_arrival >= 0 &&
                slo1 > 1e-12) {
                const double transfer = transfer_cost(req[id].len);
                const double transfer_limit = .005 * slo1;
                const double irreversible = transfer + task_cost(0, req[id].len);
                const double irreversible_limit = .01 * slo1;
                const bool within_budget =
                    transfer <= transfer_limit + 1e-12 * std::max(1.0, transfer_limit) &&
                    irreversible <= irreversible_limit + 1e-12 * std::max(1.0, irreversible_limit);
                const double raw_epochs = (now - last_arrival) / (2.0 * slo1);
                const int epochs =
                    raw_epochs >= 4.0 ? 4 : (raw_epochs <= 0.0 ? 0 : static_cast<int>(raw_epochs));
                const int per_epoch = std::max(1, (k + 3) / 4);
                const int allowance = epochs * per_epoch;
                const double tail_limit = .04 * slo1;
                const double total_limit = .04 * slo1;
                const bool within_total_budget =
                    allowance * transfer <= tail_limit + 1e-12 * std::max(1.0, tail_limit) &&
                    allowance * irreversible <= total_limit + 1e-12 * std::max(1.0, total_limit);
                int queued_prefill = 0;
                for (const predicted_transfer& item : transfer_queue[0]) {
                    if (!item.decode)
                        ++queued_prefill;
                }
                if (within_budget && within_total_budget && queued_prefill < allowance) {
                    return false;
                }
            }
            const double next_wakeup = transfer_queue[0].front().due;
            const double prepare = task_cost(0, req[id].len);
            return next_wakeup + prepare <=
                   link_tail[0] + 1e-12 * std::max(1.0, std::abs(link_tail[0]));
        }

        bool on_tdn(std::istream& in) {
            std::string server, family, step;
            if (!(in >> server >> family >> step) || !release(server))
                return false;
            if (family == "P") {
                if (step == "PRE") {
                    int c = -1, id = -1;
                    double dur = 0;
                    if (!(in >> c >> id >> dur))
                        return false;
                    if (server != "E" || !valid(id) || req[id].c != c)
                        return false;
                    if (!advance(id, state::p_pre_run, state::p_up_wait))
                        return false;
                    predict_transfer(0, c, false, req[id].len);
                    return true;
                }
                if (step == "PROC") {
                    int l = -1, r = -1, c = -1, id = -1;
                    double dur = 0;
                    if (!(in >> l >> r >> c >> id >> dur))
                        return false;
                    int server_c = -1;
                    if (!parse_cloud(server, server_c) || server_c != c || !valid(id) ||
                        req[id].c != c || l != req[id].next_layer || r != req[id].chunk_end ||
                        l < 0 || l >= r || r > layers) {
                        return false;
                    }
                    const double raw =
                        table.get(1, req[id].len) * static_cast<double>(r - l) / layers;
                    c_prefill_work[c] = std::max(0.0, c_prefill_work[c] - raw);
                    req[id].next_layer = r;
                    ++req[id].prefill_pieces;
                    if (r == layers) {
                        set_state(id, state::p_down_wait);
                        predict_transfer(1, c, false, req[id].len);
                    } else {
                        set_state(id, state::p_proc_ready);
                    }
                    return true;
                }
                if (step == "POST") {
                    int c = -1, id = -1;
                    double dur = 0;
                    if (!(in >> c >> id >> dur))
                        return false;
                    if (server != "E" || !valid(id) || req[id].c != c)
                        return false;
                    if (!advance(id, state::p_post_run, state::d_pre_ready))
                        return false;
                    --ptdr;
                    pending_arrival_sum -= req[id].arrival;
                    completed_tdr_sum += now - req[id].arrival;
                    req[id].last_token = now;
                    ++unrd;
                    return true;
                }
                return false;
            }
            if (family != "D")
                return false;
            int c = -2, m = 0;
            if (!(in >> c >> m) || m < 1)
                return false;
            std::vector<int> ids(static_cast<std::size_t>(m));
            for (int& id : ids) {
                if (!(in >> id))
                    return false;
            }
            double dur = 0;
            if (!(in >> dur))
                return false;
            if (step == "PRE") {
                if (server != "E" || c != -1)
                    return false;
                std::vector<int> by_cloud(k);
                for (int id : ids) {
                    if (!advance(id, state::d_pre_run, state::d_up_wait))
                        return false;
                    ++by_cloud[req[id].c];
                }
                for (int cloud = 0; cloud < k; ++cloud) {
                    if (by_cloud[cloud] > 0)
                        predict_transfer(0, cloud, true, by_cloud[cloud]);
                }
                return true;
            }
            if (step == "PROC") {
                int server_c = -1;
                if (!parse_cloud(server, server_c) || server_c != c || c < 0 || c >= k) {
                    return false;
                }
                for (int id : ids) {
                    if (!valid(id) || req[id].c != c ||
                        !advance(id, state::d_proc_run, state::d_down_wait)) {
                        return false;
                    }
                }
                predict_transfer(1, c, true, m);
                return true;
            }
            if (step == "POST") {
                if (server != "E" || c != -1)
                    return false;
                for (int id : ids) {
                    if (!valid(id) || req[id].st != state::d_post_run)
                        return false;
                    request& r = req[id];
                    if (r.tokens == 0) {
                        ++c_hot_load[r.c];
                        ftcf.push_back(id);
                    }
                    ++r.tokens;
                    ++ptok;
                    r.last_token = now;
                    set_state(id, state::d_pre_ready);
                }
                return true;
            }
            return false;
        }

        bool on_xdn(std::istream& in) {
            std::string dir, kind;
            int c = -1, m = 0;
            i64 size = 0;
            if (!(in >> dir >> c >> size >> kind >> m) || c < 0 || c >= k || size < 0 || m < 1) {
                return false;
            }
            std::vector<int> ids(static_cast<std::size_t>(m));
            for (int& id : ids) {
                if (!(in >> id))
                    return false;
            }
            if (kind == "PRE") {
                if (m != 1 || !valid(ids[0]) || req[ids[0]].c != c)
                    return false;
                if (dir == "UP") {
                    consume_transfer(0, c, false, size, m);
                    return advance(ids[0], state::p_up_wait, state::p_proc_ready);
                }
                if (dir == "DOWN") {
                    consume_transfer(1, c, false, size, m);
                    return advance(ids[0], state::p_down_wait, state::p_post_ready);
                }
                return false;
            }
            if (kind != "DEC")
                return false;
            if (dir == "UP") {
                consume_transfer(0, c, true, size, m);
                for (int id : ids) {
                    if (!valid(id) || req[id].c != c ||
                        !advance(id, state::d_up_wait, state::d_proc_ready)) {
                        return false;
                    }
                }
                return true;
            }
            if (dir == "DOWN") {
                consume_transfer(1, c, true, size, m);
                for (int id : ids) {
                    if (!valid(id) || req[id].c != c ||
                        !advance(id, state::d_down_wait, state::d_post_ready)) {
                        return false;
                    }
                    const int w = req[id].wave;
                    if (w >= 0 && w < static_cast<int>(waves.size()))
                        ++waves[w].ready;
                }
                return true;
            }
            return false;
        }

        bool read_event(std::istream& in, std::vector<int>& fin) {
            std::string type;
            if (!(in >> type))
                return false;
            if (type == "ARR") {
                int id = -1, len = 0;
                if (!(in >> id >> len) || id < 0 || len <= 0)
                    return false;
                request& r = get(id);
                if (r.st != state::none)
                    return false;
                r.len = len;
                r.arrival = now;
                last_arrival = now;
                arrival_seen_in_frame = true;
                ++arrived_count;
                ++ptdr;
                pending_arrival_sum += now;
                if (first_arrival < 0)
                    first_arrival = now;
                set_state(id, state::p_pre_ready);
                return true;
            }
            if (type == "FIN") {
                int id = -1;
                if (!(in >> id) || !valid(id))
                    return false;
                fin.push_back(id);
                return true;
            }
            if (type == "TDN")
                return on_tdn(in);
            if (type == "XDN")
                return on_xdn(in);
            return false;
        }

        bool finish_frame(const std::vector<int>& fin) {
            std::vector<unsigned char> finishes(req.size(), 0);
            for (int id : fin) {
                if (valid(id))
                    finishes[id] = 1;
            }
            for (int id : ftcf) {
                if (!valid(id))
                    return false;
                ++fto;
                if (id >= static_cast<int>(finishes.size()) || !finishes[id]) {
                    ++multi_token_outcomes;
                }
            }
            if (arrival_seen_in_frame) {
                fto_at_last_arrival = fto;
                arrival_seen_in_frame = false;
            }
            ftcf.clear();
            for (int id : fin) {
                if (!valid(id) || req[id].st != state::d_pre_ready || req[id].tokens <= 0) {
                    return false;
                }
                request& r = req[id];
                if (!r.counted || r.c < 0 || r.c >= k || c_load[r.c] <= 0)
                    return false;
                --c_load[r.c];
                r.counted = false;
                if (!r.admitted || active_decode <= 0 || c_decode_load[r.c] <= 0)
                    return false;
                --active_decode;
                --c_decode_load[r.c];
                if (r.tokens > 0 && c_hot_load[r.c] > 0)
                    --c_hot_load[r.c];
                r.admitted = false;
                ++finished_count;
                finished_token_count += r.tokens;
                if (r.tokens == 1)
                    ++one_token_finished;
                if (r.tokens > 1)
                    sdc = true;
                set_state(id, state::done);
            }
            if (!synchronized_now() && finished_count >= 8 && w_tp > 0.10) {
                const double singleton_ratio =
                    static_cast<double>(one_token_finished) / finished_count;
                const double mean_tokens =
                    static_cast<double>(finished_token_count) / finished_count;
                if (singleton_ratio >= 0.75 && mean_tokens <= 1.5) {
                    const double confidence = std::min(1.0, (finished_count - 7) / 24.0);
                    const double score_tolerance = dist_base / (dist_base + 16.0);
                    const double strength =
                        confidence * (0.45 + 0.55 * w_tp) * (0.35 + 0.65 * score_tolerance);
                    const int desired = std::clamp(
                        static_cast<int>(std::lround(base_decode_window +
                                                     strength * (2000 - base_decode_window))),
                        base_decode_window,
                        2000);
                    decode_window = std::max(decode_window, desired);
                    controller_max = std::max(controller_max, desired);
                    if (confidence >= 0.75)
                        base_decode_window = std::max(base_decode_window, desired);
                }
            }
            return true;
        }

        std::vector<int> collect(std::deque<queue_item>& q, state need) {
            std::vector<int> ids;
            const std::size_t count = q.size();
            ids.reserve(count);
            for (std::size_t i = 0; i < count; ++i) {
                const queue_item item = q.front();
                q.pop_front();
                if (!valid(item.id) || req[item.id].version != item.version ||
                    req[item.id].st != need) {
                    continue;
                }
                ids.push_back(item.id);
                q.push_back(item);
            }
            return ids;
        }

        int first_ready(std::deque<queue_item>& q, state need) {
            while (!q.empty()) {
                const queue_item item = q.front();
                q.pop_front();
                if (!valid(item.id) || req[item.id].version != item.version ||
                    req[item.id].st != need) {
                    continue;
                }
                q.push_back(item);
                return item.id;
            }
            return -1;
        }

        double task_cost(int kind, int size) const {
            return schedule_cost + table.get(kind, size);
        }

        bool pwo() const {
            return w_tp <= 1e-12 && w_c > 1e-12;
        }

        bool short_output_evidence() const {
            return fto >= 8 && multi_token_outcomes == 0;
        }

        int ready_prefill_count() const {
            return ready_count[static_cast<std::size_t>(state::p_pre_ready)] +
                   ready_count[static_cast<std::size_t>(state::p_proc_ready)] +
                   ready_count[static_cast<std::size_t>(state::p_post_ready)];
        }

        bool balanced_startup_regime() const {
            return !sdc && w_c >= 0.30 - 1e-12 && w_tp <= 0.52 + 1e-12 &&
                   dist_base >= 512.0 - 1e-12 && tp_upper <= 1.0 + 1e-12;
        }

        bool p21_chunk_regime() const {
            return balanced_startup_regime() && w_tp >= 0.45 - 1e-12;
        }

        bool cpa() const {
            return balanced_startup_regime() &&
                   ptdr >= (short_output_evidence() ? 2 : std::max(2, (k + 1) / 2));
        }

        bool evidence_prefill_drain_active() const {
            const double relative_span =
                (tp_upper - tp_base) /
                std::max(1e-15, std::max(std::abs(tp_upper), std::abs(tp_base)));
            return w_c + 1e-12 >= w_tp && !synchronized_now() && relative_span + 1e-12 >= .10 &&
                   short_output_evidence() && ready_prefill_count() >= std::max(2, k);
        }

        bool strict_latency_mode() const {
            return pwo() && dist_base <= 8.0 + 1e-12;
        }

        bool latency_rr() const {
            if (strict_latency_mode())
                return true;
            if (!pwo())
                return false;
            const int population = std::clamp(std::max(1, active_decode), 1, max_batch);
            return latency_size[0][population] == 1 && latency_size[2][population] == 1;
        }

        int group_size(int step, int ready) const {
            if (ready <= 0)
                return 0;
            if (strict_latency_mode())
                return 1;
            if (pwo() && ready <= max_batch)
                return latency_size[step][ready];
            if (ready <= max_batch)
                return best_size[step][ready];
            int best = 1;
            double best_unit = std::numeric_limits<double>::infinity();
            for (int size = 1; size <= ready; ++size) {
                const double unit = task_cost(3 + step, size) / size;
                const double eps =
                    std::isfinite(best_unit) ? 1e-12 * std::max(1.0, std::abs(best_unit)) : 0;
                if (!std::isfinite(best_unit) || unit < best_unit - eps ||
                    (std::abs(unit - best_unit) <= eps && size > best)) {
                    best = size;
                    best_unit = unit;
                }
            }
            return best;
        }

        double decode_wait_weight(int id) const {
            const request& r = req[id];
            if (r.tokens <= 0)
                return 0;
            const double age = std::max(0.0, now - r.last_token) / std::max(1e-9, slo2);
            const double excess = std::max(0.0, age - 1.0);
            return 0.10 + std::min(3.0, age) + 0.5 * std::min(4.0, excess * excess);
        }

        std::vector<int> dynamic_batch_candidates(int step, int ready) const {
            std::vector<int> candidate;
            candidate.reserve(40);
            const auto add = [&](int size) {
                if (size >= 1 && size <= ready)
                    candidate.push_back(size);
            };
            const int legacy = group_size(step, ready);
            add(1);
            add(legacy);
            add(ready);
            add(legacy / 2);
            add((legacy + 1) / 2);
            add(legacy * 2);
            for (int divisor : {2, 3, 4, 6, 8}) {
                const int part = (ready + divisor - 1) / divisor;
                add(part);
                add(ready - part);
                add(group_size(step, part));
            }
            for (int size = 2; size < ready; size *= 2)
                add(size);
            std::sort(candidate.begin(), candidate.end());
            candidate.erase(std::unique(candidate.begin(), candidate.end()), candidate.end());
            return candidate;
        }

        double downstream_tail(int step, int size, const std::vector<int>& ids) const {
            if (step == 2 || size <= 0)
                return 0;
            if (step == 1) {
                const int ready = ready_count[static_cast<std::size_t>(state::d_post_ready)];
                return transfer_cost(size) + task_cost(5, std::min(max_batch, ready + size));
            }
            std::vector<int> by_cloud(k);
            const int take = std::min(size, static_cast<int>(ids.size()));
            for (int i = 0; i < take; ++i)
                ++by_cloud[req[ids[i]].c];
            if (take < size) {
                for (int i = take; i < size; ++i)
                    ++by_cloud[i % k];
            }
            double up = 0;
            double remote = 0;
            for (int c = 0; c < k; ++c) {
                if (by_cloud[c] == 0)
                    continue;
                up += transfer_cost(by_cloud[c]);
                const int merged = std::min(max_batch, d_proc_ready_count[c] + by_cloud[c]);
                remote = std::max(remote, task_cost(4, merged) + transfer_cost(by_cloud[c]));
            }
            const int ready = ready_count[static_cast<std::size_t>(state::d_post_ready)];
            return up + remote + task_cost(5, std::min(max_batch, ready + size));
        }

        int dynamic_group_size(int step, const std::vector<int>& ids) const {
            const int ready = static_cast<int>(ids.size());
            if (ready <= 1)
                return ready;
            if (strict_latency_mode())
                return 1;
            if (pwo() && ready <= max_batch)
                return latency_size[step][ready];
            if (step != 1 || w_tp <= 1e-12 || w_tp >= 0.95 - 1e-12 || latency > schedule_cost ||
                dal) {
                return group_size(step, ready);
            }
            std::vector<double> prefix(static_cast<std::size_t>(ready) + 1);
            for (int i = 0; i < ready; ++i) {
                prefix[i + 1] = prefix[i] + decode_wait_weight(ids[i]);
            }
            const double total_weight = prefix.back();
            const double dist_scale = std::max(1.0, dist_base);
            const double wait_factor = w_c / dist_scale;
            double tp_factor = w_tp;
            if (ptok >= 64) {
                tp_factor *= std::max(0.05, 1.0 - online_norm_tp());
            }
            tp_factor += 2.0 * w_c;
            const std::vector<int> candidate = dynamic_batch_candidates(step, ready);
            const int legacy = group_size(step, ready);
            int best = legacy;
            double best_value = std::numeric_limits<double>::infinity();
            double legacy_value = std::numeric_limits<double>::infinity();
            for (int size : candidate) {
                const double service = task_cost(3 + step, size);
                const int remaining = ready - size;
                const int future_group = remaining > 0 ? group_size(step, remaining) : 0;
                const double future_unit =
                    remaining > 0 ? task_cost(3 + step, future_group) / future_group : 0;
                const double future_service = future_unit * remaining;
                const double first_tail = downstream_tail(step, size, ids);
                const double future_tail =
                    remaining > 0 ? downstream_tail(step, future_group, {}) : 0;
                const double first_weight = prefix[size];
                const double later_weight = total_weight - first_weight;
                const double wait_area =
                    first_weight * (service + first_tail) +
                    later_weight * (service + 0.5 * future_service + future_tail);
                const double makespan =
                    service + future_service + std::max(first_tail, future_tail);
                const double value = wait_factor * wait_area + tp_factor * ready * makespan;
                if (size == legacy)
                    legacy_value = value;
                const double eps =
                    std::isfinite(best_value) ? 1e-10 * std::max(1.0, std::abs(best_value)) : 0;
                if (!std::isfinite(best_value) || value < best_value - eps ||
                    (std::abs(value - best_value) <= eps && size == legacy)) {
                    best_value = value;
                    best = size;
                }
            }
            const double relative_gain =
                (legacy_value - best_value) / std::max(1e-12, std::abs(legacy_value));
            if (relative_gain < 0.04 - 1e-12)
                best = legacy;
            if (best != legacy && (transfer_cost(legacy) > 0.60 * task_cost(4, legacy) ||
                                   transfer_cost(best) > 0.60 * task_cost(4, best))) {
                best = legacy;
            }
            return best;
        }

        double transfer_cost(int len) const {
            return latency + 8.0 * static_cast<double>(bytes_per_token) * len / (bandwidth * 1e6);
        }

        double batch_hold_strength() const {
            if (w_tp <= 1e-15)
                return 0.0;
            if (w_c <= 1e-15)
                return 0.95;
            const double tolerance = dist_base / (dist_base + 16.0);
            const double effective = w_tp + w_c * tolerance;
            return std::clamp((effective - 0.82) / 0.18, 0.0, 1.0) * (0.55 + 0.40 * w_tp);
        }

        bool should_hold_known_batch(int step, int current, std::pair<double, int> future) const {
            if (current <= 0 || future.second <= 0 || !std::isfinite(future.first) ||
                future.first <= now + 1e-9 || current + future.second > max_batch) {
                return false;
            }
            double strength = batch_hold_strength();
            if (prefill_risk() && arrived_count > 0 && ptdr == 0)
                strength = std::max(strength, .25);
            if (strength <= 1e-12)
                return false;
            const auto [g1, g2] = waiting_guard();
            const double risk = std::hypot(std::max(0.0, g1 - 1.0), std::max(0.0, g2 - 1.0));
            if ((dist_base <= 1e-15 && risk > 1e-12) ||
                (dist_base > 1e-15 && risk >= 0.75 * dist_base)) {
                return false;
            }
            const double separate =
                task_cost(3 + step, current) + task_cost(3 + step, future.second);
            const double merged = task_cost(3 + step, current + future.second);
            const double saved = separate - merged;
            return saved > 1e-12 && future.first - now <= strength * saved + 1e-9;
        }

        bool prefill_chunk_mode() const {
            return layers > 1 && w_tp > 1e-12 && w_tp < 0.25 - 1e-12 && w_c >= 0.75 - 1e-12 &&
                   dist_base >= 100.0;
        }

        double remaining_prefill_path(int id, int extra_pieces = 1) const {
            const request& r = req[id];
            const double fraction = static_cast<double>(layers - r.next_layer) / layers;
            return extra_pieces * schedule_cost + fraction * table.get(1, r.len) +
                   transfer_cost(r.len) + task_cost(2, r.len);
        }

        int choose_prefill_chunk_end(int id, int cloud) const {
            const request& r = req[id];
            const int remaining = layers - r.next_layer;
            if (P21_ENABLE_CHUNK && p21_chunk_regime()) {
                if (remaining <= 1 || r.prefill_pieces >= P21_CHUNK_CAP - 1)
                    return layers;
                const bool decode_competition = c_decode_load[cloud] > 0;
                int same_cloud_ready = 0;
                for (const request& other : req) {
                    same_cloud_ready += other.st == state::p_proc_ready && other.c == cloud;
                }
                if (!decode_competition && same_cloud_ready <= 1) {
                    return layers;
                }
                const double full_raw = table.get(1, r.len);
                const double remaining_raw = full_raw * remaining / layers;
                if (remaining_raw <= 4 * schedule_cost + 1e-12)
                    return layers;
                const double overhead_fraction = .025 + .155 * std::clamp(w_c + .20, 0.0, 1.0);
                const double overhead_floor = schedule_cost / std::max(.01, overhead_fraction);
                const int representative =
                    std::clamp(std::max(1, std::min(c_decode_load[cloud], d_proc_batch)), 1, 64);
                double quantum =
                    std::max(overhead_floor, (1.05 + .45 * w_tp) * task_cost(4, representative));
                if (decode_competition) {
                    quantum = std::max(quantum, (.16 + .34 * w_tp) * std::max(slo2, 1e-9));
                }
                quantum = std::min(quantum, std::max(overhead_floor, .08 * std::max(slo1, 1e-9)));
                const double per_layer = full_raw / layers;
                const int minimum_layers = (remaining + P21_CHUNK_CAP - 1) / P21_CHUNK_CAP;
                const double modeled_take = std::floor(
                    std::max(per_layer, quantum - schedule_cost) / std::max(1e-15, per_layer) +
                    1e-12);
                int take = std::max(minimum_layers,
                                    static_cast<int>(std::min<double>(remaining, modeled_take)));
                take = std::clamp(take, 1, remaining);
                if (take >= remaining)
                    return layers;
                const int pieces = (remaining + take - 1) / take;
                if (static_cast<double>(pieces - 1) * schedule_cost >
                    overhead_fraction * remaining_raw + 1e-12) {
                    return layers;
                }
                return r.next_layer + take;
            }
            if (remaining <= 1 || r.prefill_pieces >= 3 || !prefill_chunk_mode())
                return layers;
            const auto future = next_decode_transfer(0, cloud);
            const bool decode_sensitive = c_hot_load[cloud] > 0 || std::isfinite(future.first);
            if (!decode_sensitive)
                return layers;
            const double full_raw = table.get(1, r.len);
            const double per_layer = full_raw / layers;
            const double remaining_raw = per_layer * remaining;
            const int representative = std::max(
                1,
                std::min(
                    {max_batch, std::max(1, c_decode_load[cloud]), std::max(1, d_proc_batch)}));
            const double pressure = assignment_latency_pressure();
            double quantum = std::max({schedule_cost + per_layer,
                                       0.85 * task_cost(4, representative),
                                       slo2 * (0.14 + 1.05 * (1.0 - pressure))});
            if (std::isfinite(future.first) && future.first > now) {
                quantum = std::min(
                    quantum, std::max(schedule_cost + per_layer, 0.92 * (future.first - now)));
            }
            if (schedule_cost > 0.10 * remaining_raw ||
                schedule_cost + remaining_raw <= 1.35 * quantum) {
                return layers;
            }
            int take = static_cast<int>(
                std::floor((quantum - schedule_cost) / std::max(1e-15, per_layer) + 1e-10));
            take = std::clamp(take, 1, remaining);
            return r.next_layer + take;
        }

        bool should_idle_for_decode(int cloud, int prefill_id, int right) const {
            const auto future = next_decode_transfer(0, cloud);
            if (!std::isfinite(future.first) || future.first <= now + 1e-9 ||
                c_hot_load[cloud] <= 0)
                return false;
            const request& r = req[prefill_id];
            const double raw =
                table.get(1, r.len) * static_cast<double>(right - r.next_layer) / layers;
            const double block = schedule_cost + raw;
            const double delay = future.first - now;
            if (delay >= 0.82 * block || assignment_latency_pressure() < 0.20 - 1e-12) {
                return false;
            }
            const double slack = r.arrival + slo1 - (now + remaining_prefill_path(prefill_id, 2));
            return slack > 0.06 * slo1;
        }

        double age_bonus(const std::vector<int>& ids, double scale) const {
            if (ids.empty())
                return 0;
            double oldest = 0;
            for (int id : ids)
                oldest = std::max(oldest, now - req[id].ready_since);
            return 0.08 * std::min(4.0, oldest / std::max(1e-9, scale));
        }

        bool prefill_risk() const {
            const double ratio = tp_upper / std::max(1e-15, tp_base);
            return w_tp >= 0.20 - 1e-12 && w_tp <= 0.40 + 1e-12 && w_c > w_tp &&
                   dist_base >= 24.0 && dist_base <= 64.0 && ratio >= 8.0;
        }

        double p_key(int id, double remaining, double stage_bonus) const {
            const double scale = std::max(1e-9, slo1);
            if (prefill_risk()) {
                double offset = 1.0 - 0.05 * w_c;
                if (stage_bonus > 0.30) {
                    offset = 0.75 - 0.15 * w_c;
                } else if (stage_bonus > 0.10) {
                    offset = 1.0 - 0.10 * w_c;
                }
                const double ready_age = (now - req[id].ready_since) / scale;
                return -(now - req[id].arrival) / scale + .25 * remaining / scale + offset -
                       0.08 * std::min(4.0, ready_age);
            }
            const double norm_tp = online_norm_tp();
            const double headroom = w_tp * (1.0 - norm_tp);
            const bool moderate_risk = w_tp >= 0.85 - 1e-12 && w_tp < 0.95 - 1e-12 &&
                                       dist_base >= 100.0 && dist_base < 1200.0;
            const bool spent_waiting =
                w_tp >= 0.95 - 1e-12 && w_tp < 1.0 - 1e-12 && dist_base <= 16.0;
            const bool neutral_prefill_order = w_tp >= 0.72 - 1e-12 && w_tp < 0.88 - 1e-12 &&
                                               dist_base >= 512.0 && dist_base <= 8192.0 &&
                                               headroom >= 0.15;
            double alpha = 0.5 + 0.5 * w_c;
            if (headroom >= 0.12 && (moderate_risk || spent_waiting))
                alpha = -1.0;
            if (neutral_prefill_order && stage_bonus < 0.05)
                alpha = 0;
            return -(now - req[id].arrival) / scale + alpha * remaining / scale - stage_bonus;
        }

        int p_post_skip_limit() const {
            if (w_tp >= 0.95 - 1e-12)
                return 32;
            return 2 + static_cast<int>(std::lround(14.0 * w_tp));
        }

        int p_work_skip_limit() const {
            if (w_tp >= 0.95 - 1e-12)
                return 32;
            return 4 + static_cast<int>(std::lround(28.0 * w_tp));
        }

        static void update_skip(int& skip, bool ready, bool selected) {
            if (!ready || selected)
                skip = 0;
            else
                skip = std::min(skip + 1, 1000000);
        }

        bool is_prefill_state(state st) const {
            return st == state::p_pre_ready || st == state::p_pre_run || st == state::p_up_wait ||
                   st == state::p_proc_ready || st == state::p_proc_run ||
                   st == state::p_down_wait || st == state::p_post_ready || st == state::p_post_run;
        }

        double online_norm_tp() const {
            const double span = tp_upper - tp_base;
            const double elapsed = now - first_arrival;
            if (span <= 1e-12 || first_arrival < 0 || elapsed <= 1e-12)
                return 0;
            const double tp = static_cast<double>(ptok) / elapsed;
            return std::clamp((tp - tp_base) / span, 0.0, 1.0);
        }

        std::pair<double, double> waiting_guard() const {
            double g1 = 0, g2 = 0;
            const double scale1 = std::max(1e-9, slo1);
            const double scale2 = std::max(1e-9, slo2);
            for (const request& r : req) {
                if (is_prefill_state(r.st)) {
                    g1 = std::max(g1, (now - r.arrival) / scale1);
                }
                if (r.admitted && r.tokens > 0) {
                    g2 = std::max(g2, (now - r.last_token) / scale2);
                }
            }
            return {g1, g2};
        }

        void maybe_activate_throughput_fallback() {
            if (rtf || w_tp <= 1e-12 || arrived_count < std::max(16, 4 * k) ||
                minimum_prefill_path > slo1 * (1.0 + dist_base))
                return;
            double lower = completed_tdr_sum + ptdr * now - pending_arrival_sum;
            if (last_fallback_arrivals != arrived_count) {
                last_fallback_arrivals = arrived_count;
                std::vector<double> edge_work;
                edge_work.reserve(ptdr);
                for (const request& r : req) {
                    double work = 0;
                    if (r.st == state::p_pre_ready) {
                        work = 2.0 * schedule_cost + table.get(0, r.len) + table.get(2, r.len);
                    } else if (r.st == state::p_pre_run || r.st == state::p_up_wait ||
                               r.st == state::p_proc_ready || r.st == state::p_proc_run ||
                               r.st == state::p_down_wait || r.st == state::p_post_ready) {
                        work = schedule_cost + table.get(2, r.len);
                    } else if (r.st != state::p_post_run) {
                        continue;
                    }
                    edge_work.push_back(work);
                }
                std::sort(edge_work.begin(), edge_work.end());
                const int jobs = static_cast<int>(edge_work.size());
                for (int i = 0; i < jobs; ++i)
                    lower += (jobs - i) * edge_work[i];
            }
            if (lower / arrived_count <= 1.5 * slo1 * (1.0 + dist_base))
                return;
            rtf = true;
            base_decode_window = decode_window = controller_max = 2000;
        }

        double edge_window_gain() const {
            const int next_window = std::min(controller_max, decode_window + controller_step);
            if (next_window <= decode_window)
                return 0;
            const double current_unit =
                (task_cost(3, decode_window) + task_cost(5, decode_window)) / decode_window;
            const double next_unit =
                (task_cost(3, next_window) + task_cost(5, next_window)) / next_window;
            if (!std::isfinite(current_unit) || current_unit <= 1e-12)
                return 0;
            return std::max(0.0, 1.0 - next_unit / current_unit);
        }

        void reset_controller_epoch() {
            epoch_opportunities = 0;
            epoch_blocked = 0;
            epoch_launches = 0;
            epoch_starved = 0;
            epoch_util_sum = 0;
        }

        void finish_controller_epoch() {
            const double count = std::max(1, epoch_opportunities);
            const double saturation = epoch_blocked / count;
            const double utilization = epoch_launches > 0 ? epoch_util_sum / epoch_launches : 0;
            const double starvation = epoch_starved / count;
            const double deficit = (1.0 - utilization) + 0.75 * starvation;
            const auto [g1, g2] = waiting_guard();
            const double norm_tp = online_norm_tp();
            const double headroom = w_tp * (1.0 - norm_tp);
            const double risk = std::hypot(std::max(0.0, g1 - 1.0), std::max(0.0, g2 - 1.0));
            bool rolled_back = false;
            if (probe_pending) {
                const bool no_supply_gain = deficit > probe_deficit - 0.08 &&
                                            saturation > probe_saturation - 0.20 &&
                                            norm_tp < probe_norm_tp + 0.01;
                const bool waiting_worse = g1 > probe_g1 + 0.15 || g2 > probe_g2 + 0.15;
                if (no_supply_gain || waiting_worse) {
                    decode_window = std::max(base_decode_window, decode_window - controller_step);
                    cooldown = 3;
                    rolled_back = true;
                }
                probe_pending = false;
            }
            if (decode_window > base_decode_window && risk >= 0.9 * dist_base) {
                decode_window = base_decode_window;
                cooldown = 3;
                probe_pending = false;
                rolled_back = true;
            }
            if (cooldown > 0)
                --cooldown;
            if (saturation <= 0.20)
                ++low_epochs;
            else
                low_epochs = 0;
            if (low_epochs >= 2 && decode_window > base_decode_window) {
                decode_window = std::max(base_decode_window, decode_window - controller_step);
                low_epochs = 0;
                probe_pending = false;
            }
            const double deficit_threshold = w_tp < 0.7 - 1e-12 ? 0.40 : 0.25;
            const bool score_gate =
                ptok >= 128 && norm_tp < 0.95 - 1e-12 && headroom >= 0.025 - 1e-12;
            const bool risk_gate = risk < 0.9 * dist_base;
            const bool supply_gate =
                deficit >= deficit_threshold - 1e-12 || edge_window_gain() >= 0.04 - 1e-12;
            const bool good = !rolled_back && cooldown == 0 && completed_epochs > 0 &&
                              decode_window < controller_max && unrd > 0 &&
                              saturation >= 0.75 - 1e-12 && score_gate && risk_gate && supply_gate;
            if (good)
                ++good_epochs;
            else
                good_epochs = 0;
            if (good_epochs >= 2) {
                probe_deficit = deficit;
                probe_saturation = saturation;
                probe_g1 = g1;
                probe_g2 = g2;
                probe_norm_tp = norm_tp;
                decode_window = std::min(controller_max, decode_window + controller_step);
                probe_pending = true;
                good_epochs = 0;
            }
            ++completed_epochs;
            reset_controller_epoch();
        }

        void controller_opportunity(int group_size, bool starved) {
            if (controller_max <= base_decode_window)
                return;
            ++epoch_opportunities;
            if (unrd > 0 && active_decode >= decode_window)
                ++epoch_blocked;
            if (group_size > 0) {
                const int target = std::clamp(d_proc_batch, 1, 64);
                ++epoch_launches;
                epoch_util_sum += std::min(1.0, static_cast<double>(group_size) / target);
            }
            if (starved)
                ++epoch_starved;
            const int horizon = std::max(32, 8 * k);
            if (epoch_opportunities >= horizon)
                finish_controller_epoch();
        }

        bool synchronized_now() const {
            return syde && arrived_count - finished_count >= effective_sypp();
        }

        int effective_sypp() const {
            return sdc && hdp() ? mep : sypp;
        }

        int effective_warm_population() const {
            return sdc && hdp() ? mep : bc;
        }

        double assignment_latency_pressure() const {
            if (w_c <= 1e-15)
                return 0.0;
            if (w_tp <= 1e-15)
                return 1.0;
            if (dist_base <= 1e-15)
                return 0.98;
            const double distance_scale = std::clamp(dist_base, 0.25, 64.0);
            return std::clamp(w_c / (w_c + w_tp * distance_scale), 0.0, 1.0);
        }

        int choose_cloud(int id) {
            int cloud_limit = k;
            if (synchronized_now()) {
                const int potential = std::min(2000, std::max(bc, arrived_count - finished_count));
                const int target = std::max(1, cohort_target(potential));
                cloud_limit = std::clamp(cbq[target], 1, k);
            }
            if (P21_ENABLE_PRIOR && p21_chunk_regime()) {
                const int batch = std::max(1, std::min(d_proc_batch, 64));
                const double unit = task_cost(4, batch) / batch;
                const double observed_prior = (16 + fto - multi_token_outcomes) / (4.0 + fto);
                const double prior = 4.0 + P21_PRIOR_STRENGTH_MILLI * .001 * (observed_prior - 4.0);
                int best = -1;
                double low = 1e100;
                for (int d = 0; d < cloud_limit; ++d) {
                    const int c = (next_c + d) % cloud_limit;
                    const double value = c_prefill_work[c] + prior * c_load[c] * unit;
                    if (value < low - 1e-12) {
                        low = value;
                        best = c;
                    }
                }
                next_c = (best + 1) % cloud_limit;
                return best;
            }
            const bool wb = assignment_latency_pressure() <= 0.12 + 1e-12;
            int best = -1;
            for (int d = 0; d < cloud_limit; ++d) {
                const int c = (next_c + d) % cloud_limit;
                if (best < 0) {
                    best = c;
                    continue;
                }
                if (wb && w_tp >= 0.8 - 1e-12) {
                    const double value = c_prefill_work[c] + .5 * c_load[c] * task_cost(4, 1);
                    const double old = c_prefill_work[best] + .5 * c_load[best] * task_cost(4, 1);
                    if (value < old - 1e-12)
                        best = c;
                } else if (wb) {
                    if (c_load[c] < c_load[best] ||
                        (c_load[c] == c_load[best] &&
                         (c_prefill_work[c] < c_prefill_work[best] - 1e-12 ||
                          (std::abs(c_prefill_work[c] - c_prefill_work[best]) <= 1e-12 &&
                           (c_decode_load[c] < c_decode_load[best] ||
                            (c_decode_load[c] == c_decode_load[best] &&
                             static_cast<int>(c_busy[c]) < static_cast<int>(c_busy[best]))))))) {
                        best = c;
                    }
                } else {
                    const double value = c_load[c] + (0.4 + 0.8 * w_tp) * c_decode_load[c] +
                                         (c_busy[c] ? 0.35 : 0.0);
                    const double best_value = c_load[best] +
                                              (0.4 + 0.8 * w_tp) * c_decode_load[best] +
                                              (c_busy[best] ? 0.35 : 0.0);
                    if (value < best_value - 1e-12)
                        best = c;
                }
            }
            (void)id;
            next_c = (best + 1) % cloud_limit;
            return best;
        }

        bool hintf() const {
            if (e_busy)
                return true;
            for (bool busy : c_busy) {
                if (busy)
                    return true;
            }
            for (const request& r : req) {
                if (r.st == state::p_up_wait || r.st == state::p_down_wait ||
                    r.st == state::d_up_wait || r.st == state::d_down_wait) {
                    return true;
                }
            }
            return false;
        }

        static void append_group(std::string& task, const std::vector<int>& ids) {
            task += " " + std::to_string(ids.size());
            for (int id : ids)
                task += " " + std::to_string(id);
        }

        int cohort_target(int available) const {
            if (available <= 1)
                return std::max(0, available);
            const int capped = std::min(2000, available);
            int target = crb[capped];
            const double sum = w_tp + w_c;
            const double share = sum > 1e-15 ? w_tp / sum : 0.0;
            if (share >= 0.74 - 1e-12 && share <= 0.85 + 1e-12 && dist_base >= 64.0) {
                target = std::max(
                    1,
                    (target * T5_COHORT_SCALE_NUM + T5_COHORT_SCALE_DEN - 1) / T5_COHORT_SCALE_DEN);
            }
            return std::min(capped, target);
        }

        std::vector<int> synchronized_d_pre_group() {
            std::vector<int> open = collect(d_pre_open_q, state::d_pre_ready);
            std::sort(open.begin(), open.end(), [&](int x, int y) {
                if (req[x].last_token != req[y].last_token) {
                    return req[x].last_token < req[y].last_token;
                }
                if (req[x].tokens != req[y].tokens)
                    return req[x].tokens < req[y].tokens;
                return x < y;
            });
            std::vector<int> unopened = collect(d_pre_new_q, state::d_pre_ready);
            std::sort(unopened.begin(), unopened.end(), [&](int x, int y) {
                if (req[x].ready_since != req[y].ready_since) {
                    return req[x].ready_since < req[y].ready_since;
                }
                return x < y;
            });
            std::vector<int> ids;
            if (active_decode > 0) {
                if (static_cast<int>(open.size()) < active_decode && hintf()) {
                    return ids;
                }
                ids = std::move(open);
                const int available = std::min(2000, active_decode + unrd);
                const int target = std::max(active_decode, cohort_target(available));
                const int slots = std::min({std::max(0, target - active_decode),
                                            std::max(0, decode_window - active_decode),
                                            static_cast<int>(unopened.size())});
                ids.insert(ids.end(), unopened.begin(), unopened.begin() + slots);
            } else {
                const int unfinished = std::max(1, arrived_count - finished_count);
                const int target = std::max(1, cohort_target(std::min(2000, unfinished)));
                const int pending_prefill = std::max(0, unfinished - unrd);
                const int warm_target = std::min(target, std::max(2, effective_warm_population()));
                if (ptok == 0 && pending_prefill > 0 &&
                    static_cast<int>(unopened.size()) < warm_target && hintf()) {
                    return ids;
                }
                const int take =
                    std::min({target, decode_window, static_cast<int>(unopened.size())});
                ids.insert(ids.end(), unopened.begin(), unopened.begin() + take);
            }
            if (ids.empty() && !hintf()) {
                const int id = first_ready(d_pre_new_q, state::d_pre_ready);
                if (id >= 0)
                    ids.push_back(id);
            }
            return ids;
        }

        std::vector<int> d_pre_group() {
            if (synchronized_now() && !cpa()) {
                return synchronized_d_pre_group();
            }
            if (unrd > 0 && active_decode + std::max(1, k) >= decode_window) {
                dal = true;
            }
            std::vector<int> open = collect(d_pre_open_q, state::d_pre_ready);
            std::sort(open.begin(), open.end(), [&](int x, int y) {
                if (req[x].last_token != req[y].last_token) {
                    return req[x].last_token < req[y].last_token;
                }
                if (req[x].tokens != req[y].tokens)
                    return req[x].tokens < req[y].tokens;
                return x < y;
            });
            std::vector<int> ids = std::move(open);
            const int slots = std::max(0, decode_window - active_decode);
            const bool drain_prefill_before_fresh_decode =
                evidence_prefill_drain_active() || cpa() || (pwo() && arrived_count > fto);
            if (slots > 0 && !drain_prefill_before_fresh_decode) {
                std::vector<int> unopened = collect(d_pre_new_q, state::d_pre_ready);
                std::sort(unopened.begin(), unopened.end(), [&](int x, int y) {
                    if (req[x].ready_since != req[y].ready_since) {
                        return req[x].ready_since < req[y].ready_since;
                    }
                    return x < y;
                });
                const int take = std::min(slots, static_cast<int>(unopened.size()));
                ids.insert(ids.end(), unopened.begin(), unopened.begin() + take);
            }
            if (ids.empty() && !hintf()) {
                const int id = first_ready(d_pre_new_q, state::d_pre_ready);
                if (id >= 0)
                    ids.push_back(id);
            }
            if (!ids.empty())
                ids.resize(dynamic_group_size(0, ids));
            return ids;
        }

        edge_choice make_d_post_choice() {
            edge_choice choice;
            choice.kind = edge_kind::d_post;
            choice.tie = 0;
            choice.ids = collect(d_post_q, state::d_post_ready);
            if (choice.ids.empty())
                return choice;
            if (!synchronized_now() && w_tp >= 0.70 - 1e-12 && w_tp < 0.80 - 1e-12 &&
                dist_base < 64.0 &&
                static_cast<int>(choice.ids.size()) < std::min(4, active_decode) && hintf())
                return edge_choice{};
            if (synchronized_now()) {
                int wave_id = -1;
                for (int id : choice.ids) {
                    const int w = req[id].wave;
                    if (w >= 0 && (wave_id < 0 || w < wave_id))
                        wave_id = w;
                }
                if (wave_id >= 0) {
                    std::vector<int> same;
                    same.reserve(choice.ids.size());
                    for (int id : choice.ids)
                        if (req[id].wave == wave_id)
                            same.push_back(id);
                    if (wave_id < static_cast<int>(waves.size()) &&
                        waves[wave_id].ready < waves[wave_id].remaining && hintf()) {
                        return choice;
                    }
                    choice.ids = std::move(same);
                }
            }
            std::sort(choice.ids.begin(), choice.ids.end(), [&](int x, int y) {
                const bool ox = req[x].tokens > 0;
                const bool oy = req[y].tokens > 0;
                if (ox != oy)
                    return ox > oy;
                if (ox && req[x].last_token != req[y].last_token) {
                    return req[x].last_token < req[y].last_token;
                }
                if (req[x].tokens != req[y].tokens)
                    return req[x].tokens < req[y].tokens;
                return x < y;
            });
            if (!synchronized_now()) {
                choice.ids.resize(dynamic_group_size(2, choice.ids));
                if (should_hold_known_batch(
                        2, static_cast<int>(choice.ids.size()), next_decode_transfer(1))) {
                    return edge_choice{};
                }
            }
            const double finish = now + task_cost(5, static_cast<int>(choice.ids.size()));
            bool has_open = false;
            double key = 1e100;
            for (int id : choice.ids) {
                if (req[id].tokens == 0)
                    continue;
                has_open = true;
                key = std::min(key, (req[id].last_token + slo2 - finish) / slo2);
            }
            if (has_open) {
                key -= 0.35 + 0.15 * w_tp;
            } else {
                key = 0.30 + 0.20 * w_c - 0.30 * w_tp;
            }
            key -= age_bonus(choice.ids, slo2);
            key -= 0.025 * std::log2(static_cast<double>(choice.ids.size()) + 1.0);
            choice.key = key;
            choice.valid = true;
            return choice;
        }

        edge_choice make_p_post_choice() {
            edge_choice choice;
            choice.kind = edge_kind::p_post;
            choice.tie = 1;
            const std::vector<int> ids = collect(p_post_q, state::p_post_ready);
            if (ids.empty())
                return choice;
            double best_rank = 1e100;
            double chosen_key = 1e100;
            for (int id : ids) {
                const double remaining = task_cost(2, req[id].len);
                const double key = p_key(id, remaining, 0.35 + 0.15 * w_c);
                const double rank = cpr() ? req[id].ready_since
                                          : ((score_srpt_active() ||
                                              (p21_chunk_regime() && ptdr >= std::max(8, 2 * k)))
                                                 ? remaining
                                                 : key);
                if (rank < best_rank - 1e-12 ||
                    (std::abs(rank - best_rank) <= 1e-12 && (choice.id < 0 || id < choice.id))) {
                    best_rank = rank;
                    chosen_key = key;
                    choice.id = id;
                }
            }
            choice.key = chosen_key;
            choice.valid = true;
            return choice;
        }

        edge_choice make_d_pre_choice() {
            edge_choice choice;
            choice.kind = edge_kind::d_pre;
            choice.tie = 2;
            choice.ids = d_pre_group();
            if (choice.ids.empty())
                return choice;
            std::vector<int> by_cloud(k);
            for (int id : choice.ids)
                ++by_cloud[req[id].c];
            const int m = static_cast<int>(choice.ids.size());
            const double e_cost = task_cost(3, m);
            const double post_cost = task_cost(5, m);
            bool has_open = false;
            double key = 1e100;
            for (int id : choice.ids) {
                if (req[id].tokens == 0)
                    continue;
                has_open = true;
                const int local_m = by_cloud[req[id].c];
                const double remaining = e_cost + transfer_cost(local_m) + task_cost(4, local_m) +
                                         transfer_cost(local_m) + post_cost;
                const double item_key = (req[id].last_token + slo2 - (now + remaining)) / slo2;
                key = std::min(key, item_key);
            }
            if (has_open) {
                key -= 0.15 + 0.10 * w_tp;
            } else {
                key = 0.55 + 0.25 * w_c - 0.45 * w_tp;
            }
            key -= age_bonus(choice.ids, has_open ? slo2 : slo1);
            key -= 0.02 * std::log2(static_cast<double>(m) + 1.0);
            choice.key = key;
            choice.valid = true;
            return choice;
        }

        edge_choice make_p_pre_choice() {
            edge_choice choice;
            choice.kind = edge_kind::p_pre;
            choice.tie = 3;
            const std::vector<int> ids = collect(p_pre_q, state::p_pre_ready);
            if (ids.empty())
                return choice;
            double best_rank = 1e100;
            double chosen_key = 1e100;
            const bool legacy_pressure = score_srpt_active() ||
                                         (p21_chunk_regime() && ptdr >= std::max(8, 2 * k)) ||
                                         (!sdc && !hdp() && kpub());
            for (int id : ids) {
                const request& r = req[id];
                const double remaining = task_cost(0, r.len) + 2.0 * transfer_cost(r.len) +
                                         task_cost(1, r.len) + task_cost(2, r.len);
                const double key = p_key(id, remaining, 0);
                const double restraint = legacy_pressure ? 1.0 : curst(id);
                const double srpt_rank = remaining / std::max(1e-9, slo1);
                const double rank =
                    cpr() ? r.ready_since : (1.0 - restraint) * key + restraint * srpt_rank;
                if (rank < best_rank - 1e-12 ||
                    (std::abs(rank - best_rank) <= 1e-12 && (choice.id < 0 || id < choice.id))) {
                    best_rank = rank;
                    chosen_key = key;
                    choice.id = id;
                }
            }
            choice.key = chosen_key;
            choice.valid = true;
            return choice;
        }

        bool run_edge(std::string& task) {
            std::array<edge_choice, 4> choices = {make_d_post_choice(),
                                                  make_p_post_choice(),
                                                  make_d_pre_choice(),
                                                  make_p_pre_choice()};
            edge_choice* best = nullptr;
            const bool hot_decode_ready =
                (choices[0].valid && contains_hot_decode(choices[0].ids)) ||
                (choices[2].valid && contains_hot_decode(choices[2].ids));
            const bool hold_prefill_up = choices[3].valid && should_hold_prefill_up(choices[3].id);
            edge_choice* fallback_hot = nullptr;
            if (cpr()) {
                const double cycle = task_cost(3, 1) + transfer_cost(1) + task_cost(4, 1) +
                                     transfer_cost(1) + task_cost(5, 1);
                const double limit = std::max(slo2, cycle) * (1.0 + 2.0 * w_tp);
                for (int index : {0, 2}) {
                    if (!choices[index].valid)
                        continue;
                    const double fraction = index == 0 ? 1.0 : 0.75;
                    if (std::any_of(
                            choices[index].ids.begin(), choices[index].ids.end(), [&](int id) {
                                return req[id].tokens > 0 &&
                                       now - req[id].last_token >= fraction * limit;
                            })) {
                        fallback_hot = &choices[index];
                        break;
                    }
                }
            }
            const auto sg = waiting_guard();
            const double sr =
                std::hypot(std::max(0.0, sg.first - 1.0), std::max(0.0, sg.second - 1.0));
            double v = double(std::max(0, arrived_count - finished_count)) / std::max(1, k);
            double z = std::clamp((v - 8) / 8, 0., 1.) *
                       std::clamp((8192 - dist_base) / 7168, 0., 1.) *
                       std::clamp((.98 - w_tp) / .03, 0., 1.);
            int ac = static_cast<int>(std::lround((8 - 5 * z) * k));
            if (spc > 8 * k)
                ac = spc;
            const int sac = std::min({spc, ac, unrd + std::max(0, ptdr)});
            const bool bsc =
                sac >= 2 && ptok == 0 && !hot_decode_ready && choices[2].valid && ptdr > 0 &&
                unrd < sac && (choices[1].valid || choices[3].valid || hintf()) &&
                ((dist_base <= 1e-15 && sr <= 1e-12) ||
                 (dist_base > 1e-15 &&
                  sr < (.25 +
                        .125 * .75 *
                            std::clamp((w_tp / std::max(1e-15, w_tp + w_c) - .95) / .04, 0., 1.) *
                            std::clamp((64 - dist_base) / 64, 0., 1.)) *
                           dist_base));
            if (bsc) {
                if (choices[1].valid || choices[3].valid) {
                    best = choices[1].valid ? &choices[1] : &choices[3];
                } else if (hintf()) {
                    p_post_skip = 0;
                    p_pre_skip = 0;
                    return false;
                }
            } else if (cpa() && !hot_decode_ready && (choices[1].valid || choices[3].valid)) {
                best = choices[1].valid ? &choices[1] : &choices[3];
            } else if (fallback_hot != nullptr) {
                best = fallback_hot;
            } else if (cpr() && (choices[1].valid || choices[3].valid)) {
                best = choices[1].valid ? &choices[1] : &choices[3];
            } else if (pwo() && !hot_decode_ready && (choices[1].valid || choices[3].valid)) {
                best = choices[1].valid ? &choices[1] : &choices[3];
            } else if (!w_c) {
                for (int index : {3, 0, 1, 2}) {
                    if (!choices[index].valid)
                        continue;
                    best = &choices[index];
                    break;
                }
            } else if (hold_prefill_up) {
                edge_choice* non_up = nullptr;
                for (int index : {0, 1}) {
                    if (!choices[index].valid)
                        continue;
                    if (non_up == nullptr || choices[index].key < non_up->key - 1e-12 ||
                        (std::abs(choices[index].key - non_up->key) <= 1e-12 &&
                         choices[index].tie < non_up->tie)) {
                        non_up = &choices[index];
                    }
                }
                if (non_up != nullptr) {
                    const double service = non_up->kind == edge_kind::d_post
                                               ? task_cost(5, static_cast<int>(non_up->ids.size()))
                                               : task_cost(2, req[non_up->id].len);
                    const double prepare = task_cost(0, req[choices[3].id].len);
                    if (now + service + prepare <=
                        link_tail[0] + 1e-12 * std::max(1.0, std::abs(link_tail[0]))) {
                        best = non_up;
                    } else {
                        best = &choices[3];
                    }
                } else {
                    p_post_skip = 0;
                    p_pre_skip = 0;
                    return false;
                }
            } else if (synchronized_now() && choices[0].valid) {
                best = &choices[0];
            } else if (synchronized_now() && choices[2].valid &&
                       std::any_of(choices[2].ids.begin(), choices[2].ids.end(), [&](int id) {
                           return req[id].admitted;
                       })) {
                best = &choices[2];
            } else if (latency_rr() && !choices[1].valid && !choices[3].valid) {
                for (int d = 0; d < 2; ++d) {
                    const int cls = (latency_decode_edge_cur + d) % 2;
                    const int index = cls == 0 ? 0 : 2;
                    if (!choices[index].valid)
                        continue;
                    best = &choices[index];
                    latency_decode_edge_cur = (cls + 1) % 2;
                    break;
                }
            } else if (!prefill_risk() && choices[1].valid && p_post_skip >= p_post_skip_limit()) {
                best = &choices[1];
            } else if (!prefill_risk() && choices[3].valid && p_pre_skip >= p_work_skip_limit()) {
                best = &choices[3];
            } else {
                for (edge_choice& choice : choices) {
                    if (!choice.valid)
                        continue;
                    if (best == nullptr || choice.key < best->key - 1e-12 ||
                        (std::abs(choice.key - best->key) <= 1e-12 && choice.tie < best->tie)) {
                        best = &choice;
                    }
                }
            }
            if (best == nullptr) {
                p_post_skip = 0;
                p_pre_skip = 0;
                return false;
            }
            update_skip(p_post_skip, choices[1].valid, best->kind == edge_kind::p_post);
            update_skip(p_pre_skip, choices[3].valid, best->kind == edge_kind::p_pre);
            if (best->kind == edge_kind::d_post) {
                task = "E D POST -1";
                append_group(task, best->ids);
                for (int id : best->ids) {
                    const int w = req[id].wave;
                    if (w >= 0 && w < static_cast<int>(waves.size())) {
                        --waves[w].remaining;
                        --waves[w].ready;
                    }
                    req[id].wave = -1;
                    set_state(id, state::d_post_run);
                }
            } else if (best->kind == edge_kind::p_post) {
                request& r = req[best->id];
                task = "E P POST " + std::to_string(r.c) + " " + std::to_string(best->id);
                set_state(best->id, state::p_post_run);
            } else if (best->kind == edge_kind::d_pre) {
                task = "E D PRE -1";
                append_group(task, best->ids);
                const bool sync = synchronized_now();
                const int wave_id = sync ? static_cast<int>(waves.size()) : -1;
                if (sync)
                    waves.push_back({static_cast<int>(best->ids.size()), 0});
                for (int id : best->ids) {
                    request& r = req[id];
                    r.wave = wave_id;
                    if (!r.admitted) {
                        if (r.tokens == 0 && unrd > 0)
                            --unrd;
                        r.admitted = true;
                        ++active_decode;
                        ++c_decode_load[r.c];
                    }
                    set_state(id, state::d_pre_run);
                }
            } else {
                request& r = req[best->id];
                best->c = choose_cloud(best->id);
                r.c = best->c;
                r.counted = true;
                ++c_load[r.c];
                c_prefill_work[r.c] += table.get(1, r.len);
                task = "E P PRE " + std::to_string(r.c) + " " + std::to_string(best->id);
                set_state(best->id, state::p_pre_run);
            }
            e_busy = true;
            return true;
        }

        int best_p_proc(int c, double& key) {
            const std::vector<int> ids = collect(p_proc_q[c], state::p_proc_ready);
            int best = -1;
            key = 1e100;
            double best_rank = 1e100;
            for (int id : ids) {
                const request& r = req[id];
                const double fraction = static_cast<double>(layers - r.next_layer) / layers;
                const double remaining = schedule_cost + fraction * table.get(1, r.len) +
                                         transfer_cost(r.len) + task_cost(2, r.len);
                const double item_key = p_key(id, remaining, 0.15 + 0.10 * w_c);
                const double rank =
                    cpr() ? r.ready_since
                          : (score_srpt_active()
                                 ? remaining
                                 : (p21_chunk_regime() && ptok == 0
                                        ? 0 * item_key + 1 * remaining / std::max(1e-9, slo1)
                                        : item_key));
                if (rank < best_rank - 1e-12 ||
                    (std::abs(rank - best_rank) <= 1e-12 && (best < 0 || id < best))) {
                    best = id;
                    best_rank = rank;
                    key = item_key;
                }
            }
            return best;
        }

        std::vector<int> d_proc_group(int c, double& key) {
            std::vector<int> ids = collect(d_proc_q[c], state::d_proc_ready);
            if (ids.empty()) {
                key = 1e100;
                return ids;
            }
            std::sort(ids.begin(), ids.end(), [&](int x, int y) {
                const bool ox = req[x].tokens > 0;
                const bool oy = req[y].tokens > 0;
                if (ox != oy)
                    return ox > oy;
                if (ox && req[x].last_token != req[y].last_token) {
                    return req[x].last_token < req[y].last_token;
                }
                if (req[x].tokens != req[y].tokens)
                    return req[x].tokens < req[y].tokens;
                return x < y;
            });
            if (synchronized_now()) {
                int wave_id = -1;
                for (int id : ids) {
                    const int w = req[id].wave;
                    if (w >= 0 && (wave_id < 0 || w < wave_id))
                        wave_id = w;
                }
                if (wave_id >= 0) {
                    ids.erase(std::remove_if(ids.begin(),
                                             ids.end(),
                                             [&](int id) { return req[id].wave != wave_id; }),
                              ids.end());
                }
            } else {
                ids.resize(dynamic_group_size(1, ids));
                if (should_hold_known_batch(
                        1, static_cast<int>(ids.size()), next_decode_transfer(0, c))) {
                    key = 1e100;
                    return {};
                }
            }
            const int m = static_cast<int>(ids.size());
            const double finish = now + task_cost(4, m) + transfer_cost(m) + task_cost(5, m);
            bool has_open = false;
            key = 1e100;
            for (int id : ids) {
                if (req[id].tokens == 0)
                    continue;
                has_open = true;
                key = std::min(key, (req[id].last_token + slo2 - finish) / slo2);
            }
            if (has_open) {
                key -= 0.30 + 0.15 * w_tp;
            } else {
                key = 0.25 + 0.15 * w_c - 0.25 * w_tp;
            }
            key -= age_bonus(ids, has_open ? slo2 : slo1);
            key -= 0.025 * std::log2(static_cast<double>(m) + 1.0);
            return ids;
        }

        bool r_pref(int c, int p_id, const std::vector<int>& ds) {
            request& p = req[p_id];
            double tl = link_tail[1] - now;
            double pe = schedule_cost + table.get(1, p.len) * (layers - p.next_layer) / layers +
                        tl + transfer_cost(p.len) + task_cost(2, p.len);
            int m = ds.size(), ch = crb.back();
            double de = task_cost(4, m) + tl + transfer_cost(m) + task_cost(5, m);
            double cm = w_tp * ch / ccy[ch] / (tp_upper - tp_base);
            double wg = w_c / dist_base;
            double da = 0.;
            for (int id : ds) {
                da = std::max(da, now - req[id].last_token);
            }
            double pg = cm + wg * std::max(0., (now - p.arrival) / slo1 - 1.);
            double dg = cm + wg * std::max(0., da / slo2 - 1.);
            int pr = collect(p_proc_q[c], state::p_proc_ready).size();
            return pg * pr * active_decode * de > dg * d_proc_ready_count[c] * m * ptdr * pe;
        }

        bool run_cloud(int c, std::string& task, bool& is_decode) {
            double d_key = 0, p_key = 0;
            std::vector<int> d_ids = d_proc_group(c, d_key);
            const int p_id = best_p_proc(c, p_key);
            if (d_ids.empty() && p_id < 0) {
                if (c_decode_load[c] > 0 && now != last_starved_time[c]) {
                    last_starved_time[c] = now;
                    controller_opportunity(0, true);
                }
                return false;
            }
            bool run_decode =
                !d_ids.empty() &&
                (p_id < 0 || (prefill_risk() ? !r_pref(c, p_id, d_ids) : d_key <= p_key + 1e-12));
            if (cpa() && p_id >= 0 && !contains_hot_decode(d_ids)) {
                run_decode = false;
            } else if (cpr() && p_id >= 0 && !d_ids.empty()) {
                const int limit = w_c >= 0.5 - 1e-12 ? 2 : 4;
                run_decode = fallback_decode_streak[c] < limit;
            } else if (pwo() && p_id >= 0 && !contains_hot_decode(d_ids)) {
                run_decode = false;
            }
            if (!cpr() && !prefill_risk() && p_id >= 0 && p_proc_skip[c] >= p_work_skip_limit()) {
                run_decode = false;
            }
            update_skip(p_proc_skip[c], p_id >= 0, !run_decode);
            if (run_decode) {
                ++fallback_decode_streak[c];
                controller_opportunity(static_cast<int>(d_ids.size()), false);
                is_decode = true;
                task = "C" + std::to_string(c) + " D PROC " + std::to_string(c);
                append_group(task, d_ids);
                for (int id : d_ids)
                    set_state(id, state::d_proc_run);
            } else {
                fallback_decode_streak[c] = 0;
                const int right = choose_prefill_chunk_end(p_id, c);
                if (should_idle_for_decode(c, p_id, right))
                    return false;
                is_decode = false;
                task = "C" + std::to_string(c) + " P PROC " + std::to_string(req[p_id].next_layer) +
                       " " + std::to_string(right) + " " + std::to_string(c) + " " +
                       std::to_string(p_id);
                req[p_id].chunk_end = right;
                set_state(p_id, state::p_proc_run);
            }
            c_busy[c] = true;
            return true;
        }

        std::vector<std::string> work() {
            maybe_activate_throughput_fallback();
            if (hdp())
                sdc = true;
            std::vector<std::string> ans;
            ans.reserve(static_cast<std::size_t>(k) + 1);
            std::vector<std::string> p_ans;
            p_ans.reserve(k);
            for (int c = 0; c < k; ++c) {
                if (c_busy[c])
                    continue;
                std::string task;
                bool is_decode = false;
                if (!run_cloud(c, task, is_decode))
                    continue;
                if (is_decode)
                    ans.push_back(std::move(task));
                else
                    p_ans.push_back(std::move(task));
            }
            for (std::string& task : p_ans)
                ans.push_back(std::move(task));
            if (!e_busy) {
                std::string task;
                if (run_edge(task))
                    ans.push_back(std::move(task));
            }
            return ans;
        }
    };
}  // namespace

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int k = 0, bytes_per_token = 0, layers = 0;
    double schedule_cost = 0, latency = 0, bandwidth = 0;
    if (!(std::cin >> k >> schedule_cost >> latency >> bandwidth >> bytes_per_token >> layers)) {
        return 0;
    }
    double slo1 = 0, slo2 = 0, tp_upper = 0, tp_base = 0;
    double dist_base = 0, w_tp = 0, w_c = 0;
    if (!(std::cin >> slo1 >> slo2 >> tp_upper >> tp_base >> dist_base >> w_tp >> w_c)) {
        return 0;
    }
    int n = 0;
    if (!(std::cin >> n) || n < 0)
        return 0;
    task_table table;
    for (int i = 0; i < n; ++i) {
        int size = 0;
        std::array<double, 6> value{};
        if (!(std::cin >> size))
            return 0;
        for (double& x : value) {
            if (!(std::cin >> x))
                return 0;
        }
        table.add(size, value);
    }
    table.prepare();
    solver sol(k,
               layers,
               bytes_per_token,
               schedule_cost,
               latency,
               bandwidth,
               slo1,
               slo2,
               tp_upper,
               tp_base,
               dist_base,
               w_tp,
               w_c,
               std::move(table));
    std::string header;
    while (std::cin >> header) {
        if (header == "END")
            return 0;
        char* end = nullptr;
        const double time = std::strtod(header.c_str(), &end);
        if (end == header.c_str() || *end != '\0' || !std::isfinite(time) || time < 0)
            return 0;
        sol.now = time;
        int events = -1;
        if (!(std::cin >> events) || events < 0)
            return 0;
        std::vector<int> fin;
        for (int i = 0; i < events; ++i) {
            if (!sol.read_event(std::cin, fin))
                return 0;
        }
        if (!sol.finish_frame(fin))
            return 0;
        const std::vector<std::string> ans = sol.work();
        std::cout << ans.size() << "\n";
        for (const std::string& task : ans)
            std::cout << task << "\n";
        std::cout << std::flush;
        if (!std::cout)
            return 0;
    }
    return 0;
}