Drop7 Research
approaches/constructive-reservoir/structural-terminal-veto/d4-structural-terminal-veto.cppC++2,048 lines · 79.8 KB
#define DROP7_FAIR_ONLY_DEPTH4_LIBRARY
#define DROP7_FAIR_ONLY_DEPTH4_NO_MAIN
#include "../../fair-expectimax/reference/fair-only-depth4.cpp"
#undef DROP7_FAIR_ONLY_DEPTH4_NO_MAIN
#undef DROP7_FAIR_ONLY_DEPTH4_LIBRARY

#include <bit>
#include <filesystem>
#include <optional>
#include <sstream>

// A conservative terminal-rollout veto around the immutable fair-D4/s5
// policy.  D4 supplies the root action and complete ordering; only its top two
// legal actions are compared.  The forced root action is followed by the exact
// fixed constructiveContinuation (not its D3/D4-shielded outer policy) on two
// independent panels of 127 event-stratified public chance streams.  The D4
// runner-up may replace D4 only when the fixed terminal-classifier ultra gate
// passes independently on both panels.
namespace drop7::d4_structural_terminal_veto {

namespace d4 = drop7::fair_only_depth4;
namespace detail = drop7::cfpi::detail;
using Clock = std::chrono::steady_clock;

// Exact copy of the fixed cheap continuation and its transitive structural
// evaluator from constructive-spectrum-depth4.cpp.  Keeping it local avoids
// importing the D4-shielded outer policy.
namespace frozen {

constexpr int kChanceSamples = 7;
constexpr std::uint32_t kPolicySeed = 0x4353'5031u;  // "CSP1"
constexpr double kTerminalValue = -1.0e9;
constexpr std::array<int, kBoardSize> kColumnOrder{{3, 2, 4, 1, 5, 0, 6}};

struct PublicState {
  Board board{};
  std::uint8_t next_disc = 1;
  std::uint8_t moves_remaining = kMovesPerLevel;
  bool terminal = false;

  bool operator==(const PublicState&) const = default;
};

PublicState publicState(const State& source) {
  if (source.next_disc < 1 || source.next_disc > kBoardSize ||
      source.moves_remaining < 0 || source.moves_remaining > kMovesPerLevel ||
      (!source.game_over && source.moves_remaining < 1)) {
    throw std::invalid_argument("invalid public D4 constructive state");
  }
  for (const std::uint8_t cell : source.board) {
    if (cell > kCracked) throw std::invalid_argument("invalid board token");
  }
  return {source.board, source.next_disc,
          static_cast<std::uint8_t>(source.moves_remaining), source.game_over};
}

State materialize(const PublicState& source) {
  State result;
  result.board = source.board;
  result.next_disc = source.next_disc;
  result.moves_remaining = source.moves_remaining;
  result.game_over = source.terminal;
  return result;
}

PublicState mirror(const PublicState& source) {
  PublicState result = source;
  result.board = detail::mirrorBoard(source.board);
  return result;
}

PublicState canonicalPublic(const PublicState& source, bool& mirrored) {
  mirrored = detail::mirroredRepresentationIsSmaller(source.board);
  return mirrored ? mirror(source) : source;
}

std::array<int, kBoardSize> columnHeights(const Board& board) {
  std::array<int, kBoardSize> heights{};
  for (int column = 0; column < kBoardSize; ++column) {
    for (int row = 0; row < kBoardSize; ++row) {
      heights[column] += board[indexOf(row, column)] != kEmpty;
    }
  }
  return heights;
}

int topRow(const Board& board, int column) {
  for (int row = 0; row < kBoardSize; ++row) {
    if (board[indexOf(row, column)] != kEmpty) return row;
  }
  return kBoardSize;
}

struct TriggerKeys {
  int legal = 0;
  int any = 0;
  int multiple = 0;
  int placed = 0;
  int high = 0;
  int cover_contact = 0;
  int distinct_discs = 0;
  int distinct_columns = 0;
};

TriggerKeys exactTriggerKeys(const Board& source) {
  TriggerKeys result;
  std::array<bool, kBoardSize + 1> discs{};
  std::array<bool, kBoardSize> columns{};
  for (int disc = 1; disc <= kBoardSize; ++disc) {
    for (int column = 0; column < kBoardSize; ++column) {
      Board board = source;
      if (!placeDisc(board, column, static_cast<std::uint8_t>(disc))) continue;
      ++result.legal;
      int placed_index = -1;
      for (int row = 0; row < kBoardSize; ++row) {
        if (source[indexOf(row, column)] == kEmpty &&
            board[indexOf(row, column)] != kEmpty) {
          placed_index = indexOf(row, column);
          break;
        }
      }
      int count = 0;
      const auto poppers = findPoppers(board, count);
      if (count == 0) continue;
      ++result.any;
      result.multiple += count >= 2;
      discs[disc] = true;
      columns[column] = true;
      bool has_high = false;
      bool touches_cover = false;
      for (int offset = 0; offset < count; ++offset) {
        const int cell_index = poppers[offset];
        result.placed += cell_index == placed_index;
        has_high = has_high || board[cell_index] >= 5;
        const int row = cell_index / kBoardSize;
        const int pop_column = cell_index % kBoardSize;
        for (const auto [dr, dc] :
             std::array<std::array<int, 2>, 4>{{
                 {{-1, 0}}, {{1, 0}}, {{0, -1}}, {{0, 1}},
             }}) {
          const int nr = row + dr;
          const int nc = pop_column + dc;
          if (!inside(nr, nc)) continue;
          const auto neighbor = board[indexOf(nr, nc)];
          touches_cover = touches_cover || neighbor == kSolid ||
                          neighbor == kCracked;
        }
      }
      result.high += has_high;
      result.cover_contact += touches_cover;
    }
  }
  result.distinct_discs = std::accumulate(discs.begin(), discs.end(), 0);
  result.distinct_columns =
      std::accumulate(columns.begin(), columns.end(), 0);
  return result;
}

enum Metric : int {
  kOccupancy,
  kCovers,
  kMaximumHeight,
  kHeightMean,
  kHeightStddev,
  kHeightRange,
  kDistinctHeights,
  kAdjacentHeightSteps,
  kUnitHeightSteps,
  kRoughness,
  kInteriorWells,
  kEdgeHeight,
  kSurfaceNumbered,
  kSurfaceHigh,
  kSurfaceLow,
  kSurfaceCover,
  kHighReservoir,
  kHighReady,
  kSameTargetHighPairs,
  kEdgeCovers,
  kEdgeCoverFrontier,
  kCoverNumberContacts,
  kTriggerAny,
  kTriggerMultiple,
  kTriggerPlaced,
  kTriggerHigh,
  kTriggerCover,
  kTriggerDiscBreadth,
  kTriggerColumnBreadth,
  kMetricCount,
};

using Metrics = std::array<double, kMetricCount>;

Metrics extractMetrics(const PublicState& state) {
  Metrics result{};
  const auto heights = columnHeights(state.board);
  const double mean = std::accumulate(heights.begin(), heights.end(), 0.0) /
                      static_cast<double>(kBoardSize);
  std::array<bool, kBoardSize + 1> seen_heights{};
  int minimum = kBoardSize;
  int maximum = 0;
  std::array<int, kBoardSize + 1> ready_high_by_target{};
  for (int column = 0; column < kBoardSize; ++column) {
    minimum = std::min(minimum, heights[column]);
    maximum = std::max(maximum, heights[column]);
    seen_heights[heights[column]] = true;
    result[kOccupancy] += heights[column];
    result[kHeightStddev] +=
        (static_cast<double>(heights[column]) - mean) *
        (static_cast<double>(heights[column]) - mean);
    if (column > 0) {
      const int difference = std::abs(heights[column] - heights[column - 1]);
      result[kRoughness] += difference;
      result[kAdjacentHeightSteps] += difference > 0;
      result[kUnitHeightSteps] += difference == 1;
    }
    if (column > 0 && column + 1 < kBoardSize &&
        heights[column] < heights[column - 1] &&
        heights[column] < heights[column + 1]) {
      ++result[kInteriorWells];
    }
    if (column == 0 || column == kBoardSize - 1) {
      result[kEdgeHeight] += heights[column];
    }
    const int surface_row = topRow(state.board, column);
    if (surface_row < kBoardSize) {
      const std::uint8_t cap = state.board[indexOf(surface_row, column)];
      result[kSurfaceNumbered] += isNumbered(cap);
      result[kSurfaceHigh] += cap >= 5 && cap <= 7;
      result[kSurfaceLow] += cap == 1 || cap == 2;
      result[kSurfaceCover] += cap == kSolid || cap == kCracked;
    }
  }
  result[kHeightMean] = mean;
  result[kHeightStddev] = std::sqrt(result[kHeightStddev] / kBoardSize);
  result[kMaximumHeight] = maximum;
  result[kHeightRange] = maximum - minimum;
  result[kDistinctHeights] =
      std::accumulate(seen_heights.begin(), seen_heights.end(), 0);

  for (int row = 0; row < kBoardSize; ++row) {
    for (int column = 0; column < kBoardSize; ++column) {
      const std::uint8_t cell = state.board[indexOf(row, column)];
      if (cell == kSolid || cell == kCracked) {
        ++result[kCovers];
        if (column == 0 || column == kBoardSize - 1) {
          ++result[kEdgeCovers];
          if (row == topRow(state.board, column)) {
            ++result[kEdgeCoverFrontier];
          }
        }
        for (const auto [dr, dc] :
             std::array<std::array<int, 2>, 4>{{
                 {{-1, 0}}, {{1, 0}}, {{0, -1}}, {{0, 1}},
             }}) {
          const int nr = row + dr;
          const int nc = column + dc;
          if (inside(nr, nc) &&
              isNumbered(state.board[indexOf(nr, nc)])) {
            ++result[kCoverNumberContacts];
          }
        }
      }
      if (cell < 5 || cell > 7) continue;
      const int horizontal = lineLength(state.board, row, column, false);
      const int vertical = lineLength(state.board, row, column, true);
      const int deficit =
          static_cast<int>(cell) - std::max(horizontal, vertical);
      if (deficit > 0) ++result[kHighReservoir];
      if (deficit == 1 || deficit == 2) {
        ++result[kHighReady];
        ++ready_high_by_target[cell];
      }
    }
  }
  for (int target = 5; target <= 7; ++target) {
    result[kSameTargetHighPairs] +=
        ready_high_by_target[target] * (ready_high_by_target[target] - 1) / 2;
  }
  const TriggerKeys triggers = exactTriggerKeys(state.board);
  result[kTriggerAny] = triggers.any;
  result[kTriggerMultiple] = triggers.multiple;
  result[kTriggerPlaced] = triggers.placed;
  result[kTriggerHigh] = triggers.high;
  result[kTriggerCover] = triggers.cover_contact;
  result[kTriggerDiscBreadth] = triggers.distinct_discs;
  result[kTriggerColumnBreadth] = triggers.distinct_columns;
  return result;
}

double structuralValue(const PublicState& state) {
  if (state.terminal) return kTerminalValue;
  const Metrics m = extractMetrics(state);
  const auto excess = [](double value, double target) {
    return std::max(0.0, value - target);
  };
  const auto capped = [](double value, double target) {
    return std::min(value, target);
  };
  double value = 0.0;
  value -= 2'400.0 * excess(m[kOccupancy], 15.0);
  value -= 3'000.0 * excess(m[kCovers], 8.0);
  value -= 13'000.0 * std::pow(excess(m[kMaximumHeight], 4.0), 2.0);
  value -= 2'000.0 * excess(m[kEdgeCovers], 3.0);
  value -= 6'500.0 * excess(m[kSurfaceLow], 1.0);
  value -= 1'300.0 * excess(m[kRoughness], 7.0);
  value += 3'600.0 * capped(m[kHighReservoir], 4.0);
  value += 2'000.0 * capped(m[kSurfaceHigh], 3.0);
  value += 1'200.0 * capped(m[kSameTargetHighPairs], 2.0);
  value += 550.0 * capped(m[kTriggerCover], 13.0);
  value += 900.0 * capped(m[kTriggerMultiple], 5.0);
  value += 500.0 * capped(m[kTriggerDiscBreadth], 7.0);
  value += 350.0 * capped(m[kTriggerColumnBreadth], 7.0);
  value += 700.0 * capped(m[kDistinctHeights], 4.0);
  value += 350.0 * capped(m[kUnitHeightSteps], 3.0);
  value += 1'500.0 * capped(m[kEdgeCoverFrontier], 2.0);
  const double urgency =
      static_cast<double>(kMovesPerLevel - state.moves_remaining) /
      static_cast<double>(kMovesPerLevel - 1);
  value -= 1'500.0 * urgency * excess(m[kOccupancy] + 7.0, 19.0);
  return value;
}

struct SampledStep {
  State state{};
  std::int64_t score_delta = 0;
  int clears = 0;
  int reveals = 0;
  int waves = 0;
  bool played = false;
};

SampledStep sampledStep(const State& source, int source_column, int sample,
                        int depth_tag) {
  bool mirrored = false;
  const State canonical = detail::canonicalState(source, mirrored);
  const int column = mirrored ? kBoardSize - 1 - source_column : source_column;
  SampledStep result;
  if (!isLegal(canonical.board, column)) return result;
  const std::uint32_t seed =
      detail::scenarioSeedForState(canonical, kPolicySeed, depth_tag);
  detail::StratifiedRandom random{seed, sample, kChanceSamples, 0};
  MoveResult move;
  if (!detail::playMoveSampled(canonical, column, random, move)) return result;
  result.played = true;
  result.score_delta = move.score_delta;
  result.waves = static_cast<int>(move.waves.size());
  for (const Wave& wave : move.waves) {
    result.clears += wave.cleared;
    result.reveals += wave.revealed;
  }
  if (!move.state.game_over) {
    move.state.next_disc =
        detail::sampledNextDisc(seed, sample, kChanceSamples);
  }
  bool ignored = false;
  result.state = detail::canonicalState(move.state, ignored);
  return result;
}

struct OneStepDecision {
  int action = -1;
  double value = -std::numeric_limits<double>::infinity();
  std::uint64_t work = 0;
};

OneStepDecision constructiveContinuation(const State& source, int depth_tag) {
  OneStepDecision result;
  bool ignored = false;
  const State canonical = detail::canonicalState(source, ignored);
  for (const int column : kColumnOrder) {
    if (!isLegal(canonical.board, column)) continue;
    double total = 0.0;
    for (int sample = 0; sample < kChanceSamples; ++sample) {
      const SampledStep step = sampledStep(canonical, column, sample, depth_tag);
      ++result.work;
      if (!step.played || step.state.game_over) {
        total += kTerminalValue;
        continue;
      }
      total += static_cast<double>(step.score_delta) +
               5'000.0 * step.clears + 8'000.0 * step.reveals +
               500.0 * step.waves + structuralValue(publicState(step.state));
    }
    total /= kChanceSamples;
    if (total > result.value) {
      result.value = total;
      result.action = column;
    }
  }
  if (result.action < 0) result.action = centerFirstMove(canonical.board);
  return result;
}

}  // namespace frozen

using PublicState = frozen::PublicState;

constexpr std::uint32_t kFittingSeedStart = 0x3d6e'4000u;
constexpr int kFittingGames = 4;
constexpr std::uint32_t kScreenSeedStart = 0x3d6e'5000u;
constexpr int kScreenGames = 8;
constexpr int kMaximumMoves = 1'000;
constexpr int kScenarios = 127;
constexpr int kHorizon = 200;
constexpr int kEventsPerStep = 64;
constexpr int kDefaultThreads = 4;
constexpr double kT99Df126 = 2.35631;
constexpr double kNormal99 = 2.326347874;
constexpr double kMinimumScoreLcb = 10'000.0;
constexpr double kMinimumMoveLcb = 2.0;
constexpr double kMaterialScoreLoss = -100'000.0;
constexpr double kMaterialMoveLoss = -25.0;
constexpr double kMaximumDownsideUpper99 = 0.10;
constexpr double kFittingScoreRatio = 1.10;
constexpr double kFittingMoveRatio = 1.10;
constexpr int kFittingJointWins = 3;
constexpr double kScreenScoreRatio = 1.05;
constexpr double kScreenMoveRatio = 1.05;
constexpr int kScreenJointWins = 5;
constexpr double kWallLimitSeconds = 75.0 * 60.0;
constexpr std::uint64_t kRssLimitBytes = 256ull * 1024ull * 1024ull;
constexpr int kProjectionMovesPerGame = 175;
constexpr double kProjectionSafetyFactor = 1.35;
constexpr double kProjectionReserveSeconds = 45.0;
constexpr std::uint32_t kPanelADomain = 0x4434'5041u;  // "D4PA"
constexpr std::uint32_t kPanelBDomain = 0x4434'5042u;  // "D4PB"
constexpr std::uint32_t kRevealDomain = 0x4434'5256u;  // "D4RV"
constexpr std::uint32_t kVisibleDomain = 0x4434'5653u; // "D4VS"

#if defined(__has_feature)
#if __has_feature(address_sanitizer)
constexpr bool kAddressSanitizerBuild = true;
#else
constexpr bool kAddressSanitizerBuild = false;
#endif
#else
constexpr bool kAddressSanitizerBuild = false;
#endif

constexpr std::uint64_t kMaximumD4WorkPerDecision = d4::kMaximumWork;
constexpr std::uint64_t kMaximumSyntheticTransitionsPerDecision =
    2ull * 2ull * kScenarios * kHorizon;
constexpr std::uint64_t kMaximumContinuationCallsPerDecision =
    2ull * 2ull * kScenarios * (kHorizon - 1);
constexpr std::uint64_t kMaximumConstructiveWorkPerCall =
    static_cast<std::uint64_t>(kBoardSize) * frozen::kChanceSamples;
constexpr std::uint64_t kMaximumConstructiveWorkPerDecision =
    kMaximumContinuationCallsPerDecision * kMaximumConstructiveWorkPerCall;

static_assert(kLevelBonus == 17'000);
static_assert(kMovesPerLevel == 5);
static_assert(d4::kCandidateDepth == 4 && d4::kChanceSamples == 5);
static_assert(d4::kMaximumWork > d4::kWorstCaseD4Work);
static_assert(frozen::kChanceSamples == 7);
static_assert(frozen::kPolicySeed == 0x4353'5031u);
static_assert(frozen::kTerminalValue == -1.0e9);
static_assert(kScenarios == 127 && kHorizon == 200);
static_assert(kEventsPerStep > kCellCount);
static_assert(kMaximumSyntheticTransitionsPerDecision == 101'600);
static_assert(kMaximumContinuationCallsPerDecision == 101'092);
static_assert(kMaximumConstructiveWorkPerCall == 49);
static_assert(kMaximumConstructiveWorkPerDecision == 4'953'508);
static_assert(kFittingSeedStart + kFittingGames <= kScreenSeedStart);
static_assert(kScreenSeedStart + kScreenGames <= 0x3d6e'ffffu);
static_assert((kFittingSeedStart >> 16u) == 0x3d6eu);
static_assert((kScreenSeedStart >> 16u) == 0x3d6eu);

std::mutex report_mutex;

struct Options {
  std::string output = "/tmp/drop7-d4-structural-terminal-veto.json";
  std::string switches =
      "/tmp/drop7-d4-structural-terminal-veto-switches.jsonl";
  std::string readme =
      "/tmp/drop7-d4-structural-terminal-veto-README.md";
  std::string source_sha256;
  int threads = kDefaultThreads;
};

bool isSha256(std::string_view value) {
  if (value.size() != 64) return false;
  return std::all_of(value.begin(), value.end(), [](char character) {
    return (character >= '0' && character <= '9') ||
           (character >= 'a' && character <= 'f');
  });
}

Options parseOptions(int argc, char** argv, int begin) {
  Options result;
  for (int index = begin; index < argc; index += 2) {
    if (index + 1 >= argc) throw std::invalid_argument("missing option value");
    const std::string argument = argv[index];
    if (argument == "--output") {
      result.output = argv[index + 1];
    } else if (argument == "--switches") {
      result.switches = argv[index + 1];
    } else if (argument == "--readme") {
      result.readme = argv[index + 1];
    } else if (argument == "--source-sha256") {
      result.source_sha256 = argv[index + 1];
    } else if (argument == "--threads") {
      result.threads = std::stoi(argv[index + 1]);
      if (result.threads < 1 || result.threads > 16) {
        throw std::invalid_argument("threads must be in [1,16]");
      }
    } else {
      throw std::invalid_argument("unknown option " + argument);
    }
  }
  if (!isSha256(result.source_sha256)) {
    throw std::invalid_argument("--source-sha256 must be 64 lowercase hex");
  }
  return result;
}

std::uint64_t mix64(std::uint64_t value) {
  value ^= value >> 30u;
  value *= 0xbf58'476d'1ce4'e5b9ull;
  value ^= value >> 27u;
  value *= 0x94d0'49bb'1331'11ebull;
  return value ^ (value >> 31u);
}

void hashCombine(std::uint64_t& hash, std::uint64_t value) {
  hash = mix64(hash ^ mix64(value + 0x9e37'79b9'7f4a'7c15ull));
}

std::uint32_t seed32(std::uint64_t value) {
  return mix32(static_cast<std::uint32_t>(value) ^
               static_cast<std::uint32_t>(value >> 32u));
}

std::uint64_t publicHash(const PublicState& source) {
  bool ignored = false;
  const PublicState state = frozen::canonicalPublic(source, ignored);
  std::uint64_t hash = 0xcbf2'9ce4'8422'2325ull;
  for (const std::uint8_t cell : state.board) {
    hash ^= static_cast<std::uint64_t>(cell + 1u);
    hash *= 0x0000'0100'0000'01b3ull;
  }
  hash ^= state.next_disc;
  hash *= 0x0000'0100'0000'01b3ull;
  hash ^= static_cast<std::uint64_t>(state.moves_remaining + 1u);
  hash *= 0x0000'0100'0000'01b3ull;
  hash ^= static_cast<std::uint64_t>(state.terminal);
  return mix64(hash);
}

std::uint32_t panelSeed(const PublicState& source, std::uint32_t domain) {
  return seed32(publicHash(source) ^ static_cast<std::uint64_t>(domain));
}

std::uint64_t peakRssBytes() {
  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
}

void enforceRssLimit() {
  // ASan's shadow memory is outside the runtime RSS contract.  The
  // optimized binary enforces 256 MiB after every actual and synthetic root.
  if (!kAddressSanitizerBuild && peakRssBytes() > kRssLimitBytes) {
    throw std::runtime_error("D4 structural veto exceeded 256 MiB RSS");
  }
}

struct Deadline {
  Clock::time_point started = Clock::now();

  double seconds() const {
    return std::chrono::duration<double>(Clock::now() - started).count();
  }

  void check() const {
    if (seconds() > kWallLimitSeconds) {
      throw std::runtime_error("D4 structural veto exceeded 75m wall");
    }
  }
};

struct D4Anchor {
  int action = -1;
  int alternative = -1;
  int legal_actions = 0;
  bool complete = false;
  int completed_depth = 0;
  std::uint64_t work = 0;
  std::uint64_t nodes = 0;
  std::uint64_t cache_hits = 0;
  std::size_t cache_entries = 0;
  std::array<double, kBoardSize> values{};

  bool operator==(const D4Anchor&) const = default;
};

D4Anchor chooseD4Canonical(const PublicState& canonical) {
  if (canonical.terminal) return {};
  const d4::SearchDecision decision =
      d4::chooseDepth4Action(frozen::materialize(canonical));
  D4Anchor result;
  result.action = decision.action;
  result.complete = decision.complete;
  result.completed_depth = decision.completed_depth;
  result.work = decision.work;
  result.nodes = decision.nodes;
  result.cache_hits = decision.cache_hits;
  result.cache_entries = decision.cache_entries;
  result.values = decision.root_values;
  std::array<int, kBoardSize> ranked{};
  for (const int column : frozen::kColumnOrder) {
    if (isLegal(canonical.board, column)) ranked[result.legal_actions++] = column;
  }
  std::stable_sort(ranked.begin(), ranked.begin() + result.legal_actions,
                   [&](int left, int right) {
                     return result.values[left] > result.values[right];
                   });
  if (!result.complete || result.completed_depth != d4::kCandidateDepth ||
      result.action < 0 || result.legal_actions < 1 ||
      ranked[0] != result.action || result.work > d4::kMaximumWork ||
      result.cache_entries > d4::kMaximumCacheEntries) {
    throw std::runtime_error("immutable fair-D4/s5 anchor did not complete");
  }
  if (result.legal_actions >= 2) result.alternative = ranked[1];
  return result;
}

D4Anchor chooseD4(const PublicState& source) {
  bool mirrored = false;
  const PublicState canonical = frozen::canonicalPublic(source, mirrored);
  D4Anchor result = chooseD4Canonical(canonical);
  if (!mirrored) return result;
  result.action = kBoardSize - 1 - result.action;
  if (result.alternative >= 0) {
    result.alternative = kBoardSize - 1 - result.alternative;
  }
  std::array<double, kBoardSize> values{};
  for (int column = 0; column < kBoardSize; ++column) {
    values[column] = result.values[kBoardSize - 1 - column];
  }
  result.values = values;
  return result;
}

struct PublicContinuationDecision {
  int action = -1;
  double value = -std::numeric_limits<double>::infinity();
  std::uint64_t work = 0;

  bool operator==(const PublicContinuationDecision&) const = default;
};

// This wrapper is the runtime continuation boundary.  It can carry only public
// board, visible-disc, and phase data, and invokes the fixed implementation
// through its reference entry point.
PublicContinuationDecision chooseConstructiveContinuation(
    const PublicState& source, int depth_tag) {
  if (source.terminal) return {};
  bool mirrored = false;
  const PublicState canonical = frozen::canonicalPublic(source, mirrored);
  const frozen::OneStepDecision decision = frozen::constructiveContinuation(
      frozen::materialize(canonical), depth_tag);
  PublicContinuationDecision result;
  result.action = mirrored && decision.action >= 0
                      ? kBoardSize - 1 - decision.action
                      : decision.action;
  result.value = decision.value;
  result.work = decision.work;
  if (!isLegal(source.board, result.action) ||
      result.work > kMaximumConstructiveWorkPerCall) {
    throw std::runtime_error("frozen constructive continuation was invalid");
  }
  return result;
}

using PublicContinuation = PublicContinuationDecision (*)(const PublicState&,
                                                           int);
static_assert(std::is_same_v<decltype(&chooseConstructiveContinuation),
                             PublicContinuation>);
static_assert(!std::is_invocable_v<PublicContinuation, const State&, int>);

std::uint8_t visibleDisc(std::uint32_t root_seed, int scenario, int step,
                         std::uint32_t domain = kVisibleDomain) {
  const double unit = detail::stratifiedUnit(root_seed, scenario, kScenarios,
                                             domain, step);
  return static_cast<std::uint8_t>(
      std::floor(unit * static_cast<double>(kBoardSize)) + 1.0);
}

bool playSyntheticMove(const PublicState& source, int action,
                       std::uint32_t root_seed, int scenario, int step,
                       MoveResult& result,
                       std::uint32_t reveal_domain = kRevealDomain,
                       std::uint32_t visible_domain = kVisibleDomain) {
  if (source.terminal || scenario < 0 || scenario >= kScenarios || step < 0 ||
      step >= kHorizon || !isLegal(source.board, action)) {
    return false;
  }
  Board board = source.board;
  if (!placeDisc(board, action, source.next_disc)) return false;
  struct RevealTape {
    std::uint32_t root_seed;
    int scenario;
    int step;
    std::uint32_t domain;
    int event = 0;

    std::uint8_t nextDisc() {
      if (event >= kEventsPerStep) {
        throw std::runtime_error("structural reveal event slice exhausted");
      }
      const int event_index = step * kEventsPerStep + event++;
      const double unit = detail::stratifiedUnit(
          root_seed, scenario, kScenarios, domain, event_index);
      return static_cast<std::uint8_t>(
          std::floor(unit * static_cast<double>(kBoardSize)) + 1.0);
    }
  } reveals{root_seed, scenario, step, reveal_domain};

  result = MoveResult{};
  std::int64_t score = 0;
  detail::resolveCascadeSampled(board, reveals, 1, score, result.waves);
  result.score_delta = score;
  result.cleared_board = isBoardEmpty(board);
  if (result.cleared_board) result.score_delta += kClearBonus;
  int moves_remaining = source.moves_remaining - 1;
  bool terminal = false;
  if (moves_remaining == 0) {
    Board raised{};
    if (!raiseCoveredRow(board, raised)) {
      terminal = true;
    } else {
      result.level_advanced = true;
      moves_remaining = kMovesPerLevel;
      result.score_delta += kLevelBonus;
      board = raised;
      std::int64_t rise_score = 0;
      const int next_depth =
          result.waves.empty() ? 1 : result.waves.back().depth + 1;
      detail::resolveCascadeSampled(board, reveals, next_depth, rise_score,
                                    result.waves);
      result.score_delta += rise_score;
      if (isBoardEmpty(board)) {
        result.score_delta += kClearBonus;
        result.cleared_board = true;
      }
    }
  }
  int legal_count = 0;
  legalColumns(board, legal_count);
  if (!terminal && legal_count == 0) terminal = true;
  result.state.board = board;
  result.state.next_disc =
      terminal ? source.next_disc
               : visibleDisc(root_seed, scenario, step, visible_domain);
  result.state.score = 0;
  result.state.level = 1;
  result.state.moves_remaining = moves_remaining;
  result.state.moves_played = 0;
  result.state.game_over = terminal;
  return true;
}

struct WorkMetrics {
  std::uint64_t d4_work = 0;
  std::uint64_t d4_nodes = 0;
  std::uint64_t d4_cache_hits = 0;
  std::size_t peak_d4_cache_entries = 0;
  std::uint64_t synthetic_transitions = 0;
  std::uint64_t continuation_calls = 0;
  std::uint64_t constructive_work = 0;

  bool operator==(const WorkMetrics&) const = default;

  WorkMetrics& operator+=(const WorkMetrics& other) {
    d4_work += other.d4_work;
    d4_nodes += other.d4_nodes;
    d4_cache_hits += other.d4_cache_hits;
    peak_d4_cache_entries =
        std::max(peak_d4_cache_entries, other.peak_d4_cache_entries);
    synthetic_transitions += other.synthetic_transitions;
    continuation_calls += other.continuation_calls;
    constructive_work += other.constructive_work;
    return *this;
  }
};

void observeD4(const D4Anchor& anchor, WorkMetrics& work) {
  work.d4_work += anchor.work;
  work.d4_nodes += anchor.nodes;
  work.d4_cache_hits += anchor.cache_hits;
  work.peak_d4_cache_entries =
      std::max(work.peak_d4_cache_entries, anchor.cache_entries);
}

struct ScenarioOutcome {
  double score_return = 0.0;
  double survived_moves = 0.0;
  int numbered_clears = 0;
  int covers_revealed = 0;
  bool survived_cutoff = false;

  bool operator==(const ScenarioOutcome&) const = default;
};

ScenarioOutcome rolloutScenario(const PublicState& root, int root_action,
                                std::uint32_t root_seed, int scenario,
                                WorkMetrics& work, const Deadline* deadline,
                                int horizon = kHorizon) {
  if (root.terminal || !isLegal(root.board, root_action) || horizon < 1 ||
      horizon > kHorizon) {
    throw std::invalid_argument("invalid structural terminal scenario");
  }
  PublicState state = root;
  ScenarioOutcome result;
  for (int step = 0; step < horizon; ++step) {
    if (deadline != nullptr) deadline->check();
    int action = root_action;
    if (step > 0) {
      const PublicContinuationDecision continuation =
          chooseConstructiveContinuation(state, horizon - step);
      ++work.continuation_calls;
      work.constructive_work += continuation.work;
      action = continuation.action;
    }
    if (!isLegal(state.board, action)) {
      throw std::runtime_error("structural continuation selected illegal move");
    }
    MoveResult move;
    if (!playSyntheticMove(state, action, root_seed, scenario, step, move)) {
      throw std::runtime_error("structural synthetic transition failed");
    }
    ++work.synthetic_transitions;
    result.score_return += static_cast<double>(move.score_delta);
    result.survived_moves += 1.0;
    for (const Wave& wave : move.waves) {
      result.numbered_clears += wave.cleared;
      result.covers_revealed += wave.revealed;
    }
    state = frozen::publicState(move.state);
    if (state.terminal) return result;
  }
  result.survived_cutoff = true;
  return result;
}

struct PairedMetric {
  double mean = 0.0;
  double standard_error = 0.0;
  double lower_one_sided_99 = 0.0;
  double minimum = 0.0;
  double maximum = 0.0;
  int wins = 0;
  int ties = 0;
  int losses = 0;

  bool operator==(const PairedMetric&) const = default;
};

PairedMetric pairedMetric(const std::array<double, kScenarios>& differences) {
  PairedMetric result;
  result.minimum = std::numeric_limits<double>::infinity();
  result.maximum = -std::numeric_limits<double>::infinity();
  for (const double difference : differences) {
    result.mean += difference / kScenarios;
    result.minimum = std::min(result.minimum, difference);
    result.maximum = std::max(result.maximum, difference);
    result.wins += difference > 0.0;
    result.ties += difference == 0.0;
    result.losses += difference < 0.0;
  }
  double squares = 0.0;
  for (const double difference : differences) {
    const double centered = difference - result.mean;
    squares += centered * centered;
  }
  const double deviation =
      std::sqrt(squares / static_cast<double>(kScenarios - 1));
  result.standard_error = deviation / std::sqrt(kScenarios);
  result.lower_one_sided_99 =
      result.mean - kT99Df126 * result.standard_error;
  return result;
}

double wilsonUpper99(int events, int trials) {
  if (events < 0 || trials < 1 || events > trials) {
    throw std::invalid_argument("invalid Wilson inputs");
  }
  const double n = static_cast<double>(trials);
  const double p = static_cast<double>(events) / n;
  const double z2 = kNormal99 * kNormal99;
  const double center = p + z2 / (2.0 * n);
  const double radius = kNormal99 *
      std::sqrt((p * (1.0 - p) + z2 / (4.0 * n)) / n);
  return (center + radius) / (1.0 + z2 / n);
}

struct PairedAudit {
  PairedMetric score{};
  PairedMetric moves{};
  int material_downsides = 0;
  double material_downside_upper99 = 1.0;

  bool operator==(const PairedAudit&) const = default;
};

struct ActionPanel {
  std::array<ScenarioOutcome, kScenarios> scenarios{};
  double mean_score = 0.0;
  double mean_moves = 0.0;
  double mean_clears = 0.0;
  double mean_reveals = 0.0;
  int survived_cutoffs = 0;

  bool operator==(const ActionPanel&) const = default;
};

PairedAudit pairedAudit(const ActionPanel& candidate,
                        const ActionPanel& baseline) {
  std::array<double, kScenarios> score_differences{};
  std::array<double, kScenarios> move_differences{};
  PairedAudit result;
  for (int scenario = 0; scenario < kScenarios; ++scenario) {
    score_differences[scenario] =
        candidate.scenarios[scenario].score_return -
        baseline.scenarios[scenario].score_return;
    move_differences[scenario] =
        candidate.scenarios[scenario].survived_moves -
        baseline.scenarios[scenario].survived_moves;
    result.material_downsides +=
        score_differences[scenario] < kMaterialScoreLoss ||
        move_differences[scenario] < kMaterialMoveLoss;
  }
  result.score = pairedMetric(score_differences);
  result.moves = pairedMetric(move_differences);
  result.material_downside_upper99 =
      wilsonUpper99(result.material_downsides, kScenarios);
  return result;
}

bool passesUltra(const PairedAudit& audit) {
  return audit.score.lower_one_sided_99 >= kMinimumScoreLcb &&
         audit.moves.lower_one_sided_99 >= kMinimumMoveLcb &&
         audit.material_downside_upper99 <= kMaximumDownsideUpper99;
}

struct IndependentPanel {
  std::uint32_t seed = 0;
  std::array<ActionPanel, 2> actions{};
  PairedAudit alternative_vs_d4{};

  bool operator==(const IndependentPanel&) const = default;
};

struct Evaluation {
  D4Anchor anchor{};
  std::array<IndependentPanel, 2> panels{};
  int action = -1;
  bool switched = false;
  WorkMetrics work{};
  std::uint64_t canonical_public_hash = 0;
  double seconds = 0.0;

  bool operator==(const Evaluation&) const = default;
};

ActionPanel evaluateActionPanel(const PublicState& root, int action,
                                std::uint32_t root_seed, WorkMetrics& work,
                                const Deadline* deadline, int horizon) {
  ActionPanel result;
  for (int scenario = 0; scenario < kScenarios; ++scenario) {
    ScenarioOutcome& outcome = result.scenarios[scenario];
    outcome = rolloutScenario(root, action, root_seed, scenario, work,
                              deadline, horizon);
    result.mean_score += outcome.score_return / kScenarios;
    result.mean_moves += outcome.survived_moves / kScenarios;
    result.mean_clears +=
        static_cast<double>(outcome.numbered_clears) / kScenarios;
    result.mean_reveals +=
        static_cast<double>(outcome.covers_revealed) / kScenarios;
    result.survived_cutoffs += outcome.survived_cutoff;
  }
  return result;
}

Evaluation evaluateCanonical(const PublicState& root, const Deadline* deadline,
                             int horizon = kHorizon) {
  if (root.terminal || horizon < 1 || horizon > kHorizon) {
    throw std::invalid_argument("invalid D4 structural evaluation root");
  }
  const auto started = Clock::now();
  Evaluation result;
  result.anchor = chooseD4Canonical(root);
  observeD4(result.anchor, result.work);
  result.action = result.anchor.action;
  result.canonical_public_hash = publicHash(root);
  if (result.anchor.alternative < 0) {
    result.seconds =
        std::chrono::duration<double>(Clock::now() - started).count();
    return result;
  }
  constexpr std::array<std::uint32_t, 2> panel_domains{{kPanelADomain,
                                                        kPanelBDomain}};
  for (int panel = 0; panel < 2; ++panel) {
    IndependentPanel& panel_result = result.panels[panel];
    panel_result.seed = panelSeed(root, panel_domains[panel]);
    panel_result.actions[0] = evaluateActionPanel(
        root, result.anchor.action, panel_result.seed, result.work, deadline,
        horizon);
    panel_result.actions[1] = evaluateActionPanel(
        root, result.anchor.alternative, panel_result.seed, result.work,
        deadline, horizon);
    panel_result.alternative_vs_d4 = pairedAudit(
        panel_result.actions[1], panel_result.actions[0]);
  }
  if (passesUltra(result.panels[0].alternative_vs_d4) &&
      passesUltra(result.panels[1].alternative_vs_d4)) {
    result.action = result.anchor.alternative;
    result.switched = true;
  }
  const std::uint64_t horizon_scale = static_cast<std::uint64_t>(horizon);
  const std::uint64_t maximum_transitions =
      2ull * 2ull * kScenarios * horizon_scale;
  const std::uint64_t maximum_calls =
      2ull * 2ull * kScenarios * (horizon_scale - 1u);
  if (result.work.d4_work > kMaximumD4WorkPerDecision ||
      result.work.peak_d4_cache_entries > d4::kMaximumCacheEntries ||
      result.work.synthetic_transitions > maximum_transitions ||
      result.work.continuation_calls > maximum_calls ||
      result.work.constructive_work >
          maximum_calls * kMaximumConstructiveWorkPerCall) {
    throw std::runtime_error("D4 structural evaluation exceeded work proof");
  }
  result.seconds =
      std::chrono::duration<double>(Clock::now() - started).count();
  return result;
}

Evaluation chooseAction(const PublicState& source, const Deadline* deadline,
                        int horizon = kHorizon) {
  bool mirrored = false;
  const PublicState canonical = frozen::canonicalPublic(source, mirrored);
  Evaluation result = evaluateCanonical(canonical, deadline, horizon);
  if (!mirrored) return result;
  result.action = kBoardSize - 1 - result.action;
  result.anchor.action = kBoardSize - 1 - result.anchor.action;
  if (result.anchor.alternative >= 0) {
    result.anchor.alternative = kBoardSize - 1 - result.anchor.alternative;
  }
  std::array<double, kBoardSize> values{};
  for (int column = 0; column < kBoardSize; ++column) {
    values[column] = result.anchor.values[kBoardSize - 1 - column];
  }
  result.anchor.values = values;
  return result;
}

enum class SeedCohort { kFitting, kScreen };

bool allowedSeed(std::uint32_t seed, SeedCohort cohort) {
  const std::uint32_t start =
      cohort == SeedCohort::kFitting ? kFittingSeedStart : kScreenSeedStart;
  const int games =
      cohort == SeedCohort::kFitting ? kFittingGames : kScreenGames;
  return seed >= start && seed < start + static_cast<std::uint32_t>(games) &&
         (seed >> 16u) == 0x3d6eu;
}

void requireSeed(std::uint32_t seed, SeedCohort cohort) {
  if (!allowedSeed(seed, cohort)) {
    throw std::invalid_argument("seed outside D4 structural veto allowlist");
  }
}

struct SwitchRecord {
  PublicState state{};
  int move_index = 0;
  int d4_action = -1;
  int alternative = -1;
  std::array<double, kBoardSize> d4_values{};
  std::array<IndependentPanel, 2> panels{};
};

struct GameResult {
  std::uint32_t seed = 0;
  std::int64_t score = 0;
  int moves = 0;
  bool censored = false;
  std::int64_t numbered_clears = 0;
  std::int64_t covers_revealed = 0;
  int maximum_chain = 0;
  int decisions = 0;
  int switches = 0;
  double decision_seconds = 0.0;
  WorkMetrics work{};
  std::uint64_t disc_stream_hash = 0;
  std::uint64_t decision_checksum = 0x4434'5354'5654'4f21ull;
  std::vector<SwitchRecord> switch_records;
};

std::uint64_t discStreamHash(std::uint32_t seed, int maximum_moves) {
  std::uint64_t hash = 0x9e37'79b9'7f4a'7c15ull;
  for (int move = 0; move < maximum_moves; ++move) {
    hashCombine(hash, headlessDisc(seed, move));
  }
  return hash;
}

void observeMove(const MoveResult& move, GameResult& result) {
  for (const Wave& wave : move.waves) {
    result.numbered_clears += wave.cleared;
    result.covers_revealed += wave.revealed;
    result.maximum_chain = std::max(result.maximum_chain, wave.depth);
  }
}

enum class Policy { kD4, kVeto };

GameResult runGame(std::uint32_t seed, SeedCohort cohort, Policy policy,
                   const Deadline& deadline) {
  requireSeed(seed, cohort);
  State state = initialHeadlessState(seed);
  GameResult result;
  result.seed = seed;
  result.disc_stream_hash = discStreamHash(seed, kMaximumMoves);
  while (!state.game_over && state.moves_played < kMaximumMoves) {
    deadline.check();
    if (state.next_disc != headlessDisc(seed, state.moves_played)) {
      throw std::runtime_error("actual visible disc stream guard failed");
    }
    const PublicState public_state = frozen::publicState(state);
    const auto decision_started = Clock::now();
    int action = -1;
    if (policy == Policy::kD4) {
      const D4Anchor anchor = chooseD4(public_state);
      observeD4(anchor, result.work);
      action = anchor.action;
    } else {
      const Evaluation evaluation = chooseAction(public_state, &deadline);
      result.work += evaluation.work;
      action = evaluation.action;
      ++result.decisions;
      result.switches += evaluation.switched;
      hashCombine(result.decision_checksum,
                  evaluation.canonical_public_hash);
      hashCombine(result.decision_checksum,
                  static_cast<std::uint64_t>(action + 1));
      if (evaluation.switched) {
        result.switch_records.push_back({
            public_state,
            state.moves_played,
            evaluation.anchor.action,
            evaluation.anchor.alternative,
            evaluation.anchor.values,
            evaluation.panels,
        });
      }
    }
    result.decision_seconds +=
        std::chrono::duration<double>(Clock::now() - decision_started).count();
    if (!isLegal(state.board, action)) {
      throw std::runtime_error("actual D4 structural policy chose illegal move");
    }
    MoveResult move;
    if (!playHeadlessMove(state, seed, action, move)) {
      throw std::runtime_error("actual D4 structural transition failed");
    }
    observeMove(move, result);
    enforceRssLimit();
  }
  result.score = state.score;
  result.moves = state.moves_played;
  result.censored = !state.game_over;
  return result;
}

struct PairedGame {
  GameResult d4{};
  GameResult candidate{};
};

struct Cohort {
  std::vector<std::optional<PairedGame>> games;
  int attempted = 0;
  int completed = 0;
  bool aborted = false;
  std::string abort_reason;
  double wall_seconds = 0.0;
};

Cohort runCohort(std::uint32_t start, int games, SeedCohort seed_cohort,
                 int threads, const Deadline& deadline,
                 std::string_view label) {
  const auto started = Clock::now();
  Cohort result;
  result.games.resize(static_cast<std::size_t>(games));
  std::atomic<int> next{0};
  std::atomic<int> completed{0};
  std::atomic<bool> stopped{false};
  std::mutex failure_mutex;
  std::vector<std::future<void>> workers;
  const int worker_count = std::max(1, std::min(threads, games));
  for (int worker = 0; worker < worker_count; ++worker) {
    workers.push_back(std::async(std::launch::async, [&, worker]() {
      static_cast<void>(worker);
      while (!stopped.load()) {
        const int game = next.fetch_add(1);
        if (game >= games) return;
        try {
          const std::uint32_t seed = start + static_cast<std::uint32_t>(game);
          PairedGame pair;
          pair.d4 = runGame(seed, seed_cohort, Policy::kD4, deadline);
          pair.candidate =
              runGame(seed, seed_cohort, Policy::kVeto, deadline);
          if (pair.d4.disc_stream_hash != pair.candidate.disc_stream_hash) {
            throw std::runtime_error("paired actual disc streams differed");
          }
          result.games[static_cast<std::size_t>(game)] = std::move(pair);
          const int done = completed.fetch_add(1) + 1;
          const PairedGame& stored =
              *result.games[static_cast<std::size_t>(game)];
          const std::lock_guard<std::mutex> lock(report_mutex);
          std::cerr << "D4-structural " << label << ' ' << done << '/'
                    << games << " seed=0x" << std::hex << seed << std::dec
                    << " d4=" << stored.d4.score << '/' << stored.d4.moves
                    << " candidate=" << stored.candidate.score << '/'
                    << stored.candidate.moves << " switches="
                    << stored.candidate.switches << '\n';
        } catch (const std::exception& error) {
          stopped.store(true);
          const std::lock_guard<std::mutex> lock(failure_mutex);
          if (result.abort_reason.empty()) result.abort_reason = error.what();
        }
      }
    }));
  }
  for (auto& worker : workers) worker.get();
  result.attempted = std::min(next.load(), games);
  result.completed = completed.load();
  result.aborted = result.completed != games;
  result.wall_seconds =
      std::chrono::duration<double>(Clock::now() - started).count();
  return result;
}

struct Summary {
  int games = 0;
  int natural = 0;
  int censored = 0;
  double mean_score = 0.0;
  double mean_moves = 0.0;
  double clears_per_move = 0.0;
  double reveals_per_move = 0.0;
  double mean_decision_ms = 0.0;
  std::int64_t total_moves = 0;
  std::int64_t total_clears = 0;
  std::int64_t total_reveals = 0;
  int decisions = 0;
  int switches = 0;
  WorkMetrics work{};
  std::uint64_t checksum = 0x5355'4d44'3456'4554ull;
};

Summary summarize(const Cohort& cohort, Policy policy) {
  Summary result;
  double decision_seconds = 0.0;
  for (const std::optional<PairedGame>& optional_pair : cohort.games) {
    if (!optional_pair.has_value()) continue;
    const GameResult& game =
        policy == Policy::kD4 ? optional_pair->d4 : optional_pair->candidate;
    ++result.games;
    result.mean_score += game.score;
    result.mean_moves += game.moves;
    result.natural += !game.censored;
    result.censored += game.censored;
    result.total_moves += game.moves;
    result.total_clears += game.numbered_clears;
    result.total_reveals += game.covers_revealed;
    result.decisions += game.decisions;
    result.switches += game.switches;
    decision_seconds += game.decision_seconds;
    result.work += game.work;
    hashCombine(result.checksum, game.decision_checksum);
  }
  if (result.games > 0) {
    result.mean_score /= result.games;
    result.mean_moves /= result.games;
  }
  if (result.total_moves > 0) {
    result.clears_per_move =
        static_cast<double>(result.total_clears) / result.total_moves;
    result.reveals_per_move =
        static_cast<double>(result.total_reveals) / result.total_moves;
    result.mean_decision_ms = 1'000.0 * decision_seconds / result.total_moves;
  }
  return result;
}

struct Gate {
  double score_ratio = 0.0;
  double move_ratio = 0.0;
  int joint_wins = 0;
  bool complete = false;
  bool score_passed = false;
  bool moves_passed = false;
  bool clears_passed = false;
  bool reveals_passed = false;
  bool joint_passed = false;
  bool passed = false;
};

Gate cohortGate(const Cohort& cohort, const Summary& baseline,
                const Summary& candidate, double score_ratio,
                double move_ratio, int joint_wins) {
  Gate result;
  result.complete = cohort.completed == static_cast<int>(cohort.games.size()) &&
                    !cohort.aborted;
  if (baseline.games == 0 || baseline.mean_score <= 0.0 ||
      baseline.mean_moves <= 0.0) {
    return result;
  }
  result.score_ratio = candidate.mean_score / baseline.mean_score;
  result.move_ratio = candidate.mean_moves / baseline.mean_moves;
  result.score_passed = result.score_ratio >= score_ratio;
  result.moves_passed = result.move_ratio >= move_ratio;
  result.clears_passed = candidate.clears_per_move >= baseline.clears_per_move;
  result.reveals_passed =
      candidate.reveals_per_move >= baseline.reveals_per_move;
  for (const std::optional<PairedGame>& pair : cohort.games) {
    if (!pair.has_value()) continue;
    result.joint_wins += pair->candidate.score > pair->d4.score &&
                         pair->candidate.moves > pair->d4.moves;
  }
  result.joint_passed = result.joint_wins >= joint_wins;
  result.passed = result.complete && result.score_passed &&
                  result.moves_passed && result.clears_passed &&
                  result.reveals_passed && result.joint_passed;
  return result;
}

std::string hex64(std::uint64_t value) {
  std::ostringstream output;
  output << "0x" << std::hex << std::setw(16) << std::setfill('0') << value;
  return output.str();
}

std::string jsonEscape(std::string_view source) {
  std::string result;
  for (const char character : source) {
    if (character == '\\' || character == '"') result.push_back('\\');
    result.push_back(character);
  }
  return result;
}

void writeMetric(std::ostream& output, const PairedMetric& metric) {
  output << "{\"mean\":" << metric.mean
         << ",\"standardError\":" << metric.standard_error
         << ",\"lowerOneSided99\":" << metric.lower_one_sided_99
         << ",\"minimum\":" << metric.minimum
         << ",\"maximum\":" << metric.maximum << ",\"wins\":"
         << metric.wins << ",\"ties\":" << metric.ties
         << ",\"losses\":" << metric.losses << '}';
}

void writeAudit(std::ostream& output, const PairedAudit& audit) {
  output << "{\"score\":";
  writeMetric(output, audit.score);
  output << ",\"moves\":";
  writeMetric(output, audit.moves);
  output << ",\"materialDownsides\":" << audit.material_downsides
         << ",\"materialDownsideUpper99\":"
         << audit.material_downside_upper99 << '}';
}

void writeActionPanel(std::ostream& output, const ActionPanel& panel) {
  output << "{\"meanScore\":" << panel.mean_score
         << ",\"meanMoves\":" << panel.mean_moves
         << ",\"meanNumberedClears\":" << panel.mean_clears
         << ",\"meanCoversRevealed\":" << panel.mean_reveals
         << ",\"survivedCutoffs\":" << panel.survived_cutoffs << '}';
}

std::uint64_t writeSwitches(const std::string& path, const Cohort& cohort,
                            std::string_view phase) {
  std::ofstream output(path, phase == "fitting" ? std::ios::trunc
                                                 : std::ios::app);
  if (!output) throw std::runtime_error("could not open switch JSONL");
  output << std::setprecision(12);
  std::uint64_t records = 0;
  for (const std::optional<PairedGame>& optional_pair : cohort.games) {
    if (!optional_pair.has_value()) continue;
    const GameResult& game = optional_pair->candidate;
    for (const SwitchRecord& record : game.switch_records) {
      output << "{\"phase\":\"" << phase
             << "\",\"provenance\":{\"gameSeed\":" << game.seed
             << ",\"moveIndex\":" << record.move_index << "},"
             << "\"modelInput\":{\"board\":\""
             << serializeBoard(record.state.board)
             << "\",\"nextDisc\":"
             << static_cast<int>(record.state.next_disc)
             << ",\"movesRemaining\":"
             << static_cast<int>(record.state.moves_remaining)
             << ",\"terminal\":"
             << (record.state.terminal ? "true" : "false") << "},"
             << "\"excludedFromModelInput\":[\"gameSeed\",\"moveIndex\","
                "\"score\",\"level\",\"history\",\"scenario\","
                "\"futureTape\"],\"d4Action\":" << record.d4_action
             << ",\"alternative\":" << record.alternative
             << ",\"d4RootValues\":[";
      for (int column = 0; column < kBoardSize; ++column) {
        if (column != 0) output << ',';
        if (std::isfinite(record.d4_values[column])) {
          output << record.d4_values[column];
        } else {
          output << "null";
        }
      }
      output << "],\"panels\":[";
      for (int panel = 0; panel < 2; ++panel) {
        if (panel != 0) output << ',';
        output << "{\"d4\":";
        writeActionPanel(output, record.panels[panel].actions[0]);
        output << ",\"alternative\":";
        writeActionPanel(output, record.panels[panel].actions[1]);
        output << ",\"alternativeVsD4\":";
        writeAudit(output, record.panels[panel].alternative_vs_d4);
        output << '}';
      }
      output << "]}\n";
      ++records;
    }
  }
  output.close();
  if (!output) throw std::runtime_error("could not finish switch JSONL");
  return records;
}

void writeWork(std::ostream& output, const WorkMetrics& work) {
  output << "{\"d4Work\":" << work.d4_work
         << ",\"d4Nodes\":" << work.d4_nodes
         << ",\"d4CacheHits\":" << work.d4_cache_hits
         << ",\"peakD4CacheEntries\":" << work.peak_d4_cache_entries
         << ",\"syntheticTransitions\":" << work.synthetic_transitions
         << ",\"continuationCalls\":" << work.continuation_calls
         << ",\"constructiveWork\":" << work.constructive_work << '}';
}

void writeSummary(std::ostream& output, const Summary& summary) {
  output << "{\"games\":" << summary.games << ",\"natural\":"
         << summary.natural << ",\"censored\":" << summary.censored
         << ",\"meanScore\":" << summary.mean_score
         << ",\"meanMoves\":" << summary.mean_moves
         << ",\"numberedClearsPerMove\":" << summary.clears_per_move
         << ",\"coversRevealedPerMove\":" << summary.reveals_per_move
         << ",\"meanDecisionMs\":" << summary.mean_decision_ms
         << ",\"decisions\":" << summary.decisions
         << ",\"switches\":" << summary.switches
         << ",\"checksum\":\"" << hex64(summary.checksum)
         << "\",\"work\":";
  writeWork(output, summary.work);
  output << '}';
}

void writeGate(std::ostream& output, const Gate& gate) {
  output << "{\"scoreRatio\":" << gate.score_ratio
         << ",\"moveRatio\":" << gate.move_ratio
         << ",\"jointWins\":" << gate.joint_wins
         << ",\"complete\":" << (gate.complete ? "true" : "false")
         << ",\"scorePassed\":"
         << (gate.score_passed ? "true" : "false")
         << ",\"movesPassed\":"
         << (gate.moves_passed ? "true" : "false")
         << ",\"clearsPassed\":"
         << (gate.clears_passed ? "true" : "false")
         << ",\"revealsPassed\":"
         << (gate.reveals_passed ? "true" : "false")
         << ",\"jointPassed\":"
         << (gate.joint_passed ? "true" : "false")
         << ",\"passed\":" << (gate.passed ? "true" : "false") << '}';
}

void writeCohort(std::ostream& output, const Cohort& cohort,
                 const Summary& baseline, const Summary& candidate,
                 const Gate& gate, std::uint32_t seed_start) {
  output << "{\"seedStart\":" << seed_start << ",\"attempted\":"
         << cohort.attempted << ",\"completed\":" << cohort.completed
         << ",\"aborted\":" << (cohort.aborted ? "true" : "false")
         << ",\"abortReason\":\"" << jsonEscape(cohort.abort_reason)
         << "\",\"wallSeconds\":" << cohort.wall_seconds
         << ",\"d4\":";
  writeSummary(output, baseline);
  output << ",\"candidate\":";
  writeSummary(output, candidate);
  output << ",\"gate\":";
  writeGate(output, gate);
  output << ",\"pairs\":[";
  bool first = true;
  for (const std::optional<PairedGame>& pair : cohort.games) {
    if (!pair.has_value()) continue;
    if (!first) output << ',';
    first = false;
    output << "{\"seed\":" << pair->d4.seed
           << ",\"d4Score\":" << pair->d4.score
           << ",\"d4Moves\":" << pair->d4.moves
           << ",\"candidateScore\":" << pair->candidate.score
           << ",\"candidateMoves\":" << pair->candidate.moves
           << ",\"switches\":" << pair->candidate.switches << '}';
  }
  output << "]}";
}

void writeArtifact(const Options& options, double preflight_seconds,
                   double projected_total_seconds, bool projection_passed,
                   const Cohort* fitting, const Summary* fitting_d4,
                   const Summary* fitting_candidate, const Gate* fitting_gate,
                   std::uint64_t fitting_switches, const Cohort* screen,
                   const Summary* screen_d4, const Summary* screen_candidate,
                   const Gate* screen_gate, std::uint64_t screen_switches,
                   double total_wall_seconds) {
  std::ofstream output(options.output);
  if (!output) throw std::runtime_error("could not open D4 veto artifact");
  output << std::setprecision(12)
         << "{\n  \"experiment\":\"d4-structural-terminal-veto\",\n"
         << "  \"sourceSha256\":\"" << options.source_sha256 << "\",\n"
         << "  \"preregistered\":true,\n"
         << "  \"policy\":{\"immutableAnchor\":\"completed fair-D4/s5\","
            "\"rootCandidates\":\"D4 top two only\","
            "\"continuation\":\"frozen constructiveContinuation\","
            "\"outerConstructivePolicyUsed\":false,"
            "\"fallback\":\"exact D4\"},\n"
         << "  \"publicBoundary\":[\"board\",\"nextDisc\","
            "\"movesRemaining\",\"terminal\"],\n"
         << "  \"excludedFromDecision\":[\"gameSeed\",\"score\",\"level\","
            "\"moveIndex\",\"history\",\"scenario\",\"futureTape\"],\n"
         << "  \"rollout\":{\"panels\":2,\"scenariosPerPanel\":"
         << kScenarios << ",\"horizon\":" << kHorizon
         << ",\"reward\":\"unchanged engine score and survived moves\","
            "\"cutoffTail\":0,\"commonSiblingStreams\":true,"
            "\"independentPanels\":true,\"eventStratified\":true,"
            "\"revealVisibleDomainsSeparate\":true},\n"
         << "  \"ultraGate\":{\"requiredInEachPanel\":true,"
            "\"scoreLowerOneSided99\":" << kMinimumScoreLcb
         << ",\"moveLowerOneSided99\":" << kMinimumMoveLcb
         << ",\"materialScoreLoss\":" << kMaterialScoreLoss
         << ",\"materialMoveLoss\":" << kMaterialMoveLoss
         << ",\"maximumWilsonDownsideUpper99\":"
         << kMaximumDownsideUpper99 << "},\n"
         << "  \"seedDiscipline\":{\"fittingStart\":"
         << kFittingSeedStart << ",\"fittingGames\":" << kFittingGames
         << ",\"screenStart\":" << kScreenSeedStart
         << ",\"screenGames\":" << kScreenGames
         << ",\"screenConditionalOnFit\":true,"
            "\"forbiddenFamilies\":[\"0x4d\",\"0x7d\",\"0xd7\"]},\n"
         << "  \"resources\":{\"wallLimitSeconds\":"
         << kWallLimitSeconds << ",\"rssLimitBytes\":" << kRssLimitBytes
         << ",\"maximumD4WorkPerDecision\":"
         << kMaximumD4WorkPerDecision
         << ",\"maximumSyntheticTransitionsPerDecision\":"
         << kMaximumSyntheticTransitionsPerDecision
         << ",\"maximumContinuationCallsPerDecision\":"
         << kMaximumContinuationCallsPerDecision
         << ",\"maximumConstructiveWorkPerDecision\":"
         << kMaximumConstructiveWorkPerDecision
         << ",\"preflightDecisionSeconds\":" << preflight_seconds
         << ",\"projectionMovesPerGame\":" << kProjectionMovesPerGame
         << ",\"projectionSafetyFactor\":" << kProjectionSafetyFactor
         << ",\"projectedTotalSeconds\":" << projected_total_seconds
         << ",\"projectionPassed\":"
         << (projection_passed ? "true" : "false") << "},\n"
         << "  \"fittingGateDefinition\":{\"scoreRatio\":"
         << kFittingScoreRatio << ",\"moveRatio\":" << kFittingMoveRatio
         << ",\"jointWins\":" << kFittingJointWins
         << ",\"clearRevealNonregression\":true},\n"
         << "  \"screenGateDefinition\":{\"scoreRatio\":"
         << kScreenScoreRatio << ",\"moveRatio\":" << kScreenMoveRatio
         << ",\"jointWins\":" << kScreenJointWins
         << ",\"clearRevealNonregression\":true},\n"
         << "  \"fitting\":";
  if (fitting == nullptr) {
    output << "null";
  } else {
    writeCohort(output, *fitting, *fitting_d4, *fitting_candidate,
                *fitting_gate, kFittingSeedStart);
  }
  output << ",\n  \"fittingSwitchPanelRecords\":" << fitting_switches
         << ",\n  \"screenOpened\":"
         << (screen != nullptr ? "true" : "false") << ",\n  \"screen\":";
  if (screen == nullptr) {
    output << "null";
  } else {
    writeCohort(output, *screen, *screen_d4, *screen_candidate, *screen_gate,
                kScreenSeedStart);
  }
  output << ",\n  \"screenSwitchPanelRecords\":" << screen_switches
         << ",\n  \"qualified\":"
         << (screen_gate != nullptr && screen_gate->passed ? "true" : "false")
         << ",\n  \"switchPanelPath\":\"" << jsonEscape(options.switches)
         << "\",\n  \"totalWallSeconds\":" << total_wall_seconds
         << ",\n  \"peakRssBytes\":" << peakRssBytes() << "\n}\n";
  output.close();
  if (!output) throw std::runtime_error("could not finish D4 veto artifact");
}

void writeReadme(const Options& options, double preflight_seconds,
                 double projected_total_seconds, bool projection_passed,
                 const Summary* fitting_d4,
                 const Summary* fitting_candidate, const Gate* fitting_gate,
                 const Summary* screen_d4, const Summary* screen_candidate,
                 const Gate* screen_gate, double total_wall_seconds) {
  std::ofstream output(options.readme);
  if (!output) throw std::runtime_error("could not open D4 veto README");
  output << std::fixed << std::setprecision(6)
         << "# D4 structural terminal veto\n\n"
         << "Source SHA-256: `" << options.source_sha256 << "`\n\n"
         << "The immutable completed fair-D4/s5 policy supplies the root "
            "ordering. Only its top two legal actions are rolled out. Every "
            "later move is the frozen cheap `constructiveContinuation`; its "
            "D3/D4-shielded outer policy is never called. Two independent "
            "127-scenario, public-hash-derived panels run for at most 200 "
            "moves with unchanged engine score and survived-move rewards. "
            "The runner-up replaces D4 only when the prior ultra 99% gate "
            "passes independently in both panels.\n\n"
         << "- Preflight decision seconds: " << preflight_seconds << "\n"
         << "- Projected total seconds: " << projected_total_seconds << "\n"
         << "- Projection passed: " << (projection_passed ? "yes" : "no")
         << "\n- Total wall seconds: " << total_wall_seconds << "\n"
         << "- Peak RSS bytes: " << peakRssBytes() << "\n";
  if (fitting_gate != nullptr) {
    output << "\n## Fitting (0x3d6e4000..0x3d6e4003)\n\n"
           << "- D4 mean: " << fitting_d4->mean_score << " points / "
           << fitting_d4->mean_moves << " moves\n"
           << "- Candidate mean: " << fitting_candidate->mean_score
           << " points / " << fitting_candidate->mean_moves << " moves\n"
           << "- Score/move ratios: " << fitting_gate->score_ratio << " / "
           << fitting_gate->move_ratio << "\n"
           << "- Joint wins: " << fitting_gate->joint_wins << "/4\n"
           << "- Passed: " << (fitting_gate->passed ? "yes" : "no") << "\n";
  }
  if (screen_gate != nullptr) {
    output << "\n## Screen (0x3d6e5000..0x3d6e5007)\n\n"
           << "- D4 mean: " << screen_d4->mean_score << " points / "
           << screen_d4->mean_moves << " moves\n"
           << "- Candidate mean: " << screen_candidate->mean_score
           << " points / " << screen_candidate->mean_moves << " moves\n"
           << "- Score/move ratios: " << screen_gate->score_ratio << " / "
           << screen_gate->move_ratio << "\n"
           << "- Joint wins: " << screen_gate->joint_wins << "/8\n"
           << "- Passed: " << (screen_gate->passed ? "yes" : "no") << "\n";
  } else if (fitting_gate != nullptr && !fitting_gate->passed) {
    output << "\nThe fitting gate failed, so the screen remained sealed.\n";
  }
  output.close();
  if (!output) throw std::runtime_error("could not finish D4 veto README");
}

void expect(bool condition, std::string_view message) {
  if (!condition) throw std::runtime_error(std::string(message));
}

template <typename Function>
bool throwsInvalid(Function&& function) {
  try {
    function();
  } catch (const std::invalid_argument&) {
    return true;
  }
  return false;
}

PublicState asymmetricFixture() {
  PublicState state;
  state.board.fill(kEmpty);
  state.board[indexOf(6, 0)] = kSolid;
  state.board[indexOf(6, 1)] = 4;
  state.board[indexOf(6, 2)] = 2;
  state.board[indexOf(5, 2)] = kCracked;
  state.board[indexOf(6, 4)] = 6;
  state.next_disc = 3;
  state.moves_remaining = 3;
  return state;
}

void verifyExactStrata(std::uint32_t seed, std::uint32_t domain, int event) {
  std::array<int, kScenarios> counts{};
  for (int scenario = 0; scenario < kScenarios; ++scenario) {
    const double unit = detail::stratifiedUnit(seed, scenario, kScenarios,
                                               domain, event);
    const int stratum = static_cast<int>(std::floor(unit * kScenarios));
    expect(stratum >= 0 && stratum < kScenarios,
           "chance stratum out of range");
    ++counts[static_cast<std::size_t>(stratum)];
  }
  for (const int count : counts) {
    expect(count == 1, "chance event was not exactly 127-stratified");
  }
}

bool selfTest(std::ostream& output) {
  expect(kLevelBonus == 17'000, "corrected level bonus regression");
  const PublicState fixture = asymmetricFixture();
  const D4Anchor d4_first = chooseD4(fixture);
  const D4Anchor d4_second = chooseD4(fixture);
  expect(d4_first == d4_second && d4_first.complete &&
             d4_first.completed_depth == 4 &&
             isLegal(fixture.board, d4_first.action) &&
             isLegal(fixture.board, d4_first.alternative),
         "immutable D4 anchor determinism/completion failed");
  const PublicContinuationDecision continuation =
      chooseConstructiveContinuation(fixture, 17);
  bool fixture_mirrored = false;
  const PublicState canonical =
      frozen::canonicalPublic(fixture, fixture_mirrored);
  const frozen::OneStepDecision direct = frozen::constructiveContinuation(
      frozen::materialize(canonical), 17);
  const int mapped_direct = fixture_mirrored
                                ? kBoardSize - 1 - direct.action
                                : direct.action;
  expect(continuation.action == mapped_direct &&
             continuation.value == direct.value &&
             continuation.work == direct.work &&
             isLegal(fixture.board, continuation.action),
         "constructiveContinuation wrapper changed frozen mechanism");

  const Evaluation first = chooseAction(fixture, nullptr, 1);
  const Evaluation second = chooseAction(fixture, nullptr, 1);
  const bool deterministic_evidence =
      first.anchor == second.anchor && first.panels == second.panels &&
      first.action == second.action && first.switched == second.switched &&
      first.work == second.work &&
      first.canonical_public_hash == second.canonical_public_hash;
  expect(deterministic_evidence && !first.switched &&
             first.action == d4_first.action &&
             first.anchor.values == d4_first.values &&
             first.anchor.work == d4_first.work,
         "exact zero-switch D4 parity/determinism failed");
  const Evaluation reflected = chooseAction(frozen::mirror(fixture), nullptr, 1);
  expect(reflected.action == kBoardSize - 1 - first.action &&
             reflected.anchor.action ==
                 kBoardSize - 1 - first.anchor.action &&
             reflected.anchor.alternative ==
                 kBoardSize - 1 - first.anchor.alternative &&
             reflected.canonical_public_hash == first.canonical_public_hash &&
             reflected.panels == first.panels,
         "D4 structural reflection failed");

  State metadata = frozen::materialize(fixture);
  metadata.score = 8'765'432;
  metadata.level = 71;
  metadata.moves_played = 912;
  const PublicState normalized = frozen::publicState(metadata);
  const Evaluation normalized_evaluation =
      chooseAction(normalized, nullptr, 1);
  expect(normalized == fixture && publicHash(normalized) == publicHash(fixture) &&
             normalized_evaluation.anchor == first.anchor &&
             normalized_evaluation.panels == first.panels &&
             normalized_evaluation.action == first.action &&
             normalized_evaluation.switched == first.switched &&
             normalized_evaluation.work == first.work,
         "D4 structural policy used hidden metadata");

  constexpr std::uint32_t test_seed = 0x1234'5678u;
  for (const int event : {0, 1, 63, 64, 12'799}) {
    verifyExactStrata(test_seed, kRevealDomain, event);
    verifyExactStrata(test_seed, kVisibleDomain, event);
  }
  expect(panelSeed(fixture, kPanelADomain) !=
             panelSeed(fixture, kPanelBDomain),
         "independent panel seeds collided");
  PublicState tape_fixture;
  tape_fixture.board.fill(kEmpty);
  tape_fixture.board[indexOf(6, 1)] = kCracked;
  tape_fixture.next_disc = 1;
  tape_fixture.moves_remaining = 4;
  MoveResult standard;
  expect(playSyntheticMove(tape_fixture, 0, test_seed, 0, 0, standard),
         "chance-domain fixture failed");
  bool visible_discriminates = false;
  bool reveal_discriminates = false;
  for (std::uint32_t salt = 1; salt < 512; ++salt) {
    MoveResult changed_visible;
    expect(playSyntheticMove(tape_fixture, 0, test_seed, 0, 0,
                             changed_visible, kRevealDomain,
                             kVisibleDomain ^ salt),
           "visible-domain fixture failed");
    if (changed_visible.state.next_disc != standard.state.next_disc) {
      expect(changed_visible.state.board == standard.state.board &&
                 changed_visible.score_delta == standard.score_delta,
             "visible chance leaked into reveals");
      visible_discriminates = true;
    }
    MoveResult changed_reveal;
    expect(playSyntheticMove(tape_fixture, 0, test_seed, 0, 0,
                             changed_reveal, kRevealDomain ^ salt,
                             kVisibleDomain),
           "reveal-domain fixture failed");
    if (changed_reveal.state.board != standard.state.board) {
      expect(changed_reveal.state.next_disc == standard.state.next_disc,
             "reveal chance leaked into visible disc");
      reveal_discriminates = true;
    }
  }
  expect(visible_discriminates && reveal_discriminates,
         "chance domains were not discriminating/independent");

  std::array<double, kScenarios> constants{};
  constants.fill(2.0);
  const PairedMetric constant_metric = pairedMetric(constants);
  expect(std::abs(constant_metric.mean - 2.0) < 1e-12 &&
             constant_metric.standard_error < 1e-12 &&
             std::abs(constant_metric.lower_one_sided_99 - 2.0) < 1e-12,
         "paired confidence constant-vector math failed");
  constants[0] = -2.0;
  const PairedMetric varied = pairedMetric(constants);
  expect(varied.standard_error > 0.0 &&
             varied.lower_one_sided_99 < varied.mean,
         "paired confidence variance math failed");
  PairedAudit passing;
  passing.score.lower_one_sided_99 = kMinimumScoreLcb;
  passing.moves.lower_one_sided_99 = kMinimumMoveLcb;
  passing.material_downside_upper99 = kMaximumDownsideUpper99;
  expect(passesUltra(passing), "inclusive ultra boundary failed");
  passing.moves.lower_one_sided_99 =
      std::nextafter(kMinimumMoveLcb, 0.0);
  expect(!passesUltra(passing), "ultra gate accepted sub-bound audit");
  expect(wilsonUpper99(0, kScenarios) > 0.0 &&
             wilsonUpper99(0, kScenarios) < 0.05 &&
             std::abs(wilsonUpper99(kScenarios, kScenarios) - 1.0) < 1e-12,
         "Wilson downside confidence failed");

  expect(first.work.synthetic_transitions <=
             2ull * 2ull * kScenarios &&
             first.work.continuation_calls == 0 &&
             first.work.d4_work <= kMaximumD4WorkPerDecision &&
             kMaximumSyntheticTransitionsPerDecision == 101'600 &&
             kMaximumConstructiveWorkPerDecision == 4'953'508,
         "resource proof changed");
  expect(allowedSeed(kFittingSeedStart, SeedCohort::kFitting) &&
             allowedSeed(kFittingSeedStart + 3, SeedCohort::kFitting) &&
             allowedSeed(kScreenSeedStart + 7, SeedCohort::kScreen),
         "authorized seeds rejected");
  expect(throwsInvalid([] {
           requireSeed(0x3d6e'3fffu, SeedCohort::kFitting);
         }) &&
             throwsInvalid([] {
               requireSeed(0x3d6e'4004u, SeedCohort::kFitting);
             }) &&
             throwsInvalid([] {
               requireSeed(0x4d6e'4000u, SeedCohort::kFitting);
             }) &&
             throwsInvalid([] {
               requireSeed(0x7d6e'5000u, SeedCohort::kScreen);
             }) &&
             throwsInvalid([] {
               requireSeed(0xd76e'5000u, SeedCohort::kScreen);
             }),
         "seed guards failed");
  enforceRssLimit();
  output << std::setprecision(12)
         << "D4_STRUCTURAL_TERMINAL_VETO_SELF_TEST {\"passed\":true,"
         << "\"immutableD4\":true,\"frozenConstructiveContinuation\":true,"
         << "\"exactZeroSwitchD4Parity\":true,\"publicOnly\":true,"
         << "\"metadataBlind\":true,\"reflection\":true,"
         << "\"deterministic\":true,\"legal\":true,\"panels\":2,"
         << "\"scenariosPerPanel\":" << kScenarios
         << ",\"horizon\":" << kHorizon
         << ",\"chanceDomains\":true,\"confidenceMath\":true,"
         << "\"resourceProof\":true,\"seedGuards\":true,"
         << "\"fixtureD4Work\":" << first.work.d4_work
         << ",\"peakRssBytes\":" << peakRssBytes() << "}\n";
  return true;
}

struct Projection {
  double preflight_seconds = 0.0;
  double projected_total_seconds = 0.0;
  bool passed = false;
  Evaluation evaluation{};
};

Projection measureProjection(int threads, const Deadline& deadline) {
  PublicState preflight;
  preflight.board = initialBoard();
  preflight.next_disc = 3;
  preflight.moves_remaining = kMovesPerLevel;
  Projection result;
  result.evaluation = chooseAction(preflight, &deadline, kHorizon);
  result.preflight_seconds = result.evaluation.seconds;
  const int fitting_batches = (kFittingGames + threads - 1) / threads;
  const int screen_batches = (kScreenGames + threads - 1) / threads;
  result.projected_total_seconds =
      deadline.seconds() +
      result.preflight_seconds * kProjectionMovesPerGame *
          (fitting_batches + screen_batches) * kProjectionSafetyFactor +
      kProjectionReserveSeconds;
  result.passed = result.projected_total_seconds <= kWallLimitSeconds;
  enforceRssLimit();
  return result;
}

int preflightOnly(const Options& options, std::ostream& output) {
  const Deadline deadline;
  const Projection projection = measureProjection(options.threads, deadline);
  output << std::fixed << std::setprecision(3)
         << "D4_STRUCTURAL_TERMINAL_VETO_PREFLIGHT {\"passed\":"
         << (projection.passed ? "true" : "false")
         << ",\"gameSeedsOpened\":false,\"preflightSeconds\":"
         << projection.preflight_seconds << ",\"projectedTotalSeconds\":"
         << projection.projected_total_seconds
         << ",\"projectedFittingSeconds\":"
         << projection.preflight_seconds * kProjectionMovesPerGame *
                ((kFittingGames + options.threads - 1) / options.threads) *
                kProjectionSafetyFactor
         << ",\"d4Work\":" << projection.evaluation.work.d4_work
         << ",\"syntheticTransitions\":"
         << projection.evaluation.work.synthetic_transitions
         << ",\"continuationCalls\":"
         << projection.evaluation.work.continuation_calls
         << ",\"constructiveWork\":"
         << projection.evaluation.work.constructive_work
         << ",\"switched\":"
         << (projection.evaluation.switched ? "true" : "false")
         << ",\"peakRssBytes\":" << peakRssBytes() << "}\n";
  return projection.passed ? 0 : 2;
}

int run(const Options& options, std::ostream& output) {
  const Deadline deadline;
  const Projection projection = measureProjection(options.threads, deadline);
  const double preflight_seconds = projection.preflight_seconds;
  const double projected_total_seconds = projection.projected_total_seconds;
  const bool projection_passed = projection.passed;
  if (!projection_passed) {
    writeArtifact(options, preflight_seconds, projected_total_seconds, false,
                  nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr,
                  nullptr, nullptr, 0, deadline.seconds());
    writeReadme(options, preflight_seconds, projected_total_seconds, false,
                nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
                deadline.seconds());
    output << std::fixed << std::setprecision(3)
           << "D4_STRUCTURAL_TERMINAL_VETO_RESULT {\"projectionPassed\":false,"
           << "\"preflightSeconds\":" << preflight_seconds
           << ",\"projectedTotalSeconds\":" << projected_total_seconds
           << ",\"fittingOpened\":false,\"screenOpened\":false,"
           << "\"artifact\":\"" << jsonEscape(options.output) << "\"}\n";
    return 2;
  }

  const Cohort fitting = runCohort(kFittingSeedStart, kFittingGames,
                                   SeedCohort::kFitting, options.threads,
                                   deadline, "fitting");
  const Summary fitting_d4 = summarize(fitting, Policy::kD4);
  const Summary fitting_candidate = summarize(fitting, Policy::kVeto);
  const Gate fitting_gate = cohortGate(
      fitting, fitting_d4, fitting_candidate, kFittingScoreRatio,
      kFittingMoveRatio, kFittingJointWins);
  const std::uint64_t fitting_switches =
      writeSwitches(options.switches, fitting, "fitting");

  std::optional<Cohort> screen;
  Summary screen_d4;
  Summary screen_candidate;
  Gate screen_gate;
  std::uint64_t screen_switches = 0;
  if (fitting_gate.passed) {
    screen = runCohort(kScreenSeedStart, kScreenGames, SeedCohort::kScreen,
                       options.threads, deadline, "screen");
    screen_d4 = summarize(*screen, Policy::kD4);
    screen_candidate = summarize(*screen, Policy::kVeto);
    screen_gate = cohortGate(*screen, screen_d4, screen_candidate,
                             kScreenScoreRatio, kScreenMoveRatio,
                             kScreenJointWins);
    screen_switches = writeSwitches(options.switches, *screen, "screen");
  }
  enforceRssLimit();
  writeArtifact(
      options, preflight_seconds, projected_total_seconds, true, &fitting,
      &fitting_d4, &fitting_candidate, &fitting_gate, fitting_switches,
      screen.has_value() ? &*screen : nullptr,
      screen.has_value() ? &screen_d4 : nullptr,
      screen.has_value() ? &screen_candidate : nullptr,
      screen.has_value() ? &screen_gate : nullptr, screen_switches,
      deadline.seconds());
  writeReadme(options, preflight_seconds, projected_total_seconds, true,
              &fitting_d4, &fitting_candidate, &fitting_gate,
              screen.has_value() ? &screen_d4 : nullptr,
              screen.has_value() ? &screen_candidate : nullptr,
              screen.has_value() ? &screen_gate : nullptr,
              deadline.seconds());
  output << std::fixed << std::setprecision(3)
         << "D4_STRUCTURAL_TERMINAL_VETO_RESULT {\"projectionPassed\":true,"
         << "\"preflightSeconds\":" << preflight_seconds
         << ",\"projectedTotalSeconds\":" << projected_total_seconds
         << ",\"fittingD4Score\":" << fitting_d4.mean_score
         << ",\"fittingD4Moves\":" << fitting_d4.mean_moves
         << ",\"fittingCandidateScore\":" << fitting_candidate.mean_score
         << ",\"fittingCandidateMoves\":"
         << fitting_candidate.mean_moves << ",\"fittingScoreRatio\":"
         << fitting_gate.score_ratio << ",\"fittingMoveRatio\":"
         << fitting_gate.move_ratio << ",\"fittingJointWins\":"
         << fitting_gate.joint_wins << ",\"fittingSwitches\":"
         << fitting_candidate.switches << ",\"fittingPassed\":"
         << (fitting_gate.passed ? "true" : "false")
         << ",\"screenOpened\":"
         << (screen.has_value() ? "true" : "false")
         << ",\"screenPassed\":"
         << (screen.has_value() && screen_gate.passed ? "true" : "false")
         << ",\"totalWallSeconds\":" << deadline.seconds()
         << ",\"peakRssBytes\":" << peakRssBytes()
         << ",\"artifact\":\"" << jsonEscape(options.output) << "\"}\n";
  return screen.has_value() && screen_gate.passed ? 0 : 2;
}

}  // namespace drop7::d4_structural_terminal_veto

int main(int argc, char** argv) {
  try {
    if (argc >= 2 && std::string_view(argv[1]) == "--self-test") {
      return drop7::d4_structural_terminal_veto::selfTest(std::cout)
                 ? EXIT_SUCCESS
                 : EXIT_FAILURE;
    }
    if (argc >= 2 && std::string_view(argv[1]) == "--run") {
      const auto options =
          drop7::d4_structural_terminal_veto::parseOptions(argc, argv, 2);
      return drop7::d4_structural_terminal_veto::run(options, std::cout);
    }
    if (argc >= 2 && std::string_view(argv[1]) == "--preflight") {
      const auto options =
          drop7::d4_structural_terminal_veto::parseOptions(argc, argv, 2);
      return drop7::d4_structural_terminal_veto::preflightOnly(options,
                                                               std::cout);
    }
    std::cerr << "usage: drop7_d4_structural_terminal_veto --self-test | "
                 "--preflight --source-sha256 HASH [--threads N] | "
                 "--run --source-sha256 HASH [--output PATH] "
                 "[--switches PATH] [--readme PATH] [--threads N]\n";
    return 2;
  } catch (const std::exception& error) {
    std::cerr << "drop7_d4_structural_terminal_veto: " << error.what()
              << '\n';
    return EXIT_FAILURE;
  }
}