Crafter.Review/tests/KernelModes/main.cpp
Jorijn van der Graaf e215ad986e
feat(seats): the env file's settings count, and a machine's own seats file
ApiConfig and PoolConfig read the seat order, the budgets and the
concurrency from the process environment alone, so a `.env` that said
REVIEW_GATES_SEAT_ORDER=oauth-first ordered nothing: the Python driver
reads those lines from the file under the process environment
(config_env, 2026-10-17: a setting lives beside the seats it orders).
SeatPool::SettingsOf does the same - the file's placement settings
under the process environment, in a map handed to the placement readers
alone (ApiConfig, PoolConfig, Seats::ConfigFromEnv) - and leaves the
process environment untouched, so no other reader sees a line of the
file: a path's or a binary's line reaches nothing, and two drivers
reading one .env keep one board and one ledger. The placement settings
are one list, SeatPool::PlacementSettings - the fifteen names those
readers read - for the map, the run's log and what makes a working
directory's .env a seats file; a REVIEW_GATES_* line of any other name
stays out of the map and is named, by the run's log and on `seats`'s
stderr. One dotenv grammar serves the tokens and the settings
(Seats::DotenvLines).

`run` and `seats` resolve the file from their own --env-file
(SeatPool::ResolveSeatsFile): the --env-file, else $SEATS_ENV_FILE, else
the working directory's .env - the operator's, as the Python driver and
`seats` read it, not the repository under review's - when it is a file
holding a seat or a placement setting, each with a value, or one that
cannot be read as UTF-8 text (its error is then the command's) - a
readable application .env, its Vite or Supabase lines, one of blank
placeholder lines or one that is no file is passed over, and the run
says so - else the machine's own
$XDG_CONFIG_HOME/crafter-review/env, else ~/.config/crafter-review/env:
one file for every repository on a machine, a repository's seats .env
winning over it. Each file is read once and the settings and the tokens
are taken from that read (SeatsFile::Text), so a file that can be read
only once - a pipe, `--env-file <(gpg -d seats.env.gpg)`, a FIFO - gives
its settings and its seats alike, and a failed read raises its own error
where the tokens are laid over the environment: SeatPool::WithFileTokens,
for `run` and `seats` alike, and LoadSeats takes the merged environment
and no longer reads a file by path. An empty `seats --env-file` means no file
now, as it did for `run`, and the `seats` report names the side that
runs first (it said "api seats run first" whatever the order).

Runs, Commands and KernelModes, the tests that run `run` and `seats`,
point XDG_CONFIG_HOME, and HOST_XDG_CONFIG_HOME for the Flatpak, at a
path of their own that nothing creates, so a global file stays out of
them; the grammar, the settings and their precedence, the lookup and the
one read have their tests, a run with `--env` (a prefix) and with a
repeated --env-file, and a `seats` with `--env`, take tokens and
settings from the one file, an application's .env and a venv are passed
over, a FIFO is read once, no line of the file reaches `stop`, every
listed placement setting moves a reader, another REVIEW_GATES_* line is
named and a .env of blank lines passed over, and the
README, the environment table and the procedure say the new rule.
2026-11-02 00:30:52 +01:00

749 lines
72 KiB
C++

// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
// The kernel modes (reply, series): the inventory of a review draft, a plain
// mail and a series with a cover letter; the gates, efforts, reads and
// budgets per mode; the plans (every slot, the bare headers, a persona
// instance); the text and series reuse keys; the dispositions' carry and
// block texts; the prompts (common text, run layer, tails, lens layer); the
// kernel schema; the persona vocabulary in normalize and the matrix; the
// references; the state's persona pass; the allowlist; and dry runs of both
// modes through this binary, the persona gate included.
import std;
import Crafter.Review;
namespace fs = std::filesystem;
using namespace Crafter::Review;
namespace {
std::int32_t Failures = 0;
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;
}
std::vector<std::string> Ids(const Json& units) {
std::vector<std::string> out;
for (const Json& u : units) out.push_back(Dyn::Str(u.at("id")));
return out;
}
std::string Show(const std::vector<std::string>& values) {
Json out = Json::array();
for (const std::string& v : values) out.push_back(v);
return Dyn::ReprValue(out);
}
const Json& Unit(const Json& units, std::string_view id) {
for (const Json& unit : units) {
if (unit.at("id") == id) return unit;
}
throw std::runtime_error(std::format("no unit {}", id));
}
std::vector<std::string> Titles(const std::vector<Plan::Gate>& gates) {
std::vector<std::string> out;
for (const Plan::Gate& gate : gates) out.emplace_back(gate.title);
return out;
}
std::vector<std::string> LensesOf(const Plan::Gate& gate) {
return {gate.lenses.begin(), gate.lenses.end()};
}
std::map<std::string, std::int64_t> Kinds(const std::vector<Json>& jobs) {
std::map<std::string, std::int64_t> out;
for (const Json& j : jobs) ++out[Dyn::Str(j.at("kind"))];
return out;
}
std::set<std::string> Units(const std::vector<Json>& jobs, std::string_view kind = {}) {
std::set<std::string> out;
for (const Json& j : jobs) {
if (kind.empty() || j.at("kind") == kind) out.insert(Dyn::Str(j.at("unit")));
}
return out;
}
// claude for the dry runs' sibling full run: the units from its prompt,
// every unit clear; a persona's whole pass marks nothing not-mine.
constexpr std::string_view FakeClaude = R"sh(#!/bin/sh
set -f
[ "$1" = --version ] && { echo '2.1.314 (Claude Code)'; exit 0; }
model=
sid=
prev=
for a in "$@"; do
case $prev in
--model) model=$a ;;
--session-id) sid=$a ;;
esac
prev=$a
done
ids=$(sed -n -e 's/^SCOPE - BLOCK PASS, unit "\([^"]*\)".*/\1/p' -e 's/^SCOPE - SLOT PASS, unit "\([^"]*\)".*/\1/p' -e 's/^- \(whole:[a-z-]*\) \[.*/\1/p')
echo "$$" $ids >> "$FAKE_DIR/calls"
echo "{\"type\":\"system\",\"subtype\":\"init\",\"session_id\":\"$sid\",\"model\":\"$model\",\"mcp_servers\":[],\"tools\":[\"Read\"]}"
echo '{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"reading"}]}}'
coverage=
summary=
for id in $ids; do
coverage="$coverage${coverage:+,}{\"item\":\"$id\",\"verdict\":\"clear\",\"basis\":\"no record\"}"
case $id in whole:*) summary=',"summary":"the approach holds","predictedReview":"Looks fine.","notMine":[]' ;; esac
done
echo "{\"type\":\"result\",\"subtype\":\"success\",\"is_error\":false,\"result\":\"ok\",\"structured_output\":{\"verdict\":\"SEND-READY\",\"findings\":[],\"notes\":[],\"coverage\":[$coverage]$summary},\"usage\":{\"input_tokens\":1,\"output_tokens\":1,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0},\"total_cost_usd\":0.01,\"num_turns\":1}"
)sh";
std::map<std::string, std::string> Env;
std::map<std::string, std::string> With(std::map<std::string, std::string> env, const std::map<std::string, std::string>& changes) {
for (const auto& [k, v] : changes) env[k] = v;
return env;
}
// A reply's or series' reference index as a run leaves it, so a dry run
// fetches nothing: every entry failed.
void FailedIndex(const fs::path& gateDir, std::string_view h8, const Refs::Table& refs) {
Json index = Json::object();
for (const auto& [n, url] : refs) {
const std::optional<std::string> mid = Refs::MsgidOf(url);
index[n] = {{"url", url}, {"msgid", mid.value_or("")}, {"path", std::format("gate-state/refs/{}.raw", Refs::SafeName(mid.value_or("")))}, {"status", "failed"}, {"error", "no lore here"}};
}
Write(gateDir / std::format("refs-{}.json", h8), DumpFile(index));
}
std::string SystemFiles(const fs::path& dry) {
std::string all;
std::error_code error;
for (fs::directory_iterator it(dry, error), end; !error && it != end; it.increment(error)) {
const std::string name = it->path().filename().string();
if (name.starts_with("system-") && name.ends_with(".md")) all += Platform::ReadFile(it->path()).value_or("");
}
return all;
}
std::string Prompts(const fs::path& dry) {
std::string all;
std::error_code error;
for (fs::directory_iterator it(dry / "prompts", error), end; !error && it != end; it.increment(error)) {
if (it->path().extension() == ".txt") all += Platform::ReadFile(it->path()).value_or("");
}
return all;
}
std::int32_t Checks() {
std::println("kernel modes: the inventory, gates, plans, keys, dispositions, prompts, schema, normalize, refs, state, allowlist, dry runs");
Platform::SetMode(Platform::Mode::Native);
const fs::path checkout = fs::current_path();
SetHome(checkout);
const fs::path fix = checkout / "tests" / "KernelModes" / "fixture";
const fs::path base = fs::temp_directory_path() / std::format("crafter-review-kernel-{}", Platform::PublishedPid());
fs::remove_all(base);
fs::create_directories(base);
for (const auto& [k, v] : Platform::Environment()) {
const bool review = k.starts_with("REVIEW_GATES_") || k.starts_with("CRAFTER_REVIEW_") || k == "SEATS_ENV_FILE";
const bool seat = k.starts_with("CLAUDE_CODE_OAUTH_TOKEN") || k.starts_with("ANTHROPIC_API_KEY") || k.starts_with("OPENROUTER_KEY") || k.starts_with("FAKE_");
if (!review && !seat) Env[k] = v;
}
// No seats file of the machine's own: XDG_CONFIG_HOME natively, and
// HOST_XDG_CONFIG_HOME, which the Flatpak's Platform::Init copies
// over it - a directory of this run's own, which nothing creates.
const std::string noConfig = (base / "no-config").string();
Env = With(Env, {{"XDG_CONFIG_HOME", noConfig}, {"HOST_XDG_CONFIG_HOME", noConfig}, {"GIT_CONFIG_GLOBAL", "/dev/null"}, {"GIT_CONFIG_SYSTEM", "/dev/null"}, {"CRAFTER_REVIEW_HOME", checkout.string()}, {"REVIEW_GATES_BOARD", (base / "board.json").string()}});
// ---- the inventory --------------------------------------------------------------
const Inventory::Built draft = Inventory::Build("reply", (fix / "draft-camera.txt").string());
const std::vector<std::string> draftIds = Ids(draft.out.at("units"));
Check("reply, the camera review's shape: the author's groups, the anchor, the reversals, the sections' items and sub-items, the bullets, the refs, the three slots",
draftIds == std::vector<std::string>{"nl:intro", "nl:ov13b10-of/0001-media-i2c-ov13b10.patch", "nl:ov13b10-of/0000-cover-letter.patch", "anchor", "reversals:header", "R1", "R2",
"camss:header", "camss:1", "camss:1a", "camss:1b", "camss:2", "ov13b10:header", "ov13b10:1", "x:header", "x:1", "x:2", "refs", "whole:route",
"whole:asks", "whole:absent"}
&& Dyn::Str(draft.out.at("hash8")) == Artifact::Sha256File(fix / "draft-camera.txt").substr(0, 8) && Dyn::Str(draft.out.at("mode")) == "reply",
Show(draftIds));
const Json& draftUnits = draft.out.at("units");
Check("...a reversal holds its continuation line, a sub-item is one line, the refs run to the end",
Plan::UnitText(draft.lines, Unit(draftUnits, "R1")).starts_with("R1. The active-array origin") && Plan::UnitText(draft.lines, Unit(draftUnits, "R1")).contains("withdrawn.")
&& Dyn::Str(Unit(draftUnits, "camss:1a").at("excerpt")) == "a. The error path leaves the clock enabled." && Plan::UnitText(draft.lines, Unit(draftUnits, "refs")).ends_with("example.org/"),
Plan::UnitText(draft.lines, Unit(draftUnits, "R1")));
const Inventory::Built mail = Inventory::Build("reply", (fix / "reply.eml").string());
const std::vector<std::string> mailIds = Ids(mail.out.at("units"));
Check("reply, a plain mail: the header block, each quoted block with its attribution, our paragraphs, the trailer paragraph, the slots",
mailIds == std::vector<std::string>{"hdr", "quote:1", "para:1", "quote:2", "para:2", "para:3", "trailers", "whole:route", "whole:asks", "whole:absent"}
&& Unit(mail.out.at("units"), "quote:1").at("lines") == Json({8, 11}) && Unit(mail.out.at("units"), "trailers").at("lines") == Json({21, 22})
&& Unit(mail.out.at("units"), "hdr").at("lines") == Json({1, 6}),
Show(mailIds));
const Inventory::Built series = Inventory::Build("series", (fix / "series").string());
const std::vector<std::string> seriesIds = Ids(series.out.at("units"));
std::vector<std::string> coverIds;
for (const std::string& id : seriesIds) {
if (id.starts_with("cover:")) coverIds.push_back(id);
}
Check("series: the cover letter's header and its six paragraphs (the base-commit line and the signature are one), every patch's units, a .md hunk whole, the four series slots",
coverIds == std::vector<std::string>{"cover:header", "cover:1", "cover:2", "cover:3", "cover:4", "cover:5", "cover:6"}
&& std::ranges::contains(seriesIds, std::string("p1:drivers/nfc/widget.c#1")) && std::ranges::contains(seriesIds, std::string("p2:README.md#1"))
&& !std::ranges::contains(seriesIds, std::string("p2:README.md#1.1")) && std::ranges::contains(seriesIds, std::string("p1:trailers"))
&& seriesIds.back() == "whole:absent" && std::ranges::contains(seriesIds, std::string("whole:cover-vs-patches")) && std::ranges::contains(seriesIds, std::string("whole:recipients"))
&& Unit(series.out.at("units"), "cover:header").at("lines") == Json({1, 5}),
Show(seriesIds));
Check("series: a .md hunk is code to the kernel lenses and doc to the push gates' commit-truth lens",
Plan::KindFor("bug-prover.md", Unit(series.out.at("units"), "p2:README.md#1")) == "code" && Plan::KindFor("facts.md", Unit(series.out.at("units"), "p2:README.md#1")) == "code"
&& Plan::KindFor(Plan::FactsLens, Unit(series.out.at("units"), "p2:README.md#1")) == "doc");
// ---- gates, effort, reads, budgets ---------------------------------------------
Check("gates: reply runs Gate 3 alone; series Gates 1-3; --only and --without filter within the mode; a foreign lens filters to nothing",
Titles(Plan::Gates("reply")) == std::vector<std::string>{"Gate 3 — Artifact truth"} && LensesOf(Plan::Gates("reply")[0]) == std::vector<std::string>{"facts.md", "etiquette.md", "consistency.md", "conciseness.md"}
&& Titles(Plan::Gates("series")) == std::vector<std::string>{"Gate 1 — Structure", "Gate 2 — Code", "Gate 3 — Artifact truth"}
&& LensesOf(Plan::GatesFor("reply", std::vector<std::string>{"facts.md"}, {}, {})[0]) == std::vector<std::string>{"facts.md"}
&& Titles(Plan::GatesFor("series", std::vector<std::string>{"bug-prover.md"}, {}, {}))[0].starts_with("Gate 2")
&& LensesOf(Plan::GatesFor("reply", {}, std::vector<std::string>{"conciseness.md"}, {})[0]) == std::vector<std::string>{"facts.md", "etiquette.md", "consistency.md"}
&& Plan::GatesFor("reply", std::vector<std::string>{"facts.md"}, std::vector<std::string>{"facts.md"}, {}).empty()
&& Plan::GatesFor("commits", std::vector<std::string>{"facts.md"}, {}, {}).empty() && Plan::GatesFor().size() == Plan::Gates("commits").size());
Check("mode lenses: the kernel modes have the persona lens, commits does not; effort max for the kernel modes, xhigh for commits; reads 1 for a reply, 3 otherwise",
std::ranges::contains(Plan::KindLenses("series"), std::string(Plan::PersonaLens)) && std::ranges::contains(Plan::KindLenses("reply"), std::string(Plan::PersonaLens))
&& !std::ranges::contains(Plan::KindLenses("commits"), std::string(Plan::PersonaLens)) && Plan::DefaultEffort("reply") == "max" && Plan::DefaultEffort("series") == "max"
&& Plan::DefaultEffort("commits") == "xhigh" && Plan::DefaultEffort() == "xhigh" && Plan::ReadsFor("reply") == 1 && Plan::ReadsFor("series") == 3 && Plan::ReadsFor("commits") == 3);
auto budget = [](std::string_view kind, std::string_view unitKind, std::string_view lens) {
const Plan::Budget b = Plan::BudgetFor(kind, unitKind, lens);
return std::pair(b.maxTurns, b.timeoutMin);
};
Check("budgets: facts text 80/50, other text 50/30, slot 50/35, whole 180/105",
budget("block", "text", "facts.md") == std::pair(80, 50) && budget("block", "text", "etiquette.md") == std::pair(50, 30) && budget("slot", "slot", "facts.md") == std::pair(50, 35)
&& budget("whole", "", "consistency.md") == std::pair(180, 105) && budget("block", "text", Plan::FactsLens) == std::pair(60, 40));
// ---- plans ----------------------------------------------------------------------
const Plan::LensPlan facts = Plan::PlanLens("facts.md", draftUnits, draft.lines);
const std::map<std::string, std::int64_t> factsKinds = Kinds(facts.blocks);
Check("facts on the draft: no whole pass; a block per unit - 3 slot passes, 3 bare headers mechanical n/a, the rest blocks",
facts.whole.is_null() && factsKinds.at("slot") == 3 && factsKinds.at("auto-na") == 3 && facts.blocks.size() == draftUnits.size() && Units(facts.blocks, "auto-na") == std::set<std::string>{"camss:header", "ov13b10:header", "x:header"},
DumpCompact(Json(factsKinds)));
const Plan::LensPlan consistency = Plan::PlanLens("consistency.md", draftUnits, draft.lines);
std::vector<std::string> wholeSlots;
for (const Json& id : consistency.whole.at("expectedIds")) wholeSlots.push_back(Dyn::Str(id));
Check("consistency: a whole pass over every whole:* slot, blocks that exclude the slots, no persona key on a plain job",
wholeSlots == std::vector<std::string>{"whole:route", "whole:asks", "whole:absent"} && !Units(consistency.blocks, "slot").size() && !Dyn::Has(consistency.whole, "persona"));
const Plan::LensPlan persona = Plan::PlanLens(Plan::PersonaLens, draftUnits, draft.lines, {}, {}, "Thomas Colliers", std::vector<std::string>{"R1"});
Check("persona: the instance is persona:<name>, its jobs carry the persona after the lens file, the whole pass on the fable tier, no block for an excluded unit",
Dyn::Str(persona.whole.at("lens")) == "persona:Thomas Colliers" && Dyn::Str(persona.whole.at("persona")) == "Thomas Colliers" && !Units(persona.blocks).contains("R1")
&& Units(persona.blocks).contains("R2") && Dyn::Str(persona.whole.at("model")) == Plan::ModelFor("fable") && Dyn::Str(persona.whole.at("label")) == "persona:Thomas Colliers:whole"
&& std::ranges::all_of(persona.blocks, [](const Json& j) { return j.at("persona") == "Thomas Colliers"; }),
DumpCompact(persona.whole));
Check("the same keys in the same order as a plain job, the persona after lensFile",
[&] {
std::vector<std::string> keys;
for (auto it = persona.whole.begin(); it != persona.whole.end(); ++it) keys.push_back(it.key());
return keys == std::vector<std::string>{"label", "lens", "lensFile", "persona", "kind", "unit", "expectedIds", "model", "maxTurns", "timeoutMin"};
}());
// ---- text reuse keys ------------------------------------------------------------
const Refs::Table refs = Refs::ParseRefs(Dyn::ReadText(fix / "draft-camera.txt"));
Check("refs: the draft's two numbered references", refs.size() == 2 && refs[0].first == "1" && refs[0].second.starts_with("https://lore.kernel.org/r/") && refs[1].first == "2");
const std::string r2 = Plan::UnitText(draft.lines, Unit(draftUnits, "R2"));
const std::string anchor = Plan::UnitText(draft.lines, Unit(draftUnits, "anchor"));
const Json job = {{"kind", "block"}, {"unit", "R2"}};
const std::vector<std::string> deps = Plan::TextDeps(r2, draftUnits, draft.lines, refs, anchor);
Check("text deps of R2: the [2] it cites, the anchor (a dated unit), the R1 it names - and itself, as a reversal names its own number",
deps.size() == 4 && deps[0].starts_with("ref[2]=https://lore.kernel.org/all/") && deps[1] == std::format("anchor={}", Plan::Sha(anchor)) && deps[2].starts_with("unit[R1]=")
&& deps[3] == std::format("unit[R2]={}", Plan::Sha(r2)),
Show(deps));
const std::optional<std::string> k1 = Plan::ReuseKey(job, "facts.md", r2, deps, {"w1"}, "cs", 1);
Refs::Table refs2 = refs;
refs2[1].second = "https://lore.kernel.org/all/changed@example/";
const std::string undated = "A sentence with no date, version, state word or citation at all.";
const Json jd = {{"kind", "block"}, {"unit", "R9"}};
Check("same unit, same deps -> same key; a cited URL, the anchor of a dated unit, or the dispositions in force change it; the anchor leaves an undated unit's key alone",
k1 == Plan::ReuseKey(job, "facts.md", r2, Plan::TextDeps(r2, draftUnits, draft.lines, refs, anchor), {"w1"}, "cs", 1)
&& k1 != Plan::ReuseKey(job, "facts.md", r2, Plan::TextDeps(r2, draftUnits, draft.lines, refs2, anchor), {"w1"}, "cs", 1)
&& k1 != Plan::ReuseKey(job, "facts.md", r2, Plan::TextDeps(r2, draftUnits, draft.lines, refs, std::format("{}x", anchor)), {"w1"}, "cs", 1)
&& Plan::ReuseKey(jd, "facts.md", undated, Plan::TextDeps(undated, draftUnits, draft.lines, refs, anchor), {"w1"}, "cs", 1)
== Plan::ReuseKey(jd, "facts.md", undated, Plan::TextDeps(undated, draftUnits, draft.lines, refs, std::format("{}x", anchor)), {"w1"}, "cs", 1)
&& k1 != Plan::ReuseKey(job, "facts.md", r2, deps, {"w1", "w2"}, "cs", 1));
std::vector<std::string> sortedDeps = deps;
std::ranges::sort(sortedDeps);
Check("the key is the formula it always was: lens | unit | its text | its deps | the dispositions | the charter | the prompt version | the model | effort slot max",
k1 == Plan::Sha(Dyn::Join(std::vector<std::string>{"facts.md", "R2", Plan::Sha(r2), Plan::Sha(Dyn::Join(sortedDeps, "\n")), "w1", "cs", "1", "", "max"}, "|")).substr(0, 16)
&& Plan::ReuseKeyEffortSlot == "max");
const Json px = {{"kind", "block"}, {"unit", "R2"}, {"persona", "X"}};
const Json py = {{"kind", "block"}, {"unit", "R2"}, {"persona", "Y"}};
const std::optional<std::string> kp = Plan::ReuseKey(px, Plan::PersonaLens, r2, {}, {}, "c", 1);
Check("a persona block has a key of its own per persona; a persona whole pass, a consistency block and a slot never get one",
kp && kp != Plan::ReuseKey(py, Plan::PersonaLens, r2, {}, {}, "c", 1) && kp == Plan::ReuseKey(px, Plan::PersonaLens, r2, {}, {}, "c", 1)
&& !Plan::ReuseKey({{"kind", "whole"}, {"unit", nullptr}, {"persona", "X"}}, Plan::PersonaLens, r2, {}, {}, "c", 1) && !Plan::ReuseKey(job, "consistency.md", r2, {}, {}, "c", 1)
&& !Plan::ReuseKey({{"kind", "slot"}, {"unit", "whole:route"}}, "facts.md", r2, {}, {}, "c", 1));
// ---- series code keys (the push gates' rule, on the commits fixture) ------------
const fs::path src = checkout / "tests" / "Goldens" / "fixture" / "commits";
const std::vector<std::string> names = Artifact::PatchFiles(src);
std::map<std::string, std::string> orig;
for (const std::string& f : names) orig[f] = Dyn::ReadText(src / f);
auto variant = [&](std::string_view name, const std::function<std::string(std::int64_t, const std::string&)>& edit, std::string_view prefix = {}) {
const fs::path d = base / name;
fs::create_directories(d);
for (std::size_t i = 0; i < names.size(); ++i) Write(d / std::format("{}{}", prefix, names[i]), edit(static_cast<std::int64_t>(i) + 1, orig[names[i]]));
return d;
};
auto skeys = [&](const fs::path& d, std::string_view lens = "bug-prover.md", std::string_view who = {}) {
const Inventory::Built inv = Inventory::Build("series", d.string());
const Plan::CommitCode cc = Plan::CommitCodeOf(Artifact::PatchTexts(d), true);
std::map<std::string, std::string> out;
for (const Json& u : inv.out.at("units")) {
if (Plan::KindFor(lens, u) != "code") continue;
Json j = {{"kind", "block"}, {"unit", u.at("id")}, {"unitKind", "code"}};
if (!who.empty()) j["persona"] = who;
out[Dyn::Str(u.at("id"))] = Plan::CodeReuseKey(j, lens, Plan::UnitText(inv.lines, u), cc, {}, "c", 1).value_or("");
}
return out;
};
const std::map<std::string, std::string> s0 = skeys(src);
auto changed = [&](const std::map<std::string, std::string>& k) {
std::set<std::string> out;
for (const auto& [id, key] : s0) {
if (k.at(id) != key) out.insert(id);
}
return out;
};
Check("series: every code unit of a code lens has a key - the README hunk too (documentation is code to the kernel lenses) and the two slots",
std::ranges::all_of(s0, [](const auto& e) { return !e.second.empty(); }) && s0.contains("p2:README.md#1") && s0.contains("p2:absent") && s0.contains("p1:outside"));
auto sub = [](std::string t, std::string_view a, std::string_view b) { return Dyn::Replace(t, a, b); };
const std::map<std::string, std::string> reword = skeys(variant("reword", [&](std::int64_t n, const std::string& t) {
return n == 2 ? sub(sub(sub(t, "The greeting takes a name now", "greet() takes a name now"), "From 2222", "From 3333"), "[PATCH 2/2]", "[PATCH v2 2/2]") : t;
}));
const std::set<std::string> rewordChanged = changed(reword);
Check("series: a reworded message, a new commit id and a re-roll counter -> no hunk and no `outside` asked again; that patch's `absent` is (it looks into the message)",
rewordChanged == std::set<std::string>{"p2:absent"}, Show({rewordChanged.begin(), rewordChanged.end()}));
Check("series: a re-roll that changes only the [PATCH vN n/m] counter and the commit ids asks nothing again",
skeys(variant("counter", [&](std::int64_t, const std::string& t) { return sub(sub(sub(t, "[PATCH 2/2]", "[PATCH v2 2/2]"), "[PATCH 1/2]", "[PATCH v2 1/2]"), "From 2222", "From 3333"); })) == s0);
const std::map<std::string, std::string> code = skeys(variant("code", [&](std::int64_t n, const std::string& t) { return n == 2 ? sub(t, "+ return \"hello \" + name", "+ return \"hi \" + name") : t; }));
const std::set<std::string> codeChanged = changed(code);
Check("series: one changed line -> its hunk and the four slots", codeChanged == std::set<std::string>{"p2:hello.py#1", "p1:outside", "p1:absent", "p2:outside", "p2:absent"},
Show({codeChanged.begin(), codeChanged.end()}));
Check("series: the three code lenses and each persona have keys of their own; better-solution's blocks too; consistency's never",
std::set<std::string>{skeys(src, "bug-prover.md").at("p2:hello.py#1"), skeys(src, "code-quality.md").at("p2:hello.py#1"), skeys(src, "minimalism.md").at("p2:hello.py#1"),
skeys(src, Plan::PersonaLens, "A B").at("p2:hello.py#1"), skeys(src, Plan::PersonaLens, "C D").at("p2:hello.py#1")}
.size() == 5
&& skeys(src, Plan::PersonaLens, "A B") == skeys(src, Plan::PersonaLens, "A B") && !skeys(src, "better-solution.md").at("p2:hello.py#1").empty()
&& skeys(src, "better-solution.md").at("p2:hello.py#1") != s0.at("p2:hello.py#1") && skeys(src, "consistency.md").at("p2:hello.py#1").empty());
const Plan::CommitCode cmt = Plan::CommitCodeOf(Artifact::PatchTexts(src));
const Plan::CommitCode ker = Plan::CommitCodeOf(Artifact::PatchTexts(src), true);
Check("series: nothing is documentation (a .md hunk is part of its patch's code); the message is kept for `absent`; the push gates' code moves not",
ker.docs.at(1).empty() && ker.docs.at(2).empty() && ker.code.at(2) != cmt.code.at(2) && ker.kernel && !cmt.kernel && ker.message.at(2) != ker.message.at(1) && !cmt.docs.at(2).empty());
const fs::path reroll = variant("reroll", [](std::int64_t, const std::string& t) { return t; }, "v3-");
Check("a re-rolled series (v3-0002-...) is numbered like 0002-...: the partition and the patch texts",
Artifact::PatchTexts(reroll).size() == 2 && Artifact::PatchTexts(reroll).contains(2) && Ids(Inventory::Build("series", reroll.string()).out.at("units")) == Ids(Inventory::Build("series", src.string()).out.at("units")));
const Inventory::Built sinv = Inventory::Build("series", src.string());
const std::string tm = Plan::UnitText(sinv.lines, Unit(sinv.out.at("units"), "p2:msg"));
const Json jm = {{"kind", "block"}, {"unit", "p2:msg"}, {"unitKind", "text"}};
std::vector<std::string> tdeps = Plan::TextDeps(tm, sinv.out.at("units"), sinv.lines, {}, "");
std::ranges::sort(tdeps);
Check("series: a text unit keeps the key it always had, and a persona reading it has its own",
Plan::ReuseKey(jm, "facts.md", tm, Plan::TextDeps(tm, sinv.out.at("units"), sinv.lines, {}, ""), {}, "c", 1)
== Plan::Sha(Dyn::Join(std::vector<std::string>{"facts.md", "p2:msg", Plan::Sha(tm), Plan::Sha(Dyn::Join(tdeps, "\n")), "", "c", "1", "", "max"}, "|")).substr(0, 16)
&& Plan::ReuseKey({{"kind", "block"}, {"unit", "p2:msg"}, {"unitKind", "text"}, {"persona", "A B"}}, Plan::PersonaLens, tm, Plan::TextDeps(tm, sinv.out.at("units"), sinv.lines, {}, ""), {}, "c", 1)
!= Plan::ReuseKey(jm, "facts.md", tm, Plan::TextDeps(tm, sinv.out.at("units"), sinv.lines, {}, ""), {}, "c", 1));
// ---- dispositions --------------------------------------------------------------
{
const fs::path td = base / "disp";
Write(td / "0001-a.patch", "x\nANCHOR TEXT\ny\nANCHOR TEXT\n");
const std::vector<Json> e = {{{"id", "a"}, {"hash", "H1"}},
{{"id", "b"}, {"hash", "H0"}, {"carry", true}, {"anchors", {{{"file", "0001-a.patch"}, {"text", "ANCHOR TEXT"}, {"count", 2}}}}},
{{"id", "c"}, {"hash", "H0"}, {"carry", true}, {"anchors", {{{"file", "0001-a.patch"}, {"text", "ANCHOR TEXT"}, {"count", 1}}}}},
{{"id", "d"}, {"hash", "H0"}}};
auto statuses = [](const std::vector<Json>& rows) {
std::map<std::string, std::string> out;
for (const Json& r : rows) out[Dyn::Str(r.at("id"))] = Dyn::Str(r.at("status"));
return out;
};
const std::vector<Json> seriesRows = Dispositions::Classify(e, "H1", td, "series");
Check("series: hash match in-force, count match carried, count mismatch lapsed, no carry lapsed; a reply never carries",
statuses(seriesRows) == std::map<std::string, std::string>{{"a", "in-force"}, {"b", "carried"}, {"c", "lapsed"}, {"d", "lapsed"}}
&& statuses(Dispositions::Classify(e, "H1", td, "reply")) == std::map<std::string, std::string>{{"a", "in-force"}, {"b", "lapsed"}, {"c", "lapsed"}, {"d", "lapsed"}}
&& Dyn::Str(Dispositions::Classify(e, "H1", td, "reply")[1].at("detail")).contains("no carry in reply mode"));
const std::vector<Json> inf = Dispositions::InForce(e, seriesRows);
const std::string blk = Dispositions::Block(inf, seriesRows, "facts.md", "H1", "camera");
Check("a kernel lens's block: the ledger sentence, the carried entry, lore in the rules, the owner as Gate 5, no disposition-review duty",
blk.contains("journal/camera/ledger.md for your lens that is NOT listed here is LAPSED") && blk.contains("CARRIED to this hash") && blk.contains("- a [") && blk.contains("lore via utilities/lore.py")
&& blk.contains("Gate 5 must see it") && blk.contains("do NOT emit disposition-review notes"),
blk);
const std::string repoBlk = Dispositions::Block(inf, seriesRows, Plan::FactsLens, "H1");
Check("a repo lens's block is as it was: no journal line, no lore, the owner as Gate 4", repoBlk.contains("Nothing outside this list") && !repoBlk.contains("lore") && repoBlk.contains("Gate 4 must see it"));
const std::vector<Json> e2 = {{{"id", "r"}, {"hash", "H1"}, {"kind", "refuted"}, {"lenses", {"etiquette.md"}}}};
const std::vector<Json> rows2 = {{{"id", "r"}, {"status", "in-force"}}};
const std::string personaBlk = Dispositions::Block(e2, rows2, Plan::PersonaLens, "H1", "camera");
Check("a refuted entry is hidden from other lenses, shown to its own and to a persona, whose rules ask for a disposition-review note per entry",
Dispositions::Block(e2, rows2, "facts.md", "H1", "camera").contains("(none)") && Dispositions::Block(e2, rows2, "etiquette.md", "H1", "camera").contains("- r [")
&& personaBlk.contains("- r [") && personaBlk.contains("kind=disposition-review") && personaBlk.contains("wouldComment"));
}
// ---- prompts --------------------------------------------------------------------
const std::string st = Prompt::SystemText("commits");
const std::string stk = Prompt::SystemText("series");
Check("system text: the kernel variant (a patch series, lore.py, the milos clone); the reply variant; the repo variant without them",
stk.contains("patch series") && stk.contains("lore.py") && stk.contains("milos") && Prompt::SystemText("reply").contains("mailing-list reply") && st.contains("commit range") && !st.contains("lore.py")
&& Prompt::SystemText() == st);
const std::string h = Dyn::Str(series.out.at("hash8"));
const std::vector<std::string> trees = {"work/linux", "work/milos-linux"};
const std::vector<std::string> reviewers = {"A B", "C D"};
const std::string rl = Prompt::RunLayerKernel("series", "journal/x/patch/y/v1", "camera", "work/linux @ abc", reviewers, "2026-10-31", trees, h, series.lines, series.out.at("units"),
"REFERENCES prefetched: (none - the artifact cites no lore URLs)");
Check("run layer (series): the artifact, the ledger, the thread mboxes, the captures, the base, the trees, the archaeology and lore rules, the reviewers, the date; the inventory names the partition tool; the digest last",
rl.contains(std::format("- The frozen artifact (review THIS, at hash {}): the *.patch files in journal/x/patch/y/v1 - inlined below in sorted order; nothing else in that dir is an input", h))
&& rl.contains("- Ledger: journal/camera/ledger.md (the only mutable journal file you may read)") && rl.contains("- Thread mboxes: journal/camera/captures/threads/")
&& rl.contains("- Evidence/proof artifacts: journal/camera/captures/ (index in the ledger)") && rl.contains("- Target tree at the submission base: work/linux @ abc")
&& rl.contains("- Trees: work/linux, work/milos-linux") && rl.contains("- History archaeology ONLY in work/milos-linux") && rl.contains("- lore.kernel.org ONLY via utilities/lore.py")
&& rl.contains("- Reviewers with a persona in this run: A B, C D") && rl.contains("- Run date: 2026-10-31") && rl.contains("(utilities/inventory.py: every non-blank line")
&& rl.ends_with("REFERENCES prefetched: (none - the artifact cites no lore URLs)") && rl.contains("\n0001| From 3333"),
Dyn::Slice(rl, 0, 1200));
const std::string rlr = Prompt::RunLayerKernel("reply", "journal/x/draft.txt", "camera", "", {}, "2026-10-31", trees, "H", draft.lines, draftUnits, "R");
Check("run layer (reply): the draft file, the base from the artifact, no reviewers line",
rlr.contains("the reply draft file journal/x/draft.txt - inlined below; nothing else is an input") && rlr.contains("- Target tree at the submission base: see the artifact") && !rlr.contains("Reviewers with a persona"));
const std::string rlc = Prompt::RunLayer("journal/ims/push/x", "abc123", "2026-09-25", std::vector<std::string>{"work/prepush-trees/imsd-1234"}, h, series.lines, series.out.at("units"), {}, "imsd", "ims");
const std::string rlcInputs = rlc.substr(0, rlc.find("\n\nARTIFACT (frozen"));
Check("run layer (commits, a subsystem): the ledger and captures lines in INPUTS, nothing of lore or milos there",
rlcInputs.contains("- Ledger: journal/ims/ledger.md") && rlcInputs.contains("- Evidence/proof artifacts: journal/ims/captures/") && !rlcInputs.contains("lore") && !rlcInputs.contains("milos")
&& !Prompt::RunLayer("x", "", "d", std::vector<std::string>{"."}, h, series.lines, series.out.at("units")).substr(0, 400).contains("journal/"));
const Plan::LensPlan bs = Plan::PlanLens("better-solution.md", series.out.at("units"), series.lines);
const Plan::LensPlan bp = Plan::PlanLens("bug-prover.md", series.out.at("units"), series.lines);
const Plan::LensPlan et = Plan::PlanLens("etiquette.md", draftUnits, draft.lines);
auto jobOf = [](const std::vector<Json>& jobs, std::string_view unit) -> const Json& {
for (const Json& j : jobs) {
if (j.at("unit") == unit) return j;
}
throw std::runtime_error(std::format("no job {}", unit));
};
const std::string tailWholeFirst = Prompt::Tail(bs.whole, series.out.at("units"), series.lines);
const std::string tailWholeAll = Prompt::Tail(consistency.whole, draftUnits, draft.lines);
const std::string tailPersona = Prompt::Tail(persona.whole, draftUnits, draft.lines);
Check("whole tails: the approach (first), the consistency whole (all) and the persona whole, each listing the slots, with the kernel vocabulary - the persona's its own",
tailWholeFirst.contains("judge the artifact as an APPROACH") && tailWholeFirst.contains("- whole:cover-vs-patches [0-0]") && tailWholeFirst.contains("Coverage vocabulary for this lens: clear")
&& tailWholeAll.contains("WHOLE PASS of the consistency lens") && tailWholeAll.contains("whole:route") && tailPersona.contains("predictedReview") && tailPersona.contains("`notMine`")
&& tailPersona.contains("Coverage vocabulary for a maintainer or reviewer: would-require") && !tailPersona.contains("Coverage vocabulary for this lens"));
Check("block tails: the anchor and refs hints, the kernel outside/absent hints, the text hint, the one scope phrase for every unit kind",
Prompt::Tail(jobOf(facts.blocks, "anchor"), draftUnits, draft.lines).contains("fixes the as-of date") && Prompt::Tail(jobOf(facts.blocks, "refs"), draftUnits, draft.lines).contains("numbering is contiguous")
&& Prompt::Tail(jobOf(bp.blocks, "p1:outside"), series.out.at("units"), series.lines).contains("at the submission base, outside its own diff")
&& Prompt::Tail(jobOf(bp.blocks, "p1:absent"), series.out.at("units"), series.lines).contains("a trailer, a test statement, a Cc")
&& Prompt::Tail(jobOf(facts.blocks, "R2"), draftUnits, draft.lines).contains("prefetched raw files") && !Prompt::Tail(jobOf(facts.blocks, "R2"), draftUnits, draft.lines).contains("INPUTS names")
&& Prompt::Tail(jobOf(facts.blocks, "R2"), draftUnits, draft.lines).contains("a claim at its source, a sentence against its proof obligation, a hunk against the standard")
&& Prompt::Tail(jobOf(bp.blocks, "p1:drivers/nfc/widget.c#1"), series.out.at("units"), series.lines).contains("a claim at its source, a sentence against its proof obligation, a hunk against the standard"));
Check("slot tails: each lens's duty on its slot",
Prompt::Tail(jobOf(et.blocks, "whole:asks"), draftUnits, draft.lines).contains("Step 0 and the point map") && Prompt::Tail(jobOf(facts.blocks, "whole:route"), draftUnits, draft.lines).contains("claims that span units")
&& Prompt::Tail(jobOf(Plan::PlanLens("minimalism.md", series.out.at("units"), series.lines).blocks, "whole:absent"), series.out.at("units"), series.lines).contains("series-level minimalism")
&& Prompt::Tail(jobOf(Plan::PlanLens("conciseness.md", draftUnits, draft.lines).blocks, "whole:absent"), draftUnits, draft.lines).contains("growth calibration")
&& Prompt::SlotDuty("process-docs.md", "whole:asks").contains("get_maintainer") && Prompt::SlotDuty("process-docs.md", "whole:absent").empty()
&& !Prompt::Tail(jobOf(facts.blocks, "whole:asks"), draftUnits, draft.lines).contains("for this lens that"));
const std::string ll = Prompt::LensLayer("facts.md", "CHARTER TEXT", "DISPOSITIONS BLOCK");
const std::string llp = Prompt::LensLayer(Plan::PersonaLens, "CHARTER TEXT", "DISPOSITIONS BLOCK", {}, "the digest", {}, "Thomas Colliers", "lore.py search ...\nlisting");
Check("lens layer: a persona's layer opens with who they are and the calibration map, then the charter, the dispositions and the whole pass's digest; a plain one with the charter",
llp.starts_with("Your persona: Thomas Colliers. You ARE this person") && llp.contains("\n\nCALIBRATION MAP - a lore search listing of this person's recent mail (fetch the bodies you need):\nlore.py search ...\nlisting\n\nYOUR CHARTER (process/lenses/maintainer-persona.md), verbatim:\n\nCHARTER TEXT\n\nDISPOSITIONS BLOCK\n\nThe whole pass of this lens on this hash concluded")
&& ll.starts_with("YOUR CHARTER (process/lenses/facts.md), verbatim:\n\nCHARTER TEXT\n\nDISPOSITIONS BLOCK") && Prompt::LensLayer("facts.md", "C", "D", {}, {}, {}, "P", {}).contains("Your persona: P.")
&& !Prompt::LensLayer("facts.md", "C", "D", {}, {}, {}, "P", {}).contains("CALIBRATION MAP"));
const std::string up = Prompt::UserPrompt("TAIL", Json({{"maxTurns", 60}}), {}, true);
Check("user prompt: the kernel budget line says to read the prefetched raw files; the push gates' does not",
up.contains("Tool-call budget for this pass: 60") && up.contains("Batch independent reads into one call, read the prefetched raw files instead of fetching, and return the structured output")
&& Prompt::UserPrompt("TAIL", Json({{"maxTurns", 60}})).contains("Batch independent reads into one call and return the structured output"));
// ---- the schema -----------------------------------------------------------------
const std::string wholeK = Schema::SchemaJson("whole", "series");
Check("the kernel schema: the persona vocabulary, the kernel note kinds, wouldComment, predictedReview and notMine; the push gates' schema as it was",
wholeK.contains("\"would-require\"") && wholeK.contains("\"ledger-row\"") && wholeK.contains("\"disposition-review\"") && wholeK.contains("\"wouldComment\"") && wholeK.contains("\"predictedReview\"")
&& wholeK.contains("\"notMine\"") && wholeK.contains("objective wrongness, or a predicted reviewer comment") && Schema::SchemaJson("block", "reply").contains("\"not-mine\"")
&& !Schema::SchemaJson("block", "commits").contains("would-require") && Schema::SchemaJson("block") == Schema::SchemaJson("block", "commits") && !Schema::SchemaJson("whole").contains("notMine"));
// ---- normalize and the matrix ----------------------------------------------------
{
const Json inv = Json::array({{{"id", "R1"}}, {{"id", "R2"}}, {{"id", "whole:route"}}});
const std::vector<std::string> ids = {"R1", "R2", "whole:route"};
Json v = {{"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", {{{"item", "R1"}, {"verdict", "would-object"}, {"basis", "x"}}}}};
const Json n = Normalize::NormalizeOutput(v, {}, std::string(Plan::PersonaLens), "h", Json::array({inv[0]}), ids);
Json v2 = {{"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", {{{"item", "R1"}, {"verdict", "no-comment"}, {"basis", "no record"}}}}, {"predictedReview", "r"}, {"notMine", {"R2"}}};
const Json n2 = Normalize::NormalizeOutput(v2, {}, std::string(Plan::PersonaLens), "h", Json::array({inv[0]}), ids);
Json v3 = {{"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", {{{"item", "R1"}, {"verdict", "defect"}, {"basis", "x"}}}}};
const Json n3 = Normalize::NormalizeOutput(v3, {}, std::string(Plan::PersonaLens), "h", Json::array({inv[0]}), ids);
Json v4 = {{"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()}, {"coverage", {{{"item", "R1"}, {"verdict", "would-object"}, {"basis", "x"}}}}};
const Json n4 = Normalize::NormalizeOutput(v4, {}, "facts.md", "h", Json::array({inv[0]}), ids);
Check("a persona's would-object without a finding is synthesized (fail closed), its no-comment accepted, a generic verdict logged as outside its vocabulary; the persona's review and not-mine list come through",
n.at("verdict") == "FIX FIRST" && Dyn::Truthy(n.at("findings")[0].at("synthesized")) && n2.at("verdict") == "SEND-READY" && !Dyn::Truthy(n2.at("normalizeLogs")) && n2.at("predictedReview") == "r"
&& n2.at("notMine") == Json({"R2"}) && Dyn::Str(n3.at("normalizeLogs")[0]).contains("not in the vocabulary (would-require/no-comment/") && n3.at("verdict") == "FIX FIRST"
&& !Dyn::Has(n4, "predictedReview") && Dyn::Str(n4.at("normalizeLogs")[0]).contains("(clear/defect/immaterial/n/a)"),
DumpCompact(n3.at("normalizeLogs")));
const Json pa = {{"partLabel", "persona:X:block:R1"}, {"partKind", "block"}, {"partUnit", "R1"}, {"verdict", "FIX FIRST"},
{"findings", {{{"finding", "R2 contradicts R1"}, {"evidence", "e"}, {"proposedAction", "p"}, {"items", {"R1", "R2"}}, {"discharged", false}}}},
{"notes", Json::array()}, {"coverage", {{{"item", "R1"}, {"verdict", "would-object"}, {"basis", "b"}}}}, {"coverageMissing", Json::array()}, {"undischarged", 1}};
const Json pb = {{"partLabel", "persona:X:block:R2"}, {"partKind", "block"}, {"partUnit", "R2"}, {"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()},
{"coverage", {{{"item", "R2"}, {"verdict", "no-comment"}, {"basis", "m1@x"}}}}, {"coverageMissing", Json::array()}};
const Json m = Normalize::MergeParts("persona:X", std::string(Plan::PersonaLens), std::vector<Json>{pa, pb}, {});
std::map<std::string, std::string> cov;
for (const Json& c : m.at("coverage")) cov[Dyn::Str(c.at("item"))] = Dyn::Str(c.at("verdict"));
Check("merge: a unit a persona's undischarged finding cites is raised to would-object, not defect", cov.at("R2") == "would-object" && Dyn::Str(m.at("normalizeLogs")[0]).contains("raised to would-object"), DumpCompact(m.at("coverage")));
const Json pw = {{"partLabel", "persona:X:whole"}, {"partKind", "whole"}, {"partUnit", nullptr}, {"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()},
{"coverage", {{{"item", "whole:route"}, {"verdict", "no-comment"}, {"basis", "w"}}}}, {"coverageMissing", Json::array()}};
const Json pbk = {{"partLabel", "persona:X:block:R1"}, {"partKind", "block"}, {"partUnit", "R1"}, {"verdict", "SEND-READY"}, {"findings", Json::array()}, {"notes", Json::array()},
{"coverage", {{{"item", "R1"}, {"verdict", "immaterial"}, {"basis", "w"}}}}, {"coverageMissing", Json::array()}};
Json pbk2 = pbk;
pbk2["coverage"] = {{{"item", "R1"}, {"verdict", "no-comment"}, {"basis", "later"}}};
const Json m4 = Normalize::MergeParts("persona:X", std::string(Plan::PersonaLens), std::vector<Json>{pw, pbk, pbk2}, {});
std::map<std::string, std::string> cov4;
for (const Json& c : m4.at("coverage")) cov4[Dyn::Str(c.at("item"))] = Dyn::Str(c.at("verdict"));
const Json mx = Normalize::Matrix(inv, std::vector<Json>{m4});
Json fy = m4;
fy["lens"] = "persona:Y";
fy["coverage"] = {{{"item", "R1"}, {"verdict", "no-comment"}, {"basis", " No Record "}}, {{"item", "R2"}, {"verdict", "not-mine"}, {"basis", "no record"}}};
const Json mx2 = Normalize::Matrix(inv, std::vector<Json>{m4, fy});
Check("the strongest verdict per unit wins (immaterial > no-comment); the matrix: a unit without an entry is MISSING, a hole and a persona hole; a not-mine is unowned too; thin where one persona owns it; modelled where every persona rests on \"no record\"",
cov4.at("R1") == "immaterial" && mx.at("matrix").at("R2").at("persona:X").at("verdict") == "MISSING" && mx.at("holes") == Json({"R2"}) && mx.at("personaHoles") == Json({"R2"})
&& mx.at("thin") == Json({"R1", "whole:route"}) && mx.at("modelled") == Json::array() && mx2.at("thin") == Json({"whole:route"}) && mx2.at("modelled") == Json::array()
&& mx2.at("personaHoles") == Json({"R2"}) && mx2.at("holes") == Json({"R2"}) && Dyn::Has(mx2, "notReviewed"),
DumpCompact(mx2));
Json gy = fy;
gy["coverage"] = {{{"item", "R1"}, {"verdict", "no-comment"}, {"basis", "no record"}}, {{"item", "R2"}, {"verdict", "no-comment"}, {"basis", "NO RECORD"}}, {{"item", "whole:route"}, {"verdict", "no-comment"}, {"basis", "m"}}};
const Json mx3 = Normalize::Matrix(inv, std::vector<Json>{gy});
Check("...modelled: every persona entry of the unit says no record, whatever the case or spacing", mx3.at("modelled") == Json({"R1", "R2"}) && mx3.at("thin") == Json({"R1", "R2", "whole:route"}));
const Json keys = Normalize::Matrix(inv, std::vector<Json>{});
std::vector<std::string> order;
for (auto it = keys.begin(); it != keys.end(); ++it) order.push_back(it.key());
Check("the matrix's keys, in order", order == std::vector<std::string>{"units", "lenses", "holes", "personaHoles", "thin", "modelled", "notReviewed", "defects", "matrix"}, Show(order));
}
// ---- references ---------------------------------------------------------------------
{
const Refs::Table lore = Refs::ParseRefs("see https://lore.kernel.org/all/a@b/ and <https://lore.kernel.org/linux-arm-msm/c@d> again https://lore.kernel.org/all/a@b/ http://lore.kernel.org/r/e@f");
Check("refs: without a numbered list every lore URL once, in order, L1..; the message id of each spelling; a trailing slash kept in the whole match",
lore.size() == 3 && lore[0].first == "L1" && lore[0].second == "https://lore.kernel.org/all/a@b/" && lore[1].second == "https://lore.kernel.org/linux-arm-msm/c@d" && lore[2].first == "L3"
&& lore[2].second == "http://lore.kernel.org/r/e@f" && Refs::MsgidOf("https://lore.kernel.org/r/7927bdab@kernel.org/") == "7927bdab@kernel.org"
&& Refs::MsgidOf("https://lore.kernel.org/all/x@y") == "x@y" && !Refs::MsgidOf("https://example.org/all/x@y/") && Refs::UrlOf(refs, 2) == refs[1].second && !Refs::UrlOf(refs, 3),
DumpCompact(Json(lore)));
Check("refs: a numbered list wins over lore URLs in the body, the last line of a number wins, a non-URL token is the reference as given",
Refs::ParseRefs("[1] https://a/\nhttps://lore.kernel.org/all/z@z/\n[2] foo\n[1] https://b/").size() == 2 && Refs::ParseRefs("[1] https://a/\n[1] https://b/")[0].second == "https://b/"
&& Refs::ParseRefs("[2] foo")[0].second == "foo" && Refs::ParseRefs("[2]foo").empty());
Check("safe names and headers", Refs::SafeName("a/b c@d.e-f_g") == "a_b_c@d.e-f_g" && Refs::SafeName(std::string(300, 'x')).size() == 200
&& Refs::Headers("From: A <a@x>\nSubject: s\nFrom: B\nDate: d\n\nbody From: C") == std::map<std::string, std::string>{{"From", "A <a@x>"}, {"Subject", "s"}, {"Date", "d"}});
const fs::path refsDir = base / "refs";
std::vector<std::string> calls;
std::mutex callsLock;
Refs::SetFetcher([&](const fs::path&, const std::string& url, const fs::path& path) -> std::pair<std::string, std::string> {
{
// The fetchers run on the prefetch's worker threads.
const std::lock_guard guard(callsLock);
calls.push_back(url);
}
if (url.contains("fail")) return {"failed", "no such message"};
Write(path, "From: Mark <m@x>\nDate: Mon\nSubject: Re: the thing\n\nbody\n");
return {"fetched", ""};
});
std::vector<std::string> logs;
const Refs::Table table = {{"1", "https://lore.kernel.org/all/one@x/"}, {"2", "https://lore.kernel.org/all/fail@x/"}, {"3", "https://example.org/not-lore"}};
const Json index = Refs::Prefetch(base, table, refsDir, base / "refs-h8.json", [&](const std::string& l) { logs.push_back(l); }, 2);
Check("prefetch: a lore reference fetched and its headers read, a failure listed with its error, a non-lore URL not prefetched; the index written; the log",
index.at("1").at("status") == "fetched" && index.at("1").at("From") == "Mark <m@x>" && index.at("1").at("Subject") == "Re: the thing" && index.at("1").at("bytes") == 56
&& index.at("2").at("status") == "failed" && index.at("2").at("error") == "no such message" && index.at("3").at("status") == "not-prefetched (not a lore URL)" && calls.size() == 2
&& fs::exists(base / "refs-h8.json") && logs.size() == 1 && logs[0] == "refs: 1/3 lore references available locally (1 fetched now)",
DumpCompact(index));
calls.clear();
const Json again = Refs::Prefetch(base, table, refsDir, base / "refs-h8.json", [&](const std::string&) {}, 2);
Check("...a cached reference is not fetched again", again.at("1").at("status") == "cached" && calls == std::vector<std::string>{table[1].second});
const std::string digest = Refs::Digest(index);
Check("the digest: the header, then one line per reference - numbered ones first - with the headers and the path, FETCH FAILED, or the status",
digest.starts_with("REFERENCES prefetched (read the raw file instead of fetching; a FETCH FAILED line means the reference must be fetched by you or reported as unverifiable):\n[1] one@x | From: Mark <m@x> | Date: Mon | Subject: Re: the thing | ")
&& digest.contains(" (56 B)\n[2] fail@x | FETCH FAILED | https://lore.kernel.org/all/fail@x/\n[3] https://example.org/not-lore | not-prefetched (not a lore URL)"),
digest);
Json mixed = Json::object();
mixed["L2"] = {{"url", "u2"}, {"status", "x"}};
mixed["10"] = {{"url", "u10"}, {"status", "x"}};
mixed["L1"] = {{"url", "u1"}, {"status", "x"}};
mixed["2"] = {{"url", "u2"}, {"status", "x"}};
Check("...numbered references in numeric order, then the others", Refs::Digest(mixed).contains("\n[2] u2 | x\n[10] u10 | x\n[L1] u1 | x\n[L2] u2 | x"));
Refs::SetSearcher([&](const fs::path&, const std::string& q) -> std::pair<std::string, std::string> {
calls.push_back(q);
return q.contains("Nobody") ? std::pair(std::string("No results.\n"), std::string("err")) : std::pair(std::string("2026-09-01 Re: x\n2026-09-03 Re: y\n"), std::string());
});
logs.clear();
const auto [none, emptyCorpus] = Refs::PersonaCorpus(base, "Nobody Here", refsDir, "20251031", [&](const std::string& l) { logs.push_back(l); });
const auto [path, corpus] = Refs::PersonaCorpus(base, "Mark Brown", refsDir, "20251031", [&](const std::string& l) { logs.push_back(l); });
calls.clear();
const auto [again2, corpus2] = Refs::PersonaCorpus(base, "Mark Brown", refsDir, "20251031", [&](const std::string&) {});
Check("a persona corpus: no results is not cached and says so; results are cached under the slug with the query line, and read from the cache after",
!none && emptyCorpus.empty() && logs[0] == "persona corpus: Nobody Here -> NO RESULTS for 'f:\"Nobody Here\" AND d:20251031..' (stderr: err) - the whole pass calibrates by its own searches"
&& path && path->filename() == "persona-mark-brown.txt" && corpus.starts_with("lore.py search 'f:\"Mark Brown\" AND d:20251031..' (") && corpus.ends_with("2026-09-01 Re: x\n2026-09-03 Re: y\n")
&& logs[1].starts_with("persona corpus: Mark Brown -> ") && logs[1].ends_with(" (33 chars)") && calls.empty() && corpus2 == corpus,
Dyn::Join(logs, " | "));
Check("since: 365 days before the run date", Refs::SinceOf("2026-10-31") == "20251031" && Refs::SinceOf("2024-03-01") == "20230302");
Refs::SetFetcher(nullptr);
Refs::SetSearcher(nullptr);
}
// ---- the state's persona pass ---------------------------------------------------
{
const Json disk = {{"version", 1}, {"entries", Json::object()}, {"personaPass", nullptr}};
const Json m = State::MergeState(disk, Json::object(), {}, nullptr, Json({{"hash", "H2"}}));
Check("personaPass set when given and kept when not", m.at("personaPass") == Json({{"hash", "H2"}}) && State::MergeState(m, Json::object()).at("personaPass") == Json({{"hash", "H2"}}));
}
// ---- the allowlist --------------------------------------------------------------
{
const std::vector<std::string> al = Pool::AllowedTools("facts.md", "block", std::vector<std::string>{"work/milos-linux"}, {}, std::nullopt, "none");
const std::vector<std::string> bp = Pool::AllowedTools("bug-prover.md", "block", std::vector<std::string>{"work/milos-linux"}, {}, std::nullopt, "none");
const std::vector<std::string> rp = Pool::AllowedTools(std::string(Plan::FactsLens), "block", std::vector<std::string>{"."}, {}, std::nullopt, "none");
const std::vector<std::string> pp = Pool::AllowedTools(std::string(Plan::PersonaLens), "block", std::vector<std::string>{"work/milos-linux"}, {}, std::nullopt, "none");
auto has = [](const std::vector<std::string>& l, std::string_view x) { return std::ranges::contains(l, std::string(x)); };
Check("allowlist: a kernel lens fetches from lore, a lens that judges against the list searches too, a repo lens has no lore; the tree's git verbs in both spellings",
has(al, "Bash(python3 utilities/lore.py fetch:*)") && has(al, "Bash(python3 utilities/lore.py search:*)") && has(al, "Bash(git -C work/milos-linux show:*)") && has(al, "Bash(cd:*)")
&& has(bp, "Bash(python3 utilities/lore.py fetch:*)") && !has(bp, "Bash(python3 utilities/lore.py search:*)") && std::ranges::none_of(rp, [](const std::string& x) { return x.contains("lore.py"); })
&& has(pp, "Bash(python3 utilities/lore.py search:*)") && std::ranges::none_of(al, [](const std::string& x) { return x.starts_with("Read("); }));
}
// ---- dry runs of both modes through the binary -------------------------------------
{
const fs::path bench = base / "bench";
fs::create_directories(bench / ".review-gates");
// The bench's modes: a series runs every kernel lens, a reply its
// kind's five.
Json modes = {{"series", {{"lenses", Json::array()}}}, {"reply", {{"lenses", Json::array()}}}};
const std::array<std::string_view, 10> on = {"facts.md", "etiquette.md", "consistency.md", "conciseness.md", "better-solution.md", "code-quality.md", "minimalism.md", "bug-prover.md", "process-docs.md", Plan::PersonaLens};
for (const std::string_view lf : on) modes["series"]["lenses"].push_back(Plan::LensName(lf));
const std::array<std::string_view, 5> replyOn = {"facts.md", "etiquette.md", "consistency.md", "conciseness.md", Plan::PersonaLens};
for (const std::string_view lf : replyOn) modes["reply"]["lenses"].push_back(Plan::LensName(lf));
// A mode of the bench's own name: a reply with the facts lens alone, at effort high.
modes["quick"] = {{"kind", "reply"}, {"lenses", Json::array({"facts"})}, {"effort", "high"}};
// The bench's own section for the facts lens (lenses.facts.section).
Write(bench / "process" / "lens-sections" / "facts.md", "## The bench's own section\n\n- 2026-10-31: a section of the bench repository, appended to the facts charter.\n");
Write(bench / ".review-gates" / "config.json", DumpFile(Json({{"modes", modes}, {"lenses", {{"facts", {{"section", "process/lens-sections/facts.md"}}}}}})));
const fs::path fakeDir = base / "fake";
const fs::path fake = fakeDir / "claude";
Write(fake, FakeClaude);
fs::permissions(fake, fs::perms::owner_all | fs::perms::group_read | fs::perms::group_exec | fs::perms::others_read | fs::perms::others_exec);
const std::map<std::string, std::string> env = With(Env, {{"FAKE_DIR", fakeDir.string()}});
// The reply: a draft under the journal, its references indexed
// as failed (no lore here), a reviewer with no corpus.
const fs::path draftPath = bench / "journal" / "x" / "draft.eml";
Write(draftPath, Dyn::ReadText(fix / "reply.eml"));
const std::string replyHash = Artifact::Sha256File(draftPath);
FailedIndex(bench / "journal" / "x" / "gate-state", replyHash.substr(0, 8), Refs::ParseRefs(Dyn::ReadText(draftPath)));
const fs::path scratch = base / "scratch";
auto run = [&](std::vector<std::string> args) {
std::vector<std::string> argv = {Platform::SelfExe().string(), "run"};
std::ranges::move(args, std::back_inserter(argv));
argv.insert(argv.end(), {"--date", "2026-10-31", "--claude-bin", fake.string(), "--scratch", scratch.string(), "--seats", "local", "--no-probe"});
return Process::Run(argv, bench, std::chrono::seconds(120), {}, env);
};
const Process::Captured replyDry = run({"--mode", "reply", "--subsystem", "x", "--artifact", "journal/x/draft.eml", "--hash", replyHash, "--reviewers", "Some Maintainer", "--dry-run"});
const fs::path replyDryDir = scratch / std::format("{}-run-1-dry", replyHash.substr(0, 8));
Json replyPlan;
try {
replyPlan = Dyn::LoadJsonFile(replyDryDir / "dry-run.json");
} catch (const std::exception&) {
}
const std::string replySystems = SystemFiles(replyDryDir);
const std::string replyPrompts = Prompts(replyDryDir);
const Json& byLens = replyPlan.is_object() ? replyPlan.at("dryRun").at("jobsByLens") : Json::object();
Check("a reply dry run: exit 2; Gate 3's four lenses and the persona instance planned (whole + blocks); the common text is the reply's; the run layer names the ledger and carries the failed reference; the persona's system file names them and the private-contributor text; no lore fetch attempted",
replyDry.returnCode == 2 && replyPlan.is_object() && Dyn::Has(byLens, "facts") && Dyn::Has(byLens, "etiquette") && Dyn::Has(byLens, "consistency") && Dyn::Has(byLens, "conciseness")
&& Dyn::Has(byLens, "persona:Some Maintainer") && byLens.at("persona:Some Maintainer").get<std::int64_t>() > 1 && replySystems.contains("pre-send pipeline for a Linux kernel mailing-list reply")
&& replySystems.contains("- Ledger: journal/x/ledger.md (the only mutable journal file you may read)") && replySystems.contains("| FETCH FAILED | https://lore.kernel.org/all/20260815.4567@example.org/")
&& replySystems.contains("Your persona: Some Maintainer.") && replySystems.contains("lore.py search for mail from Some Maintainer since 20251031: NO RESULTS") && replySystems.contains("journal/x/ledger.md indexes every message")
&& replyPrompts.contains("read the whole artifact as they would") && replyPrompts.contains("Coverage vocabulary for a maintainer or reviewer")
&& replyPlan.at("overall") == "DRY RUN - NOT SEND-READY (no process launched)" && replyPlan.at("mode") == "reply" && replyPlan.at("refs").at("failed") == Json({"1"})
&& Dyn::Has(replyPlan.at("coverage"), "personaHoles") && replyPlan.at("lensesOff") == Json::array() && Dyn::Truthy(replyPlan.at("dryRun").at("ok")),
std::format("exit {}; {}{}", replyDry.returnCode, Dyn::Slice(replyDry.out, -1500), replyDry.err));
const std::string replyLog = Platform::ReadFile(replyDryDir / "log.txt").value_or("");
Check("...the log: the mode, the index loaded without a fetch, the persona corpus missing, the gates and the persona gate",
replyLog.contains(": reply journal/x/draft.eml @ ") && replyLog.contains("refs: 1 entries loaded from the existing index (dry run, no fetch)") && replyLog.contains("persona corpus: Some Maintainer -> NO RESULTS")
&& replyLog.contains("Gate 3 — Artifact truth: facts, etiquette, consistency, conciseness") && replyLog.contains("Gate 4 — Personas: persona:Some Maintainer"),
replyLog);
Check("...the bench's section: appended to the facts charter in the system files, after the shipped text, and the log names the lens",
replySystems.contains("- 2026-10-31: a section of the bench repository, appended to the facts charter.")
&& replySystems.find("# Lens: facts") < replySystems.find("- 2026-10-31: a section of the bench repository")
&& replyLog.contains("lenses: the repository's sections appended to facts"), replyLog);
// The series: the fixture under the journal, its cover's
// reference indexed.
const fs::path seriesDir = bench / "journal" / "x" / "patch" / "widget" / "v1";
for (const std::string& f : Artifact::PatchFiles(fix / "series")) Write(seriesDir / f, Dyn::ReadText(fix / "series" / f));
const std::string seriesHash = Artifact::ArtifactHash("series", seriesDir);
FailedIndex(seriesDir / "gate-state", seriesHash.substr(0, 8), Refs::ParseRefs(Dyn::Join(Inventory::Build("series", seriesDir.string()).lines, "\n")));
const Process::Captured seriesDry = run({"--mode", "series", "--subsystem", "x", "--artifact", "journal/x/patch/widget/v1", "--base", "work/linux @ abc", "--dry-run"});
const fs::path seriesDryDir = scratch / std::format("{}-run-1-dry", seriesHash.substr(0, 8));
Json seriesPlan;
try {
seriesPlan = Dyn::LoadJsonFile(seriesDryDir / "dry-run.json");
} catch (const std::exception&) {
}
const std::string seriesSystems = SystemFiles(seriesDryDir);
const Json& sByLens = seriesPlan.is_object() ? seriesPlan.at("dryRun").at("jobsByLens") : Json::object();
Check("a series dry run: exit 2; the three gates' nine lenses planned, no persona without reviewers; the series common text, the base and the default trees in the run layer; every record carries its reuse key",
seriesDry.returnCode == 2 && seriesPlan.is_object() && sByLens.size() == 9 && Dyn::Has(sByLens, "better-solution") && Dyn::Has(sByLens, "minimalism") && Dyn::Has(sByLens, "process-docs")
&& seriesSystems.contains("pre-send pipeline for a Linux kernel patch series") && seriesSystems.contains("- Target tree at the submission base: work/linux @ abc")
&& seriesSystems.contains("- Trees: work/linux, work/milos-linux") && seriesSystems.contains("| FETCH FAILED | https://lore.kernel.org/all/20260901.1234@example.org/")
&& seriesPlan.at("args").at("effort") == "max" && seriesPlan.at("args").at("reads") == 3 && seriesPlan.at("mode") == "series"
&& std::ranges::any_of(seriesPlan.at("processes"), [](const Json& r) { return r.at("kind") == "block" && Dyn::Get(r, "unit") == "p1:drivers/nfc/widget.c#1" && Dyn::Truthy(Dyn::Get(r, "reuseKey")); })
&& std::ranges::any_of(seriesPlan.at("processes"), [](const Json& r) { return Dyn::Get(r, "unit") == "cover:2" && Dyn::Truthy(Dyn::Get(r, "reuseKey")); }),
std::format("exit {}; {}{}", seriesDry.returnCode, Dyn::Slice(seriesDry.out, -1500), seriesDry.err));
const Process::Captured noSubsystem = run({"--mode", "series", "--artifact", "journal/x/patch/widget/v1", "--dry-run"});
const Process::Captured withReviewers = run({"--mode", "commits", "--artifact", "journal/x/patch/widget/v1", "--reviewers", "A", "--dry-run"});
const Process::Captured replyReads = run({"--mode", "reply", "--subsystem", "x", "--artifact", "journal/x/draft.eml", "--reads", "3", "--dry-run"});
Check("preflight: a kernel mode needs --subsystem; commits refuses --reviewers; a reply is read once",
noSubsystem.returnCode == 3 && noSubsystem.err.contains("series mode: --subsystem is required") && withReviewers.returnCode == 3 && withReviewers.err.contains("no persona gate")
&& replyReads.returnCode == 3 && replyReads.err.contains("a reply has no code units and is read once"),
noSubsystem.err + withReviewers.err + replyReads.err);
// A full run of the reply on the stand-in: gates clean without a
// persona pass is GATES CLEAN; with the reviewer, SEND-READY and
// the persona pass recorded.
const Process::Captured plain = run({"--mode", "reply", "--subsystem", "x", "--artifact", "journal/x/draft.eml", "--no-reuse", "--no-salvage"});
const Json plainDump = Dyn::LoadJsonFile(bench / "journal" / "x" / "gate-state" / std::format("reply-{}-run-1.json", replyHash.substr(0, 8)));
const Process::Captured withPersona = run({"--mode", "reply", "--subsystem", "x", "--artifact", "journal/x/draft.eml", "--reviewers", "Some Maintainer", "--no-reuse", "--no-salvage"});
const Json personaDump = Dyn::LoadJsonFile(bench / "journal" / "x" / "gate-state" / std::format("reply-{}-run-2.json", replyHash.substr(0, 8)));
const Json state = Dyn::LoadJsonFile(bench / "journal" / "x" / "gate-state" / "unit-state.json");
std::int64_t personaEntries = 0;
for (auto it = state.at("entries").begin(); it != state.at("entries").end(); ++it) {
if (Dyn::Get(it.value(), "persona") == "Some Maintainer") ++personaEntries;
}
Check("a full reply run on the stand-in: gates clean without a reviewer is GATES CLEAN (exit 2); with the reviewer the persona gate runs and passes - SEND-READY, exit 0, personaPass recorded, the persona's blocks stored with its name, the matrix without persona holes",
plain.returnCode == 2 && plainDump.at("overall") == "GATES CLEAN - NOT SEND-READY (no reviewers passed, Gate 4 did not run)" && withPersona.returnCode == 0 && personaDump.at("overall") == "SEND-READY"
&& Dyn::Get(state, "personaPass").is_object() && state.at("personaPass").at("reviewers") == Json({"Some Maintainer"}) && personaEntries > 0
&& personaDump.at("coverage").at("personaHoles") == Json::array() && std::ranges::contains(personaDump.at("coverage").at("lenses"), Json("persona:Some Maintainer"))
&& !Dyn::Has(state.at("entries").begin().value(), "reads"),
std::format("exit {} / {}; {} / {}; {}{}", plain.returnCode, withPersona.returnCode, Dyn::StrOr(Dyn::Get(plainDump, "overall"), "?"), Dyn::StrOr(Dyn::Get(personaDump, "overall"), "?"),
Dyn::Slice(withPersona.out, -800), withPersona.err));
// A mode of the repository's own name (2026-11-01): `quick`, a
// reply with the facts lens alone at effort high. The run takes
// its kind, lenses and effort from the config and the dump says
// mode and kind; the run lock, the run number and the dump name
// are the kind's, so this is the artifact's third reply dump. An
// unknown mode is refused with the configured names.
const Process::Captured quick = run({"--mode", "quick", "--subsystem", "x", "--artifact", "journal/x/draft.eml", "--no-reuse", "--no-salvage"});
Json quickDump;
try {
quickDump = Dyn::LoadJsonFile(bench / "journal" / "x" / "gate-state" / std::format("reply-{}-run-3.json", replyHash.substr(0, 8)));
} catch (const std::exception&) {
}
const Process::Captured nope = run({"--mode", "nope", "--subsystem", "x", "--artifact", "journal/x/draft.eml", "--dry-run"});
const Json quickLenses = quickDump.is_object() ? quickDump.at("coverage").at("lenses") : Json::array();
Check("a named mode: its kind, lenses and effort from the config, mode and kind in the dump, the dump numbered and named by the kind; an unknown mode is refused naming the configured ones",
quick.returnCode == 2 && quickDump.is_object() && quickDump.at("mode") == "quick" && quickDump.at("kind") == "reply" && quickDump.at("args").at("effort") == "high"
&& quickLenses == Json({"facts"}) && !quickDump.at("lensesOff").empty() && quick.out.contains("quick (a reply)") && nope.returnCode == 3
&& nope.err.contains("--mode nope: no such mode in the config (modes: ") && nope.err.contains("quick"),
std::format("exit {} / {}; {}{}", quick.returnCode, nope.returnCode, Dyn::Slice(quick.out, -600), nope.err));
}
fs::remove_all(base);
return Failures ? 1 : 0;
}
}
int main(int argc, char** argv) {
const std::vector<std::string_view> args(argv, argv + argc);
// With arguments this binary is crafter-review itself, in native mode.
if (args.size() > 1) {
Platform::SystemPaths paths = Platform::Paths();
paths.flatpakInfo = "/nonexistent/.flatpak-info";
Platform::SetPaths(paths);
return Crafter::Review::Main(args);
}
try {
return Checks();
} catch (const std::exception& error) {
std::println(std::cerr, "kernel modes: {}", error.what());
return 1;
}
}