2026-10-31 09:59:12 +01:00
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
// Full runs end to end, at no cost: this binary as crafter-review on a
// scratch repository, and a claude stand-in (/bin/sh) that answers every pass
// from what the driver hands it. A run SIGKILLed in its last gate, then the
// next one resuming its first gate from the checkpoint and salvaging the
// outputs of its last; a run with nothing left to buy; a FIX FIRST; a stop by
// `crafter-review stop`'s file and by SIGTERM; a stop between two gates. No
// pass outlives any of them.
# include <signal.h>
# include <unistd.h>
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 : : string Read ( const fs : : path & path ) {
std : : ifstream in ( path , std : : ios : : binary ) ;
return { std : : istreambuf_iterator < char > ( in ) , std : : istreambuf_iterator < char > ( ) } ;
}
std : : vector < std : : string > Lines ( const fs : : path & path ) {
const std : : string text = Read ( path ) ;
return text . empty ( ) ? std : : vector < std : : string > ( ) : Dyn : : Split ( Dyn : : RStrip ( text , " \n " ) , " \n " ) ;
}
// claude for the runs: the lens from its system file, the units from its
// prompt, every unit clear. Each pass adds a line to $FAKE_DIR/calls (its
// pid, its lens, its units). FAKE_FIX: a lens:unit that comes back a
// defect; FAKE_SLEEP: seconds a pass waits before it answers - every pass,
// or the one FAKE_SLEEP_ON names. It speaks first, so the warm-up lets
// the passes behind it go.
constexpr std : : string_view FakeClaude = R " sh(#!/bin/sh
set - f
[ " $1 " = - - version ] & & { echo ' 2.1 .314 ( Claude Code ) ' ; exit 0 ; }
sys =
model =
sid =
prev =
for a in " $@ " ; do
case $ prev in
- - append - system - prompt - file ) sys = $ a ; ;
- - model ) model = $ a ; ;
- - session - id ) sid = $ a ; ;
esac
prev = $ a
done
lens = $ ( sed - n ' s / ^ # Lens : //p' "$sys" | head -n 1)
ids = $ ( sed - n - e ' s / ^ SCOPE - BLOCK PASS , unit " \ ([^ " ] * \ ) " .*/ \1 /p' -e 's/^- \ (whole:[a-z]* \ ) \ [.*/ \1 /p')
echo " $$ $lens " $ 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 " } ] } } '
pause = $ FAKE_SLEEP
if [ - n " $FAKE_SLEEP_ON " ] ; then
pause =
for id in $ ids ; do [ " $lens:$id " = " $FAKE_SLEEP_ON " ] & & pause = $ FAKE_SLEEP ; done
fi
if [ - n " $pause " ] ; then
sleep " $pause " &
echo " $! " > > " $FAKE_DIR/sleeps "
wait " $! "
fi
verdict = SEND - READY
findings =
coverage =
summary =
for id in $ ids ; do
v = clear
if [ " $lens:$id " = " $FAKE_FIX " ] ; then
v = defect
verdict = ' FIX FIRST '
findings = " { \" finding \" : \" planted \" , \" evidence \" : \" hello.py:2 \" , \" proposedAction \" : \" fix it \" , \" items \" :[ \" $id \" ]} "
fi
coverage = " $coverage${coverage:+,}{ \" item \" : \" $id \" , \" verdict \" : \" $v \" , \" basis \" : \" read at HEAD \" } "
case $ id in whole : * ) summary = ' , " summary " : " the approach holds " ' ; ; esac
done
echo " { \" type \" : \" result \" , \" subtype \" : \" success \" , \" is_error \" :false, \" result \" : \" ok \" , \" structured_output \" :{ \" verdict \" : \" $verdict \" , \" findings \" :[$findings], \" notes \" :[], \" coverage \" :[$coverage]$summary}, \" usage \" :{ \" input_tokens \" :1, \" output_tokens \" :1}, \" total_cost_usd \" :0.01} "
) sh " ;
// The environment of every child: git with no user config (the user's
// signs commits), this checkout as the home, a board of the test's own,
// and none of the review or seat variables of the shell the test runs in.
std : : map < std : : string , std : : string > Env ;
Process : : Captured Git ( const fs : : path & repo , std : : vector < std : : string > args ) {
args . insert ( args . begin ( ) , { " git " , " -C " , repo . string ( ) } ) ;
return Process : : Run ( args , std : : nullopt , std : : chrono : : seconds ( 60 ) , { } , 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 ;
}
// The stand-in's processes and their sleeps that still run.
std : : vector < std : : string > Leftovers ( const fs : : path & fakeDir ) {
std : : vector < std : : string > alive ;
auto look = [ & ] ( const fs : : path & list , std : : string_view marker ) {
for ( const std : : string & line : Lines ( list ) ) {
const std : : string pid = line . substr ( 0 , line . find ( ' ' ) ) ;
const std : : string cmdline = Read ( std : : format ( " /proc/{}/cmdline " , pid ) ) ;
if ( cmdline . contains ( marker ) ) alive . push_back ( std : : format ( " {}: {} " , pid , Dyn : : Replace ( cmdline , std : : string ( 1 , ' \0 ' ) , " " ) ) ) ;
}
} ;
look ( fakeDir / " calls " , ( fakeDir / " claude " ) . string ( ) ) ;
look ( fakeDir / " sleeps " , " sleep " ) ;
return alive ;
}
// Leftovers once the supervisors have had their moment.
std : : vector < std : : string > LeftoversAfter ( const fs : : path & fakeDir ) {
for ( std : : int32_t i = 0 ; i < 100 ; + + i ) {
if ( Leftovers ( fakeDir ) . empty ( ) ) break ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 50 ) ) ;
}
return Leftovers ( fakeDir ) ;
}
bool WaitFor ( const std : : function < bool ( ) > & ready , std : : chrono : : seconds limit ) {
const auto end = std : : chrono : : steady_clock : : now ( ) + limit ;
while ( std : : chrono : : steady_clock : : now ( ) < end ) {
if ( ready ( ) ) return true ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 50 ) ) ;
}
return ready ( ) ;
}
// The dump of the highest run number on this hash.
Json LatestDump ( const fs : : path & gateDir , std : : string_view h8 ) {
const std : : string prefix = std : : format ( " commits-{}-run- " , h8 ) ;
std : : int64_t best = 0 ;
fs : : path found ;
for ( const fs : : directory_entry & entry : fs : : directory_iterator ( gateDir ) ) {
const std : : string name = entry . path ( ) . filename ( ) . string ( ) ;
if ( ! name . starts_with ( prefix ) | | ! name . ends_with ( " .json " ) ) continue ;
const std : : string number = name . substr ( prefix . size ( ) , name . size ( ) - prefix . size ( ) - 5 ) ;
if ( number . empty ( ) | | ! std : : ranges : : all_of ( number , [ ] ( char c ) { return c > = ' 0 ' & & c < = ' 9 ' ; } ) ) continue ;
if ( const std : : int64_t n = std : : stoll ( number ) ; n > best ) {
best = n ;
found = entry . path ( ) ;
}
}
return found . empty ( ) ? Json ( ) : Dyn : : LoadJsonFile ( found ) ;
}
// The run number in a dump's own name.
std : : int64_t RunNumber ( const Json & dump ) {
if ( ! dump . is_object ( ) ) return 0 ;
const std : : string path = Dyn : : Str ( dump . at ( " dumpPath " ) ) ;
const std : : size_t at = path . rfind ( " -run- " ) ;
return at = = std : : string : : npos ? 0 : std : : stoll ( path . substr ( at + 5 ) ) ;
}
std : : int64_t Count ( const Json & records , std : : string_view key , const Json & value ) {
return std : : ranges : : count_if ( records , [ & ] ( const Json & r ) { return Dyn : : Get ( r , key ) = = value ; } ) ;
}
std : : string Text ( const Json & value ) {
return value . is_string ( ) ? value . get < std : : string > ( ) : value . dump ( ) ;
}
std : : int32_t Checks ( ) {
std : : println ( " runs: a full run on a claude stand-in - killed and salvaged, resumed, nothing left to buy, FIX FIRST, stopped by the stop file, by SIGTERM and between gates " ) ;
Platform : : SetMode ( Platform : : Mode : : Native ) ;
const fs : : path checkout = fs : : current_path ( ) ;
SetHome ( checkout ) ;
const fs : : path base = fs : : temp_directory_path ( ) / std : : format ( " crafter-review-runs-{} " , Platform : : PublishedPid ( ) ) ;
fs : : remove_all ( base ) ;
const fs : : path repo = base / " repo " ;
const fs : : path fakeDir = base / " fake " ;
const fs : : path fake = fakeDir / " claude " ;
const fs : : path scratchRoot = base / " scratch " ;
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 ) ;
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 ;
}
Env = With ( Env , { { " GIT_CONFIG_GLOBAL " , " /dev/null " } , { " GIT_CONFIG_SYSTEM " , " /dev/null " } , { " GIT_AUTHOR_NAME " , " Me " } , { " GIT_AUTHOR_EMAIL " , " me@example.com " } ,
{ " GIT_COMMITTER_NAME " , " Me " } , { " GIT_COMMITTER_EMAIL " , " me@example.com " } , { " CRAFTER_REVIEW_HOME " , checkout . string ( ) } ,
{ " REVIEW_GATES_BOARD " , ( base / " board.json " ) . string ( ) } , { " FAKE_DIR " , fakeDir . string ( ) } } ) ;
// A repository with one commit to review, the functional lens off (it
// needs a running application).
fs : : create_directories ( repo ) ;
Git ( repo , { " init " , " -q " , " -b " , " main " } ) ;
Git ( repo , { " config " , " user.email " , " me@example.com " } ) ;
Git ( repo , { " config " , " user.name " , " Me " } ) ;
Write ( repo / " .gitignore " , " .review-gates/push/ \n .review-gates/trees/ \n " ) ;
Write ( repo / " .review-gates " / " config.json " , R " ({ " lenses " : { " repo - functional " : { " run " : false}}}) " ) ;
Write ( repo / " README.md " , " a greeter \n " ) ;
Git ( repo , { " add " , " -A " } ) ;
Git ( repo , { " commit " , " -q " , " -m " , " base " } ) ;
const std : : string baseSha = Dyn : : Strip ( Git ( repo , { " rev-parse " , " HEAD " } ) . out ) ;
Write ( repo / " hello.py " , " def hello(name): \n return f'hello {name}' \n " ) ;
Git ( repo , { " add " , " hello.py " } ) ;
Git ( repo , { " commit " , " -q " , " -m " , " add hello \n \n The greeting the README promises. " } ) ;
const Process : : Captured frozen = Process : : Run ( { Platform : : SelfExe ( ) . string ( ) , " freeze " , " --slug " , " x " , " --base " , baseSha } , repo , std : : chrono : : seconds ( 60 ) , { } , Env ) ;
const fs : : path artifact = repo / " .review-gates " / " push " / " x " ;
const fs : : path gateDir = artifact / " gate-state " ;
Json freezeJson ;
try {
freezeJson = Dyn : : LoadJsonFile ( artifact / " freeze.json " ) ;
} catch ( const std : : exception & ) {
Check ( " freeze: the scratch range freezes " , false , frozen . out + frozen . err ) ;
return 1 ;
}
const std : : string hash = freezeJson . at ( " hash " ) . get < std : : string > ( ) ;
const std : : string h8 = hash . substr ( 0 , 8 ) ;
auto runArgs = [ & ] ( std : : vector < std : : string > extra ) {
std : : vector < std : : string > args = { Platform : : SelfExe ( ) . string ( ) , " run " , " --artifact " , " .review-gates/push/x " , " --hash " , hash , " --base " , baseSha , " --trees " , " . " ,
" --dispositions " , " .review-gates/push/x/gate-state/dispositions.json " , " --date " , Text ( freezeJson . at ( " date " ) ) ,
" --claude-bin " , fake . string ( ) , " --scratch " , scratchRoot . string ( ) , " --seats " , " local " , " --no-probe " , " --reads " , " 1 " } ;
std : : ranges : : move ( extra , std : : back_inserter ( args ) ) ;
return args ;
} ;
auto run = [ & ] ( std : : vector < std : : string > extra , const std : : map < std : : string , std : : string > & env = { } ) {
return Process : : Run ( runArgs ( std : : move ( extra ) ) , repo , std : : chrono : : seconds ( 60 ) , { } , With ( Env , env ) ) ;
} ;
auto start = [ & ] ( std : : vector < std : : string > extra , const std : : map < std : : string , std : : string > & env , std : : string_view name ) {
return Process : : Start ( { . argv = runArgs ( std : : move ( extra ) ) ,
. environment = With ( Env , env ) ,
. cwd = repo ,
. input = { . kind = Process : : Stream : : Kind : : Null } ,
. output = { . kind = Process : : Stream : : Kind : : File , . file = base / std : : format ( " {}.out " , name ) } ,
. error = { . kind = Process : : Stream : : Kind : : File , . file = base / std : : format ( " {}.err " , name ) } } ) ;
} ;
auto calls = [ & ] { return static_cast < std : : int64_t > ( Lines ( fakeDir / " calls " ) . size ( ) ) ; } ;
// The plan, from a dry run: what every full run below buys.
const Process : : Captured dry = run ( { " --dry-run " } ) ;
Json plan ;
try {
plan = Dyn : : LoadJsonFile ( scratchRoot / std : : format ( " {}-run-1-dry " , h8 ) / " dry-run.json " ) ;
} catch ( const std : : exception & ) {
}
const Json & planned = plan . is_object ( ) ? plan . at ( " processes " ) : Json : : array ( ) ;
const auto all = static_cast < std : : int64_t > ( planned . size ( ) ) ;
const std : : int64_t gate1 = Count ( planned , " lens " , " repo-better-solution " ) ;
std : : string securityUnit ;
std : : string proverUnit ;
for ( const Json & p : planned ) {
if ( p . at ( " kind " ) ! = " block " ) continue ;
if ( securityUnit . empty ( ) & & p . at ( " lens " ) = = " repo-security " ) securityUnit = Text ( p . at ( " unit " ) ) ;
if ( proverUnit . empty ( ) & & p . at ( " lens " ) = = " repo-bug-prover " ) proverUnit = Text ( p . at ( " unit " ) ) ;
}
Check ( " dry run: the range plans the approach lens's whole pass and blocks, then the bug-prover's and the security lens's blocks - and no pass reaches claude " ,
dry . returnCode = = 2 & & all > gate1 & & gate1 > 1 & & ! securityUnit . empty ( ) & & ! proverUnit . empty ( ) & & calls ( ) = = 0 & & Count ( planned , " lens " , " repo-functional " ) = = 0 ,
dry . out . substr ( dry . out . size ( ) > 2000 ? dry . out . size ( ) - 2000 : 0 ) + dry . err ) ;
// Killed in its last gate: one security pass never answers, and the
// driver is SIGKILLed once every other pass has.
const fs : : path scratchA = scratchRoot / std : : format ( " {}-run-1 " , h8 ) ;
const Process : : Child a = start ( { } , { { " FAKE_SLEEP " , " 571 " } , { " FAKE_SLEEP_ON " , std : : format ( " repo-security:{} " , securityUnit ) } } , " a " ) ;
auto answered = [ & ] {
std : : int64_t n = 0 ;
std : : error_code error ;
for ( fs : : directory_iterator it ( scratchA / " out " , error ) , end ; ! error & & it ! = end ; it . increment ( error ) ) {
if ( it - > path ( ) . extension ( ) = = " .jsonl " & & Read ( it - > path ( ) ) . contains ( R " ( " type " : " result " ) " ) ) + + n ;
}
return n ;
} ;
const bool settled = WaitFor ( [ & ] { return calls ( ) = = all & & answered ( ) = = all - 1 ; } , std : : chrono : : seconds ( 30 ) ) ;
Process : : Signal ( a . pid , SIGKILL ) ;
const std : : optional < std : : int32_t > aCode = Process : : Wait ( a . pid , std : : chrono : : seconds ( 10 ) ) ;
const std : : vector < std : : string > aLeft = LeftoversAfter ( fakeDir ) ;
Json resumeA ;
try {
resumeA = Dyn : : LoadJsonFile ( gateDir / std : : format ( " resume-{}.json " , h8 ) ) ;
} catch ( const std : : exception & ) {
}
const Json dumpA = LatestDump ( gateDir , h8 ) ;
Check ( " SIGKILL: a driver killed in its last gate takes its passes with it (each pass's supervisor ends its tree); its first gate is on record in the checkpoint and the partial dump " ,
settled & & aCode = = - 9 & & aLeft . empty ( ) & & dumpA . is_object ( ) & & Text ( dumpA . at ( " overall " ) ) . starts_with ( " IN PROGRESS - after Gate 1 — Approach " ) & & resumeA . is_object ( )
& & resumeA . at ( " results " ) . size ( ) = = 1 & & resumeA . at ( " results " ) . at ( 0 ) . at ( " lens " ) = = " repo-better-solution " ,
std : : format ( " settled {}, exit {}, left {}, {} of {} answered, {} " , settled , aCode . value_or ( 0 ) , Dyn : : Join ( aLeft , " ; " ) , answered ( ) , all , resumeA . dump ( ) . substr ( 0 , 300 ) ) ) ;
// The next run: the first gate resumed, the outputs of the killed run
// salvaged, the one pass that never answered bought again.
std : : int64_t before = calls ( ) ;
const Process : : Captured b = run ( { } ) ;
const Json dumpB = LatestDump ( gateDir , h8 ) ;
const Json & processesB = dumpB . is_object ( ) ? dumpB . at ( " processes " ) : Json : : array ( ) ;
Check ( " the next run resumes the first gate from the checkpoint, salvages every output the killed run finished and buys only the pass that never answered - SEND-READY, exit 0 " ,
b . returnCode = = 0 & & calls ( ) - before = = 1 & & dumpB . is_object ( ) & & dumpB . at ( " overall " ) = = " SEND-READY " & & dumpB . at ( " resumedLenses " ) = = Json : : array ( { " repo-better-solution " } )
& & std : : ranges : : count_if ( processesB , [ ] ( const Json & r ) { return Dyn : : Truthy ( Dyn : : Get ( r , " salvaged " ) ) ; } ) = = all - gate1 - 1
& & Count ( processesB , " status " , " ok " ) = = all - gate1 ,
std : : format ( " exit {}, {} call(s), {} " , b . returnCode , calls ( ) - before , dumpB . is_object ( ) ? Text ( dumpB . at ( " overall " ) ) : b . out + b . err ) ) ;
const Json stored = State : : LoadState ( gateDir / " unit-state.json " ) . at ( " entries " ) ;
Check ( " ...and stores the clean block results of the range for reuse " , static_cast < std : : int64_t > ( stored . size ( ) ) > = all - gate1 , std : : to_string ( stored . size ( ) ) ) ;
// Nothing left to buy.
before = calls ( ) ;
const Process : : Captured c = run ( { } ) ;
const Json dumpC = LatestDump ( gateDir , h8 ) ;
Check ( " a run on the same hash has nothing left to buy: every lens resumes, claude is never called, SEND-READY " ,
c . returnCode = = 0 & & calls ( ) = = before & & dumpC . is_object ( ) & & dumpC . at ( " overall " ) = = " SEND-READY " & & dumpC . at ( " resumedLenses " ) . size ( ) = = 3 ,
std : : format ( " exit {}, {} call(s) " , c . returnCode , calls ( ) - before ) ) ;
// A defect, on a run that reuses nothing; the scratch dir it claims
// holds a stop file from before, which is not this run's.
const std : : string nextRun = std : : format ( " {}-run-{} " , h8 , RunNumber ( dumpC ) + 1 ) ;
const fs : : path stale = scratchRoot / nextRun / " stop " ;
Write ( stale , " " ) ;
before = calls ( ) ;
const Process : : Captured d = run ( { " --no-reuse " , " --no-salvage " } ,
{ { " FAKE_FIX " , std : : format ( " repo-bug-prover:{} " , proverUnit ) } , { " FAKE_SLEEP " , " 3 " } , { " FAKE_SLEEP_ON " , " repo-better-solution:whole:order " } } ) ;
const Json dumpD = LatestDump ( gateDir , h8 ) ;
Check ( " FIX FIRST: a defect in the last gate stops the run there, exit 1 - every pass bought again with --no-reuse --no-salvage " ,
d . returnCode = = 1 & & calls ( ) - before = = all & & dumpD . is_object ( ) & & dumpD . at ( " overall " ) = = " FIX FIRST " & & dumpD . at ( " stoppedAt " ) = = " Gate 3 — Proof " ,
std : : format ( " exit {}, {} call(s), {} " , d . returnCode , calls ( ) - before , dumpD . is_object ( ) ? Text ( dumpD . at ( " stoppedAt " ) ) : d . out + d . err ) ) ;
Check ( " stop: a stop file left in the scratch dir a run claims is dropped - the run ran its course past the watcher's first look " ,
! fs : : exists ( stale ) & & dumpD . is_object ( ) & & Dyn : : Str ( dumpD . at ( " scratch " ) ) . ends_with ( nextRun ) , nextRun ) ;
// Stopped by `crafter-review stop`'s file, and by SIGTERM, while the
// first gate's whole pass is under way: the pass is killed, no later
// gate starts, nothing is left running.
for ( const bool bySignal : { false , true } ) {
before = calls ( ) ;
const std : : string name = bySignal ? " term " : " file " ;
const Process : : Child child = start ( { " --no-reuse " , " --no-salvage " } , { { " FAKE_SLEEP " , " 573 " } } , name ) ;
const bool running = WaitFor ( [ & ] { return calls ( ) > before ; } , std : : chrono : : seconds ( 30 ) ) ;
std : : string scratch ;
for ( const std : : string & line : Lines ( base / std : : format ( " {}.out " , name ) ) ) {
if ( const std : : size_t at = line . rfind ( " ; scratch " ) ; at ! = std : : string : : npos ) scratch = line . substr ( at + 10 ) ;
}
if ( bySignal ) {
Process : : Signal ( child . pid , SIGTERM ) ;
} else if ( ! scratch . empty ( ) ) {
Write ( fs : : path ( scratch ) / " stop " , " " ) ;
}
const std : : optional < std : : int32_t > code = Process : : Wait ( child . pid , std : : chrono : : seconds ( 30 ) ) ;
if ( ! code ) Process : : Signal ( child . pid , SIGKILL ) ;
const std : : vector < std : : string > left = LeftoversAfter ( fakeDir ) ;
const Json dump = LatestDump ( gateDir , h8 ) ;
const std : : string why = bySignal ? " stopped by signal 15 (1 running processes killed) " : " stopped by crafter-review stop (1 running processes killed) " ;
Check ( bySignal ? " SIGTERM: the run stops as the stop file stops it - the same abort, the same exit, nothing left running "
: " stop file: `crafter-review stop` stops the run - its running pass killed, no later gate started, INCOMPLETE, exit 2, nothing left running " ,
running & & code = = 2 & & calls ( ) - before = = 1 & & left . empty ( ) & & dump . is_object ( ) & & dump . at ( " stoppedAt " ) = = std : : format ( " Gate 1 — Approach - ABORTED ({}) " , why )
& & Text ( dump . at ( " overall " ) ) . starts_with ( " INCOMPLETE - NOT SEND-READY " ) ,
std : : format ( " running {}, exit {}, {} call(s), left {}, {} " , running , code . value_or ( - 1 ) , calls ( ) - before , Dyn : : Join ( left , " ; " ) ,
dump . is_object ( ) ? Text ( dump . at ( " stoppedAt " ) ) : Read ( base / std : : format ( " {}.err " , name ) ) ) ) ;
}
2026-10-31 16:35:26 +01:00
// An env file that is not UTF-8: the preflight stops the run.
Write ( base / " bad.env " , std : : string ( " \xff \n " , 2 ) ) ;
const Process : : Captured badEnv = run ( { " --no-reuse " , " --no-salvage " , " --env-file " , ( base / " bad.env " ) . string ( ) } ) ;
Check ( " preflight: an env file that is not UTF-8 stops the run, exit 3, with the decoder's own words " ,
badEnv . returnCode = = 3 & & badEnv . err . contains ( " preflight: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte " ) , badEnv . err ) ;
2026-10-31 09:59:12 +01:00
// A stop between two gates: the next gate's pool starts aborted and
// runs nothing of it.
{
const fs : : path fx = checkout / " tests " / " Goldens " / " fixture " / " commits " ;
Run : : Run g ;
g . log = [ ] ( const std : : string & ) { } ;
g . a . artifact = fx . string ( ) ;
g . hash = Artifact : : ArtifactHash ( " commits " , fx ) ;
g . testMode = true ;
g . cfg = Config : : Defaults ( ) ;
g . environments = Config : : Environments ( g . cfg ) ;
for ( const Plan : : Lens & lens : Plan : : Lenses ) {
const std : : string lf ( lens . file ) ;
g . charters [ lf ] = Prompt : : Charter ( lf ) ;
g . charterSha [ lf ] = Plan : : Sha ( g . charters [ lf ] ) ;
}
const Inventory : : Built built = Inventory : : Build ( " commits " , fx . string ( ) ) ;
g . units = built . out . at ( " units " ) ;
g . lines = built . lines ;
g . scratch = base / " between " ;
fs : : create_directories ( g . scratch ) ;
g . calibration = std : : make_unique < Memory : : Calibration > ( base / " between " / " memory.json " , base , std : : map < std : : string , std : : int64_t > { { " none " , 210 } } ) ;
std : : int32_t ran = 0 ;
g . runPass = [ & ] ( const Json & job , const std : : string & , const fs : : path & , std : : string_view , std : : int64_t , std : : int64_t , bool ) {
+ + ran ;
return std : : pair < Json , Json > ( { { " label " , job . at ( " label " ) } , { " status " , " error " } , { " reason " , " ran " } } , nullptr ) ;
} ;
g . Stop ( " crafter-review stop " ) ;
const std : : vector < Json > res = g . RunGate ( " Gate 3 — Proof " , { " repo-bug-prover.md " } ) ;
Check ( " stop between gates: the next gate's pool starts aborted - none of its passes runs, and the abort is the run's " ,
ran = = 0 & & g . abort & & g . abort - > starts_with ( " stopped by crafter-review stop " ) & & res . size ( ) = = 1 & & ! res [ 0 ] . at ( " coverageMissing " ) . empty ( ) , g . abort . value_or ( " None " ) ) ;
}
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 - the driver, its
// supervisor, its helpers - in native mode whatever builds it.
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 , " runs: {} " , error . what ( ) ) ;
return 1 ;
}
}