Drop7 Research
approaches/constructive-reservoir/tail-survival-cem/tail-survival-cem.cppC++1,377 lines · 58.8 KB
// Runs tail-focused complete-game CEM for the fixed public phase evaluator.
//
// It preserves the 165-weight public policy and the exact D3 /
// internal-width-two / three-stratum selective expectimax mechanism, while
// ranking complete-game CRN batches with a survival-curve utility fixed before
// evaluation.  No proxy labels or private headless metadata enter a decision.

#pragma push_macro("main")
#undef main
#define main drop7_evo_public_policy_frozen_entrypoint
#include "../../heuristic-search/evolved-public-policy/evo-public-policy.cpp"
#pragma pop_macro("main")

#include <array>
#include <atomic>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <exception>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <limits>
#include <mutex>
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <vector>

#if defined(__APPLE__) || defined(__linux__)
#include <sys/resource.h>
#endif

namespace drop7::tail_survival_cem {

namespace evo = drop7::evo_public_policy;

using Clock = std::chrono::steady_clock;
using GameResult = evo::GameResult;
using Weights = evo::Weights;

// Frozen inputs.
constexpr std::string_view kInputCheckpoint =
    "/tmp/drop7-evo-public-phase-v2.bin";
constexpr std::string_view kInputCheckpointSha256 =
    "d3de888162a02b658e8ebcbb10091022a7539a4d6917ac9218b45c53be1ae10a";
constexpr std::uint64_t kInputFingerprint = 0xbe99'd8ca'57c6'4ea2ull;
constexpr int kInputStoredSamples = 7;
constexpr std::string_view kInputSourceSha256 =
    "939298e1616f2ebbf76297439006db19f8e2c7d95cd2ab26c53cd30969bce1c3";
constexpr std::string_view kBehaviorSha256 =
    "e5e81fa103589a9a911b6019a15aa48339c78ae2460ea0b0df4b0f66d59f27df";
constexpr std::string_view kEngineSha256 =
    "b6dcde5f40dc39c6931b9a88e42bb351acd6fadaddd1e07691c41a82e44f3090";

// Frozen selective expectimax configuration.  chooseSearchAction evaluates
// every legal root; width applies only below the root.
constexpr int kSearchDepth = 3;
constexpr int kInternalWidth = 2;
constexpr int kStrata = 3;
constexpr int kMaximumMoves = 500;

// Frozen diagonal-CEM schedule and bounds.
constexpr int kGenerations = 32;
constexpr int kPopulation = 33;
constexpr int kElite = 8;
constexpr int kBatchGames = 32;
constexpr int kTournamentGames = 256;
constexpr int kThreads = 8;
constexpr double kMinimumWeight = -120.0;
constexpr double kMaximumWeight = 40.0;
constexpr double kMeanRetention = 0.25;
constexpr double kEliteMeanRate = 0.75;
constexpr double kSigmaRetention = 0.30;
constexpr double kEliteSigmaRate = 0.70;
constexpr double kMinimumSigma = 0.025;
constexpr double kMaximumSigma = 6.0;
constexpr std::uint64_t kOptimizerSeed = 0x7461'696c'2d63'656dull;

// Exact seed partitions.  Preflight can read only the documented,
// previously evaluated mechanism-ablation replay; it is not fitting evidence.
constexpr std::uint32_t kReplayStart = 0x3d51'0900u;
constexpr std::uint32_t kReplayEnd = 0x3d51'0907u;
constexpr std::uint32_t kFittingAllowStart = 0x3d74'0000u;
constexpr std::uint32_t kFittingAllowEnd = 0x3d74'ffffu;
constexpr std::uint32_t kTournamentStart = 0x3d75'0000u;
constexpr std::uint32_t kTournamentEnd = 0x3d75'00ffu;
constexpr std::uint32_t kStageAStart = 0x3d76'0000u;
constexpr std::uint32_t kStageAEnd = 0x3d76'001fu;

// Preregistered robust survival-curve utility.  A first isolated milestone
// hit receives only 35% of its ordinary rate; the remaining 65% is unlocked
// by repeated hits.  Thus a lucky outlier cannot dominate a 32-game batch.
constexpr std::array<int, 5> kMilestones{{75, 100, 150, 225, 300}};
constexpr std::array<double, 5> kMilestoneWeights{{24.0, 40.0, 80.0,
                                                    150.0, 240.0}};
constexpr double kFirstHitRateWeight = 0.35;
constexpr double kRepeatedHitRateWeight = 0.65;
constexpr double kMeanSurvivalWeight = 0.55;
constexpr double kLowerQuartileSurvivalWeight = 0.45;
constexpr double kMeanScoreWeight = 0.55;
constexpr double kLowerQuartileScoreWeight = 0.45;
constexpr double kSurvivalCoreWeight = 0.55;
constexpr double kCorrectedScoreCoreWeight = 0.15;

// Frozen tournament admission.  The first four checks are externally set;
// the last four define "material robust improvement" before Stage-A evaluation.
constexpr double kTournamentScoreGate = 500'000.0;
constexpr double kTournamentMovesGate = 150.0;
constexpr double kTournamentClearsGate = 2.15;
constexpr double kTournamentRevealsGate = 1.18;
constexpr double kTournamentObjectiveDeltaGate = 25.0;
constexpr double kTournamentMilestoneDeltaGate = 25.0;
constexpr double kTournamentMilestoneRateDelta = 0.02;
constexpr int kTournamentImprovedMilestonesGate = 3;
constexpr double kTournamentHighTailRateDelta = 0.03;

// Frozen Stage-A gate.
constexpr double kStageAScoreGate = 700'000.0;
constexpr double kStageAMovesGate = 200.0;
constexpr double kStageABottomQuartileMovesGate = 100.0;
constexpr double kStageAClearsGate = 2.20;
constexpr double kStageARevealsGate = 1.20;
constexpr int kStageAJointWinsGate = 20;

constexpr double kWallLimitSeconds = 75.0 * 60.0;
constexpr std::uint64_t kRssLimitBytes = 256ull * 1024ull * 1024ull;
constexpr double kProjectionSafetyFactor = 1.20;

constexpr std::string_view kOutputCheckpoint =
    "/tmp/drop7-tail-survival-cem.bin";
constexpr std::string_view kOutputGolden =
    "/tmp/drop7-tail-survival-cem-golden.json";
constexpr std::string_view kPreflightArtifact =
    "/tmp/drop7-tail-survival-cem-preflight-admitted.json";
constexpr std::string_view kOutputArtifact =
    "/tmp/drop7-tail-survival-cem.json";

static_assert(evo::kFeatureCount == 165);
static_assert(evo::kBaseFeatureCount == 33);
static_assert(evo::kPhaseCount == 5);
static_assert(evo::kCheckpointVersion == 2);
static_assert(kPopulation % 2 == 1 && kPopulation >= 5);
static_assert(kElite >= 2 && kElite < kPopulation);
static_assert(kGenerations >= 32 && kGenerations <= 48);
static_assert(kGenerations * kBatchGames <=
              static_cast<int>(kFittingAllowEnd - kFittingAllowStart + 1));
static_assert(kTournamentGames ==
              static_cast<int>(kTournamentEnd - kTournamentStart + 1));
static_assert(kStageAEnd - kStageAStart + 1 == 32);
static_assert((kFittingAllowStart >> 24) == 0x3du);
static_assert((kTournamentStart >> 24) == 0x3du);
static_assert((kStageAStart >> 24) == 0x3du);
static_assert(kSearchDepth == 3 && kInternalWidth == 2 && kStrata == 3);
static_assert(kMaximumMoves == 500 && kThreads == 8);

enum class SeedPurpose { kReplay, kFitting, kTournament, kStageA };

struct SeedAudit {
  std::atomic<std::uint64_t> replay_games{0};
  std::atomic<std::uint64_t> fitting_games{0};
  std::atomic<std::uint64_t> tournament_games{0};
  std::atomic<std::uint64_t> stage_a_games{0};
  std::atomic<bool> other_seed_opened{false};
  std::atomic<bool> forbidden_prefix_opened{false};
};

SeedAudit g_seed_audit;

void resetSeedAudit() {
  g_seed_audit.replay_games.store(0);
  g_seed_audit.fitting_games.store(0);
  g_seed_audit.tournament_games.store(0);
  g_seed_audit.stage_a_games.store(0);
  g_seed_audit.other_seed_opened.store(false);
  g_seed_audit.forbidden_prefix_opened.store(false);
}

bool seedAllowed(std::uint32_t seed, SeedPurpose purpose) {
  switch (purpose) {
    case SeedPurpose::kReplay:
      return seed >= kReplayStart && seed <= kReplayEnd;
    case SeedPurpose::kFitting:
      return seed >= kFittingAllowStart && seed <= kFittingAllowEnd;
    case SeedPurpose::kTournament:
      return seed >= kTournamentStart && seed <= kTournamentEnd;
    case SeedPurpose::kStageA:
      return seed >= kStageAStart && seed <= kStageAEnd;
  }
  return false;
}

void auditSeed(std::uint32_t seed, SeedPurpose purpose) {
  const std::uint32_t prefix = seed >> 24;
  if (prefix == 0x4du || prefix == 0x7du || prefix == 0xd7u) {
    g_seed_audit.forbidden_prefix_opened.store(true);
    throw std::runtime_error("protected Drop7 seed prefix requested");
  }
  if (!seedAllowed(seed, purpose)) {
    g_seed_audit.other_seed_opened.store(true);
    throw std::runtime_error("Drop7 seed outside preregistered lane");
  }
  switch (purpose) {
    case SeedPurpose::kReplay:
      ++g_seed_audit.replay_games;
      break;
    case SeedPurpose::kFitting:
      ++g_seed_audit.fitting_games;
      break;
    case SeedPurpose::kTournament:
      ++g_seed_audit.tournament_games;
      break;
    case SeedPurpose::kStageA:
      ++g_seed_audit.stage_a_games;
      break;
  }
}

std::uint64_t peakRssBytes() {
#if defined(__APPLE__) || defined(__linux__)
  struct rusage usage {};
  if (getrusage(RUSAGE_SELF, &usage) != 0) return 0;
#if defined(__APPLE__)
  return static_cast<std::uint64_t>(usage.ru_maxrss);
#else
  return static_cast<std::uint64_t>(usage.ru_maxrss) * 1024ull;
#endif
#else
  return 0;
#endif
}

constexpr std::array<std::uint32_t, 64> kSha256Constants{{
    0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u,
    0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
    0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u,
    0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u,
    0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu,
    0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
    0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u,
    0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u,
    0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u,
    0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u,
    0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u,
    0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
    0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u,
    0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u,
    0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u,
    0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u,
}};

std::string sha256(std::string_view source) {
  std::vector<std::uint8_t> message(source.begin(), source.end());
  const std::uint64_t bit_length =
      static_cast<std::uint64_t>(message.size()) * 8u;
  message.push_back(0x80u);
  while (message.size() % 64 != 56) message.push_back(0u);
  for (int byte = 7; byte >= 0; --byte) {
    message.push_back(
        static_cast<std::uint8_t>((bit_length >> (byte * 8)) & 0xffu));
  }
  std::array<std::uint32_t, 8> hash{{
      0x6a09e667u, 0xbb67ae85u, 0x3c6ef372u, 0xa54ff53au,
      0x510e527fu, 0x9b05688cu, 0x1f83d9abu, 0x5be0cd19u,
  }};
  for (std::size_t offset = 0; offset < message.size(); offset += 64) {
    std::array<std::uint32_t, 64> words{};
    for (int word = 0; word < 16; ++word) {
      const std::size_t begin = offset + static_cast<std::size_t>(word * 4);
      words[word] = (static_cast<std::uint32_t>(message[begin]) << 24) |
                    (static_cast<std::uint32_t>(message[begin + 1]) << 16) |
                    (static_cast<std::uint32_t>(message[begin + 2]) << 8) |
                    static_cast<std::uint32_t>(message[begin + 3]);
    }
    for (int word = 16; word < 64; ++word) {
      const std::uint32_t s0 = std::rotr(words[word - 15], 7) ^
                               std::rotr(words[word - 15], 18) ^
                               (words[word - 15] >> 3);
      const std::uint32_t s1 = std::rotr(words[word - 2], 17) ^
                               std::rotr(words[word - 2], 19) ^
                               (words[word - 2] >> 10);
      words[word] = words[word - 16] + s0 + words[word - 7] + s1;
    }
    std::uint32_t a = hash[0];
    std::uint32_t b = hash[1];
    std::uint32_t c = hash[2];
    std::uint32_t d = hash[3];
    std::uint32_t e = hash[4];
    std::uint32_t f = hash[5];
    std::uint32_t g = hash[6];
    std::uint32_t h = hash[7];
    for (int round = 0; round < 64; ++round) {
      const std::uint32_t upper = std::rotr(e, 6) ^ std::rotr(e, 11) ^
                                  std::rotr(e, 25);
      const std::uint32_t choose = (e & f) ^ (~e & g);
      const std::uint32_t first =
          h + upper + choose + kSha256Constants[round] + words[round];
      const std::uint32_t lower = std::rotr(a, 2) ^ std::rotr(a, 13) ^
                                  std::rotr(a, 22);
      const std::uint32_t majority = (a & b) ^ (a & c) ^ (b & c);
      const std::uint32_t second = lower + majority;
      h = g;
      g = f;
      f = e;
      e = d + first;
      d = c;
      c = b;
      b = a;
      a = first + second;
    }
    hash[0] += a;
    hash[1] += b;
    hash[2] += c;
    hash[3] += d;
    hash[4] += e;
    hash[5] += f;
    hash[6] += g;
    hash[7] += h;
  }
  constexpr char kDigits[] = "0123456789abcdef";
  std::string result;
  result.reserve(64);
  for (const std::uint32_t value : hash) {
    for (int nibble = 7; nibble >= 0; --nibble) {
      result.push_back(kDigits[(value >> (nibble * 4)) & 0x0fu]);
    }
  }
  return result;
}

std::string readWholeFile(std::string_view path) {
  std::ifstream input(std::string(path), std::ios::binary | std::ios::ate);
  if (!input) throw std::runtime_error("unable to read frozen input");
  const std::streampos end = input.tellg();
  if (end < 0) throw std::runtime_error("invalid frozen input size");
  std::string result(static_cast<std::size_t>(end), '\0');
  input.seekg(0);
  input.read(result.data(), static_cast<std::streamsize>(result.size()));
  if (!input) throw std::runtime_error("frozen input read failed");
  return result;
}

struct TailEvaluation {
  std::vector<GameResult> games;
  double objective = -std::numeric_limits<double>::infinity();
  double mean_score = 0.0;
  double mean_moves = 0.0;
  double lower_quartile_score = 0.0;
  double lower_quartile_moves = 0.0;
  double clears_per_move = 0.0;
  double reveals_per_move = 0.0;
  double survival_core = 0.0;
  double corrected_score_core = 0.0;
  double milestone_utility = 0.0;
  std::array<int, kMilestones.size()> milestone_hits{};
  std::array<double, kMilestones.size()> milestone_rates{};
  std::array<double, kMilestones.size()> robust_milestone_rates{};
  int censored = 0;
  double seconds = 0.0;
};

double robustMilestoneRate(int hits, int games) {
  if (hits <= 0 || games <= 0) return 0.0;
  const double ordinary = static_cast<double>(hits) / games;
  const double repeated = hits > 1 && games > 1
                              ? static_cast<double>(hits - 1) / (games - 1)
                              : 0.0;
  return kFirstHitRateWeight * ordinary +
         kRepeatedHitRateWeight * repeated;
}

void summarize(TailEvaluation& evaluation) {
  if (evaluation.games.empty()) {
    throw std::invalid_argument("cannot summarize an empty game batch");
  }
  evaluation.censored = 0;
  evaluation.milestone_hits.fill(0);
  std::vector<double> scores;
  std::vector<double> moves;
  scores.reserve(evaluation.games.size());
  moves.reserve(evaluation.games.size());
  double total_score = 0.0;
  double total_moves = 0.0;
  double total_clears = 0.0;
  double total_reveals = 0.0;
  for (const GameResult& game : evaluation.games) {
    total_score += static_cast<double>(game.score);
    total_moves += static_cast<double>(game.moves);
    total_clears += static_cast<double>(game.clears);
    total_reveals += static_cast<double>(game.reveals);
    scores.push_back(static_cast<double>(game.score));
    moves.push_back(static_cast<double>(game.moves));
    if (!game.terminal) ++evaluation.censored;
    for (std::size_t index = 0; index < kMilestones.size(); ++index) {
      if (game.moves >= kMilestones[index]) {
        ++evaluation.milestone_hits[index];
      }
    }
  }
  const double count = static_cast<double>(evaluation.games.size());
  evaluation.mean_score = total_score / count;
  evaluation.mean_moves = total_moves / count;
  evaluation.lower_quartile_score = evo::lowerFractionMean(scores, 0.25);
  evaluation.lower_quartile_moves = evo::lowerFractionMean(moves, 0.25);
  evaluation.clears_per_move =
      total_moves > 0.0 ? total_clears / total_moves : 0.0;
  evaluation.reveals_per_move =
      total_moves > 0.0 ? total_reveals / total_moves : 0.0;
  evaluation.survival_core =
      kMeanSurvivalWeight * evaluation.mean_moves +
      kLowerQuartileSurvivalWeight * evaluation.lower_quartile_moves;
  evaluation.corrected_score_core =
      kMeanScoreWeight * (evaluation.mean_score / kLevelBonus) +
      kLowerQuartileScoreWeight *
          (evaluation.lower_quartile_score / kLevelBonus);
  evaluation.milestone_utility = 0.0;
  for (std::size_t index = 0; index < kMilestones.size(); ++index) {
    evaluation.milestone_rates[index] =
        static_cast<double>(evaluation.milestone_hits[index]) / count;
    evaluation.robust_milestone_rates[index] = robustMilestoneRate(
        evaluation.milestone_hits[index],
        static_cast<int>(evaluation.games.size()));
    evaluation.milestone_utility +=
        kMilestoneWeights[index] * evaluation.robust_milestone_rates[index];
  }
  evaluation.objective =
      kSurvivalCoreWeight * evaluation.survival_core +
      kCorrectedScoreCoreWeight * evaluation.corrected_score_core +
      evaluation.milestone_utility;
}

GameResult playTailGame(std::uint32_t seed, const Weights& weights,
                        SeedPurpose purpose) {
  auditSeed(seed, purpose);
  return evo::playSearchGame(seed, weights, kStrata, kMaximumMoves,
                             kSearchDepth, kInternalWidth);
}

TailEvaluation evaluate(const Weights& weights, std::uint32_t seed_start,
                        int games, SeedPurpose purpose) {
  if (games < 1) throw std::invalid_argument("game count must be positive");
  TailEvaluation result;
  result.games.reserve(static_cast<std::size_t>(games));
  const auto started = Clock::now();
  for (int game = 0; game < games; ++game) {
    result.games.push_back(playTailGame(
        seed_start + static_cast<std::uint32_t>(game), weights, purpose));
  }
  result.seconds =
      std::chrono::duration<double>(Clock::now() - started).count();
  summarize(result);
  return result;
}

struct Candidate {
  Weights weights{};
  TailEvaluation evaluation;
  std::string provenance;
  int generation = -1;
};

void evaluatePopulation(std::vector<Candidate>& candidates,
                        std::uint32_t seed_start, int games,
                        SeedPurpose purpose) {
  std::atomic<std::size_t> next{0};
  std::atomic<bool> stopped{false};
  std::exception_ptr failure;
  std::mutex failure_mutex;
  const int worker_count =
      std::min(kThreads, static_cast<int>(candidates.size()));
  std::vector<std::thread> workers;
  workers.reserve(static_cast<std::size_t>(worker_count));
  for (int worker = 0; worker < worker_count; ++worker) {
    workers.emplace_back([&]() {
      while (!stopped.load()) {
        const std::size_t index = next.fetch_add(1);
        if (index >= candidates.size()) break;
        try {
          candidates[index].evaluation =
              evaluate(candidates[index].weights, seed_start, games, purpose);
        } catch (...) {
          stopped.store(true);
          std::lock_guard<std::mutex> lock(failure_mutex);
          if (!failure) failure = std::current_exception();
        }
      }
    });
  }
  for (std::thread& worker : workers) worker.join();
  if (failure) std::rethrow_exception(failure);
}

TailEvaluation runReplayBenchmark(const Weights& weights) {
  TailEvaluation aggregate;
  constexpr int replay_games =
      static_cast<int>(kReplayEnd - kReplayStart + 1);
  // Production workers evaluate long candidate batches.  Give every worker
  // the same complete, already-documented eight-game replay so thread startup
  // and cold caches cannot dominate the 50k-game resource projection.
  aggregate.games.resize(static_cast<std::size_t>(kThreads * replay_games));
  const auto started = Clock::now();
  std::exception_ptr failure;
  std::mutex failure_mutex;
  std::vector<std::thread> workers;
  workers.reserve(kThreads);
  for (int worker = 0; worker < kThreads; ++worker) {
    workers.emplace_back([&, worker]() {
      try {
        for (int game = 0; game < replay_games; ++game) {
          const std::size_t index = static_cast<std::size_t>(
              worker * replay_games + game);
          aggregate.games[index] = playTailGame(
              kReplayStart + static_cast<std::uint32_t>(game), weights,
              SeedPurpose::kReplay);
        }
      } catch (...) {
        std::lock_guard<std::mutex> lock(failure_mutex);
        if (!failure) failure = std::current_exception();
      }
    });
  }
  for (std::thread& worker : workers) worker.join();
  if (failure) std::rethrow_exception(failure);
  aggregate.seconds =
      std::chrono::duration<double>(Clock::now() - started).count();
  summarize(aggregate);
  return aggregate;
}

struct TournamentGate {
  bool mean_score = false;
  bool mean_moves = false;
  bool clears = false;
  bool reveals = false;
  bool objective_delta = false;
  bool milestone_delta = false;
  bool improved_milestones = false;
  bool high_tail = false;
  int materially_improved_milestones = 0;
  double objective_improvement = 0.0;
  double milestone_improvement = 0.0;
  bool passed = false;
};

TournamentGate tournamentGate(const TailEvaluation& candidate,
                              const TailEvaluation& inherited) {
  TournamentGate result;
  result.mean_score = candidate.mean_score >= kTournamentScoreGate;
  result.mean_moves = candidate.mean_moves >= kTournamentMovesGate;
  result.clears = candidate.clears_per_move >= kTournamentClearsGate;
  result.reveals = candidate.reveals_per_move >= kTournamentRevealsGate;
  result.objective_improvement = candidate.objective - inherited.objective;
  result.milestone_improvement =
      candidate.milestone_utility - inherited.milestone_utility;
  result.objective_delta =
      result.objective_improvement >= kTournamentObjectiveDeltaGate;
  result.milestone_delta =
      result.milestone_improvement >= kTournamentMilestoneDeltaGate;
  for (std::size_t index = 0; index < kMilestones.size(); ++index) {
    if (candidate.milestone_rates[index] >=
        inherited.milestone_rates[index] + kTournamentMilestoneRateDelta) {
      ++result.materially_improved_milestones;
    }
  }
  result.improved_milestones =
      result.materially_improved_milestones >=
      kTournamentImprovedMilestonesGate;
  result.high_tail =
      candidate.milestone_rates[2] >=
      inherited.milestone_rates[2] + kTournamentHighTailRateDelta;
  result.passed = result.mean_score && result.mean_moves && result.clears &&
                  result.reveals && result.objective_delta &&
                  result.milestone_delta && result.improved_milestones &&
                  result.high_tail;
  return result;
}

struct StageAGate {
  bool mean_score = false;
  bool mean_moves = false;
  bool bottom_quartile_moves = false;
  bool clears = false;
  bool reveals = false;
  bool joint_wins = false;
  int joint_win_count = 0;
  bool passed = false;
};

StageAGate stageAGate(const TailEvaluation& candidate,
                      const TailEvaluation& inherited) {
  if (candidate.games.size() != inherited.games.size()) {
    throw std::invalid_argument("paired Stage-A batches differ in size");
  }
  StageAGate result;
  result.mean_score = candidate.mean_score >= kStageAScoreGate;
  result.mean_moves = candidate.mean_moves >= kStageAMovesGate;
  result.bottom_quartile_moves =
      candidate.lower_quartile_moves >= kStageABottomQuartileMovesGate;
  result.clears = candidate.clears_per_move >= kStageAClearsGate;
  result.reveals = candidate.reveals_per_move >= kStageARevealsGate;
  for (std::size_t game = 0; game < candidate.games.size(); ++game) {
    if (candidate.games[game].score > inherited.games[game].score &&
        candidate.games[game].moves > inherited.games[game].moves) {
      ++result.joint_win_count;
    }
  }
  result.joint_wins = result.joint_win_count >= kStageAJointWinsGate;
  result.passed = result.mean_score && result.mean_moves &&
                  result.bottom_quartile_moves && result.clears &&
                  result.reveals && result.joint_wins;
  return result;
}

struct Progress {
  int generation = 0;
  double best_objective = 0.0;
  double best_score = 0.0;
  double best_moves = 0.0;
  double best_lower_quartile_moves = 0.0;
  double best_milestone_utility = 0.0;
  std::array<int, kMilestones.size()> hits{};
  double elapsed_seconds = 0.0;
  double projected_seconds = 0.0;
  std::uint64_t peak_rss_bytes = 0;
};

void checkResources(double elapsed_seconds, double projected_seconds) {
  if (elapsed_seconds > kWallLimitSeconds ||
      projected_seconds > kWallLimitSeconds ||
      peakRssBytes() > kRssLimitBytes) {
    throw std::runtime_error("tail CEM resource projection failed");
  }
}

void writeMetric(std::ostream& output, const TailEvaluation& evaluation) {
  output << std::setprecision(12)
         << "{\"objective\":" << evaluation.objective
         << ",\"meanScore\":" << evaluation.mean_score
         << ",\"meanMoves\":" << evaluation.mean_moves
         << ",\"lowerQuartileScore\":"
         << evaluation.lower_quartile_score
         << ",\"lowerQuartileMoves\":"
         << evaluation.lower_quartile_moves
         << ",\"clearsPerMove\":" << evaluation.clears_per_move
         << ",\"revealsPerMove\":" << evaluation.reveals_per_move
         << ",\"survivalCore\":" << evaluation.survival_core
         << ",\"correctedScoreCore\":"
         << evaluation.corrected_score_core
         << ",\"milestoneUtility\":" << evaluation.milestone_utility
         << ",\"censored\":" << evaluation.censored
         << ",\"milestones\":[";
  for (std::size_t index = 0; index < kMilestones.size(); ++index) {
    if (index != 0) output << ',';
    output << "{\"moves\":" << kMilestones[index]
           << ",\"hits\":" << evaluation.milestone_hits[index]
           << ",\"rate\":" << evaluation.milestone_rates[index]
           << ",\"robustRate\":"
           << evaluation.robust_milestone_rates[index] << '}';
  }
  output << "]}";
}

void writeGames(std::ostream& output, const TailEvaluation& evaluation) {
  output << '[';
  for (std::size_t index = 0; index < evaluation.games.size(); ++index) {
    if (index != 0) output << ',';
    const GameResult& game = evaluation.games[index];
    output << "{\"seed\":" << game.seed << ",\"score\":" << game.score
           << ",\"moves\":" << game.moves << ",\"clears\":"
           << game.clears << ",\"reveals\":" << game.reveals
           << ",\"maximumChain\":" << game.maximum_chain
           << ",\"terminal\":" << (game.terminal ? "true" : "false")
           << '}';
  }
  output << ']';
}

void writePreflight(const TailEvaluation& benchmark,
                    double projected_seconds, bool passed) {
  std::ofstream output(std::string(kPreflightArtifact),
                       std::ios::trunc);
  if (!output) throw std::runtime_error("unable to write preflight artifact");
  output << std::setprecision(12)
         << "{\n  \"format\":\"drop7-tail-survival-cem-preflight-v2\",\n"
         << "  \"input\":{\"path\":\"" << kInputCheckpoint
         << "\",\"sha256\":\"" << kInputCheckpointSha256
         << "\",\"fingerprint\":\"0x" << std::hex << kInputFingerprint
         << std::dec << "\",\"storedSamples\":" << kInputStoredSamples
         << ",\"bitExact\":true},\n"
         << "  \"search\":{\"depth\":" << kSearchDepth
         << ",\"internalWidth\":" << kInternalWidth
         << ",\"strata\":" << kStrata
         << ",\"allLegalRootActions\":true},\n"
         << "  \"utility\":{\"formula\":\"0.55*(0.55*meanMoves+0.45*lowerQuartileMoves)+0.15*(0.55*meanScore/17000+0.45*lowerQuartileScore/17000)+sum(milestoneWeight*robustRate)\",\"robustRate\":\"0.35*hits/n+0.65*max(0,hits-1)/max(1,n-1)\",\"milestones\":[75,100,150,225,300],\"weights\":[24,40,80,150,240]},\n"
         << "  \"schedule\":{\"generations\":" << kGenerations
         << ",\"population\":" << kPopulation << ",\"elite\":"
         << kElite << ",\"gamesPerCandidate\":" << kBatchGames
         << ",\"threads\":" << kThreads << ",\"maximumMoves\":"
         << kMaximumMoves << ",\"tournamentGames\":"
         << kTournamentGames << ",\"archiveCandidates\":"
         << (1 + 2 * kGenerations) << "},\n"
         << "  \"bounds\":{\"weights\":[" << kMinimumWeight << ','
         << kMaximumWeight << "],\"sigma\":[" << kMinimumSigma << ','
         << kMaximumSigma << "],\"terminalWeightsFixed\":-100},\n"
         << "  \"seedSeal\":{\"replayOnly\":\"0x3d510900..0x3d510907\",\"fittingAllowlist\":\"0x3d740000..0x3d74ffff unopened\",\"tournament\":\"0x3d750000..0x3d7500ff unopened\",\"stageA\":\"0x3d760000..0x3d76001f unopened\",\"forbidden\":\"0x4d/0x7d/0xd7 unopened\"},\n"
         << "  \"benchmark\":";
  writeMetric(output, benchmark);
  output << ",\n  \"performance\":{\"replayWallSeconds\":"
         << benchmark.seconds << ",\"projectedWorstCaseWallSeconds\":"
         << projected_seconds << ",\"wallLimitSeconds\":"
         << kWallLimitSeconds << ",\"peakRssBytes\":" << peakRssBytes()
         << ",\"rssLimitBytes\":" << kRssLimitBytes << "},\n"
         << "  \"freshSeedCounts\":{\"fitting\":"
         << g_seed_audit.fitting_games.load() << ",\"tournament\":"
         << g_seed_audit.tournament_games.load() << ",\"stageA\":"
         << g_seed_audit.stage_a_games.load() << "},\n"
         << "  \"passed\":" << (passed ? "true" : "false") << "\n}\n";
  if (!output) throw std::runtime_error("preflight artifact write failed");
}

Weights loadFrozenInput() {
  const std::string contents = readWholeFile(kInputCheckpoint);
  if (contents.size() != 1'352 || sha256(contents) != kInputCheckpointSha256) {
    throw std::runtime_error("frozen phase-policy checkpoint changed");
  }
  auto [weights, stored_samples] =
      evo::loadCheckpoint(std::string(kInputCheckpoint));
  if (stored_samples != kInputStoredSamples ||
      evo::fingerprint(weights) != kInputFingerprint) {
    throw std::runtime_error("frozen phase-policy checkpoint identity mismatch");
  }
  return weights;
}

double projectedWorstCaseSeconds(double replay_seconds,
                                 std::size_t replay_game_executions) {
  constexpr std::uint64_t fitting_games =
      static_cast<std::uint64_t>(kGenerations) * kPopulation * kBatchGames;
  constexpr std::uint64_t tournament_games =
      static_cast<std::uint64_t>(1 + 2 * kGenerations) * kTournamentGames;
  constexpr std::uint64_t conditional_stage_games = 2u * 32u;
  constexpr std::uint64_t total_games =
      fitting_games + tournament_games + conditional_stage_games;
  return replay_seconds / static_cast<double>(replay_game_executions) *
         static_cast<double>(total_games) * kProjectionSafetyFactor;
}

TailEvaluation runPreflight() {
  resetSeedAudit();
  const Weights weights = loadFrozenInput();
  const TailEvaluation benchmark = runReplayBenchmark(weights);
  const double projection =
      projectedWorstCaseSeconds(benchmark.seconds, benchmark.games.size());
  bool exact_replay = benchmark.games.size() == 64;
  for (int worker = 0; worker < kThreads && exact_replay; ++worker) {
    const std::size_t first = static_cast<std::size_t>(worker * 8);
    exact_replay = benchmark.games[first].seed == kReplayStart &&
                   benchmark.games[first + 7].seed == kReplayEnd;
  }
  const bool fresh_sealed = g_seed_audit.fitting_games.load() == 0 &&
                            g_seed_audit.tournament_games.load() == 0 &&
                            g_seed_audit.stage_a_games.load() == 0;
  const bool resources = projection <= kWallLimitSeconds &&
                         peakRssBytes() <= kRssLimitBytes;
  const bool passed = exact_replay && fresh_sealed && resources &&
                      !g_seed_audit.other_seed_opened.load() &&
                      !g_seed_audit.forbidden_prefix_opened.load();
  writePreflight(benchmark, projection, passed);
  std::cout << std::fixed << std::setprecision(6)
            << "TAIL_SURVIVAL_CEM_PREFLIGHT {\"replayGames\":"
            << benchmark.games.size()
            << ",\"meanScore\":" << benchmark.mean_score
            << ",\"meanMoves\":" << benchmark.mean_moves
            << ",\"wallSeconds\":" << benchmark.seconds
            << ",\"projectedWorstCaseSeconds\":" << projection
            << ",\"freshFittingSeedsOpened\":"
            << g_seed_audit.fitting_games.load()
            << ",\"tournamentSeedsOpened\":"
            << g_seed_audit.tournament_games.load()
            << ",\"stageASeedsOpened\":"
            << g_seed_audit.stage_a_games.load() << ",\"peakRssBytes\":"
            << peakRssBytes() << ",\"passed\":"
            << (passed ? "true" : "false") << "}\n";
  if (!passed) throw std::runtime_error("tail CEM preflight failed");
  return benchmark;
}

void freezeCandidate(const Weights& candidate) {
  evo::saveCheckpoint(std::string(kOutputCheckpoint), candidate, kStrata);
  auto [reloaded, stored_samples] =
      evo::loadCheckpoint(std::string(kOutputCheckpoint));
  if (stored_samples != kStrata || reloaded != candidate ||
      evo::fingerprint(reloaded) != evo::fingerprint(candidate)) {
    throw std::runtime_error("frozen tail candidate failed round trip");
  }

  State state;
  state.board = initialBoard();
  state.board[indexOf(5, 0)] = 3;
  state.board[indexOf(5, 1)] = 5;
  state.board[indexOf(5, 4)] = 4;
  state.next_disc = 6;
  state.moves_remaining = 3;
  const int action = evo::chooseSearchAction(
      state, reloaded, kSearchDepth, kInternalWidth, kStrata);
  State mirrored = state;
  mirrored.board = evo::detail::mirrorBoard(state.board);
  const int reflected = evo::chooseSearchAction(
      mirrored, reloaded, kSearchDepth, kInternalWidth, kStrata);
  const bool reflection_exact = reflected == kBoardSize - 1 - action;
  if (!reflection_exact) throw std::runtime_error("golden reflection failed");

  std::ofstream output(std::string(kOutputGolden), std::ios::trunc);
  if (!output) throw std::runtime_error("unable to write golden artifact");
  output << "{\n  \"format\":\"drop7-tail-survival-cem-golden-v1\",\n"
         << "  \"modelFingerprint\":\"0x" << std::hex
         << evo::fingerprint(reloaded) << std::dec << "\",\n"
         << "  \"search\":{\"depth\":" << kSearchDepth
         << ",\"internalWidth\":" << kInternalWidth
         << ",\"strata\":" << kStrata << "},\n"
         << "  \"fixtureAction\":" << action
         << ",\"reflectedAction\":" << reflected
         << ",\"reflectionExact\":true\n}\n";
}

void writeGate(std::ostream& output, const TournamentGate& gate) {
  output << std::setprecision(12)
         << "{\"thresholds\":{\"meanScore\":" << kTournamentScoreGate
         << ",\"meanMoves\":" << kTournamentMovesGate
         << ",\"clearsPerMove\":" << kTournamentClearsGate
         << ",\"revealsPerMove\":" << kTournamentRevealsGate
         << ",\"objectiveDelta\":" << kTournamentObjectiveDeltaGate
         << ",\"milestoneUtilityDelta\":"
         << kTournamentMilestoneDeltaGate
         << ",\"improvedMilestones\":"
         << kTournamentImprovedMilestonesGate
         << ",\"highTail150RateDelta\":"
         << kTournamentHighTailRateDelta << "},\"observed\":{"
         << "\"objectiveDelta\":" << gate.objective_improvement
         << ",\"milestoneUtilityDelta\":" << gate.milestone_improvement
         << ",\"materiallyImprovedMilestones\":"
         << gate.materially_improved_milestones << "},\"checks\":{"
         << "\"meanScore\":" << (gate.mean_score ? "true" : "false")
         << ",\"meanMoves\":" << (gate.mean_moves ? "true" : "false")
         << ",\"clears\":" << (gate.clears ? "true" : "false")
         << ",\"reveals\":" << (gate.reveals ? "true" : "false")
         << ",\"objectiveDelta\":"
         << (gate.objective_delta ? "true" : "false")
         << ",\"milestoneDelta\":"
         << (gate.milestone_delta ? "true" : "false")
         << ",\"improvedMilestones\":"
         << (gate.improved_milestones ? "true" : "false")
         << ",\"highTail\":" << (gate.high_tail ? "true" : "false")
         << "},\"passed\":" << (gate.passed ? "true" : "false") << '}';
}

void writeGate(std::ostream& output, const StageAGate& gate) {
  output << std::setprecision(12)
         << "{\"thresholds\":{\"meanScore\":" << kStageAScoreGate
         << ",\"meanMoves\":" << kStageAMovesGate
         << ",\"bottomQuartileMoves\":"
         << kStageABottomQuartileMovesGate << ",\"clearsPerMove\":"
         << kStageAClearsGate << ",\"revealsPerMove\":"
         << kStageARevealsGate << ",\"jointWins\":"
         << kStageAJointWinsGate << "},\"observed\":{\"jointWins\":"
         << gate.joint_win_count << "},\"checks\":{\"meanScore\":"
         << (gate.mean_score ? "true" : "false") << ",\"meanMoves\":"
         << (gate.mean_moves ? "true" : "false")
         << ",\"bottomQuartileMoves\":"
         << (gate.bottom_quartile_moves ? "true" : "false")
         << ",\"clears\":" << (gate.clears ? "true" : "false")
         << ",\"reveals\":" << (gate.reveals ? "true" : "false")
         << ",\"jointWins\":" << (gate.joint_wins ? "true" : "false")
         << "},\"passed\":" << (gate.passed ? "true" : "false") << '}';
}

void writeArtifact(const std::vector<Candidate>& finalists,
                   const TailEvaluation& inherited,
                   const Candidate& champion,
                   const TournamentGate& tournament_gate,
                   const std::vector<Progress>& progress,
                   bool stage_opened,
                   const TailEvaluation* stage_candidate,
                   const TailEvaluation* stage_inherited,
                   const StageAGate* stage_gate,
                   double wall_seconds) {
  std::ofstream output(std::string(kOutputArtifact), std::ios::trunc);
  if (!output) throw std::runtime_error("unable to write tail CEM artifact");
  output << std::setprecision(12)
         << "{\n  \"format\":\"drop7-tail-survival-cem-v1\",\n"
         << "  \"lockedInputs\":{\"checkpoint\":\"" << kInputCheckpoint
         << "\",\"checkpointSha256\":\"" << kInputCheckpointSha256
         << "\",\"checkpointFingerprint\":\"0x" << std::hex
         << kInputFingerprint << std::dec << "\",\"sourceSha256\":\""
         << kInputSourceSha256 << "\",\"behaviorSha256\":\""
         << kBehaviorSha256 << "\",\"engineSha256\":\""
         << kEngineSha256 << "\"},\n"
         << "  \"search\":{\"depth\":" << kSearchDepth
         << ",\"internalWidth\":" << kInternalWidth
         << ",\"strata\":" << kStrata
         << ",\"allLegalRootActions\":true},\n"
         << "  \"objectivePreregistered\":true,\n"
         << "  \"training\":{\"generations\":" << kGenerations
         << ",\"population\":" << kPopulation << ",\"elite\":"
         << kElite << ",\"batchGames\":" << kBatchGames
         << ",\"maximumMoves\":" << kMaximumMoves
         << ",\"fittingAllowlist\":\"0x3d740000..0x3d74ffff\",\"usedDistinctSeeds\":\"0x3d740000..0x3d7403ff\",\"candidateGames\":"
         << static_cast<std::uint64_t>(kGenerations) * kPopulation *
                kBatchGames
         << ",\"progress\":[";
  for (std::size_t index = 0; index < progress.size(); ++index) {
    if (index != 0) output << ',';
    const Progress& item = progress[index];
    output << "{\"generation\":" << item.generation
           << ",\"bestObjective\":" << item.best_objective
           << ",\"bestScore\":" << item.best_score
           << ",\"bestMoves\":" << item.best_moves
           << ",\"bestLowerQuartileMoves\":"
           << item.best_lower_quartile_moves
           << ",\"bestMilestoneUtility\":"
           << item.best_milestone_utility << ",\"hits\":[";
    for (std::size_t milestone = 0; milestone < item.hits.size(); ++milestone) {
      if (milestone != 0) output << ',';
      output << item.hits[milestone];
    }
    output << "],\"elapsedSeconds\":" << item.elapsed_seconds
           << ",\"projectedSeconds\":" << item.projected_seconds
           << ",\"peakRssBytes\":" << item.peak_rss_bytes << '}';
  }
  output << "]},\n  \"tournament\":{\"seedLane\":\"0x3d750000..0x3d7500ff\",\"gamesPerFinalist\":"
         << kTournamentGames << ",\"finalistCount\":" << finalists.size()
         << ",\"allStartMeansAndChampionsReranked\":true,\"startingPolicy\":";
  writeMetric(output, inherited);
  output << ",\"champion\":{\"provenance\":\"" << champion.provenance
         << "\",\"generation\":" << champion.generation
         << ",\"fingerprint\":\"0x" << std::hex
         << evo::fingerprint(champion.weights) << std::dec
         << "\",\"metrics\":";
  writeMetric(output, champion.evaluation);
  output << "},\"admissionGate\":";
  writeGate(output, tournament_gate);
  output << ",\"finalists\":[";
  for (std::size_t index = 0; index < finalists.size(); ++index) {
    if (index != 0) output << ',';
    const Candidate& finalist = finalists[index];
    output << "{\"rank\":" << index + 1 << ",\"provenance\":\""
           << finalist.provenance << "\",\"generation\":"
           << finalist.generation << ",\"fingerprint\":\"0x" << std::hex
           << evo::fingerprint(finalist.weights) << std::dec
           << "\",\"metrics\":";
    writeMetric(output, finalist.evaluation);
    output << '}';
  }
  output << "]},\n  \"stageA\":{\"opened\":"
         << (stage_opened ? "true" : "false")
         << ",\"seedLane\":\"0x3d760000..0x3d76001f\"";
  if (stage_opened && stage_candidate != nullptr &&
      stage_inherited != nullptr && stage_gate != nullptr) {
    output << ",\"candidate\":";
    writeMetric(output, *stage_candidate);
    output << ",\"inherited\":";
    writeMetric(output, *stage_inherited);
    output << ",\"gate\":";
    writeGate(output, *stage_gate);
    output << ",\"candidateGames\":";
    writeGames(output, *stage_candidate);
    output << ",\"inheritedGames\":";
    writeGames(output, *stage_inherited);
  }
  output << "},\n  \"seedAudit\":{\"replayGames\":"
         << g_seed_audit.replay_games.load() << ",\"fittingGames\":"
         << g_seed_audit.fitting_games.load() << ",\"tournamentGames\":"
         << g_seed_audit.tournament_games.load() << ",\"stageAGames\":"
         << g_seed_audit.stage_a_games.load()
         << ",\"otherSeedOpened\":"
         << (g_seed_audit.other_seed_opened.load() ? "true" : "false")
         << ",\"forbiddenPrefixOpened\":"
         << (g_seed_audit.forbidden_prefix_opened.load() ? "true" : "false")
         << "},\n  \"resources\":{\"wallSeconds\":" << wall_seconds
         << ",\"wallLimitSeconds\":" << kWallLimitSeconds
         << ",\"peakRssBytes\":" << peakRssBytes()
         << ",\"rssLimitBytes\":" << kRssLimitBytes << "},\n"
         << "  \"passed\":"
         << (stage_opened && stage_gate != nullptr && stage_gate->passed
                 ? "true"
                 : "false")
         << "\n}\n";
  if (!output) throw std::runtime_error("tail CEM artifact write failed");
}

struct TrainingResult {
  std::vector<Candidate> finalists;
  TailEvaluation inherited_tournament;
  Candidate champion;
  TournamentGate gate;
  std::vector<Progress> progress;
};

TrainingResult trainAndTournament(const Weights& inherited,
                                  const Clock::time_point& run_started) {
  Weights mean = inherited;
  Weights sigma = evo::initialSigma();
  evo::SplitMix64 random(kOptimizerSeed);
  std::vector<Candidate> archive;
  archive.reserve(static_cast<std::size_t>(1 + 2 * kGenerations));
  archive.push_back(Candidate{mean, {}, "starting-policy", 0});
  std::vector<Progress> progress;
  progress.reserve(kGenerations / 4);

  for (int generation = 0; generation < kGenerations; ++generation) {
    std::vector<Candidate> population(static_cast<std::size_t>(kPopulation));
    population[0].weights = mean;
    population[0].provenance = "generation-mean";
    population[0].generation = generation + 1;
    for (int pair = 0; pair < (kPopulation - 1) / 2; ++pair) {
      Weights positive = mean;
      Weights negative = mean;
      for (int index = 0; index < evo::kFeatureCount; ++index) {
        const double perturbation = sigma[index] * random.normal();
        positive[index] = std::clamp(mean[index] + perturbation,
                                     kMinimumWeight, kMaximumWeight);
        negative[index] = std::clamp(mean[index] - perturbation,
                                     kMinimumWeight, kMaximumWeight);
      }
      for (int phase = 0; phase < evo::kPhaseCount; ++phase) {
        const int terminal = phase * evo::kBaseFeatureCount + 31;
        positive[terminal] = -100.0;
        negative[terminal] = -100.0;
      }
      Candidate& positive_candidate =
          population[static_cast<std::size_t>(1 + pair * 2)];
      Candidate& negative_candidate =
          population[static_cast<std::size_t>(2 + pair * 2)];
      positive_candidate.weights = positive;
      positive_candidate.provenance = "generation-sample";
      positive_candidate.generation = generation + 1;
      negative_candidate.weights = negative;
      negative_candidate.provenance = "generation-sample";
      negative_candidate.generation = generation + 1;
    }

    const std::uint32_t seed_start =
        kFittingAllowStart +
        static_cast<std::uint32_t>(generation * kBatchGames);
    evaluatePopulation(population, seed_start, kBatchGames,
                       SeedPurpose::kFitting);
    std::stable_sort(population.begin(), population.end(),
                     [](const Candidate& first, const Candidate& second) {
                       return first.evaluation.objective >
                              second.evaluation.objective;
                     });

    const Candidate generation_champion = population.front();
    Weights elite_mean{};
    double rank_mass = 0.0;
    for (int rank = 0; rank < kElite; ++rank) {
      const double rank_weight =
          std::log(static_cast<double>(kElite) + 0.5) -
          std::log(static_cast<double>(rank) + 1.0);
      rank_mass += rank_weight;
      for (int index = 0; index < evo::kFeatureCount; ++index) {
        elite_mean[index] += rank_weight * population[rank].weights[index];
      }
    }
    for (double& value : elite_mean) value /= rank_mass;

    Weights elite_variance{};
    for (int rank = 0; rank < kElite; ++rank) {
      const double rank_weight =
          std::log(static_cast<double>(kElite) + 0.5) -
          std::log(static_cast<double>(rank) + 1.0);
      for (int index = 0; index < evo::kFeatureCount; ++index) {
        const double delta = population[rank].weights[index] - elite_mean[index];
        elite_variance[index] += rank_weight * delta * delta;
      }
    }
    for (int index = 0; index < evo::kFeatureCount; ++index) {
      mean[index] = kMeanRetention * mean[index] +
                    kEliteMeanRate * elite_mean[index];
      const double selected_sigma =
          std::sqrt(elite_variance[index] / rank_mass + 1e-12);
      sigma[index] = std::clamp(kSigmaRetention * sigma[index] +
                                    kEliteSigmaRate * selected_sigma,
                                kMinimumSigma, kMaximumSigma);
    }
    for (int phase = 0; phase < evo::kPhaseCount; ++phase) {
      const int terminal = phase * evo::kBaseFeatureCount + 31;
      mean[terminal] = -100.0;
      sigma[terminal] = 0.0;
    }

    archive.push_back(Candidate{mean, {}, "post-update-mean", generation + 1});
    Candidate archived_champion = generation_champion;
    archived_champion.provenance = "generation-champion";
    archive.push_back(std::move(archived_champion));

    if ((generation + 1) % 4 == 0) {
      const double elapsed =
          std::chrono::duration<double>(Clock::now() - run_started).count();
      const double completed_candidate_games =
          static_cast<double>(generation + 1) * kPopulation * kBatchGames;
      const double total_candidate_games =
          static_cast<double>(kGenerations) * kPopulation * kBatchGames +
          static_cast<double>(1 + 2 * kGenerations) * kTournamentGames +
          64.0;
      const double projected = elapsed / completed_candidate_games *
                               total_candidate_games *
                               kProjectionSafetyFactor;
      Progress item;
      item.generation = generation + 1;
      item.best_objective = generation_champion.evaluation.objective;
      item.best_score = generation_champion.evaluation.mean_score;
      item.best_moves = generation_champion.evaluation.mean_moves;
      item.best_lower_quartile_moves =
          generation_champion.evaluation.lower_quartile_moves;
      item.best_milestone_utility =
          generation_champion.evaluation.milestone_utility;
      item.hits = generation_champion.evaluation.milestone_hits;
      item.elapsed_seconds = elapsed;
      item.projected_seconds = projected;
      item.peak_rss_bytes = peakRssBytes();
      progress.push_back(item);
      std::cout << std::fixed << std::setprecision(6)
                << "TAIL_SURVIVAL_CEM_PROGRESS {\"generation\":"
                << item.generation << ",\"bestObjective\":"
                << item.best_objective << ",\"bestScore\":"
                << item.best_score << ",\"bestMoves\":"
                << item.best_moves << ",\"bottomQuartileMoves\":"
                << item.best_lower_quartile_moves
                << ",\"milestoneUtility\":"
                << item.best_milestone_utility << ",\"hits\":[";
      for (std::size_t index = 0; index < item.hits.size(); ++index) {
        if (index != 0) std::cout << ',';
        std::cout << item.hits[index];
      }
      std::cout << "],\"elapsedSeconds\":" << item.elapsed_seconds
                << ",\"projectedSeconds\":" << item.projected_seconds
                << ",\"peakRssBytes\":" << item.peak_rss_bytes << "}\n";
      checkResources(elapsed, projected);
    }
  }

  if (archive.size() != static_cast<std::size_t>(1 + 2 * kGenerations)) {
    throw std::runtime_error("tail CEM finalist archive size changed");
  }
  evaluatePopulation(archive, kTournamentStart, kTournamentGames,
                     SeedPurpose::kTournament);
  const TailEvaluation inherited_tournament = archive.front().evaluation;
  std::stable_sort(archive.begin(), archive.end(),
                   [](const Candidate& first, const Candidate& second) {
                     return first.evaluation.objective >
                            second.evaluation.objective;
                   });
  const Candidate champion = archive.front();
  const TournamentGate gate =
      tournamentGate(champion.evaluation, inherited_tournament);
  freezeCandidate(champion.weights);
  checkResources(
      std::chrono::duration<double>(Clock::now() - run_started).count(),
      std::chrono::duration<double>(Clock::now() - run_started).count());
  return TrainingResult{std::move(archive), inherited_tournament, champion,
                        gate, std::move(progress)};
}

bool selfTest() {
  const bool sha =
      sha256("abc") ==
      "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
  const Weights input = loadFrozenInput();
  const bool input_exact = evo::fingerprint(input) == kInputFingerprint;

  State state;
  state.board = initialBoard();
  state.board[indexOf(5, 0)] = 3;
  state.board[indexOf(5, 1)] = 5;
  state.board[indexOf(5, 4)] = 4;
  state.next_disc = 6;
  state.moves_remaining = 3;
  evo::SearchMetrics first_metrics;
  evo::SearchMetrics second_metrics;
  const int first = evo::chooseSearchAction(
      state, input, kSearchDepth, kInternalWidth, kStrata, &first_metrics);
  const int second = evo::chooseSearchAction(
      state, input, kSearchDepth, kInternalWidth, kStrata, &second_metrics);
  State mirrored = state;
  mirrored.board = evo::detail::mirrorBoard(state.board);
  const int reflected = evo::chooseSearchAction(
      mirrored, input, kSearchDepth, kInternalWidth, kStrata);
  State metadata = state;
  metadata.score = 999'999'999;
  metadata.level = 999;
  metadata.moves_played = 999;
  const int metadata_action = evo::chooseSearchAction(
      metadata, input, kSearchDepth, kInternalWidth, kStrata);
  const bool search_exact = first == second &&
                            first_metrics.transitions ==
                                second_metrics.transitions &&
                            reflected == kBoardSize - 1 - first &&
                            metadata_action == first &&
                            isLegal(state.board, first);

  TailEvaluation single;
  TailEvaluation repeated;
  for (int game = 0; game < 32; ++game) {
    GameResult first_game;
    first_game.seed = static_cast<std::uint32_t>(game);
    first_game.score = 17'000 * 20;
    first_game.moves = game == 0 ? 300 : 50;
    first_game.terminal = true;
    first_game.clears = 100;
    first_game.reveals = 50;
    single.games.push_back(first_game);
    GameResult repeated_game = first_game;
    repeated_game.moves = game < 8 ? 300 : 50;
    repeated.games.push_back(repeated_game);
  }
  summarize(single);
  summarize(repeated);
  const bool repeated_reward =
      repeated.milestone_utility > single.milestone_utility * 5.0 &&
      repeated.objective > single.objective;

  TailEvaluation inherited = repeated;
  TailEvaluation qualifying = repeated;
  qualifying.mean_score = 600'000.0;
  qualifying.mean_moves = 170.0;
  qualifying.clears_per_move = 2.2;
  qualifying.reveals_per_move = 1.2;
  qualifying.objective = inherited.objective + 30.0;
  qualifying.milestone_utility = inherited.milestone_utility + 30.0;
  for (std::size_t index = 0; index < kMilestones.size(); ++index) {
    qualifying.milestone_rates[index] =
        inherited.milestone_rates[index] + 0.04;
  }
  const bool tournament_gate_positive =
      tournamentGate(qualifying, inherited).passed;
  qualifying.mean_score = 100'000.0;
  const bool tournament_gate_negative =
      !tournamentGate(qualifying, inherited).passed;

  evo::saveCheckpoint("/tmp/drop7-tail-survival-cem-selftest.bin", input,
                      kStrata);
  const auto [round_trip, stored_samples] = evo::loadCheckpoint(
      "/tmp/drop7-tail-survival-cem-selftest.bin");
  const bool checkpoint = round_trip == input && stored_samples == kStrata;
  const bool seed_guards =
      seedAllowed(kFittingAllowStart, SeedPurpose::kFitting) &&
      seedAllowed(kFittingAllowEnd, SeedPurpose::kFitting) &&
      !seedAllowed(kFittingAllowStart - 1, SeedPurpose::kFitting) &&
      seedAllowed(kTournamentStart, SeedPurpose::kTournament) &&
      seedAllowed(kTournamentEnd, SeedPurpose::kTournament) &&
      seedAllowed(kStageAStart, SeedPurpose::kStageA) &&
      seedAllowed(kStageAEnd, SeedPurpose::kStageA) &&
      !seedAllowed(0x4d00'0000u, SeedPurpose::kFitting) &&
      !seedAllowed(0x7d00'0000u, SeedPurpose::kTournament) &&
      !seedAllowed(0xd700'0000u, SeedPurpose::kStageA);
  const bool passed = sha && input_exact && search_exact && repeated_reward &&
                      tournament_gate_positive && tournament_gate_negative &&
                      checkpoint && seed_guards &&
                      peakRssBytes() <= kRssLimitBytes;
  std::cout << "TAIL_SURVIVAL_CEM_SELF_TEST {\"passed\":"
            << (passed ? "true" : "false") << ",\"sha256\":"
            << (sha ? "true" : "false") << ",\"inputExact\":"
            << (input_exact ? "true" : "false")
            << ",\"publicSearchExact\":"
            << (search_exact ? "true" : "false")
            << ",\"repeatedMilestonesRewarded\":"
            << (repeated_reward ? "true" : "false")
            << ",\"gatePositiveNegative\":"
            << (tournament_gate_positive && tournament_gate_negative ? "true"
                                                                      : "false")
            << ",\"checkpointRoundTrip\":"
            << (checkpoint ? "true" : "false")
            << ",\"seedGuards\":" << (seed_guards ? "true" : "false")
            << ",\"freshSeedsOpened\":0,\"peakRssBytes\":"
            << peakRssBytes() << "}\n";
  return passed;
}

int run() {
  const auto run_started = Clock::now();
  runPreflight();
  const Weights inherited = loadFrozenInput();
  TrainingResult result = trainAndTournament(inherited, run_started);
  const double tournament_wall =
      std::chrono::duration<double>(Clock::now() - run_started).count();
  writeArtifact(result.finalists, result.inherited_tournament,
                result.champion, result.gate, result.progress, false, nullptr,
                nullptr, nullptr, tournament_wall);
  std::cout << std::fixed << std::setprecision(6)
            << "TAIL_SURVIVAL_CEM_TOURNAMENT {\"championScore\":"
            << result.champion.evaluation.mean_score
            << ",\"championMoves\":"
            << result.champion.evaluation.mean_moves
            << ",\"bottomQuartileMoves\":"
            << result.champion.evaluation.lower_quartile_moves
            << ",\"clearsPerMove\":"
            << result.champion.evaluation.clears_per_move
            << ",\"revealsPerMove\":"
            << result.champion.evaluation.reveals_per_move
            << ",\"milestoneUtility\":"
            << result.champion.evaluation.milestone_utility
            << ",\"startingScore\":"
            << result.inherited_tournament.mean_score
            << ",\"startingMoves\":"
            << result.inherited_tournament.mean_moves
            << ",\"objectiveDelta\":" << result.gate.objective_improvement
            << ",\"milestoneDelta\":"
            << result.gate.milestone_improvement
            << ",\"modelFingerprint\":\"0x" << std::hex
            << evo::fingerprint(result.champion.weights) << std::dec
            << "\",\"stageAOpened\":"
            << (result.gate.passed ? "true" : "false") << "}\n";
  if (!result.gate.passed) return 2;

  std::vector<Candidate> stage_candidates;
  stage_candidates.push_back(
      Candidate{result.champion.weights, {}, "frozen-candidate", -1});
  stage_candidates.push_back(
      Candidate{inherited, {}, "starting-policy", -1});
  evaluatePopulation(stage_candidates, kStageAStart, 32,
                     SeedPurpose::kStageA);
  const StageAGate stage_gate = stageAGate(stage_candidates[0].evaluation,
                                           stage_candidates[1].evaluation);
  const double wall_seconds =
      std::chrono::duration<double>(Clock::now() - run_started).count();
  checkResources(wall_seconds, wall_seconds);
  writeArtifact(result.finalists, result.inherited_tournament,
                result.champion, result.gate, result.progress, true,
                &stage_candidates[0].evaluation,
                &stage_candidates[1].evaluation, &stage_gate, wall_seconds);
  std::cout << std::fixed << std::setprecision(6)
            << "TAIL_SURVIVAL_CEM_STAGE_A {\"candidateScore\":"
            << stage_candidates[0].evaluation.mean_score
            << ",\"candidateMoves\":"
            << stage_candidates[0].evaluation.mean_moves
            << ",\"bottomQuartileMoves\":"
            << stage_candidates[0].evaluation.lower_quartile_moves
            << ",\"clearsPerMove\":"
            << stage_candidates[0].evaluation.clears_per_move
            << ",\"revealsPerMove\":"
            << stage_candidates[0].evaluation.reveals_per_move
            << ",\"startingScore\":"
            << stage_candidates[1].evaluation.mean_score
            << ",\"startingMoves\":"
            << stage_candidates[1].evaluation.mean_moves
            << ",\"jointWins\":" << stage_gate.joint_win_count
            << ",\"passed\":" << (stage_gate.passed ? "true" : "false")
            << ",\"wallSeconds\":" << wall_seconds
            << ",\"peakRssBytes\":" << peakRssBytes() << "}\n";
  return stage_gate.passed ? 0 : 3;
}

}  // namespace drop7::tail_survival_cem

int main(int argc, char** argv) {
  using namespace drop7::tail_survival_cem;
  try {
    if (argc != 2) {
      throw std::invalid_argument("usage: --self-test | --preflight | --run");
    }
    const std::string_view mode(argv[1]);
    if (mode == "--self-test") return selfTest() ? 0 : 1;
    if (mode == "--preflight") {
      runPreflight();
      return 0;
    }
    if (mode == "--run") return run();
    throw std::invalid_argument("unknown tail CEM mode");
  } catch (const std::exception& error) {
    std::cerr << "tail survival CEM failure: " << error.what() << '\n';
    return 1;
  }
}