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>
This commit is contained in:
Jorijn van der Graaf 2026-10-31 06:48:55 +01:00
commit 741e3a656d
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
70 changed files with 30565 additions and 21 deletions

View file

@ -13,7 +13,7 @@ using namespace Crafter;
namespace {
// The umbrella, then the partitions in import order: each after the ones
// it imports, which is also the order the module map in AGENTS.md uses.
constexpr std::array<std::string_view, 9> Interfaces = {
constexpr std::array<std::string_view, 21> Interfaces = {
"interfaces/Crafter.Review",
"interfaces/Crafter.Review-Unicode",
"interfaces/Crafter.Review-Json",
@ -22,24 +22,54 @@ namespace {
"interfaces/Crafter.Review-Platform",
"interfaces/Crafter.Review-Process",
"interfaces/Crafter.Review-Core",
"interfaces/Crafter.Review-Schema",
"interfaces/Crafter.Review-Tools",
"interfaces/Crafter.Review-Plan",
"interfaces/Crafter.Review-Artifact",
"interfaces/Crafter.Review-Inventory",
"interfaces/Crafter.Review-Dispositions",
"interfaces/Crafter.Review-State",
"interfaces/Crafter.Review-Normalize",
"interfaces/Crafter.Review-PgWire",
"interfaces/Crafter.Review-Stream",
"interfaces/Crafter.Review-Prompt",
"interfaces/Crafter.Review-Config",
"interfaces/Crafter.Review-Driver",
};
constexpr std::array<std::string_view, 6> Implementations = {
constexpr std::array<std::string_view, 18> Implementations = {
"implementations/Crafter.Review-Text",
"implementations/Crafter.Review-Crypto",
"implementations/Crafter.Review-Platform",
"implementations/Crafter.Review-Process",
"implementations/Crafter.Review-Core",
"implementations/Crafter.Review-Schema",
"implementations/Crafter.Review-Tools",
"implementations/Crafter.Review-Plan",
"implementations/Crafter.Review-Artifact",
"implementations/Crafter.Review-Inventory",
"implementations/Crafter.Review-Dispositions",
"implementations/Crafter.Review-State",
"implementations/Crafter.Review-Normalize",
"implementations/Crafter.Review-PgWire",
"implementations/Crafter.Review-Stream",
"implementations/Crafter.Review-Prompt",
"implementations/Crafter.Review-Config",
"implementations/Crafter.Review-Driver",
};
// With -march=native clang would fuse a multiply and an add: a cost
// estimate, a usage total or a memory threshold must come out to the
// same last bit on every machine, as the goldens record it.
constexpr std::string_view NoContraction = "-ffp-contract=off";
// One per directory under tests/, each an ordinary main() that links the
// library: exit 0 passes, nonzero fails, 77 skips.
constexpr std::array<std::string_view, 4> Tests = {
constexpr std::array<std::string_view, 5> Tests = {
"Crypto",
"Text",
"Platform",
"Process",
"Goldens",
};
// The version the binary reports: CI sets it from the tag, a checkout
@ -218,6 +248,7 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
ApplyStandardArgs(*ReviewLib, args);
ReviewLib->type = ConfigurationType::LibraryStatic;
ReviewLib->dependencies = { network };
ReviewLib->compileFlags.emplace_back(NoContraction);
// Backslash-escaped quotes: the define travels through the shell before
// it reaches clang, which must still see a string literal.
ReviewLib->defines.push_back({"CRAFTER_REVIEW_VERSION", std::format("\\\"{}\\\"", Version())});
@ -234,6 +265,7 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
ApplyStandardArgs(cfg, args);
cfg.type = ConfigurationType::Executable;
cfg.dependencies = { ReviewLib.get() };
cfg.compileFlags.emplace_back(NoContraction);
{
std::array<fs::path, 0> interfaces = {};
std::array<fs::path, 1> implementations = { "implementations/main" };
@ -241,7 +273,7 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
}
for (const std::string_view test : Tests) {
cfg.AddTest(test).Dependencies({ ReviewLib.get() });
cfg.AddTest(test).Dependencies({ ReviewLib.get() }).CompileFlag(std::string(NoContraction));
}
LintRules::AddLiteRules(cfg);