feat(seats): accounts without a 5-hour limit

Anthropic is removing the 5-hour limit in stages (from 2026-10-31), and
an account without it reports the weekly window alone. Until now the pool
took such an account for an unprobed seat: always eligible, ranked after
every other, never held to the weekly cutoff, with no cap on its passes.

- The burst window is the 5-hour one, else the weekly one
  (Seats::BurstWindow). An account whose burst window is the weekly one is
  ranked by it and admitted under the 95 % cutoff with the passes in
  flight projected on it, at the measured share per pass (0.04 at xhigh,
  0.125 otherwise; REVIEW_GATES_LENS_COST_7D_PCT), and waits for the weekly
  reset when over it.
- Every OAuth account and the local login takes at most 128 passes at once,
  every driver's counted (REVIEW_GATES_OAUTH_CONCURRENCY): every run
  measured with 149 or more in flight on one account drew usage-limit
  rejections, none of the 119 with 139 or fewer.
- A 'concurrents' rejection pauses the seat for 20 s or its retry-after,
  not until a window's reset (a seat sat two hours at 10 % on one).
- Board entries, the folded foreign record and the board's view carry
  cost7d, so the drivers see each other's weekly load.
- `seats` and the log table say `no limit` in such an account's 5-hour
  column; the board's others-line names its weekly projection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-10-31 17:07:17 +01:00
commit c28307601b
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
11 changed files with 209 additions and 26 deletions

View file

@ -649,7 +649,7 @@ namespace Crafter::Review::Run {
} catch (const std::runtime_error& e) {
Die(e.what());
}
const Json pc = SeatPool::PoolConfig(processEnv);
const Json pc = SeatPool::PoolConfig(processEnv, a.effort);
board = std::make_unique<SeatPool::Board>(SeatPool::BoardPath(), std::string(), std::nullopt, log);
board->Join({{"run", std::format("commits {} @ {}", Basename(Dyn::RStrip(a.artifact, "/")), h8)},
{"dump", Basename(dumpPath)},
@ -673,7 +673,7 @@ namespace Crafter::Review::Run {
const double now = Platform::Now();
board->Publish(seats, now, !a.noProbe);
board->Fold(seats, now);
for (const std::string& line : board->OthersLines(seats, now, SeatPool::PoolConfig(processEnv), apiCfg, a.concurrency)) log(line);
for (const std::string& line : board->OthersLines(seats, now, SeatPool::PoolConfig(processEnv, a.effort), apiCfg, a.concurrency)) log(line);
}
if (a.harness == "opencode") {
runner->opencodeHome = OpenCode::PrepareHome(scratch, repo, modelIds);
@ -1467,6 +1467,7 @@ namespace Crafter::Review::Run {
.cacheKey = warm ? std::function<std::optional<std::string>(Json&)>([this](Json& job) { return CacheKey(job); }) : nullptr,
.warmProbe = warm ? std::function<bool(const Json&)>([this](const Json& job) { return WarmProbe(job); }) : nullptr,
.seats = &seats,
.seatConfig = SeatPool::PoolConfig(Platform::Environment(), a.effort),
.apiConfig = apiCfg,
.ledger = ledger.get(),
.admission = admission.get(),

View file

@ -69,7 +69,7 @@ namespace Crafter::Review::SeatPool {
}
Json ZeroForeign() {
return {{"count", 0}, {"cost5h", 0.0}, {"costUsd", 0.0}};
return {{"count", 0}, {"cost5h", 0.0}, {"cost7d", 0.0}, {"costUsd", 0.0}};
}
std::string Kind(const Json& seat) {
@ -510,16 +510,50 @@ namespace Crafter::Review::SeatPool {
}
// ---- placement -------------------------------------------------------------------------
Json PoolConfig(const std::map<std::string, std::string>& env) {
namespace {
// A finite number >= 0 in Dyn::ParseFloat's syntax, else the default.
double EnvNumber(const std::map<std::string, std::string>& env, const std::string& name, double fallback) {
const std::string text = EnvOf(env, name);
const std::optional<double> n = Dyn::ParseFloat(text);
return n && !Dyn::Strip(text).empty() && std::isfinite(*n) && *n >= 0 ? *n : fallback;
}
// A pass's share of the weekly window, as measured: 0.04 at xhigh,
// 0.125 at max and for any other effort.
double Cost7d(const Json& config) {
return Dyn::Has(config, "lensCost7dPct") ? AsDouble(config.at("lensCost7dPct")) : 0.125;
}
// The weekly window with the passes in flight and this one projected
// on it stays under the cutoff: the room of an account whose burst
// window is the weekly one.
bool WeeklyRoom(const Json& s, const Json& config) {
const double ahead = static_cast<double>(Running(s) + 1) * Cost7d(config) + Num(Dyn::Get(Foreign(s), "cost7d"));
const Json& windows = Dyn::At(s, "windows");
for (auto it = windows.begin(); it != windows.end(); ++it) {
if (it.key() == "five_hour" || Seats::IsFableWindow(it.key())) continue;
if (Num(Dyn::Get(it.value(), "utilization")) + ahead >= Seats::LongWindowCutoff) return false;
}
return true;
}
}
Json PoolConfig(const std::map<std::string, std::string>& env, std::string_view effort) {
Json config = Seats::ConfigFromEnv(env);
if (Dyn::Strip(EnvOf(env, "REVIEW_GATES_LENS_COST_PCT")).empty()) config["lensCostPct"] = 0.25;
config["lensCost7dPct"] = EnvNumber(env, "REVIEW_GATES_LENS_COST_7D_PCT", effort == "xhigh" ? 0.04 : 0.125);
config["oauthConcurrency"] = static_cast<std::int64_t>(EnvNumber(env, "REVIEW_GATES_OAUTH_CONCURRENCY", static_cast<double>(OauthConcurrency)));
return config;
}
double OauthProjected(const Json& s, const Json& config) {
// Where the seat's 5-hour window will be with its running processes -
// Where the seat's burst window will be with its running processes -
// this driver's at its projection, the other drivers' at theirs (the
// board). Unknown = at the ceiling, ranked last.
// board): the 5-hour window, or the weekly one on an account without
// a 5-hour limit. Unknown = at the ceiling, ranked last.
if (Seats::BurstWindow(Dyn::At(s, "windows")) == "seven_day") {
return AsDouble(s.at("windows").at("seven_day").at("utilization")) + static_cast<double>(Running(s)) * Cost7d(config) + Num(Dyn::Get(Foreign(s), "cost7d"));
}
const Json& five = Dyn::Get(FiveHour(s), "utilization");
const double base = five.is_null() ? AsDouble(config.at("maxUtil")) : AsDouble(five);
return base + static_cast<double>(Running(s)) * AsDouble(config.at("lensCostPct")) + AsDouble(Foreign(s).at("cost5h"));
@ -552,9 +586,17 @@ namespace Crafter::Review::SeatPool {
// Its pause is over (checked above): back in placement, its windows
// decide.
if (s.at("state") == "limited") s["state"] = "ok";
// No 5-hour reading (no probe, or it failed): usable, ranked at the
// ceiling - after every known seat.
if (Dyn::Get(FiveHour(s), "utilization").is_null()) return true;
// So many passes per account at once, every driver's counted,
// whatever its windows (2026-10-31).
const std::int64_t cap = Dyn::Has(config, "oauthConcurrency") ? Int(AsDouble(config.at("oauthConcurrency"))) : OauthConcurrency;
if (Running(s) + Int(AsDouble(Foreign(s).at("count"))) >= cap) return false;
const std::optional<std::string> burst = Seats::BurstWindow(s.at("windows"));
// No reading (no probe, or it failed): usable, ranked at the ceiling -
// after every known seat.
if (!burst) return true;
// No 5-hour limit on the account: the weekly cutoff alone, with the
// passes projected on it.
if (*burst == "seven_day") return WeeklyRoom(s, config);
return OauthProjected(s, config) + AsDouble(config.at("lensCostPct")) <= AsDouble(config.at("maxUtil")) && LongOk(s);
}
@ -628,11 +670,14 @@ namespace Crafter::Review::SeatPool {
std::vector<double> times;
for (const Json& s : seats) {
if (s.at("state") == "out" || s.at("state") == "invalid") continue;
const Json& five = FiveHour(s);
if (AsDouble(s.at("pauseUntil")) > now) {
times.push_back(AsDouble(s.at("pauseUntil")));
} else if (Kind(s) != "api" && Dyn::Truthy(Dyn::Get(five, "resetsAt")) && AsDouble(five.at("resetsAt")) + 30 > now) {
times.push_back(AsDouble(five.at("resetsAt")) + 30);
} else if (Kind(s) != "api") {
// The reset of the seat's burst window: the 5-hour one, the
// weekly one on an account without it.
const std::optional<std::string> burst = Seats::BurstWindow(s.at("windows"));
const Json& window = burst ? Dyn::Get(s.at("windows"), *burst) : Dyn::EmptyDict();
if (Dyn::Truthy(Dyn::Get(window, "resetsAt")) && AsDouble(window.at("resetsAt")) + 30 > now) times.push_back(AsDouble(window.at("resetsAt")) + 30);
}
if (recheck && AsDouble(Foreign(s).at("count")) > 0) times.push_back(now + *recheck);
}
@ -730,6 +775,16 @@ namespace Crafter::Review::SeatPool {
return true;
}
const std::string rateType = Dyn::StrOr(Dyn::Get(record, "rateType"), "");
if (rateType == "concurrents") {
// Not a window: the account had too many requests in flight
// at once (a burst of passes released onto one seat when its
// prompt prefix became cached). Seconds, not the window's
// reset.
s["pauseUntil"] = std::max(AsDouble(s.at("pauseUntil")), now + RetryAfter(reason, ConcurrentBackoffS));
s["state"] = "limited";
log(std::format("seat {}: too many requests at once ({}) - paused {} s, the process is placed again", Id(s), Dyn::Slice(reason, 0, 40), Int(AsDouble(s.at("pauseUntil")) - now)));
return true;
}
const Json& binding = s.at("binding");
if (rateType.starts_with("seven_day") || (Dyn::StrOr(binding, "").starts_with("seven_day") && Num(Dyn::Get(s, "util")) >= 100)) {
s["state"] = "out";
@ -1112,17 +1167,20 @@ namespace Crafter::Review::SeatPool {
const Json& inflight = Dyn::Or(Dyn::Get(b, "inflight"), Dyn::EmptyDict());
std::int64_t count = 0;
double cost5h = 0.0;
double cost7d = 0.0;
double costUsd = 0.0;
for (auto it = inflight.begin(); it != inflight.end(); ++it) {
const std::string owner = Owner(it.key());
if (owner == me) continue;
++count;
cost5h += Num(Dyn::Get(it.value(), "cost5h"));
cost7d += Num(Dyn::Get(it.value(), "cost7d"));
costUsd += Num(Dyn::Get(it.value(), "costUsd"));
f["drivers"][owner] = Dyn::Has(f["drivers"], owner) ? f["drivers"][owner].get<std::int64_t>() + 1 : 1;
}
f["count"] = count;
f["cost5h"] = cost5h;
f["cost7d"] = cost7d;
f["costUsd"] = costUsd;
if (!IsPaid(s) && !MergeWindows(s["windows"], Dyn::Get(b, "windows"), now).empty()) Reutil(s);
const double pause = Num(Dyn::Get(b, "pauseUntil"));
@ -1140,6 +1198,7 @@ namespace Crafter::Review::SeatPool {
}
}
f["cost5h"] = Dyn::Round(AsDouble(f.at("cost5h")), 4);
f["cost7d"] = Dyn::Round(AsDouble(f.at("cost7d")), 4);
f["costUsd"] = Dyn::Round(AsDouble(f.at("costUsd")), 4);
s["foreign"] = std::move(f);
}
@ -1309,6 +1368,7 @@ namespace Crafter::Review::SeatPool {
{"since", now},
{"deadline", now + 60 * (Dyn::Truthy(timeout) ? AsDouble(timeout) : 20.0) * 1.5 + InflightGraceS},
{"cost5h", paid ? Json(0) : config.at("lensCostPct")},
{"cost7d", paid ? Json(0) : Json(Cost7d(config))},
{"costUsd", paid ? LensCostValue(seat, apiConfig) : Json(0)},
};
if (!Dyn::Get(job, "_admitted").is_null()) entry["mb"] = Dyn::Round(AsDouble(job.at("_admitted")), 1);
@ -1362,6 +1422,7 @@ namespace Crafter::Review::SeatPool {
Json by = Json::object();
std::int64_t count = 0;
double cost5h = 0.0;
double cost7d = 0.0;
double costUsd = 0.0;
Json oldest;
const Json& inflight = Dyn::Or(Dyn::Get(s, "inflight"), Dyn::EmptyDict());
@ -1370,6 +1431,7 @@ namespace Crafter::Review::SeatPool {
by[owner] = Dyn::Has(by, owner) ? by[owner].get<std::int64_t>() + 1 : 1;
++count;
cost5h += Num(Dyn::Get(e.value(), "cost5h"));
cost7d += Num(Dyn::Get(e.value(), "cost7d"));
costUsd += Num(Dyn::Get(e.value(), "costUsd"));
const double since = Num(Dyn::Get(e.value(), "since"));
if (oldest.is_null() || since < oldest.get<double>()) oldest = since;
@ -1386,6 +1448,7 @@ namespace Crafter::Review::SeatPool {
{"kind", Dyn::Get(s, "kind")},
{"inflight", count},
{"cost5h", Dyn::Round(cost5h, 4)},
{"cost7d", Dyn::Round(cost7d, 4)},
{"costUsd", Dyn::Round(costUsd, 4)},
{"by", by},
{"oldest", oldest},
@ -1436,6 +1499,8 @@ namespace Crafter::Review::SeatPool {
const std::int64_t c = Concurrency(s, apiConfig);
lines.push_back(std::format(" seat {}: {} in flight ({}) - {} of {} slots free, ${:.2f} reserved", Id(s), count, Dyn::Join(who, ", "), std::max<std::int64_t>(0, c - count - Running(s)), c,
AsDouble(f.at("costUsd"))));
} else if (Seats::BurstWindow(s.at("windows")) == "seven_day") {
lines.push_back(std::format(" seat {}: {} passes in flight ({}) - projected 7d {:.1f} %, no 5-hour limit", Id(s), count, Dyn::Join(who, ", "), OauthProjected(s, config)));
} else {
lines.push_back(std::format(" seat {}: {} passes in flight ({}) - projected 5h {:.1f} %", Id(s), count, Dyn::Join(who, ", "), OauthProjected(s, config)));
}
@ -1475,10 +1540,7 @@ namespace Crafter::Review::SeatPool {
std::vector<std::vector<std::string>> rows = {{"seat", "kind", "state", "5h", "7d", "fable", "running", "foreign", "done", "spent", "note"}};
for (const Json& s : seats) {
const Json& windows = s.at("windows");
auto w = [&](std::string_view k) {
const Json& u = Dyn::Get(Dyn::Or(Dyn::Get(windows, k), Dyn::EmptyDict()), "utilization");
return u.is_null() ? std::string("—") : std::format("{}%", Seats::Fmt(u));
};
auto w = [&](std::string_view k) { return Seats::WindowCell(windows, k); };
std::string fable = "—";
for (auto it = windows.begin(); it != windows.end(); ++it) {
if (Seats::IsFableWindow(it.key()) && !Dyn::Get(it.value(), "utilization").is_null()) {

View file

@ -827,6 +827,19 @@ namespace Crafter::Review::Seats {
return std::format("{:02d}:{:02d}", d.tm_hour, d.tm_min);
}
std::optional<std::string> BurstWindow(const Json& windows) {
for (const std::string_view window : {std::string_view("five_hour"), std::string_view("seven_day")}) {
if (!Dyn::Get(Dyn::Or(Dyn::Get(windows, window), Dyn::EmptyDict()), "utilization").is_null()) return std::string(window);
}
return std::nullopt;
}
std::string WindowCell(const Json& windows, std::string_view window) {
const Json& u = Dyn::Get(Dyn::Or(Dyn::Get(windows, window), Dyn::EmptyDict()), "utilization");
if (!u.is_null()) return std::format("{}%", Fmt(u));
return window == "five_hour" && BurstWindow(windows) == "seven_day" ? std::string("no limit") : std::string("—");
}
std::string FormatWhen(double epoch, double now, const Zone& zone) {
const auto diffMin = static_cast<std::int64_t>(JsRound((epoch - now) / 60));
std::string relative;
@ -876,10 +889,7 @@ namespace Crafter::Review::Seats {
if (anyInflight) header.emplace_back("in flight");
rows.push_back(header);
for (const Json& s : ordered) {
auto w = [&](std::string_view k) {
if (!Dyn::Has(Dyn::Or(Dyn::Get(s, "windows"), Dyn::EmptyDict()), k)) return std::string("—");
return std::format("{}%", Fmt(Dyn::At(Window(s, k), "utilization")));
};
auto w = [&](std::string_view k) { return WindowCell(Dyn::Or(Dyn::Get(s, "windows"), Dyn::EmptyDict()), k); };
auto when = [&](std::string_view k) {
const Json& at = Dyn::Get(Dyn::Or(Window(s, k), Dyn::EmptyDict()), "resetsAt");
return Dyn::Truthy(at) ? FormatWhen(AsDouble(at), now, zone) : std::string("—");