From ea4d362a101ce88e32cb74092db52b7ff49bce46 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Sat, 31 Oct 2026 21:13:55 +0100 Subject: [PATCH] feat(seats): a pass's share of the windows by the run's effort, the weekly cutoff at 99 % The 5-hour share of a running pass was a flat 0.25 points; it follows the run's effort now, as the weekly share already did: 0.5 at max and any other effort, 0.125 at xhigh - the pooled means of 5438 Opus 5.5 passes on 141 seat-runs (2026-10-12..15), rounded up. The weekly cutoff moves from 95 % to 99 %: the weekly window is the budget the lenses run out of, and with the running passes projected against the cutoff the last percent is spent a pass at a time, not in a burst. REVIEW_GATES_LENS_COST_PCT and REVIEW_GATES_LENS_COST_7D_PCT still override every effort. --- AGENTS.md | 5 +++-- implementations/Crafter.Review-SeatPool.cpp | 10 +++++----- interfaces/Crafter.Review-SeatPool.cppm | 19 +++++++++++++------ interfaces/Crafter.Review-Seats.cppm | 6 +++++- process/prepush.md | 2 +- tests/Drivers/main.cpp | 6 +++--- tests/SeatPool/main.cpp | 21 +++++++++++---------- tests/Seats/main.cpp | 6 +++--- 8 files changed, 44 insertions(+), 31 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3f1b5f0..55e3e69 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -108,7 +108,8 @@ Conventions: No file the drivers write holds these in practice, and a file that fails to parse is treated as a damaged one. - **HTTP.** `ClientHTTP1::Fetch` ignores `*_proxy` variables. The OpenRouter requests send `User-Agent: crafter-review`; `app_ready` sends `review-gates`. Reason phrases are the standard ones, not the server's. - **Seat placement** (SeatPool, Seats, Drivers): - - An account whose 5-hour limit Anthropic has removed reports the weekly window alone. Its burst window (`Seats::BurstWindow`) is the weekly one: it is ranked and admitted by the weekly window with the passes in flight projected on it (0.04 points per pass at xhigh, 0.125 otherwise), under the 95 % cutoff. + - An account whose 5-hour limit Anthropic has removed reports the weekly window alone. Its burst window (`Seats::BurstWindow`) is the weekly one: it is ranked and admitted by the weekly window with the passes in flight projected on it (0.04 points per pass at xhigh, 0.125 otherwise), under the 99 % cutoff. + - A pass's projected share of the windows follows the run's effort: 0.5 / 0.125 points of the 5-hour window and 0.125 / 0.04 of the weekly one at max / xhigh (`SeatPool::LensCostPct`, `LensCost7dPct`), the pooled means of 5438 passes on 141 seat-runs (2026-10-12..15) rounded up. The weekly cutoff is 99 %: the running passes are projected against it, so the last percent is spent a pass at a time. - Every OAuth account and the local login takes at most 128 passes at once, every driver's counted. - There is no machine-wide width (2026-10-31, Jorijn: "there is no need to do a global cap anymore, the cap should be 128 per available account"). `--concurrency` caps only when given, and the dump's `args.concurrency` is then null. The board's driver settings read `128 per account`, which every driver's `seats` shows as that driver's width (Scheduler, Runs). - A 'concurrents' rejection pauses the seat for 20 s or its retry-after, not until a window's reset. @@ -179,7 +180,7 @@ What the binary reads at run time, and how. A variable the driver only sets or s | `SEATS_ENV_FILE` | `:Run` Gate0 (run), `seats` | run: `/.env` if it exists; `seats`: `./.env` if it exists | `--env-file` wins (in run even `--env-file ""`, meaning no file); empty counts as unset. Only seat lines are taken (`[export ]NAME=value`, one pair of matching quotes stripped), overriding the process environment; no knob below is ever read from the file. A file that cannot be read, or is not UTF-8: run stops at preflight (exit 3), `seats` exits 1 with the read error. | The dotenv file the seat secrets come from | | `REVIEW_GATES_SEATS` | `:Driver` RunCommand → LoadSeats | `auto` | Only without `--seats`. Stripped, case-sensitive; unset or empty is `auto` (every api and oauth seat, else `local`); `local`, `api`, `oauth`, `openrouter` select that kind; anything else is a comma list of ids (`apiN`, `N`, `orN`, `local`; blank items skipped). An id not configured, or OpenRouter mixed with others, is a preflight error (exit 3). | The seats a run places lens processes on | | `REVIEW_GATES_SEAT_MAX_UTIL` | `:Seats` ConfigFromEnv (`seats`; run through `:SeatPool` PoolConfig) | `85` | A finite number >= 0, in decimal or exponent notation; surrounding whitespace, `_` between digits and Unicode digits are taken. Empty, garbage, negative, `inf`, `nan` keep the default; a whole value is stored as an int. Process environment only. | Ceiling (%) of an OAuth seat's projected 5-hour utilisation | -| `REVIEW_GATES_LENS_COST_PCT` | `:Seats` ConfigFromEnv; `:SeatPool` PoolConfig | run: `0.25`; `seats`: `10` | As MAX_UTIL. PoolConfig puts in 0.25 only when it is unset or blank, so a set but invalid value gives 10, in run too. | Percentage points of the 5-hour window a running process is projected to add (its cost on the board too) | +| `REVIEW_GATES_LENS_COST_PCT` | `:Seats` ConfigFromEnv; `:SeatPool` PoolConfig | run: `0.5` at max and any other effort, `0.125` at xhigh; `seats`: `10` | As MAX_UTIL. PoolConfig puts in the effort's figure only when it is unset or blank, so a set but invalid value gives 10, in run too. | Percentage points of the 5-hour window a running process is projected to add (its cost on the board too) | | `REVIEW_GATES_SEAT_POLICY` | `:Seats` ConfigFromEnv | `spread` | Exactly `pack` (case-sensitive, untrimmed) is pack; anything else spread. | pack: the first eligible OAuth seat by id; spread: the lowest projected one | | `REVIEW_GATES_SEAT_WAIT_MIN` | `:Seats` ConfigFromEnv | `15` | As MAX_UTIL | Shown by `seats --json` as `waitMaxMin`; nothing else reads it | | `REVIEW_GATES_SEAT_HANDOVER_PCT` | `:Seats` ConfigFromEnv | `90` | As MAX_UTIL | Shown in the `seats` report and `--json` only | diff --git a/implementations/Crafter.Review-SeatPool.cpp b/implementations/Crafter.Review-SeatPool.cpp index 8bc9803..b745222 100644 --- a/implementations/Crafter.Review-SeatPool.cpp +++ b/implementations/Crafter.Review-SeatPool.cpp @@ -518,10 +518,10 @@ namespace Crafter::Review::SeatPool { 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. + // A pass's share of the weekly window: the config's, else the max + // figure. double Cost7d(const Json& config) { - return Dyn::Has(config, "lensCost7dPct") ? AsDouble(config.at("lensCost7dPct")) : 0.125; + return Dyn::Has(config, "lensCost7dPct") ? AsDouble(config.at("lensCost7dPct")) : LensCost7dPct({}); } // The weekly window with the passes in flight and this one projected @@ -540,8 +540,8 @@ namespace Crafter::Review::SeatPool { Json PoolConfig(const std::map& 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); + if (Dyn::Strip(EnvOf(env, "REVIEW_GATES_LENS_COST_PCT")).empty()) config["lensCostPct"] = LensCostPct(effort); + config["lensCost7dPct"] = EnvNumber(env, "REVIEW_GATES_LENS_COST_7D_PCT", LensCost7dPct(effort)); config["oauthConcurrency"] = static_cast(EnvNumber(env, "REVIEW_GATES_OAUTH_CONCURRENCY", static_cast(OauthConcurrency))); return config; } diff --git a/interfaces/Crafter.Review-SeatPool.cppm b/interfaces/Crafter.Review-SeatPool.cppm index 7306efb..5e78ae2 100644 --- a/interfaces/Crafter.Review-SeatPool.cppm +++ b/interfaces/Crafter.Review-SeatPool.cppm @@ -43,6 +43,16 @@ export namespace Crafter::Review::SeatPool { // rejections, none of the 119 with 139 or fewer. // REVIEW_GATES_OAUTH_CONCURRENCY overrides. constexpr std::int64_t OauthConcurrency = 128; + // What one running pass is projected to cost of an OAuth seat's windows, + // in percentage points, by the run's reasoning effort (every lens of a run + // shares --effort): the pooled means of 5438 Opus 5.5 passes on 141 + // seat-runs (2026-10-12..15), rounded up - max 0.44 / 0.118, xhigh + // 0.12 / 0.033. The 85 % ceiling and the cutoff's last percent absorb the + // spread. An effort not in the table projects at the max figures; + // REVIEW_GATES_LENS_COST_PCT and REVIEW_GATES_LENS_COST_7D_PCT override + // every effort. + constexpr double LensCostPct(std::string_view effort) { return effort == "xhigh" ? 0.125 : 0.5; } + constexpr double LensCost7dPct(std::string_view effort) { return effort == "xhigh" ? 0.04 : 0.125; } // The kinds whose processes cost money the ledger counts. constexpr std::array Paid = {"api", "openrouter"}; // The kinds whose out/invalid verdict crosses drivers on the board. @@ -101,12 +111,9 @@ export namespace Crafter::Review::SeatPool { void ApplyProbe(Json& seat, const Json& result); std::string Describe(const Json& seat); - // The OAuth placement knobs, with the pool's own per-process projections: - // 0.25 of the 5-hour window (the 2026-10-15 load test moved a 20x seat's - // window 0.08 points a pass) and, for an account without a 5-hour limit, - // the measured share of the weekly window at the run's effort (0.04 at - // xhigh, 0.125 otherwise; REVIEW_GATES_LENS_COST_7D_PCT); and the - // per-account cap. + // The OAuth placement knobs, with the pool's own per-pass projections at + // the run's effort (LensCostPct, LensCost7dPct; the env overrides them) + // and the per-account cap. Json PoolConfig(const std::map& env, std::string_view effort = {}); double OauthProjected(const Json& seat, const Json& config); // A window whose reset has passed counts as empty until the next reading. diff --git a/interfaces/Crafter.Review-Seats.cppm b/interfaces/Crafter.Review-Seats.cppm index 43177f9..f88d654 100644 --- a/interfaces/Crafter.Review-Seats.cppm +++ b/interfaces/Crafter.Review-Seats.cppm @@ -28,8 +28,12 @@ export namespace Crafter::Review::Seats { // Fixed rules, not knobs: utilisation is rounded to RankQuantum before // ranking, and a seat whose 7-day window is at or above LongWindowCutoff is // out regardless — its reset is days away. The Fable window is exempt here. + // 99 since 2026-10-15 (95 before): the weekly window is the budget the + // lenses run out of, and the pool projects its running passes against the + // cutoff (SeatPool::LensCost7dPct), so the last percent is spent a pass at + // a time, not in a burst. constexpr std::int32_t RankQuantum = 5; - constexpr std::int32_t LongWindowCutoff = 95; + constexpr std::int32_t LongWindowCutoff = 99; // JavaScript's Math.round: halves go up, never to even. double JsRound(double x); diff --git a/process/prepush.md b/process/prepush.md index d9dc395..d0a55bb 100644 --- a/process/prepush.md +++ b/process/prepush.md @@ -261,7 +261,7 @@ drivers running and what they hold. The seat pool still places every process by its seat's projected 5-hour headroom (`REVIEW_GATES_LENS_COST_PCT`, `REVIEW_GATES_SEAT_MAX_UTIL`) — or, on an account whose 5-hour limit Anthropic has removed, by its weekly window -under the 95 % cutoff — at most 128 passes per account, every driver's +under the 99 % cutoff — at most 128 passes per account, every driver's counted (`REVIEW_GATES_OAUTH_CONCURRENCY`), and a pass launches only when its environment's instrument is free and it fits in free memory (How the passes share the stacks): the driver logs per gate diff --git a/tests/Drivers/main.cpp b/tests/Drivers/main.cpp index 6480b29..e2696af 100644 --- a/tests/Drivers/main.cpp +++ b/tests/Drivers/main.cpp @@ -169,14 +169,14 @@ namespace { const Json f1 = At(sa, "1").at("foreign"); const Json fa = At(sa, "api1").at("foreign"); Check("three passes of B on seat 1 and two on api1 fold into A as foreign, at B's own per-pass figures", - f1.at("count") == 3 && Dyn::Equal(f1.at("cost5h"), 0.75) && Dyn::Equal(f1.at("costUsd"), 0) && fa.at("count") == 2 && Dyn::Equal(fa.at("costUsd"), 2.0) + f1.at("count") == 3 && Dyn::Equal(f1.at("cost5h"), 1.5) && Dyn::Equal(f1.at("costUsd"), 0) && fa.at("count") == 2 && Dyn::Equal(fa.at("costUsd"), 2.0) && Dyn::Equal(f1.at("drivers"), {{B.Me(), 3}}), std::format("{} {}", DumpSpaced(f1), DumpSpaced(fa))); Json s84 = mk("x", "oauth", "tx", 84, 50); s84["foreign"] = {{"count", 3}, {"cost5h", 1.5}, {"costUsd", 0}}; const bool over = !SeatPool::Eligible(s84, now, cfg, acfg); Json s84Bare = With(s84, {{"foreign", {{"count", 0}, {"cost5h", 0.0}, {"costUsd", 0.0}}}}); - Check("the 5-hour projection counts the foreign passes: 84 + 1.5 + 0.25 is over 85, without them under", over && SeatPool::Eligible(s84Bare, now, cfg, acfg)); + Check("the 5-hour projection counts the foreign passes: 84 + 1.5 + 0.5 is over 85, without them under", over && SeatPool::Eligible(s84Bare, now, cfg, acfg)); Json a8 = mk("api9", "api", "k9"); a8["foreign"] = {{"count", 6}, {"cost5h", 0}, {"costUsd", 6.0}}; a8["running"] = 2; @@ -338,7 +338,7 @@ namespace { // The board's reading of the account (40, B's) folded in before the // projection. const Json base = sm["windows"]["five_hour"]["utilization"]; - Check("a driver's passes fold at its own projection (2 % each) into another driver's (0.25 %)", + Check("a driver's passes fold at its own projection (2 % each) into another driver's (0.5 %)", Dyn::Equal(sm["foreign"], {{"count", 2}, {"cost5h", 4.0}, {"cost7d", 0.25}, {"costUsd", 0}, {"drivers", {{D.Me(), 2}}}}) && base == 40 && SeatPool::OauthProjected(sm, cfg) == base.get() + 4.0, std::format("{} {}", DumpSpaced(sm["foreign"]), base.dump())); diff --git a/tests/SeatPool/main.cpp b/tests/SeatPool/main.cpp index 4a7d7e1..66e946b 100644 --- a/tests/SeatPool/main.cpp +++ b/tests/SeatPool/main.cpp @@ -59,8 +59,9 @@ int main() { Ids(seats) == "api1,1,2" && Ids(SeatPool::LoadSeats({}, std::nullopt, "")) == "local", Ids(seats)); const std::string summary = DumpSpaced(SeatPool::Summary(seats)); Check("no secret in the summary or the table", !(summary + SeatPool::Table(seats)).contains("tok-one") && !summary.contains("sk-ant")); - Check("the pool's default projection is 0.25% of the 5-hour window per process (measured 0.08, 2026-10-15); the env overrides", - Dyn::Equal(SeatPool::PoolConfig({}).at("lensCostPct"), 0.25) && Dyn::Equal(SeatPool::PoolConfig({{"REVIEW_GATES_LENS_COST_PCT", "5"}}).at("lensCostPct"), 5)); + Check("the 5-hour share of a pass follows the run's effort (0.125 at xhigh, 0.5 at max and any other); the env overrides every effort", + Dyn::Equal(SeatPool::PoolConfig({}).at("lensCostPct"), 0.5) && Dyn::Equal(SeatPool::PoolConfig({}, "max").at("lensCostPct"), 0.5) + && Dyn::Equal(SeatPool::PoolConfig({}, "xhigh").at("lensCostPct"), 0.125) && Dyn::Equal(SeatPool::PoolConfig({{"REVIEW_GATES_LENS_COST_PCT", "5"}}, "xhigh").at("lensCostPct"), 5)); const double now = std::floor(Platform::Now()); Json& api1 = seats[0]; @@ -109,7 +110,7 @@ int main() { Check("...and the seat is back after the back-off", !requeued && sc.at("state") == "ok" && SeatPool::Eligible(sc, now + SeatPool::ConcurrentBackoffS + 1, cfg, acfg)); // 2026-10-31: an account whose 5-hour limit is removed reports the weekly // window alone; until then the pool took it for an unprobed seat - ranked - // after every other, never held to the weekly cutoff. The cutoff is 95 %. + // after every other, never held to the weekly cutoff. The cutoff is 99 %. const Json px = SeatPool::PoolConfig({}, "xhigh"); Json nf = With(SeatPool::NewSeat("n", "oauth", "tn"), {{"state", "ok"}, {"running", 0}, {"pauseUntil", 0}, {"windows", {{"seven_day", {{"utilization", 3}, {"resetsAt", now + 6 * 86400}}}}}}); Json f15 = With(SeatPool::NewSeat("f", "oauth", "tf"), {{"state", "ok"}, {"running", 0}, {"pauseUntil", 0}, @@ -119,13 +120,13 @@ int main() { for (const Json* s : SeatPool::Ranked(pair, now, px, acfg)) order.push_back(s->at("id").get()); Check("an account without a 5-hour window is placed by its weekly one: ranked by it, ahead of a seat at 5h 15 %, its running passes projected at the weekly figure", order == std::vector{"n", "f"} && std::abs(SeatPool::OauthProjected(With(nf, {{"running", 100}}), px) - 7.0) < 1e-9, Dyn::Join(order, ",")); - Json n93 = With(nf, {{"windows", {{"seven_day", {{"utilization", 93}, {"resetsAt", now + 86400}}}}}}); - Json n93r40 = With(n93, {{"running", 40}}); - Json n93r60 = With(n93, {{"running", 60}}); - Check("...under the weekly cutoff alone, no 5-hour ceiling: at 93 % it takes a pass with 40 running, not with 60 (93 + 61 x 0.04 >= 95)", - SeatPool::Eligible(n93r40, now, px, acfg) && !SeatPool::Eligible(n93r60, now, px, acfg)); - Json n95 = With(nf, {{"windows", {{"seven_day", {{"utilization", 95}, {"resetsAt", now + 86400}}}}}}); - Check("...and over the cutoff it waits for its weekly reset + 30 s", !SeatPool::Eligible(n95, now, px, acfg) && SeatPool::EarliestResume({n95}, now) == now + 86430); + Json n97 = With(nf, {{"windows", {{"seven_day", {{"utilization", 97}, {"resetsAt", now + 86400}}}}}}); + Json n97r40 = With(n97, {{"running", 40}}); + Json n97r60 = With(n97, {{"running", 60}}); + Check("...under the weekly cutoff alone, no 5-hour ceiling: at 97 % it takes a pass with 40 running, not with 60 (97 + 61 x 0.04 >= 99)", + SeatPool::Eligible(n97r40, now, px, acfg) && !SeatPool::Eligible(n97r60, now, px, acfg)); + Json n99 = With(nf, {{"windows", {{"seven_day", {{"utilization", 99}, {"resetsAt", now + 86400}}}}}}); + Check("...and over the cutoff it waits for its weekly reset + 30 s", !SeatPool::Eligible(n99, now, px, acfg) && SeatPool::EarliestResume({n99}, now) == now + 86430); Json n127 = With(nf, {{"running", 127}}); Json n128 = With(nf, {{"running", 128}}); Json nShared = With(nf, {{"running", 100}, {"foreign", {{"count", 28}, {"cost5h", 0.0}, {"cost7d", 0.0}, {"costUsd", 0.0}}}}); diff --git a/tests/Seats/main.cpp b/tests/Seats/main.cpp index 7628db2..a49c68c 100644 --- a/tests/Seats/main.cpp +++ b/tests/Seats/main.cpp @@ -82,7 +82,7 @@ int main() { Eq(lines.at(3), "| 2 | 61% | 10:10 (in 10 min) | 18% | Thu 10 Sept, 10:00 (in 3d 0h) | — |"); Eq(lines.at(4), "| 3 | 62% | 10:15 (in 15 min) | 16% | Thu 10 Sept, 10:00 (in 3d 0h) | 22% |"); Eq(lines.at(5), ""); - Eq(lines.at(6), "policy spread · ceiling 85% · handover at 90% · a lens is placed at +10% · 7d cutoff 95%"); + Eq(lines.at(6), "policy spread · ceiling 85% · handover at 90% · a lens is placed at +10% · 7d cutoff 99%"); Eq(lines.at(7), "eligible now: seat 2 (25% headroom), seat 3 (25% headroom) → next lens: seat 2"); Eq(lines.at(8), "fable lenses: seat 3 (63% fable headroom)"); Eq(lines.at(9), "limited: seat 1 until 10:05 (in 5 min)"); @@ -223,8 +223,8 @@ int main() { auto pair = [](const std::pair& p) { return Json::array({p.first, p.second}); }; EqJson(pair(SeatUtil({{"five_hour", {{"utilization", 61}, {"resetsAt", 1}}}, {"seven_day", {{"utilization", 18}, {"resetsAt", 2}}}})), Json::array({60, "five_hour"})); EqJson(pair(SeatUtil({{"five_hour", {{"utilization", 12}, {"resetsAt", 1}}}, {"seven_day_fable", {{"utilization", 97}, {"resetsAt", 2}}}})), Json::array({95, "seven_day_fable"})); - Eq(IsEligible(seat(1, 10, 96), With(cfg, {{"maxUtil", 100}})), false); - Eq(IsEligible(seat(1, 10, 94), With(cfg, {{"maxUtil", 100}})), true); + Eq(IsEligible(seat(1, 10, 99), With(cfg, {{"maxUtil", 100}})), false); + Eq(IsEligible(seat(1, 10, 98), With(cfg, {{"maxUtil", 100}})), true); Eq(IsEligible(seat(1, 10, 94), cfg), false); // Redaction: the seat's own token, token shapes and addresses; auth // failures by status or by text.