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)
feat(lenses): the commit-truth lens, repo-facts, as Gate 4
Every claim in every commit message, and in the documentation the range
adds or changes, proven or gone. The lens's block kinds are text, doc and
slot: a message unit is keyed on its text, the base and the code up to its
commit (MessageDeps); a documentation unit on its file, its normalised
text, the base and the code of the whole range (DocKeyParts); a diffstat on
its text alone; whole:order and whole:absent are asked in slot passes of
its own, never stored. A documentation file's diff header and a part the
commit writes nothing in are a mechanical n/a. Budgets 60/40 for a text or
doc block, 50/35 for a slot; one read. Gate 4, after the proofs, so the
messages and documents are read once the code they describe has settled;
the owner's gate is 5.
The goldens that follow from the lens table are derived by
tests/Goldens/derive.py, which asserts that the recorded table still
reproduces the recorded entries before it writes.
Proven, with the opt-in commit after this one: the suite (26 passed); a dry
run of a scratch range (2 commits, a README with sections) by the previous
binary and this one with the three static lenses on and the rest off, 25
prompts and 4 system files byte for byte; with repo-facts on as well,
those files unchanged and 10 passes and 1 system file added.
The lens's firing proof in this pipeline is owed (the owner's go).
2026-10-31 20:08:26 +01:00
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 ' )
2026-10-31 09:59:12 +01:00
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 ( ) } } ) ;
2026-10-31 20:09:07 +01:00
// A repository with one commit to review, the three static code lenses
// on (every lens is off until a config turns it on; the functional
// lens needs a running application, the commit-truth lens gets the
// last scenario).
2026-10-31 09:59:12 +01:00
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 " ) ;
2026-10-31 20:09:07 +01:00
Write ( repo / " .review-gates " / " config.json " , R " ({ " lenses " : { " repo - better - solution " : { " run " : true}, " repo - bug - prover " : { " run " : true}, " repo - security " : { " run " : true}}}) " ) ;
2026-10-31 09:59:12 +01:00
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 ) ;
2026-10-31 16:45:53 +01:00
// Dry runs with no full run between them share one dir: the next
// drops the last one's prompts.
const fs : : path dryDir = scratchRoot / std : : format ( " {}-run-1-dry " , h8 ) ;
Write ( dryDir / " prompts " / " stale.txt " , " a prompt of another range " ) ;
const Process : : Captured again = run ( { " --dry-run " } ) ;
std : : int64_t prompts = 0 ;
for ( const fs : : directory_entry & entry : fs : : directory_iterator ( dryDir / " prompts " ) ) prompts + = entry . path ( ) . extension ( ) = = " .txt " ? 1 : 0 ;
Check ( " dry run: a second dry run on a hash counts its own prompts, the one before's gone " , again . returnCode = = 2 & & ! fs : : exists ( dryDir / " prompts " / " stale.txt " ) & & prompts = = all ,
std : : to_string ( prompts ) ) ;
2026-10-31 09:59:12 +01:00
// 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.
2026-10-31 17:33:11 +01:00
std : : vector < std : : string > widths ;
2026-10-31 09:59:12 +01:00
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 ) ) ;
2026-10-31 17:33:11 +01:00
// While it runs, the board shows its width: per account, there
// being no machine-wide cap.
std : : string width ;
try {
const Json drivers = Dyn : : LoadJsonFile ( base / " board.json " ) . at ( " drivers " ) ;
for ( auto it = drivers . begin ( ) ; it ! = drivers . end ( ) ; + + it ) width = Text ( Dyn : : Get ( Dyn : : Get ( it . value ( ) , " settings " ) , " concurrency " ) ) ;
} catch ( const std : : exception & ) {
}
widths . push_back ( width ) ;
2026-10-31 09:59:12 +01:00
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 17:33:11 +01:00
// No machine-wide width by default (2026-10-31): the dump's args record
// none, a live run's board entry shows the per-account one, and a
// width below 1 is refused.
const Process : : Captured noWidth = run ( { " --concurrency " , " 0 " } ) ;
Check ( " no global cap by default: the dump records none, a live run shows `128 per account` on the board; --concurrency below 1 is a usage error " ,
dumpB . is_object ( ) & & dumpB . at ( " args " ) . at ( " concurrency " ) . is_null ( ) & & widths = = std : : vector < std : : string > { " 128 per account " , " 128 per account " } & & noWidth . returnCode = = 3
& & noWidth . err . contains ( " argument --concurrency: a number from 1 up " ) ,
std : : format ( " {} | {} " , Dyn : : Join ( widths , " , " ) , noWidth . err ) ) ;
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 16:45:53 +01:00
// A filter that names nothing is refused: skipping its empty items
// must not leave no filter, which is a full run.
const Process : : Captured noUnits = run ( { " --units " , " , " } ) ;
const Process : : Captured noLenses = run ( { " --only " , " , " } ) ;
Check ( " --units and --only that name nothing are usage errors (exit 3) - never a full run " ,
noUnits . returnCode = = 3 & & noUnits . err . contains ( " argument --units: names no unit id (',') " ) & & noLenses . returnCode = = 3
& & noLenses . err . contains ( " argument --only: names no lens file (' , ') " ) ,
noUnits . err + noLenses . err ) ;
// A patch that is not UTF-8 is no artifact: a preflight stop.
const fs : : path badArtifact = repo / " .review-gates " / " push " / " bad " ;
fs : : copy ( artifact , badArtifact , fs : : copy_options : : recursive ) ;
for ( const fs : : directory_entry & entry : fs : : directory_iterator ( badArtifact ) ) {
if ( entry . path ( ) . extension ( ) = = " .patch " ) std : : ofstream ( entry . path ( ) , std : : ios : : binary | std : : ios : : app ) < < std : : string ( " \xff \n " , 2 ) ;
}
const Process : : Captured badPatch = Process : : Run ( { Platform : : SelfExe ( ) . string ( ) , " run " , " --artifact " , " .review-gates/push/bad " , " --base " , baseSha , " --trees " , " . " , " --dispositions " ,
" .review-gates/push/bad/gate-state/dispositions.json " , " --claude-bin " , fake . string ( ) , " --scratch " , scratchRoot . string ( ) , " --dry-run " } ,
repo , std : : chrono : : seconds ( 60 ) , { } , Env ) ;
Check ( " preflight: a patch that is not UTF-8 stops the run, exit 3, saying so " ,
badPatch . returnCode = = 3 & & badPatch . err . contains ( " the artifact's patches are not UTF-8 ('utf-8' codec can't decode byte 0xff " ) , badPatch . err ) ;
// An error that escapes a run ends it with its message, exit 1,
// through the run's cleanup.
const Process : : Captured badReserve = run ( { " --no-reuse " , " --no-salvage " } , { { " REVIEW_GATES_MEM_RESERVE_MB " , " x " } } ) ;
Check ( " an error escaping a full run (a reserve that is no number) ends it with its ValueError, exit 1 " ,
badReserve . returnCode = = 1 & & badReserve . err . contains ( " crafter-review: ValueError: could not convert string to float: 'x' " ) , badReserve . err ) ;
2026-10-31 20:09:07 +01:00
// The commit-truth lens (2026-10-31), alone: a config that turns on
// only it (through --config: the tracked config file must stay as
// committed, or the tree is dirty) runs Gate 4 - its three text
feat(lenses): the commit-truth lens, repo-facts, as Gate 4
Every claim in every commit message, and in the documentation the range
adds or changes, proven or gone. The lens's block kinds are text, doc and
slot: a message unit is keyed on its text, the base and the code up to its
commit (MessageDeps); a documentation unit on its file, its normalised
text, the base and the code of the whole range (DocKeyParts); a diffstat on
its text alone; whole:order and whole:absent are asked in slot passes of
its own, never stored. A documentation file's diff header and a part the
commit writes nothing in are a mechanical n/a. Budgets 60/40 for a text or
doc block, 50/35 for a slot; one read. Gate 4, after the proofs, so the
messages and documents are read once the code they describe has settled;
the owner's gate is 5.
The goldens that follow from the lens table are derived by
tests/Goldens/derive.py, which asserts that the recorded table still
reproduces the recorded entries before it writes.
Proven, with the opt-in commit after this one: the suite (26 passed); a dry
run of a scratch range (2 commits, a README with sections) by the previous
binary and this one with the three static lenses on and the rest off, 25
prompts and 4 system files byte for byte; with repo-facts on as well,
those files unchanged and 10 passes and 1 system file added.
The lens's firing proof in this pipeline is owed (the owner's go).
2026-10-31 20:08:26 +01:00
// blocks and its two slot passes (the stand-in answers a SLOT PASS
// too) - push-ready, with the code units, the per-commit slots and
// the functional lens's slot listed as not reviewed.
{
2026-10-31 20:09:07 +01:00
Write ( base / " facts.json " , R " ({ " lenses " : { " repo - facts " : { " run " : true}}}) " ) ;
feat(lenses): the commit-truth lens, repo-facts, as Gate 4
Every claim in every commit message, and in the documentation the range
adds or changes, proven or gone. The lens's block kinds are text, doc and
slot: a message unit is keyed on its text, the base and the code up to its
commit (MessageDeps); a documentation unit on its file, its normalised
text, the base and the code of the whole range (DocKeyParts); a diffstat on
its text alone; whole:order and whole:absent are asked in slot passes of
its own, never stored. A documentation file's diff header and a part the
commit writes nothing in are a mechanical n/a. Budgets 60/40 for a text or
doc block, 50/35 for a slot; one read. Gate 4, after the proofs, so the
messages and documents are read once the code they describe has settled;
the owner's gate is 5.
The goldens that follow from the lens table are derived by
tests/Goldens/derive.py, which asserts that the recorded table still
reproduces the recorded entries before it writes.
Proven, with the opt-in commit after this one: the suite (26 passed); a dry
run of a scratch range (2 commits, a README with sections) by the previous
binary and this one with the three static lenses on and the rest off, 25
prompts and 4 system files byte for byte; with repo-facts on as well,
those files unchanged and 10 passes and 1 system file added.
The lens's firing proof in this pipeline is owed (the owner's go).
2026-10-31 20:08:26 +01:00
const std : : int64_t before = calls ( ) ;
std : : vector < std : : string > truthArgs = runArgs ( { " --no-reuse " , " --no-salvage " } ) ;
truthArgs . insert ( truthArgs . begin ( ) + 1 , { " --config " , ( base / " facts.json " ) . string ( ) } ) ;
const Process : : Captured truth = Process : : Run ( truthArgs , repo , std : : chrono : : seconds ( 60 ) , { } , Env ) ;
const Json dumpT = LatestDump ( gateDir , h8 ) ;
const Json & processesT = dumpT . is_object ( ) ? dumpT . at ( " processes " ) : Json : : array ( ) ;
std : : set < std : : string > labels ;
for ( const Json & p : processesT ) labels . insert ( Text ( p . at ( " label " ) ) ) ;
const Json notReviewedT = dumpT . is_object ( ) ? dumpT . at ( " coverage " ) . at ( " notReviewed " ) : Json : : array ( ) ;
auto notReviewed = [ & ] ( std : : string_view id ) { return std : : ranges : : any_of ( notReviewedT , [ & ] ( const Json & x ) { return x = = id ; } ) ; } ;
Check ( " the commit-truth lens alone: Gate 4 runs its three text blocks and its two slot passes (5 calls) - SEND-READY, exit 0; the code units, the per-commit slots and whole:behaviour are not reviewed " ,
truth . returnCode = = 0 & & calls ( ) - before = = 5 & & dumpT . is_object ( ) & & dumpT . at ( " overall " ) = = " SEND-READY " & & dumpT . at ( " stoppedAt " ) . is_null ( )
& & labels = = std : : set < std : : string > { " repo-facts:block:p1:subject " , " repo-facts:block:p1:msg " , " repo-facts:block:p1:diffstat " , " repo-facts:slot:whole:order " , " repo-facts:slot:whole:absent " }
& & Count ( processesT , " kind " , " slot " ) = = 2 & & dumpT . at ( " lensesOff " ) = = Json : : array ( { " repo-better-solution " , " repo-functional " , " repo-bug-prover " , " repo-security " } )
& & notReviewed ( " p1:hello.py#1 " ) & & notReviewed ( " p1:absent " ) & & notReviewed ( " whole:behaviour " ) & & ! notReviewed ( " whole:order " ) & & ! notReviewed ( " p1:msg " ) ,
std : : format ( " exit {}, {} call(s), {} " , truth . returnCode , calls ( ) - before , dumpT . is_object ( ) ? Text ( dumpT . at ( " overall " ) ) : truth . out + truth . err ) ) ;
}
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
// A workbench (2026-10-31): a directory that reviews another
// repository - its own config and env file, the artifact wherever
// --out says, the lenses' tree the frozen worktree. The run reads the
// repository under review from the freeze record: the prompt names
// it, not the working directory, and --trees defaults to the
// recorded worktree.
{
const fs : : path bench = base / " bench " ;
fs : : create_directories ( bench / " .review-gates " ) ;
Write ( bench / " .review-gates " / " config.json " , R " ({ " lenses " : { " repo - bug - prover " : { " run " : true}}}) " ) ;
const fs : : path out = bench / " journal " / " push " / " y " ;
const Process : : Captured benchFreeze = Process : : Run ( { Platform : : SelfExe ( ) . string ( ) , " freeze " , " --repo " , repo . string ( ) , " --out " , out . string ( ) , " --worktree " , " --base " , baseSha } ,
bench , std : : chrono : : seconds ( 60 ) , { } , Env ) ;
Json benchRecord ;
try {
benchRecord = Dyn : : LoadJsonFile ( out / " freeze.json " ) ;
} catch ( const std : : exception & ) {
}
const std : : string benchHash = benchRecord . is_object ( ) ? Text ( benchRecord . at ( " hash " ) ) : std : : string ( ) ;
const std : : string benchTree = benchRecord . is_object ( ) ? Text ( Dyn : : Get ( benchRecord , " worktree " ) ) : std : : string ( ) ;
Check ( " a workbench freezes another repository: the record names it, and the worktree is under the workbench's .review-gates/trees/ " ,
benchFreeze . returnCode = = 0 & & benchRecord . is_object ( ) & & Text ( benchRecord . at ( " repo " ) ) = = Dyn : : AbsPath ( repo . string ( ) )
& & benchTree = = std : : format ( " .review-gates/trees/repo-{} " , benchHash . substr ( 0 , 8 ) ) & & fs : : is_directory ( bench / benchTree ) ,
benchFreeze . out + benchFreeze . err ) ;
const fs : : path benchScratch = base / " bench-scratch " ;
const Process : : Captured benchRun = Process : : Run ( { Platform : : SelfExe ( ) . string ( ) , " run " , " --artifact " , " journal/push/y " , " --hash " , benchHash , " --base " , baseSha , " --dispositions " ,
" journal/push/y/gate-state/dispositions.json " , " --date " , Text ( freezeJson . at ( " date " ) ) , " --claude-bin " , fake . string ( ) , " --scratch " ,
benchScratch . string ( ) , " --seats " , " local " , " --no-probe " , " --dry-run " } ,
bench , std : : chrono : : seconds ( 60 ) , { } , Env ) ;
const fs : : path benchDry = benchScratch / std : : format ( " {}-run-1-dry " , benchHash . substr ( 0 , 8 ) ) ;
// The run layer is in the system prompts (system-<sha8>.md).
std : : string systems ;
std : : error_code benchError ;
for ( fs : : directory_iterator it ( benchDry , benchError ) , end ; ! benchError & & it ! = end ; it . increment ( benchError ) ) {
const std : : string name = it - > path ( ) . filename ( ) . string ( ) ;
if ( name . starts_with ( " system- " ) & & name . ends_with ( " .md " ) ) systems + = Platform : : ReadFile ( it - > path ( ) ) . value_or ( " " ) ;
}
const std : : string benchLog = Platform : : ReadFile ( benchDry / " log.txt " ) . value_or ( " " ) ;
Check ( " ...and a dry run from the workbench without --trees (exit 2, as every dry run) reads the recorded worktree, names the repository under review in the run layer, not the workbench, and logs it " ,
benchRun . returnCode = = 2 & & ! systems . empty ( )
& & systems . contains ( std : : format ( " Repository under review (repo), checked out at the range HEAD (the last commit of the artifact): {} - " , benchTree ) ) & & ! systems . contains ( " (bench) " )
& & benchLog . contains ( std : : format ( " repository under review: {} (read at {}) " , Dyn : : AbsPath ( repo . string ( ) ) , benchTree ) ) ,
std : : format ( " exit {}, {} bytes of system prompt; {}{} " , benchRun . returnCode , systems . size ( ) , benchRun . out , benchRun . 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 ;
}
}