feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
module Crafter . Review : Config_impl ;
import : Config ;
import : Json ;
import : Text ;
import : Core ;
import : Plan ;
import : Tools ;
import : PgWire ;
import : Process ;
2026-10-31 16:45:53 +01:00
import : Platform ;
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
import std ;
namespace fs = std : : filesystem ;
namespace Crafter : : Review : : Config {
namespace {
// Keys a consumer's config may still carry, with what replaced them.
struct Retired {
std : : string_view section ;
std : : string_view key ;
std : : string why ;
} ;
std : : vector < Retired > RetiredKeys ( ) {
return { {
" functional " , " concurrency " ,
std : : format ( " passes run as many at once as free memory allows, each at its environment's measured cost, and a pass that drives "
" the application holds a stack of its own (2026-10-22); for more of them at once bring up more stacks "
" (slots.*, `{} slots`) " , Invocation ( ) ) ,
} } ;
}
std : : string EnvironmentNames ( std : : string_view separator ) {
std : : vector < std : : string > names ;
for ( const Plan : : Environment & environment : Plan : : Environments ) names . emplace_back ( environment . name ) ;
return Dyn : : Join ( names , separator ) ;
}
Json EnvironmentTable ( ) {
Json table = Json : : object ( ) ;
for ( const Plan : : Environment & environment : Plan : : Environments ) table [ std : : string ( environment . name ) ] = true ;
return table ;
}
bool AllStrings ( const Json & list ) {
return list . is_array ( ) & & std : : ranges : : all_of ( list , [ ] ( const Json & item ) { return item . is_string ( ) ; } ) ;
}
// ^(Bash\([^()]+:\*\)|mcp__[A-Za-z0-9_-]+(__[A-Za-z0-9_-]+)?)$; `$`
// also matches before a final newline.
bool IsToolEntry ( std : : string_view tool ) {
std : : string_view body = tool ;
if ( body . ends_with ( ' \n ' ) ) body . remove_suffix ( 1 ) ;
if ( body . starts_with ( " Bash( " ) & & body . ends_with ( " :*) " ) & & body . size ( ) > 8 ) {
const std : : string_view prefix = body . substr ( 5 , body . size ( ) - 8 ) ;
return ! prefix . contains ( ' ( ' ) & & ! prefix . contains ( ' ) ' ) ;
}
if ( body . starts_with ( " mcp__ " ) & & body . size ( ) > 5 ) {
return std : : ranges : : all_of ( body . substr ( 5 ) , [ ] ( char c ) {
return ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' a ' & & c < = ' z ' ) | | ( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' _ ' | | c = = ' - ' ;
} ) ;
}
return false ;
}
// re.match(r'^https?://', text)
bool IsHttpUrl ( std : : string_view text ) {
return text . starts_with ( " http:// " ) | | text . starts_with ( " https:// " ) ;
}
// An integer or a float, not a bool.
bool IsRealNumber ( const Json & value ) {
return value . is_number ( ) ;
}
bool Positive ( const Json & value ) {
return value . is_number_float ( ) ? value . get < double > ( ) > 0.0 : ( value . is_number_unsigned ( ) ? value . get < std : : uint64_t > ( ) > 0 : value . get < std : : int64_t > ( ) > 0 ) ;
}
std : : vector < std : : string > Merge ( Json & destination , const Json & source , const std : : string & path ) {
std : : vector < std : : string > problems ;
for ( auto it = source . begin ( ) ; it ! = source . end ( ) ; + + it ) {
const std : : string & key = it . key ( ) ;
if ( ! Dyn : : Has ( destination , key ) ) {
problems . push_back ( std : : format ( " unknown key {}{} " , path , key ) ) ;
continue ;
}
Json & target = destination [ key ] ;
if ( target . is_object ( ) & & it . value ( ) . is_object ( ) ) {
std : : ranges : : move ( Merge ( target , it . value ( ) , std : : format ( " {}{}. " , path , key ) ) , std : : back_inserter ( problems ) ) ;
} else {
target = it . value ( ) ;
}
}
return problems ;
}
// The config's entry for the lens, else its default one.
const Json & LensEntry ( const Json & config , std : : string_view lensFile ) {
static const Json defaults = Defaults ( ) [ " lenses " ] ;
const Json & lenses = Dyn : : Get ( config , " lenses " ) ;
const std : : string name = Plan : : LensName ( lensFile ) ;
const Json * entry = lenses . is_object ( ) ? & Dyn : : Get ( lenses , name ) : nullptr ;
return entry & & entry - > is_object ( ) ? * entry : defaults . at ( name ) ;
}
// A config or a slot file as JSON: the value, or the text that goes
// into the "not JSON (...)" problem.
std : : variant < Json , std : : string > LoadJson ( const fs : : path & path ) {
try {
return Dyn : : LoadJsonFile ( path ) ;
} catch ( const std : : exception & error ) {
return std : : string ( error . what ( ) ) ;
}
}
}
Json Defaults ( ) {
Json lenses = Json : : object ( ) ;
2026-10-31 20:09:07 +01:00
// Every lens is off until the repository's config turns it on
// (2026-10-31, Jorijn: "all lenses off by default and opt in only").
for ( const Plan : : Lens & lens : Plan : : Lenses ) lenses [ Plan : : LensName ( lens . file ) ] = { { " run " , false } , { " environment " , lens . env } } ;
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
return {
// The integration branch a range is measured against (e.g.
// origin/dev): merge-base HEAD <base>.
{ " base " , nullptr } ,
// upstream: the push delta @{upstream}..HEAD, the base branch only
// when HEAD tracks nothing; base: always merge-base HEAD
// <base>..HEAD, the whole pull request.
{ " rangeFrom " , " upstream " } ,
// Author and committer emails the freeze accepts; null: the
// repository's `git config user.email`.
{ " authors " , nullptr } ,
// forbid | allow: Assisted-by / Co-Authored-By trailers in the
// range.
{ " aiTrailers " , " forbid " } ,
// An unsigned commit fails the freeze (else a warning).
{ " requireSigned " , false } ,
// Tracked paths the local stack rewrites in place while the lenses
// run.
{ " allowDirty " , Json : : array ( ) } ,
// The commands Gate 0 runs by hand, in order (documentation for the
// skill; the driver runs none of them).
{ " gate0 " , Json : : array ( ) } ,
2026-10-31 20:09:07 +01:00
// Per lens: run (off until true: every lens is opt-in) and
// environment (Plan::Environments).
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
{ " lenses " , lenses } ,
// The database under test, for every lens whose environment
// reaches it. The URL reaches a db pass's broker, never a prompt,
// and the dump and the log show it with the password masked.
{ " supabase " , { { " dbUrl " , " postgresql://postgres:postgres@127.0.0.1:54322/postgres " } , { " start " , nullptr } , { " stop " , nullptr } , { " notes " , " " } } } ,
// Stacks side by side (2026-10-22): a pass that drives an
// application holds one of its own.
{ " slots " , { { " dir " , nullptr } , { " start " , nullptr } , { " stop " , nullptr } , { " memMb " , nullptr } , { " startMb " , nullptr } } } ,
// The application under test, for every lens whose environment
// reaches one.
{ " functional " , {
{ " appUrl " , " http://localhost:8080 " } ,
{ " readyPath " , " / " } ,
{ " apiUrls " , Json : : array ( ) } ,
{ " start " , nullptr } ,
{ " stop " , nullptr } ,
{ " login " , { { " fixtures " , Json : : array ( ) } , { " notes " , " " } } } ,
{ " exclude " , Json : : array ( ) } ,
{ " extraTools " , Json : : array ( ) } ,
{ " mcp " , { { " command " , " npx " } , { " args " , nullptr } } } ,
{ " notes " , " " } ,
} } ,
} ;
}
Loaded Load ( const fs : : path & repo , const fs : : path & path ) {
Loaded loaded { Defaults ( ) , { } } ;
Json & config = loaded . config ;
const fs : : path p = path . empty ( ) ? repo / ConfigFile : path ;
std : : vector < std : : string > warnings ;
if ( fs : : exists ( p ) ) {
std : : variant < Json , std : : string > read = LoadJson ( p ) ;
if ( std : : holds_alternative < std : : string > ( read ) ) {
loaded . problems . push_back ( std : : format ( " {}: not JSON ({}) " , p . string ( ) , std : : get < std : : string > ( read ) ) ) ;
return loaded ;
}
Json data = std : : move ( std : : get < Json > ( read ) ) ;
if ( ! data . is_object ( ) ) {
loaded . problems . push_back ( std : : format ( " {}: the top level must be an object " , p . string ( ) ) ) ;
return loaded ;
}
for ( const Retired & retired : RetiredKeys ( ) ) {
const Json & section = Dyn : : Get ( data , retired . section ) ;
if ( section . is_object ( ) & & Dyn : : Has ( section , retired . key ) ) {
warnings . push_back ( std : : format ( " {}.{} is no longer read - remove it from {}: {} " , retired . section , retired . key , p . filename ( ) . string ( ) , retired . why ) ) ;
data [ std : : string ( retired . section ) ] . erase ( std : : string ( retired . key ) ) ;
}
}
loaded . problems = Merge ( config , data , " " ) ;
} else if ( ! path . empty ( ) ) {
loaded . problems . push_back ( std : : format ( " {}: no such file " , p . string ( ) ) ) ;
}
config [ " _path " ] = fs : : exists ( p ) ? Json ( p . string ( ) ) : Json ( ) ;
Json warningList = Json : : array ( ) ;
for ( const std : : string & warning : warnings ) warningList . push_back ( warning ) ;
config [ " _warnings " ] = std : : move ( warningList ) ;
std : : ranges : : move ( Validate ( config ) , std : : back_inserter ( loaded . problems ) ) ;
return loaded ;
}
std : : vector < std : : string > Validate ( const Json & config ) {
std : : vector < std : : string > out ;
const Json & trailers = Dyn : : At ( config , " aiTrailers " ) ;
if ( trailers ! = " forbid " & & trailers ! = " allow " ) out . emplace_back ( " aiTrailers must be 'forbid' or 'allow' " ) ;
const Json & rangeFrom = Dyn : : At ( config , " rangeFrom " ) ;
if ( rangeFrom ! = " upstream " & & rangeFrom ! = " base " ) out . emplace_back ( " rangeFrom must be 'upstream' or 'base' " ) ;
if ( rangeFrom = = " base " & & ! Dyn : : Truthy ( Dyn : : At ( config , " base " ) ) ) out . emplace_back ( " rangeFrom 'base' needs a base branch " ) ;
const Json & authors = Dyn : : At ( config , " authors " ) ;
if ( ! authors . is_null ( ) & & ( ! authors . is_array ( ) | | ! std : : ranges : : all_of ( authors , [ ] ( const Json & a ) {
return a . is_string ( ) & & a . get_ref < const std : : string & > ( ) . contains ( ' @ ' ) ;
} ) ) ) {
out . emplace_back ( " authors must be null or a list of email addresses " ) ;
}
for ( const std : : string_view key : { " allowDirty " , " gate0 " } ) {
if ( ! AllStrings ( Dyn : : At ( config , key ) ) ) out . push_back ( std : : format ( " {} must be a list of strings " , key ) ) ;
}
const Json environments = EnvironmentTable ( ) ;
Json lenses = Dyn : : At ( config , " lenses " ) ;
if ( ! lenses . is_object ( ) ) {
out . push_back ( std : : format ( " lenses must be an object: {{<lens name>: {{run: bool, environment: {}}}}} " , EnvironmentNames ( " | " ) ) ) ;
lenses = Json : : object ( ) ;
}
for ( auto it = lenses . begin ( ) ; it ! = lenses . end ( ) ; + + it ) {
const Json & entry = it . value ( ) ;
if ( ! entry . is_object ( ) ) {
out . push_back ( std : : format ( " lenses.{} must be an object {{run: bool, environment: {}}} " , it . key ( ) , EnvironmentNames ( " | " ) ) ) ;
continue ;
}
if ( ! Dyn : : Get ( entry , " run " ) . is_boolean ( ) ) out . push_back ( std : : format ( " lenses.{}.run must be true or false " , it . key ( ) ) ) ;
if ( ! Dyn : : In ( Dyn : : Get ( entry , " environment " ) , environments ) ) out . push_back ( std : : format ( " lenses.{}.environment must be one of {} " , it . key ( ) , EnvironmentNames ( " , " ) ) ) ;
}
auto runs = [ ] ( const Json & entry ) { return entry . is_object ( ) & & Dyn : : Get ( entry , " run " ) = = true ; } ;
2026-10-31 20:09:07 +01:00
// Every lens is off until the repository turns it on: a config that
// turns on none has nothing to run.
if ( std : : ranges : : none_of ( Plan : : Lenses , [ & ] ( const Plan : : Lens & lens ) { return runs ( Dyn : : Get ( lenses , Plan : : LensName ( lens . file ) ) ) ; } ) ) {
std : : vector < std : : string > names ;
for ( const Plan : : Lens & lens : Plan : : Lenses ) names . push_back ( Plan : : LensName ( lens . file ) ) ;
out . push_back ( std : : format ( " lenses: no lens is on - every lens is off until lenses.<name>.run = true turns it on for this repository ({}) " , Dyn : : Join ( names , " , " ) ) ) ;
}
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
for ( const Plan : : Lens & lens : Plan : : Lenses ) {
const Json & entry = Dyn : : Get ( lenses , Plan : : LensName ( lens . file ) ) ;
if ( ! lens . empirical | | ! runs ( entry ) ) continue ;
const Json & name = Dyn : : Get ( entry , " environment " ) ;
if ( ! Dyn : : In ( name , environments ) ) continue ;
if ( ! Plan : : FindEnvironment ( name . get_ref < const std : : string & > ( ) ) - > app ) {
std : : vector < std : : string > withApp ;
for ( const Plan : : Environment & environment : Plan : : Environments ) {
if ( environment . app ) withApp . emplace_back ( environment . name ) ;
}
out . push_back ( std : : format ( " lenses.{}: an empirical lens needs an environment with an application under test ({}) - or turn it off " , Plan : : LensName ( lens . file ) ,
Dyn : : Join ( withApp , " , " ) ) ) ;
}
}
const Json & supabase = Dyn : : At ( config , " supabase " ) ;
if ( ! supabase . is_object ( ) ) {
out . emplace_back ( " supabase must be an object {dbUrl, start, stop, notes} " ) ;
} else {
if ( const std : : optional < std : : string > problem = PgWire : : CheckUrl ( Dyn : : Get ( supabase , " dbUrl " ) ) ) out . push_back ( std : : format ( " supabase.dbUrl: {} " , * problem ) ) ;
for ( const std : : string_view key : { " start " , " stop " } ) {
const Json & value = Dyn : : Get ( supabase , key ) ;
if ( ! value . is_null ( ) & & ! value . is_string ( ) ) out . push_back ( std : : format ( " supabase.{} must be null or a command line " , key ) ) ;
}
if ( ! Dyn : : Get ( supabase , " notes " ) . is_string ( ) ) out . emplace_back ( " supabase.notes must be text " ) ;
}
const Json & functional = Dyn : : At ( config , " functional " ) ;
if ( ! functional . is_object ( ) ) {
out . emplace_back ( " functional must be an object " ) ;
return out ;
}
// The application's URL matters only to a lens that drives it.
const bool drivesApp = std : : ranges : : any_of ( lenses , [ & ] ( const Json & entry ) {
if ( ! runs ( entry ) ) return false ;
const Json & name = Dyn : : Get ( entry , " environment " ) ;
if ( name . is_array ( ) | | name . is_object ( ) ) throw Dyn : : Error ( " TypeError " , std : : format ( " unhashable type: '{}' " , Dyn : : TypeName ( name ) ) ) ;
const Plan : : Environment * environment = name . is_string ( ) ? Plan : : FindEnvironment ( name . get_ref < const std : : string & > ( ) ) : nullptr ;
return environment & & environment - > app ;
} ) ;
if ( drivesApp & & ! IsHttpUrl ( Dyn : : StrOr ( Dyn : : At ( functional , " appUrl " ) , " " ) ) ) out . emplace_back ( " functional.appUrl must be an http(s) URL " ) ;
if ( ! AllStrings ( Dyn : : At ( functional , " exclude " ) ) ) out . emplace_back ( " functional.exclude must be a list of globs " ) ;
const Json & extraTools = Dyn : : At ( functional , " extraTools " ) ;
if ( ! extraTools . is_array ( ) | | ! std : : ranges : : all_of ( extraTools , [ ] ( const Json & x ) { return x . is_string ( ) & & IsToolEntry ( x . get_ref < const std : : string & > ( ) ) ; } ) ) {
out . emplace_back ( " functional.extraTools entries must be Bash(<prefix>:*) or mcp__<server>[__<tool>] " ) ;
} else {
std : : vector < std : : string > dead ;
for ( const Json & tool : extraTools ) {
if ( Tools : : Denied ( tool . get_ref < const std : : string & > ( ) ) ) dead . push_back ( tool . get < std : : string > ( ) ) ;
}
if ( ! dead . empty ( ) ) {
out . push_back ( std : : format ( " functional.extraTools: {} - denied to every pass (pool.DENY wins over an allowlist); "
" a lens reaches the database through the supabase environment, every call rolled back " , Dyn : : Join ( dead , " , " ) ) ) ;
}
}
const Json & login = Dyn : : At ( functional , " login " ) ;
if ( ! login . is_object ( ) | | ! ( Dyn : : Has ( login , " fixtures " ) ? Dyn : : At ( login , " fixtures " ) . is_array ( ) : true ) ) out . emplace_back ( " functional.login must be {fixtures: [paths], notes: text} " ) ;
const Json & slots = Dyn : : At ( config , " slots " ) ;
if ( ! slots . is_object ( ) ) {
out . emplace_back ( " slots must be an object {dir, start, stop, memMb, startMb} " ) ;
} else if ( ! Dyn : : Get ( slots , " dir " ) . is_null ( ) ) {
const Json & dir = Dyn : : At ( slots , " dir " ) ;
bool bad = ! dir . is_string ( ) ;
if ( ! bad ) {
const std : : string & d = dir . get_ref < const std : : string & > ( ) ;
const std : : vector < std : : string > parts = Dyn : : Split ( Dyn : : Replace ( d , " \\ " , " / " ) , " / " ) ;
bad = Dyn : : Strip ( d ) . empty ( ) | | d . starts_with ( ' / ' ) | | std : : ranges : : contains ( parts , std : : string ( " .. " ) ) ;
}
if ( bad ) out . emplace_back ( " slots.dir must be null or a directory inside the repository (a relative path) " ) ;
for ( const std : : string_view key : { " start " , " stop " } ) {
const Json & value = Dyn : : Get ( slots , key ) ;
if ( ! value . is_null ( ) & & ( ! value . is_string ( ) | | ! value . get_ref < const std : : string & > ( ) . contains ( " {n} " ) ) ) {
out . push_back ( std : : format ( " slots.{} must be null or a command line with {{n}}, the slot number " , key ) ) ;
}
}
const Json & memMb = Dyn : : Get ( slots , " memMb " ) ;
if ( ! IsRealNumber ( memMb ) | | ! Positive ( memMb ) ) {
out . push_back ( std : : format ( " slots.memMb must be the measured memory of one slot in MB (a number > 0): `{} slots` sizes the slots by it " , Invocation ( ) ) ) ;
}
const Json & startMb = Dyn : : Get ( slots , " startMb " ) ;
if ( ! startMb . is_null ( ) & & ( ! IsRealNumber ( startMb ) | | ! Positive ( startMb ) ) ) {
out . emplace_back ( " slots.startMb must be null or the measured peak of one slot coming up in MB (a number > 0) " ) ;
}
}
const Json & args = Dyn : : Get ( Dyn : : At ( functional , " mcp " ) , " args " ) ;
if ( ! args . is_null ( ) & & ! AllStrings ( args ) ) out . emplace_back ( " functional.mcp.args must be null or a list of strings " ) ;
2026-10-31 16:45:53 +01:00
// A path found on the host, such as /usr/bin/npx, is not there inside
// the Flatpak, whose /usr is the Sdk's.
const Json & command = Dyn : : Get ( Dyn : : At ( functional , " mcp " ) , " command " ) ;
if ( command . is_string ( ) & & command . get < std : : string > ( ) . starts_with ( ' / ' ) ) {
std : : error_code error ;
const fs : : path file ( command . get < std : : string > ( ) ) ;
const bool executable = fs : : is_regular_file ( file , error ) & & ( fs : : status ( file , error ) . permissions ( ) & ( fs : : perms : : owner_exec | fs : : perms : : group_exec | fs : : perms : : others_exec ) ) ! = fs : : perms : : none ;
if ( ! executable ) {
out . emplace_back ( std : : format ( " functional.mcp.command {} is no program here{} " , Dyn : : Repr ( command . get < std : : string > ( ) ) ,
Platform : : InSandbox ( ) ? " (inside the Flatpak /usr is the Sdk's: name it `npx`, the bundled one) " : " " ) ) ;
}
}
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
return out ;
}
Json Redacted ( const Json & config ) {
Json copy = Json : : object ( ) ;
for ( auto it = config . begin ( ) ; it ! = config . end ( ) ; + + it ) {
if ( ! it . key ( ) . starts_with ( ' _ ' ) ) copy [ it . key ( ) ] = it . value ( ) ;
}
if ( Dyn : : Get ( copy , " supabase " ) . is_object ( ) & & Dyn : : Get ( copy [ " supabase " ] , " dbUrl " ) . is_string ( ) ) {
copy [ " supabase " ] [ " dbUrl " ] = PgWire : : Redact ( copy [ " supabase " ] [ " dbUrl " ] . get < std : : string > ( ) ) ;
}
return copy ;
}
std : : string GitUserEmail ( const fs : : path & repo ) {
const Process : : Captured run = Process : : Run ( { " git " , " -C " , repo . string ( ) , " config " , " user.email " } ) ;
return run . returnCode = = 0 ? Dyn : : Strip ( Dyn : : UniversalNewlines ( Dyn : : DecodeReplace ( run . out ) ) ) : std : : string ( ) ;
}
std : : vector < std : : string > Authors ( const Json & config , const fs : : path & repo ) {
const Json & authors = Dyn : : Get ( config , " authors " ) ;
if ( Dyn : : Truthy ( authors ) ) {
std : : vector < std : : string > out ;
for ( const Json & author : authors ) out . push_back ( Dyn : : Str ( author ) ) ;
return out ;
}
const std : : string email = GitUserEmail ( repo ) ;
if ( email . empty ( ) ) return { } ;
return { email } ;
}
std : : vector < std : : string > LensesOff ( const Json & config ) {
std : : vector < std : : string > out ;
for ( const Plan : : Lens & lens : Plan : : Lenses ) {
if ( Dyn : : Get ( LensEntry ( config , lens . file ) , " run " ) = = false ) out . emplace_back ( lens . file ) ;
}
return out ;
}
Json Environments ( const Json & config ) {
Json out = Json : : object ( ) ;
for ( const Plan : : Lens & lens : Plan : : Lenses ) {
const Json & entry = LensEntry ( config , lens . file ) ;
out [ std : : string ( lens . file ) ] = Dyn : : Has ( entry , " environment " ) ? Dyn : : At ( entry , " environment " ) : Json ( " none " ) ;
}
return out ;
}
Slots SlotStacks ( const Json & config , const fs : : path & repo ) {
Slots slots ;
const Json & dir = Dyn : : Get ( Dyn : : Or ( Dyn : : Get ( config , " slots " ) , Dyn : : EmptyDict ( ) ) , " dir " ) ;
if ( ! Dyn : : Truthy ( dir ) | | ! fs : : is_directory ( repo / dir . get < std : : string > ( ) ) ) return slots ;
const std : : string d = dir . get < std : : string > ( ) ;
std : : vector < std : : string > names ;
for ( const fs : : directory_entry & entry : fs : : directory_iterator ( repo / d ) ) names . push_back ( entry . path ( ) . filename ( ) . string ( ) ) ;
std : : ranges : : stable_sort ( names , { } , [ ] ( const std : : string & name ) { return Dyn : : Natural ( name ) ; } ) ;
for ( const std : : string & n : names ) {
const fs : : path file = repo / d / n / SlotFile ;
if ( ! fs : : is_regular_file ( file ) ) continue ;
const std : : string rel = Dyn : : JoinPath ( Dyn : : JoinPath ( d , n ) , SlotFile ) ;
std : : variant < Json , std : : string > read = LoadJson ( file ) ;
if ( std : : holds_alternative < std : : string > ( read ) ) {
slots . problems . push_back ( std : : format ( " {}: not JSON ({}) " , rel , std : : get < std : : string > ( read ) ) ) ;
continue ;
}
const Json & s = std : : get < Json > ( read ) ;
if ( ! s . is_object ( ) | | ! IsHttpUrl ( Dyn : : StrOr ( Dyn : : Get ( s , " appUrl " ) , " " ) ) ) {
slots . problems . push_back ( std : : format ( " {}: no appUrl " , rel ) ) ;
continue ;
}
const Json & api = Dyn : : Or ( Dyn : : Get ( s , " apiUrls " ) , Dyn : : EmptyList ( ) ) ;
if ( ! AllStrings ( api ) ) {
slots . problems . push_back ( std : : format ( " {}: apiUrls must be a list of URLs " , rel ) ) ;
continue ;
}
const Json & db = Dyn : : Get ( s , " dbUrl " ) ;
if ( ! db . is_null ( ) ) {
if ( const std : : optional < std : : string > problem = PgWire : : CheckUrl ( db ) ) {
slots . problems . push_back ( std : : format ( " {}: dbUrl: {} " , rel , * problem ) ) ;
continue ;
}
}
const Json & login = Dyn : : Get ( s , " login " ) ;
if ( ! login . is_null ( ) & & ( ! login . is_string ( ) | | ! fs : : exists ( repo / login . get < std : : string > ( ) ) ) ) {
slots . problems . push_back ( std : : format ( " {}: login {} is not a file " , rel , Dyn : : ReprValue ( login ) ) ) ;
continue ;
}
slots . stacks . push_back ( {
{ " id " , std : : format ( " slot {} " , n ) } ,
{ " appUrl " , Dyn : : RStrip ( Dyn : : At ( s , " appUrl " ) . get < std : : string > ( ) , " / " ) } ,
{ " apiUrls " , api } ,
{ " dbUrl " , db } ,
{ " login " , login } ,
{ " slot " , true } ,
} ) ;
}
return slots ;
}
std : : vector < std : : string > SlotCommands ( const Json & config , std : : string_view which , std : : span < const std : : int64_t > slots ) {
const Json & command = Dyn : : Get ( Dyn : : Or ( Dyn : : Get ( config , " slots " ) , Dyn : : EmptyDict ( ) ) , which ) ;
if ( ! Dyn : : Truthy ( command ) ) return { } ;
std : : vector < std : : string > out ;
for ( const std : : int64_t n : slots ) out . push_back ( Dyn : : Replace ( command . get < std : : string > ( ) , " {n} " , std : : to_string ( n ) ) ) ;
return out ;
}
std : : optional < std : : string > LoginFixture ( const Json & config , const fs : : path & repo ) {
const Json & login = Dyn : : Or ( Dyn : : Get ( Dyn : : At ( config , " functional " ) , " login " ) , Dyn : : EmptyDict ( ) ) ;
for ( const Json & fixture : Dyn : : Or ( Dyn : : Get ( login , " fixtures " ) , Dyn : : EmptyList ( ) ) ) {
if ( fs : : exists ( repo / fixture . get < std : : string > ( ) ) ) return fixture . get < std : : string > ( ) ;
}
return std : : nullopt ;
}
Json Example ( ) {
Json example = Defaults ( ) ;
example [ " base " ] = " origin/main " ;
example [ " authors " ] = { " you@example.com " } ;
example [ " aiTrailers " ] = " forbid " ;
example [ " gate0 " ] = { " make check " } ;
Json & functional = example [ " functional " ] ;
functional [ " appUrl " ] = " http://localhost:8080 " ;
functional [ " start " ] = " make run " ;
functional [ " stop " ] = " make stop " ;
functional [ " login " ] = { { " fixtures " , { " .local-stack/test-user.json " } } , { " notes " , " the fixture holds a TOTP-verified login " } } ;
functional [ " exclude " ] = { " **/*.test.* " , " **/*.spec.* " , " docs/** " , " .github/** " , " *.md " } ;
return example ;
}
std : : int32_t Main ( const fs : : path & repo , const fs : : path & path ) {
const Loaded loaded = Load ( repo , path ) ;
Json shown = Redacted ( loaded . config ) ;
// The database password masked, as in the dump.
shown [ " _path " ] = Dyn : : Get ( loaded . config , " _path " ) ;
std : : println ( " {} " , DumpFile ( shown ) ) ;
for ( const Json & warning : Dyn : : Or ( Dyn : : Get ( loaded . config , " _warnings " ) , Dyn : : EmptyList ( ) ) ) std : : println ( " warning: {} " , Dyn : : Str ( warning ) ) ;
for ( const std : : string & problem : loaded . problems ) std : : println ( " problem: {} " , problem ) ;
return loaded . problems . empty ( ) ? 0 : 1 ;
}
}