#define DROP7_FAIR_ONLY_DEPTH4_LIBRARY
#include "../../fair-expectimax/reference/fair-only-depth4.cpp"
#undef DROP7_FAIR_ONLY_DEPTH4_LIBRARY
#include <bit>
#include <filesystem>
#include <optional>
#include <set>
#include <span>
#include <type_traits>
// B0 is an offline, falsification-first architecture/fidelity gate. It is
// deliberately incapable of starting or replaying an origin game. Its only
// stochastic evaluations begin at public roots in the checksum-locked,
// development-only corpus and use its recorded public-state-derived tape seed.
//
// Provenance exists in PanelRecord only to define an entire-origin-game fold.
// The actor boundary below accepts ActorInput, which contains public state and
// exact public D1 values but cannot carry the origin seed, move index, stored
// tape, history, score, level, or scenario id.
namespace drop7::full_panel_cpi_preflight {
namespace d1 = drop7::fair_only_horizon;
namespace d4 = drop7::fair_only_depth4;
namespace detail = drop7::cfpi::detail;
using Clock = std::chrono::steady_clock;
constexpr std::string_view kExpectedCorpusSha256 =
"bfda8ae32fa0be3577c6b27f6413aba28f2854930e2f91a0dcf7674808f04196";
constexpr int kExpectedRecords = 477;
constexpr int kExpectedGames = 8;
constexpr std::uint32_t kExpectedGameStart = 0x3d6d'0010u;
constexpr std::array<int, kExpectedGames> kExpectedGameRecords{{
77, 50, 55, 35, 35, 65, 55, 105,
}};
constexpr std::array<int, 4> kSampleSizes{{7, 21, 35, 63}};
constexpr int kMaximumSampleSize = 63;
constexpr int kStoredScenarioCount = 255;
constexpr int kHorizon = 200;
constexpr int kContinuationDepth = 1;
constexpr int kContinuationStrata = 5;
constexpr int kEventsPerStep = 64;
constexpr std::uint32_t kDeploymentPanelDomain = 0x5444'4550u;
constexpr std::uint32_t kRevealTapeDomain = 0x5452'564cu;
constexpr std::uint32_t kVisibleTapeDomain = 0x5456'4953u;
constexpr std::array<int, kBoardSize> kActionOrder{{3, 2, 4, 1, 5, 0, 6}};
constexpr double kStabilityMinimum = 0.70;
constexpr double kOverridePrecisionMinimum = 0.80;
constexpr double kOverrideRecallMinimum = 0.25;
constexpr double kPairwiseGainMinimum = 0.02;
constexpr double kRegretRatioMaximum = 0.90;
constexpr int kRequiredNonregressingFolds = 6;
constexpr double kActorOverrideMargin = 0.10;
constexpr double kTieTolerance = 1.0e-9;
constexpr double kPredictionTieTolerance = 1.0e-12;
constexpr int kActorWeights = 1024;
constexpr int kActorEpochs = 28;
constexpr float kActorLearningRate = 0.0125f;
constexpr float kActorWeightDecay = 2.0e-5f;
constexpr float kActorPointWeight = 0.35f;
constexpr float kActorPairWeight = 0.65f;
constexpr float kActorPairMargin = 0.20f;
constexpr float kActorGradientClip = 4.0f;
constexpr std::uint32_t kActorSeedA = 0x4230'4131u;
constexpr std::uint32_t kActorSeedB = 0x4230'4232u;
constexpr std::uint64_t kInputByteLimit = 32ull * 1024ull * 1024ull;
constexpr std::size_t kLineByteLimit = 512ull * 1024ull;
constexpr std::uint64_t kRssLimitBytes = 256ull * 1024ull * 1024ull;
constexpr double kWallLimitSeconds = 45.0 * 60.0;
constexpr int kMaximumThreads = 4;
constexpr std::uint64_t kMaximumSyntheticTransitions =
static_cast<std::uint64_t>(kExpectedRecords) * kBoardSize * 2ull *
kMaximumSampleSize * kHorizon;
constexpr std::uint64_t kMaximumD4Work =
static_cast<std::uint64_t>(kExpectedRecords) * d4::kMaximumWork;
static_assert(kStoredScenarioCount == 255);
static_assert(kHorizon == 200 && kContinuationDepth == 1);
static_assert(kContinuationStrata == d1::kChanceSamples);
static_assert(kEventsPerStep > kCellCount);
static_assert(kLevelBonus == 17'000 && kMovesPerLevel == 5);
static_assert(kExpectedGameStart + kExpectedGames == 0x3d6d'0018u);
static_assert(kSampleSizes.back() == kMaximumSampleSize);
struct RunOptions {
std::string input =
"/tmp/drop7-terminal-policy-deployment-panels.jsonl";
std::string input_sha256 = std::string(kExpectedCorpusSha256);
std::string output = "/tmp/drop7-full-panel-cpi-preflight.json";
int threads = kMaximumThreads;
};
std::filesystem::path resolvedPath(const std::string& source) {
std::error_code error;
const std::filesystem::path absolute =
std::filesystem::absolute(std::filesystem::path(source), error);
if (error) throw std::invalid_argument("could not resolve absolute path");
const std::filesystem::path resolved =
std::filesystem::weakly_canonical(absolute, error);
if (error) throw std::invalid_argument("could not weakly canonicalize path");
return resolved;
}
void validateDistinctInputOutput(const RunOptions& options) {
const std::filesystem::path input = resolvedPath(options.input);
const std::filesystem::path output = resolvedPath(options.output);
bool equivalent = input == output;
std::error_code exists_error;
const bool input_exists = std::filesystem::exists(input, exists_error);
if (exists_error) throw std::invalid_argument("could not inspect input path");
exists_error.clear();
const bool output_exists = std::filesystem::exists(output, exists_error);
if (exists_error) throw std::invalid_argument("could not inspect output path");
if (input_exists && output_exists) {
std::error_code equivalent_error;
equivalent = equivalent ||
std::filesystem::equivalent(input, output, equivalent_error);
if (equivalent_error) {
throw std::invalid_argument("could not compare input/output identity");
}
}
if (equivalent) {
throw std::invalid_argument(
"input and output resolve to the same filesystem object");
}
}
RunOptions parseOptions(int argc, char** argv, int begin) {
RunOptions result;
for (int index = begin; index < argc; ++index) {
if (index + 1 >= argc) throw std::invalid_argument("missing option value");
const std::string_view flag(argv[index]);
const std::string value(argv[++index]);
if (flag == "--input") result.input = value;
else if (flag == "--input-sha256") result.input_sha256 = value;
else if (flag == "--output") result.output = value;
else if (flag == "--threads") result.threads = std::stoi(value);
else throw std::invalid_argument("unknown option " + std::string(flag));
}
if (result.input.empty() || result.output.empty() ||
result.input_sha256 != kExpectedCorpusSha256) {
throw std::invalid_argument("the frozen panel checksum is not configurable");
}
if (result.threads < 1 || result.threads > kMaximumThreads) {
throw std::invalid_argument("threads must be in [1,4]");
}
validateDistinctInputOutput(result);
return result;
}
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
}
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("B0 preflight exceeded 45 minute wall limit");
}
if (peakRssBytes() > kRssLimitBytes) {
throw std::runtime_error("B0 preflight exceeded 256 MiB RSS limit");
}
}
};
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);
}
std::uint32_t seed32(std::uint64_t value) {
return mix32(static_cast<std::uint32_t>(value) ^
static_cast<std::uint32_t>(value >> 32u));
}
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 value) {
std::string result;
for (const char token : value) {
if (token == '"' || token == '\\') result.push_back('\\');
if (token == '\n') result += "\\n";
else result.push_back(token);
}
return result;
}
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)));
}
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 at = offset + static_cast<std::size_t>(word * 4);
words[word] = (static_cast<std::uint32_t>(message[at]) << 24) |
(static_cast<std::uint32_t>(message[at + 1]) << 16) |
(static_cast<std::uint32_t>(message[at + 2]) << 8) |
static_cast<std::uint32_t>(message[at + 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], b = hash[1], c = hash[2], d = hash[3];
std::uint32_t e = hash[4], f = hash[5], g = hash[6], h = hash[7];
for (int round = 0; round < 64; ++round) {
const std::uint32_t s1 =
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 + s1 + choose + kSha256Constants[round] + words[round];
const std::uint32_t s0 =
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 = s0 + 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 digits[] = "0123456789abcdef";
std::string result;
result.reserve(64);
for (const std::uint32_t value : hash) {
for (int shift = 28; shift >= 0; shift -= 4) {
result.push_back(digits[(value >> shift) & 0xfu]);
}
}
return result;
}
std::string readBoundedFile(const std::string& path) {
std::error_code error;
const std::uintmax_t size = std::filesystem::file_size(path, error);
if (error) throw std::runtime_error("could not stat frozen panel corpus");
if (size == 0 || size > kInputByteLimit) {
throw std::runtime_error("frozen panel corpus violates byte bound");
}
std::ifstream input(path, std::ios::binary);
if (!input) throw std::runtime_error("could not open frozen panel corpus");
std::string result(static_cast<std::size_t>(size), '\0');
input.read(result.data(), static_cast<std::streamsize>(result.size()));
if (!input || input.peek() != std::char_traits<char>::eof()) {
throw std::runtime_error("short or unstable frozen panel corpus read");
}
return result;
}
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;
};
State materialize(const PublicState& source) {
State result;
result.board = source.board;
result.next_disc = source.next_disc;
result.score = 0;
result.level = 1;
result.moves_remaining = source.moves_remaining;
result.moves_played = 0;
result.game_over = source.terminal;
return result;
}
PublicState publicState(const State& source) {
return {source.board, source.next_disc,
static_cast<std::uint8_t>(source.moves_remaining), source.game_over};
}
PublicState mirror(const PublicState& source) {
PublicState result = source;
result.board = detail::mirrorBoard(source.board);
return result;
}
PublicState canonicalPublic(const PublicState& source, bool& mirrored) {
return publicState(detail::canonicalState(materialize(source), mirrored));
}
std::uint64_t publicHash(const PublicState& source) {
bool ignored = false;
const PublicState state = 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) {
return seed32(publicHash(source) ^
static_cast<std::uint64_t>(kDeploymentPanelDomain));
}
std::size_t afterMarker(std::string_view text, std::string_view marker,
std::size_t begin = 0) {
const std::size_t found = text.find(marker, begin);
if (found == std::string_view::npos) {
throw std::runtime_error("missing JSON marker " + std::string(marker));
}
return found + marker.size();
}
long long integerAfter(std::string_view text, std::string_view marker,
std::size_t begin = 0) {
const std::size_t cursor = afterMarker(text, marker, begin);
const std::string owned(text);
char* end = nullptr;
const char* first = owned.c_str() + cursor;
const long long result = std::strtoll(first, &end, 10);
if (end == first) throw std::runtime_error("invalid JSON integer");
return result;
}
double numberAfter(std::string_view text, std::string_view marker,
std::size_t begin = 0) {
const std::size_t cursor = afterMarker(text, marker, begin);
const std::string owned(text);
char* end = nullptr;
const char* first = owned.c_str() + cursor;
const double result = std::strtod(first, &end);
if (end == first || !std::isfinite(result)) {
throw std::runtime_error("invalid JSON number");
}
return result;
}
bool booleanAfter(std::string_view text, std::string_view marker,
std::size_t begin = 0) {
const std::size_t cursor = afterMarker(text, marker, begin);
if (text.substr(cursor, 4) == "true") return true;
if (text.substr(cursor, 5) == "false") return false;
throw std::runtime_error("invalid JSON boolean");
}
std::string stringAfter(std::string_view text, std::string_view marker,
std::size_t begin = 0) {
const std::size_t cursor = afterMarker(text, marker, begin);
const std::size_t end = text.find('"', cursor);
if (end == std::string_view::npos) {
throw std::runtime_error("unterminated JSON string");
}
return std::string(text.substr(cursor, end - cursor));
}
std::size_t matchingDelimiter(std::string_view text, std::size_t begin,
char open, char close) {
if (begin >= text.size() || text[begin] != open) {
throw std::runtime_error("invalid JSON delimiter start");
}
int depth = 0;
bool quoted = false;
bool escaped = false;
for (std::size_t cursor = begin; cursor < text.size(); ++cursor) {
const char token = text[cursor];
if (quoted) {
if (escaped) escaped = false;
else if (token == '\\') escaped = true;
else if (token == '"') quoted = false;
continue;
}
if (token == '"') quoted = true;
else if (token == open) ++depth;
else if (token == close && --depth == 0) return cursor;
}
throw std::runtime_error("unterminated JSON delimiter");
}
void skipSeparators(std::string_view text, std::size_t& cursor) {
while (cursor < text.size() &&
(text[cursor] == ' ' || text[cursor] == '\t' ||
text[cursor] == ',')) {
++cursor;
}
}
std::uint64_t parseHex64(std::string_view text) {
const std::string owned(text);
char* end = nullptr;
const unsigned long long result = std::strtoull(owned.c_str(), &end, 0);
if (end == owned.c_str() || *end != '\0') {
throw std::runtime_error("invalid hexadecimal integer");
}
return static_cast<std::uint64_t>(result);
}
struct StoredAction {
bool legal = false;
double mean_score = 0.0;
double mean_moves = 0.0;
double mean_clears = 0.0;
double mean_reveals = 0.0;
int surviving_cutoffs = 0;
};
// Only origin_slot is later used, and only by the split coordinator. Neither
// this record nor any function accepting it is an actor inference boundary.
struct PanelRecord {
std::uint32_t origin_game = 0;
int origin_slot = -1;
int move_index = -1;
std::uint64_t stored_public_hash = 0;
std::uint32_t tape_seed = 0;
PublicState state{};
int stored_d1_action = -1;
int stored_deployment_action = -1;
std::array<StoredAction, kBoardSize> actions{};
};
StoredAction parseStoredAction(std::string_view object, int expected_action) {
StoredAction result;
result.legal = true;
if (integerAfter(object, "\"action\":") != expected_action) {
throw std::runtime_error("panel action index mismatch");
}
result.mean_score = numberAfter(object, "\"meanScoreReturn\":");
result.mean_moves = numberAfter(object, "\"meanSurvivedMoves\":");
result.mean_clears = numberAfter(object, "\"meanNumberedClears\":");
result.mean_reveals = numberAfter(object, "\"meanCoversRevealed\":");
result.surviving_cutoffs =
static_cast<int>(integerAfter(object, "\"survivingCutoffs\":"));
// The fixed h200 target includes the public fair leaf at a surviving
// cutoff, so a finite score return may legitimately be negative.
if (result.mean_moves < 0.0 || result.mean_moves > kHorizon ||
result.mean_clears < 0.0 ||
result.mean_reveals < 0.0 || result.surviving_cutoffs < 0 ||
result.surviving_cutoffs > kStoredScenarioCount) {
throw std::runtime_error("out-of-domain stored action summary");
}
return result;
}
PanelRecord parsePanel(std::string_view line) {
constexpr std::string_view excluded =
"\"excludedFromModelInput\":[\"screenSeed\",\"moveIndex\","
"\"canonicalPublicHash\",\"tapeSeed\",\"score\",\"level\","
"\"history\",\"scenario\"]";
if (line.empty() || line.size() > kLineByteLimit || line.front() != '{' ||
line.back() != '}' || line.find('\0') != std::string_view::npos ||
line.find("\"recordType\":\"deployment-panel-export-replay\"") ==
std::string_view::npos ||
line.find("\"gate\":\"ultra\"") == std::string_view::npos ||
line.find(excluded) == std::string_view::npos) {
throw std::runtime_error("unexpected panel record metadata");
}
PanelRecord result;
const long long origin = integerAfter(line, "\"screenSeed\":");
const long long tape = integerAfter(line, "\"tapeSeed\":");
if (origin < 0 || origin > std::numeric_limits<std::uint32_t>::max() ||
tape < 0 || tape > std::numeric_limits<std::uint32_t>::max()) {
throw std::runtime_error("invalid panel provenance integer");
}
result.origin_game = static_cast<std::uint32_t>(origin);
result.move_index = static_cast<int>(integerAfter(line, "\"moveIndex\":"));
result.stored_public_hash =
parseHex64(stringAfter(line, "\"canonicalPublicHash\":\""));
result.tape_seed = static_cast<std::uint32_t>(tape);
const std::string board = stringAfter(line, "\"board\":\"");
if (board.size() != kCellCount) throw std::runtime_error("invalid board size");
for (int cell = 0; cell < kCellCount; ++cell) {
if (board[cell] < '0' || board[cell] > '9') {
throw std::runtime_error("invalid board token");
}
result.state.board[cell] = static_cast<std::uint8_t>(board[cell] - '0');
if (result.state.board[cell] > kCracked) {
throw std::runtime_error("out-of-domain board token");
}
}
result.state.next_disc =
static_cast<std::uint8_t>(integerAfter(line, "\"nextDisc\":"));
result.state.moves_remaining =
static_cast<std::uint8_t>(integerAfter(line, "\"movesRemaining\":"));
result.state.terminal = booleanAfter(line, "\"terminal\":");
result.stored_d1_action =
static_cast<int>(integerAfter(line, "\"fairD1Action\":"));
result.stored_deployment_action =
static_cast<int>(integerAfter(line, "\"selectedAction\":"));
if (result.move_index < 0 || result.state.terminal ||
result.state.next_disc < 1 || result.state.next_disc > kBoardSize ||
result.state.moves_remaining < 1 ||
result.state.moves_remaining > kMovesPerLevel) {
throw std::runtime_error("invalid public root metadata");
}
std::size_t cursor = afterMarker(line, "\"actions\":[");
for (int action = 0; action < kBoardSize; ++action) {
skipSeparators(line, cursor);
if (line.substr(cursor, 4) == "null") {
cursor += 4;
continue;
}
if (cursor >= line.size() || line[cursor] != '{') {
throw std::runtime_error("invalid action array");
}
const std::size_t end = matchingDelimiter(line, cursor, '{', '}');
result.actions[action] =
parseStoredAction(line.substr(cursor, end - cursor + 1), action);
cursor = end + 1;
}
skipSeparators(line, cursor);
if (cursor >= line.size() || line[cursor] != ']') {
throw std::runtime_error("unterminated action array");
}
for (int action = 0; action < kBoardSize; ++action) {
if (result.actions[action].legal != isLegal(result.state.board, action)) {
throw std::runtime_error("stored legal mask differs from public state");
}
}
if (result.stored_d1_action < 0 ||
result.stored_d1_action >= kBoardSize ||
result.stored_deployment_action < 0 ||
result.stored_deployment_action >= kBoardSize ||
!result.actions[result.stored_d1_action].legal ||
!result.actions[result.stored_deployment_action].legal ||
publicHash(result.state) != result.stored_public_hash ||
panelSeed(result.state) != result.tape_seed) {
throw std::runtime_error("panel public-state/hash/tape invariant failed");
}
return result;
}
std::vector<PanelRecord> parseLockedCorpus(std::string_view bytes) {
if (bytes.size() > kInputByteLimit || sha256(bytes) != kExpectedCorpusSha256) {
throw std::runtime_error("frozen panel corpus SHA-256 mismatch");
}
std::vector<PanelRecord> result;
result.reserve(kExpectedRecords);
std::size_t begin = 0;
while (begin < bytes.size()) {
const std::size_t newline = bytes.find('\n', begin);
const std::size_t end =
newline == std::string_view::npos ? bytes.size() : newline;
if (end > begin) result.push_back(parsePanel(bytes.substr(begin, end - begin)));
begin = newline == std::string_view::npos ? bytes.size() : newline + 1;
}
if (result.size() != kExpectedRecords) {
throw std::runtime_error("frozen panel record count mismatch");
}
std::array<int, kExpectedGames> counts{};
std::array<int, kExpectedGames> next_move{};
for (PanelRecord& panel : result) {
const std::int64_t slot64 =
static_cast<std::int64_t>(panel.origin_game) - kExpectedGameStart;
if (slot64 < 0 || slot64 >= kExpectedGames) {
throw std::runtime_error("out-of-domain origin game");
}
panel.origin_slot = static_cast<int>(slot64);
if (panel.move_index != next_move[panel.origin_slot]++) {
throw std::runtime_error("origin records are not whole ordered games");
}
++counts[panel.origin_slot];
}
if (counts != kExpectedGameRecords || next_move != kExpectedGameRecords) {
throw std::runtime_error("frozen per-origin record counts changed");
}
return result;
}
std::vector<PanelRecord> loadLockedCorpus(const RunOptions& options) {
if (options.input_sha256 != kExpectedCorpusSha256) {
throw std::runtime_error("frozen checksum declaration changed");
}
return parseLockedCorpus(readBoundedFile(options.input));
}
// Each half takes a different point from each of 63 equal strata over the
// source 255 scenario ids. The 63 base positions are seven blocks of nine.
// Within every block, K=7 selects {4}, K=21 selects {1,4,7}, K=35 selects
// {1,2,4,6,7}, and K=63 selects all positions. Consequently each smaller set
// is an exact subset of every larger set and each of the seven coarse strata
// contributes exactly K/7 samples. The two scenario halves remain disjoint.
constexpr int scenarioAt(int half, int base_position) {
return ((4 * base_position + (half == 0 ? 1 : 3)) *
kStoredScenarioCount) /
(4 * kMaximumSampleSize);
}
constexpr int selectedBasePosition(int sample_index, int sample_position) {
if (sample_index < 0 || sample_index >= 4 || sample_position < 0 ||
sample_position >= kSampleSizes[sample_index]) {
throw std::invalid_argument("invalid nested sample position");
}
if (sample_index == 0) return sample_position * 9 + 4;
if (sample_index == 1) {
constexpr std::array<int, 3> offsets{{1, 4, 7}};
return (sample_position / 3) * 9 + offsets[sample_position % 3];
}
if (sample_index == 2) {
constexpr std::array<int, 5> offsets{{1, 2, 4, 6, 7}};
return (sample_position / 5) * 9 + offsets[sample_position % 5];
}
return sample_position;
}
std::vector<int> selectedBasePositions(int sample_index) {
if (sample_index < 0 || sample_index >= 4) {
throw std::invalid_argument("invalid sample index");
}
std::vector<int> result;
result.reserve(kSampleSizes[sample_index]);
for (int position = 0; position < kSampleSizes[sample_index]; ++position) {
result.push_back(selectedBasePosition(sample_index, position));
}
return result;
}
std::vector<int> selectedScenarios(int half, int sample_index) {
if (half < 0 || half > 1) throw std::invalid_argument("invalid sample half");
std::vector<int> result;
for (const int base : selectedBasePositions(sample_index)) {
result.push_back(scenarioAt(half, base));
}
return result;
}
std::array<int, kMaximumSampleSize> scenarioHalf(int half) {
if (half < 0 || half > 1) throw std::invalid_argument("invalid sample half");
std::array<int, kMaximumSampleSize> result{};
for (int position = 0; position < kMaximumSampleSize; ++position) {
result[position] = scenarioAt(half, position);
}
return result;
}
struct FairD1Decision {
int action = -1;
std::array<double, kBoardSize> values{};
std::uint64_t work = 0;
int evaluated_actions = 0;
};
// Public-only boundary. In particular, this cannot accept PanelRecord.
FairD1Decision chooseFairD1(const PublicState& source) {
FairD1Decision result;
result.values.fill(-std::numeric_limits<double>::infinity());
if (source.terminal) return result;
bool mirrored = false;
const PublicState canonical = canonicalPublic(source, mirrored);
d1::SearchContext context;
const d1::RootEvaluation root =
d1::rootDecision(materialize(canonical), kContinuationDepth, context);
int legal = 0;
int evaluated = 0;
for (int action = 0; action < kBoardSize; ++action) {
legal += isLegal(canonical.board, action);
evaluated += std::isfinite(root.values[action]);
}
if (root.action < 0 || legal != evaluated || !context.cache.empty() ||
context.work > 2ull * kBoardSize * kContinuationStrata) {
throw std::runtime_error("exact public D1 root did not complete");
}
result.action = mirrored ? kBoardSize - 1 - root.action : root.action;
for (int canonical_action = 0; canonical_action < kBoardSize;
++canonical_action) {
const int source_action = mirrored ? kBoardSize - 1 - canonical_action
: canonical_action;
result.values[source_action] = root.values[canonical_action];
}
result.work = context.work;
result.evaluated_actions = evaluated;
return result;
}
using PublicD1Boundary = FairD1Decision (*)(const PublicState&);
static_assert(std::is_same_v<decltype(&chooseFairD1), PublicD1Boundary>);
static_assert(!std::is_invocable_v<PublicD1Boundary, const PanelRecord&>);
struct SyntheticWork {
std::uint64_t transitions = 0;
std::uint64_t d1_calls = 0;
std::uint64_t d1_work = 0;
SyntheticWork& operator+=(const SyntheticWork& other) {
transitions += other.transitions;
d1_calls += other.d1_calls;
d1_work += other.d1_work;
return *this;
}
};
std::uint8_t visibleDisc(std::uint32_t root_seed, int scenario, int step) {
const double unit = detail::stratifiedUnit(
root_seed, scenario, kStoredScenarioCount, kVisibleTapeDomain, 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) {
if (source.terminal || scenario < 0 || scenario >= kStoredScenarioCount ||
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;
int event = 0;
std::uint8_t nextDisc() {
if (event >= kEventsPerStep) {
throw std::runtime_error("synthetic reveal slice exhausted");
}
const int event_index = step * kEventsPerStep + event++;
const double unit = detail::stratifiedUnit(
root_seed, scenario, kStoredScenarioCount, kRevealTapeDomain,
event_index);
return static_cast<std::uint8_t>(
std::floor(unit * static_cast<double>(kBoardSize)) + 1.0);
}
} reveals{root_seed, scenario, step};
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 depth = result.waves.empty() ? 1 : result.waves.back().depth + 1;
detail::resolveCascadeSampled(board, reveals, 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);
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 ScenarioOutcome {
double score = 0.0;
double moves = 0.0;
bool operator==(const ScenarioOutcome&) const = default;
};
ScenarioOutcome rolloutScenario(const PublicState& root, int root_action,
std::uint32_t root_seed, int scenario,
SyntheticWork& work,
const Deadline* deadline,
int horizon = kHorizon) {
if (root.terminal || !isLegal(root.board, root_action) || horizon < 1 ||
horizon > kHorizon) {
throw std::invalid_argument("invalid synthetic rollout root");
}
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 FairD1Decision continuation = chooseFairD1(state);
action = continuation.action;
++work.d1_calls;
work.d1_work += continuation.work;
}
MoveResult move;
if (!playSyntheticMove(state, action, root_seed, scenario, step, move)) {
throw std::runtime_error("synthetic rollout transition failed");
}
++work.transitions;
result.score += static_cast<double>(move.score_delta);
result.moves += 1.0;
state = publicState(move.state);
if (state.terminal) return result;
}
result.score += d1::fairLeaf(materialize(state));
return result;
}
struct SparseFeatures {
static constexpr int kCapacity = 96;
std::array<std::uint16_t, kCapacity> index{};
std::array<float, kCapacity> value{};
std::uint16_t size = 0;
void add(int at, float amount) {
if (at < 0 || at >= kActorWeights || !std::isfinite(amount)) {
throw std::invalid_argument("invalid actor feature");
}
for (int item = 0; item < size; ++item) {
if (index[item] == at) {
value[item] += amount;
return;
}
}
if (size >= kCapacity) throw std::runtime_error("actor feature overflow");
index[size] = static_cast<std::uint16_t>(at);
value[size] = amount;
++size;
}
bool operator==(const SparseFeatures&) const = default;
};
struct ActorInput {
PublicState state{};
std::array<double, kBoardSize> d1_q{};
};
static_assert(!std::is_constructible_v<ActorInput, PanelRecord>);
struct CanonicalActorInput {
PublicState state{};
std::array<double, kBoardSize> d1_q{};
int action = -1;
bool mirrored = false;
};
CanonicalActorInput canonicalizeStateAction(const ActorInput& input,
int source_action) {
if (source_action < 0 || source_action >= kBoardSize) {
throw std::invalid_argument("actor action is out of range");
}
const PublicState reflected = mirror(input.state);
const int reflected_action = kBoardSize - 1 - source_action;
const bool reflected_state_is_smaller =
std::lexicographical_compare(reflected.board.begin(),
reflected.board.end(),
input.state.board.begin(),
input.state.board.end());
const bool state_is_symmetric = reflected.board == input.state.board;
const bool use_reflection =
reflected_state_is_smaller ||
(state_is_symmetric && reflected_action < source_action);
CanonicalActorInput result;
result.state = use_reflection ? reflected : input.state;
result.action = use_reflection ? reflected_action : source_action;
result.mirrored = use_reflection;
for (int canonical_action = 0; canonical_action < kBoardSize;
++canonical_action) {
const int original_action =
use_reflection ? kBoardSize - 1 - canonical_action : canonical_action;
result.d1_q[canonical_action] = input.d1_q[original_action];
}
return result;
}
int hashedFeature(std::uint64_t domain, std::uint64_t key) {
constexpr int begin = 64;
return begin + static_cast<int>(mix64(domain ^ key) %
static_cast<std::uint64_t>(kActorWeights - begin));
}
SparseFeatures actorFeatures(const ActorInput& input, int source_action) {
if (source_action < 0 || source_action >= kBoardSize ||
!isLegal(input.state.board, source_action)) {
throw std::invalid_argument("illegal actor feature action");
}
const CanonicalActorInput canonical =
canonicalizeStateAction(input, source_action);
const PublicState& state = canonical.state;
const int action = canonical.action;
const auto& q = canonical.d1_q;
double q_min = std::numeric_limits<double>::infinity();
double q_max = -std::numeric_limits<double>::infinity();
double q_sum = 0.0;
int legal = 0;
for (int column = 0; column < kBoardSize; ++column) {
if (!isLegal(state.board, column)) continue;
if (!std::isfinite(q[column])) throw std::invalid_argument("invalid D1 Q");
q_min = std::min(q_min, q[column]);
q_max = std::max(q_max, q[column]);
q_sum += q[column];
++legal;
}
const double q_mean = q_sum / static_cast<double>(legal);
const double q_scale = std::max(1.0, q_max - q_min);
SparseFeatures result;
result.add(0, 1.0f);
result.add(1, static_cast<float>((q[action] - q_mean) / q_scale));
result.add(2, static_cast<float>((q[action] - q_max) / q_scale));
result.add(3, static_cast<float>(std::abs(action - 3) / 3.0));
result.add(8 + action, 1.0f);
result.add(16 + state.moves_remaining - 1, 1.0f);
result.add(24 + state.next_disc - 1, 1.0f);
const auto heights = detail::columnHeights(state.board);
int occupied = 0;
int maximum_height = 0;
for (int column = 0; column < kBoardSize; ++column) {
occupied += heights[column];
maximum_height = std::max(maximum_height, heights[column]);
const int relative = column - action + (kBoardSize - 1);
const std::uint64_t key =
static_cast<std::uint64_t>(relative * (kBoardSize + 1) + heights[column]);
result.add(hashedFeature(0x4845'4947ull, key), 1.0f);
}
result.add(32, static_cast<float>(occupied) / kCellCount);
result.add(33, static_cast<float>(maximum_height) / kBoardSize);
result.add(34, static_cast<float>(heights[action]) / kBoardSize);
for (int row = 0; row < kBoardSize; ++row) {
for (int column = 0; column < kBoardSize; ++column) {
const int relative = column - action + (kBoardSize - 1);
const std::uint64_t key =
static_cast<std::uint64_t>(((row * (2 * kBoardSize - 1) + relative) *
(kCracked + 1)) +
state.board[indexOf(row, column)]);
result.add(hashedFeature(0x4345'4c4cull, key), 1.0f);
}
}
return result;
}
using PublicActorBoundary = SparseFeatures (*)(const ActorInput&, int);
static_assert(std::is_same_v<decltype(&actorFeatures), PublicActorBoundary>);
static_assert(!std::is_invocable_v<PublicActorBoundary, const PanelRecord&, int>);
struct ActorModel {
std::array<float, kActorWeights> weights{};
double predict(const SparseFeatures& features) const {
double result = 0.0;
for (int item = 0; item < features.size; ++item) {
result += static_cast<double>(weights[features.index[item]]) *
features.value[item];
}
return result;
}
};
static_assert(sizeof(ActorModel) == kActorWeights * sizeof(float));
static_assert(sizeof(ActorModel) <= 8ull * 1024ull);
struct SampleMeans {
std::array<std::array<std::array<double, kBoardSize>, 4>, 2> score{};
std::array<std::array<std::array<double, kBoardSize>, 4>, 2> moves{};
};
struct RootData {
PanelRecord panel{};
FairD1Decision d1_search{};
d4::SearchDecision d4_search{};
std::array<SparseFeatures, kBoardSize> features{};
SampleMeans samples{};
SyntheticWork work{};
};
std::array<double, kBoardSize> storedTeacher(const RootData& root) {
std::array<double, kBoardSize> result{};
result.fill(-std::numeric_limits<double>::infinity());
for (int action = 0; action < kBoardSize; ++action) {
if (root.panel.actions[action].legal) {
result[action] = root.panel.actions[action].mean_score;
}
}
return result;
}
std::array<double, kBoardSize> normalizedTargets(
const RootData& root, int half, int sample_index) {
std::array<double, kBoardSize> result{};
double minimum = std::numeric_limits<double>::infinity();
double maximum = -std::numeric_limits<double>::infinity();
double sum = 0.0;
int legal = 0;
for (int action = 0; action < kBoardSize; ++action) {
if (!root.panel.actions[action].legal) continue;
const double value = root.samples.score[half][sample_index][action];
minimum = std::min(minimum, value);
maximum = std::max(maximum, value);
sum += value;
++legal;
}
const double mean = sum / static_cast<double>(legal);
const double scale = std::max(1.0, maximum - minimum);
for (int action = 0; action < kBoardSize; ++action) {
result[action] = root.panel.actions[action].legal
? (root.samples.score[half][sample_index][action] - mean) /
scale
: -std::numeric_limits<double>::infinity();
}
return result;
}
int bestAction(const std::array<double, kBoardSize>& values,
const std::array<StoredAction, kBoardSize>& legal) {
int best = -1;
for (const int action : kActionOrder) {
if (!legal[action].legal) continue;
if (best < 0 || values[action] > values[best] + kTieTolerance) best = action;
}
if (best < 0) throw std::runtime_error("no legal best action");
return best;
}
void addGradient(ActorModel& model, const SparseFeatures& features,
double gradient, float learning_rate) {
gradient = std::clamp(gradient, -static_cast<double>(kActorGradientClip),
static_cast<double>(kActorGradientClip));
for (int item = 0; item < features.size; ++item) {
float& weight = model.weights[features.index[item]];
const float feature = features.value[item];
weight -= learning_rate *
(static_cast<float>(gradient) * feature +
kActorWeightDecay * weight);
}
}
struct FoldSelection {
int heldout_origin = -1;
std::vector<bool> eligible;
std::size_t heldout_origin_roots = 0;
std::size_t purged_canonical_state_roots = 0;
std::size_t training_roots = 0;
};
PublicState exactCanonicalPublicState(const PublicState& source) {
bool ignored = false;
return canonicalPublic(source, ignored);
}
FoldSelection buildFoldSelection(const std::vector<RootData>& roots,
int heldout_origin) {
if (heldout_origin < 0 || heldout_origin >= kExpectedGames) {
throw std::invalid_argument("invalid heldout origin");
}
FoldSelection result;
result.heldout_origin = heldout_origin;
result.eligible.assign(roots.size(), false);
std::vector<PublicState> heldout_states;
heldout_states.reserve(roots.size());
for (const RootData& root : roots) {
if (root.panel.origin_slot == heldout_origin) {
heldout_states.push_back(exactCanonicalPublicState(root.panel.state));
++result.heldout_origin_roots;
}
}
if (heldout_states.empty()) {
throw std::runtime_error("whole-origin fold has no heldout roots");
}
for (std::size_t index = 0; index < roots.size(); ++index) {
const RootData& root = roots[index];
if (root.panel.origin_slot == heldout_origin) continue;
const PublicState candidate = exactCanonicalPublicState(root.panel.state);
const bool duplicates_heldout =
std::find(heldout_states.begin(), heldout_states.end(), candidate) !=
heldout_states.end();
if (duplicates_heldout) {
++result.purged_canonical_state_roots;
continue;
}
result.eligible[index] = true;
++result.training_roots;
}
if (result.training_roots + result.heldout_origin_roots +
result.purged_canonical_state_roots !=
roots.size()) {
throw std::runtime_error("fold exclusion accounting failed");
}
return result;
}
std::vector<std::size_t> trainingOrder(const std::vector<RootData>& roots,
const FoldSelection& selection,
std::uint32_t domain, int epoch) {
if (selection.eligible.size() != roots.size()) {
throw std::invalid_argument("fold selection size mismatch");
}
std::vector<std::size_t> result;
result.reserve(roots.size());
for (std::size_t index = 0; index < roots.size(); ++index) {
if (selection.eligible[index]) result.push_back(index);
}
if (result.size() != selection.training_roots) {
throw std::runtime_error("fold training count changed");
}
std::uint32_t state = mix32(domain ^ static_cast<std::uint32_t>(epoch));
for (std::size_t index = result.size(); index > 1; --index) {
state = mix32(state + 0x9e37'79b9u);
const std::size_t other = state % index;
std::swap(result[index - 1], result[other]);
}
return result;
}
ActorModel trainActor(const std::vector<RootData>& roots,
const FoldSelection& selection, int half,
int sample_index, std::uint32_t domain) {
if (selection.heldout_origin < 0 ||
selection.heldout_origin >= kExpectedGames || half < 0 || half > 1 ||
sample_index < 0 || sample_index >= 4 ||
selection.eligible.size() != roots.size()) {
throw std::invalid_argument("invalid actor training split");
}
ActorModel result;
for (int epoch = 0; epoch < kActorEpochs; ++epoch) {
const float learning_rate =
kActorLearningRate / std::sqrt(1.0f + 0.12f * epoch);
const std::vector<std::size_t> order =
trainingOrder(roots, selection, domain, epoch);
for (const std::size_t root_index : order) {
const RootData& root = roots[root_index];
if (!selection.eligible[root_index] ||
root.panel.origin_slot == selection.heldout_origin) {
throw std::runtime_error("whole-origin/state-group fold leakage");
}
const auto target = normalizedTargets(root, half, sample_index);
std::array<double, kBoardSize> prediction{};
prediction.fill(-std::numeric_limits<double>::infinity());
for (int action = 0; action < kBoardSize; ++action) {
if (!root.panel.actions[action].legal) continue;
prediction[action] = result.predict(root.features[action]);
addGradient(result, root.features[action],
kActorPointWeight * (prediction[action] - target[action]),
learning_rate);
}
const int teacher_best = bestAction(target, root.panel.actions);
for (int action = 0; action < kBoardSize; ++action) {
if (!root.panel.actions[action].legal || action == teacher_best) continue;
const double target_gap = target[teacher_best] - target[action];
if (target_gap <= kTieTolerance) continue;
const double predicted_gap =
result.predict(root.features[teacher_best]) -
result.predict(root.features[action]);
if (predicted_gap >= kActorPairMargin) continue;
const double gradient = kActorPairWeight *
(predicted_gap - kActorPairMargin);
addGradient(result, root.features[teacher_best], gradient,
learning_rate);
addGradient(result, root.features[action], -gradient, learning_rate);
}
}
}
return result;
}
std::uint64_t actorFingerprint(const ActorModel& model) {
std::uint64_t result = 0x4230'4143'544f'5221ull;
for (const float weight : model.weights) {
result = mix64(result ^ std::bit_cast<std::uint32_t>(weight));
}
return result;
}
RootData evaluateRoot(const PanelRecord& panel, const Deadline& deadline) {
RootData result;
result.panel = panel;
result.d1_search = chooseFairD1(panel.state);
if (result.d1_search.action != panel.stored_d1_action) {
throw std::runtime_error("stored and exact public D1 actions differ");
}
result.d4_search = d4::chooseDepth4Action(materialize(panel.state));
if (!result.d4_search.complete ||
result.d4_search.completed_depth != d4::kCandidateDepth ||
result.d4_search.action < 0 ||
result.d4_search.work > d4::kMaximumWork) {
throw std::runtime_error("exact public D4 root did not complete");
}
ActorInput actor_input{panel.state, result.d1_search.values};
for (int action = 0; action < kBoardSize; ++action) {
if (panel.actions[action].legal) {
result.features[action] = actorFeatures(actor_input, action);
}
}
std::array<std::array<std::array<ScenarioOutcome, kMaximumSampleSize>, 2>,
kBoardSize>
outcomes{};
for (int action = 0; action < kBoardSize; ++action) {
if (!panel.actions[action].legal) continue;
for (int half = 0; half < 2; ++half) {
for (int position = 0; position < kMaximumSampleSize; ++position) {
outcomes[action][half][position] = rolloutScenario(
panel.state, action, panel.tape_seed, scenarioAt(half, position),
result.work, &deadline);
}
}
}
for (int half = 0; half < 2; ++half) {
for (int sample_index = 0; sample_index < 4; ++sample_index) {
const int sample_size = kSampleSizes[sample_index];
for (int action = 0; action < kBoardSize; ++action) {
if (!panel.actions[action].legal) continue;
double score = 0.0;
double moves = 0.0;
for (int position = 0; position < sample_size; ++position) {
const int base = selectedBasePosition(sample_index, position);
score += outcomes[action][half][base].score;
moves += outcomes[action][half][base].moves;
}
result.samples.score[half][sample_index][action] =
score / sample_size;
result.samples.moves[half][sample_index][action] =
moves / sample_size;
}
}
}
if (result.work.transitions >
static_cast<std::uint64_t>(kBoardSize) * 2ull * kMaximumSampleSize *
kHorizon) {
throw std::runtime_error("per-root synthetic work proof failed");
}
deadline.check();
return result;
}
struct EvaluatedCorpus {
std::vector<RootData> roots;
SyntheticWork synthetic{};
std::uint64_t d4_work = 0;
std::uint64_t d4_nodes = 0;
};
EvaluatedCorpus evaluateCorpus(const std::vector<PanelRecord>& panels,
int threads, const Deadline& deadline) {
EvaluatedCorpus result;
result.roots.resize(panels.size());
std::atomic<std::size_t> next{0};
std::atomic<std::size_t> completed{0};
std::mutex progress_mutex;
std::vector<std::future<void>> workers;
for (int worker = 0; worker < threads; ++worker) {
workers.push_back(std::async(std::launch::async, [&] {
for (;;) {
const std::size_t index = next.fetch_add(1);
if (index >= panels.size()) return;
result.roots[index] = evaluateRoot(panels[index], deadline);
const std::size_t done = completed.fetch_add(1) + 1;
if (done % 10 == 0 || done == panels.size()) {
const std::lock_guard<std::mutex> lock(progress_mutex);
std::cerr << "B0 burned-root evaluation " << done << '/'
<< panels.size() << '\n';
}
}
}));
}
for (auto& worker : workers) worker.get();
for (const RootData& root : result.roots) {
result.synthetic += root.work;
result.d4_work += root.d4_search.work;
result.d4_nodes += root.d4_search.nodes;
}
if (result.synthetic.transitions > kMaximumSyntheticTransitions ||
result.d4_work > kMaximumD4Work) {
throw std::runtime_error("whole-corpus work proof failed");
}
deadline.check();
return result;
}
struct RankingAccumulator {
std::uint64_t roots = 0;
std::uint64_t pairs = 0;
double pairwise_credit = 0.0;
double top1_credit = 0.0;
double normalized_regret = 0.0;
};
void addRanking(RankingAccumulator& result,
const std::array<double, kBoardSize>& prediction,
const std::array<double, kBoardSize>& teacher,
const std::array<StoredAction, kBoardSize>& actions) {
const int selected = bestAction(prediction, actions);
const int teacher_best = bestAction(teacher, actions);
double teacher_minimum = std::numeric_limits<double>::infinity();
double teacher_maximum = -std::numeric_limits<double>::infinity();
for (int action = 0; action < kBoardSize; ++action) {
if (!actions[action].legal) continue;
teacher_minimum = std::min(teacher_minimum, teacher[action]);
teacher_maximum = std::max(teacher_maximum, teacher[action]);
}
++result.roots;
result.top1_credit +=
std::abs(teacher[selected] - teacher[teacher_best]) <= kTieTolerance;
const double range = teacher_maximum - teacher_minimum;
if (range > kTieTolerance) {
result.normalized_regret +=
(teacher_maximum - teacher[selected]) / range;
}
for (int first = 0; first < kBoardSize; ++first) {
if (!actions[first].legal) continue;
for (int second = first + 1; second < kBoardSize; ++second) {
if (!actions[second].legal) continue;
const double truth = teacher[first] - teacher[second];
const double guessed = prediction[first] - prediction[second];
result.pairwise_credit +=
std::abs(truth) <= kTieTolerance ||
std::abs(guessed) <= kPredictionTieTolerance
? 0.5
: ((truth > 0.0) == (guessed > 0.0) ? 1.0 : 0.0);
++result.pairs;
}
}
}
struct RankingMetrics {
double top1 = 0.0;
double pairwise = 0.0;
double normalized_regret = 0.0;
};
RankingMetrics finishRanking(const RankingAccumulator& source) {
if (source.roots == 0 || source.pairs == 0) return {};
return {source.top1_credit / source.roots,
source.pairwise_credit / source.pairs,
source.normalized_regret / source.roots};
}
struct FoldMetrics {
RankingMetrics actor{};
RankingMetrics d4{};
bool pairwise_regret_nonregression = false;
std::size_t heldout_origin_roots = 0;
std::size_t purged_canonical_state_roots = 0;
std::size_t training_roots = 0;
};
struct HalfMetrics {
RankingMetrics actor{};
RankingMetrics d4{};
double hybrid_mean_score = 0.0;
double d4_mean_score = 0.0;
bool pairwise_regret_nonregression = false;
bool hybrid_score_nonregression = false;
};
struct SampleEvaluation {
int sample_size = 0;
double independent_half_top_action_stability = 0.0;
double half_a_full_top_fidelity = 0.0;
double half_b_full_top_fidelity = 0.0;
RankingMetrics actor{};
RankingMetrics d4{};
std::uint64_t predicted_overrides = 0;
std::uint64_t beneficial_override_roots = 0;
std::uint64_t true_positive_overrides = 0;
double override_precision = 0.0;
double override_recall = 0.0;
int nonregressing_folds = 0;
std::array<FoldMetrics, kExpectedGames> folds{};
std::array<HalfMetrics, 2> halves{};
bool stability_gate = false;
bool precision_gate = false;
bool recall_gate = false;
bool pairwise_gate = false;
bool regret_gate = false;
bool fold_gate = false;
bool halves_ranking_gate = false;
bool halves_hybrid_score_gate = false;
bool passed = false;
};
struct RootPrediction {
std::array<double, kBoardSize> actor_a{};
std::array<double, kBoardSize> actor_b{};
std::array<double, kBoardSize> actor_mean{};
int hybrid_action = -1;
};
bool rankingNonregression(const RankingMetrics& actor,
const RankingMetrics& baseline) {
return actor.pairwise + kTieTolerance >= baseline.pairwise &&
actor.normalized_regret <= baseline.normalized_regret + kTieTolerance;
}
void applyFrozenGates(SampleEvaluation& result) {
result.stability_gate =
result.independent_half_top_action_stability >= kStabilityMinimum;
result.precision_gate =
result.override_precision >= kOverridePrecisionMinimum;
result.recall_gate = result.override_recall >= kOverrideRecallMinimum;
result.pairwise_gate =
result.actor.pairwise + kTieTolerance >=
result.d4.pairwise + kPairwiseGainMinimum;
result.regret_gate =
result.actor.normalized_regret <=
kRegretRatioMaximum * result.d4.normalized_regret + kTieTolerance;
result.fold_gate =
result.nonregressing_folds >= kRequiredNonregressingFolds;
result.halves_ranking_gate =
result.halves[0].pairwise_regret_nonregression &&
result.halves[1].pairwise_regret_nonregression;
result.halves_hybrid_score_gate =
result.halves[0].hybrid_score_nonregression &&
result.halves[1].hybrid_score_nonregression;
result.passed = result.stability_gate && result.precision_gate &&
result.recall_gate && result.pairwise_gate &&
result.regret_gate && result.fold_gate &&
result.halves_ranking_gate &&
result.halves_hybrid_score_gate;
}
SampleEvaluation evaluateSample(const std::vector<RootData>& roots,
int sample_index) {
SampleEvaluation result;
result.sample_size = kSampleSizes[sample_index];
std::vector<RootPrediction> predictions(roots.size());
for (int fold = 0; fold < kExpectedGames; ++fold) {
const FoldSelection selection = buildFoldSelection(roots, fold);
result.folds[fold].heldout_origin_roots =
selection.heldout_origin_roots;
result.folds[fold].purged_canonical_state_roots =
selection.purged_canonical_state_roots;
result.folds[fold].training_roots = selection.training_roots;
const ActorModel actor_a =
trainActor(roots, selection, 0, sample_index, kActorSeedA);
const ActorModel actor_b =
trainActor(roots, selection, 1, sample_index, kActorSeedB);
for (std::size_t index = 0; index < roots.size(); ++index) {
const RootData& root = roots[index];
if (root.panel.origin_slot != fold) continue;
RootPrediction& prediction = predictions[index];
prediction.actor_a.fill(-std::numeric_limits<double>::infinity());
prediction.actor_b.fill(-std::numeric_limits<double>::infinity());
prediction.actor_mean.fill(-std::numeric_limits<double>::infinity());
for (int action = 0; action < kBoardSize; ++action) {
if (!root.panel.actions[action].legal) continue;
prediction.actor_a[action] = actor_a.predict(root.features[action]);
prediction.actor_b[action] = actor_b.predict(root.features[action]);
prediction.actor_mean[action] =
0.5 * (prediction.actor_a[action] + prediction.actor_b[action]);
}
const int action_a = bestAction(prediction.actor_a, root.panel.actions);
const int action_b = bestAction(prediction.actor_b, root.panel.actions);
const int d1_action = root.d1_search.action;
prediction.hybrid_action = d1_action;
if (action_a == action_b && action_a != d1_action &&
prediction.actor_a[action_a] - prediction.actor_a[d1_action] >=
kActorOverrideMargin &&
prediction.actor_b[action_b] - prediction.actor_b[d1_action] >=
kActorOverrideMargin) {
prediction.hybrid_action = action_a;
}
}
}
RankingAccumulator actor_overall;
RankingAccumulator d4_overall;
std::array<RankingAccumulator, kExpectedGames> actor_fold{};
std::array<RankingAccumulator, kExpectedGames> d4_fold{};
std::array<RankingAccumulator, 2> actor_half{};
std::array<RankingAccumulator, 2> d4_half{};
std::array<double, 2> hybrid_score{};
std::array<double, 2> d4_score{};
std::array<int, 2> half_roots{};
std::uint64_t stable = 0;
std::uint64_t fidelity_a = 0;
std::uint64_t fidelity_b = 0;
for (std::size_t index = 0; index < roots.size(); ++index) {
const RootData& root = roots[index];
const RootPrediction& prediction = predictions[index];
const auto teacher = storedTeacher(root);
const int full_best = bestAction(teacher, root.panel.actions);
const int sample_a =
bestAction(root.samples.score[0][sample_index], root.panel.actions);
const int sample_b =
bestAction(root.samples.score[1][sample_index], root.panel.actions);
stable += sample_a == sample_b;
fidelity_a += sample_a == full_best;
fidelity_b += sample_b == full_best;
const int fold = root.panel.origin_slot;
const int half = fold < 4 ? 0 : 1;
addRanking(actor_overall, prediction.actor_mean, teacher,
root.panel.actions);
addRanking(d4_overall, root.d4_search.root_values, teacher,
root.panel.actions);
addRanking(actor_fold[fold], prediction.actor_mean, teacher,
root.panel.actions);
addRanking(d4_fold[fold], root.d4_search.root_values, teacher,
root.panel.actions);
addRanking(actor_half[half], prediction.actor_mean, teacher,
root.panel.actions);
addRanking(d4_half[half], root.d4_search.root_values, teacher,
root.panel.actions);
const int d1_action = root.d1_search.action;
const int hybrid_action = prediction.hybrid_action;
const bool beneficial = teacher[full_best] > teacher[d1_action] +
kTieTolerance;
result.beneficial_override_roots += beneficial;
if (hybrid_action != d1_action) {
++result.predicted_overrides;
if (teacher[hybrid_action] > teacher[d1_action] + kTieTolerance) {
++result.true_positive_overrides;
}
}
hybrid_score[half] += teacher[hybrid_action];
d4_score[half] += teacher[root.d4_search.action];
++half_roots[half];
}
result.independent_half_top_action_stability =
static_cast<double>(stable) / roots.size();
result.half_a_full_top_fidelity = static_cast<double>(fidelity_a) / roots.size();
result.half_b_full_top_fidelity = static_cast<double>(fidelity_b) / roots.size();
result.actor = finishRanking(actor_overall);
result.d4 = finishRanking(d4_overall);
result.override_precision =
result.predicted_overrides == 0
? 0.0
: static_cast<double>(result.true_positive_overrides) /
result.predicted_overrides;
result.override_recall =
result.beneficial_override_roots == 0
? 0.0
: static_cast<double>(result.true_positive_overrides) /
result.beneficial_override_roots;
for (int fold = 0; fold < kExpectedGames; ++fold) {
result.folds[fold].actor = finishRanking(actor_fold[fold]);
result.folds[fold].d4 = finishRanking(d4_fold[fold]);
result.folds[fold].pairwise_regret_nonregression =
rankingNonregression(result.folds[fold].actor, result.folds[fold].d4);
result.nonregressing_folds +=
result.folds[fold].pairwise_regret_nonregression;
}
for (int half = 0; half < 2; ++half) {
result.halves[half].actor = finishRanking(actor_half[half]);
result.halves[half].d4 = finishRanking(d4_half[half]);
result.halves[half].hybrid_mean_score =
hybrid_score[half] / half_roots[half];
result.halves[half].d4_mean_score = d4_score[half] / half_roots[half];
result.halves[half].pairwise_regret_nonregression =
rankingNonregression(result.halves[half].actor,
result.halves[half].d4);
result.halves[half].hybrid_score_nonregression =
result.halves[half].hybrid_mean_score + kTieTolerance >=
result.halves[half].d4_mean_score;
}
applyFrozenGates(result);
return result;
}
void writeRanking(std::ostream& output, const RankingMetrics& value) {
output << "{\"top1\":" << value.top1 << ",\"pairwise\":"
<< value.pairwise << ",\"normalizedRegret\":"
<< value.normalized_regret << '}';
}
void writeSample(std::ostream& output, const SampleEvaluation& value) {
output << "{\"K\":" << value.sample_size
<< ",\"independentHalfTopActionStability\":"
<< value.independent_half_top_action_stability
<< ",\"halfAFullTopFidelity\":" << value.half_a_full_top_fidelity
<< ",\"halfBFullTopFidelity\":" << value.half_b_full_top_fidelity
<< ",\"actor\":";
writeRanking(output, value.actor);
output << ",\"exactD4\":";
writeRanking(output, value.d4);
output << ",\"overrides\":{\"predicted\":" << value.predicted_overrides
<< ",\"beneficialRoots\":" << value.beneficial_override_roots
<< ",\"truePositive\":" << value.true_positive_overrides
<< ",\"precision\":" << value.override_precision
<< ",\"recall\":" << value.override_recall << "},\"folds\":[";
for (int fold = 0; fold < kExpectedGames; ++fold) {
if (fold) output << ',';
output << "{\"heldoutOrigin\":\"" << hex64(kExpectedGameStart + fold)
<< "\",\"heldoutOriginRoots\":"
<< value.folds[fold].heldout_origin_roots
<< ",\"purgedExactCanonicalPublicStateRoots\":"
<< value.folds[fold].purged_canonical_state_roots
<< ",\"trainingRootsAfterPurge\":"
<< value.folds[fold].training_roots
<< ",\"actor\":";
writeRanking(output, value.folds[fold].actor);
output << ",\"exactD4\":";
writeRanking(output, value.folds[fold].d4);
output << ",\"pairwiseRegretNonregression\":"
<< (value.folds[fold].pairwise_regret_nonregression ? "true" : "false")
<< '}';
}
output << "],\"fourGameHalves\":[";
for (int half = 0; half < 2; ++half) {
if (half) output << ',';
output << "{\"actor\":";
writeRanking(output, value.halves[half].actor);
output << ",\"exactD4\":";
writeRanking(output, value.halves[half].d4);
output << ",\"hybridMeanScore\":" << value.halves[half].hybrid_mean_score
<< ",\"exactD4MeanScore\":" << value.halves[half].d4_mean_score
<< ",\"pairwiseRegretNonregression\":"
<< (value.halves[half].pairwise_regret_nonregression ? "true" : "false")
<< ",\"hybridScoreNonregression\":"
<< (value.halves[half].hybrid_score_nonregression ? "true" : "false")
<< '}';
}
output << "],\"gates\":{\"stability\":"
<< (value.stability_gate ? "true" : "false")
<< ",\"overridePrecision\":"
<< (value.precision_gate ? "true" : "false")
<< ",\"overrideRecall\":"
<< (value.recall_gate ? "true" : "false")
<< ",\"pairwiseGain\":"
<< (value.pairwise_gate ? "true" : "false")
<< ",\"regretRatio\":"
<< (value.regret_gate ? "true" : "false")
<< ",\"wholeOriginFolds\":"
<< (value.fold_gate ? "true" : "false")
<< ",\"bothFourGameHalvesRanking\":"
<< (value.halves_ranking_gate ? "true" : "false")
<< ",\"bothFourGameHalvesHybridScore\":"
<< (value.halves_hybrid_score_gate ? "true" : "false")
<< ",\"passed\":" << (value.passed ? "true" : "false") << "}}";
}
void writeIntegerArray(std::ostream& output, const std::vector<int>& values) {
output << '[';
for (std::size_t index = 0; index < values.size(); ++index) {
if (index) output << ',';
output << values[index];
}
output << ']';
}
void writeSamplingSelections(std::ostream& output) {
output << '[';
for (int sample_index = 0; sample_index < 4; ++sample_index) {
if (sample_index) output << ',';
output << "{\"K\":" << kSampleSizes[sample_index]
<< ",\"basePositions\":";
writeIntegerArray(output, selectedBasePositions(sample_index));
output << ",\"halfAScenarios\":";
writeIntegerArray(output, selectedScenarios(0, sample_index));
output << ",\"halfBScenarios\":";
writeIntegerArray(output, selectedScenarios(1, sample_index));
output << '}';
}
output << ']';
}
void writeArtifact(const RunOptions& options,
const std::array<SampleEvaluation, 4>& evaluations,
const EvaluatedCorpus& corpus, double wall_seconds) {
// Repeat immediately before truncation to narrow path/symlink TOCTOU risk.
validateDistinctInputOutput(options);
std::ofstream output(options.output, std::ios::trunc);
if (!output) throw std::runtime_error("could not write B0 artifact");
output << std::setprecision(12)
<< "{\n \"experiment\":\"drop7-full-panel-cpi-preflight-b0\","
<< "\n \"status\":\""
<< (evaluations.back().passed ? "passed" : "falsified") << "\","
<< "\n \"corpus\":{\"path\":\"" << jsonEscape(options.input)
<< "\",\"sha256\":\"" << kExpectedCorpusSha256
<< "\",\"records\":" << corpus.roots.size()
<< ",\"wholeOriginGames\":" << kExpectedGames
<< ",\"newGameplaySeeds\":0,\"originTransitions\":0},"
<< "\n \"sampling\":{\"storedScenarioCount\":"
<< kStoredScenarioCount
<< ",\"balancedDisjointHalves\":true,\"nestedK\":[7,21,35,63],"
"\"coarseBalance\":\"exactly K/7 positions in each contiguous "
"nine-position base block\",\"continuation\":\"exact public D1\","
"\"horizon\":"
<< kHorizon << ",\"exactSelections\":";
writeSamplingSelections(output);
output << "},"
<< "\n \"actor\":{\"publicInputs\":[\"board\",\"nextDisc\","
"\"movesRemaining\",\"action\",\"exactPublicD1Q\"],"
"\"forbiddenInputs\":[\"screenSeed\",\"moveIndex\","
"\"canonicalPublicHash\",\"tapeSeed\",\"score\",\"level\","
"\"history\",\"scenario\"],\"reflectionExact\":true,"
"\"canonicalization\":\"joint lexicographic public-state/action; "
"symmetric-state ties use the smaller reflected action and remap "
"the complete D1-Q vector\","
"\"weightsPerMember\":"
<< kActorWeights << ",\"float32BytesPerMember\":"
<< sizeof(ActorModel) << ",\"members\":2,\"epochs\":"
<< kActorEpochs << ",\"overrideMargin\":"
<< kActorOverrideMargin
<< ",\"fallback\":\"exact public D1\"},"
<< "\n \"frozenThresholds\":{\"K63StabilityMinimum\":"
<< kStabilityMinimum << ",\"overridePrecisionMinimum\":"
<< kOverridePrecisionMinimum << ",\"overrideRecallMinimum\":"
<< kOverrideRecallMinimum << ",\"pairwiseGainOverD4Minimum\":"
<< kPairwiseGainMinimum << ",\"regretRatioToD4Maximum\":"
<< kRegretRatioMaximum << ",\"nonregressingWholeOriginFolds\":"
<< kRequiredNonregressingFolds
<< ",\"bothFourGameHalvesMustPass\":true,"
"\"crossValidationExclusion\":\"entire heldout origin plus every "
"other-origin root with exactly equal canonical board, nextDisc, "
"movesRemaining, and terminal flag; no hash surrogate\"},"
<< "\n \"metricDefinitions\":{\"pairwiseDenominator\":"
"\"every unordered legal-action pair, including ties\","
"\"targetTieAbsoluteTolerance\":"
<< kTieTolerance << ",\"predictionTieAbsoluteTolerance\":"
<< kPredictionTieTolerance
<< ",\"targetOrPredictionTieCredit\":0.5,"
"\"nonTieCredit\":\"1 iff signs agree, otherwise 0\","
"\"normalizedRegret\":\"(teacher maximum - teacher value of "
"predicted top action)/(teacher maximum - teacher minimum), zero "
"for a tied teacher range\"},"
<< "\n \"evaluations\":[";
for (int index = 0; index < 4; ++index) {
if (index) output << ',';
writeSample(output, evaluations[index]);
}
output << "],\n \"B0Decision\":{\"usesK\":63,\"passed\":"
<< (evaluations.back().passed ? "true" : "false")
<< ",\"consequence\":\""
<< (evaluations.back().passed
? "architecture may proceed to a separately preregistered training lane"
: "stop before opening any fresh gameplay lane")
<< "\"},"
<< "\n \"resources\":{\"syntheticTransitions\":"
<< corpus.synthetic.transitions << ",\"syntheticTransitionLimit\":"
<< kMaximumSyntheticTransitions << ",\"exactD1Calls\":"
<< corpus.synthetic.d1_calls << ",\"exactD1Work\":"
<< corpus.synthetic.d1_work << ",\"exactD4Work\":"
<< corpus.d4_work << ",\"exactD4WorkLimit\":" << kMaximumD4Work
<< ",\"exactD4Nodes\":" << corpus.d4_nodes
<< ",\"wallSeconds\":" << wall_seconds << ",\"wallLimitSeconds\":"
<< kWallLimitSeconds << ",\"peakRssBytes\":" << peakRssBytes()
<< ",\"rssLimitBytes\":" << kRssLimitBytes << "},"
<< "\n \"claims\":{\"architectureEvidenceOnly\":true,"
"\"gameplayPerformanceClaim\":false,\"censorRateGate\":false,"
"\"terminalScoreImputation\":false}\n}\n";
if (!output) throw std::runtime_error("could not finish B0 artifact");
}
void expect(bool condition, std::string_view message) {
if (!condition) throw std::runtime_error(std::string(message));
}
std::string fixturePanelJson(const PublicState& state) {
std::ostringstream output;
output << std::setprecision(12)
<< "{\"recordType\":\"deployment-panel-export-replay\","
<< "\"provenance\":{\"screenSeed\":" << kExpectedGameStart
<< ",\"moveIndex\":0,\"canonicalPublicHash\":\""
<< hex64(publicHash(state)) << "\",\"tapeSeed\":"
<< panelSeed(state) << "},\"modelInput\":{\"board\":\"";
for (const std::uint8_t cell : state.board) output << static_cast<int>(cell);
output << "\",\"nextDisc\":" << static_cast<int>(state.next_disc)
<< ",\"movesRemaining\":" << static_cast<int>(state.moves_remaining)
<< ",\"terminal\":false},"
"\"excludedFromModelInput\":[\"screenSeed\",\"moveIndex\","
"\"canonicalPublicHash\",\"tapeSeed\",\"score\",\"level\","
"\"history\",\"scenario\"],\"gate\":\"ultra\","
"\"fairD1Action\":3,\"selectedAction\":3,\"switched\":false,"
"\"actions\":[";
for (int action = 0; action < kBoardSize; ++action) {
if (action) output << ',';
if (!isLegal(state.board, action)) {
output << "null";
continue;
}
output << "{\"action\":" << action
<< ",\"meanScoreReturn\":" << 1000 + action
<< ",\"meanSurvivedMoves\":20,\"meanNumberedClears\":1,"
"\"meanCoversRevealed\":2,\"survivingCutoffs\":0,"
"\"pairedVsFairD1\":{\"score\":{\"lowerOneSided99\":0},"
"\"moves\":{\"lowerOneSided99\":0},\"materialDownsides\":0,"
"\"materialDownsideUpper99\":0}}";
}
output << "]}";
return output.str();
}
RootData syntheticTrainingRoot(int origin) {
RootData result;
result.panel.origin_slot = origin;
result.panel.origin_game = kExpectedGameStart + origin;
result.panel.state.next_disc = static_cast<std::uint8_t>(origin % 7 + 1);
result.panel.state.moves_remaining = static_cast<std::uint8_t>(origin % 5 + 1);
result.panel.stored_d1_action = 3;
result.d1_search.action = 3;
result.d1_search.values.fill(0.0);
for (int action = 0; action < kBoardSize; ++action) {
result.panel.actions[action].legal = true;
result.d1_search.values[action] = -std::abs(action - 3);
}
ActorInput input{result.panel.state, result.d1_search.values};
for (int action = 0; action < kBoardSize; ++action) {
result.features[action] = actorFeatures(input, action);
for (int half = 0; half < 2; ++half) {
for (int sample = 0; sample < 4; ++sample) {
result.samples.score[half][sample][action] =
1000.0 + 25.0 * (action == origin % 7) -
std::abs(action - origin % 7) + half * 0.01;
}
}
}
return result;
}
void refreshSyntheticRootFeatures(RootData& root) {
ActorInput input{root.panel.state, root.d1_search.values};
for (int action = 0; action < kBoardSize; ++action) {
if (root.panel.actions[action].legal) {
root.features[action] = actorFeatures(input, action);
}
}
}
bool selfTest(std::ostream& output) {
expect(sha256("") ==
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"empty SHA-256 vector failed");
expect(sha256("abc") ==
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
"abc SHA-256 vector failed");
std::set<int> all_scenarios;
for (int half = 0; half < 2; ++half) {
const auto scenarios = scenarioHalf(half);
expect(std::is_sorted(scenarios.begin(), scenarios.end()),
"scenario half is not ordered");
expect(std::set<int>(scenarios.begin(), scenarios.end()).size() ==
kMaximumSampleSize,
"scenario half contains duplicates");
for (const int scenario : scenarios) {
expect(scenario >= 0 && scenario < kStoredScenarioCount,
"scenario out of range");
expect(all_scenarios.insert(scenario).second,
"independent scenario halves overlap");
}
}
constexpr std::array<int, 4> maximum_base_gap{{9, 3, 3, 1}};
constexpr std::array<int, 4> maximum_scenario_gap{{37, 13, 13, 5}};
constexpr std::array<int, 4> maximum_boundary_gap{{20, 7, 7, 4}};
std::array<std::set<int>, 4> position_sets;
for (int sample_index = 0; sample_index < 4; ++sample_index) {
const int sample_size = kSampleSizes[sample_index];
const std::vector<int> positions = selectedBasePositions(sample_index);
expect(static_cast<int>(positions.size()) == sample_size &&
std::is_sorted(positions.begin(), positions.end()),
"nested sample size/order changed");
position_sets[sample_index] =
std::set<int>(positions.begin(), positions.end());
expect(static_cast<int>(position_sets[sample_index].size()) == sample_size,
"nested sample contains duplicates");
std::array<int, 7> coarse_counts{};
int observed_base_gap = 0;
for (std::size_t index = 0; index < positions.size(); ++index) {
expect(positions[index] >= 0 && positions[index] < kMaximumSampleSize,
"nested sample position out of range");
++coarse_counts[positions[index] / 9];
if (index) {
observed_base_gap =
std::max(observed_base_gap, positions[index] - positions[index - 1]);
}
}
for (const int count : coarse_counts) {
expect(count == sample_size / 7,
"nested sample coarse-stratum balance changed");
}
expect(observed_base_gap <= maximum_base_gap[sample_index],
"nested sample base max-gap changed");
for (int half = 0; half < 2; ++half) {
const std::vector<int> scenarios = selectedScenarios(half, sample_index);
expect(std::is_sorted(scenarios.begin(), scenarios.end()) &&
std::set<int>(scenarios.begin(), scenarios.end()).size() ==
scenarios.size(),
"selected scenario order/uniqueness changed");
int observed_scenario_gap = 0;
for (std::size_t index = 1; index < scenarios.size(); ++index) {
observed_scenario_gap = std::max(
observed_scenario_gap, scenarios[index] - scenarios[index - 1]);
}
expect(observed_scenario_gap <= maximum_scenario_gap[sample_index],
"selected scenario max-gap changed");
expect(scenarios.front() <= maximum_boundary_gap[sample_index] &&
kStoredScenarioCount - 1 - scenarios.back() <=
maximum_boundary_gap[sample_index],
"selected scenario boundary balance changed");
}
}
for (int smaller = 0; smaller < 3; ++smaller) {
expect(std::includes(position_sets[smaller + 1].begin(),
position_sets[smaller + 1].end(),
position_sets[smaller].begin(),
position_sets[smaller].end()),
"K sample sets are not truly nested");
}
PublicState empty;
empty.next_disc = 1;
empty.moves_remaining = 5;
const PanelRecord parsed = parsePanel(fixturePanelJson(empty));
expect(parsed.state == empty && parsed.tape_seed == panelSeed(empty) &&
parsed.stored_public_hash == publicHash(empty),
"strict panel parser fixture failed");
std::string altered = fixturePanelJson(empty);
const std::size_t gate = altered.find("\"gate\":\"ultra\"");
altered.replace(gate, std::string("\"gate\":\"ultra\"").size(),
"\"gate\":\"other\"");
bool rejected = false;
try {
(void)parsePanel(altered);
} catch (const std::exception&) {
rejected = true;
}
expect(rejected, "metadata mutation was not rejected");
rejected = false;
try {
(void)parseLockedCorpus(fixturePanelJson(empty));
} catch (const std::exception&) {
rejected = true;
}
expect(rejected, "checksum mutation was not rejected");
const std::filesystem::path io_base =
std::filesystem::temp_directory_path() /
"drop7-b0-nonexistent-io-selftest";
RunOptions same_io;
same_io.input = (io_base / "corpus.jsonl").string();
same_io.output = (io_base / "child" / ".." / "corpus.jsonl").string();
rejected = false;
try {
validateDistinctInputOutput(same_io);
} catch (const std::exception&) {
rejected = true;
}
expect(rejected, "weakly-canonical identical input/output was accepted");
same_io.output = (io_base / "artifact.json").string();
validateDistinctInputOutput(same_io);
PublicState state;
state.board[indexOf(6, 0)] = 2;
state.board[indexOf(6, 1)] = kCracked;
state.board[indexOf(6, 4)] = 5;
state.next_disc = 4;
state.moves_remaining = 3;
std::array<double, kBoardSize> q{};
for (int action = 0; action < kBoardSize; ++action) q[action] = action * 1.25;
ActorInput input{state, q};
PublicState reflected = mirror(state);
std::array<double, kBoardSize> reflected_q{};
for (int action = 0; action < kBoardSize; ++action) {
reflected_q[kBoardSize - 1 - action] = q[action];
}
ActorInput reflected_input{reflected, reflected_q};
for (int action = 0; action < kBoardSize; ++action) {
expect(actorFeatures(input, action) ==
actorFeatures(reflected_input, kBoardSize - 1 - action),
"actor features are not reflection exact");
}
PublicState symmetric_empty;
symmetric_empty.next_disc = 3;
symmetric_empty.moves_remaining = 2;
std::array<double, kBoardSize> asymmetric_q{{
-4.0, -2.0, -1.0, 0.25, 1.5, 3.0, 8.0,
}};
std::array<double, kBoardSize> asymmetric_q_reflected{};
for (int action = 0; action < kBoardSize; ++action) {
asymmetric_q_reflected[kBoardSize - 1 - action] = asymmetric_q[action];
}
const ActorInput empty_side_left{symmetric_empty, asymmetric_q};
const ActorInput empty_side_right{symmetric_empty, asymmetric_q_reflected};
expect(actorFeatures(empty_side_left, 0) ==
actorFeatures(empty_side_right, kBoardSize - 1),
"empty symmetric side-action joint canonicalization failed");
const CanonicalActorInput empty_left_canonical =
canonicalizeStateAction(empty_side_left, 0);
const CanonicalActorInput empty_right_canonical =
canonicalizeStateAction(empty_side_right, kBoardSize - 1);
expect(empty_left_canonical.state == empty_right_canonical.state &&
empty_left_canonical.action == empty_right_canonical.action &&
empty_left_canonical.d1_q == empty_right_canonical.d1_q,
"empty symmetric D1-Q remapping failed");
std::array<double, kBoardSize> symmetric_q{{
-3.0, -2.0, -1.0, 0.0, -1.0, -2.0, -3.0,
}};
const ActorInput empty_center{symmetric_empty, symmetric_q};
const CanonicalActorInput empty_center_canonical =
canonicalizeStateAction(empty_center, 3);
expect(empty_center_canonical.state == symmetric_empty &&
empty_center_canonical.action == 3 &&
empty_center_canonical.d1_q == symmetric_q &&
actorFeatures(empty_center, 3) ==
actorFeatures(ActorInput{mirror(symmetric_empty), symmetric_q},
3),
"empty symmetric center-action canonicalization failed");
PublicState symmetric_nonempty = symmetric_empty;
symmetric_nonempty.board[indexOf(6, 0)] = 2;
symmetric_nonempty.board[indexOf(6, 6)] = 2;
symmetric_nonempty.board[indexOf(6, 3)] = kCracked;
symmetric_nonempty.board[indexOf(5, 3)] = 4;
const ActorInput nonempty_side_left{symmetric_nonempty, asymmetric_q};
const ActorInput nonempty_side_right{
symmetric_nonempty, asymmetric_q_reflected};
expect(actorFeatures(nonempty_side_left, 1) ==
actorFeatures(nonempty_side_right, kBoardSize - 1 - 1),
"nonempty symmetric side-action joint canonicalization failed");
const ActorInput nonempty_center{symmetric_nonempty, symmetric_q};
expect(actorFeatures(nonempty_center, 3) ==
actorFeatures(ActorInput{mirror(symmetric_nonempty), symmetric_q},
3),
"nonempty symmetric center-action canonicalization failed");
PanelRecord metadata_a;
metadata_a.origin_game = 1;
metadata_a.move_index = 2;
metadata_a.tape_seed = 3;
PanelRecord metadata_b = metadata_a;
metadata_b.origin_game = 0xffff'ffffu;
metadata_b.move_index = 999999;
metadata_b.tape_seed = 0xdead'beefu;
expect(actorFeatures(input, 3) == actorFeatures(input, 3) &&
metadata_a.origin_game != metadata_b.origin_game,
"metadata-blind actor boundary failed");
const FairD1Decision first_d1 = chooseFairD1(state);
const FairD1Decision mirror_d1 = chooseFairD1(reflected);
expect(first_d1.action == kBoardSize - 1 - mirror_d1.action,
"public D1 reflection action failed");
for (int action = 0; action < kBoardSize; ++action) {
expect(std::abs(first_d1.values[action] -
mirror_d1.values[kBoardSize - 1 - action]) < 1.0e-8,
"public D1 reflection values failed");
}
SyntheticWork work_a, work_b;
const int scenario = scenarioAt(0, 7);
const std::uint32_t tape = panelSeed(state);
const ScenarioOutcome outcome_a =
rolloutScenario(state, 2, tape, scenario, work_a, nullptr, 3);
const ScenarioOutcome outcome_b = rolloutScenario(
reflected, kBoardSize - 1 - 2, tape, scenario, work_b, nullptr, 3);
expect(outcome_a == outcome_b && work_a.transitions == work_b.transitions,
"synthetic tape reflection failed");
std::vector<RootData> training;
for (int origin = 0; origin < kExpectedGames; ++origin) {
training.push_back(syntheticTrainingRoot(origin));
}
// Make origin 3 asymmetric, then add a mirrored copy under another origin.
// Exact canonical state grouping must purge that copy in addition to every
// root from origin 3. A second, distinct origin-3 root proves whole-origin
// exclusion remains in force independently of the duplicate-state purge.
training[3].panel.state.board[indexOf(6, 0)] = 2;
refreshSyntheticRootFeatures(training[3]);
RootData mirrored_duplicate = training[3];
mirrored_duplicate.panel.origin_slot = 4;
mirrored_duplicate.panel.origin_game = kExpectedGameStart + 4;
mirrored_duplicate.panel.state = mirror(training[3].panel.state);
for (int action = 0; action < kBoardSize; ++action) {
mirrored_duplicate.d1_search.values[kBoardSize - 1 - action] =
training[3].d1_search.values[action];
}
refreshSyntheticRootFeatures(mirrored_duplicate);
RootData second_heldout = syntheticTrainingRoot(3);
second_heldout.panel.state.board[indexOf(6, 2)] = 5;
refreshSyntheticRootFeatures(second_heldout);
training.push_back(mirrored_duplicate);
training.push_back(second_heldout);
const FoldSelection selection = buildFoldSelection(training, 3);
expect(selection.heldout_origin_roots == 2 &&
selection.purged_canonical_state_roots == 1 &&
selection.training_roots == 7,
"whole-origin/exact-state purge accounting failed");
std::vector<PublicState> synthetic_heldout_states;
for (const RootData& root : training) {
if (root.panel.origin_slot == 3) {
synthetic_heldout_states.push_back(
exactCanonicalPublicState(root.panel.state));
}
}
for (std::size_t index = 0; index < training.size(); ++index) {
if (!selection.eligible[index]) continue;
expect(training[index].panel.origin_slot != 3 &&
std::find(synthetic_heldout_states.begin(),
synthetic_heldout_states.end(),
exactCanonicalPublicState(
training[index].panel.state)) ==
synthetic_heldout_states.end(),
"heldout origin or exact heldout state leaked into training");
}
const ActorModel model_first =
trainActor(training, selection, 0, 3, kActorSeedA);
const ActorModel model_second =
trainActor(training, selection, 0, 3, kActorSeedA);
expect(actorFingerprint(model_first) == actorFingerprint(model_second),
"deterministic purged whole-origin actor training failed");
std::array<StoredAction, kBoardSize> tie_actions{};
std::array<double, kBoardSize> tie_prediction{};
std::array<double, kBoardSize> tie_teacher{};
tie_prediction.fill(-std::numeric_limits<double>::infinity());
tie_teacher.fill(-std::numeric_limits<double>::infinity());
for (int action = 0; action < 3; ++action) tie_actions[action].legal = true;
tie_prediction[0] = 2.0;
tie_prediction[1] = 1.0;
tie_prediction[2] = 1.0;
tie_teacher[0] = 1.0;
tie_teacher[1] = 1.0;
tie_teacher[2] = 0.0;
RankingAccumulator tie_ranking;
addRanking(tie_ranking, tie_prediction, tie_teacher, tie_actions);
expect(tie_ranking.pairs == 3 &&
std::abs(tie_ranking.pairwise_credit - 2.0) < kTieTolerance,
"pairwise target/prediction tie accounting changed");
SampleEvaluation passing;
passing.independent_half_top_action_stability = kStabilityMinimum;
passing.override_precision = kOverridePrecisionMinimum;
passing.override_recall = kOverrideRecallMinimum;
passing.actor.pairwise = 0.82;
passing.d4.pairwise = 0.80;
passing.actor.normalized_regret = 0.09;
passing.d4.normalized_regret = 0.10;
passing.nonregressing_folds = 6;
for (HalfMetrics& half : passing.halves) {
half.pairwise_regret_nonregression = true;
half.hybrid_score_nonregression = true;
}
applyFrozenGates(passing);
expect(passing.passed, "exact frozen gate boundary should pass");
{
SampleEvaluation below = passing;
below.independent_half_top_action_stability =
std::nextafter(kStabilityMinimum, 0.0);
applyFrozenGates(below);
expect(!below.stability_gate && !below.passed,
"sub-threshold stability should fail");
}
{
SampleEvaluation below = passing;
below.override_precision =
std::nextafter(kOverridePrecisionMinimum, 0.0);
applyFrozenGates(below);
expect(!below.precision_gate && !below.passed,
"sub-threshold precision should fail");
}
{
SampleEvaluation below = passing;
below.override_recall = std::nextafter(kOverrideRecallMinimum, 0.0);
applyFrozenGates(below);
expect(!below.recall_gate && !below.passed,
"sub-threshold recall should fail");
}
{
SampleEvaluation below = passing;
below.actor.pairwise = below.d4.pairwise + kPairwiseGainMinimum -
2.0 * kTieTolerance;
applyFrozenGates(below);
expect(!below.pairwise_gate && !below.passed,
"sub-threshold pairwise gain should fail");
}
{
SampleEvaluation below = passing;
below.actor.normalized_regret =
kRegretRatioMaximum * below.d4.normalized_regret +
2.0 * kTieTolerance;
applyFrozenGates(below);
expect(!below.regret_gate && !below.passed,
"above-threshold regret ratio should fail");
}
{
SampleEvaluation below = passing;
below.nonregressing_folds = kRequiredNonregressingFolds - 1;
applyFrozenGates(below);
expect(!below.fold_gate && !below.passed,
"sub-threshold whole-origin fold count should fail");
}
{
SampleEvaluation below = passing;
below.halves[1].pairwise_regret_nonregression = false;
applyFrozenGates(below);
expect(!below.halves_ranking_gate && !below.passed,
"one failing ranking half should fail");
}
{
SampleEvaluation below = passing;
below.halves[0].hybrid_score_nonregression = false;
applyFrozenGates(below);
expect(!below.halves_hybrid_score_gate && !below.passed,
"one failing hybrid-score half should fail");
}
expect(sizeof(ActorModel) <= 8ull * 1024ull &&
kMaximumSyntheticTransitions == 84'142'800ull,
"static resource proof changed");
output << "FULL_PANEL_CPI_PREFLIGHT_SELF_TEST {"
<< "\"passed\":true,\"sha256\":true,\"strictParser\":true,"
"\"checksumLock\":true,\"balancedK\":true,"
"\"disjointHalves\":true,\"publicMetadataBlind\":true,"
"\"jointStateActionReflectionExact\":true,"
"\"symmetricStateActions\":true,\"syntheticTapeReflection\":true,"
"\"wholeOriginSplit\":true,\"exactStateGroupPurge\":true,"
"\"pairwiseTieAccounting\":true,\"distinctInputOutput\":true,"
"\"deterministicActor\":true,\"everyGateBoundary\":true,"
"\"gameplaySeedsOpened\":0,"
"\"originTransitions\":0,\"actorBytesPerMember\":"
<< sizeof(ActorModel) << ",\"maximumSyntheticTransitions\":"
<< kMaximumSyntheticTransitions << ",\"peakRssBytes\":"
<< peakRssBytes() << "}\n";
return true;
}
int run(const RunOptions& options, std::ostream& summary) {
validateDistinctInputOutput(options);
const Deadline deadline;
const std::vector<PanelRecord> panels = loadLockedCorpus(options);
const EvaluatedCorpus corpus = evaluateCorpus(panels, options.threads, deadline);
std::array<SampleEvaluation, 4> evaluations{};
for (int sample = 0; sample < 4; ++sample) {
evaluations[sample] = evaluateSample(corpus.roots, sample);
deadline.check();
}
writeArtifact(options, evaluations, corpus, deadline.seconds());
const SampleEvaluation& b0 = evaluations.back();
summary << std::fixed << std::setprecision(6)
<< "FULL_PANEL_CPI_PREFLIGHT_RESULT {\"K\":63,"
<< "\"stability\":" << b0.independent_half_top_action_stability
<< ",\"overridePrecision\":" << b0.override_precision
<< ",\"overrideRecall\":" << b0.override_recall
<< ",\"actorPairwise\":" << b0.actor.pairwise
<< ",\"d4Pairwise\":" << b0.d4.pairwise
<< ",\"actorRegret\":" << b0.actor.normalized_regret
<< ",\"d4Regret\":" << b0.d4.normalized_regret
<< ",\"nonregressingFolds\":" << b0.nonregressing_folds
<< ",\"bothHalvesRanking\":"
<< (b0.halves_ranking_gate ? "true" : "false")
<< ",\"bothHalvesHybridScore\":"
<< (b0.halves_hybrid_score_gate ? "true" : "false")
<< ",\"passed\":" << (b0.passed ? "true" : "false")
<< ",\"newGameplaySeeds\":0,\"originTransitions\":0,"
<< "\"artifact\":\"" << jsonEscape(options.output) << "\"}\n";
return b0.passed ? 0 : 2;
}
} // namespace drop7::full_panel_cpi_preflight
#ifndef DROP7_FULL_PANEL_CPI_PREFLIGHT_LIBRARY
int main(int argc, char** argv) {
try {
if (argc >= 2 && std::string_view(argv[1]) == "--self-test") {
return drop7::full_panel_cpi_preflight::selfTest(std::cout)
? EXIT_SUCCESS
: EXIT_FAILURE;
}
if (argc >= 2 && std::string_view(argv[1]) == "--run") {
const auto options =
drop7::full_panel_cpi_preflight::parseOptions(argc, argv, 2);
return drop7::full_panel_cpi_preflight::run(options, std::cout);
}
std::cerr << "usage: drop7_full_panel_cpi_preflight --self-test | "
"--run [--input PATH] [--input-sha256 LOCKED_SHA256] "
"[--output PATH] [--threads 1..4]\n";
return 2;
} catch (const std::exception& error) {
std::cerr << "drop7_full_panel_cpi_preflight: " << error.what() << '\n';
return 1;
}
}
#endif