feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
|
|
|
|
|
|
export module Crafter.Review:Run;
|
|
|
|
|
import std;
|
|
|
|
|
import :Json;
|
|
|
|
|
import :Plan;
|
|
|
|
|
import :Pool;
|
|
|
|
|
import :SeatPool;
|
|
|
|
|
import :Memory;
|
|
|
|
|
import :PgWire;
|
|
|
|
|
import :State;
|
|
|
|
|
import :Platform;
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
import :Refs;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
|
|
|
|
|
// Run: the driver for a commit range about to be pushed
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// (process/prepush.md), and for the kernel modes - a mailing-list reply or
|
|
|
|
|
// a patch series about to be sent. One claude process per inventory unit
|
|
|
|
|
// per lens, whole passes where a lens has one (each gating its block
|
|
|
|
|
// passes), fail-closed coverage per unit, the matrix, per-unit reuse across
|
|
|
|
|
// hashes, a seat pool.
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
//
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// Gates (commits): 1 repo-better-solution (approach) -> 2 repo-functional
|
|
|
|
|
// (the range exercised in the running application) -> 3 repo-bug-prover
|
|
|
|
|
// and repo-security -> 4 the owner. SEND-READY = push-ready. The kernel
|
|
|
|
|
// modes run their own gates (Plan::Gates), then the persona gate for every
|
|
|
|
|
// reviewer given; gates clean without a persona pass is GATES CLEAN, not
|
|
|
|
|
// SEND-READY. Exit codes: 0 SEND-READY, 1 FIX FIRST, 2 INCOMPLETE / PARTIAL
|
|
|
|
|
// / GATES CLEAN / CONFIRMING (gates clean, code units still owe clean reads
|
|
|
|
|
// - run the same line again), 3 preflight.
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
//
|
|
|
|
|
// A Run is built empty and filled field by field, as the tests fill one, so
|
|
|
|
|
// its attributes are public; Main builds and runs the real one.
|
|
|
|
|
export namespace Crafter::Review::Run {
|
|
|
|
|
using Log = std::function<void(const std::string&)>;
|
|
|
|
|
|
|
|
|
|
// `crafter-review run`'s options: the dump records them under `args`, in
|
|
|
|
|
// this order.
|
|
|
|
|
struct Arguments {
|
|
|
|
|
std::optional<std::string> config;
|
|
|
|
|
std::string mode = "commits";
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// The journal subsystem: required in the kernel modes (its ledger,
|
|
|
|
|
// captures and threads are the lenses' evidence); optional in
|
|
|
|
|
// commits mode.
|
|
|
|
|
std::optional<std::string> subsystem;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
std::string artifact;
|
|
|
|
|
std::optional<std::string> hash;
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// The reviewers a persona reads as, comma-separated (the kernel
|
|
|
|
|
// modes).
|
|
|
|
|
std::string reviewers;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
std::optional<std::string> dispositions;
|
|
|
|
|
std::string base;
|
|
|
|
|
std::string date;
|
|
|
|
|
std::optional<std::string> trees;
|
|
|
|
|
std::string contextPaths;
|
|
|
|
|
std::optional<std::string> only;
|
|
|
|
|
std::optional<std::string> without;
|
|
|
|
|
// --units, split on commas.
|
|
|
|
|
std::optional<std::set<std::string>> units;
|
|
|
|
|
bool warm = false;
|
2026-10-31 17:33:11 +01:00
|
|
|
// A cap on the passes in flight on this machine, every driver's
|
|
|
|
|
// counted; none by default (2026-10-31, Jorijn: "there is no need to
|
|
|
|
|
// do a global cap anymore, the cap should be 128 per available
|
|
|
|
|
// account"): each account's own cap is the limit.
|
|
|
|
|
std::optional<std::int64_t> concurrency;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
std::string effort;
|
|
|
|
|
std::int64_t reads = Plan::Reads;
|
|
|
|
|
bool noReuse = false;
|
|
|
|
|
bool noSalvage = false;
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// pruned: a persona's block passes skip the units its whole pass
|
|
|
|
|
// marked not-mine; all: every unit.
|
|
|
|
|
std::string personaBlocks = "pruned";
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
bool dryRun = false;
|
|
|
|
|
std::optional<std::string> claudeBin;
|
|
|
|
|
std::string models;
|
|
|
|
|
std::optional<std::string> scratch;
|
|
|
|
|
std::optional<std::string> seats;
|
|
|
|
|
std::optional<std::string> envFile;
|
|
|
|
|
bool noProbe = false;
|
|
|
|
|
std::optional<double> apiBudget;
|
|
|
|
|
std::string harness = "claude";
|
|
|
|
|
std::optional<std::string> variant;
|
|
|
|
|
std::optional<std::string> opencodeBin;
|
|
|
|
|
};
|
|
|
|
|
// vars(a) without `cmd`, the units sorted.
|
|
|
|
|
Json ArgsJson(const Arguments& a);
|
|
|
|
|
|
|
|
|
|
// die(): "preflight: <message>" on stderr, exit 3.
|
|
|
|
|
class Preflight : public std::runtime_error {
|
|
|
|
|
public:
|
|
|
|
|
using std::runtime_error::runtime_error;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// (ok, detail): does the application under test answer at <url><path>?
|
|
|
|
|
// Below 500 is ok.
|
|
|
|
|
std::pair<bool, std::string> AppReady(std::string_view url, std::string_view path = "/", double timeout = 10);
|
|
|
|
|
|
test(run): the store rules, stacks and memory, and the review fixes, check by check
StoreRules (23 checks), StacksMemory (24) and ReviewFixes (19), each a
test of its own.
Run and SlotsPlan now have seams that start as the real ones: appReady,
probe, query, bypassesRls, migrationsAtHead, migrationsDrift, treeDrift,
promptFor, runPass, resumable, instrumentPreflight, and a Machine for
SlotsPlan. MigrationsAtHead is split out of MigrationsDrift for it; the
HEAD side is still worked out once per tree and base.
The Postgres stand-in and the raw broker call move to tests/Common, shared
by PgWire and ReviewFixes. ReviewFixes runs this binary as `sql`, and a
real server that resets every connection makes the startup message either
fail to go out or never get its answer - a DbError either way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:39:53 +01:00
|
|
|
// The machine's memory as SlotsPlan reads it (the tests give their own).
|
|
|
|
|
struct Machine {
|
|
|
|
|
std::function<std::optional<std::int64_t>()> available;
|
|
|
|
|
std::function<std::int64_t()> reserve;
|
|
|
|
|
};
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
// `slots`: how many stacks to bring up - as many as free memory holds,
|
|
|
|
|
// and no more than the range's browser passes can use at once - and the
|
|
|
|
|
// commands for the ones not up yet. (want, commands).
|
|
|
|
|
std::pair<std::int64_t, std::vector<std::string>> SlotsPlan(const Json& cfg, const std::filesystem::path& repo, const std::optional<std::filesystem::path>& artifact = std::nullopt,
|
test(run): the store rules, stacks and memory, and the review fixes, check by check
StoreRules (23 checks), StacksMemory (24) and ReviewFixes (19), each a
test of its own.
Run and SlotsPlan now have seams that start as the real ones: appReady,
probe, query, bypassesRls, migrationsAtHead, migrationsDrift, treeDrift,
promptFor, runPass, resumable, instrumentPreflight, and a Machine for
SlotsPlan. MigrationsAtHead is split out of MigrationsDrift for it; the
HEAD side is still worked out once per tree and base.
The Postgres stand-in and the raw broker call move to tests/Common, shared
by PgWire and ReviewFixes. ReviewFixes runs this binary as `sql`, and a
real server that resets every connection makes the startup message either
fail to go out or never get its answer - a DbError either way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:39:53 +01:00
|
|
|
const std::optional<std::filesystem::path>& scratchRoot = std::nullopt, const Log& log = {}, const Machine& machine = {});
|
|
|
|
|
|
|
|
|
|
// ({version: path} of the migrations at the range HEAD, the range's added
|
|
|
|
|
// or changed migrations, {path: fingerprint at HEAD} of those).
|
|
|
|
|
using MigrationsHead = std::tuple<std::map<std::string, std::string>, std::vector<std::string>, std::map<std::string, std::string>>;
|
|
|
|
|
using QueryResult = std::pair<std::vector<std::string>, std::vector<std::vector<std::optional<std::string>>>>;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
|
|
|
|
|
class Run {
|
|
|
|
|
public:
|
|
|
|
|
Run();
|
|
|
|
|
Run(Arguments a, Json cfg);
|
|
|
|
|
~Run();
|
|
|
|
|
Run(const Run&) = delete;
|
|
|
|
|
Run& operator=(const Run&) = delete;
|
|
|
|
|
|
|
|
|
|
// The whole run: the gates, the dump, the summary; the exit code.
|
|
|
|
|
std::int32_t Execute();
|
|
|
|
|
// A signal or `crafter-review stop`: every running pass killed, the
|
|
|
|
|
// pool aborted, and the stop stays in force for the gates after.
|
|
|
|
|
void Stop(const std::string& why, std::int32_t signal = 0);
|
|
|
|
|
// The file `crafter-review stop` writes, once the scratch dir is
|
|
|
|
|
// known.
|
|
|
|
|
std::optional<std::filesystem::path> StopFile() const;
|
|
|
|
|
// The handler a signal reaches: false before gate 0 set it up (the
|
|
|
|
|
// signal then ends the process).
|
|
|
|
|
bool Ready() const;
|
|
|
|
|
|
|
|
|
|
// ---- gate 0 and its preflights ---------------------------------------
|
|
|
|
|
void Gate0();
|
|
|
|
|
std::map<std::string, std::string> AppLenses(std::span<const std::string> lensFiles) const;
|
|
|
|
|
std::map<std::string, std::string> DbLenses(std::span<const std::string> lensFiles) const;
|
|
|
|
|
void InstrumentPreflight(std::span<const std::string> lensFiles);
|
|
|
|
|
static std::optional<std::string> MigrationVersion(std::string_view file);
|
test(run): the store rules, stacks and memory, and the review fixes, check by check
StoreRules (23 checks), StacksMemory (24) and ReviewFixes (19), each a
test of its own.
Run and SlotsPlan now have seams that start as the real ones: appReady,
probe, query, bypassesRls, migrationsAtHead, migrationsDrift, treeDrift,
promptFor, runPass, resumable, instrumentPreflight, and a Machine for
SlotsPlan. MigrationsAtHead is split out of MigrationsDrift for it; the
HEAD side is still worked out once per tree and base.
The Postgres stand-in and the raw broker call move to tests/Common, shared
by PgWire and ReviewFixes. ReviewFixes runs this binary as `sql`, and a
real server that resets every connection makes the startup message either
fail to go out or never get its answer - a DbError either way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:39:53 +01:00
|
|
|
MigrationsHead MigrationsAtHead();
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
// (problem, note): the migrations at the range HEAD against the ones
|
|
|
|
|
// the database applied.
|
|
|
|
|
std::pair<std::optional<std::string>, std::optional<std::string>> MigrationsDrift(const std::string& url);
|
|
|
|
|
std::unique_ptr<Pool::Stacks> LoadStacks();
|
|
|
|
|
std::string StacksLine() const;
|
|
|
|
|
std::vector<Json> DbStacks(std::span<const std::string> lensFiles) const;
|
|
|
|
|
void StackPreflight(std::span<const std::string> lensFiles);
|
|
|
|
|
std::optional<std::string> LoginMissing(const Json& stack) const;
|
|
|
|
|
std::optional<std::string> TreeDrift();
|
|
|
|
|
|
|
|
|
|
// ---- prompts ---------------------------------------------------------------
|
|
|
|
|
// (appended system prompt file, stdin user message) of a pass.
|
|
|
|
|
std::pair<std::filesystem::path, std::string> PromptFor(const Json& job);
|
|
|
|
|
std::optional<std::string> CacheKey(Json& job);
|
|
|
|
|
bool WarmProbe(const Json& job) const;
|
|
|
|
|
|
|
|
|
|
// ---- reuse -----------------------------------------------------------------
|
|
|
|
|
const Plan::CommitCode& RangeCode();
|
|
|
|
|
std::optional<Json> ReuseWhole(const std::string& name, Json& job);
|
|
|
|
|
std::optional<std::string> ReuseKey(const Json& job, const std::optional<std::string>& environment = std::nullopt);
|
|
|
|
|
std::vector<std::string> OtherKeys(const Json& job, const std::optional<std::string>& key);
|
|
|
|
|
std::optional<std::pair<Json, Json>> Salvage(const Json& job);
|
|
|
|
|
Json DirEnvironments(const std::filesystem::path& dir);
|
|
|
|
|
static std::int64_t DirRound(const std::filesystem::path& dir);
|
|
|
|
|
std::int64_t ReadsNeeded(const Json& job) const;
|
|
|
|
|
|
|
|
|
|
// ---- one process, a gate -------------------------------------------------
|
|
|
|
|
std::pair<Json, Json> ExecJob(const Json& job, std::int64_t attempt);
|
|
|
|
|
Json PartFrom(const Json& job, const Json& rec, Json raw);
|
|
|
|
|
static Json DryPart(const Json& job);
|
|
|
|
|
std::vector<Json> RunGate(std::string_view title, std::vector<std::string> lensFiles);
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// (lens file, persona) per lens instance: a persona's instance reads
|
|
|
|
|
// as that reviewer.
|
|
|
|
|
std::vector<Json> RunGate(std::string_view title, std::vector<std::pair<std::string, std::string>> specs);
|
|
|
|
|
// The kernel modes (reply, series).
|
|
|
|
|
bool Kernel() const;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
std::unique_ptr<Pool::Admission> Admission(std::span<const std::string> lensFiles);
|
|
|
|
|
std::optional<Json> Resumable(const std::string& name, const std::string& lensFile, std::string_view title);
|
|
|
|
|
void Checkpoint(std::string_view title);
|
|
|
|
|
std::vector<Json> PrepareBlocks(const std::string& name, std::vector<Json> blocks, std::map<std::string, std::vector<Json>>& parts);
|
|
|
|
|
|
|
|
|
|
// ---- the end ---------------------------------------------------------------
|
|
|
|
|
std::int32_t Finish(std::string overall, const Json& stoppedAt, Json incomplete);
|
|
|
|
|
Json BuildDump(std::string_view overall, const Json& stoppedAt, const Json& incomplete);
|
|
|
|
|
Json DryReport();
|
|
|
|
|
bool Storable(const Json& rec) const;
|
|
|
|
|
Json StoreState();
|
|
|
|
|
|
|
|
|
|
void Message(const std::string& message);
|
|
|
|
|
|
|
|
|
|
// ---- the run's state -----------------------------------------------------
|
|
|
|
|
Arguments a;
|
|
|
|
|
Json cfg = Json::object();
|
|
|
|
|
std::vector<std::string> off;
|
|
|
|
|
// {lens file: environment}, in the config's lens order: the dump, the
|
|
|
|
|
// resume file and the scratch dir's marker write it in that order.
|
|
|
|
|
Json environments = Json::object();
|
feat(run): the repository under review is the freeze record's, not the working directory's
A directory can review repositories other than itself: a workbench whose
config, env file and records serve several, freezing each with --repo and
--out. The run took the working directory for the repository under review:
the prompt named it, the calibration was kept under it, and --trees fell
back to it. The run now reads the repository from the artifact's
freeze.json - the prompt names it and the calibration is kept under it -
and --trees defaults to what the record says: the worktree, else the
repository when it is not the working directory, else `.`, the same rule
that builds the printed run line. The working directory keeps its roles:
the config, the env file, the slots, the lens processes' cwd and every
logged path. A damaged record stops the run at preflight.
2026-10-31 21:31:48 +01:00
|
|
|
// The working directory: the config, the env file and the slots are
|
|
|
|
|
// its, the lens processes run in it, and every path logged is relative
|
|
|
|
|
// to it.
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
std::filesystem::path repo;
|
feat(run): the repository under review is the freeze record's, not the working directory's
A directory can review repositories other than itself: a workbench whose
config, env file and records serve several, freezing each with --repo and
--out. The run took the working directory for the repository under review:
the prompt named it, the calibration was kept under it, and --trees fell
back to it. The run now reads the repository from the artifact's
freeze.json - the prompt names it and the calibration is kept under it -
and --trees defaults to what the record says: the worktree, else the
repository when it is not the working directory, else `.`, the same rule
that builds the printed run line. The working directory keeps its roles:
the config, the env file, the slots, the lens processes' cwd and every
logged path. A damaged record stops the run at preflight.
2026-10-31 21:31:48 +01:00
|
|
|
// The repository under review, from the artifact's freeze record (the
|
|
|
|
|
// working directory when it has none): the prompt names it, and the
|
|
|
|
|
// calibration is kept under it.
|
|
|
|
|
std::filesystem::path reviewed;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
std::vector<std::string> logs;
|
|
|
|
|
double t0 = 0;
|
|
|
|
|
std::optional<std::filesystem::path> logFile;
|
|
|
|
|
std::vector<Json> records;
|
|
|
|
|
std::vector<Json> results;
|
|
|
|
|
std::map<std::string, std::int64_t> lensLayersBytes;
|
|
|
|
|
std::vector<Json> jobsRun;
|
|
|
|
|
std::map<std::string, std::string> summaries;
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// The kernel modes: the reviewers with a persona, their calibration
|
|
|
|
|
// maps, the references the artifact cites and their digest, the
|
|
|
|
|
// anchor unit's text, and whether the persona gate passed.
|
|
|
|
|
std::vector<std::string> reviewers;
|
|
|
|
|
std::map<std::string, std::string> corpora;
|
|
|
|
|
Refs::Table refUrls;
|
|
|
|
|
Json refIndex = Json::object();
|
|
|
|
|
std::string refDigest;
|
|
|
|
|
std::string anchorText;
|
|
|
|
|
bool personaRan = false;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
std::optional<std::string> abort;
|
|
|
|
|
Pool::Scheduler* sched = nullptr;
|
|
|
|
|
std::optional<Plan::CommitCode> commitCode;
|
|
|
|
|
std::int64_t x = 1;
|
|
|
|
|
std::int64_t round = 1;
|
|
|
|
|
bool newRound = false;
|
|
|
|
|
Json owed = Json::object();
|
|
|
|
|
std::map<std::string, Json> wholeParts;
|
|
|
|
|
std::optional<std::string> dbChecked;
|
|
|
|
|
std::optional<bool> dbBypass;
|
|
|
|
|
std::optional<std::string> dbRole;
|
|
|
|
|
std::unique_ptr<PgWire::Broker> broker;
|
|
|
|
|
std::unique_ptr<Pool::Stacks> stacks;
|
|
|
|
|
bool slotMode = false;
|
|
|
|
|
std::vector<std::string> slotProblems;
|
|
|
|
|
std::unique_ptr<SeatPool::Board> board;
|
|
|
|
|
std::unique_ptr<State::RunLock> runLock;
|
|
|
|
|
std::unique_ptr<Platform::LifetimeLock> lifetime;
|
|
|
|
|
std::vector<std::string> trees;
|
|
|
|
|
std::vector<std::string> contextPaths;
|
|
|
|
|
std::string hash;
|
|
|
|
|
std::string h8;
|
|
|
|
|
std::string head;
|
|
|
|
|
std::filesystem::path gateDir;
|
|
|
|
|
Json units = Json::array();
|
|
|
|
|
std::vector<std::string> lines;
|
|
|
|
|
bool testMode = false;
|
|
|
|
|
std::filesystem::path scratch;
|
|
|
|
|
std::filesystem::path dumpPath;
|
|
|
|
|
std::vector<std::string> notReviewed;
|
|
|
|
|
std::vector<Json> dispEntries;
|
|
|
|
|
std::vector<Json> dispRows;
|
|
|
|
|
std::vector<Json> inForce;
|
|
|
|
|
std::filesystem::path statePath;
|
|
|
|
|
Json state = State::EmptyState();
|
|
|
|
|
std::vector<std::filesystem::path> salvageDirs;
|
|
|
|
|
std::filesystem::path resumePath;
|
|
|
|
|
Json resume;
|
|
|
|
|
std::map<std::string, std::string> charters;
|
|
|
|
|
std::map<std::string, std::string> charterSha;
|
|
|
|
|
std::string systemText;
|
|
|
|
|
// {sha: path}, in the order first written.
|
|
|
|
|
std::vector<std::pair<std::string, std::filesystem::path>> systemPaths;
|
|
|
|
|
// {lens: the shas of its system files}, lenses in the order first met.
|
|
|
|
|
std::vector<std::pair<std::string, std::set<std::string>>> systemByLens;
|
|
|
|
|
std::string runLayer;
|
|
|
|
|
std::optional<std::string> loginFixture;
|
|
|
|
|
std::string appBlock;
|
|
|
|
|
std::map<std::string, std::string> schemas;
|
|
|
|
|
std::unique_ptr<Memory::Calibration> calibration;
|
|
|
|
|
std::unique_ptr<Memory::Sampler> sampler;
|
|
|
|
|
std::unique_ptr<Pool::Runner> runner;
|
|
|
|
|
Json apiCfg = Json::object();
|
|
|
|
|
std::unique_ptr<SeatPool::Ledger> ledger;
|
|
|
|
|
std::vector<Json> seats;
|
|
|
|
|
std::map<std::filesystem::path, Json> envMarkers;
|
|
|
|
|
std::set<std::pair<std::string, std::string>> envSkips;
|
test(run): the store rules, stacks and memory, and the review fixes, check by check
StoreRules (23 checks), StacksMemory (24) and ReviewFixes (19), each a
test of its own.
Run and SlotsPlan now have seams that start as the real ones: appReady,
probe, query, bypassesRls, migrationsAtHead, migrationsDrift, treeDrift,
promptFor, runPass, resumable, instrumentPreflight, and a Machine for
SlotsPlan. MigrationsAtHead is split out of MigrationsDrift for it; the
HEAD side is still worked out once per tree and base.
The Postgres stand-in and the raw broker call move to tests/Common, shared
by PgWire and ReviewFixes. ReviewFixes runs this binary as `sql`, and a
real server that resets every connection makes the startup message either
fail to go out or never get its answer - a DbError either way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:39:53 +01:00
|
|
|
std::map<std::pair<std::string, std::string>, MigrationsHead> migCache;
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
// The log every line goes to (the tests put their own here).
|
|
|
|
|
Log log;
|
|
|
|
|
|
test(run): the store rules, stacks and memory, and the review fixes, check by check
StoreRules (23 checks), StacksMemory (24) and ReviewFixes (19), each a
test of its own.
Run and SlotsPlan now have seams that start as the real ones: appReady,
probe, query, bypassesRls, migrationsAtHead, migrationsDrift, treeDrift,
promptFor, runPass, resumable, instrumentPreflight, and a Machine for
SlotsPlan. MigrationsAtHead is split out of MigrationsDrift for it; the
HEAD side is still worked out once per tree and base.
The Postgres stand-in and the raw broker call move to tests/Common, shared
by PgWire and ReviewFixes. ReviewFixes runs this binary as `sql`, and a
real server that resets every connection makes the startup message either
fail to go out or never get its answer - a DbError either way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:39:53 +01:00
|
|
|
// ---- the seams a test replaces ---------------------------------------------
|
|
|
|
|
// Each starts as the real one; the methods call through these.
|
|
|
|
|
std::function<std::pair<bool, std::string>(std::string_view url, std::string_view path)> appReady;
|
|
|
|
|
std::function<std::pair<bool, std::string>(std::string_view url)> probe;
|
|
|
|
|
std::function<QueryResult(std::string_view url, std::string_view sql)> query;
|
|
|
|
|
std::function<std::optional<bool>(std::string_view url)> bypassesRls;
|
|
|
|
|
std::function<MigrationsHead()> migrationsAtHead;
|
|
|
|
|
std::function<std::pair<std::optional<std::string>, std::optional<std::string>>(const std::string& url)> migrationsDrift;
|
|
|
|
|
std::function<std::optional<std::string>()> treeDrift;
|
|
|
|
|
std::function<std::pair<std::filesystem::path, std::string>(const Json& job)> promptFor;
|
|
|
|
|
std::function<std::pair<Json, Json>(const Json& job, const std::string& prompt, const std::filesystem::path& systemPath, std::string_view schema, std::int64_t maxTurns, std::int64_t timeoutMin,
|
|
|
|
|
bool persist)>
|
|
|
|
|
runPass;
|
|
|
|
|
std::function<std::optional<Json>(const std::string& name, const std::string& lensFile, std::string_view title)> resumable;
|
|
|
|
|
std::function<void(std::span<const std::string> lensFiles)> instrumentPreflight;
|
|
|
|
|
|
feat(run): `crafter-review run` and `slots`, the driver of the gates
Run: gate 0 (the artifact, the trees, the inventory, the run lock, the
scratch dir, dispositions, reuse state, resume, reads per round, seats,
the board), the stack and migration preflights, the prompts, reuse of
whole and block verdicts, salvage, a gate on the pool, checkpoints, the
dump, the dry-run report and the unit-state store; slots_plan and
app_ready beside it. The CLI parses run's 28 options, types and choices
included.
A full run takes its lifetime lock beside the board before it joins it.
A signal - or the stop file `crafter-review stop` writes, looked at
every 2 s - stops the run once gate 0 is through, and the stop stays in
force for the gates after; before that it ends the process with its
descendants.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:16:41 +01:00
|
|
|
private:
|
|
|
|
|
// What exec_job's threads share with the pool's: the system files,
|
|
|
|
|
// the lens layers, the jobs run.
|
|
|
|
|
mutable std::recursive_mutex shared;
|
|
|
|
|
mutable std::mutex logLock;
|
|
|
|
|
std::optional<std::string> stopped;
|
|
|
|
|
std::atomic<bool> ready = false;
|
|
|
|
|
std::optional<std::filesystem::path> stopFile;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// The `run` command: argv parsed by the CLI; the exit code.
|
|
|
|
|
std::int32_t Main(Arguments a, const Json& cfg);
|
|
|
|
|
// What SIGINT, SIGTERM and SIGHUP do (Process::InstallSignalThread):
|
|
|
|
|
// stop the run once gate 0 is through; before that, and for every other
|
|
|
|
|
// command, the process ends, its descendants with it.
|
|
|
|
|
void OnSignal(std::int32_t signal);
|
|
|
|
|
}
|