// SPDX-License-Identifier: AGPL-3.0-only // SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // Stacks and memory: the slots config, slot.json, free memory, a pass's // measured cost, the admission, the prompts, the preflight, `slots`. // app_ready, the database calls, the memory readings and the methods of Run // are replaced through the Run's seams. #include #include import std; import Crafter.Review; namespace fs = std::filesystem; using namespace Crafter::Review; namespace { std::int32_t Failures = 0; const std::string Fn(Plan::FunctionalLens); void Check(std::string_view name, bool cond, std::string_view detail = {}) { std::println("{}{}{}", cond ? " ok " : " FAIL ", name, !cond && !detail.empty() ? std::format(" ({})", detail) : std::string()); if (!cond) ++Failures; } void Write(const fs::path& path, std::string_view text) { fs::create_directories(path.parent_path()); std::ofstream(path, std::ios::binary) << text; } bool AnyContains(const std::vector& lines, std::string_view part) { return std::ranges::any_of(lines, [&](const std::string& line) { return line.contains(part); }); } Json With(Json value, const Json& changes) { for (auto it = changes.begin(); it != changes.end(); ++it) value[it.key()] = it.value(); return value; } } int main() { std::println("stacks and memory: the slots config, slot.json, free memory, a pass's measured cost, the admission, the prompts, the preflight, `slots`"); Platform::SetMode(Platform::Mode::Native); SetHome(fs::current_path()); const fs::path base = fs::temp_directory_path() / std::format("crafter-review-stacks-{}", Platform::PublishedPid()); fs::remove_all(base); { const fs::path td = base / "one"; fs::create_directories(td / ".review-gates"); const fs::path p = td / ".review-gates" / "config.json"; auto bad = [&](const Json& d) { Write(p, DumpSpaced(d)); return Config::Load(td).problems; }; auto sl = [](const Json& kw) { return Json {{"slots", kw}}; }; Check("config: slots default to none; a dir inside the repository, start/stop with {n}, and the measured memMb with it; anything else is a problem", Dyn::Equal(Config::Defaults().at("slots"), {{"dir", nullptr}, {"start", nullptr}, {"stop", nullptr}, {"memMb", nullptr}, {"startMb", nullptr}}) && AnyContains(bad(sl({{"dir", "s"}, {"memMb", 1}, {"startMb", 0}})), "slots.startMb") && bad(sl({{"dir", ".local-stack/slots"}, {"start", "bash s.sh full --slot {n}"}, {"stop", "bash s.sh stop --slot {n}"}, {"memMb", 1500}})).empty() && AnyContains(bad(sl({{"dir", "/abs"}, {"memMb", 1}})), "inside the repository") && AnyContains(bad(sl({{"dir", "s"}, {"start", "bash s.sh"}, {"memMb", 1}})), "{n}") && AnyContains(bad(sl({{"dir", "s"}})), "slots.memMb") && AnyContains(bad(sl({{"dir", "s"}, {"memMb", true}})), "slots.memMb") && bad({{"slots", {{"nope", 1}}}}).size() == 1); Write(p, R"({"functional": {"concurrency": 4}})"); const Config::Loaded cr = Config::Load(td); const Config::Loaded cr2 = Config::Load("/", p); const Json& warnings = cr.config.at("_warnings"); const std::string w0 = warnings.empty() ? std::string() : warnings.at(0).get(); Check("config: functional.concurrency is retired - no problem (a freeze or a run goes on), the key dropped, a warning that says what replaced it; the --config path kept; no _warnings in the dump", cr.problems.empty() && cr2.problems.empty() && warnings.size() == 1 && w0.starts_with("functional.concurrency is no longer read - remove it from config.json:") && w0.contains("free memory") && w0.contains("slots") && !cr.config.at("functional").contains("concurrency") && cr2.config.at("_path") == p.string() && !Config::Redacted(cr.config).contains("_warnings") && Config::Load(td / "nowhere").config.at("_warnings").empty(), w0); const fs::path sd = td / ".local-stack" / "slots"; const std::vector> slots = { {"10", {{"appUrl", "http://localhost:21080"}, {"apiUrls", {"http://127.0.0.1:21021"}}, {"dbUrl", "postgresql://postgres:postgres@127.0.0.1:21022/postgres"}, {"login", ".local-stack/slots/10/u.json"}}}, {"2", {{"appUrl", "http://localhost:20280/"}, {"apiUrls", Json::array()}, {"dbUrl", nullptr}, {"login", nullptr}}}, {"1", {{"appUrl", "http://localhost:20180"}, {"dbUrl", "postgresql://u:p@db.example.supabase.co:5432/postgres"}}}, {"3", {{"apiUrls", Json::array()}}}, {"4", nullptr}, }; for (const auto& [n, body] : slots) { fs::create_directories(sd / n); if (!body.is_null()) Write(sd / n / "slot.json", DumpSpaced(body)); } fs::create_directories(sd / "5"); Write(sd / "5" / "slot.json", "{bad"); Write(sd / "10" / "u.json", "{}"); const Json cfg = {{"slots", {{"dir", ".local-stack/slots"}, {"start", "up --slot {n}"}, {"stop", "down --slot {n}"}, {"memMb", 1500}}}}; const Config::Slots found = Config::SlotStacks(cfg, td); std::vector ids; for (const Json& s : found.stacks) ids.push_back(s.at("id").get()); Check("slot_stacks: the slots that are up in slot order (2, 10), the URL without its trailing slash; a hosted database, no appUrl and bad JSON are problems; a dir without slot.json is not up", ids == std::vector{"slot 2", "slot 10"} && found.stacks.at(0).at("appUrl") == "http://localhost:20280" && found.stacks.at(1).at("login") == ".local-stack/slots/10/u.json" && found.stacks.at(1).at("dbUrl").get().ends_with(":21022/postgres") && std::ranges::all_of(found.stacks, [](const Json& s) { return s.at("slot") == true; }) && found.problems.size() == 3 && AnyContains(found.problems, "slots/1/slot.json: dbUrl") && AnyContains(found.problems, "slots/3/slot.json: no appUrl") && AnyContains(found.problems, "slots/5/slot.json: not JSON"), Dyn::Join(found.problems, " | ")); const std::vector threeFour = {3, 4}; const std::vector justOne = {1}; Check("slot_commands: the start and stop commands for the slots named; none without a command", Config::SlotCommands(cfg, "start", threeFour) == std::vector{"up --slot 3", "up --slot 4"} && Config::SlotCommands({{"slots", {{"stop", nullptr}}}}, "stop", justOne).empty()); // Memory: what is free, the reserve, a tree's PSS, the sampler, the // calibration. const fs::path mi = td / "meminfo"; Write(mi, "MemTotal: 131371024 kB\nMemFree: 3000000 kB\nMemAvailable: 82119216 kB\nHugePages_Total: 0\n"); Check("memory: MemAvailable and MemTotal in MB; the reserve is 10 % of MemTotal (at least 2048 MB) unless REVIEW_GATES_MEM_RESERVE_MB says otherwise; no file, no number", Memory::Available(mi) == 80194 && Platform::MemInfo(mi).at("MemTotal") == 128292 && Memory::Reserve(std::nullopt, mi) == 12829 && Memory::Reserve(std::string("4096"), mi) == 4096 && Memory::Reserve(std::nullopt, td / "none") == 2048 && !Memory::Available(td / "none")); auto raised = [&](std::string_view value) { try { Memory::Reserve(std::string(value), mi); return std::string("nothing"); } catch (const Dyn::Error& e) { return std::format("{}: {}", e.Kind(), e.what()); } }; Check("memory: a reserve that is no number raises (exit 1); one past int64 saturates; every number spelling is taken", raised("x") == "ValueError: could not convert string to float: 'x'" && raised("nan") == "ValueError: cannot convert float NaN to integer" && raised("-inf") == "OverflowError: cannot convert float infinity to integer" && Memory::Reserve(std::string("1e30"), mi) == std::numeric_limits::max() && Memory::Reserve(std::string(" 4_096.9 "), mi) == 4096, raised("x") + raised("nan")); const std::int64_t me = getpid(); const std::vector tree = Platform::Tree(me, Platform::PpidMap()); const std::vector gone = {(1 << 22) + 7}; Check("memory: a process tree's PSS - this process measures above zero, a pid that is gone measures zero", Platform::PssMb(tree) > 1 && Platform::PssMb(gone) == 0 && std::ranges::contains(tree, me)); std::deque vals = {100.0, 400.0, 250.0}; Memory::Sampler sm(3600, [&](std::int64_t, const auto&) { const double v = vals.front(); vals.pop_front(); return v; }, [] { return std::map> {}; }); sm.Watch("a", 1); sm.Sample(); sm.Sample(); sm.Sample(); const std::optional peak = sm.Done("a"); Check("Sampler: the peak of the samples of a watched pass, and nothing once it is done", peak == 400.0 && !sm.Done("a")); Memory::Calibration cal(td / "memory.json", td, {{"none", 300}, {"browser", 900}}); const Memory::Calibration::Cost d0 = cal.CostOf("browser"); cal.Record("browser", 500.0); cal.Record("browser", 1200.0); for (std::size_t i = 0; i < Memory::Keep; ++i) cal.Record("browser", 700.0); const Memory::Calibration other(td / "memory.json", td / "elsewhere", {{"none", 300}, {"browser", 900}}); Check("Calibration: the measured default before any peak; then the highest of the last 30 peaks of this repository and environment (an old outlier ages out); another repository keeps its own", d0.megabytes == 900 && d0.source == "the default measured 2026-10-22; none measured in this repository yet" && cal.CostOf("browser").megabytes == 700.0 && cal.Peaks("browser").size() == Memory::Keep && other.CostOf("browser").megabytes == 900 && cal.CostOf("none").megabytes == 300); } // Stacks: exclusive, least recently returned first, the preferred one // only. { Pool::Stacks st({{{"id", "s1"}}, {{"id", "s2"}}, {{"id", "s3"}}}); const Json a = st.Take(); const Json b = st.Take(); st.Give(a.at("id")); const bool third = st.Take().at("id") == "s3"; const bool busy = !st.Can(std::string("s2")); const bool back = st.Can(std::string("s1")); const bool preferred = st.Take(std::string("s1")).at("id") == "s1"; const bool none = !st.Can(); st.Give("s2"); Check("Stacks: two takes are two stacks; a returned one goes to the back; prefer takes that one or reports it busy", a.at("id") == "s1" && b.at("id") == "s2" && third && busy && back && preferred && none && st.Can()); } // Admission: stacks, the memory budget, the machine's free memory now, // nothing in flight. { std::vector logs; double free = 10'000; Pool::Stacks st2({{{"id", "slot 1"}}}); Pool::Admission adm([](const Json& j) { return j.at("mb").get(); }, [](const Json& j) { return Dyn::Truthy(Dyn::Get(j, "app")); }, &st2, 1000.0, 500, [&]() -> std::optional { return free; }, [&](const std::string& line) { logs.push_back(line); }); Json j1 = {{"label", "a"}, {"mb", 600}, {"app", true}}; const Json j2 = {{"label", "b"}, {"mb", 600}}; const Json j3 = {{"label", "c"}, {"mb", 300}, {"app", true}}; const bool first = adm.Can(j1); adm.Take(j1); Check("Admission: a pass with an application takes a stack of its own and its cost; the next one waits for the stack, one over the budget waits for memory", first && j1.at("stack").at("id") == "slot 1" && j1.at("prevStack") == "slot 1" && !adm.Can(j3) && !adm.Can(j2) && adm.Held() == 600 && adm.Inflight() == 1); const Json j4 = {{"label", "d"}, {"mb", 300}}; free = 700; const bool low = adm.Can(j4); free = 10'000; Check("Admission: inside the budget but the machine has less than cost + reserve free right now -> wait; with room -> go", !low && adm.Can(j4)); adm.Give(j1); Json big = {{"label", "e"}, {"mb", 5000}}; const bool alone = adm.Can(big); adm.Take(big); Check("Admission: given back, the stack and the memory are free again; with nothing in flight a pass over the budget runs alone, and the log says so once", st2.Can() && adm.Held() == 5000 && alone && logs.size() == 1 && logs.front().contains("launched alone") && !j1.contains("stack")); adm.Give(big); Pool::Stacks st3({{{"id", "slot 1"}}, {{"id", "slot 2"}}}); Pool::Admission adm3([](const Json&) { return 1.0; }, [](const Json&) { return true; }, &st3); Json taken = {{"label", "x"}}; adm3.Take(taken); Json rj = {{"label", "r"}, {"resumeSession", "sid"}, {"prevStack", "slot 1"}}; const bool waits = !adm3.Can(rj); adm3.Give(taken); const bool can = adm3.Can(rj); adm3.Take(rj); Check("Admission: a resumed pass waits for the stack its transcript ran on, not for any", waits && can && rj.at("stack").at("id") == "slot 1"); } // The prompts: the shared block names no stack in slot mode; the pass's // own goes into its user message. const Json fcfg = {{"appUrl", "http://localhost:8080"}, {"apiUrls", {"http://127.0.0.1:54321"}}, {"login", {{"notes", "TOTP enrolled"}}}}; const std::string abSlots = Prompt::AppBlock(fcfg, std::string(".local-stack/test-user.json"), std::string("/p/bin/crafter-review totp .local-stack/test-user.json"), true); const std::string abOne = Prompt::AppBlock(fcfg, std::string(".local-stack/test-user.json"), std::string("/p/bin/crafter-review totp .local-stack/test-user.json")); Check("app block with slots: a stack of this pass's own, STACK FOR THIS PASS named, no URL, origin, fixture or TOTP command in the shared block; the rules: yours alone, not reset between passes", abSlots.contains("a stack of this pass's own") && abSlots.contains("STACK FOR THIS PASS") && !abSlots.contains("localhost:8080") && !abSlots.contains("54321") && !abSlots.contains("test-user.json") && !abSlots.contains("/p/bin/crafter-review") && abSlots.contains("TOTP enrolled") && abSlots.ends_with(Prompt::ShotRules) && abSlots.contains("not reset between passes") && abOne.contains("localhost:8080") && abOne.contains("test-user.json") && abOne.contains("not reset between passes") && !abOne.contains("STACK FOR THIS PASS")); const Json stk = {{"id", "slot 2"}, {"appUrl", "http://localhost:20280"}, {"apiUrls", {"http://127.0.0.1:20221"}}, {"dbUrl", "postgresql://postgres:secret@127.0.0.1:20222/postgres"}, {"login", ".local-stack/slots/2/test-user.json"}}; const std::string stackLogin = stk.at("login").get(); const std::string tx = Prompt::StackText(stk, Pool::TotpCommand(stackLogin)); const Json seven = {{"maxTurns", 7}}; const std::string up = Prompt::UserPrompt("TAIL", seven, tx); const std::string up0 = Prompt::UserPrompt("TAIL", seven); Check("user prompt: the pass's stack - its URL, origins, login and exact TOTP command, never its database URL - between the scope and the budget line; without one the message is what it was", up.find("TAIL") < up.find("STACK FOR THIS PASS (slot 2, yours alone while this pass runs)") && up.find("STACK FOR THIS PASS (slot 2, yours alone while this pass runs)") < up.find("Tool-call budget") && up.contains("http://localhost:20280") && up.contains("20221") && up.contains(std::format("`{}`", *Pool::TotpCommand(stackLogin))) && !up.contains("20222") && !up.contains("secret") && up0 == std::format("TAIL{}\n\nReturn the structured output described in your instructions.\n", Prompt::BudgetLine(seven)) && Prompt::StackText(With(stk, {{"login", nullptr}}), std::nullopt).contains("no login fixture")); Check("functional block hint: the stack is the pass's own and not reset between passes", Prompt::FunctionalBlockHint.contains("yours alone while this pass runs, but it is not reset between passes") && !Prompt::FunctionalBlockHint.contains("at the same time")); { const fs::path td = base / "runner"; fs::create_directories(td); PgWire::Broker broker; broker.Start(); const Pool::Runner r({.repo = fs::current_path(), .scratch = td, .bin = "/bin/true", .effort = "xhigh", .log = [](const std::string&) {}, .dryRun = true, .functional = {{"mcp", {{"command", "npx"}, {"args", nullptr}}}, {"extraTools", Json::array()}}, .loginFixture = ".local-stack/test-user.json", .environments = {{Fn, "browser+supabase"}, {"repo-bug-prover.md", "supabase"}}, .dbUrl = "postgresql://postgres:postgres@127.0.0.1:54322/postgres", .broker = &broker}); const std::vector here = {"."}; auto allowed = [](const std::vector& c) { return c[static_cast(std::ranges::find(c, "--allowedTools") - c.begin()) + 1]; }; const std::string al2 = allowed(r.Cmd({{"label", "f"}, {"model", "m"}, {"lensFile", Fn}, {"kind", "block"}, {"stack", stk}}, "/dev/null", "{}", here, 20, false, "sid")); const std::string al1 = allowed(r.Cmd({{"label", "f"}, {"model", "m"}, {"lensFile", Fn}, {"kind", "block"}}, "/dev/null", "{}", here, 20, false, "sid")); Check("runner: a pass on a slot may run the TOTP command of that slot's login alone; a pass without a stack keeps the run's fixture", al2.contains(std::format("Bash({}:*)", *Pool::TotpCommand(stackLogin))) && !Dyn::Replace(al2, stackLogin, "").contains("test-user.json:*") && al1.contains(std::format("Bash({}:*)", *Pool::TotpCommand(".local-stack/test-user.json")))); const std::string brokerEnv(PgWire::BrokerEnv); auto dbOf = [&](const std::map& e) { const std::string v = e.at(brokerEnv); return broker.UrlOf(v.substr(v.rfind('#') + 1)).value_or(""); }; Check("runner: the database a pass reaches is its stack's; a pass with the database alone reaches the run's first", dbOf(r.ProcessEnv({{"lensFile", Fn}, {"stack", stk}}, {})) == stk.at("dbUrl").get() && dbOf(r.ProcessEnv({{"lensFile", "repo-bug-prover.md"}}, {})).ends_with(":54322/postgres")); broker.Close(); } // The preflight: slots up, every stack answers, its login in its // auth.users. { const fs::path td = base / "preflight"; fs::create_directories(td); Run::Run g; std::vector logs; g.repo = td; g.log = [&](const std::string& line) { logs.push_back(line); }; g.cfg = {{"functional", {{"start", "make run"}, {"readyPath", "/"}, {"exclude", Json::array()}}}, {"supabase", {{"dbUrl", "postgresql://postgres:postgres@127.0.0.1:1/postgres"}, {"start", nullptr}}}, {"slots", {{"dir", ".local-stack/slots"}, {"start", "up --slot {n}"}, {"stop", nullptr}, {"memMb", 1500}}}}; g.environments = {{Fn, "browser+supabase"}, {"repo-bug-prover.md", "supabase"}}; g.a.dryRun = false; g.a.harness = "claude"; g.trees = {"."}; auto pre = [&](const std::vector& lenses) -> std::pair { try { g.StackPreflight(lenses); return {"ok", logs.empty() ? std::string() : logs.back()}; } catch (const Run::Preflight& e) { return {"3", std::format("preflight: {}\n", e.what())}; } }; g.slotMode = true; g.stacks = std::make_unique(std::vector {{{"id", "slot 1 (dry run: none is up)"}, {"appUrl", "http://x"}, {"apiUrls", Json::array()}, {"dbUrl", nullptr}, {"login", nullptr}, {"slot", true}}}); const auto noneUp = pre({Fn}); g.slotProblems = {".local-stack/slots/3/slot.json: no appUrl"}; const auto broken = pre({Fn}); g.slotProblems.clear(); Write(td / "l" / "u.json", R"({"email": "A@x.test", "password": "p"})"); std::vector two; for (const std::int32_t n : {1, 2}) { two.push_back({{"id", std::format("slot {}", n)}, {"appUrl", std::format("http://localhost:2{}180", n)}, {"apiUrls", Json::array()}, {"dbUrl", std::format("postgresql://postgres:postgres@127.0.0.1:2{}122/postgres", n)}, {"login", "l/u.json"}, {"slot", true}}); } g.stacks = std::make_unique(two); std::vector answered; std::vector probed; Run::QueryResult::second_type users = {{"x"}}; g.appReady = [&](std::string_view url, std::string_view) { answered.emplace_back(url); return std::pair(true, std::format("HTTP 200 from {}", url)); }; g.probe = [&](std::string_view url) { probed.emplace_back(url); return std::pair(true, "postgres on 127.0.0.1 as postgres - PostgreSQL 17.6"); }; g.query = [&](std::string_view, std::string_view) { return Run::QueryResult({"?"}, users); }; g.bypassesRls = [](std::string_view) { return std::optional(true); }; g.migrationsDrift = [](const std::string&) { return std::pair, std::optional>(std::nullopt, "its 2 applied migrations are the range HEAD's"); }; const auto good = pre({Fn}); const std::vector appSeen = answered; const std::vector dbSeen = probed; answered.clear(); probed.clear(); const auto onlyDb = pre({"repo-bug-prover.md"}); const std::vector dbOnlySeen = probed; users.clear(); const auto stale = pre({Fn}); users.push_back({"x"}); g.appReady = [](std::string_view url, std::string_view) { return std::pair(!url.contains(":22180"), std::format("connection refused by {}", url)); }; const auto down = pre({Fn}); Check("preflight: slots configured and none up stops the run and names ` slots`; a broken slot.json stops it", noneUp.first == "3" && noneUp.second.contains("no slot is up under .local-stack/slots") && noneUp.second.contains(std::format("`{} slots`", Invocation())) && broken.first == "3" && broken.second.contains("slots/3/slot.json"), noneUp.second + broken.second); Check("preflight: a lens that drives the application checks every stack - its app, its database, its migrations; a lens with the database alone checks the first", good.first == "ok" && appSeen.size() == 2 && dbSeen.size() == 2 && dbOnlySeen == std::vector{two.front().at("dbUrl").get()} && good.second.contains("2 slot(s) under .local-stack/slots") && g.dbChecked && g.dbChecked->starts_with("the database of each of the 2 stacks answers") && onlyDb.first == "ok", good.second); Check("preflight: a stack whose login is not in its auth.users stops the run (a fixture left from another bring-up); an app that does not answer names its slot and the start command", stale.first == "3" && stale.second.contains("slot 1: its login l/u.json (a@x.test) is not in that stack's auth.users") && down.first == "3" && down.second.contains("slot 2: the application does not answer") && down.second.contains("(up --slot {n})"), stale.second + down.second); // exec_job: the stack the admission gave, the measured peak into the // calibration. const fs::path fx = fs::current_path() / "tests" / "Goldens" / "fixture" / "commits"; g.a.artifact = fx.string(); g.a.dryRun = false; g.a.effort = "xhigh"; g.a.noSalvage = true; g.hash = Artifact::ArtifactHash("commits", fx); g.testMode = true; g.schemas = {{"block", "{}"}, {"whole", "{}"}}; g.treeDrift = [] { return std::optional(); }; g.promptFor = [](const Json&) { return std::pair("/dev/null", "PROMPT"); }; g.calibration = std::make_unique(td / "memory.json", td, std::map {{"none", 300}, {"browser+supabase", 900}}); g.runPass = [](const Json& job, const std::string&, const fs::path&, std::string_view, std::int64_t, std::int64_t, bool) { return std::pair({{"label", job.at("label")}, {"status", "ok"}, {"memPeakMb", 812.5}}, nullptr); }; const auto [rec, raw] = g.ExecJob({{"label", "f1"}, {"lens", "repo-functional"}, {"lensFile", Fn}, {"kind", "block"}, {"model", "m"}, {"stack", g.stacks->All().at(1)}}, 1); Check("exec_job: the record names the pass's stack, and its measured peak becomes its environment's calibration", rec.at("stack") == "slot 2" && g.calibration->CostOf("browser+supabase").megabytes == 812.5); // `slots`: as many as free memory holds, no more than the range's // browser passes, the commands for the missing ones. Write(td / ".local-stack" / "slots" / "1" / "slot.json", R"({"appUrl": "http://localhost:20180", "apiUrls": [], "dbUrl": null, "login": null})"); Json cfg = Config::Load(td).config; cfg["slots"] = {{"dir", ".local-stack/slots"}, {"start", "up --slot {n}"}, {"stop", nullptr}, {"memMb", 1500}, {"startMb", 6000}}; cfg["lenses"]["repo-functional"]["environment"] = "browser+supabase"; std::vector out; const Run::Machine machine = {.available = [] { return std::optional(20'000); }, .reserve = [] { return std::int64_t {4000}; }}; auto sink = [&](const std::string& line) { out.push_back(line); }; const auto [want, cmds] = Run::SlotsPlan(cfg, td, std::nullopt, td, sink, machine); const auto [want2, cmds2] = Run::SlotsPlan(cfg, td, fx, td, sink, machine); std::vector expected; for (std::int32_t n = 2; n < 8; ++n) expected.push_back(std::format("up --slot {}", n)); // 20000 free - 4000 reserve - 1 slot up x 812.5 = 15187.5 for (1500 + // 812.5) each -> 6 more. Check("slots: room = free - reserve - the passes of the slots up, each new slot at memMb plus one measured pass -> 6 more, numbered after the ones up; with the fixture range no more than its 3 browser block passes", want == 7 && cmds == expected && want2 == 3 && cmds2 == std::vector{"up --slot 2", "up --slot 3"} && AnyContains(out, "room for 6 more by memory"), Dyn::Join(out, " | ")); Check("slots: no more start at once than free memory holds at slots.startMb each (15187 MB / 6000 -> 2), and one at a time without it", AnyContains(out, "at most 2 at once (slots.startMb 6000 MB each"), Dyn::Join(out, " | ")); } fs::remove_all(base); return Failures == 0 ? 0 : 1; }