BT_EXPIRE: tester builds stop working 14 days after build (compile gate)

Distributed test zips go stale and stray.  BT_EXPIRE (CMake option,
DEFAULT ON so a zip can never accidentally ship without it) makes the
exe refuse to start BT_EXPIRE_DAYS (default 14) after its build day:
boot logs the remaining window, an expired build logs + shows a
"test build expired -- ask the operator for the current build" box and
exits.  btversion.h now stamps BT_BUILD_UNIX (UTC-midnight-rounded so
the only-on-change header churns once per day, not every build) +
BT_BUILD_DATE.  Dev is unaffected: every build re-stamps the day.

-DBT_EXPIRE=OFF builds a non-expiring exe; mkdist reads the cache and
marks such a zip "-noexpire" + prints a warning, and the tester README
expiry note is {EXPIRE}-marker-gated like the steam lines.  Second
compile-gate exception after BT_STEAM (convention updated in
glass-cockpit.md).  Quality gate, not DRM -- a clock rollback defeats it.

Verified live: default build logs "test build window: 14 day(s) left";
a -DBT_EXPIRE_DAYS=0 build logs TEST BUILD EXPIRED and parks on the
explanation box (window title checked) without starting the game;
restored to 14 and rebuilt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-22 13:39:19 -05:00
co-authored by Claude Opus 4.8
parent 753540de96
commit eb618fe9e6
6 changed files with 85 additions and 3 deletions
+34
View File
@@ -24,6 +24,7 @@
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <ctime> // BT_EXPIRE tripwire (time)
#include <string>
#include <vector>
@@ -542,6 +543,39 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
std::cout << "BattleTech " << BT_VERSION_FULL
<< " (win32 reconstruction of Tesla 4.10)" << std::endl << std::flush;
#ifdef BT_EXPIRE
// TESTER-BUILD EXPIRY TRIPWIRE (compile gate BT_EXPIRE, default ON --
// see CMakeLists). Distributed zips go stale and stray; refuse to run
// BT_EXPIRE_DAYS after the build day (btversion.h BT_BUILD_UNIX, UTC
// midnight). Dev builds re-stamp every build, so this never fires
// locally. Quality gate, not DRM.
{
const time_t expires = (time_t)BT_BUILD_UNIX
+ (time_t)BT_EXPIRE_DAYS * 86400;
const time_t now = time(0);
if (now >= expires)
{
std::cout << "[boot] TEST BUILD EXPIRED (built " << BT_BUILD_DATE
<< ", " << BT_EXPIRE_DAYS << "-day test window)"
<< std::endl << std::flush;
char expired_text[256];
sprintf(expired_text,
"This BattleTech test build (%s, built %s) has expired.\n\n"
"Test builds stop working %d days after they are made so\n"
"stale copies don't wander around.\n\n"
"Ask the operator for the current build.",
BT_VERSION_STRING, BT_BUILD_DATE, (int)BT_EXPIRE_DAYS);
MessageBoxA(NULL, expired_text,
"BattleTech -- test build expired", MB_OK | MB_ICONWARNING);
return 0;
}
int days_left = (int)((expires - now + 86399) / 86400);
std::cout << "[boot] test build window: " << days_left
<< " day(s) left (built " << BT_BUILD_DATE << ")"
<< std::endl << std::flush;
}
#endif
// CPU pin (timing stability). BT_AFFINITY overrides the mask; =0 disables --
// required for multi-instance runs (two instances pinned to core 0 starve
// each other, and the L4NET connect-retry loop busy-waits).